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 98bb518a3..e49b3ab11 100644 --- a/include/mapnik/cairo/render_polygon_pattern.hpp +++ b/include/mapnik/cairo/render_polygon_pattern.hpp @@ -37,45 +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&) {} - - void operator() (marker_svg const& marker) + image_rgba8 operator() (marker_null const&) { - mapnik::rasterizer ras; - mapnik::box2d const& bbox_image = marker.get_data()->bounding_box() * image_tr_; - mapnik::image_rgba8 image(bbox_image.width(), bbox_image.height()); - render_pattern(ras, 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_rgba8(); } - void operator() (marker_rgba8 const& marker) + image_rgba8 operator() (marker_svg 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); + 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); + return image; + } + + image_rgba8 operator() (marker_rgba8 const& marker) + { + 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 @@ -123,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); @@ -150,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 db606ec55..2b9c94c69 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/include/mapnik/renderer_common/render_pattern.hpp b/include/mapnik/renderer_common/render_pattern.hpp index 4ecac8a77..fe127cf62 100644 --- a/include/mapnik/renderer_common/render_pattern.hpp +++ b/include/mapnik/renderer_common/render_pattern.hpp @@ -38,8 +38,7 @@ struct rasterizer; struct marker_svg; template -void render_pattern(rasterizer & ras, - marker_svg const& marker, +void render_pattern(marker_svg const& marker, agg::trans_affine const& tr, double opacity, T & image); diff --git a/src/agg/process_line_pattern_symbolizer.cpp b/src/agg/process_line_pattern_symbolizer.cpp index 005c95744..2538b256a 100644 --- a/src/agg/process_line_pattern_symbolizer.cpp +++ b/src/agg/process_line_pattern_symbolizer.cpp @@ -199,7 +199,7 @@ struct agg_renderer_process_visitor_l if (image_transform) evaluate_transform(image_tr, feature_, common_.vars_, *image_transform, common_.scale_factor_); mapnik::box2d const& bbox_image = marker.get_data()->bounding_box() * image_tr; image_rgba8 image(bbox_image.width(), bbox_image.height()); - render_pattern(ras_, marker, image_tr, 1.0, image); + render_pattern(marker, image_tr, 1.0, image); render_by_pattern_type(image); } diff --git a/src/agg/process_polygon_pattern_symbolizer.cpp b/src/agg/process_polygon_pattern_symbolizer.cpp index 67e868c94..0e95317ec 100644 --- a/src/agg/process_polygon_pattern_symbolizer.cpp +++ b/src/agg/process_polygon_pattern_symbolizer.cpp @@ -85,7 +85,7 @@ struct agg_renderer_process_visitor_p if (image_transform) evaluate_transform(image_tr, feature_, common_.vars_, *image_transform, common_.scale_factor_); mapnik::box2d const& bbox_image = marker.get_data()->bounding_box() * image_tr; mapnik::image_rgba8 image(bbox_image.width(), bbox_image.height()); - render_pattern(*ras_ptr_, marker, image_tr, 1.0, image); + render_pattern(marker, image_tr, 1.0, image); render(image); } diff --git a/src/build.py b/src/build.py index 32938b656..4c3ded137 100644 --- a/src/build.py +++ b/src/build.py @@ -269,6 +269,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 util/math.cpp value.cpp """ diff --git a/src/cairo/process_line_pattern_symbolizer.cpp b/src/cairo/process_line_pattern_symbolizer.cpp index ad7098b46..daa2d1056 100644 --- a/src/cairo/process_line_pattern_symbolizer.cpp +++ b/src/cairo/process_line_pattern_symbolizer.cpp @@ -65,13 +65,12 @@ struct prepare_pattern_visitor std::shared_ptr operator() (mapnik::marker_svg const& marker) { double opacity = get(sym_, feature_, common_.vars_); - mapnik::rasterizer ras; agg::trans_affine image_tr = agg::trans_affine_scaling(common_.scale_factor_); auto image_transform = get_optional(sym_, keys::image_transform); if (image_transform) evaluate_transform(image_tr, feature_, common_.vars_, *image_transform, common_.scale_factor_); mapnik::box2d const& bbox_image = marker.get_data()->bounding_box() * image_tr; mapnik::image_rgba8 image(bbox_image.width(), bbox_image.height()); - render_pattern(ras, marker, image_tr, 1.0, image); + render_pattern(marker, image_tr, 1.0, image); width_ = image.width(); height_ = image.height(); return std::make_shared(image, opacity); 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); +} + +} diff --git a/src/renderer_common/render_pattern.cpp b/src/renderer_common/render_pattern.cpp index 41ba3ee62..074fe6f00 100644 --- a/src/renderer_common/render_pattern.cpp +++ b/src/renderer_common/render_pattern.cpp @@ -41,8 +41,7 @@ namespace mapnik { template <> -void render_pattern(rasterizer & ras, - marker_svg const& marker, +void render_pattern(marker_svg const& marker, agg::trans_affine const& tr, double opacity, image_rgba8 & image) @@ -68,6 +67,7 @@ void render_pattern(rasterizer & ras, svg_attribute_type, renderer_solid, pixfmt> svg_renderer(svg_path, marker.get_data()->attributes()); + rasterizer ras; svg_renderer.render(ras, sl, renb, mtx, opacity, bbox); } diff --git a/test/data-visual b/test/data-visual index f527cc743..540fedb87 160000 --- a/test/data-visual +++ b/test/data-visual @@ -1 +1 @@ -Subproject commit f527cc7438b64c5b21e8d909547a6708859098c1 +Subproject commit 540fedb872bcc14af4e319e6e368b273a1660719