diff --git a/Makefile b/Makefile index 541559dbb..df50a147b 100755 --- a/Makefile +++ b/Makefile @@ -1,4 +1,3 @@ - OS := $(shell uname -s) PYTHON = python @@ -40,18 +39,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_x3.os \ - src/image_filter_types.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 \ + src/expression_grammar.os \ + src/transform_expression_grammar.os \ + src/image_filter_grammar.os \ mapnik: src/json/libmapnik-json.a # then install the rest with -j$(JOBS) diff --git a/deps/mapbox/variant b/deps/mapbox/variant index 9afd64060..7f7c667f8 160000 --- a/deps/mapbox/variant +++ b/deps/mapbox/variant @@ -1 +1 @@ -Subproject commit 9afd6406065440e02b6bf42db4633b815846db0d +Subproject commit 7f7c667f870541c208c07d99a9f2c22dfa1f32de diff --git a/include/mapnik/expression_evaluator.hpp b/include/mapnik/expression_evaluator.hpp index 2c1ab1464..58b34486e 100644 --- a/include/mapnik/expression_evaluator.hpp +++ b/include/mapnik/expression_evaluator.hpp @@ -45,27 +45,27 @@ struct evaluate : feature_(f), vars_(v) {} - value_integer operator() (value_integer val) const + value_type operator() (value_integer val) const { return val; } - value_double operator() (value_double val) const + value_type operator() (value_double val) const { return val; } - value_bool operator() (value_bool val) const + value_type operator() (value_bool val) const { return val; } - value_null operator() (value_null val) const + value_type operator() (value_null val) const { return val; } - value_unicode_string const& operator() (value_unicode_string const& str) const + value_type operator() (value_unicode_string const& str) const { return str; } diff --git a/include/mapnik/font_engine_freetype.hpp b/include/mapnik/font_engine_freetype.hpp index 33ac45035..73227cdbf 100644 --- a/include/mapnik/font_engine_freetype.hpp +++ b/include/mapnik/font_engine_freetype.hpp @@ -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; - 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 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; + using face_cache_ptr = std::shared_ptr; + + 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_; diff --git a/include/mapnik/geometry_reprojection_impl.hpp b/include/mapnik/geometry_reprojection_impl.hpp index 867c0ba44..ff01bd451 100644 --- a/include/mapnik/geometry_reprojection_impl.hpp +++ b/include/mapnik/geometry_reprojection_impl.hpp @@ -178,12 +178,12 @@ struct geom_reproj_copy_visitor : proj_trans_(proj_trans), n_err_(n_err) {} - geometry operator() (geometry_empty const&) + geometry operator() (geometry_empty const&) const { return geometry_empty(); } - geometry operator() (point const& p) + geometry operator() (point const& p) const { geometry geom; // default empty unsigned int intial_err = n_err_; @@ -193,7 +193,7 @@ struct geom_reproj_copy_visitor return geom; } - geometry operator() (line_string const& ls) + geometry operator() (line_string const& ls) const { geometry geom; // default empty unsigned int intial_err = n_err_; @@ -203,7 +203,7 @@ struct geom_reproj_copy_visitor return geom; } - geometry operator() (polygon const& poly) + geometry operator() (polygon const& poly) const { geometry geom; // default empty polygon new_poly = reproject_internal(poly, proj_trans_, n_err_); @@ -212,7 +212,7 @@ struct geom_reproj_copy_visitor return geom; } - geometry operator() (multi_point const& mp) + geometry operator() (multi_point const& mp) const { geometry geom; // default empty multi_point new_mp = reproject_internal(mp, proj_trans_, n_err_); @@ -221,7 +221,7 @@ struct geom_reproj_copy_visitor return geom; } - geometry operator() (multi_line_string const& mls) + geometry operator() (multi_line_string const& mls) const { geometry geom; // default empty multi_line_string new_mls = reproject_internal(mls, proj_trans_, n_err_); @@ -230,7 +230,7 @@ struct geom_reproj_copy_visitor return geom; } - geometry operator() (multi_polygon const& mpoly) + geometry operator() (multi_polygon const& mpoly) const { geometry geom; // default empty multi_polygon new_mpoly = reproject_internal(mpoly, proj_trans_, n_err_); @@ -239,7 +239,7 @@ struct geom_reproj_copy_visitor return geom; } - geometry operator() (geometry_collection const& c) + geometry operator() (geometry_collection const& c) const { geometry geom; // default empty geometry_collection new_c = reproject_internal(c, proj_trans_, n_err_); @@ -284,15 +284,15 @@ struct geom_reproj_visitor { : proj_trans_(proj_trans) {} template - bool operator() (geometry & geom) + bool operator() (geometry & geom) const { return mapnik::util::apply_visitor((*this), geom); } - bool operator() (geometry_empty &) { return true; } + bool operator() (geometry_empty &) const { return true; } template - bool operator() (point & p) + bool operator() (point & p) const { if (!proj_trans_.forward(p)) { @@ -302,7 +302,7 @@ struct geom_reproj_visitor { } template - bool operator() (line_string & ls) + bool operator() (line_string & ls) const { if (proj_trans_.forward(ls) > 0) { @@ -312,7 +312,7 @@ struct geom_reproj_visitor { } template - bool operator() (polygon & poly) + bool operator() (polygon & poly) const { if (proj_trans_.forward(poly.exterior_ring) > 0) { @@ -330,13 +330,13 @@ struct geom_reproj_visitor { } template - bool operator() (multi_point & mp) + bool operator() (multi_point & mp) const { return (*this) (static_cast &>(mp)); } template - bool operator() (multi_line_string & mls) + bool operator() (multi_line_string & mls) const { for (auto & ls : mls) { @@ -349,7 +349,7 @@ struct geom_reproj_visitor { } template - bool operator() (multi_polygon & mpoly) + bool operator() (multi_polygon & mpoly) const { for (auto & poly : mpoly) { @@ -362,7 +362,7 @@ struct geom_reproj_visitor { } template - bool operator() (geometry_collection & c) + bool operator() (geometry_collection & c) const { for (auto & g : c) { diff --git a/include/mapnik/group/group_layout_manager.hpp b/include/mapnik/group/group_layout_manager.hpp index 38ee30b5d..548e37bb6 100644 --- a/include/mapnik/group/group_layout_manager.hpp +++ b/include/mapnik/group/group_layout_manager.hpp @@ -31,43 +31,51 @@ // stl #include -using std::vector; - namespace mapnik { -using bound_box = box2d; - struct group_layout_manager { - group_layout_manager(group_layout const& layout) + using bound_box = box2d; + + group_layout_manager() + : update_layout_(false) + {} + + explicit group_layout_manager(group_layout const& layout) : layout_(layout), - input_origin_(0, 0), - member_boxes_(vector()), - member_offsets_(vector()), - 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()), - member_offsets_(vector()), - update_layout_(true) + update_layout_(false) { } group_layout_manager(group_layout const& layout, pixel_position const& input_origin, - vector const& item_boxes) + std::vector const& item_boxes) : layout_(layout), input_origin_(input_origin), member_boxes_(item_boxes), - member_offsets_(vector()), 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 member_boxes_; - vector member_offsets_; + std::vector member_boxes_; + std::vector member_offsets_; bool update_layout_; }; diff --git a/include/mapnik/image_filter.hpp b/include/mapnik/image_filter.hpp index 62a3f3b5b..9b0b754cc 100644 --- a/include/mapnik/image_filter.hpp +++ b/include/mapnik/image_filter.hpp @@ -683,7 +683,7 @@ void color_blind_filter(Src & src, ColorBlindFilter const& op) using namespace boost::gil; rgba8_view_t src_view = rgba8_view(src); bool premultiplied = src.get_premultiplied(); - + for (std::ptrdiff_t y = 0; y < src_view.height(); ++y) { rgba8_view_t::x_iterator src_it = src_view.row_begin(static_cast(y)); @@ -738,7 +738,7 @@ void color_blind_filter(Src & src, ColorBlindFilter const& op) X = deviate_x * Y / deviate_y; Z = (1.0 - (deviate_x + deviate_y)) * Y / deviate_y; // Neutral grey calculated from luminance (in D65) - double neutral_X = 0.312713 * Y / 0.329016; + double neutral_X = 0.312713 * Y / 0.329016; double neutral_Z = 0.358271 * Y / 0.329016; // Difference between simulated color and neutral grey double diff_X = neutral_X - X; @@ -761,12 +761,12 @@ void color_blind_filter(Src & src, ColorBlindFilter const& op) // Convert to RGB color space dr = X * 3.24071 + Y * -1.53726 + Z * -0.498571; // XYZ->RGB (sRGB:D65) dg = X * -0.969258 + Y * 1.87599 + Z * 0.0415557; - db = X * 0.0556352 + Y * -0.203996 + Z * 1.05707; + db = X * 0.0556352 + Y * -0.203996 + Z * 1.05707; // Compensate simulated color towards a neutral fit in RGB space double fit_r = ((dr < 0.0 ? 0.0 : 1.0) - dr) / diff_r; double fit_g = ((dg < 0.0 ? 0.0 : 1.0) - dg) / diff_g; double fit_b = ((db < 0.0 ? 0.0 : 1.0) - db) / diff_b; - double adjust = std::max( (fit_r > 1.0 || fit_r < 0.0) ? 0.0 : fit_r, + double adjust = std::max( (fit_r > 1.0 || fit_r < 0.0) ? 0.0 : fit_r, (fit_g > 1.0 || fit_g < 0.0) ? 0.0 : fit_g ); adjust = std::max((fit_b > 1.0 || fit_b < 0.0) ? 0.0 : fit_b, adjust); @@ -777,7 +777,7 @@ void color_blind_filter(Src & src, ColorBlindFilter const& op) // Apply gamma correction dr = std::pow(dr, 1.0 / 2.2); dg = std::pow(dg, 1.0 / 2.2); - db = std::pow(db, 1.0 / 2.2); + db = std::pow(db, 1.0 / 2.2); // premultiply dr *= da; dg *= da; @@ -917,7 +917,7 @@ struct filter_visitor : src_(src) {} template - void operator () (T const& filter) + void operator () (T const& filter) const { apply_filter(src_, filter); } @@ -931,9 +931,9 @@ struct filter_radius_visitor filter_radius_visitor(int & radius) : radius_(radius) {} template - void operator () (T const& /*filter*/) {} + void operator () (T const& /*filter*/) const {} - void operator () (agg_stack_blur const& op) + void operator () (agg_stack_blur const& op) const { if (static_cast(op.rx) > radius_) radius_ = static_cast(op.rx); if (static_cast(op.ry) > radius_) radius_ = static_cast(op.ry); diff --git a/include/mapnik/marker.hpp b/include/mapnik/marker.hpp index 66e56b2ae..bde8d65a2 100644 --- a/include/mapnik/marker.hpp +++ b/include/mapnik/marker.hpp @@ -41,8 +41,10 @@ namespace mapnik struct image_any; namespace svg { struct path_attributes; } -using attr_storage = agg::pod_bvector; -using svg_storage_type = mapnik::svg::svg_storage; +using svg::svg_path_adapter; + +using svg_attribute_type = agg::pod_bvector; +using svg_storage_type = svg::svg_storage; using svg_path_ptr = std::shared_ptr; using image_ptr = std::shared_ptr; diff --git a/include/mapnik/marker_helpers.hpp b/include/mapnik/marker_helpers.hpp index 375d16fac..49c011a3b 100644 --- a/include/mapnik/marker_helpers.hpp +++ b/include/mapnik/marker_helpers.hpp @@ -35,6 +35,7 @@ #include #include #include +#include // agg #include "agg_trans_affine.h" @@ -52,60 +53,53 @@ template 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 void add_path(T & path) { - marker_placement_enum placement_method = get(sym_, feature_, vars_); - value_bool ignore_placement = get(sym_, feature_, vars_); - value_bool allow_overlap = get(sym_, feature_, vars_); - value_bool avoid_edges = get(sym_, feature_, vars_); - value_double opacity = get(sym_, feature_, vars_); - value_double spacing = get(sym_, feature_, vars_); - value_double max_error = get(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(sym_, feature_, vars_); - markers_placement_params params { src_->bounding_box(), tr, spacing * scale_factor_, max_error, allow_overlap, avoid_edges, direction }; markers_placement_finder 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 @@ -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(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 void add_path(T & path) { - marker_placement_enum placement_method = get(sym_, feature_, vars_); - value_bool allow_overlap = get(sym_, feature_, vars_); - value_bool avoid_edges = get(sym_, feature_, vars_); - value_double opacity = get(sym_, feature_, vars_); - value_bool ignore_placement = get(sym_, feature_, vars_); - value_double spacing = get(sym_, feature_, vars_); - value_double max_error = get(sym_, feature_, vars_); - box2d bbox(0,0, src_.width(),src_.height()); - direction_enum direction = get(sym_, feature_, vars_); - markers_placement_params params { bbox, marker_trans_, spacing * scale_factor_, max_error, allow_overlap, avoid_edges, direction }; markers_placement_finder 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, diff --git a/include/mapnik/markers_placements/point.hpp b/include/mapnik/markers_placements/point.hpp index 65b95ce79..13f174d9b 100644 --- a/include/mapnik/markers_placements/point.hpp +++ b/include/mapnik/markers_placements/point.hpp @@ -40,8 +40,8 @@ namespace mapnik { struct markers_placement_params { - box2d const& size; - agg::trans_affine const& tr; + box2d 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 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 result(xA, yA, xC, yC); - result.expand_to_include(xB, yB); - result.expand_to_include(xD, yD); - return result; + return box2d(params_.size, tr); } bool set_direction(double & angle) diff --git a/include/mapnik/renderer_common.hpp b/include/mapnik/renderer_common.hpp index 213443899..c9d181b42 100644 --- a/include/mapnik/renderer_common.hpp +++ b/include/mapnik/renderer_common.hpp @@ -42,13 +42,16 @@ namespace mapnik { struct renderer_common : private util::noncopyable { + using detector_ptr = std::shared_ptr; + 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 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 query_extent_; view_transform t_; - std::shared_ptr 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 detector); + attributes const& vars, view_transform && t, detector_ptr detector); }; } diff --git a/include/mapnik/renderer_common/apply_vertex_converter.hpp b/include/mapnik/renderer_common/apply_vertex_converter.hpp index de239c95b..503dc4176 100644 --- a/include/mapnik/renderer_common/apply_vertex_converter.hpp +++ b/include/mapnik/renderer_common/apply_vertex_converter.hpp @@ -31,7 +31,7 @@ struct apply_vertex_converter apply_vertex_converter(VertexConverter & converter, Processor & proc) : converter_(converter), proc_(proc) {} template - void operator() (Adapter const& adapter) const + void operator() (Adapter const& adapter) { converter_.apply(adapter, proc_); } diff --git a/include/mapnik/renderer_common/process_group_symbolizer.hpp b/include/mapnik/renderer_common/process_group_symbolizer.hpp deleted file mode 100644 index edec30830..000000000 --- a/include/mapnik/renderer_common/process_group_symbolizer.hpp +++ /dev/null @@ -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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// agg -#include - -namespace mapnik { - -class text_symbolizer_helper; - -using svg::svg_path_adapter; -using svg_attribute_type = agg::pod_bvector; - -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(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 & shared_font_library_; - font_library & font_library_; - face_manager_freetype & font_manager_; - box2d & query_extent_; - view_transform & t_; - std::shared_ptr 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; - -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; -using render_thunk_ptr = std::unique_ptr; -using render_thunk_list = std::list; - -// 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 & box, - render_thunk_list & thunks, - feature_impl & feature, - attributes const& vars, - proj_transform const& prj_trans, - virtual_renderer_common & common, - box2d 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 - void operator()(T const& ) const - { - // TODO: warning if unimplemented? - } - -private: - void extract_text_thunk(helper_ptr && helper, text_symbolizer const& sym) const; - - box2d & box_; - render_thunk_list & thunks_; - feature_impl & feature_; - attributes const& vars_; - proj_transform const& prj_trans_; - virtual_renderer_common & common_; - box2d clipping_extent_; - - void update_box() const; -}; - -template -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 -void render_group_symbolizer(group_symbolizer const& sym, - feature_impl & feature, - attributes const& vars, - proj_transform const& prj_trans, - box2d const& clipping_extent, - renderer_common & common, - F render_thunks) -{ - // find all column names referenced in the group rules and symbolizers - std::set columns; - group_attribute_collector column_collector(columns, false); - column_collector(sym); - - group_symbolizer_properties_ptr props = get(sym, keys::group_properties); - - // create a new context for the sub features of this group - context_ptr sub_feature_ctx = std::make_shared(); - - // 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 > 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 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(sym, keys::start_column); - value_integer end = start + get(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 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(*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(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(*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 diff --git a/include/mapnik/renderer_common/render_group_symbolizer.hpp b/include/mapnik/renderer_common/render_group_symbolizer.hpp new file mode 100644 index 000000000..e7b1b2248 --- /dev/null +++ b/include/mapnik/renderer_common/render_group_symbolizer.hpp @@ -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 +#include +#include +#include +#include + +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 const& clipping_extent, + renderer_common & common, + render_thunk_list_dispatch & render_thunks); + +} // namespace mapnik + +#endif // MAPNIK_RENDERER_COMMON_RENDER_GROUP_SYMBOLIZER_HPP diff --git a/include/mapnik/renderer_common/render_markers_symbolizer.hpp b/include/mapnik/renderer_common/render_markers_symbolizer.hpp new file mode 100644 index 000000000..42639fbb6 --- /dev/null +++ b/include/mapnik/renderer_common/render_markers_symbolizer.hpp @@ -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 +#include +#include +#include + +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 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 const& clip_box, + markers_renderer_context & renderer_context); + +} // namespace mapnik + +#endif // MAPNIK_RENDERER_COMMON_RENDER_MARKERS_SYMBOLIZER_HPP diff --git a/include/mapnik/renderer_common/render_thunk.hpp b/include/mapnik/renderer_common/render_thunk.hpp new file mode 100644 index 000000000..2a957d260 --- /dev/null +++ b/include/mapnik/renderer_common/render_thunk.hpp @@ -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 // composite_mode_e +#include // svg_attribute_type, svg_path_ptr +#include // halo_rasterizer_enum +#include +#include +#include +#include + +// agg +#include + +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; + // 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; +using render_thunk_ptr = std::unique_ptr; +using render_thunk_list = std::list; + +} // namespace mapnik + +#endif // MAPNIK_RENDERER_COMMON_RENDER_THUNK_HPP diff --git a/include/mapnik/renderer_common/render_thunk_extractor.hpp b/include/mapnik/renderer_common/render_thunk_extractor.hpp new file mode 100644 index 000000000..3ea86f6d7 --- /dev/null +++ b/include/mapnik/renderer_common/render_thunk_extractor.hpp @@ -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 +#include +#include +#include + +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 & box, + render_thunk_list & thunks, + feature_impl & feature, + attributes const& vars, + proj_transform const& prj_trans, + virtual_renderer_common & common, + box2d 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 + 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 & box_; + render_thunk_list & thunks_; + feature_impl & feature_; + attributes const& vars_; + proj_transform const& prj_trans_; + virtual_renderer_common & common_; + box2d clipping_extent_; + + void update_box() const; +}; + +} // namespace mapnik + +#endif // MAPNIK_RENDERER_COMMON_RENDER_THUNK_EXTRACTOR_HPP diff --git a/include/mapnik/text/glyph_positions.hpp b/include/mapnik/text/glyph_positions.hpp index e956edda8..72314c319 100644 --- a/include/mapnik/text/glyph_positions.hpp +++ b/include/mapnik/text/glyph_positions.hpp @@ -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 #include @@ -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 data_; @@ -88,8 +90,46 @@ private: pixel_position marker_pos_; box2d bbox_; }; + using glyph_positions_ptr = std::unique_ptr; using placements_list = std::list; -} -#endif // PLACEMENTS_LIST_HPP + +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); + } + } + + ~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 diff --git a/include/mapnik/text/renderer.hpp b/include/mapnik/text/renderer.hpp index 1b6bac112..a4cd76ed7 100644 --- a/include/mapnik/text/renderer.hpp +++ b/include/mapnik/text/renderer.hpp @@ -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; void prepare_glyphs(glyph_positions const& positions); diff --git a/include/mapnik/transform_processor.hpp b/include/mapnik/transform_processor.hpp index bec6bff3b..2e4bfa3ed 100644 --- a/include/mapnik/transform_processor.hpp +++ b/include/mapnik/transform_processor.hpp @@ -111,11 +111,11 @@ struct transform_processor vars_(v), scale_factor_(scale_factor) {} - void operator() (identity_node const&) + void operator() (identity_node const&) const { } - void operator() (matrix_node const& node) + void operator() (matrix_node const& node) const { double a = eval(node.a_); // scale x; double b = eval(node.b_); @@ -126,21 +126,21 @@ struct transform_processor transform_.multiply(agg::trans_affine(a, b, c, d, e, f)); } - void operator() (translate_node const& node) + void operator() (translate_node const& node) const { double tx = eval(node.tx_) * scale_factor_; double ty = eval(node.ty_, 0.0) * scale_factor_; transform_.translate(tx, ty); } - void operator() (scale_node const& node) + void operator() (scale_node const& node) const { double sx = eval(node.sx_); double sy = eval(node.sy_, sx); transform_.scale(sx, sy); } - void operator() (rotate_node const& node) + void operator() (rotate_node const& node) const { double angle = deg2rad(eval(node.angle_)); double cx = eval(node.cx_, 0.0); @@ -150,7 +150,7 @@ struct transform_processor transform_.translate(cx, cy); } - void operator() (skewX_node const& node) + void operator() (skewX_node const& node) const { auto degrees = std::fmod(eval(node.angle_),90.0); if (degrees < -89.0) degrees = -89.0; @@ -159,7 +159,7 @@ struct transform_processor transform_.multiply(agg::trans_affine_skewing(angle, 0.0)); } - void operator() (skewY_node const& node) + void operator() (skewY_node const& node) const { auto degrees = std::fmod(eval(node.angle_),90.0); if (degrees < -89.0) degrees = -89.0; diff --git a/include/mapnik/util/noncopyable.hpp b/include/mapnik/util/noncopyable.hpp index 1cd4a4a31..7a6a9f8f7 100644 --- a/include/mapnik/util/noncopyable.hpp +++ b/include/mapnik/util/noncopyable.hpp @@ -28,6 +28,15 @@ namespace mapnik { namespace util { namespace non_copyable_ { +class movable +{ +protected: + constexpr movable() = default; + ~movable() = default; + movable( movable && ) = default; + movable& operator=(movable && ) = default; +}; + class noncopyable { protected: @@ -36,8 +45,10 @@ protected: noncopyable( noncopyable const& ) = delete; noncopyable& operator=(noncopyable const& ) = delete; }; + } +using movable = non_copyable_::movable; using noncopyable = non_copyable_::noncopyable; }} diff --git a/include/mapnik/util/spatial_index.hpp b/include/mapnik/util/spatial_index.hpp index da30f058e..b0c26ed4b 100644 --- a/include/mapnik/util/spatial_index.hpp +++ b/include/mapnik/util/spatial_index.hpp @@ -69,7 +69,7 @@ bool spatial_index::check_header(InputStream& in) template box2d spatial_index::bounding_box(InputStream& in) { - if (!check_header(in)) throw std::runtime_error("Invalid index file"); + if (!check_header(in)) throw std::runtime_error("Invalid index file (regenerate with shapeindex)"); in.seekg(16 + 4, std::ios::beg); box2d box; read_envelope(in, box); @@ -80,7 +80,7 @@ box2d spatial_index::bounding_box(InputStrea template void spatial_index::query(Filter const& filter, InputStream& in, std::vector& results) { - if (!check_header(in)) throw std::runtime_error("Invalid index file"); + if (!check_header(in)) throw std::runtime_error("Invalid index file (regenerate with shapeindex)"); in.seekg(16, std::ios::beg); query_node(filter, in, results); } @@ -115,7 +115,7 @@ void spatial_index::query_node(Filter const& filter, template void spatial_index::query_first_n(Filter const& filter, InputStream& in, std::vector& results, std::size_t count) { - if (!check_header(in)) throw std::runtime_error("Invalid index file"); + if (!check_header(in)) throw std::runtime_error("Invalid index file (regenerate with shapeindex)"); in.seekg(16, std::ios::beg); query_first_n_impl(filter, in, results, count); } diff --git a/include/mapnik/util/variant.hpp b/include/mapnik/util/variant.hpp index 8473903e0..61832a0b7 100644 --- a/include/mapnik/util/variant.hpp +++ b/include/mapnik/util/variant.hpp @@ -46,30 +46,31 @@ public: // unary visitor interface // const -template -auto VARIANT_INLINE static apply_visitor(F f, V const& v) -> decltype(V::visit(v, f)) +template +auto VARIANT_INLINE static apply_visitor(F && f, V const& v) -> decltype(V::visit(v, f)) { - return V::visit(v, f); + return V::visit(v, std::forward(f)); } // non-const -template -auto VARIANT_INLINE static apply_visitor(F f, V & v) -> decltype(V::visit(v, f)) +template +auto VARIANT_INLINE static apply_visitor(F && f, V & v) -> decltype(V::visit(v, f)) { - return V::visit(v, f); + return V::visit(v, std::forward(f)); } // binary visitor interface // const -template -auto VARIANT_INLINE static apply_visitor(F f, V const& v0, V const& v1) -> decltype(V::binary_visit(v0, v1, f)) +template +auto VARIANT_INLINE static apply_visitor(F && f, V const& v0, V const& v1) -> decltype(V::binary_visit(v0, v1, f)) { - return V::binary_visit(v0, v1, f); + return V::binary_visit(v0, v1, std::forward(f)); } + // non-const -template -auto VARIANT_INLINE static apply_visitor(F f, V & v0, V & v1) -> decltype(V::binary_visit(v0, v1, f)) +template +auto VARIANT_INLINE static apply_visitor(F && f, V & v0, V & v1) -> decltype(V::binary_visit(v0, v1, f)) { - return V::binary_visit(v0, v1, f); + return V::binary_visit(v0, v1, std::forward(f)); } // getter interface diff --git a/include/mapnik/vertex_processor.hpp b/include/mapnik/vertex_processor.hpp index a3b63c133..7cd2c40a4 100644 --- a/include/mapnik/vertex_processor.hpp +++ b/include/mapnik/vertex_processor.hpp @@ -35,38 +35,38 @@ struct vertex_processor : proc_(proc) {} template - void operator() (Geometry const& geom) + void operator() (Geometry const& geom) const { util::apply_visitor(*this, geom); } - void operator() (geometry_empty const&) + void operator() (geometry_empty const&) const { // no-op } - + template - void operator() (point const& pt) + void operator() (point const& pt) const { point_vertex_adapter va(pt); proc_(va); } template - void operator() (line_string const& line) + void operator() (line_string const& line) const { line_string_vertex_adapter va(line); proc_(va); } template - void operator() (polygon const& poly) + void operator() (polygon const& poly) const { polygon_vertex_adapter va(poly); proc_(va); } template - void operator() (multi_point const& multi_pt) + void operator() (multi_point const& multi_pt) const { for (auto const& pt : multi_pt) { @@ -76,7 +76,7 @@ struct vertex_processor } template - void operator() (multi_line_string const& multi_line) + void operator() (multi_line_string const& multi_line) const { for (auto const& line : multi_line) { @@ -86,7 +86,7 @@ struct vertex_processor } template - void operator() (multi_polygon const& multi_poly) + void operator() (multi_polygon const& multi_poly) const { for ( auto const& poly : multi_poly) { @@ -96,7 +96,7 @@ struct vertex_processor } template - void operator() (geometry_collection const& collection) + void operator() (geometry_collection const& collection) const { for (auto const& geom : collection) { diff --git a/src/agg/agg_renderer.cpp b/src/agg/agg_renderer.cpp index 74e3c935b..9fbcdca4b 100644 --- a/src/agg/agg_renderer.cpp +++ b/src/agg/agg_renderer.cpp @@ -121,11 +121,11 @@ struct setup_agg_bg_visitor mode_(mode), opacity_(opacity) {} - void operator() (marker_null const&) {} + void operator() (marker_null const&) const {} - void operator() (marker_svg const&) {} + void operator() (marker_svg const&) const {} - void operator() (marker_rgba8 const& marker) + void operator() (marker_rgba8 const& marker) const { mapnik::image_rgba8 const& bg_image = marker.get_data(); std::size_t w = bg_image.width(); @@ -361,9 +361,9 @@ struct agg_render_marker_visitor opacity_(opacity), comp_op_(comp_op) {} - void operator() (marker_null const&) {} + void operator() (marker_null const&) const {} - void operator() (marker_svg const& marker) + void operator() (marker_svg const& marker) const { using color_type = agg::rgba8; using order_type = agg::order_rgba; @@ -414,7 +414,7 @@ struct agg_render_marker_visitor svg_renderer.render(*ras_ptr_, sl, renb, mtx, opacity_, bbox); } - void operator() (marker_rgba8 const& marker) + void operator() (marker_rgba8 const& marker) const { using color_type = agg::rgba8; using order_type = agg::order_rgba; diff --git a/src/agg/process_debug_symbolizer.cpp b/src/agg/process_debug_symbolizer.cpp index c56add951..2016c456d 100644 --- a/src/agg/process_debug_symbolizer.cpp +++ b/src/agg/process_debug_symbolizer.cpp @@ -165,12 +165,12 @@ struct RingRenderer { }; template -struct render_ring_visitor { - +struct render_ring_visitor +{ render_ring_visitor(RingRenderer & renderer) : renderer_(renderer) {} - void operator()(mapnik::geometry::multi_polygon const& geom) + void operator()(mapnik::geometry::multi_polygon const& geom) const { for (auto const& poly : geom) { @@ -178,7 +178,7 @@ struct render_ring_visitor { } } - void operator()(mapnik::geometry::polygon const& geom) + void operator()(mapnik::geometry::polygon const& geom) const { agg::rgba8 red(255,0,0,255); agg::rgba8 green(0,255,255,255); @@ -199,7 +199,7 @@ struct render_ring_visitor { } template - void operator()(GeomType const&) {} + void operator()(GeomType const&) const {} RingRenderer & renderer_; }; diff --git a/src/agg/process_group_symbolizer.cpp b/src/agg/process_group_symbolizer.cpp index f2c8adf48..010d3f18a 100644 --- a/src/agg/process_group_symbolizer.cpp +++ b/src/agg/process_group_symbolizer.cpp @@ -25,20 +25,16 @@ #include #include #include -#include #include -#include #include -#include -#include -#include #include -#include #include +#include #include #include #include #include + // agg #include "agg_trans_affine.h" @@ -55,7 +51,7 @@ template struct thunk_renderer; template <> -struct thunk_renderer +struct thunk_renderer : render_thunk_list_dispatch { using renderer_type = agg_renderer; using buffer_type = renderer_type::buffer_type; @@ -64,12 +60,13 @@ struct thunk_renderer thunk_renderer(renderer_type &ren, std::unique_ptr 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; // comp blender using buf_type = agg::rendering_buffer; @@ -95,7 +92,7 @@ struct thunk_renderer 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; // comp blender using buf_type = agg::rendering_buffer; @@ -113,32 +110,25 @@ struct thunk_renderer 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_) + { + scoped_glyph_positions_offset tmp_off(*glyphs, offset_); + + if (auto const& mark = glyphs->get_marker()) { - marker_info_ptr mark = glyphs->get_marker(); - if (mark) - { - ren_.render_marker(glyphs->marker_pos(), - *mark->marker_, - mark->transform_, - thunk.opacity_, thunk.comp_op_); - } - ren.render(*glyphs); - }); - } - - template - void operator()(T const &) const - { - throw std::runtime_error("Rendering of this data type is not supported currently by the renderer"); + ren_.render_marker(glyphs->marker_pos(), + *mark->marker_, + mark->transform_, + thunk.opacity_, thunk.comp_op_); + } + tex_.render(*glyphs); + } } private: @@ -146,7 +136,7 @@ private: std::unique_ptr const& ras_ptr_; buffer_type *buf_; renderer_common &common_; - pixel_position offset_; + text_renderer_type tex_; }; template @@ -154,16 +144,11 @@ void agg_renderer::process(group_symbolizer const& sym, mapnik::feature_impl & feature, proj_transform const& prj_trans) { + thunk_renderer 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 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::process(group_symbolizer const&, diff --git a/src/agg/process_line_pattern_symbolizer.cpp b/src/agg/process_line_pattern_symbolizer.cpp index 17ec5bbf0..f5045c5a3 100644 --- a/src/agg/process_line_pattern_symbolizer.cpp +++ b/src/agg/process_line_pattern_symbolizer.cpp @@ -71,9 +71,9 @@ struct agg_renderer_process_visitor_l feature_(feature), prj_trans_(prj_trans) {} - void operator() (marker_null const&) {} + void operator() (marker_null const&) const {} - void operator() (marker_svg const& marker) + void operator() (marker_svg const& marker) const { using color = agg::rgba8; using order = agg::order_rgba; @@ -147,7 +147,7 @@ struct agg_renderer_process_visitor_l mapnik::util::apply_visitor(vertex_processor_type(apply),feature_.get_geometry()); } - void operator() (marker_rgba8 const& marker) + void operator() (marker_rgba8 const& marker) const { using color = agg::rgba8; using order = agg::order_rgba; @@ -214,7 +214,7 @@ struct agg_renderer_process_visitor_l using apply_vertex_converter_type = detail::apply_vertex_converter; using vertex_processor_type = geometry::vertex_processor; apply_vertex_converter_type apply(converter, ras); - mapnik::util::apply_visitor(vertex_processor_type(apply),feature_.get_geometry()); + mapnik::util::apply_visitor(vertex_processor_type(apply), feature_.get_geometry()); } private: diff --git a/src/agg/process_markers_symbolizer.cpp b/src/agg/process_markers_symbolizer.cpp index 767d0951a..b229f01af 100644 --- a/src/agg/process_markers_symbolizer.cpp +++ b/src/agg/process_markers_symbolizer.cpp @@ -24,22 +24,15 @@ #include #include #include - -#include -#include -#include -#include -#include -#include #include #include #include #include #include #include -#include -#include #include +#include + // 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 - namespace mapnik { namespace detail { -template -struct vector_markers_rasterizer_dispatch : public vector_markers_dispatch +template +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, - attributes const& vars, - bool snap_to_pixels, - RendererContext const& renderer_context) -: vector_markers_dispatch(src, marker_trans, sym, detector, scale_factor, feature, vars), - buf_(std::get<0>(renderer_context)), + agg_markers_renderer_context(symbolizer_base const& sym, + feature_impl const& feature, + attributes const& vars, + 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(get(sym, feature, vars))); + auto comp_op = get(sym, feature, vars); + pixf_.comp_op(static_cast(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 -struct raster_markers_rasterizer_dispatch : public raster_markers_dispatch -{ - using BufferType = typename std::remove_reference::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; // comp blender - using pixfmt_comp_type = agg::pixfmt_custom_blend_rgba; - using renderer_base = agg::renderer_base; - - 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(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(get(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 void agg_renderer::process(markers_symbolizer const& sym, @@ -194,16 +135,16 @@ void agg_renderer::process(markers_symbolizer const& sym, buf_type render_buffer(current_buffer_->bytes(), current_buffer_->width(), current_buffer_->height(), current_buffer_->row_size()); box2d 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; - using raster_dispatch_type = detail::raster_markers_rasterizer_dispatch; + using context_type = detail::agg_markers_renderer_context; + context_type renderer_context(sym, feature, common_.vars_, render_buffer, *ras_ptr); - render_markers_symbolizer( + render_markers_symbolizer( sym, feature, prj_trans, common_, clip_box, renderer_context); } template void agg_renderer::process(markers_symbolizer const&, mapnik::feature_impl &, proj_transform const&); -} +} // namespace mapnik diff --git a/src/agg/process_point_symbolizer.cpp b/src/agg/process_point_symbolizer.cpp index 8dc40f1af..1da740fe6 100644 --- a/src/agg/process_point_symbolizer.cpp +++ b/src/agg/process_point_symbolizer.cpp @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include diff --git a/src/agg/process_polygon_pattern_symbolizer.cpp b/src/agg/process_polygon_pattern_symbolizer.cpp index fb00b2a00..8e340a9a8 100644 --- a/src/agg/process_polygon_pattern_symbolizer.cpp +++ b/src/agg/process_polygon_pattern_symbolizer.cpp @@ -75,9 +75,9 @@ struct agg_renderer_process_visitor_p feature_(feature), prj_trans_(prj_trans) {} - void operator() (marker_null const&) {} + void operator() (marker_null const&) const {} - void operator() (marker_svg const& marker) + void operator() (marker_svg const& marker) const { agg::trans_affine image_tr = agg::trans_affine_scaling(common_.scale_factor_); auto image_transform = get_optional(sym_, keys::image_transform); @@ -180,7 +180,7 @@ struct agg_renderer_process_visitor_p agg::render_scanlines(*ras_ptr_, sl, rp); } - void operator() (marker_rgba8 const& marker) + void operator() (marker_rgba8 const& marker) const { using color = agg::rgba8; using order = agg::order_rgba; diff --git a/src/build.py b/src/build.py index 75bef48bf..28b2cc343 100644 --- a/src/build.py +++ b/src/build.py @@ -154,6 +154,7 @@ source = Split( well_known_srs.cpp params.cpp image_filter_types.cpp + image_filter_grammar.cpp miniz_png.cpp color.cpp conversions.cpp @@ -252,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 """ ) diff --git a/src/cairo/cairo_renderer.cpp b/src/cairo/cairo_renderer.cpp index 17723071c..83e1208b1 100644 --- a/src/cairo/cairo_renderer.cpp +++ b/src/cairo/cairo_renderer.cpp @@ -104,10 +104,10 @@ struct setup_marker_visitor setup_marker_visitor(cairo_context & context, renderer_common const& common) : context_(context), common_(common) {} - void operator() (marker_null const &) {} - void operator() (marker_svg const &) {} + void operator() (marker_null const &) const{} + void operator() (marker_svg const &) const {} - void operator() (marker_rgba8 const& marker) + void operator() (marker_rgba8 const& marker) const { mapnik::image_rgba8 const& bg_image = marker.get_data(); std::size_t w = bg_image.width(); diff --git a/src/cairo/process_group_symbolizer.cpp b/src/cairo/process_group_symbolizer.cpp index 6479c0f31..0885df49d 100644 --- a/src/cairo/process_group_symbolizer.cpp +++ b/src/cairo/process_group_symbolizer.cpp @@ -25,13 +25,12 @@ // mapnik #include #include -#include #include #include #include // mapnik symbolizer generics -#include +#include #include @@ -49,20 +48,19 @@ namespace { // to render it, and the boxes themselves should already be // in the detector from the placement_finder. template -struct thunk_renderer +struct thunk_renderer : render_thunk_list_dispatch { using renderer_type = cairo_renderer; 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_); @@ -80,7 +78,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_); @@ -90,32 +88,24 @@ 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) - { - marker_info_ptr mark = glyphs->get_marker(); - if (mark) - { - ren_.render_marker(glyphs->marker_pos(), - *mark->marker_, - mark->transform_, - thunk.opacity_, thunk.comp_op_); - } - context_.add_text(*glyphs, face_manager_, src_over, src_over, common_.scale_factor_); - }); - } + for (auto const& glyphs : thunk.placements_) + { + scoped_glyph_positions_offset tmp_off(*glyphs, offset_); - template - void operator()(T0 const &) const - { - throw std::runtime_error("Rendering of this type is not supported by the cairo renderer."); + if (auto const& mark = glyphs->get_marker()) + { + ren_.render_marker(glyphs->marker_pos(), + *mark->marker_, + mark->transform_, + thunk.opacity_, thunk.comp_op_); + } + context_.add_text(*glyphs, face_manager_, src_over, src_over, common_.scale_factor_); + } } private: @@ -123,7 +113,6 @@ private: cairo_context & context_; cairo_face_manager & face_manager_; renderer_common & common_; - pixel_position offset_; }; } // anonymous namespace @@ -133,16 +122,11 @@ void cairo_renderer::process(group_symbolizer const& sym, mapnik::feature_impl & feature, proj_transform const& prj_trans) { + thunk_renderer 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 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::process(group_symbolizer const&, diff --git a/src/cairo/process_markers_symbolizer.cpp b/src/cairo/process_markers_symbolizer.cpp index faffd3d6a..73b84ecb7 100644 --- a/src/cairo/process_markers_symbolizer.cpp +++ b/src/cairo/process_markers_symbolizer.cpp @@ -25,90 +25,46 @@ // mapnik #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// agg -#include "agg/include/agg_array.h" // for pod_bvector -#include "agg/include/agg_trans_affine.h" // for trans_affine, etc +#include +#include namespace mapnik { -class feature_impl; -class proj_transform; - namespace detail { -template -struct vector_markers_dispatch_cairo : public vector_markers_dispatch +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(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 -struct raster_markers_dispatch_cairo : public raster_markers_dispatch -{ - 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(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) + virtual void render_marker(image_rgba8 const& src, + markers_dispatch_params const& params, + agg::trans_affine const& marker_tr) { - ctx_.add_image(marker_tr, this->src_, opacity); + ctx_.add_image(marker_tr, src, params.opacity); } private: cairo_context & ctx_; }; -} +} // namespace detail template void cairo_renderer::process(markers_symbolizer const& sym, @@ -120,17 +76,10 @@ void cairo_renderer::process(markers_symbolizer const& sym, context_.set_operator(comp_op); box2d 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; - - using raster_dispatch_type = detail::raster_markers_dispatch_cairo; - - - render_markers_symbolizer( + render_markers_symbolizer( sym, feature, prj_trans, common_, clip_box, renderer_context); } @@ -139,6 +88,6 @@ template void cairo_renderer::process(markers_symbolizer const&, mapnik::feature_impl &, proj_transform const&); -} +} // namespace mapnik #endif // HAVE_CAIRO diff --git a/src/font_engine_freetype.cpp b/src/font_engine_freetype.cpp index 2feb7c526..3558f75c9 100644 --- a/src/font_engine_freetype.cpp +++ b/src/font_engine_freetype.cpp @@ -362,7 +362,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) @@ -377,8 +377,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; } @@ -392,7 +392,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; } diff --git a/src/grid/process_group_symbolizer.cpp b/src/grid/process_group_symbolizer.cpp index f73118969..a93ea9d59 100644 --- a/src/grid/process_group_symbolizer.cpp +++ b/src/grid/process_group_symbolizer.cpp @@ -29,25 +29,13 @@ #include #include #include -#include -#include -#include #include #include #include #include #include #include -#include -#include -#include -#include -#include -#include - -#include -#include -#include +#include // agg #include "agg_trans_affine.h" @@ -61,7 +49,7 @@ namespace mapnik { * in the detector from the placement_finder. */ template -struct thunk_renderer +struct thunk_renderer : render_thunk_list_dispatch { using renderer_type = grid_renderer; 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,34 +110,28 @@ 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) - { - marker_info_ptr mark = glyphs->get_marker(); - if (mark) - { - ren_.render_marker(feature_, - glyphs->marker_pos(), - *mark->marker_, - mark->transform_, - thunk.opacity_, thunk.comp_op_); - } - ren.render(*glyphs, feature_id); - }); - pixmap_.add_feature(feature_); - } + for (auto const& glyphs : thunk.placements_) + { + scoped_glyph_positions_offset tmp_off(*glyphs, offset_); - template - void operator()(T1 const &) const - { - // TODO: warning if unimplemented? + if (auto const& mark = glyphs->get_marker()) + { + ren_.render_marker(feature_, + glyphs->marker_pos(), + *mark->marker_, + mark->transform_, + thunk.opacity_, thunk.comp_op_); + } + tex_.render(*glyphs, feature_id); + } + + 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 @@ -166,16 +148,11 @@ void grid_renderer::process(group_symbolizer const& sym, mapnik::feature_impl & feature, proj_transform const& prj_trans) { + thunk_renderer 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 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::process(group_symbolizer const&, diff --git a/src/grid/process_markers_symbolizer.cpp b/src/grid/process_markers_symbolizer.cpp index 52d3f5577..2fa71c880 100644 --- a/src/grid/process_markers_symbolizer.cpp +++ b/src/grid/process_markers_symbolizer.cpp @@ -44,146 +44,92 @@ porting notes --> */ // mapnik -#include -#include -#include #include #include #include #include #include - -#include -#include -#include -#include -#include #include #include #include #include -#include -#include +#include // agg #include "agg_basics.h" #include "agg_rendering_buffer.h" #include "agg_rasterizer_scanline_aa.h" -// boost -#include - -// stl -#include -#include - namespace mapnik { namespace detail { -template -struct vector_markers_rasterizer_dispatch : public vector_markers_dispatch +template +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(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 -struct raster_markers_rasterizer_dispatch : public raster_markers_dispatch -{ - 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(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 void grid_renderer::process(markers_symbolizer const& sym, @@ -193,7 +139,6 @@ void grid_renderer::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; - using detector_type = label_collision_detector4; using namespace mapnik::svg; using svg_attribute_type = agg::pod_bvector; @@ -206,22 +151,20 @@ void grid_renderer::process(markers_symbolizer const& sym, ras_ptr->reset(); box2d 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; - using raster_dispatch_type = detail::raster_markers_rasterizer_dispatch; - render_markers_symbolizer( - sym, feature, prj_trans, common_, clip_box,renderer_context); + using context_type = detail::grid_markers_renderer_context; + 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::process(markers_symbolizer const&, mapnik::feature_impl &, proj_transform const&); -} +} // namespace mapnik #endif diff --git a/src/grid/process_point_symbolizer.cpp b/src/grid/process_point_symbolizer.cpp index 731291d78..130fc1fc2 100644 --- a/src/grid/process_point_symbolizer.cpp +++ b/src/grid/process_point_symbolizer.cpp @@ -30,7 +30,6 @@ #include #include -#include #include #include #include diff --git a/src/group/group_layout_manager.cpp b/src/group/group_layout_manager.cpp index fe00e7d02..ad9aaad7c 100644 --- a/src/group/group_layout_manager.cpp +++ b/src/group/group_layout_manager.cpp @@ -34,19 +34,21 @@ namespace mapnik // This visitor will process offsets for the given layout struct process_layout { + using bound_box = box2d; + // The vector containing the existing, centered item bounding boxes - vector const& member_boxes_; + std::vector const& member_boxes_; // The vector to populate with item offsets - vector & member_offsets_; + std::vector & 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 const& member_bboxes, - vector &member_offsets, + process_layout(std::vector const& member_bboxes, + std::vector &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 group_layout_manager::offset_box_at(size_t i) { handle_update(); pixel_position const& offset = member_offsets_.at(i); diff --git a/src/image_compositing.cpp b/src/image_compositing.cpp index 12633cbc2..925f56e64 100644 --- a/src/image_compositing.cpp +++ b/src/image_compositing.cpp @@ -190,7 +190,7 @@ struct composite_visitor dy_(dy) {} template - void operator() (T & dst); + void operator() (T & dst) const; private: image_any const& src_; @@ -201,19 +201,19 @@ struct composite_visitor }; template -void composite_visitor::operator() (T & dst) +void composite_visitor::operator() (T & dst) const { throw std::runtime_error("Error: Composite with " + std::string(typeid(dst).name()) + " is not supported"); } template <> -void composite_visitor::operator() (image_rgba8 & dst) +void composite_visitor::operator() (image_rgba8 & dst) const { composite(dst, util::get(src_), mode_, opacity_, dx_, dy_); } template <> -void composite_visitor::operator() (image_gray32f & dst) +void composite_visitor::operator() (image_gray32f & dst) const { composite(dst, util::get(src_), mode_, opacity_, dx_, dy_); } diff --git a/src/image_copy.cpp b/src/image_copy.cpp index 01225c25b..04fa75c32 100644 --- a/src/image_copy.cpp +++ b/src/image_copy.cpp @@ -37,7 +37,7 @@ struct visitor_image_copy { using dst_type = typename T0::pixel_type; - T0 operator() (image_null const&) + T0 operator() (image_null const&) const { throw std::runtime_error("Can not cast a null image"); } @@ -48,7 +48,7 @@ struct visitor_image_copy } template - T0 operator() (T1 const& src) + T0 operator() (T1 const& src) const { T0 dst(safe_cast(src.width()), safe_cast(src.height()), false); for (std::size_t y = 0; y < dst.height(); ++y) @@ -75,7 +75,7 @@ struct visitor_image_copy_so throw std::runtime_error("Can not cast a null image"); } - T0 operator() (T0 const& src) + T0 operator() (T0 const& src) const { if (offset_ == src.get_offset() && scaling_ == src.get_scaling()) { @@ -91,7 +91,7 @@ struct visitor_image_copy_so } template - T0 operator() (T1 const& src) + T0 operator() (T1 const& src) const { double src_offset = src.get_offset(); double src_scaling = src.get_scaling(); diff --git a/src/image_filter_grammar.cpp b/src/image_filter_grammar.cpp new file mode 100644 index 000000000..9a4bea35a --- /dev/null +++ b/src/image_filter_grammar.cpp @@ -0,0 +1,29 @@ +/***************************************************************************** + * + * 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 + * + *****************************************************************************/ + +#include +#include +#include +#include +#include + +template struct mapnik::image_filter_grammar>; diff --git a/src/image_filter_types.cpp b/src/image_filter_types.cpp index 6755757ec..d30804378 100644 --- a/src/image_filter_types.cpp +++ b/src/image_filter_types.cpp @@ -22,7 +22,6 @@ // mapnik #include #include -#include #pragma GCC diagnostic push #include diff --git a/src/image_util.cpp b/src/image_util.cpp index fdbd80c9b..43c599166 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -2087,7 +2087,7 @@ struct visitor_view_to_stream : os_(os) {} template - void operator() (T const& view) + void operator() (T const& view) const { for (std::size_t i=0;i - marker operator() (T &) + marker operator() (T &) const { throw std::runtime_error("Can not make marker from this data type"); } diff --git a/src/renderer_common.cpp b/src/renderer_common.cpp index 37223e35d..d45e3a03c 100644 --- a/src/renderer_common.cpp +++ b/src/renderer_common.cpp @@ -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 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 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 +} + } diff --git a/src/renderer_common/process_group_symbolizer.cpp b/src/renderer_common/process_group_symbolizer.cpp deleted file mode 100644 index 50dc9f63a..000000000 --- a/src/renderer_common/process_group_symbolizer.cpp +++ /dev/null @@ -1,235 +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 -#include -#include - -#include - -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 -struct vector_marker_thunk_dispatch : public vector_markers_dispatch -{ - 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(src, marker_trans, sym, detector, scale_factor, feature, vars), - attrs_(attrs), comp_op_(get(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(std::move(thunk))); - } - -private: - svg_attribute_type const& attrs_; - composite_mode_e comp_op_; - bool snap_to_pixels_; - render_thunk_list & thunks_; -}; - -template -struct raster_marker_thunk_dispatch : public raster_markers_dispatch -{ - 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(src, marker_trans, sym, detector, scale_factor, feature, vars), - comp_op_(get(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(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 & box, - render_thunk_list & thunks, - feature_impl & feature, - attributes const& vars, - proj_transform const& prj_trans, - virtual_renderer_common & common, - box2d 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; - using raster_dispatch_type = detail::raster_marker_thunk_dispatch; - - render_markers_symbolizer( - sym, feature_, prj_trans_, common_, clipping_extent_, renderer_context); - - update_box(); -} - -void render_thunk_extractor::operator()(text_symbolizer const& sym) const -{ - box2d clip_box = clipping_extent_; - helper_ptr helper = std::make_unique( - 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 clip_box = clipping_extent_; - helper_ptr helper = std::make_unique( - 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(sym, keys::opacity, feature_, common_.vars_, 1.0); - composite_mode_e comp_op = get(sym, keys::comp_op, feature_, common_.vars_, src_over); - halo_rasterizer_enum halo_rasterizer = get(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(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 diff --git a/src/renderer_common/render_group_symbolizer.cpp b/src/renderer_common/render_group_symbolizer.cpp new file mode 100644 index 000000000..9892dfc8d --- /dev/null +++ b/src/renderer_common/render_group_symbolizer.cpp @@ -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 +#include +#include +#include +#include +#include +#include +#include + +namespace mapnik { + +void render_group_symbolizer(group_symbolizer const& sym, + feature_impl & feature, + attributes const& vars, + proj_transform const& prj_trans, + box2d 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 columns; + group_attribute_collector column_collector(columns, false); + column_collector(sym); + + auto props = get(sym, keys::group_properties); + + // create a new context for the sub features of this group + context_ptr sub_feature_ctx = std::make_shared(); + + // 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 > 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 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(sym, keys::start_column); + value_integer end = start + get(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 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(*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 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(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(*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 diff --git a/include/mapnik/renderer_common/process_markers_symbolizer.hpp b/src/renderer_common/render_markers_symbolizer.cpp similarity index 84% rename from include/mapnik/renderer_common/process_markers_symbolizer.hpp rename to src/renderer_common/render_markers_symbolizer.cpp index 1009d2fcf..7864d3bef 100644 --- a/include/mapnik/renderer_common/process_markers_symbolizer.hpp +++ b/src/renderer_common/render_markers_symbolizer.cpp @@ -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 #include #include #include #include #include +#include +#include namespace mapnik { -template +namespace detail { + +template 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; + using raster_dispatch_type = raster_markers_dispatch; using vertex_converter_type = vertex_converter const& clip_box, - ContextType const& renderer_context) + ContextType & renderer_context) : filename_(filename), sym_(sym), feature_(feature), @@ -62,9 +62,9 @@ struct render_marker_symbolizer_visitor clip_box_(clip_box), renderer_context_(renderer_context) {} - void operator() (marker_null const&) {} + void operator() (marker_null const&) const {} - void operator() (marker_svg const& mark) + void operator() (marker_svg const& mark) const { using namespace mapnik::svg; bool clip = get(sym_, feature_, common_.vars_); @@ -179,7 +179,7 @@ struct render_marker_symbolizer_visitor } } - void operator() (marker_rgba8 const& mark) + void operator() (marker_rgba8 const& mark) const { using namespace mapnik::svg; bool clip = get(sym_, feature_, common_.vars_); @@ -243,33 +243,57 @@ struct render_marker_symbolizer_visitor proj_transform const& prj_trans_; RendererType const& common_; box2d const& clip_box_; - ContextType const& renderer_context_; + ContextType & renderer_context_; }; -template +} // namespace detail + +markers_dispatch_params::markers_dispatch_params(box2d 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(sym, feature, vars), + .max_error = get(sym, feature, vars), + .allow_overlap = get(sym, feature, vars), + .avoid_edges = get(sym, feature, vars), + .direction = get(sym, feature, vars)} + , placement_method(get(sym, feature, vars)) + , ignore_placement(get(sym, feature, vars)) + , snap_to_pixels(snap) + , scale_factor(scale) + , opacity(get(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 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; + std::string filename = get(sym, keys::file, feature, common.vars_, "shape://ellipse"); if (!filename.empty()) { - std::shared_ptr mark = mapnik::marker_cache::instance().find(filename, true); - render_marker_symbolizer_visitor visitor(filename, - sym, - feature, - prj_trans, - common, - clip_box, - renderer_context); + 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 diff --git a/src/renderer_common/render_thunk_extractor.cpp b/src/renderer_common/render_thunk_extractor.cpp new file mode 100644 index 000000000..c437262da --- /dev/null +++ b/src/renderer_common/render_thunk_extractor.cpp @@ -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 +#include +#include +#include + +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(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(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(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(std::move(thunk))); + } + +private: + composite_mode_e comp_op_; + render_thunk_list & thunks_; +}; + +} // namespace detail + +render_thunk_extractor::render_thunk_extractor(box2d & box, + render_thunk_list & thunks, + feature_impl & feature, + attributes const& vars, + proj_transform const& prj_trans, + virtual_renderer_common & common, + box2d 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( + 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( + 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(sym, keys::opacity, feature_, common_.vars_, 1.0); + composite_mode_e comp_op = get(sym, keys::comp_op, feature_, common_.vars_, src_over); + halo_rasterizer_enum halo_rasterizer = get(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(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 diff --git a/src/svg/output/svg_renderer.cpp b/src/svg/output/svg_renderer.cpp index c110e5e8c..569164645 100644 --- a/src/svg/output/svg_renderer.cpp +++ b/src/svg/output/svg_renderer.cpp @@ -27,7 +27,6 @@ #include #include #include -#include #include #include diff --git a/src/text/glyph_positions.cpp b/src/text/glyph_positions.cpp index da3b30084..fdcb3a811 100644 --- a/src/text/glyph_positions.cpp +++ b/src/text/glyph_positions.cpp @@ -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_; } diff --git a/src/text/renderer.cpp b/src/text/renderer.cpp index 227c35dbe..163d11c6f 100644 --- a/src/text/renderer.cpp +++ b/src/text/renderer.cpp @@ -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::agg_text_renderer (pixmap_type & pixmap, template void agg_text_renderer::render(glyph_positions const& pos) { - glyphs_.clear(); prepare_glyphs(pos); FT_Error error; FT_Vector start; @@ -232,7 +233,6 @@ void agg_text_renderer::render(glyph_positions const& pos) template void grid_text_renderer::render(glyph_positions const& pos, value_integer feature_id) { - glyphs_.clear(); prepare_glyphs(pos); FT_Error error; FT_Vector start; diff --git a/src/warp.cpp b/src/warp.cpp index b250d6e39..4a468a8b3 100644 --- a/src/warp.cpp +++ b/src/warp.cpp @@ -181,10 +181,10 @@ struct warp_image_visitor nodata_value_(nodata_value) {} - void operator() (image_null const&) {} + void operator() (image_null const&) const {} template - void operator() (T const& source) + void operator() (T const& source) const { using image_type = T; //source and target image data types must match diff --git a/test/unit/datasource/postgis.cpp b/test/unit/datasource/postgis.cpp index 94ba4d9ec..268995216 100644 --- a/test/unit/datasource/postgis.cpp +++ b/test/unit/datasource/postgis.cpp @@ -76,17 +76,19 @@ TEST_CASE("postgis") { REQUIRE(run("psql -q -f ./test/data/sql/postgis-create-db-and-tables.sql " + dbname)); } - mapnik::parameters params; - params["type"] = "postgis"; - params["dbname"] = dbname; + mapnik::parameters base_params; + base_params["type"] = "postgis"; + base_params["dbname"] = dbname; SECTION("Postgis should throw without 'table' parameter") { + mapnik::parameters params(base_params); CHECK_THROWS(mapnik::datasource_cache::instance().create(params)); } SECTION("Postgis should throw with 'max_async_connection' greater than 'max_size'") { + mapnik::parameters params(base_params); params["table"] = "test"; params["max_async_connection"] = "2"; params["max_size"] = "1"; @@ -95,12 +97,14 @@ TEST_CASE("postgis") { SECTION("Postgis should throw with invalid metadata query") { + mapnik::parameters params(base_params); params["table"] = "does_not_exist"; CHECK_THROWS(mapnik::datasource_cache::instance().create(params)); } SECTION("Postgis should throw with invalid key field") { + mapnik::parameters params(base_params); params["table"] = "test_invalid_id"; params["key_field"] = "id"; CHECK_THROWS(mapnik::datasource_cache::instance().create(params)); @@ -108,6 +112,7 @@ TEST_CASE("postgis") { SECTION("Postgis should throw with multicolumn primary key") { + mapnik::parameters params(base_params); params["table"] = "test_invalid_multi_col_pk"; params["autodetect_key_field"] = "true"; CHECK_THROWS(mapnik::datasource_cache::instance().create(params)); @@ -115,6 +120,7 @@ TEST_CASE("postgis") { SECTION("Postgis should throw without geom column") { + mapnik::parameters params(base_params); params["table"] = "test_no_geom_col"; auto ds = mapnik::datasource_cache::instance().create(params); REQUIRE(ds != nullptr); @@ -123,6 +129,7 @@ TEST_CASE("postgis") { SECTION("Postgis should throw with invalid credentials") { + mapnik::parameters params(base_params); params["table"] = "test"; params["user"] = "not_a_valid_user"; params["password"] = "not_a_valid_pwd"; @@ -131,6 +138,7 @@ TEST_CASE("postgis") { SECTION("Postgis initialize dataset with persist_connection, schema, extent, geometry field, autodectect key field, simplify_geometries, row_limit") { + mapnik::parameters params(base_params); params["persist_connection"] = "false"; params["table"] = "public.test"; params["geometry_field"] = "geom"; @@ -143,6 +151,7 @@ TEST_CASE("postgis") { SECTION("Postgis dataset geometry type") { + mapnik::parameters params(base_params); params["table"] = "(SELECT * FROM test WHERE gid=1) as data"; auto ds = mapnik::datasource_cache::instance().create(params); REQUIRE(ds != nullptr); @@ -151,6 +160,7 @@ TEST_CASE("postgis") { SECTION("Postgis query field names") { + mapnik::parameters params(base_params); params["table"] = "test"; auto ds = mapnik::datasource_cache::instance().create(params); REQUIRE(ds != nullptr); @@ -162,6 +172,7 @@ TEST_CASE("postgis") { SECTION("Postgis iterate features") { + mapnik::parameters params(base_params); params["table"] = "test"; params["key_field"] = "gid"; params["max_async_connection"] = "2"; @@ -192,6 +203,7 @@ TEST_CASE("postgis") { SECTION("Postgis cursorresultest") { + mapnik::parameters params(base_params); params["table"] = "(SELECT * FROM test) as data"; params["cursor_size"] = "2"; auto ds = mapnik::datasource_cache::instance().create(params); @@ -218,6 +230,7 @@ TEST_CASE("postgis") { SECTION("Postgis bbox query") { + mapnik::parameters params(base_params); params["table"] = "(SELECT * FROM public.test) as data WHERE geom && !bbox!"; auto ds = mapnik::datasource_cache::instance().create(params); REQUIRE(ds != nullptr); @@ -233,6 +246,7 @@ TEST_CASE("postgis") { SECTION("Postgis query extent: full dataset") { //include schema to increase coverage + mapnik::parameters params(base_params); params["table"] = "(SELECT * FROM public.test) as data"; auto ds = mapnik::datasource_cache::instance().create(params); REQUIRE(ds != nullptr); @@ -247,6 +261,7 @@ TEST_CASE("postgis") { /* deactivated for merging: still investigating a proper fix SECTION("Postgis query extent from subquery") { + mapnik::parameters params(base_params); params["table"] = "(SELECT * FROM test where gid=4) as data"; auto ds = mapnik::datasource_cache::instance().create(params); REQUIRE(ds != nullptr); @@ -261,6 +276,7 @@ TEST_CASE("postgis") { */ SECTION("Postgis query extent: from subquery with 'extent_from_subquery=true'") { + mapnik::parameters params(base_params); params["table"] = "(SELECT * FROM test where gid=4) as data"; params["extent_from_subquery"] = "true"; auto ds = mapnik::datasource_cache::instance().create(params); @@ -276,6 +292,7 @@ TEST_CASE("postgis") { /* deactivated for merging: still investigating a proper fix SECTION("Postgis query extent: subset with 'extent_from_subquery=true' and 'scale_denominator'") { + mapnik::parameters params(base_params); // !!!! postgis-vt-util::z() returns 'null' when 'scale_denominator > 600000000' // https://github.com/mapbox/postgis-vt-util/blob/559f073877696a6bfea41baf3e1065f9cf4d18d1/postgis-vt-util.sql#L615-L617 params["table"] = "(SELECT * FROM test where gid=4 AND z(!scale_denominator!) BETWEEN 0 AND 22) as data"; diff --git a/test/unit/geometry/geometry_equal.hpp b/test/unit/geometry/geometry_equal.hpp index cb4a30ddf..3907149ac 100644 --- a/test/unit/geometry/geometry_equal.hpp +++ b/test/unit/geometry/geometry_equal.hpp @@ -89,26 +89,26 @@ void assert_g_equal(geometry const& g1, geometry const& g2); struct geometry_equal_visitor { template - void operator() (T1 const&, T2 const&) + void operator() (T1 const&, T2 const&) const { // comparing two different types! REQUIRE(false); } - void operator() (geometry_empty const&, geometry_empty const&) + void operator() (geometry_empty const&, geometry_empty const&) const { REQUIRE(true); } template - void operator() (point const& p1, point const& p2) + void operator() (point const& p1, point const& p2) const { REQUIRE(p1.x == Approx(p2.x)); REQUIRE(p1.y == Approx(p2.y)); } template - void operator() (line_string const& ls1, line_string const& ls2) + void operator() (line_string const& ls1, line_string const& ls2) const { if (ls1.size() != ls2.size()) { @@ -123,7 +123,7 @@ struct geometry_equal_visitor } template - void operator() (polygon const& p1, polygon const& p2) + void operator() (polygon const& p1, polygon const& p2) const { (*this)(static_cast const&>(p1.exterior_ring), static_cast const&>(p2.exterior_ring)); @@ -139,13 +139,13 @@ struct geometry_equal_visitor } template - void operator() (multi_point const& mp1, multi_point const& mp2) + void operator() (multi_point const& mp1, multi_point const& mp2) const { (*this)(static_cast const&>(mp1), static_cast const&>(mp2)); } template - void operator() (multi_line_string const& mls1, multi_line_string const& mls2) + void operator() (multi_line_string const& mls1, multi_line_string const& mls2) const { if (mls1.size() != mls2.size()) { @@ -159,7 +159,7 @@ struct geometry_equal_visitor } template - void operator() (multi_polygon const& mpoly1, multi_polygon const& mpoly2) + void operator() (multi_polygon const& mpoly1, multi_polygon const& mpoly2) const { if (mpoly1.size() != mpoly2.size()) { @@ -173,7 +173,7 @@ struct geometry_equal_visitor } template - void operator() (mapnik::util::recursive_wrapper > const& c1_, mapnik::util::recursive_wrapper > const& c2_) + void operator() (mapnik::util::recursive_wrapper > const& c1_, mapnik::util::recursive_wrapper > const& c2_) const { geometry_collection const& c1 = static_cast const&>(c1_); geometry_collection const& c2 = static_cast const&>(c2_); @@ -189,7 +189,7 @@ struct geometry_equal_visitor } template - void operator() (geometry_collection const& c1, geometry_collection const& c2) + void operator() (geometry_collection const& c1, geometry_collection const& c2) const { if (c1.size() != c2.size()) { diff --git a/test/unit/geometry/geometry_is_valid.cpp b/test/unit/geometry/geometry_is_valid.cpp index 6d8fcf993..c36549b3e 100644 --- a/test/unit/geometry/geometry_is_valid.cpp +++ b/test/unit/geometry/geometry_is_valid.cpp @@ -43,6 +43,8 @@ SECTION("point -- geometry object") { CHECK( failure == boost::geometry::no_failure ); } +#if BOOST_VERSION < 106000 + SECTION("point unitialized") { mapnik::geometry::point pt2; CHECK( mapnik::geometry::is_valid(pt2) ); @@ -53,6 +55,7 @@ SECTION("point unitialized") { CHECK( mapnik::geometry::is_valid(pt2, failure2) ); CHECK( failure2 == boost::geometry::no_failure ); } +#endif #if BOOST_VERSION >= 106000 @@ -120,7 +123,7 @@ SECTION("point Infinity") { SECTION("multi point") { mapnik::geometry::multi_point mpt; - mpt.add_coord(0,0); + mpt.add_coord(0,0); mpt.add_coord(1,1); CHECK( mapnik::geometry::is_valid(mpt) ); std::string message; @@ -145,7 +148,7 @@ SECTION("multi point empty") { SECTION("line_string") { mapnik::geometry::line_string line; - line.add_coord(0,0); + line.add_coord(0,0); line.add_coord(1,1); CHECK( mapnik::geometry::is_valid(line) ); std::string message; @@ -159,7 +162,7 @@ SECTION("line_string") { // This shouldn't fail -- test added in case logic ever changes SECTION("line_string repeated points") { mapnik::geometry::line_string line; - line.add_coord(0,0); + line.add_coord(0,0); line.add_coord(1,1); line.add_coord(1,1); line.add_coord(2,2); @@ -185,10 +188,10 @@ SECTION("line_string empty") { SECTION("multi_line_string") { mapnik::geometry::line_string line1; - line1.add_coord(0,0); + line1.add_coord(0,0); line1.add_coord(1,1); mapnik::geometry::line_string line2; - line2.add_coord(0,1); + line2.add_coord(0,1); line2.add_coord(1,2); mapnik::geometry::multi_line_string lines; lines.emplace_back(line1); @@ -216,7 +219,7 @@ SECTION("multi_line_string empty") { SECTION("polygon") { mapnik::geometry::polygon poly; mapnik::geometry::linear_ring ring; - ring.add_coord(0,0); + ring.add_coord(0,0); ring.add_coord(1,0); ring.add_coord(1,1); ring.add_coord(0,1); @@ -234,7 +237,7 @@ SECTION("polygon") { SECTION("polygon invalid winding order") { mapnik::geometry::polygon poly; mapnik::geometry::linear_ring ring; - ring.add_coord(0,0); + ring.add_coord(0,0); ring.add_coord(0,1); ring.add_coord(1,1); ring.add_coord(1,0); @@ -253,7 +256,7 @@ SECTION("polygon invalid winding order") { SECTION("polygon 2 repeated points") { mapnik::geometry::polygon poly; mapnik::geometry::linear_ring ring; - ring.add_coord(0,0); + ring.add_coord(0,0); ring.add_coord(1,0); ring.add_coord(1,1); ring.add_coord(1,1); @@ -272,7 +275,7 @@ SECTION("polygon 2 repeated points") { SECTION("polygon 3 repeated points") { mapnik::geometry::polygon poly; mapnik::geometry::linear_ring ring; - ring.add_coord(0,0); + ring.add_coord(0,0); ring.add_coord(1,0); ring.add_coord(1,1); ring.add_coord(1,1); @@ -303,7 +306,7 @@ SECTION("polygon that is empty") { SECTION("polygon with spike") { mapnik::geometry::polygon poly; mapnik::geometry::linear_ring ring; - ring.add_coord(0,0); + ring.add_coord(0,0); ring.add_coord(1,0); ring.add_coord(1,1); ring.add_coord(2,2); @@ -323,14 +326,14 @@ SECTION("polygon with spike") { SECTION("polygon with hole") { mapnik::geometry::polygon poly; mapnik::geometry::linear_ring ring; - ring.add_coord(0,0); + ring.add_coord(0,0); ring.add_coord(3,0); ring.add_coord(3,3); ring.add_coord(0,3); ring.add_coord(0,0); poly.set_exterior_ring(std::move(ring)); mapnik::geometry::linear_ring hole; - hole.add_coord(1,1); + hole.add_coord(1,1); hole.add_coord(1,2); hole.add_coord(2,2); hole.add_coord(2,1); @@ -348,7 +351,7 @@ SECTION("polygon with hole") { SECTION("polygon with empty hole") { mapnik::geometry::polygon poly; mapnik::geometry::linear_ring ring; - ring.add_coord(0,0); + ring.add_coord(0,0); ring.add_coord(3,0); ring.add_coord(3,3); ring.add_coord(0,3); @@ -369,14 +372,14 @@ SECTION("polygon with empty hole") { SECTION("polygon with hole with invalid winding order") { mapnik::geometry::polygon poly; mapnik::geometry::linear_ring ring; - ring.add_coord(0,0); + ring.add_coord(0,0); ring.add_coord(3,0); ring.add_coord(3,3); ring.add_coord(0,3); ring.add_coord(0,0); poly.set_exterior_ring(std::move(ring)); mapnik::geometry::linear_ring hole; - hole.add_coord(1,1); + hole.add_coord(1,1); hole.add_coord(2,1); hole.add_coord(2,2); hole.add_coord(1,2); @@ -395,7 +398,7 @@ SECTION("multi polygon") { mapnik::geometry::multi_polygon mp; mapnik::geometry::polygon poly; mapnik::geometry::linear_ring ring; - ring.add_coord(0,0); + ring.add_coord(0,0); ring.add_coord(1,0); ring.add_coord(1,1); ring.add_coord(0,1); @@ -403,7 +406,7 @@ SECTION("multi polygon") { poly.set_exterior_ring(std::move(ring)); mapnik::geometry::polygon poly2; mapnik::geometry::linear_ring ring2; - ring2.add_coord(0,0); + ring2.add_coord(0,0); ring2.add_coord(-1,0); ring2.add_coord(-1,-1); ring2.add_coord(0,-1); @@ -424,14 +427,14 @@ SECTION("multi polygon with hole") { mapnik::geometry::multi_polygon mp; mapnik::geometry::polygon poly; mapnik::geometry::linear_ring ring; - ring.add_coord(0,0); + ring.add_coord(0,0); ring.add_coord(3,0); ring.add_coord(3,3); ring.add_coord(0,3); ring.add_coord(0,0); poly.set_exterior_ring(std::move(ring)); mapnik::geometry::linear_ring hole; - hole.add_coord(1,1); + hole.add_coord(1,1); hole.add_coord(1,2); hole.add_coord(2,2); hole.add_coord(2,1); @@ -439,14 +442,14 @@ SECTION("multi polygon with hole") { poly.add_hole(std::move(hole)); mapnik::geometry::polygon poly2; mapnik::geometry::linear_ring ring2; - ring2.add_coord(0,0); + ring2.add_coord(0,0); ring2.add_coord(-3,0); ring2.add_coord(-3,-3); ring2.add_coord(0,-3); ring2.add_coord(0,0); poly2.set_exterior_ring(std::move(ring2)); mapnik::geometry::linear_ring hole2; - hole2.add_coord(-1,-1); + hole2.add_coord(-1,-1); hole2.add_coord(-1,-2); hole2.add_coord(-2,-2); hole2.add_coord(-2,-1); diff --git a/test/visual/runner.cpp b/test/visual/runner.cpp index 5ff923172..d0c7222fb 100644 --- a/test/visual/runner.cpp +++ b/test/visual/runner.cpp @@ -57,13 +57,13 @@ public: } template ::type* = nullptr> - void operator()(T const & renderer) + void operator()(T const& renderer) const { test(renderer); } template ::type* = nullptr> - void operator()(T const & renderer) + void operator()(T const & renderer) const { if (tiles_.width == 1 && tiles_.height == 1) { @@ -73,7 +73,7 @@ public: private: template - void test(T const & renderer) + void test(T const & renderer) const { map_size size { map_.width(), map_.height() }; std::chrono::high_resolution_clock::time_point start(std::chrono::high_resolution_clock::now()); @@ -96,7 +96,7 @@ private: } template ::type* = nullptr> - typename T::image_type render(T const & renderer) + typename T::image_type render(T const& renderer) const { if (tiles_.width == 1 && tiles_.height == 1) { @@ -109,7 +109,7 @@ private: } template ::type* = nullptr> - typename T::image_type render(T const & renderer) + typename T::image_type render(T const & renderer) const { return renderer.render(map_, scale_factor_); } @@ -364,4 +364,3 @@ void runner::parse_map_sizes(std::string const & str, std::vector & si } } - diff --git a/utils/svg2png/svg2png.cpp b/utils/svg2png/svg2png.cpp index 2b5e79369..c7fe79735 100644 --- a/utils/svg2png/svg2png.cpp +++ b/utils/svg2png/svg2png.cpp @@ -56,7 +56,7 @@ struct main_marker_visitor verbose_(verbose), auto_open_(auto_open) {} - int operator() (mapnik::marker_svg const& marker) + int operator() (mapnik::marker_svg const& marker) const { using pixfmt = agg::pixfmt_rgba32_pre; using renderer_base = agg::renderer_base; @@ -122,14 +122,14 @@ struct main_marker_visitor // default template - int operator() (T const&) + int operator() (T const&) const { std::clog << "svg2png error: '" << svg_name_ << "' is not a valid vector!\n"; return -1; } private: - std::string const& svg_name_; + std::string svg_name_; bool verbose_; bool auto_open_; };