Merge pull request #3265 from lightmare/refactor-symbolizers

refactoring group, markers symbolizers to reduce compile time / memory usage
This commit is contained in:
lightmare 2016-01-29 02:23:12 +01:00
commit 0b2775a5e1
33 changed files with 1152 additions and 1212 deletions

View file

@ -40,19 +40,15 @@ src/json/libmapnik-json.a:
# we first build memory intensive files with -j1
$(PYTHON) scons/scons.py -j1 \
--config=cache --implicit-cache --max-drift=1 \
src/renderer_common/process_group_symbolizer.os \
src/renderer_common/render_group_symbolizer.os \
src/renderer_common/render_markers_symbolizer.os \
src/renderer_common/render_thunk_extractor.os \
src/json/libmapnik-json.a \
src/wkt/libmapnik-wkt.a \
src/css_color_grammar.os \
src/expression_grammar.os \
src/transform_expression_grammar.os \
src/image_filter_grammar.os \
src/agg/process_markers_symbolizer.os \
src/agg/process_group_symbolizer.os \
src/grid/process_markers_symbolizer.os \
src/grid/process_group_symbolizer.os \
src/cairo/process_markers_symbolizer.os \
src/cairo/process_group_symbolizer.os \
mapnik: src/json/libmapnik-json.a
# then install the rest with -j$(JOBS)

View file

@ -100,10 +100,8 @@ private:
static font_memory_cache_type global_memory_fonts_;
};
class MAPNIK_DECL face_manager : private util::noncopyable
class MAPNIK_DECL face_manager
{
using face_ptr_cache_type = std::map<std::string, face_ptr>;
public:
face_manager(font_library & library,
freetype_engine::font_file_mapping_type const& font_file_mapping,
@ -112,9 +110,13 @@ public:
face_set_ptr get_face_set(std::string const& name);
face_set_ptr get_face_set(font_set const& fset);
face_set_ptr get_face_set(std::string const& name, boost::optional<font_set> fset);
inline stroker_ptr get_stroker() { return stroker_; }
stroker_ptr get_stroker() const { return stroker_; }
private:
face_ptr_cache_type face_ptr_cache_;
using face_cache = std::map<std::string, face_ptr>;
using face_cache_ptr = std::shared_ptr<face_cache>;
face_cache_ptr face_cache_;
font_library & library_;
freetype_engine::font_file_mapping_type const& font_file_mapping_;
freetype_engine::font_memory_cache_type const& font_memory_cache_;

View file

@ -31,43 +31,51 @@
// stl
#include <vector>
using std::vector;
namespace mapnik
{
using bound_box = box2d<double>;
struct group_layout_manager
{
group_layout_manager(group_layout const& layout)
using bound_box = box2d<double>;
group_layout_manager()
: update_layout_(false)
{}
explicit group_layout_manager(group_layout const& layout)
: layout_(layout),
input_origin_(0, 0),
member_boxes_(vector<bound_box>()),
member_offsets_(vector<pixel_position>()),
update_layout_(true)
update_layout_(false)
{
}
group_layout_manager(group_layout const& layout, pixel_position const& input_origin)
: layout_(layout),
input_origin_(input_origin),
member_boxes_(vector<bound_box>()),
member_offsets_(vector<pixel_position>()),
update_layout_(true)
update_layout_(false)
{
}
group_layout_manager(group_layout const& layout, pixel_position const& input_origin,
vector<bound_box> const& item_boxes)
std::vector<bound_box> const& item_boxes)
: layout_(layout),
input_origin_(input_origin),
member_boxes_(item_boxes),
member_offsets_(vector<pixel_position>()),
update_layout_(true)
{
}
void set_input_origin(double x, double y)
{
input_origin_.set(x, y);
update_layout_ = true;
}
void set_input_origin(pixel_position const& input_origin)
{
input_origin_ = input_origin;
update_layout_ = true;
}
inline void set_layout(group_layout const& layout)
{
layout_ = layout;
@ -94,8 +102,8 @@ private:
group_layout layout_;
pixel_position input_origin_;
vector<bound_box> member_boxes_;
vector<pixel_position> member_offsets_;
std::vector<bound_box> member_boxes_;
std::vector<pixel_position> member_offsets_;
bool update_layout_;
};

View file

@ -41,8 +41,10 @@ namespace mapnik
struct image_any;
namespace svg { struct path_attributes; }
using attr_storage = agg::pod_bvector<mapnik::svg::path_attributes>;
using svg_storage_type = mapnik::svg::svg_storage<mapnik::svg::svg_path_storage,attr_storage>;
using svg::svg_path_adapter;
using svg_attribute_type = agg::pod_bvector<svg::path_attributes>;
using svg_storage_type = svg::svg_storage<svg::svg_path_storage, svg_attribute_type>;
using svg_path_ptr = std::shared_ptr<svg_storage_type>;
using image_ptr = std::shared_ptr<image_any>;

View file

@ -35,6 +35,7 @@
#include <mapnik/box2d.hpp>
#include <mapnik/vertex_processor.hpp>
#include <mapnik/renderer_common/apply_vertex_converter.hpp>
#include <mapnik/renderer_common/render_markers_symbolizer.hpp>
// agg
#include "agg_trans_affine.h"
@ -52,60 +53,53 @@ template <typename Detector>
struct vector_markers_dispatch : util::noncopyable
{
vector_markers_dispatch(svg_path_ptr const& src,
svg_path_adapter & path,
svg_attribute_type const& attrs,
agg::trans_affine const& marker_trans,
symbolizer_base const& sym,
Detector & detector,
double scale_factor,
feature_impl const& feature,
attributes const& vars)
: src_(src),
marker_trans_(marker_trans),
sym_(sym),
detector_(detector),
feature_(feature),
vars_(vars),
scale_factor_(scale_factor)
attributes const& vars,
bool snap_to_pixels,
markers_renderer_context & renderer_context)
: params_(src->bounding_box(), recenter(src) * marker_trans,
sym, feature, vars, scale_factor, snap_to_pixels)
, renderer_context_(renderer_context)
, src_(src)
, path_(path)
, attrs_(attrs)
, detector_(detector)
{}
virtual ~vector_markers_dispatch() {}
template <typename T>
void add_path(T & path)
{
marker_placement_enum placement_method = get<marker_placement_enum, keys::markers_placement_type>(sym_, feature_, vars_);
value_bool ignore_placement = get<value_bool, keys::ignore_placement>(sym_, feature_, vars_);
value_bool allow_overlap = get<value_bool, keys::allow_overlap>(sym_, feature_, vars_);
value_bool avoid_edges = get<value_bool, keys::avoid_edges>(sym_, feature_, vars_);
value_double opacity = get<value_double,keys::opacity>(sym_, feature_, vars_);
value_double spacing = get<value_double, keys::spacing>(sym_, feature_, vars_);
value_double max_error = get<value_double, keys::max_error>(sym_, feature_, vars_);
coord2d center = src_->bounding_box().center();
agg::trans_affine_translation recenter(-center.x, -center.y);
agg::trans_affine tr = recenter * marker_trans_;
direction_enum direction = get<direction_enum, keys::direction>(sym_, feature_, vars_);
markers_placement_params params { src_->bounding_box(), tr, spacing * scale_factor_, max_error, allow_overlap, avoid_edges, direction };
markers_placement_finder<T, Detector> placement_finder(
placement_method, path, detector_, params);
params_.placement_method, path, detector_, params_.placement_params);
double x, y, angle = .0;
while (placement_finder.get_point(x, y, angle, ignore_placement))
while (placement_finder.get_point(x, y, angle, params_.ignore_placement))
{
agg::trans_affine matrix = tr;
agg::trans_affine matrix = params_.placement_params.tr;
matrix.rotate(angle);
matrix.translate(x, y);
render_marker(matrix, opacity);
renderer_context_.render_marker(src_, path_, attrs_, params_, matrix);
}
}
virtual void render_marker(agg::trans_affine const& marker_tr, double opacity) = 0;
protected:
static agg::trans_affine recenter(svg_path_ptr const& src)
{
coord2d center = src->bounding_box().center();
return agg::trans_affine_translation(-center.x, -center.y);
}
markers_dispatch_params params_;
markers_renderer_context & renderer_context_;
svg_path_ptr const& src_;
agg::trans_affine const& marker_trans_;
symbolizer_base const& sym_;
svg_path_adapter & path_;
svg_attribute_type const& attrs_;
Detector & detector_;
feature_impl const& feature_;
attributes const& vars_;
double scale_factor_;
};
template <typename Detector>
@ -117,53 +111,35 @@ struct raster_markers_dispatch : util::noncopyable
Detector & detector,
double scale_factor,
feature_impl const& feature,
attributes const& vars)
: src_(src),
marker_trans_(marker_trans),
sym_(sym),
detector_(detector),
feature_(feature),
vars_(vars),
scale_factor_(scale_factor)
attributes const& vars,
markers_renderer_context & renderer_context)
: params_(box2d<double>(0, 0, src.width(), src.height()),
marker_trans, sym, feature, vars, scale_factor)
, renderer_context_(renderer_context)
, src_(src)
, detector_(detector)
{}
virtual ~raster_markers_dispatch() {}
template <typename T>
void add_path(T & path)
{
marker_placement_enum placement_method = get<marker_placement_enum, keys::markers_placement_type>(sym_, feature_, vars_);
value_bool allow_overlap = get<value_bool, keys::allow_overlap>(sym_, feature_, vars_);
value_bool avoid_edges = get<value_bool, keys::avoid_edges>(sym_, feature_, vars_);
value_double opacity = get<value_double, keys::opacity>(sym_, feature_, vars_);
value_bool ignore_placement = get<value_bool, keys::ignore_placement>(sym_, feature_, vars_);
value_double spacing = get<value_double, keys::spacing>(sym_, feature_, vars_);
value_double max_error = get<value_double, keys::max_error>(sym_, feature_, vars_);
box2d<double> bbox(0,0, src_.width(),src_.height());
direction_enum direction = get<direction_enum, keys::direction>(sym_, feature_, vars_);
markers_placement_params params { bbox, marker_trans_, spacing * scale_factor_, max_error, allow_overlap, avoid_edges, direction };
markers_placement_finder<T, Detector> placement_finder(
placement_method, path, detector_, params);
params_.placement_method, path, detector_, params_.placement_params);
double x, y, angle = .0;
while (placement_finder.get_point(x, y, angle, ignore_placement))
while (placement_finder.get_point(x, y, angle, params_.ignore_placement))
{
agg::trans_affine matrix = marker_trans_;
agg::trans_affine matrix = params_.placement_params.tr;
matrix.rotate(angle);
matrix.translate(x, y);
render_marker(matrix, opacity);
renderer_context_.render_marker(src_, params_, matrix);
}
}
virtual void render_marker(agg::trans_affine const& marker_tr, double opacity) = 0;
protected:
markers_dispatch_params params_;
markers_renderer_context & renderer_context_;
image_rgba8 const& src_;
agg::trans_affine const& marker_trans_;
symbolizer_base const& sym_;
Detector & detector_;
feature_impl const& feature_;
attributes const& vars_;
double scale_factor_;
};
void build_ellipse(symbolizer_base const& sym, mapnik::feature_impl & feature, attributes const& vars,

View file

@ -40,8 +40,8 @@ namespace mapnik {
struct markers_placement_params
{
box2d<double> const& size;
agg::trans_affine const& tr;
box2d<double> size;
agg::trans_affine tr;
double spacing;
double max_error;
bool allow_overlap;
@ -132,23 +132,8 @@ protected:
// Rotates the size_ box and translates the position.
box2d<double> perform_transform(double angle, double dx, double dy)
{
double x1 = params_.size.minx();
double x2 = params_.size.maxx();
double y1 = params_.size.miny();
double y2 = params_.size.maxy();
agg::trans_affine tr = params_.tr * agg::trans_affine_rotation(angle).translate(dx, dy);
double xA = x1, yA = y1,
xB = x2, yB = y1,
xC = x2, yC = y2,
xD = x1, yD = y2;
tr.transform(&xA, &yA);
tr.transform(&xB, &yB);
tr.transform(&xC, &yC);
tr.transform(&xD, &yD);
box2d<double> result(xA, yA, xC, yC);
result.expand_to_include(xB, yB);
result.expand_to_include(xD, yD);
return result;
return box2d<double>(params_.size, tr);
}
bool set_direction(double & angle)

View file

@ -42,13 +42,16 @@ namespace mapnik {
struct renderer_common : private util::noncopyable
{
using detector_ptr = std::shared_ptr<label_collision_detector4>;
renderer_common(Map const &m, attributes const& vars, unsigned offset_x, unsigned offset_y,
unsigned width, unsigned height, double scale_factor);
renderer_common(Map const &m, attributes const& vars, unsigned offset_x, unsigned offset_y,
unsigned width, unsigned height, double scale_factor,
std::shared_ptr<label_collision_detector4> detector);
detector_ptr detector);
renderer_common(Map const &m, request const &req, attributes const& vars, unsigned offset_x, unsigned offset_y,
unsigned width, unsigned height, double scale_factor);
~renderer_common();
unsigned width_;
unsigned height_;
@ -60,11 +63,18 @@ struct renderer_common : private util::noncopyable
face_manager_freetype font_manager_;
box2d<double> query_extent_;
view_transform t_;
std::shared_ptr<label_collision_detector4> detector_;
detector_ptr detector_;
protected:
// it's desirable to keep this class implicitly noncopyable to prevent
// inadvertent copying from other places;
// this copy constructor is therefore protected and should only be used
// by virtual_renderer_common
renderer_common(renderer_common const& other);
private:
renderer_common(Map const &m, unsigned width, unsigned height, double scale_factor,
attributes const& vars, view_transform &&t, std::shared_ptr<label_collision_detector4> detector);
attributes const& vars, view_transform && t, detector_ptr detector);
};
}

View file

@ -1,403 +0,0 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2015 Artem Pavlenko
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*****************************************************************************/
#ifndef MAPNIK_RENDERER_COMMON_PROCESS_GROUP_SYMBOLIZER_HPP
#define MAPNIK_RENDERER_COMMON_PROCESS_GROUP_SYMBOLIZER_HPP
// mapnik
#include <mapnik/pixel_position.hpp>
#include <mapnik/marker.hpp>
#include <mapnik/feature.hpp>
#include <mapnik/feature_factory.hpp>
#include <mapnik/renderer_common.hpp>
#include <mapnik/symbolizer.hpp>
#include <mapnik/attribute_collector.hpp>
#include <mapnik/group/group_layout_manager.hpp>
#include <mapnik/group/group_symbolizer_helper.hpp>
#include <mapnik/group/group_symbolizer_properties.hpp>
#include <mapnik/text/glyph_positions.hpp>
#include <mapnik/util/conversions.hpp>
#include <mapnik/util/variant.hpp>
#include <mapnik/label_collision_detector.hpp>
#include <mapnik/util/noncopyable.hpp>
#include <mapnik/svg/svg_path_adapter.hpp>
#include <mapnik/svg/svg_path_attributes.hpp>
// agg
#include <agg_trans_affine.h>
namespace mapnik {
class text_symbolizer_helper;
using svg::svg_path_adapter;
using svg_attribute_type = agg::pod_bvector<svg::path_attributes>;
struct virtual_renderer_common : private util::noncopyable
{
virtual_renderer_common(renderer_common & common) :
width_(common.width_),
height_(common.height_),
scale_factor_(common.scale_factor_),
vars_(common.vars_),
shared_font_library_(common.shared_font_library_),
font_library_(*shared_font_library_),
font_manager_(common.font_manager_),
query_extent_(common.query_extent_),
t_(common.t_),
detector_(std::make_shared<label_collision_detector4>(common.detector_->extent())) {}
unsigned & width_;
unsigned & height_;
double & scale_factor_;
attributes & vars_;
// TODO: dirty hack for cairo renderer, figure out how to remove this
std::shared_ptr<font_library> & shared_font_library_;
font_library & font_library_;
face_manager_freetype & font_manager_;
box2d<double> & query_extent_;
view_transform & t_;
std::shared_ptr<label_collision_detector4> detector_;
};
// General:
// The approach here is to run the normal symbolizers, but in
// a 'virtual' blank environment where the changes that they
// make are recorded (the detector, the render_* calls).
//
// The recorded boxes are then used to lay out the items and
// the offsets from old to new positions can be used to perform
// the actual rendering calls.
// This should allow us to re-use as much as possible of the
// existing symbolizer layout and rendering code while still
// being able to interpose our own decisions about whether
// a collision has occurred or not.
// Thunk for rendering a particular instance of a point - this
// stores all the arguments necessary to re-render this point
// symbolizer at a later time.
struct vector_marker_render_thunk : util::noncopyable
{
svg_path_ptr src_;
svg_attribute_type attrs_;
agg::trans_affine tr_;
double opacity_;
composite_mode_e comp_op_;
bool snap_to_pixels_;
vector_marker_render_thunk(svg_path_ptr const& src,
svg_attribute_type const& attrs,
agg::trans_affine const& marker_trans,
double opacity,
composite_mode_e comp_op,
bool snap_to_pixels);
vector_marker_render_thunk(vector_marker_render_thunk && rhs);
};
struct raster_marker_render_thunk : util::noncopyable
{
image_rgba8 const& src_;
agg::trans_affine tr_;
double opacity_;
composite_mode_e comp_op_;
bool snap_to_pixels_;
raster_marker_render_thunk(image_rgba8 const& src,
agg::trans_affine const& marker_trans,
double opacity,
composite_mode_e comp_op,
bool snap_to_pixels);
raster_marker_render_thunk(raster_marker_render_thunk && rhs);
};
using helper_ptr = std::unique_ptr<text_symbolizer_helper>;
struct text_render_thunk : util::noncopyable
{
// helper is stored here in order
// to keep in scope the text rendering structures
helper_ptr helper_;
placements_list const& placements_;
double opacity_;
composite_mode_e comp_op_;
halo_rasterizer_enum halo_rasterizer_;
text_render_thunk(helper_ptr && helper,
double opacity, composite_mode_e comp_op,
halo_rasterizer_enum halo_rasterizer);
text_render_thunk(text_render_thunk && rhs);
};
// Variant type for render thunks to allow us to re-render them
// via a static visitor later.
using render_thunk = util::variant<vector_marker_render_thunk,
raster_marker_render_thunk,
text_render_thunk>;
using render_thunk_ptr = std::unique_ptr<render_thunk>;
using render_thunk_list = std::list<render_thunk_ptr>;
// Base class for extracting the bounding boxes associated with placing
// a symbolizer at a fake, virtual point - not real geometry.
//
// The bounding boxes can be used for layout, and the thunks are
// used to re-render at locations according to the group layout.
struct render_thunk_extractor
{
render_thunk_extractor(box2d<double> & box,
render_thunk_list & thunks,
feature_impl & feature,
attributes const& vars,
proj_transform const& prj_trans,
virtual_renderer_common & common,
box2d<double> const& clipping_extent);
void operator()(markers_symbolizer const& sym) const;
void operator()(text_symbolizer const& sym) const;
void operator()(shield_symbolizer const& sym) const;
template <typename T>
void operator()(T const& ) const
{
// TODO: warning if unimplemented?
}
private:
void extract_text_thunk(helper_ptr && helper, text_symbolizer const& sym) const;
box2d<double> & box_;
render_thunk_list & thunks_;
feature_impl & feature_;
attributes const& vars_;
proj_transform const& prj_trans_;
virtual_renderer_common & common_;
box2d<double> clipping_extent_;
void update_box() const;
};
template <typename F>
void render_offset_placements(placements_list const& placements,
pixel_position const& offset,
F render_text) {
for (auto const& glyphs : placements)
{
// move the glyphs to the correct offset
pixel_position base_point = glyphs->get_base_point();
glyphs->set_base_point(base_point + offset);
// update the position of any marker
marker_info_ptr marker_info = glyphs->get_marker();
pixel_position marker_pos = glyphs->marker_pos();
if (marker_info)
{
glyphs->set_marker(marker_info, marker_pos + offset);
}
render_text(glyphs);
// Need to put the base_point back how it was in case something else calls this again
// (don't want to add offset twice) or calls with a different offset.
glyphs->set_base_point(base_point);
if (marker_info)
{
glyphs->set_marker(marker_info, marker_pos);
}
}
}
template <typename F>
void render_group_symbolizer(group_symbolizer const& sym,
feature_impl & feature,
attributes const& vars,
proj_transform const& prj_trans,
box2d<double> const& clipping_extent,
renderer_common & common,
F render_thunks)
{
// find all column names referenced in the group rules and symbolizers
std::set<std::string> columns;
group_attribute_collector column_collector(columns, false);
column_collector(sym);
group_symbolizer_properties_ptr props = get<group_symbolizer_properties_ptr>(sym, keys::group_properties);
// create a new context for the sub features of this group
context_ptr sub_feature_ctx = std::make_shared<mapnik::context_type>();
// populate new context with column names referenced in the group rules and symbolizers
for (auto const& col_name : columns)
{
sub_feature_ctx->push(col_name);
}
// keep track of the sub features that we'll want to symbolize
// along with the group rules that they matched
std::vector< std::pair<group_rule_ptr, feature_ptr> > matches;
// create a copied 'virtual' common renderer for processing sub feature symbolizers
// create an empty detector for it, so we are sure we won't hit anything
virtual_renderer_common virtual_renderer(common);
// keep track of which lists of render thunks correspond to
// entries in the group_layout_manager.
std::vector<render_thunk_list> layout_thunks;
size_t num_layout_thunks = 0;
// layout manager to store and arrange bboxes of matched features
group_layout_manager layout_manager(props->get_layout(), pixel_position(common.width_ / 2.0, common.height_ / 2.0));
// run feature or sub feature through the group rules & symbolizers
// for each index value in the range
value_integer start = get<value_integer>(sym, keys::start_column);
value_integer end = start + get<value_integer>(sym, keys::num_columns);
for (value_integer col_idx = start; col_idx < end; ++col_idx)
{
// create sub feature with indexed column values
feature_ptr sub_feature = feature_factory::create(sub_feature_ctx, col_idx);
// copy the necessary columns to sub feature
for(auto const& col_name : columns)
{
if (col_name.find('%') != std::string::npos)
{
if (col_name.size() == 1)
{
// column name is '%' by itself, so give the index as the value
sub_feature->put(col_name, col_idx);
}
else
{
// indexed column
std::string col_idx_str;
if (mapnik::util::to_string(col_idx_str,col_idx))
{
std::string col_idx_name = col_name;
boost::replace_all(col_idx_name, "%", col_idx_str);
sub_feature->put(col_name, feature.get(col_idx_name));
}
}
}
else
{
// non-indexed column
sub_feature->put(col_name, feature.get(col_name));
}
}
// add a single point geometry at pixel origin
double x = common.width_ / 2.0, y = common.height_ / 2.0, z = 0.0;
common.t_.backward(&x, &y);
prj_trans.forward(x, y, z);
// note that we choose a point in the middle of the screen to
// try to ensure that we don't get edge artefacts due to any
// symbolizers with avoid-edges set: only the avoid-edges of
// the group symbolizer itself should matter.
geometry::point<double> origin_pt(x,y);
sub_feature->set_geometry(origin_pt);
// get the layout for this set of properties
for (auto const& rule : props->get_rules())
{
if (util::apply_visitor(evaluate<feature_impl,value_type,attributes>(*sub_feature,common.vars_),
*(rule->get_filter())).to_bool())
{
// add matched rule and feature to the list of things to draw
matches.emplace_back(rule, sub_feature);
// construct a bounding box around all symbolizers for the matched rule
bound_box bounds;
render_thunk_list thunks;
render_thunk_extractor extractor(bounds, thunks, *sub_feature, common.vars_, prj_trans,
virtual_renderer, clipping_extent);
for (auto const& _sym : *rule)
{
// TODO: construct layout and obtain bounding box
util::apply_visitor(extractor, _sym);
}
// add the bounding box to the layout manager
layout_manager.add_member_bound_box(bounds);
layout_thunks.emplace_back(std::move(thunks));
++num_layout_thunks;
break;
}
}
}
// create a symbolizer helper
group_symbolizer_helper helper(sym, feature, vars, prj_trans,
common.width_, common.height_,
common.scale_factor_, common.t_,
*common.detector_, clipping_extent);
for (size_t i = 0; i < matches.size(); ++i)
{
group_rule_ptr match_rule = matches[i].first;
feature_ptr match_feature = matches[i].second;
value_unicode_string rpt_key_value = "";
// get repeat key from matched group rule
expression_ptr rpt_key_expr = match_rule->get_repeat_key();
// if no repeat key was defined, use default from group symbolizer
if (!rpt_key_expr)
{
rpt_key_expr = get<expression_ptr>(sym, keys::repeat_key);
}
// evaluate the repeat key with the matched sub feature if we have one
if (rpt_key_expr)
{
rpt_key_value = util::apply_visitor(evaluate<feature_impl,value_type,attributes>(*match_feature,common.vars_),
*rpt_key_expr).to_unicode();
}
helper.add_box_element(layout_manager.offset_box_at(i), rpt_key_value);
}
pixel_position_list positions = helper.get();
for (pixel_position const& pos : positions)
{
for (size_t layout_i = 0; layout_i < num_layout_thunks; ++layout_i)
{
pixel_position const& offset = layout_manager.offset_at(layout_i);
pixel_position render_offset = pos + offset;
render_thunks(layout_thunks[layout_i], render_offset);
}
}
}
} // namespace mapnik
#endif // MAPNIK_RENDERER_COMMON_PROCESS_GROUP_SYMBOLIZER_HPP

View file

@ -0,0 +1,66 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2016 Artem Pavlenko
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*****************************************************************************/
#ifndef MAPNIK_RENDERER_COMMON_RENDER_GROUP_SYMBOLIZER_HPP
#define MAPNIK_RENDERER_COMMON_RENDER_GROUP_SYMBOLIZER_HPP
// mapnik
#include <mapnik/pixel_position.hpp>
#include <mapnik/renderer_common.hpp>
#include <mapnik/renderer_common/render_thunk.hpp>
#include <mapnik/symbolizer_base.hpp>
#include <mapnik/text/glyph_positions.hpp>
namespace mapnik {
struct render_thunk_list_dispatch
{
virtual void operator()(vector_marker_render_thunk const& thunk) = 0;
virtual void operator()(raster_marker_render_thunk const& thunk) = 0;
virtual void operator()(text_render_thunk const& thunk) = 0;
void render_list(render_thunk_list const& thunks, pixel_position const& offset)
{
offset_ = offset;
for (render_thunk_ptr const& thunk : thunks)
{
util::apply_visitor(std::ref(*this), *thunk);
}
}
protected:
pixel_position offset_;
};
MAPNIK_DECL
void render_group_symbolizer(group_symbolizer const& sym,
feature_impl & feature,
attributes const& vars,
proj_transform const& prj_trans,
box2d<double> const& clipping_extent,
renderer_common & common,
render_thunk_list_dispatch & render_thunks);
} // namespace mapnik
#endif // MAPNIK_RENDERER_COMMON_RENDER_GROUP_SYMBOLIZER_HPP

View file

@ -0,0 +1,76 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2016 Artem Pavlenko
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*****************************************************************************/
#ifndef MAPNIK_RENDERER_COMMON_RENDER_MARKERS_SYMBOLIZER_HPP
#define MAPNIK_RENDERER_COMMON_RENDER_MARKERS_SYMBOLIZER_HPP
#include <mapnik/marker.hpp>
#include <mapnik/markers_placement.hpp>
#include <mapnik/renderer_common.hpp>
#include <mapnik/symbolizer_base.hpp>
namespace mapnik {
struct markers_dispatch_params
{
// placement
markers_placement_params placement_params;
marker_placement_enum placement_method;
value_bool ignore_placement;
// rendering
bool snap_to_pixels;
double scale_factor;
value_double opacity;
markers_dispatch_params(box2d<double> const& size,
agg::trans_affine const& tr,
symbolizer_base const& sym,
feature_impl const& feature,
attributes const& vars,
double scale_factor = 1.0,
bool snap_to_pixels = false);
};
struct markers_renderer_context : util::noncopyable
{
virtual void render_marker(image_rgba8 const& src,
markers_dispatch_params const& params,
agg::trans_affine const& marker_tr) = 0;
virtual void render_marker(svg_path_ptr const& src,
svg_path_adapter & path,
svg_attribute_type const& attrs,
markers_dispatch_params const& params,
agg::trans_affine const& marker_tr) = 0;
};
MAPNIK_DECL
void render_markers_symbolizer(markers_symbolizer const& sym,
mapnik::feature_impl & feature,
proj_transform const& prj_trans,
renderer_common const& common,
box2d<double> const& clip_box,
markers_renderer_context & renderer_context);
} // namespace mapnik
#endif // MAPNIK_RENDERER_COMMON_RENDER_MARKERS_SYMBOLIZER_HPP

View file

@ -0,0 +1,115 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2016 Artem Pavlenko
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*****************************************************************************/
#ifndef MAPNIK_RENDERER_COMMON_RENDER_THUNK_HPP
#define MAPNIK_RENDERER_COMMON_RENDER_THUNK_HPP
// mapnik
#include <mapnik/image_compositing.hpp> // composite_mode_e
#include <mapnik/marker.hpp> // svg_attribute_type, svg_path_ptr
#include <mapnik/symbolizer_enumerations.hpp> // halo_rasterizer_enum
#include <mapnik/svg/svg_path_attributes.hpp>
#include <mapnik/text/symbolizer_helpers.hpp>
#include <mapnik/util/noncopyable.hpp>
#include <mapnik/util/variant.hpp>
// agg
#include <agg_trans_affine.h>
namespace mapnik {
// Thunk for rendering a particular instance of a point - this
// stores all the arguments necessary to re-render this point
// symbolizer at a later time.
struct vector_marker_render_thunk : util::movable
{
svg_path_ptr src_;
svg_attribute_type attrs_;
agg::trans_affine tr_;
double opacity_;
composite_mode_e comp_op_;
bool snap_to_pixels_;
vector_marker_render_thunk(svg_path_ptr const& src,
svg_attribute_type const& attrs,
agg::trans_affine const& marker_trans,
double opacity,
composite_mode_e comp_op,
bool snap_to_pixels)
: src_(src), attrs_(attrs), tr_(marker_trans), opacity_(opacity),
comp_op_(comp_op), snap_to_pixels_(snap_to_pixels)
{}
};
struct raster_marker_render_thunk : util::movable
{
image_rgba8 const& src_;
agg::trans_affine tr_;
double opacity_;
composite_mode_e comp_op_;
bool snap_to_pixels_;
raster_marker_render_thunk(image_rgba8 const& src,
agg::trans_affine const& marker_trans,
double opacity,
composite_mode_e comp_op,
bool snap_to_pixels)
: src_(src), tr_(marker_trans), opacity_(opacity), comp_op_(comp_op),
snap_to_pixels_(snap_to_pixels)
{}
};
struct text_render_thunk : util::movable
{
using helper_ptr = std::unique_ptr<text_symbolizer_helper>;
// helper is stored here in order
// to keep in scope the text rendering structures
helper_ptr helper_;
placements_list const& placements_;
double opacity_;
composite_mode_e comp_op_;
halo_rasterizer_enum halo_rasterizer_;
text_render_thunk(helper_ptr && helper,
double opacity, composite_mode_e comp_op,
halo_rasterizer_enum halo_rasterizer)
: helper_(std::move(helper)),
placements_(helper_->get()),
opacity_(opacity),
comp_op_(comp_op),
halo_rasterizer_(halo_rasterizer)
{}
};
// Variant type for render thunks to allow us to re-render them
// via a static visitor later.
using render_thunk = util::variant<vector_marker_render_thunk,
raster_marker_render_thunk,
text_render_thunk>;
using render_thunk_ptr = std::unique_ptr<render_thunk>;
using render_thunk_list = std::list<render_thunk_ptr>;
} // namespace mapnik
#endif // MAPNIK_RENDERER_COMMON_RENDER_THUNK_HPP

View file

@ -0,0 +1,97 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2016 Artem Pavlenko
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*****************************************************************************/
#ifndef MAPNIK_RENDERER_COMMON_RENDER_THUNK_EXTRACTOR_HPP
#define MAPNIK_RENDERER_COMMON_RENDER_THUNK_EXTRACTOR_HPP
// mapnik
#include <mapnik/renderer_common.hpp>
#include <mapnik/renderer_common/render_thunk.hpp>
#include <mapnik/symbolizer_base.hpp>
#include <mapnik/util/noncopyable.hpp>
namespace mapnik {
// The approach here is to run the normal symbolizers, but in
// a 'virtual' blank environment where the changes that they
// make are recorded (the detector, the render_* calls).
//
// The recorded boxes are then used to lay out the items and
// the offsets from old to new positions can be used to perform
// the actual rendering calls.
// This should allow us to re-use as much as possible of the
// existing symbolizer layout and rendering code while still
// being able to interpose our own decisions about whether
// a collision has occurred or not.
struct virtual_renderer_common : renderer_common
{
explicit virtual_renderer_common(renderer_common const& other);
};
// Base class for extracting the bounding boxes associated with placing
// a symbolizer at a fake, virtual point - not real geometry.
//
// The bounding boxes can be used for layout, and the thunks are
// used to re-render at locations according to the group layout.
struct render_thunk_extractor
{
render_thunk_extractor(box2d<double> & box,
render_thunk_list & thunks,
feature_impl & feature,
attributes const& vars,
proj_transform const& prj_trans,
virtual_renderer_common & common,
box2d<double> const& clipping_extent);
void operator()(markers_symbolizer const& sym) const;
void operator()(text_symbolizer const& sym) const;
void operator()(shield_symbolizer const& sym) const;
template <typename T>
void operator()(T const& ) const
{
// TODO: warning if unimplemented?
}
private:
void extract_text_thunk(text_render_thunk::helper_ptr && helper,
text_symbolizer const& sym) const;
box2d<double> & box_;
render_thunk_list & thunks_;
feature_impl & feature_;
attributes const& vars_;
proj_transform const& prj_trans_;
virtual_renderer_common & common_;
box2d<double> clipping_extent_;
void update_box() const;
};
} // namespace mapnik
#endif // MAPNIK_RENDERER_COMMON_RENDER_THUNK_EXTRACTOR_HPP

View file

@ -19,8 +19,10 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*****************************************************************************/
#ifndef MAPNIK_PLACEMENTS_LIST_HPP
#define MAPNIK_PLACEMENTS_LIST_HPP
#ifndef MAPNIK_TEXT_GLYPH_POSITIONS_HPP
#define MAPNIK_TEXT_GLYPH_POSITIONS_HPP
//mapnik
#include <mapnik/box2d.hpp>
#include <mapnik/pixel_position.hpp>
@ -79,7 +81,7 @@ public:
pixel_position const& get_base_point() const;
void set_base_point(pixel_position const& base_point);
void set_marker(marker_info_ptr marker, pixel_position const& marker_pos);
marker_info_ptr get_marker() const;
marker_info_ptr const& get_marker() const;
pixel_position const& marker_pos() const;
private:
std::vector<glyph_position> data_;
@ -88,8 +90,46 @@ private:
pixel_position marker_pos_;
box2d<double> bbox_;
};
using glyph_positions_ptr = std::unique_ptr<glyph_positions>;
using placements_list = std::list<glyph_positions_ptr>;
struct scoped_glyph_positions_offset
{
scoped_glyph_positions_offset(glyph_positions & glyphs, pixel_position const& offset)
: glyphs_(glyphs)
, base_point_(glyphs.get_base_point())
, marker_pos_(glyphs.marker_pos())
{
// move the glyphs to the correct offset
glyphs_.set_base_point(base_point_ + offset);
// update the position of any marker
if (auto const& marker_info = glyphs_.get_marker())
{
glyphs_.set_marker(marker_info, marker_pos_ + offset);
}
#endif // PLACEMENTS_LIST_HPP
}
~scoped_glyph_positions_offset()
{
// set the base_point back how it was
glyphs_.set_base_point(base_point_);
// restore marker as well, if there is any
if (auto const& marker_info = glyphs_.get_marker())
{
glyphs_.set_marker(marker_info, marker_pos_);
}
}
private:
glyph_positions & glyphs_;
pixel_position base_point_;
pixel_position marker_pos_;
};
} // namespace mapnik
#endif // MAPNIK_TEXT_GLYPH_POSITIONS_HPP

View file

@ -58,8 +58,35 @@ public:
composite_mode_e halo_comp_op = src_over,
double scale_factor = 1.0,
stroker_ptr stroker = stroker_ptr());
void set_comp_op(composite_mode_e comp_op)
{
comp_op_ = comp_op;
}
void set_halo_comp_op(composite_mode_e halo_comp_op)
{
halo_comp_op_ = halo_comp_op;
}
void set_halo_rasterizer(halo_rasterizer_e rasterizer)
{
rasterizer_ = rasterizer;
}
void set_scale_factor(double scale_factor)
{
scale_factor_ = scale_factor;
}
void set_stroker(stroker_ptr stroker)
{
stroker_ = stroker;
}
void set_transform(agg::trans_affine const& transform);
void set_halo_transform(agg::trans_affine const& halo_transform);
protected:
using glyph_vector = std::vector<glyph_t>;
void prepare_glyphs(glyph_positions const& positions);

View file

@ -25,20 +25,16 @@
#include <mapnik/agg_renderer.hpp>
#include <mapnik/agg_rasterizer.hpp>
#include <mapnik/agg_render_marker.hpp>
#include <mapnik/image_util.hpp>
#include <mapnik/image.hpp>
#include <mapnik/util/variant.hpp>
#include <mapnik/text/renderer.hpp>
#include <mapnik/geom_util.hpp>
#include <mapnik/symbolizer.hpp>
#include <mapnik/pixel_position.hpp>
#include <mapnik/text/glyph_positions.hpp>
#include <mapnik/renderer_common/process_group_symbolizer.hpp>
#include <mapnik/renderer_common/clipping_extent.hpp>
#include <mapnik/renderer_common/render_group_symbolizer.hpp>
#include <mapnik/svg/svg_renderer_agg.hpp>
#include <mapnik/svg/svg_path_attributes.hpp>
#include <mapnik/svg/svg_path_adapter.hpp>
#include <mapnik/svg/svg_converter.hpp>
// agg
#include "agg_trans_affine.h"
@ -55,7 +51,7 @@ template <typename T>
struct thunk_renderer;
template <>
struct thunk_renderer<image_rgba8>
struct thunk_renderer<image_rgba8> : render_thunk_list_dispatch
{
using renderer_type = agg_renderer<image_rgba8>;
using buffer_type = renderer_type::buffer_type;
@ -64,12 +60,13 @@ struct thunk_renderer<image_rgba8>
thunk_renderer(renderer_type &ren,
std::unique_ptr<rasterizer> const& ras_ptr,
buffer_type *buf,
renderer_common &common,
pixel_position const &offset)
: ren_(ren), ras_ptr_(ras_ptr), buf_(buf), common_(common), offset_(offset)
renderer_common &common)
: ren_(ren), ras_ptr_(ras_ptr), buf_(buf), common_(common),
tex_(*buf, HALO_RASTERIZER_FULL, src_over, src_over,
common.scale_factor_, common.font_manager_.get_stroker())
{}
void operator()(vector_marker_render_thunk const &thunk) const
virtual void operator()(vector_marker_render_thunk const& thunk)
{
using blender_type = agg::comp_op_adaptor_rgba_pre<agg::rgba8, agg::order_rgba>; // comp blender
using buf_type = agg::rendering_buffer;
@ -95,7 +92,7 @@ struct thunk_renderer<image_rgba8>
render_vector_marker(svg_renderer, *ras_ptr_, renb, thunk.src_->bounding_box(), offset_tr, thunk.opacity_, thunk.snap_to_pixels_);
}
void operator()(raster_marker_render_thunk const &thunk) const
virtual void operator()(raster_marker_render_thunk const& thunk)
{
using blender_type = agg::comp_op_adaptor_rgba_pre<agg::rgba8, agg::order_rgba>; // comp blender
using buf_type = agg::rendering_buffer;
@ -113,32 +110,25 @@ struct thunk_renderer<image_rgba8>
render_raster_marker(renb, *ras_ptr_, thunk.src_, offset_tr, thunk.opacity_, common_.scale_factor_, thunk.snap_to_pixels_);
}
void operator()(text_render_thunk const &thunk) const
virtual void operator()(text_render_thunk const& thunk)
{
text_renderer_type ren(*buf_, thunk.halo_rasterizer_, thunk.comp_op_, thunk.comp_op_,
common_.scale_factor_, common_.font_manager_.get_stroker());
tex_.set_comp_op(thunk.comp_op_);
tex_.set_halo_comp_op(thunk.comp_op_);
tex_.set_halo_rasterizer(thunk.halo_rasterizer_);
render_offset_placements(
thunk.placements_,
offset_,
[&] (glyph_positions_ptr const& glyphs)
for (auto const& glyphs : thunk.placements_)
{
marker_info_ptr mark = glyphs->get_marker();
if (mark)
scoped_glyph_positions_offset tmp_off(*glyphs, offset_);
if (auto const& mark = glyphs->get_marker())
{
ren_.render_marker(glyphs->marker_pos(),
*mark->marker_,
mark->transform_,
thunk.opacity_, thunk.comp_op_);
}
ren.render(*glyphs);
});
tex_.render(*glyphs);
}
template <typename T>
void operator()(T const &) const
{
throw std::runtime_error("Rendering of this data type is not supported currently by the renderer");
}
private:
@ -146,7 +136,7 @@ private:
std::unique_ptr<rasterizer> const& ras_ptr_;
buffer_type *buf_;
renderer_common &common_;
pixel_position offset_;
text_renderer_type tex_;
};
template <typename T0, typename T1>
@ -154,16 +144,11 @@ void agg_renderer<T0,T1>::process(group_symbolizer const& sym,
mapnik::feature_impl & feature,
proj_transform const& prj_trans)
{
thunk_renderer<buffer_type> ren(*this, ras_ptr, current_buffer_, common_);
render_group_symbolizer(
sym, feature, common_.vars_, prj_trans, clipping_extent(common_), common_,
[&](render_thunk_list const& thunks, pixel_position const& render_offset)
{
thunk_renderer<buffer_type> ren(*this, ras_ptr, current_buffer_, common_, render_offset);
for (render_thunk_ptr const& thunk : thunks)
{
util::apply_visitor(ren, *thunk);
}
});
ren);
}
template void agg_renderer<image_rgba8>::process(group_symbolizer const&,

View file

@ -24,22 +24,15 @@
#include <mapnik/agg_helpers.hpp>
#include <mapnik/agg_renderer.hpp>
#include <mapnik/agg_rasterizer.hpp>
#include <mapnik/debug.hpp>
#include <mapnik/feature.hpp>
#include <mapnik/geom_util.hpp>
#include <mapnik/marker_helpers.hpp>
#include <mapnik/marker.hpp>
#include <mapnik/marker_cache.hpp>
#include <mapnik/agg_render_marker.hpp>
#include <mapnik/svg/svg_renderer_agg.hpp>
#include <mapnik/svg/svg_storage.hpp>
#include <mapnik/svg/svg_path_adapter.hpp>
#include <mapnik/svg/svg_path_attributes.hpp>
#include <mapnik/symbolizer.hpp>
#include <mapnik/parse_path.hpp>
#include <mapnik/renderer_common/process_markers_symbolizer.hpp>
#include <mapnik/renderer_common/clipping_extent.hpp>
#include <mapnik/renderer_common/render_markers_symbolizer.hpp>
// agg
#include "agg_basics.h"
#include "agg_renderer_base.h"
@ -52,114 +45,62 @@
#include "agg_path_storage.h"
#include "agg_conv_transform.h"
// boost
#include <boost/optional.hpp>
namespace mapnik {
namespace detail {
template <typename SvgRenderer, typename Detector, typename RendererContext>
struct vector_markers_rasterizer_dispatch : public vector_markers_dispatch<Detector>
template <typename SvgRenderer, typename BufferType, typename RasterizerType>
struct agg_markers_renderer_context : markers_renderer_context
{
using renderer_base = typename SvgRenderer::renderer_base;
using vertex_source_type = typename SvgRenderer::vertex_source_type;
using attribute_source_type = typename SvgRenderer::attribute_source_type;
using pixfmt_type = typename renderer_base::pixfmt_type;
using BufferType = typename std::tuple_element<0,RendererContext>::type;
using RasterizerType = typename std::tuple_element<1,RendererContext>::type;
vector_markers_rasterizer_dispatch(svg_path_ptr const& src,
vertex_source_type & path,
svg_attribute_type const& attrs,
agg::trans_affine const& marker_trans,
symbolizer_base const& sym,
Detector & detector,
double scale_factor,
feature_impl & feature,
agg_markers_renderer_context(symbolizer_base const& sym,
feature_impl const& feature,
attributes const& vars,
bool snap_to_pixels,
RendererContext const& renderer_context)
: vector_markers_dispatch<Detector>(src, marker_trans, sym, detector, scale_factor, feature, vars),
buf_(std::get<0>(renderer_context)),
BufferType & buf,
RasterizerType & ras)
: buf_(buf),
pixf_(buf_),
renb_(pixf_),
svg_renderer_(path, attrs),
ras_(std::get<1>(renderer_context)),
snap_to_pixels_(snap_to_pixels)
ras_(ras)
{
pixf_.comp_op(static_cast<agg::comp_op_e>(get<composite_mode_e, keys::comp_op>(sym, feature, vars)));
auto comp_op = get<composite_mode_e, keys::comp_op>(sym, feature, vars);
pixf_.comp_op(static_cast<agg::comp_op_e>(comp_op));
}
~vector_markers_rasterizer_dispatch() {}
void render_marker(agg::trans_affine const& marker_tr, double opacity)
virtual void render_marker(svg_path_ptr const& src,
svg_path_adapter & path,
svg_attribute_type const& attrs,
markers_dispatch_params const& params,
agg::trans_affine const& marker_tr)
{
render_vector_marker(svg_renderer_, ras_, renb_, this->src_->bounding_box(),
marker_tr, opacity, snap_to_pixels_);
SvgRenderer svg_renderer(path, attrs);
render_vector_marker(svg_renderer, ras_, renb_, src->bounding_box(),
marker_tr, params.opacity, params.snap_to_pixels);
}
virtual void render_marker(image_rgba8 const& src,
markers_dispatch_params const& params,
agg::trans_affine const& marker_tr)
{
// In the long term this should be a visitor pattern based on the type of
// render src provided that converts the destination pixel type required.
render_raster_marker(renb_, ras_, src, marker_tr, params.opacity,
params.scale_factor, params.snap_to_pixels);
}
private:
BufferType & buf_;
pixfmt_type pixf_;
renderer_base renb_;
SvgRenderer svg_renderer_;
RasterizerType & ras_;
bool snap_to_pixels_;
};
template <typename Detector, typename RendererContext>
struct raster_markers_rasterizer_dispatch : public raster_markers_dispatch<Detector>
{
using BufferType = typename std::remove_reference<typename std::tuple_element<0,RendererContext>::type>::type;
using RasterizerType = typename std::tuple_element<1,RendererContext>::type;
using color_type = agg::rgba8;
using order_type = agg::order_rgba;
using pixel_type = agg::pixel32_type;
using blender_type = agg::comp_op_adaptor_rgba_pre<color_type, order_type>; // comp blender
using pixfmt_comp_type = agg::pixfmt_custom_blend_rgba<blender_type, BufferType>;
using renderer_base = agg::renderer_base<pixfmt_comp_type>;
raster_markers_rasterizer_dispatch(image_rgba8 const& src,
agg::trans_affine const& marker_trans,
symbolizer_base const& sym,
Detector & detector,
double scale_factor,
feature_impl & feature,
attributes const& vars,
RendererContext const& renderer_context,
bool snap_to_pixels = false)
: raster_markers_dispatch<Detector>(src, marker_trans, sym, detector, scale_factor, feature, vars),
buf_(std::get<0>(renderer_context)),
pixf_(buf_),
renb_(pixf_),
ras_(std::get<1>(renderer_context)),
snap_to_pixels_(snap_to_pixels)
{
pixf_.comp_op(static_cast<agg::comp_op_e>(get<composite_mode_e, keys::comp_op>(sym, feature, vars)));
}
~raster_markers_rasterizer_dispatch() {}
void render_marker(agg::trans_affine const& marker_tr, double opacity)
{
// In the long term this should be a visitor pattern based on the type of render this->src_ provided that converts
// the destination pixel type required.
render_raster_marker(renb_, ras_, this->src_, marker_tr, opacity, this->scale_factor_, snap_to_pixels_);
}
private:
BufferType & buf_;
pixfmt_comp_type pixf_;
renderer_base renb_;
RasterizerType & ras_;
bool snap_to_pixels_;
};
}
} // namespace detail
template <typename T0, typename T1>
void agg_renderer<T0,T1>::process(markers_symbolizer const& sym,
@ -194,16 +135,16 @@ void agg_renderer<T0,T1>::process(markers_symbolizer const& sym,
buf_type render_buffer(current_buffer_->bytes(), current_buffer_->width(), current_buffer_->height(), current_buffer_->row_size());
box2d<double> clip_box = clipping_extent(common_);
auto renderer_context = std::tie(render_buffer,*ras_ptr,pixmap_);
using markers_context_type = decltype(renderer_context);
using vector_dispatch_type = detail::vector_markers_rasterizer_dispatch<svg_renderer_type, detector_type, markers_context_type>;
using raster_dispatch_type = detail::raster_markers_rasterizer_dispatch<detector_type, markers_context_type>;
using context_type = detail::agg_markers_renderer_context<svg_renderer_type,
buf_type,
rasterizer>;
context_type renderer_context(sym, feature, common_.vars_, render_buffer, *ras_ptr);
render_markers_symbolizer<vector_dispatch_type, raster_dispatch_type>(
render_markers_symbolizer(
sym, feature, prj_trans, common_, clip_box, renderer_context);
}
template void agg_renderer<image_rgba8>::process(markers_symbolizer const&,
mapnik::feature_impl &,
proj_transform const&);
}
} // namespace mapnik

View file

@ -30,7 +30,6 @@
#include <mapnik/symbolizer.hpp>
#include <mapnik/marker.hpp>
#include <mapnik/marker_cache.hpp>
#include <mapnik/label_collision_detector.hpp>
#include <mapnik/parse_path.hpp>
#include <mapnik/pixel_position.hpp>
#include <mapnik/renderer_common/process_point_symbolizer.hpp>

View file

@ -253,8 +253,10 @@ source = Split(
config_error.cpp
color_factory.cpp
renderer_common.cpp
renderer_common/render_group_symbolizer.cpp
renderer_common/render_markers_symbolizer.cpp
renderer_common/render_pattern.cpp
renderer_common/process_group_symbolizer.cpp
renderer_common/render_thunk_extractor.cpp
math.cpp
"""
)

View file

@ -25,13 +25,12 @@
// mapnik
#include <mapnik/marker.hpp>
#include <mapnik/svg/svg_path_adapter.hpp>
#include <mapnik/make_unique.hpp>
#include <mapnik/text/glyph_positions.hpp>
#include <mapnik/cairo/cairo_renderer.hpp>
#include <mapnik/cairo/cairo_render_vector.hpp>
// mapnik symbolizer generics
#include <mapnik/renderer_common/process_group_symbolizer.hpp>
#include <mapnik/renderer_common/render_group_symbolizer.hpp>
namespace mapnik
{
@ -47,20 +46,19 @@ namespace {
// to render it, and the boxes themselves should already be
// in the detector from the placement_finder.
template <typename T>
struct thunk_renderer
struct thunk_renderer : render_thunk_list_dispatch
{
using renderer_type = cairo_renderer<T>;
thunk_renderer(renderer_type & ren,
cairo_context & context,
cairo_face_manager & face_manager,
renderer_common & common,
pixel_position const& offset)
renderer_common & common)
: ren_(ren), context_(context), face_manager_(face_manager),
common_(common), offset_(offset)
common_(common)
{}
void operator()(vector_marker_render_thunk const &thunk) const
virtual void operator()(vector_marker_render_thunk const& thunk)
{
cairo_save_restore guard(context_);
context_.set_operator(thunk.comp_op_);
@ -78,7 +76,7 @@ struct thunk_renderer
thunk.opacity_);
}
void operator()(raster_marker_render_thunk const& thunk) const
virtual void operator()(raster_marker_render_thunk const& thunk)
{
cairo_save_restore guard(context_);
context_.set_operator(thunk.comp_op_);
@ -88,18 +86,16 @@ struct thunk_renderer
context_.add_image(offset_tr, thunk.src_, thunk.opacity_);
}
void operator()(text_render_thunk const &thunk) const
virtual void operator()(text_render_thunk const& thunk)
{
cairo_save_restore guard(context_);
context_.set_operator(thunk.comp_op_);
render_offset_placements(
thunk.placements_,
offset_,
[&] (glyph_positions_ptr const& glyphs)
for (auto const& glyphs : thunk.placements_)
{
marker_info_ptr mark = glyphs->get_marker();
if (mark)
scoped_glyph_positions_offset tmp_off(*glyphs, offset_);
if (auto const& mark = glyphs->get_marker())
{
ren_.render_marker(glyphs->marker_pos(),
*mark->marker_,
@ -107,13 +103,7 @@ struct thunk_renderer
thunk.opacity_, thunk.comp_op_);
}
context_.add_text(*glyphs, face_manager_, src_over, src_over, common_.scale_factor_);
});
}
template <typename T0>
void operator()(T0 const &) const
{
throw std::runtime_error("Rendering of this type is not supported by the cairo renderer.");
}
private:
@ -121,7 +111,6 @@ private:
cairo_context & context_;
cairo_face_manager & face_manager_;
renderer_common & common_;
pixel_position offset_;
};
} // anonymous namespace
@ -131,16 +120,11 @@ void cairo_renderer<T>::process(group_symbolizer const& sym,
mapnik::feature_impl & feature,
proj_transform const& prj_trans)
{
thunk_renderer<T> ren(*this, context_, face_manager_, common_);
render_group_symbolizer(
sym, feature, common_.vars_, prj_trans, common_.query_extent_, common_,
[&](render_thunk_list const& thunks, pixel_position const& render_offset)
{
thunk_renderer<T> ren(*this, context_, face_manager_, common_, render_offset);
for (render_thunk_ptr const& thunk : thunks)
{
util::apply_visitor(ren, *thunk);
}
});
ren);
}
template void cairo_renderer<cairo_ptr>::process(group_symbolizer const&,

View file

@ -25,90 +25,46 @@
// mapnik
#include <mapnik/cairo/cairo_renderer.hpp>
#include <mapnik/cairo/cairo_render_vector.hpp>
#include <mapnik/markers_placement.hpp>
#include <mapnik/svg/svg_path_adapter.hpp>
#include <mapnik/util/noncopyable.hpp>
#include <mapnik/pixel_position.hpp>
#include <mapnik/attribute.hpp>
#include <mapnik/marker.hpp>
#include <mapnik/marker_cache.hpp>
#include <mapnik/marker_helpers.hpp>
#include <mapnik/renderer_common/process_markers_symbolizer.hpp>
// agg
#include "agg/include/agg_array.h" // for pod_bvector
#include "agg/include/agg_trans_affine.h" // for trans_affine, etc
#include <mapnik/renderer_common/render_markers_symbolizer.hpp>
#include <mapnik/symbolizer.hpp>
namespace mapnik
{
class feature_impl;
class proj_transform;
namespace detail {
template <typename RendererContext, typename Detector>
struct vector_markers_dispatch_cairo : public vector_markers_dispatch<Detector>
struct cairo_markers_renderer_context : markers_renderer_context
{
vector_markers_dispatch_cairo(svg_path_ptr const& src,
svg::svg_path_adapter & path,
svg_attribute_type const& attrs,
agg::trans_affine const& marker_trans,
markers_symbolizer const& sym,
Detector & detector,
double scale_factor,
feature_impl & feature,
mapnik::attributes const& vars,
bool /* snap_to_pixels */, // only used in agg renderer currently
RendererContext const& renderer_context)
: vector_markers_dispatch<Detector>(src, marker_trans, sym, detector, scale_factor, feature, vars),
path_(path),
attr_(attrs),
ctx_(std::get<0>(renderer_context))
explicit cairo_markers_renderer_context(cairo_context & ctx)
: ctx_(ctx)
{}
void render_marker(agg::trans_affine const& marker_tr, double opacity)
virtual void render_marker(svg_path_ptr const& src,
svg_path_adapter & path,
svg_attribute_type const& attrs,
markers_dispatch_params const& params,
agg::trans_affine const& marker_tr)
{
render_vector_marker(ctx_,
path_,
attr_,
this->src_->bounding_box(),
path,
attrs,
src->bounding_box(),
marker_tr,
opacity);
params.opacity);
}
private:
svg::svg_path_adapter & path_;
svg_attribute_type const& attr_;
cairo_context & ctx_;
};
template <typename RendererContext, typename Detector>
struct raster_markers_dispatch_cairo : public raster_markers_dispatch<Detector>
virtual void render_marker(image_rgba8 const& src,
markers_dispatch_params const& params,
agg::trans_affine const& marker_tr)
{
raster_markers_dispatch_cairo(image_rgba8 const& src,
agg::trans_affine const& marker_trans,
markers_symbolizer const& sym,
Detector & detector,
double scale_factor,
feature_impl & feature,
mapnik::attributes const& vars,
RendererContext const& renderer_context)
: raster_markers_dispatch<Detector>(src, marker_trans, sym, detector, scale_factor, feature, vars),
ctx_(std::get<0>(renderer_context)) {}
~raster_markers_dispatch_cairo() {}
void render_marker(agg::trans_affine const& marker_tr, double opacity)
{
ctx_.add_image(marker_tr, this->src_, opacity);
ctx_.add_image(marker_tr, src, params.opacity);
}
private:
cairo_context & ctx_;
};
}
} // namespace detail
template <typename T>
void cairo_renderer<T>::process(markers_symbolizer const& sym,
@ -120,17 +76,10 @@ void cairo_renderer<T>::process(markers_symbolizer const& sym,
context_.set_operator(comp_op);
box2d<double> clip_box = common_.query_extent_;
auto renderer_context = std::tie(context_);
using context_type = detail::cairo_markers_renderer_context;
context_type renderer_context(context_);
using RendererContextType = decltype(renderer_context);
using vector_dispatch_type = detail::vector_markers_dispatch_cairo<RendererContextType,
label_collision_detector4>;
using raster_dispatch_type = detail::raster_markers_dispatch_cairo<RendererContextType,
label_collision_detector4>;
render_markers_symbolizer<vector_dispatch_type, raster_dispatch_type>(
render_markers_symbolizer(
sym, feature, prj_trans, common_, clip_box,
renderer_context);
}
@ -139,6 +88,6 @@ template void cairo_renderer<cairo_ptr>::process(markers_symbolizer const&,
mapnik::feature_impl &,
proj_transform const&);
}
} // namespace mapnik
#endif // HAVE_CAIRO

View file

@ -361,7 +361,7 @@ face_ptr freetype_engine::create_face(std::string const& family_name,
face_manager::face_manager(font_library & library,
freetype_engine::font_file_mapping_type const& font_file_mapping,
freetype_engine::font_memory_cache_type const& font_cache)
: face_ptr_cache_(),
: face_cache_(new face_cache()),
library_(library),
font_file_mapping_(font_file_mapping),
font_memory_cache_(font_cache)
@ -376,8 +376,8 @@ face_manager::face_manager(font_library & library,
face_ptr face_manager::get_face(std::string const& name)
{
auto itr = face_ptr_cache_.find(name);
if (itr != face_ptr_cache_.end())
auto itr = face_cache_->find(name);
if (itr != face_cache_->end())
{
return itr->second;
}
@ -391,7 +391,7 @@ face_ptr face_manager::get_face(std::string const& name)
freetype_engine::get_cache());
if (face)
{
face_ptr_cache_.emplace(name,face);
face_cache_->emplace(name, face);
}
return face;
}

View file

@ -29,25 +29,13 @@
#include <mapnik/grid/grid_renderer_base.hpp>
#include <mapnik/grid/grid.hpp>
#include <mapnik/grid/grid_render_marker.hpp>
#include <mapnik/attribute_collector.hpp>
#include <mapnik/text/placement_finder.hpp>
#include <mapnik/text/symbolizer_helpers.hpp>
#include <mapnik/text/renderer.hpp>
#include <mapnik/text/glyph_positions.hpp>
#include <mapnik/svg/svg_renderer_agg.hpp>
#include <mapnik/svg/svg_storage.hpp>
#include <mapnik/svg/svg_path_adapter.hpp>
#include <mapnik/svg/svg_path_attributes.hpp>
#include <mapnik/group/group_layout_manager.hpp>
#include <mapnik/group/group_symbolizer_helper.hpp>
#include <mapnik/util/variant.hpp>
#include <mapnik/geom_util.hpp>
#include <mapnik/pixel_position.hpp>
#include <mapnik/label_collision_detector.hpp>
#include <mapnik/geom_util.hpp>
#include <mapnik/renderer_common/process_point_symbolizer.hpp>
#include <mapnik/renderer_common/process_group_symbolizer.hpp>
#include <mapnik/renderer_common/render_group_symbolizer.hpp>
// agg
#include "agg_trans_affine.h"
@ -61,7 +49,7 @@ namespace mapnik {
* in the detector from the placement_finder.
*/
template <typename T0>
struct thunk_renderer
struct thunk_renderer : render_thunk_list_dispatch
{
using renderer_type = grid_renderer<T0>;
using buffer_type = typename renderer_type::buffer_type;
@ -71,13 +59,13 @@ struct thunk_renderer
grid_rasterizer &ras,
buffer_type &pixmap,
renderer_common &common,
feature_impl &feature,
pixel_position const &offset)
feature_impl &feature)
: ren_(ren), ras_(ras), pixmap_(pixmap),
common_(common), feature_(feature), offset_(offset)
common_(common), feature_(feature),
tex_(pixmap, src_over, common.scale_factor_)
{}
void operator()(vector_marker_render_thunk const &thunk) const
virtual void operator()(vector_marker_render_thunk const& thunk)
{
using buf_type = grid_rendering_buffer;
using pixfmt_type = typename grid_renderer_base_type::pixfmt_type;
@ -106,7 +94,7 @@ struct thunk_renderer
pixmap_.add_feature(feature_);
}
void operator()(raster_marker_render_thunk const &thunk) const
virtual void operator()(raster_marker_render_thunk const& thunk)
{
using buf_type = grid_rendering_buffer;
using pixfmt_type = typename grid_renderer_base_type::pixfmt_type;
@ -122,18 +110,17 @@ struct thunk_renderer
pixmap_.add_feature(feature_);
}
void operator()(text_render_thunk const &thunk) const
virtual void operator()(text_render_thunk const &thunk)
{
text_renderer_type ren(pixmap_, thunk.comp_op_, common_.scale_factor_);
tex_.set_comp_op(thunk.comp_op_);
value_integer feature_id = feature_.id();
render_offset_placements(
thunk.placements_,
offset_,
[&] (glyph_positions_ptr const& glyphs)
for (auto const& glyphs : thunk.placements_)
{
marker_info_ptr mark = glyphs->get_marker();
if (mark)
scoped_glyph_positions_offset tmp_off(*glyphs, offset_);
if (auto const& mark = glyphs->get_marker())
{
ren_.render_marker(feature_,
glyphs->marker_pos(),
@ -141,15 +128,10 @@ struct thunk_renderer
mark->transform_,
thunk.opacity_, thunk.comp_op_);
}
ren.render(*glyphs, feature_id);
});
pixmap_.add_feature(feature_);
tex_.render(*glyphs, feature_id);
}
template <typename T1>
void operator()(T1 const &) const
{
// TODO: warning if unimplemented?
pixmap_.add_feature(feature_);
}
private:
@ -158,7 +140,7 @@ private:
buffer_type &pixmap_;
renderer_common &common_;
feature_impl &feature_;
pixel_position offset_;
text_renderer_type tex_;
};
template <typename T>
@ -166,16 +148,11 @@ void grid_renderer<T>::process(group_symbolizer const& sym,
mapnik::feature_impl & feature,
proj_transform const& prj_trans)
{
thunk_renderer<T> ren(*this, *ras_ptr, pixmap_, common_, feature);
render_group_symbolizer(
sym, feature, common_.vars_, prj_trans, common_.query_extent_, common_,
[&](render_thunk_list const& thunks, pixel_position const& render_offset)
{
thunk_renderer<T> ren(*this, *ras_ptr, pixmap_, common_, feature, render_offset);
for (render_thunk_ptr const& thunk : thunks)
{
util::apply_visitor(ren, *thunk);
}
});
ren);
}
template void grid_renderer<grid>::process(group_symbolizer const&,

View file

@ -44,146 +44,92 @@ porting notes -->
*/
// mapnik
#include <mapnik/feature.hpp>
#include <mapnik/geom_util.hpp>
#include <mapnik/marker_helpers.hpp>
#include <mapnik/grid/grid_rasterizer.hpp>
#include <mapnik/grid/grid_renderer.hpp>
#include <mapnik/grid/grid_renderer_base.hpp>
#include <mapnik/grid/grid_render_marker.hpp>
#include <mapnik/grid/grid.hpp>
#include <mapnik/debug.hpp>
#include <mapnik/geom_util.hpp>
#include <mapnik/marker.hpp>
#include <mapnik/marker_cache.hpp>
#include <mapnik/marker_helpers.hpp>
#include <mapnik/svg/svg_renderer_agg.hpp>
#include <mapnik/svg/svg_storage.hpp>
#include <mapnik/svg/svg_path_adapter.hpp>
#include <mapnik/svg/svg_path_attributes.hpp>
#include <mapnik/parse_path.hpp>
#include <mapnik/renderer_common/process_markers_symbolizer.hpp>
#include <mapnik/renderer_common/render_markers_symbolizer.hpp>
// agg
#include "agg_basics.h"
#include "agg_rendering_buffer.h"
#include "agg_rasterizer_scanline_aa.h"
// boost
#include <boost/optional.hpp>
// stl
#include <algorithm>
#include <tuple>
namespace mapnik {
namespace detail {
template <typename SvgRenderer, typename Detector, typename RendererContext>
struct vector_markers_rasterizer_dispatch : public vector_markers_dispatch<Detector>
template <typename SvgRenderer, typename ScanlineRenderer,
typename BufferType, typename RasterizerType, typename PixMapType>
struct grid_markers_renderer_context : markers_renderer_context
{
using renderer_base = typename SvgRenderer::renderer_base;
using vertex_source_type = typename SvgRenderer::vertex_source_type;
using attribute_source_type = typename SvgRenderer::attribute_source_type;
using pixfmt_type = typename renderer_base::pixfmt_type;
using BufferType = typename std::tuple_element<0,RendererContext>::type;
using RasterizerType = typename std::tuple_element<1,RendererContext>::type;
using PixMapType = typename std::tuple_element<2,RendererContext>::type;
vector_markers_rasterizer_dispatch(svg_path_ptr const& src,
vertex_source_type & path,
svg_attribute_type const& attrs,
agg::trans_affine const& marker_trans,
markers_symbolizer const& sym,
Detector & detector,
double scale_factor,
mapnik::feature_impl & feature,
attributes const& vars,
bool snap_to_pixels,
RendererContext const& renderer_context)
: vector_markers_dispatch<Detector>(src, marker_trans, sym, detector, scale_factor, feature, vars),
buf_(std::get<0>(renderer_context)),
grid_markers_renderer_context(feature_impl const& feature,
BufferType & buf,
RasterizerType & ras,
PixMapType & pixmap)
: feature_(feature),
buf_(buf),
pixf_(buf_),
renb_(pixf_),
svg_renderer_(path, attrs),
ras_(std::get<1>(renderer_context)),
pixmap_(std::get<2>(renderer_context)),
ras_(ras),
pixmap_(pixmap),
placed_(false)
{}
void render_marker(agg::trans_affine const& marker_tr, double opacity)
virtual void render_marker(svg_path_ptr const& src,
svg_path_adapter & path,
svg_attribute_type const& attrs,
markers_dispatch_params const& params,
agg::trans_affine const& marker_tr)
{
SvgRenderer svg_renderer_(path, attrs);
agg::scanline_bin sl_;
svg_renderer_.render_id(ras_, sl_, renb_, this->feature_.id(), marker_tr, opacity, this->src_->bounding_box());
svg_renderer_.render_id(ras_, sl_, renb_, feature_.id(), marker_tr,
params.opacity, src->bounding_box());
place_feature();
}
virtual void render_marker(image_rgba8 const& src,
markers_dispatch_params const& params,
agg::trans_affine const& marker_tr)
{
// In the long term this should be a visitor pattern based on the type of
// render src provided that converts the destination pixel type required.
render_raster_marker(ScanlineRenderer(renb_), ras_, src, feature_,
marker_tr, params.opacity);
place_feature();
}
void place_feature()
{
if (!placed_)
{
pixmap_.add_feature(this->feature_);
pixmap_.add_feature(feature_);
placed_ = true;
}
}
private:
feature_impl const& feature_;
BufferType & buf_;
pixfmt_type pixf_;
renderer_base renb_;
SvgRenderer svg_renderer_;
RasterizerType & ras_;
PixMapType & pixmap_;
bool placed_;
};
template <typename RendererBase, typename RendererType, typename Detector, typename RendererContext>
struct raster_markers_rasterizer_dispatch : public raster_markers_dispatch<Detector>
{
using pixfmt_type = typename RendererBase::pixfmt_type;
using color_type = typename RendererBase::pixfmt_type::color_type;
using BufferType = typename std::tuple_element<0,RendererContext>::type;
using RasterizerType = typename std::tuple_element<1,RendererContext>::type;
using PixMapType = typename std::tuple_element<2,RendererContext>::type;
raster_markers_rasterizer_dispatch(image_rgba8 const& src,
agg::trans_affine const& marker_trans,
markers_symbolizer const& sym,
Detector & detector,
double scale_factor,
mapnik::feature_impl & feature,
attributes const& vars,
RendererContext const& renderer_context)
: raster_markers_dispatch<Detector>(src, marker_trans, sym, detector, scale_factor, feature, vars),
buf_(std::get<0>(renderer_context)),
pixf_(buf_),
renb_(pixf_),
ras_(std::get<1>(renderer_context)),
pixmap_(std::get<2>(renderer_context)),
placed_(false)
{}
void render_marker(agg::trans_affine const& marker_tr, double opacity)
{
// In the long term this should be a visitor pattern based on the type of render this->src_ provided that converts
// the destination pixel type required.
render_raster_marker(RendererType(renb_), ras_, this->src_, this->feature_, marker_tr, opacity);
if (!placed_)
{
pixmap_.add_feature(this->feature_);
placed_ = true;
}
}
private:
BufferType & buf_;
pixfmt_type pixf_;
RendererBase renb_;
RasterizerType & ras_;
PixMapType & pixmap_;
bool placed_;
};
}
} // namespace detail
template <typename T>
void grid_renderer<T>::process(markers_symbolizer const& sym,
@ -193,7 +139,6 @@ void grid_renderer<T>::process(markers_symbolizer const& sym,
using buf_type = grid_rendering_buffer;
using pixfmt_type = typename grid_renderer_base_type::pixfmt_type;
using renderer_type = agg::renderer_scanline_bin_solid<grid_renderer_base_type>;
using detector_type = label_collision_detector4;
using namespace mapnik::svg;
using svg_attribute_type = agg::pod_bvector<path_attributes>;
@ -206,22 +151,20 @@ void grid_renderer<T>::process(markers_symbolizer const& sym,
ras_ptr->reset();
box2d<double> clip_box = common_.query_extent_;
auto renderer_context = std::tie(render_buf,*ras_ptr,pixmap_);
using grid_context_type = decltype(renderer_context);
using vector_dispatch_type = detail::vector_markers_rasterizer_dispatch<svg_renderer_type,
detector_type,
grid_context_type>;
using raster_dispatch_type = detail::raster_markers_rasterizer_dispatch<grid_renderer_base_type,
using context_type = detail::grid_markers_renderer_context<svg_renderer_type,
renderer_type,
detector_type,
grid_context_type>;
render_markers_symbolizer<vector_dispatch_type, raster_dispatch_type>(
buf_type,
grid_rasterizer,
buffer_type>;
context_type renderer_context(feature, render_buf, *ras_ptr, pixmap_);
render_markers_symbolizer(
sym, feature, prj_trans, common_, clip_box, renderer_context);
}
template void grid_renderer<grid>::process(markers_symbolizer const&,
mapnik::feature_impl &,
proj_transform const&);
}
} // namespace mapnik
#endif

View file

@ -30,7 +30,6 @@
#include <mapnik/grid/grid.hpp>
#include <mapnik/geom_util.hpp>
#include <mapnik/label_collision_detector.hpp>
#include <mapnik/marker.hpp>
#include <mapnik/marker_cache.hpp>
#include <mapnik/parse_path.hpp>

View file

@ -34,19 +34,21 @@ namespace mapnik
// This visitor will process offsets for the given layout
struct process_layout
{
using bound_box = box2d<double>;
// The vector containing the existing, centered item bounding boxes
vector<bound_box> const& member_boxes_;
std::vector<bound_box> const& member_boxes_;
// The vector to populate with item offsets
vector<pixel_position> & member_offsets_;
std::vector<pixel_position> & member_offsets_;
// The origin point of the member boxes
// i.e. The member boxes are positioned around input_origin,
// and the offset values should position them around (0,0)
pixel_position const& input_origin_;
process_layout(vector<bound_box> const& member_bboxes,
vector<pixel_position> &member_offsets,
process_layout(std::vector<bound_box> const& member_bboxes,
std::vector<pixel_position> &member_offsets,
pixel_position const& input_origin)
: member_boxes_(member_bboxes),
member_offsets_(member_offsets),
@ -54,9 +56,12 @@ struct process_layout
{
}
// arrange group memebers in centered, horizontal row
// arrange group members in centered, horizontal row
void operator()(simple_row_layout const& layout) const
{
member_offsets_.clear();
member_offsets_.reserve(member_boxes_.size());
double total_width = (member_boxes_.size() - 1) * layout.get_item_margin();
for (auto const& box : member_boxes_)
{
@ -66,7 +71,7 @@ struct process_layout
double x_offset = -(total_width / 2.0);
for (auto const& box : member_boxes_)
{
member_offsets_.push_back(pixel_position(x_offset - box.minx(), -input_origin_.y));
member_offsets_.emplace_back(x_offset - box.minx(), -input_origin_.y);
x_offset += box.width() + layout.get_item_margin();
}
}
@ -150,7 +155,7 @@ private:
}
};
bound_box group_layout_manager::offset_box_at(size_t i)
box2d<double> group_layout_manager::offset_box_at(size_t i)
{
handle_update();
pixel_position const& offset = member_offsets_.at(i);

View file

@ -29,10 +29,24 @@
namespace mapnik {
// copy constructor exclusively for virtual_renderer_common
renderer_common::renderer_common(renderer_common const& other)
: width_(other.width_),
height_(other.height_),
scale_factor_(other.scale_factor_),
vars_(other.vars_),
shared_font_library_(other.shared_font_library_),
font_library_(other.font_library_),
font_manager_(other.font_manager_),
query_extent_(other.query_extent_),
t_(other.t_),
detector_(other.detector_)
{}
renderer_common::renderer_common(Map const& map, unsigned width, unsigned height, double scale_factor,
attributes const& vars,
view_transform && t,
std::shared_ptr<label_collision_detector4> detector)
detector_ptr detector)
: width_(width),
height_(height),
scale_factor_(scale_factor),
@ -57,7 +71,7 @@ renderer_common::renderer_common(Map const &m, attributes const& vars, unsigned
renderer_common::renderer_common(Map const &m, attributes const& vars, unsigned offset_x, unsigned offset_y,
unsigned width, unsigned height, double scale_factor,
std::shared_ptr<label_collision_detector4> detector)
detector_ptr detector)
: renderer_common(m, width, height, scale_factor,
vars,
view_transform(m.width(),m.height(),m.get_current_extent(),offset_x,offset_y),
@ -74,4 +88,10 @@ renderer_common::renderer_common(Map const &m, request const &req, attributes co
req.width() + req.buffer_size() ,req.height() + req.buffer_size())))
{}
renderer_common::~renderer_common()
{
// defined in .cpp to make this destructible elsewhere without
// having to #include <mapnik/label_collision_detector.hpp>
}
}

View file

@ -1,233 +0,0 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2015 Artem Pavlenko
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*****************************************************************************/
// mapnik
#include <mapnik/renderer_common/process_group_symbolizer.hpp>
#include <mapnik/renderer_common/process_markers_symbolizer.hpp>
#include <mapnik/make_unique.hpp>
namespace mapnik {
vector_marker_render_thunk::vector_marker_render_thunk(svg_path_ptr const& src,
svg_attribute_type const& attrs,
agg::trans_affine const& marker_trans,
double opacity,
composite_mode_e comp_op,
bool snap_to_pixels)
: src_(src), attrs_(attrs), tr_(marker_trans), opacity_(opacity),
comp_op_(comp_op), snap_to_pixels_(snap_to_pixels)
{}
vector_marker_render_thunk::vector_marker_render_thunk(vector_marker_render_thunk && rhs)
: src_(std::move(rhs.src_)),
attrs_(std::move(rhs.attrs_)),
tr_(std::move(rhs.tr_)),
opacity_(std::move(rhs.opacity_)),
comp_op_(std::move(rhs.comp_op_)),
snap_to_pixels_(std::move(rhs.snap_to_pixels_)) {}
raster_marker_render_thunk::raster_marker_render_thunk(image_rgba8 const& src,
agg::trans_affine const& marker_trans,
double opacity,
composite_mode_e comp_op,
bool snap_to_pixels)
: src_(src), tr_(marker_trans), opacity_(opacity), comp_op_(comp_op),
snap_to_pixels_(snap_to_pixels)
{}
raster_marker_render_thunk::raster_marker_render_thunk(raster_marker_render_thunk && rhs)
: src_(rhs.src_),
tr_(std::move(rhs.tr_)),
opacity_(std::move(rhs.opacity_)),
comp_op_(std::move(rhs.comp_op_)),
snap_to_pixels_(std::move(rhs.snap_to_pixels_)) {}
text_render_thunk::text_render_thunk(helper_ptr && helper,
double opacity, composite_mode_e comp_op,
halo_rasterizer_enum halo_rasterizer)
: helper_(std::move(helper)),
placements_(helper_->get()),
opacity_(opacity),
comp_op_(comp_op),
halo_rasterizer_(halo_rasterizer)
{}
text_render_thunk::text_render_thunk(text_render_thunk && rhs)
: helper_(std::move(rhs.helper_)),
placements_(std::move(rhs.placements_)),
opacity_(std::move(rhs.opacity_)),
comp_op_(std::move(rhs.comp_op_)),
halo_rasterizer_(std::move(rhs.halo_rasterizer_)) {}
namespace detail {
template <typename Detector, typename RendererContext>
struct vector_marker_thunk_dispatch : public vector_markers_dispatch<Detector>
{
vector_marker_thunk_dispatch(svg_path_ptr const& src,
svg_path_adapter & path,
svg_attribute_type const& attrs,
agg::trans_affine const& marker_trans,
symbolizer_base const& sym,
Detector & detector,
double scale_factor,
feature_impl & feature,
attributes const& vars,
bool snap_to_pixels,
RendererContext const& renderer_context)
: vector_markers_dispatch<Detector>(src, marker_trans, sym, detector, scale_factor, feature, vars),
attrs_(attrs), comp_op_(get<composite_mode_e, keys::comp_op>(sym, feature, vars)),
snap_to_pixels_(snap_to_pixels), thunks_(std::get<0>(renderer_context))
{}
~vector_marker_thunk_dispatch() {}
void render_marker(agg::trans_affine const& marker_tr, double opacity)
{
vector_marker_render_thunk thunk(this->src_, this->attrs_, marker_tr, opacity, comp_op_, snap_to_pixels_);
thunks_.push_back(std::make_unique<render_thunk>(std::move(thunk)));
}
private:
svg_attribute_type const& attrs_;
composite_mode_e comp_op_;
bool snap_to_pixels_;
render_thunk_list & thunks_;
};
template <typename Detector, typename RendererContext>
struct raster_marker_thunk_dispatch : public raster_markers_dispatch<Detector>
{
raster_marker_thunk_dispatch(image_rgba8 const& src,
agg::trans_affine const& marker_trans,
symbolizer_base const& sym,
Detector & detector,
double scale_factor,
feature_impl & feature,
attributes const& vars,
RendererContext const& renderer_context,
bool snap_to_pixels = false)
: raster_markers_dispatch<Detector>(src, marker_trans, sym, detector, scale_factor, feature, vars),
comp_op_(get<composite_mode_e, keys::comp_op>(sym, feature, vars)),
snap_to_pixels_(snap_to_pixels), thunks_(std::get<0>(renderer_context))
{}
~raster_marker_thunk_dispatch() {}
void render_marker(agg::trans_affine const& marker_tr, double opacity)
{
raster_marker_render_thunk thunk(this->src_, marker_tr, opacity, comp_op_, snap_to_pixels_);
thunks_.push_back(std::make_unique<render_thunk>(std::move(thunk)));
}
private:
composite_mode_e comp_op_;
bool snap_to_pixels_;
render_thunk_list & thunks_;
};
} // end detail ns
render_thunk_extractor::render_thunk_extractor(box2d<double> & box,
render_thunk_list & thunks,
feature_impl & feature,
attributes const& vars,
proj_transform const& prj_trans,
virtual_renderer_common & common,
box2d<double> const& clipping_extent)
: box_(box), thunks_(thunks), feature_(feature), vars_(vars), prj_trans_(prj_trans),
common_(common), clipping_extent_(clipping_extent)
{}
void render_thunk_extractor::operator()(markers_symbolizer const& sym) const
{
auto renderer_context = std::tie(thunks_);
using thunk_context_type = decltype(renderer_context);
using vector_dispatch_type = detail::vector_marker_thunk_dispatch<label_collision_detector4, thunk_context_type>;
using raster_dispatch_type = detail::raster_marker_thunk_dispatch<label_collision_detector4, thunk_context_type>;
render_markers_symbolizer<vector_dispatch_type, raster_dispatch_type>(
sym, feature_, prj_trans_, common_, clipping_extent_, renderer_context);
update_box();
}
void render_thunk_extractor::operator()(text_symbolizer const& sym) const
{
box2d<double> clip_box = clipping_extent_;
helper_ptr helper = std::make_unique<text_symbolizer_helper>(
sym, feature_, vars_, prj_trans_,
common_.width_, common_.height_,
common_.scale_factor_,
common_.t_, common_.font_manager_, *common_.detector_,
clip_box, agg::trans_affine());
extract_text_thunk(std::move(helper), sym);
}
void render_thunk_extractor::operator()(shield_symbolizer const& sym) const
{
box2d<double> clip_box = clipping_extent_;
helper_ptr helper = std::make_unique<text_symbolizer_helper>(
sym, feature_, vars_, prj_trans_,
common_.width_, common_.height_,
common_.scale_factor_,
common_.t_, common_.font_manager_, *common_.detector_,
clip_box, agg::trans_affine());
extract_text_thunk(std::move(helper), sym);
}
void render_thunk_extractor::extract_text_thunk(helper_ptr && helper, text_symbolizer const& sym) const
{
double opacity = get<double>(sym, keys::opacity, feature_, common_.vars_, 1.0);
composite_mode_e comp_op = get<composite_mode_e>(sym, keys::comp_op, feature_, common_.vars_, src_over);
halo_rasterizer_enum halo_rasterizer = get<halo_rasterizer_enum>(sym, keys::halo_rasterizer, feature_, common_.vars_, HALO_RASTERIZER_FULL);
text_render_thunk thunk(std::move(helper), opacity, comp_op, halo_rasterizer);
thunks_.push_back(std::make_unique<render_thunk>(std::move(thunk)));
update_box();
}
void render_thunk_extractor::update_box() const
{
label_collision_detector4 & detector = *common_.detector_;
for (auto const& label : detector)
{
if (box_.width() > 0 && box_.height() > 0)
{
box_.expand_to_include(label.get().box);
}
else
{
box_ = label.get().box;
}
}
detector.clear();
}
} // namespace mapnik

View file

@ -0,0 +1,194 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2016 Artem Pavlenko
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*****************************************************************************/
// mapnik
#include <mapnik/attribute_collector.hpp>
#include <mapnik/feature_factory.hpp>
#include <mapnik/group/group_layout_manager.hpp>
#include <mapnik/group/group_symbolizer_helper.hpp>
#include <mapnik/group/group_symbolizer_properties.hpp>
#include <mapnik/renderer_common/render_group_symbolizer.hpp>
#include <mapnik/renderer_common/render_thunk_extractor.hpp>
#include <mapnik/util/conversions.hpp>
namespace mapnik {
void render_group_symbolizer(group_symbolizer const& sym,
feature_impl & feature,
attributes const& vars,
proj_transform const& prj_trans,
box2d<double> const& clipping_extent,
renderer_common & common,
render_thunk_list_dispatch & render_thunks)
{
// find all column names referenced in the group rules and symbolizers
std::set<std::string> columns;
group_attribute_collector column_collector(columns, false);
column_collector(sym);
auto props = get<group_symbolizer_properties_ptr>(sym, keys::group_properties);
// create a new context for the sub features of this group
context_ptr sub_feature_ctx = std::make_shared<mapnik::context_type>();
// populate new context with column names referenced in the group rules and symbolizers
for (auto const& col_name : columns)
{
sub_feature_ctx->push(col_name);
}
// keep track of the sub features that we'll want to symbolize
// along with the group rules that they matched
std::vector< std::pair<group_rule_ptr, feature_ptr> > matches;
// create a copied 'virtual' common renderer for processing sub feature symbolizers
// create an empty detector for it, so we are sure we won't hit anything
virtual_renderer_common virtual_renderer(common);
// keep track of which lists of render thunks correspond to
// entries in the group_layout_manager.
std::vector<render_thunk_list> layout_thunks;
// layout manager to store and arrange bboxes of matched features
group_layout_manager layout_manager(props->get_layout());
layout_manager.set_input_origin(common.width_ * 0.5, common.height_ * 0.5);
// run feature or sub feature through the group rules & symbolizers
// for each index value in the range
value_integer start = get<value_integer>(sym, keys::start_column);
value_integer end = start + get<value_integer>(sym, keys::num_columns);
for (value_integer col_idx = start; col_idx < end; ++col_idx)
{
// create sub feature with indexed column values
feature_ptr sub_feature = feature_factory::create(sub_feature_ctx, col_idx);
// copy the necessary columns to sub feature
for(auto const& col_name : columns)
{
if (col_name.find('%') != std::string::npos)
{
if (col_name.size() == 1)
{
// column name is '%' by itself, so give the index as the value
sub_feature->put(col_name, col_idx);
}
else
{
// indexed column
std::string col_idx_str;
if (mapnik::util::to_string(col_idx_str,col_idx))
{
std::string col_idx_name = col_name;
boost::replace_all(col_idx_name, "%", col_idx_str);
sub_feature->put(col_name, feature.get(col_idx_name));
}
}
}
else
{
// non-indexed column
sub_feature->put(col_name, feature.get(col_name));
}
}
// add a single point geometry at pixel origin
double x = common.width_ / 2.0, y = common.height_ / 2.0, z = 0.0;
common.t_.backward(&x, &y);
prj_trans.forward(x, y, z);
// note that we choose a point in the middle of the screen to
// try to ensure that we don't get edge artefacts due to any
// symbolizers with avoid-edges set: only the avoid-edges of
// the group symbolizer itself should matter.
geometry::point<double> origin_pt(x,y);
sub_feature->set_geometry(origin_pt);
// get the layout for this set of properties
for (auto const& rule : props->get_rules())
{
if (util::apply_visitor(evaluate<feature_impl,value_type,attributes>(*sub_feature,common.vars_),
*(rule->get_filter())).to_bool())
{
// add matched rule and feature to the list of things to draw
matches.emplace_back(rule, sub_feature);
// construct a bounding box around all symbolizers for the matched rule
box2d<double> bounds;
render_thunk_list thunks;
render_thunk_extractor extractor(bounds, thunks, *sub_feature, common.vars_, prj_trans,
virtual_renderer, clipping_extent);
for (auto const& _sym : *rule)
{
// TODO: construct layout and obtain bounding box
util::apply_visitor(extractor, _sym);
}
// add the bounding box to the layout manager
layout_manager.add_member_bound_box(bounds);
layout_thunks.emplace_back(std::move(thunks));
break;
}
}
}
// create a symbolizer helper
group_symbolizer_helper helper(sym, feature, vars, prj_trans,
common.width_, common.height_,
common.scale_factor_, common.t_,
*common.detector_, clipping_extent);
for (size_t i = 0; i < matches.size(); ++i)
{
group_rule_ptr match_rule = matches[i].first;
feature_ptr match_feature = matches[i].second;
value_unicode_string rpt_key_value = "";
// get repeat key from matched group rule
expression_ptr rpt_key_expr = match_rule->get_repeat_key();
// if no repeat key was defined, use default from group symbolizer
if (!rpt_key_expr)
{
rpt_key_expr = get<expression_ptr>(sym, keys::repeat_key);
}
// evaluate the repeat key with the matched sub feature if we have one
if (rpt_key_expr)
{
rpt_key_value = util::apply_visitor(evaluate<feature_impl,value_type,attributes>(*match_feature,common.vars_),
*rpt_key_expr).to_unicode();
}
helper.add_box_element(layout_manager.offset_box_at(i), rpt_key_value);
}
pixel_position_list const& positions = helper.get();
for (pixel_position const& pos : positions)
{
for (size_t layout_i = 0; layout_i < layout_thunks.size(); ++layout_i)
{
pixel_position const& offset = layout_manager.offset_at(layout_i);
pixel_position render_offset = pos + offset;
render_thunks.render_list(layout_thunks[layout_i], render_offset);
}
}
}
} // namespace mapnik

View file

@ -2,7 +2,7 @@
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2015 Artem Pavlenko
* Copyright (C) 2016 Artem Pavlenko
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -20,24 +20,24 @@
*
*****************************************************************************/
#ifndef MAPNIK_RENDERER_COMMON_PROCESS_MARKERS_SYMBOLIZER_HPP
#define MAPNIK_RENDERER_COMMON_PROCESS_MARKERS_SYMBOLIZER_HPP
#include <mapnik/svg/svg_storage.hpp>
#include <mapnik/svg/svg_path_adapter.hpp>
#include <mapnik/vertex_converters.hpp>
#include <mapnik/marker_cache.hpp>
#include <mapnik/marker_helpers.hpp>
#include <mapnik/geometry_type.hpp>
#include <mapnik/renderer_common/render_markers_symbolizer.hpp>
#include <mapnik/symbolizer.hpp>
namespace mapnik {
template <typename VD, typename RD, typename RendererType, typename ContextType>
namespace detail {
template <typename Detector, typename RendererType, typename ContextType>
struct render_marker_symbolizer_visitor
{
using vector_dispatch_type = VD;
using raster_dispatch_type = RD;
using buffer_type = typename std::tuple_element<0,ContextType>::type;
using vector_dispatch_type = vector_markers_dispatch<Detector>;
using raster_dispatch_type = raster_markers_dispatch<Detector>;
using vertex_converter_type = vertex_converter<clip_line_tag,
clip_poly_tag,
@ -53,7 +53,7 @@ struct render_marker_symbolizer_visitor
proj_transform const& prj_trans,
RendererType const& common,
box2d<double> const& clip_box,
ContextType const& renderer_context)
ContextType & renderer_context)
: filename_(filename),
sym_(sym),
feature_(feature),
@ -243,33 +243,57 @@ struct render_marker_symbolizer_visitor
proj_transform const& prj_trans_;
RendererType const& common_;
box2d<double> const& clip_box_;
ContextType const& renderer_context_;
ContextType & renderer_context_;
};
template <typename VD, typename RD, typename RendererType, typename ContextType>
} // namespace detail
markers_dispatch_params::markers_dispatch_params(box2d<double> const& size,
agg::trans_affine const& tr,
symbolizer_base const& sym,
feature_impl const& feature,
attributes const& vars,
double scale,
bool snap)
: placement_params{
.size = size,
.tr = tr,
.spacing = get<value_double, keys::spacing>(sym, feature, vars),
.max_error = get<value_double, keys::max_error>(sym, feature, vars),
.allow_overlap = get<value_bool, keys::allow_overlap>(sym, feature, vars),
.avoid_edges = get<value_bool, keys::avoid_edges>(sym, feature, vars),
.direction = get<direction_enum, keys::direction>(sym, feature, vars)}
, placement_method(get<marker_placement_enum, keys::markers_placement_type>(sym, feature, vars))
, ignore_placement(get<value_bool, keys::ignore_placement>(sym, feature, vars))
, snap_to_pixels(snap)
, scale_factor(scale)
, opacity(get<value_double, keys::opacity>(sym, feature, vars))
{
placement_params.spacing *= scale;
}
void render_markers_symbolizer(markers_symbolizer const& sym,
mapnik::feature_impl & feature,
proj_transform const& prj_trans,
RendererType const& common,
renderer_common const& common,
box2d<double> const& clip_box,
ContextType const& renderer_context)
markers_renderer_context & renderer_context)
{
using namespace mapnik::svg;
using Detector = decltype(*common.detector_);
using RendererType = renderer_common;
using ContextType = markers_renderer_context;
using VisitorType = detail::render_marker_symbolizer_visitor<Detector,
RendererType,
ContextType>;
std::string filename = get<std::string>(sym, keys::file, feature, common.vars_, "shape://ellipse");
if (!filename.empty())
{
std::shared_ptr<mapnik::marker const> mark = mapnik::marker_cache::instance().find(filename, true);
render_marker_symbolizer_visitor<VD,RD,RendererType,ContextType> visitor(filename,
sym,
feature,
prj_trans,
common,
clip_box,
auto mark = mapnik::marker_cache::instance().find(filename, true);
VisitorType visitor(filename, sym, feature, prj_trans, common, clip_box,
renderer_context);
util::apply_visitor(visitor, *mark);
}
}
} // namespace mapnik
#endif // MAPNIK_RENDERER_COMMON_PROCESS_MARKERS_SYMBOLIZER_HPP

View file

@ -0,0 +1,155 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2016 Artem Pavlenko
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*****************************************************************************/
// mapnik
#include <mapnik/label_collision_detector.hpp>
#include <mapnik/make_unique.hpp>
#include <mapnik/renderer_common/render_markers_symbolizer.hpp>
#include <mapnik/renderer_common/render_thunk_extractor.hpp>
namespace mapnik {
virtual_renderer_common::virtual_renderer_common(renderer_common const& other)
: renderer_common(other)
{
// replace collision detector with my own so that I don't pollute the original
detector_ = std::make_shared<label_collision_detector4>(other.detector_->extent());
}
namespace detail {
struct thunk_markers_renderer_context : markers_renderer_context
{
thunk_markers_renderer_context(symbolizer_base const& sym,
feature_impl const& feature,
attributes const& vars,
render_thunk_list & thunks)
: comp_op_(get<composite_mode_e, keys::comp_op>(sym, feature, vars))
, thunks_(thunks)
{}
virtual void render_marker(svg_path_ptr const& src,
svg_path_adapter & path,
svg_attribute_type const& attrs,
markers_dispatch_params const& params,
agg::trans_affine const& marker_tr)
{
vector_marker_render_thunk thunk(src, attrs, marker_tr, params.opacity,
comp_op_, params.snap_to_pixels);
thunks_.push_back(std::make_unique<render_thunk>(std::move(thunk)));
}
virtual void render_marker(image_rgba8 const& src,
markers_dispatch_params const& params,
agg::trans_affine const& marker_tr)
{
raster_marker_render_thunk thunk(src, marker_tr, params.opacity,
comp_op_, params.snap_to_pixels);
thunks_.push_back(std::make_unique<render_thunk>(std::move(thunk)));
}
private:
composite_mode_e comp_op_;
render_thunk_list & thunks_;
};
} // namespace detail
render_thunk_extractor::render_thunk_extractor(box2d<double> & box,
render_thunk_list & thunks,
feature_impl & feature,
attributes const& vars,
proj_transform const& prj_trans,
virtual_renderer_common & common,
box2d<double> const& clipping_extent)
: box_(box), thunks_(thunks), feature_(feature), vars_(vars), prj_trans_(prj_trans),
common_(common), clipping_extent_(clipping_extent)
{}
void render_thunk_extractor::operator()(markers_symbolizer const& sym) const
{
using context_type = detail::thunk_markers_renderer_context;
context_type renderer_context(sym, feature_, vars_, thunks_);
render_markers_symbolizer(
sym, feature_, prj_trans_, common_, clipping_extent_, renderer_context);
update_box();
}
void render_thunk_extractor::operator()(text_symbolizer const& sym) const
{
auto helper = std::make_unique<text_symbolizer_helper>(
sym, feature_, vars_, prj_trans_,
common_.width_, common_.height_,
common_.scale_factor_,
common_.t_, common_.font_manager_, *common_.detector_,
clipping_extent_, agg::trans_affine::identity);
extract_text_thunk(std::move(helper), sym);
}
void render_thunk_extractor::operator()(shield_symbolizer const& sym) const
{
auto helper = std::make_unique<text_symbolizer_helper>(
sym, feature_, vars_, prj_trans_,
common_.width_, common_.height_,
common_.scale_factor_,
common_.t_, common_.font_manager_, *common_.detector_,
clipping_extent_, agg::trans_affine::identity);
extract_text_thunk(std::move(helper), sym);
}
void render_thunk_extractor::extract_text_thunk(text_render_thunk::helper_ptr && helper,
text_symbolizer const& sym) const
{
double opacity = get<double>(sym, keys::opacity, feature_, common_.vars_, 1.0);
composite_mode_e comp_op = get<composite_mode_e>(sym, keys::comp_op, feature_, common_.vars_, src_over);
halo_rasterizer_enum halo_rasterizer = get<halo_rasterizer_enum>(sym, keys::halo_rasterizer, feature_, common_.vars_, HALO_RASTERIZER_FULL);
text_render_thunk thunk(std::move(helper), opacity, comp_op, halo_rasterizer);
thunks_.push_back(std::make_unique<render_thunk>(std::move(thunk)));
update_box();
}
void render_thunk_extractor::update_box() const
{
label_collision_detector4 & detector = *common_.detector_;
for (auto const& label : detector)
{
if (box_.width() > 0 && box_.height() > 0)
{
box_.expand_to_include(label.get().box);
}
else
{
box_ = label.get().box;
}
}
detector.clear();
}
} // namespace mapnik

View file

@ -27,7 +27,6 @@
#include <mapnik/svg/output/svg_renderer.hpp>
#include <mapnik/map.hpp>
#include <mapnik/layer.hpp>
#include <mapnik/label_collision_detector.hpp>
#include <mapnik/feature_type_style.hpp>
#include <mapnik/font_set.hpp>

View file

@ -74,7 +74,7 @@ void glyph_positions::set_marker(marker_info_ptr mark, pixel_position const& mar
marker_pos_ = marker_pos;
}
marker_info_ptr glyph_positions::get_marker() const
marker_info_ptr const& glyph_positions::get_marker() const
{
return marker_info_;
}

View file

@ -60,7 +60,9 @@ void text_renderer::prepare_glyphs(glyph_positions const& positions)
FT_Vector pen;
FT_Error error;
glyphs_.clear();
glyphs_.reserve(positions.size());
for (auto const& glyph_pos : positions)
{
glyph_info const& glyph = glyph_pos.glyph;
@ -121,7 +123,6 @@ agg_text_renderer<T>::agg_text_renderer (pixmap_type & pixmap,
template <typename T>
void agg_text_renderer<T>::render(glyph_positions const& pos)
{
glyphs_.clear();
prepare_glyphs(pos);
FT_Error error;
FT_Vector start;
@ -232,7 +233,6 @@ void agg_text_renderer<T>::render(glyph_positions const& pos)
template <typename T>
void grid_text_renderer<T>::render(glyph_positions const& pos, value_integer feature_id)
{
glyphs_.clear();
prepare_glyphs(pos);
FT_Error error;
FT_Vector start;