From dd9584bdd6f4de60202390d109a0383b43ecce07 Mon Sep 17 00:00:00 2001 From: Matt Amos Date: Mon, 9 Dec 2013 18:50:00 +0000 Subject: [PATCH] Factored out markers symbolizer logic. It's not ideal - there's still a bunch of "dispatch" objects from which the common elements could be factored for greater readability. --- include/mapnik/grid/grid_marker_helpers.hpp | 45 +++- include/mapnik/marker_helpers.hpp | 29 ++- .../process_markers_symbolizer.hpp | 176 ++++++++++++++ include/mapnik/svg/svg_renderer_agg.hpp | 6 + src/agg/process_markers_symbolizer.cpp | 225 +++++------------ src/cairo_renderer.cpp | 160 +++--------- src/grid/process_markers_symbolizer.cpp | 230 +++++------------- 7 files changed, 380 insertions(+), 491 deletions(-) create mode 100644 include/mapnik/renderer_common/process_markers_symbolizer.hpp diff --git a/include/mapnik/grid/grid_marker_helpers.hpp b/include/mapnik/grid/grid_marker_helpers.hpp index dde6acec5..1f75e7192 100644 --- a/include/mapnik/grid/grid_marker_helpers.hpp +++ b/include/mapnik/grid/grid_marker_helpers.hpp @@ -73,6 +73,14 @@ struct raster_markers_rasterizer_dispatch_grid //pixf_.comp_op(static_cast(sym_.comp_op())); } + raster_markers_rasterizer_dispatch_grid(raster_markers_rasterizer_dispatch_grid &&d) + : buf_(d.buf_), pixf_(d.pixf_), renb_(d.renb_), ras_(d.ras_), src_(d.src_), + marker_trans_(d.marker_trans_), sym_(d.sym_), detector_(d.detector_), + scale_factor_(d.scale_factor_), feature_(d.feature_), pixmap_(d.pixmap_), + placed_(d.placed_) + { + } + template void add_path(T & path) { @@ -185,23 +193,26 @@ private: template struct vector_markers_rasterizer_dispatch_grid { - typedef typename SvgRenderer::renderer_base renderer_base; - typedef typename renderer_base::pixfmt_type pixfmt_type; + typedef typename SvgRenderer::renderer_base renderer_base; + typedef typename SvgRenderer::vertex_source_type vertex_source_type; + typedef typename SvgRenderer::attribute_source_type attribute_source_type; + typedef typename renderer_base::pixfmt_type pixfmt_type; vector_markers_rasterizer_dispatch_grid(BufferType & render_buffer, - SvgRenderer & svg_renderer, - Rasterizer & ras, - box2d const& bbox, - agg::trans_affine const& marker_trans, - markers_symbolizer const& sym, - Detector & detector, - double scale_factor, - mapnik::feature_impl & feature, - PixMapType & pixmap) + vertex_source_type &path, + const attribute_source_type &attrs, + Rasterizer & ras, + box2d const& bbox, + agg::trans_affine const& marker_trans, + markers_symbolizer const& sym, + Detector & detector, + double scale_factor, + mapnik::feature_impl & feature, + PixMapType & pixmap) : buf_(render_buffer), pixf_(buf_), renb_(pixf_), - svg_renderer_(svg_renderer), + svg_renderer_(path, attrs), ras_(ras), bbox_(bbox), marker_trans_(marker_trans), @@ -216,6 +227,14 @@ struct vector_markers_rasterizer_dispatch_grid //pixf_.comp_op(static_cast(sym_.comp_op())); } + vector_markers_rasterizer_dispatch_grid(vector_markers_rasterizer_dispatch_grid &&d) + : buf_(d.buf_), pixf_(d.pixf_), svg_renderer_(std::move(d.svg_renderer_)), ras_(d.ras_), + bbox_(d.bbox_), marker_trans_(d.marker_trans_), sym_(d.sym_), detector_(d.detector_), + scale_factor_(d.scale_factor_), feature_(d.feature_), pixmap_(d.pixmap_), + placed_(d.placed_) + { + } + template void add_path(T & path) { @@ -290,7 +309,7 @@ private: BufferType & buf_; pixfmt_type pixf_; renderer_base renb_; - SvgRenderer & svg_renderer_; + SvgRenderer svg_renderer_; Rasterizer & ras_; box2d const& bbox_; agg::trans_affine const& marker_trans_; diff --git a/include/mapnik/marker_helpers.hpp b/include/mapnik/marker_helpers.hpp index 643d9d744..8241778d9 100644 --- a/include/mapnik/marker_helpers.hpp +++ b/include/mapnik/marker_helpers.hpp @@ -61,11 +61,14 @@ namespace mapnik { template struct vector_markers_rasterizer_dispatch { - typedef typename SvgRenderer::renderer_base renderer_base; - typedef typename renderer_base::pixfmt_type pixfmt_type; - + typedef typename SvgRenderer::renderer_base renderer_base; + typedef typename SvgRenderer::vertex_source_type vertex_source_type; + typedef typename SvgRenderer::attribute_source_type attribute_source_type; + typedef typename renderer_base::pixfmt_type pixfmt_type; + vector_markers_rasterizer_dispatch(BufferType & render_buffer, - SvgRenderer & svg_renderer, + vertex_source_type &path, + attribute_source_type const &attrs, Rasterizer & ras, box2d const& bbox, agg::trans_affine const& marker_trans, @@ -76,7 +79,7 @@ struct vector_markers_rasterizer_dispatch : buf_(render_buffer), pixf_(buf_), renb_(pixf_), - svg_renderer_(svg_renderer), + svg_renderer_(path, attrs), ras_(ras), bbox_(bbox), marker_trans_(marker_trans), @@ -88,6 +91,13 @@ struct vector_markers_rasterizer_dispatch pixf_.comp_op(get(sym_, keys::comp_op, agg::comp_op_src_over)); } + vector_markers_rasterizer_dispatch(vector_markers_rasterizer_dispatch &&d) + : buf_(d.buf_), pixf_(d.pixf_), svg_renderer_(std::move(d.svg_renderer_)), ras_(d.ras_), + bbox_(d.bbox_), marker_trans_(d.marker_trans_), sym_(d.sym_), detector_(d.detector_), + scale_factor_(d.scale_factor_), snap_to_pixels_(d.snap_to_pixels_) + { + } + template void add_path(T & path) { @@ -162,7 +172,7 @@ private: BufferType & buf_; pixfmt_type pixf_; renderer_base renb_; - SvgRenderer & svg_renderer_; + SvgRenderer svg_renderer_; Rasterizer & ras_; box2d const& bbox_; agg::trans_affine const& marker_trans_; @@ -204,6 +214,13 @@ struct raster_markers_rasterizer_dispatch pixf_.comp_op(get(sym_, keys::comp_op, agg::comp_op_src_over)); } + raster_markers_rasterizer_dispatch(raster_markers_rasterizer_dispatch &&d) + : buf_(d.buf_), pixf_(d.pixf_), renb_(d.renb_), ras_(d.ras_), src_(d.src_), + marker_trans_(d.marker_trans_), sym_(d.sym_), detector_(d.detector_), + scale_factor_(d.scale_factor_), snap_to_pixels_(d.snap_to_pixels_) + { + } + template void add_path(T & path) { diff --git a/include/mapnik/renderer_common/process_markers_symbolizer.hpp b/include/mapnik/renderer_common/process_markers_symbolizer.hpp new file mode 100644 index 000000000..26f08e9b2 --- /dev/null +++ b/include/mapnik/renderer_common/process_markers_symbolizer.hpp @@ -0,0 +1,176 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2013 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_MARKERS_SYMBOLIZER_HPP +#define MAPNIK_RENDERER_COMMON_PROCESS_MARKERS_SYMBOLIZER_HPP + +#include +#include +#include + +namespace mapnik { + +namespace { + + + +} // anonymous namespace + +template +void render_markers_symbolizer(markers_symbolizer const &sym, + mapnik::feature_impl &feature, + proj_transform const &prj_trans, + renderer_common &common, + box2d const &clip_box, + F1 make_vector_dispatch, + F2 make_raster_dispatch) +{ + using namespace mapnik::svg; + typedef boost::mpl::vector conv_types; + typedef agg::pod_bvector svg_attribute_type; + + std::string filename = get(sym, keys::file, feature, "shape://ellipse"); + bool clip = get(sym, keys::clip, feature, false); + double smooth = get(sym, keys::smooth, feature, false); + + // https://github.com/mapnik/mapnik/issues/1316 + bool snap_pixels = !mapnik::marker_cache::instance().is_uri(filename); + if (!filename.empty()) + { + boost::optional mark = mapnik::marker_cache::instance().find(filename, true); + if (mark && *mark) + { + agg::trans_affine tr = agg::trans_affine_scaling(common.scale_factor_); + + if ((*mark)->is_vector()) + { + boost::optional const& stock_vector_marker = (*mark)->get_vector_data(); + + auto width_expr = get_optional(sym, keys::width); + auto height_expr = get_optional(sym, keys::height); + + // special case for simple ellipse markers + // to allow for full control over rx/ry dimensions + if (filename == "shape://ellipse" + && (width_expr || height_expr)) + { + svg_storage_type marker_ellipse; + vertex_stl_adapter stl_storage(marker_ellipse.source()); + svg_path_adapter svg_path(stl_storage); + build_ellipse(sym, feature, marker_ellipse, svg_path); + svg_attribute_type attributes; + bool result = push_explicit_style( (*stock_vector_marker)->attributes(), attributes, sym); + auto image_transform = get_optional(sym, keys::image_transform); + if (image_transform) evaluate_transform(tr, feature, *image_transform); + box2d bbox = marker_ellipse.bounding_box(); + + auto rasterizer_dispatch = make_vector_dispatch( + svg_path, result ? attributes : (*stock_vector_marker)->attributes(), + marker_ellipse, bbox, tr, snap_pixels); + typedef decltype(rasterizer_dispatch) dispatch_type; + + vertex_converter, dispatch_type, markers_symbolizer, + CoordTransform, proj_transform, agg::trans_affine, conv_types> + converter(clip_box, rasterizer_dispatch, sym,common.t_,prj_trans,tr,common.scale_factor_); + if (clip && feature.paths().size() > 0) // optional clip (default: true) + { + geometry_type::types type = feature.paths()[0].type(); + if (type == geometry_type::types::Polygon) + converter.template set(); + // line clipping disabled due to https://github.com/mapnik/mapnik/issues/1426 + //else if (type == LineString) + // converter.template set(); + // don't clip if type==Point + } + converter.template set(); //always transform + if (smooth > 0.0) converter.template set(); // optional smooth converter + apply_markers_multi(feature, converter, sym); + } + else + { + box2d const& bbox = (*mark)->bounding_box(); + setup_transform_scaling(tr, bbox.width(), bbox.height(), feature, sym); + auto image_transform = get_optional(sym, keys::image_transform); + if (image_transform) evaluate_transform(tr, feature, *image_transform); + vertex_stl_adapter stl_storage((*stock_vector_marker)->source()); + svg_path_adapter svg_path(stl_storage); + svg_attribute_type attributes; + bool result = push_explicit_style( (*stock_vector_marker)->attributes(), attributes, sym); + auto rasterizer_dispatch = make_vector_dispatch( + svg_path, result ? attributes : (*stock_vector_marker)->attributes(), + **stock_vector_marker, bbox, tr, snap_pixels); + typedef decltype(rasterizer_dispatch) dispatch_type; + + vertex_converter, dispatch_type, markers_symbolizer, + CoordTransform, proj_transform, agg::trans_affine, conv_types> + converter(clip_box, rasterizer_dispatch, sym,common.t_,prj_trans,tr,common.scale_factor_); + if (clip && feature.paths().size() > 0) // optional clip (default: true) + { + geometry_type::types type = feature.paths()[0].type(); + if (type == geometry_type::types::Polygon) + converter.template set(); + // line clipping disabled due to https://github.com/mapnik/mapnik/issues/1426 + //else if (type == LineString) + // converter.template set(); + // don't clip if type==Point + } + converter.template set(); //always transform + if (smooth > 0.0) converter.template set(); // optional smooth converter + apply_markers_multi(feature, converter, sym); + } + } + else // raster markers + { + setup_transform_scaling(tr, (*mark)->width(), (*mark)->height(), feature, sym); + auto image_transform = get_optional(sym, keys::image_transform); + if (image_transform) evaluate_transform(tr, feature, *image_transform); + box2d const& bbox = (*mark)->bounding_box(); + boost::optional marker = (*mark)->get_bitmap_data(); + + auto rasterizer_dispatch = make_raster_dispatch(**marker, tr, bbox); + typedef decltype(rasterizer_dispatch) dispatch_type; + + vertex_converter, dispatch_type, markers_symbolizer, + CoordTransform, proj_transform, agg::trans_affine, conv_types> + converter(clip_box, rasterizer_dispatch, sym,common.t_,prj_trans,tr,common.scale_factor_); + + if (clip && feature.paths().size() > 0) // optional clip (default: true) + { + geometry_type::types type = feature.paths()[0].type(); + if (type == geometry_type::types::Polygon) + converter.template set(); + // line clipping disabled due to https://github.com/mapnik/mapnik/issues/1426 + //else if (type == geometry_type::types::LineString) + // converter.template set(); + // don't clip if type==geometry_type::types::Point + } + converter.template set(); //always transform + if (smooth > 0.0) converter.template set(); // optional smooth converter + apply_markers_multi(feature, converter, sym); + } + } + } +} + +} // namespace mapnik + +#endif /* MAPNIK_RENDERER_COMMON_PROCESS_MARKERS_SYMBOLIZER_HPP */ diff --git a/include/mapnik/svg/svg_renderer_agg.hpp b/include/mapnik/svg/svg_renderer_agg.hpp index a5b9274f8..bcdb04857 100644 --- a/include/mapnik/svg/svg_renderer_agg.hpp +++ b/include/mapnik/svg/svg_renderer_agg.hpp @@ -107,6 +107,8 @@ public: typedef agg::conv_transform curved_trans_type; typedef agg::conv_contour curved_trans_contour_type; typedef agg::renderer_base renderer_base; + typedef VertexSource vertex_source_type; + typedef AttributeSource attribute_source_type; svg_renderer_agg(VertexSource & source, AttributeSource const& attributes) : source_(source), @@ -114,6 +116,10 @@ public: curved_stroked_(curved_), attributes_(attributes) {} + svg_renderer_agg(svg_renderer_agg &&r) + : source_(r.source_), curved_(source_), curved_stroked_(curved_), + attributes_(r.attributes_) {} + template void render_gradient(Rasterizer& ras, Scanline& sl, diff --git a/src/agg/process_markers_symbolizer.cpp b/src/agg/process_markers_symbolizer.cpp index 5a3b8933c..8ccd0c3cd 100644 --- a/src/agg/process_markers_symbolizer.cpp +++ b/src/agg/process_markers_symbolizer.cpp @@ -38,6 +38,7 @@ #include #include #include +#include // agg #include "agg_basics.h" @@ -63,183 +64,71 @@ void agg_renderer::process(markers_symbolizer const& sym, feature_impl & feature, proj_transform const& prj_trans) { + using namespace mapnik::svg; typedef agg::rgba8 color_type; typedef agg::order_rgba order_type; typedef agg::comp_op_adaptor_rgba_pre blender_type; // comp blender typedef agg::rendering_buffer buf_type; typedef agg::pixfmt_custom_blend_rgba pixfmt_comp_type; typedef agg::renderer_base renderer_base; - typedef label_collision_detector4 detector_type; - typedef boost::mpl::vector conv_types; + typedef agg::renderer_scanline_aa_solid renderer_type; + typedef agg::pod_bvector svg_attribute_type; + typedef svg_renderer_agg svg_renderer_type; + typedef vector_markers_rasterizer_dispatch vector_dispatch_type; + typedef raster_markers_rasterizer_dispatch raster_dispatch_type; - std::string filename = get(sym, keys::file, feature, "shape://ellipse"); - bool clip = get(sym, keys::clip, feature, false); - double smooth = get(sym, keys::smooth, feature, false); - - // https://github.com/mapnik/mapnik/issues/1316 - bool snap_pixels = !mapnik::marker_cache::instance().is_uri(filename); - if (!filename.empty()) + double gamma = get(sym, keys::gamma, feature, 1.0); + gamma_method_enum gamma_method = get(sym, keys::gamma_method, feature, GAMMA_POWER); + if (gamma != gamma_ || gamma_method != gamma_method_) { - boost::optional mark = mapnik::marker_cache::instance().find(filename, true); - if (mark && *mark) - { - ras_ptr->reset(); - double gamma = get(sym, keys::gamma, feature, 1.0); - gamma_method_enum gamma_method = get(sym, keys::gamma_method, feature, GAMMA_POWER); - if (gamma != gamma_ || gamma_method != gamma_method_) - { - set_gamma_method(ras_ptr, gamma, gamma_method); - gamma_method_ = gamma_method; - gamma_ = gamma; - } - - agg::trans_affine tr = agg::trans_affine_scaling(common_.scale_factor_); - box2d clip_box = clipping_extent(); - if ((*mark)->is_vector()) - { - using namespace mapnik::svg; - typedef agg::renderer_scanline_aa_solid renderer_type; - typedef agg::pod_bvector svg_attribute_type; - typedef svg_renderer_agg svg_renderer_type; - typedef vector_markers_rasterizer_dispatch dispatch_type; - boost::optional const& stock_vector_marker = (*mark)->get_vector_data(); - - auto width_expr = get_optional(sym, keys::width); - auto height_expr = get_optional(sym, keys::height); - - // special case for simple ellipse markers - // to allow for full control over rx/ry dimensions - if (filename == "shape://ellipse" - && (width_expr || height_expr)) - { - svg_storage_type marker_ellipse; - vertex_stl_adapter stl_storage(marker_ellipse.source()); - svg_path_adapter svg_path(stl_storage); - build_ellipse(sym, feature, marker_ellipse, svg_path); - svg_attribute_type attributes; - bool result = push_explicit_style( (*stock_vector_marker)->attributes(), attributes, sym); - svg_renderer_type svg_renderer(svg_path, result ? attributes : (*stock_vector_marker)->attributes()); - auto image_transform = get_optional(sym, keys::image_transform); - if (image_transform) evaluate_transform(tr, feature, *image_transform); - box2d bbox = marker_ellipse.bounding_box(); - coord2d center = bbox.center(); - agg::trans_affine_translation recenter(-center.x, -center.y); - agg::trans_affine marker_trans = recenter * tr; - buf_type render_buffer(current_buffer_->raw_data(), current_buffer_->width(), current_buffer_->height(), current_buffer_->width() * 4); - dispatch_type rasterizer_dispatch(render_buffer, - svg_renderer, - *ras_ptr, - bbox, - marker_trans, - sym, - *common_.detector_, - common_.scale_factor_, - snap_pixels); - vertex_converter, dispatch_type, markers_symbolizer, - CoordTransform, proj_transform, agg::trans_affine, conv_types> - converter(clip_box, rasterizer_dispatch, sym,common_.t_,prj_trans,tr,common_.scale_factor_); - if (clip && feature.paths().size() > 0) // optional clip (default: true) - { - geometry_type::types type = feature.paths()[0].type(); - if (type == geometry_type::types::Polygon) - converter.template set(); - // line clipping disabled due to https://github.com/mapnik/mapnik/issues/1426 - //else if (type == LineString) - // converter.template set(); - // don't clip if type==Point - } - converter.template set(); //always transform - if (smooth > 0.0) converter.template set(); // optional smooth converter - apply_markers_multi(feature, converter, sym); - } - else - { - box2d const& bbox = (*mark)->bounding_box(); - setup_transform_scaling(tr, bbox.width(), bbox.height(), feature, sym); - auto image_transform = get_optional(sym, keys::image_transform); - if (image_transform) evaluate_transform(tr, feature, *image_transform); - coord2d center = bbox.center(); - agg::trans_affine_translation recenter(-center.x, -center.y); - agg::trans_affine marker_trans = recenter * tr; - vertex_stl_adapter stl_storage((*stock_vector_marker)->source()); - svg_path_adapter svg_path(stl_storage); - svg_attribute_type attributes; - bool result = push_explicit_style( (*stock_vector_marker)->attributes(), attributes, sym); - svg_renderer_type svg_renderer(svg_path, result ? attributes : (*stock_vector_marker)->attributes()); - buf_type render_buffer(current_buffer_->raw_data(), current_buffer_->width(), current_buffer_->height(), current_buffer_->width() * 4); - dispatch_type rasterizer_dispatch(render_buffer, - svg_renderer, - *ras_ptr, - bbox, - marker_trans, - sym, - *common_.detector_, - common_.scale_factor_, - snap_pixels); - vertex_converter, dispatch_type, markers_symbolizer, - CoordTransform, proj_transform, agg::trans_affine, conv_types> - converter(clip_box, rasterizer_dispatch, sym,common_.t_,prj_trans,tr,common_.scale_factor_); - if (clip && feature.paths().size() > 0) // optional clip (default: true) - { - geometry_type::types type = feature.paths()[0].type(); - if (type == geometry_type::types::Polygon) - converter.template set(); - // line clipping disabled due to https://github.com/mapnik/mapnik/issues/1426 - //else if (type == LineString) - // converter.template set(); - // don't clip if type==Point - } - converter.template set(); //always transform - if (smooth > 0.0) converter.template set(); // optional smooth converter - apply_markers_multi(feature, converter, sym); - } - } - else // raster markers - { - setup_transform_scaling(tr, (*mark)->width(), (*mark)->height(), feature, sym); - auto image_transform = get_optional(sym, keys::image_transform); - if (image_transform) evaluate_transform(tr, feature, *image_transform); - box2d const& bbox = (*mark)->bounding_box(); - coord2d center = bbox.center(); - agg::trans_affine_translation recenter(-center.x, -center.y); - agg::trans_affine marker_trans = recenter * tr; - boost::optional marker = (*mark)->get_bitmap_data(); - typedef raster_markers_rasterizer_dispatch dispatch_type; - buf_type render_buffer(current_buffer_->raw_data(), current_buffer_->width(), current_buffer_->height(), current_buffer_->width() * 4); - dispatch_type rasterizer_dispatch(render_buffer, - *ras_ptr, - **marker, - marker_trans, - sym, - *common_.detector_, - common_.scale_factor_, - true /*snap rasters no matter what*/); - vertex_converter, dispatch_type, markers_symbolizer, - CoordTransform, proj_transform, agg::trans_affine, conv_types> - converter(clip_box, rasterizer_dispatch, sym,common_.t_,prj_trans,tr,common_.scale_factor_); - - if (clip && feature.paths().size() > 0) // optional clip (default: true) - { - geometry_type::types type = feature.paths()[0].type(); - if (type == geometry_type::types::Polygon) - converter.template set(); - // line clipping disabled due to https://github.com/mapnik/mapnik/issues/1426 - //else if (type == geometry_type::types::LineString) - // converter.template set(); - // don't clip if type==geometry_type::types::Point - } - converter.template set(); //always transform - if (smooth > 0.0) converter.template set(); // optional smooth converter - apply_markers_multi(feature, converter, sym); - } - } + set_gamma_method(ras_ptr, gamma, gamma_method); + gamma_method_ = gamma_method; + gamma_ = gamma; } + + buf_type render_buffer(current_buffer_->raw_data(), current_buffer_->width(), current_buffer_->height(), current_buffer_->width() * 4); + + ras_ptr->reset(); + box2d clip_box = clipping_extent(); + + render_markers_symbolizer( + sym, feature, prj_trans, common_, clip_box, + [&](svg_path_adapter &path, svg_attribute_type const &attr, svg_storage_type &, + box2d const &bbox, agg::trans_affine const &tr, + bool snap_pixels) -> vector_dispatch_type { + coord2d center = bbox.center(); + agg::trans_affine_translation recenter(-center.x, -center.y); + agg::trans_affine marker_trans = recenter * tr; + return vector_dispatch_type(render_buffer, + path, attr, + *ras_ptr, + bbox, + marker_trans, + sym, + *common_.detector_, + common_.scale_factor_, + snap_pixels); + }, + [&](image_data_32 const &marker, agg::trans_affine const &tr, + box2d const &bbox) -> raster_dispatch_type { + coord2d center = bbox.center(); + agg::trans_affine_translation recenter(-center.x, -center.y); + agg::trans_affine marker_trans = recenter * tr; + return raster_dispatch_type(render_buffer, + *ras_ptr, + marker, + marker_trans, + sym, + *common_.detector_, + common_.scale_factor_, + true /*snap rasters no matter what*/); + }); } template void agg_renderer::process(markers_symbolizer const&, diff --git a/src/cairo_renderer.cpp b/src/cairo_renderer.cpp index 03e15f0f9..3c2688448 100644 --- a/src/cairo_renderer.cpp +++ b/src/cairo_renderer.cpp @@ -58,6 +58,7 @@ #include #include #include +#include // cairo #include @@ -880,12 +881,12 @@ template struct markers_dispatch_2 { markers_dispatch_2(Context & ctx, - ImageMarker & marker, - Detector & detector, - markers_symbolizer const& sym, - box2d const& bbox, - agg::trans_affine const& marker_trans, - double scale_factor) + ImageMarker & marker, + Detector & detector, + markers_symbolizer const& sym, + box2d const& bbox, + agg::trans_affine const& marker_trans, + double scale_factor) :ctx_(ctx), marker_(marker), detector_(detector), @@ -935,7 +936,7 @@ struct markers_dispatch_2 if (allow_overlap || detector_.has_placement(transformed_bbox)) { - ctx_.add_image(matrix, *marker_, opacity); + ctx_.add_image(matrix, marker_, opacity); if (!ignore_placement) { detector_.insert(transformed_bbox); @@ -956,7 +957,7 @@ struct markers_dispatch_2 matrix *= marker_trans_; matrix *= agg::trans_affine_rotation(angle); matrix *= agg::trans_affine_translation(x, y); - ctx_.add_image(matrix, *marker_, opacity); + ctx_.add_image(matrix, marker_, opacity); } } } @@ -975,135 +976,30 @@ void cairo_renderer_base::process(markers_symbolizer const& sym, mapnik::feature_impl & feature, proj_transform const& prj_trans) { - typedef boost::mpl::vector conv_types; + typedef agg::pod_bvector svg_attribute_type; + typedef detail::markers_dispatch_2 raster_dispatch_type; + typedef detail::markers_dispatch vector_dispatch_type; cairo_save_restore guard(context_); composite_mode_e comp_op = get(sym, keys::comp_op, feature, src_over); - std::string filename = get(sym, keys::file, feature, "shape://ellipse"); - auto geom_transform = get_optional(sym, keys::geometry_transform); - auto img_transform = get_optional(sym, keys::image_transform); - auto width = get_optional(sym, keys::width); - auto height = get_optional(sym, keys::height); - bool clip = get(sym, keys::clip, feature, false); - double smooth = get(sym, keys::smooth, feature, 0.0); - context_.set_operator(comp_op); + box2d clip_box = common_.query_extent_; - agg::trans_affine tr = agg::trans_affine_scaling(common_.scale_factor_); - - if (!filename.empty()) - { - boost::optional mark = mapnik::marker_cache::instance().find(filename, true); - if (mark && *mark) - { - agg::trans_affine geom_tr; - if (geom_transform) { evaluate_transform(geom_tr, feature, *geom_transform); } - box2d const& bbox = (*mark)->bounding_box(); - setup_transform_scaling(tr, bbox.width(), bbox.height(), feature, sym); - if (img_transform) { evaluate_transform(tr, feature, *img_transform); } - - if ((*mark)->is_vector()) - { - using namespace mapnik::svg; - typedef agg::pod_bvector svg_attributes_type; - typedef detail::markers_dispatch dispatch_type; - - boost::optional const& stock_vector_marker = (*mark)->get_vector_data(); - - // special case for simple ellipse markers - // to allow for full control over rx/ry dimensions - if (filename == "shape://ellipse" - && (width || height)) - { - svg_storage_type marker_ellipse; - vertex_stl_adapter stl_storage(marker_ellipse.source()); - svg_path_adapter svg_path(stl_storage); - build_ellipse(sym, feature, marker_ellipse, svg_path); - svg_attributes_type attributes; - bool result = push_explicit_style( (*stock_vector_marker)->attributes(), attributes, sym); - agg::trans_affine marker_tr = agg::trans_affine_scaling(common_.scale_factor_); - if (img_transform) { evaluate_transform(marker_tr, feature, *img_transform); } - box2d new_bbox = marker_ellipse.bounding_box(); - - dispatch_type dispatch(context_, marker_ellipse, result?attributes:(*stock_vector_marker)->attributes(), - *common_.detector_, sym, new_bbox, marker_tr, common_.scale_factor_); - vertex_converter, dispatch_type, markers_symbolizer, - CoordTransform, proj_transform, agg::trans_affine, conv_types> - converter(common_.query_extent_, dispatch, sym, common_.t_, prj_trans, marker_tr, common_.scale_factor_); - - if (clip && feature.paths().size() > 0) // optional clip (default: true) - { - geometry_type::types type = feature.paths()[0].type(); - if (type == geometry_type::types::Polygon) - converter.set(); - // line clipping disabled due to https://github.com/mapnik/mapnik/issues/1426 - //else if (type == geometry_type::types::LineString) - // converter.template set(); - // don't clip if type==geometry_type::types::Point - } - converter.set(); //always transform - if (smooth > 0.0) converter.set(); // optional smooth converter - apply_markers_multi(feature, converter, sym); - } - else - { - svg_attributes_type attributes; - bool result = push_explicit_style( (*stock_vector_marker)->attributes(), attributes, sym); - - dispatch_type dispatch(context_, **stock_vector_marker, result?attributes:(*stock_vector_marker)->attributes(), - *common_.detector_, sym, bbox, tr, common_.scale_factor_); - vertex_converter, dispatch_type, markers_symbolizer, - CoordTransform, proj_transform, agg::trans_affine, conv_types> - converter(common_.query_extent_, dispatch, sym, common_.t_, prj_trans, tr, common_.scale_factor_); - - if (clip && feature.paths().size() > 0) // optional clip (default: true) - { - geometry_type::types type = feature.paths()[0].type(); - if (type == geometry_type::types::Polygon) - converter.set(); - // line clipping disabled due to https://github.com/mapnik/mapnik/issues/1426 - //else if (type == geometry_type::types::LineString) - // converter.template set(); - // don't clip if type==geometry_type::types::Point - } - converter.set(); //always transform - if (smooth > 0.0) converter.set(); // optional smooth converter - apply_markers_multi(feature, converter, sym); - } - } - else // raster markers - { - typedef detail::markers_dispatch_2 dispatch_type; - boost::optional marker = (*mark)->get_bitmap_data(); - if ( marker ) - { - dispatch_type dispatch(context_, *marker, - *common_.detector_, sym, bbox, tr, common_.scale_factor_); - - vertex_converter, dispatch_type, markers_symbolizer, - CoordTransform, proj_transform, agg::trans_affine, conv_types> - converter(common_.query_extent_, dispatch, sym, common_.t_, prj_trans, tr, common_.scale_factor_); - - if (clip && feature.paths().size() > 0) // optional clip (default: true) - { - geometry_type::types type = feature.paths()[0].type(); - if (type == geometry_type::types::Polygon) - converter.set(); - // line clipping disabled due to https://github.com/mapnik/mapnik/issues/1426 - //else if (type == geometry_type::types::LineString) - // converter.template set(); - // don't clip if type==geometry_type::types::Point - } - converter.set(); //always transform - if (smooth > 0.0) converter.set(); // optional smooth converter - apply_markers_multi(feature, converter, sym); - } - } - } - } + render_markers_symbolizer( + sym, feature, prj_trans, common_, clip_box, + [&](svg::svg_path_adapter &, svg_attribute_type const &attr, svg_storage_type &marker, + box2d const &bbox, agg::trans_affine const &marker_trans, + bool) -> vector_dispatch_type { + return vector_dispatch_type(context_, marker, attr, *common_.detector_, sym, bbox, + marker_trans, common_.scale_factor_); + }, + [&](image_data_32 &marker, agg::trans_affine const &marker_trans, + box2d const &bbox) -> raster_dispatch_type { + return raster_dispatch_type(context_, marker, *common_.detector_, sym, bbox, + marker_trans, common_.scale_factor_); + }); } void cairo_renderer_base::process(text_symbolizer const& sym, diff --git a/src/grid/process_markers_symbolizer.cpp b/src/grid/process_markers_symbolizer.cpp index ed0845379..22c4dbb6a 100644 --- a/src/grid/process_markers_symbolizer.cpp +++ b/src/grid/process_markers_symbolizer.cpp @@ -60,6 +60,7 @@ porting notes --> #include #include #include +#include // agg #include "agg_basics.h" @@ -84,181 +85,66 @@ void grid_renderer::process(markers_symbolizer const& sym, typedef typename grid_renderer_base_type::pixfmt_type pixfmt_type; typedef agg::renderer_scanline_bin_solid renderer_type; typedef label_collision_detector4 detector_type; - typedef boost::mpl::vector conv_types; - std::string filename = get(sym, keys::file, feature, "shape://ellipse"); - bool clip = get(sym, keys::clip, feature, false); - double smooth = get(sym, keys::smooth, feature, false); + using namespace mapnik::svg; + typedef agg::pod_bvector svg_attribute_type; + typedef svg_renderer_agg svg_renderer_type; + typedef vector_markers_rasterizer_dispatch_grid vector_dispatch_type; + typedef raster_markers_rasterizer_dispatch_grid raster_dispatch_type; - if (!filename.empty()) - { - boost::optional mark = mapnik::marker_cache::instance().find(filename, true); - if (mark && *mark) - { - ras_ptr->reset(); - agg::trans_affine geom_tr; - auto geom_transform = get_optional(sym, keys::geometry_transform); - if (geom_transform) { evaluate_transform(geom_tr, feature, *geom_transform); } + buf_type render_buf(pixmap_.raw_data(), common_.width_, common_.height_, common_.width_); + ras_ptr->reset(); + box2d clip_box = common_.query_extent_; - agg::trans_affine tr = agg::trans_affine_scaling(common_.scale_factor_*(1.0/pixmap_.get_resolution())); - auto img_transform = get_optional(sym, keys::image_transform); - - if ((*mark)->is_vector()) - { - using namespace mapnik::svg; - typedef agg::pod_bvector svg_attribute_type; - typedef svg_renderer_agg svg_renderer_type; - typedef vector_markers_rasterizer_dispatch_grid dispatch_type; - boost::optional const& stock_vector_marker = (*mark)->get_vector_data(); - - auto width_expr = get_optional(sym, keys::width); - auto height_expr = get_optional(sym, keys::height); - - // special case for simple ellipse markers - // to allow for full control over rx/ry dimensions - if (filename == "shape://ellipse" - && (width_expr || height_expr)) - { - svg_storage_type marker_ellipse; - vertex_stl_adapter stl_storage(marker_ellipse.source()); - svg_path_adapter svg_path(stl_storage); - // TODO - clamping to >= 4 pixels - build_ellipse(sym, feature, marker_ellipse, svg_path); - svg_attribute_type attributes; - bool result = push_explicit_style( (*stock_vector_marker)->attributes(), attributes, sym); - svg_renderer_type svg_renderer(svg_path, result ? attributes : (*stock_vector_marker)->attributes()); - if (img_transform) { evaluate_transform(tr, feature, *img_transform); } - - box2d bbox = marker_ellipse.bounding_box(); - coord2d center = bbox.center(); - agg::trans_affine_translation recenter(-center.x, -center.y); - agg::trans_affine marker_trans = recenter * tr; - buf_type render_buf(pixmap_.raw_data(), common_.width_, common_.height_, common_.width_); - dispatch_type rasterizer_dispatch(render_buf, - svg_renderer, - *ras_ptr, - bbox, - marker_trans, - sym, - *common_.detector_, - common_.scale_factor_, - feature, - pixmap_); - vertex_converter, dispatch_type, markers_symbolizer, - CoordTransform, proj_transform, agg::trans_affine, conv_types> - converter(common_.query_extent_, rasterizer_dispatch, sym,common_.t_,prj_trans,tr,common_.scale_factor_); - if (clip && feature.paths().size() > 0) // optional clip (default: true) - { - geometry_type::types type = feature.paths()[0].type(); - if (type == geometry_type::types::Polygon) - converter.template set(); - // line clipping disabled due to https://github.com/mapnik/mapnik/issues/1426 - //else if (type == LineString) - // converter.template set(); - // don't clip if type==Point - } - converter.template set(); //always transform - if (smooth > 0.0) converter.template set(); // optional smooth converter - apply_markers_multi(feature, converter, sym); - } - else - { - box2d const& bbox = (*mark)->bounding_box(); - setup_transform_scaling(tr, bbox.width(), bbox.height(), feature, sym); - if (img_transform) { evaluate_transform(tr, feature, *img_transform); } - - // TODO - clamping to >= 4 pixels - coord2d center = bbox.center(); - agg::trans_affine_translation recenter(-center.x, -center.y); - agg::trans_affine marker_trans = recenter * tr; - vertex_stl_adapter stl_storage((*stock_vector_marker)->source()); - svg_path_adapter svg_path(stl_storage); - svg_attribute_type attributes; - bool result = push_explicit_style( (*stock_vector_marker)->attributes(), attributes, sym); - svg_renderer_type svg_renderer(svg_path, result ? attributes : (*stock_vector_marker)->attributes()); - buf_type render_buf(pixmap_.raw_data(), common_.width_, common_.height_, common_.width_); - dispatch_type rasterizer_dispatch(render_buf, - svg_renderer, - *ras_ptr, - bbox, - marker_trans, - sym, - *common_.detector_, - common_.scale_factor_, - feature, - pixmap_); - vertex_converter, dispatch_type, markers_symbolizer, - CoordTransform, proj_transform, agg::trans_affine, conv_types> - converter(common_.query_extent_, rasterizer_dispatch, sym,common_.t_,prj_trans,tr,common_.scale_factor_); - if (clip && feature.paths().size() > 0) // optional clip (default: true) - { - geometry_type::types type = feature.paths()[0].type(); - if (type == geometry_type::types::Polygon) - converter.template set(); - // line clipping disabled due to https://github.com/mapnik/mapnik/issues/1426 - //else if (type == LineString) - // converter.template set(); - // don't clip if type==Point - } - converter.template set(); //always transform - if (smooth > 0.0) converter.template set(); // optional smooth converter - apply_markers_multi(feature, converter, sym); - } - } - else // raster markers - { - setup_transform_scaling(tr, (*mark)->width(), (*mark)->height(), feature, sym); - if (img_transform) { evaluate_transform(tr, feature, *img_transform); } - - box2d const& bbox = (*mark)->bounding_box(); - // - clamp sizes to > 4 pixels of interactivity - coord2d center = bbox.center(); - agg::trans_affine_translation recenter(-center.x, -center.y); - agg::trans_affine marker_trans = recenter * tr; - boost::optional marker = (*mark)->get_bitmap_data(); - typedef raster_markers_rasterizer_dispatch_grid dispatch_type; - buf_type render_buf(pixmap_.raw_data(), common_.width_, common_.height_, common_.width_); - dispatch_type rasterizer_dispatch(render_buf, - *ras_ptr, - **marker, - marker_trans, - sym, - *common_.detector_, - common_.scale_factor_, - feature, - pixmap_); - vertex_converter, dispatch_type, markers_symbolizer, - CoordTransform, proj_transform, agg::trans_affine, conv_types> - converter(common_.query_extent_, rasterizer_dispatch, sym,common_.t_,prj_trans,tr,common_.scale_factor_); - if (clip && feature.paths().size() > 0) // optional clip (default: true) - { - geometry_type::types type = feature.paths()[0].type(); - if (type == geometry_type::types::Polygon) - converter.template set(); - // line clipping disabled due to https://github.com/mapnik/mapnik/issues/1426 - //else if (type == LineString) - // converter.template set(); - // don't clip if type==Point - } - converter.template set(); //always transform - if (smooth > 0.0) converter.template set(); // optional smooth converter - apply_markers_multi(feature, converter, sym); - } - } - } + render_markers_symbolizer( + sym, feature, prj_trans, common_, clip_box, + [&](svg_path_adapter &path, svg_attribute_type const &attr, svg_storage_type &, + box2d const &bbox, agg::trans_affine const &tr, + bool) -> vector_dispatch_type { + // TODO - clamping to >= 4 pixels + coord2d center = bbox.center(); + agg::trans_affine_translation recenter(-center.x, -center.y); + agg::trans_affine marker_trans = recenter * tr; + return vector_dispatch_type(render_buf, + path, attr, + *ras_ptr, + bbox, + marker_trans, + sym, + *common_.detector_, + common_.scale_factor_, + feature, + pixmap_); + }, + [&](image_data_32 const &marker, agg::trans_affine const &tr, + box2d const &bbox) -> raster_dispatch_type { + // - clamp sizes to > 4 pixels of interactivity + coord2d center = bbox.center(); + agg::trans_affine_translation recenter(-center.x, -center.y); + agg::trans_affine marker_trans = recenter * tr; + return raster_dispatch_type(render_buf, + *ras_ptr, + marker, + marker_trans, + sym, + *common_.detector_, + common_.scale_factor_, + feature, + pixmap_); + }); } template void grid_renderer::process(markers_symbolizer const&,