From e472ad965e72c1b696d0377bb642898a78bcbb41 Mon Sep 17 00:00:00 2001 From: Jiri Drbalek Date: Thu, 13 Sep 2018 16:10:48 +0200 Subject: [PATCH] True global pattern alignment, fixed local alignment --- include/mapnik/agg/render_polygon_pattern.hpp | 22 +---- .../mapnik/cairo/render_polygon_pattern.hpp | 59 ++++-------- .../renderer_common/pattern_alignment.hpp | 58 +++--------- src/build.py | 1 + src/renderer_common/pattern_alignment.cpp | 93 +++++++++++++++++++ 5 files changed, 130 insertions(+), 103 deletions(-) create mode 100644 src/renderer_common/pattern_alignment.cpp diff --git a/include/mapnik/agg/render_polygon_pattern.hpp b/include/mapnik/agg/render_polygon_pattern.hpp index 38736d044..412788006 100644 --- a/include/mapnik/agg/render_polygon_pattern.hpp +++ b/include/mapnik/agg/render_polygon_pattern.hpp @@ -29,6 +29,7 @@ #include #include #include +#include #pragma GCC diagnostic push #include @@ -107,29 +108,14 @@ struct agg_polygon_pattern : agg_pattern_base void render(renderer_base & ren_base, rasterizer & ras) { - pattern_alignment_enum alignment = get( - sym_, feature_, common_.vars_); - unsigned offset_x=0; - unsigned offset_y=0; - - if (alignment == LOCAL_ALIGNMENT) - { - double x0 = 0; - double y0 = 0; - using apply_local_alignment = detail::apply_local_alignment; - apply_local_alignment apply(common_.t_, prj_trans_, clip_box_, x0, y0); - util::apply_visitor(geometry::vertex_processor(apply), feature_.get_geometry()); - - offset_x = unsigned(ren_base.width() - x0); - offset_y = unsigned(ren_base.height() - y0); - } - + coord offset(pattern_offset(sym_, feature_, prj_trans_, common_, + pattern_img_.width(), pattern_img_.height())); agg::rendering_buffer pattern_rbuf((agg::int8u*)pattern_img_.bytes(), pattern_img_.width(), pattern_img_.height(), pattern_img_.width() * 4); agg::pixfmt_rgba32_pre pixf_pattern(pattern_rbuf); img_source_type img_src(pixf_pattern); - span_gen_type sg(img_src, offset_x, offset_y); + span_gen_type sg(img_src, safe_cast(offset.x), safe_cast(offset.y)); agg::span_allocator sa; value_double opacity = get(sym_, feature_, common_.vars_); diff --git a/include/mapnik/cairo/render_polygon_pattern.hpp b/include/mapnik/cairo/render_polygon_pattern.hpp index 9e6e82dda..e49b3ab11 100644 --- a/include/mapnik/cairo/render_polygon_pattern.hpp +++ b/include/mapnik/cairo/render_polygon_pattern.hpp @@ -37,44 +37,30 @@ namespace mapnik { struct cairo_renderer_process_visitor_p { - cairo_renderer_process_visitor_p(cairo_context & context, - agg::trans_affine & image_tr, - unsigned offset_x, - unsigned offset_y, - float opacity) - : context_(context), - image_tr_(image_tr), - offset_x_(offset_x), - offset_y_(offset_y), - opacity_(opacity) {} + cairo_renderer_process_visitor_p(agg::trans_affine & image_tr) + : image_tr_(image_tr) + {} - void operator() (marker_null const&) {} + image_rgba8 operator() (marker_null const&) + { + return image_rgba8(); + } - void operator() (marker_svg const& marker) + image_rgba8 operator() (marker_svg const& marker) { mapnik::box2d const& bbox_image = marker.get_data()->bounding_box() * image_tr_; mapnik::image_rgba8 image(bbox_image.width(), bbox_image.height()); render_pattern(marker, image_tr_, 1.0, image); - cairo_pattern pattern(image, opacity_); - pattern.set_extend(CAIRO_EXTEND_REPEAT); - pattern.set_origin(offset_x_, offset_y_); - context_.set_pattern(pattern); + return image; } - void operator() (marker_rgba8 const& marker) + image_rgba8 operator() (marker_rgba8 const& marker) { - cairo_pattern pattern(marker.get_data(), opacity_); - pattern.set_extend(CAIRO_EXTEND_REPEAT); - pattern.set_origin(offset_x_, offset_y_); - context_.set_pattern(pattern); + return marker.get_data(); } private: - cairo_context & context_; agg::trans_affine & image_tr_; - unsigned offset_x_; - unsigned offset_y_; - float opacity_; }; struct cairo_pattern_base @@ -122,20 +108,6 @@ struct cairo_polygon_pattern : cairo_pattern_base void render(cairo_fill_rule_t fill_rule, cairo_context & context) { - unsigned offset_x=0; - unsigned offset_y=0; - pattern_alignment_enum alignment = get(sym_, feature_, common_.vars_); - if (alignment == LOCAL_ALIGNMENT) - { - double x0 = 0.0; - double y0 = 0.0; - using apply_local_alignment = detail::apply_local_alignment; - apply_local_alignment apply(common_.t_, prj_trans_, clip_box_, x0, y0); - util::apply_visitor(geometry::vertex_processor(apply), feature_.get_geometry()); - offset_x = std::abs(clip_box_.width() - x0); - offset_y = std::abs(clip_box_.height() - y0); - } - value_double opacity = get(sym_, feature_, common_.vars_); agg::trans_affine image_tr = agg::trans_affine_scaling(common_.scale_factor_); auto image_transform = get_optional(sym_, keys::image_transform); @@ -149,8 +121,13 @@ struct cairo_polygon_pattern : cairo_pattern_base cairo_save_restore guard(context); context.set_operator(comp_op); - util::apply_visitor(cairo_renderer_process_visitor_p( - context, image_tr, offset_x, offset_y, opacity), marker_); + image_rgba8 pattern_img(util::apply_visitor(cairo_renderer_process_visitor_p(image_tr), marker_)); + coord offset(pattern_offset(sym_, feature_, prj_trans_, common_, + pattern_img.width(), pattern_img.height())); + cairo_pattern pattern(pattern_img, opacity); + pattern.set_extend(CAIRO_EXTEND_REPEAT); + pattern.set_origin(-offset.x, -offset.y); + context.set_pattern(pattern); using apply_vertex_converter_type = detail::apply_vertex_converter; using vertex_processor_type = geometry::vertex_processor; diff --git a/include/mapnik/renderer_common/pattern_alignment.hpp b/include/mapnik/renderer_common/pattern_alignment.hpp index c2e585df9..04f101c29 100644 --- a/include/mapnik/renderer_common/pattern_alignment.hpp +++ b/include/mapnik/renderer_common/pattern_alignment.hpp @@ -20,56 +20,26 @@ * *****************************************************************************/ - #ifndef MAPNIK_PATTERN_ALIGNMENT_HPP #define MAPNIK_PATTERN_ALIGNMENT_HPP -#include -#include -#include +#include -#pragma GCC diagnostic push -#include -#include "agg_conv_clip_polygon.h" -#pragma GCC diagnostic pop +namespace mapnik { -namespace mapnik { namespace detail { +class symbolizer_base; +class feature_impl; +class proj_transform; +class renderer_common; -struct apply_local_alignment -{ - apply_local_alignment(view_transform const& t, - proj_transform const& prj_trans, - box2d const& clip_box, - double & x, double & y) - : t_(t), - prj_trans_(prj_trans), - clip_box_(clip_box), - x_(x), - y_(y) {} - - void operator() (geometry::polygon_vertex_adapter & va) - { - using clipped_geometry_type = agg::conv_clip_polygon >; - using path_type = transform_path_adapter; - clipped_geometry_type clipped(va); - clipped.clip_box(clip_box_.minx(),clip_box_.miny(),clip_box_.maxx(),clip_box_.maxy()); - path_type path(t_, clipped, prj_trans_); - path.vertex(&x_,&y_); - } +coord pattern_offset( + symbolizer_base const & sym, + feature_impl const & feature, + proj_transform const & prj_trans, + renderer_common const & common, + unsigned pattern_width, + unsigned pattern_height); - template - void operator() (Adapter &) - { - // no-op - } - - view_transform const& t_; - proj_transform const& prj_trans_; - box2d const& clip_box_; - double & x_; - double & y_; -}; - -}} +} #endif // MAPNIK_PATTERN_ALIGNMENT_HPP diff --git a/src/build.py b/src/build.py index 009f4d0de..8fb358008 100644 --- a/src/build.py +++ b/src/build.py @@ -263,6 +263,7 @@ source = Split( renderer_common/render_markers_symbolizer.cpp renderer_common/render_pattern.cpp renderer_common/render_thunk_extractor.cpp + renderer_common/pattern_alignment.cpp math.cpp value.cpp """ diff --git a/src/renderer_common/pattern_alignment.cpp b/src/renderer_common/pattern_alignment.cpp new file mode 100644 index 000000000..1bc056366 --- /dev/null +++ b/src/renderer_common/pattern_alignment.cpp @@ -0,0 +1,93 @@ +/***************************************************************************** + * + * 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 + * + *****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +namespace mapnik { + +namespace { + +struct apply_local_alignment +{ + apply_local_alignment(view_transform const& t, + proj_transform const& prj_trans, + double & x, double & y) + : t_(t), + prj_trans_(prj_trans), + x_(x), + y_(y) {} + + void operator() (geometry::polygon_vertex_adapter & va) + { + using path_type = transform_path_adapter; + path_type path(t_, va, prj_trans_); + path.rewind(0); + path.vertex(&x_, &y_); + } + + template + void operator() (Adapter &) + { + // no-op + } + + view_transform const& t_; + proj_transform const& prj_trans_; + double & x_; + double & y_; +}; + +} + +coord pattern_offset( + symbolizer_base const & sym, + mapnik::feature_impl const & feature, + proj_transform const & prj_trans, + renderer_common const & common, + unsigned pattern_width, + unsigned pattern_height) +{ + coord reference_position(0, 0); + pattern_alignment_enum alignment_type = get(sym, feature, common.vars_); + + if (alignment_type == LOCAL_ALIGNMENT) + { + apply_local_alignment apply(common.t_, prj_trans, reference_position.x, reference_position.y); + util::apply_visitor(geometry::vertex_processor(apply), feature.get_geometry()); + } + else + { + common.t_.forward(&reference_position.x, &reference_position.y); + } + + return coord( + std::fmod(-reference_position.x, pattern_width) + pattern_width, + std::fmod(-reference_position.y, pattern_height) + pattern_height); +} + +}