From 02505381495d5c29204e72cb89ea6931a93e557e Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Tue, 5 Nov 2013 16:40:09 -0800 Subject: [PATCH] add support for geometry-transform in pattern symbolizers - closes #2065 --- src/agg/process_line_pattern_symbolizer.cpp | 3 +- .../process_polygon_pattern_symbolizer.cpp | 3 +- src/grid/process_line_pattern_symbolizer.cpp | 65 ++++++++++-- .../process_polygon_pattern_symbolizer.cpp | 17 +++ ...e-patterns-200-200-1.0-grid-reference.json | 59 +++++++++++ ...symbolizer-900-250-1.0-grid-reference.json | 54 +++++----- ...er-opacity-512-512-1.0-grid-reference.json | 40 +++---- ...ate-patterns-200-200-1.0-agg-reference.png | Bin 0 -> 8607 bytes ...e-patterns-200-200-1.0-cairo-reference.png | Bin 0 -> 7238 bytes ...ate-patterns-200-200-2.0-agg-reference.png | Bin 0 -> 8769 bytes ...e-patterns-200-200-2.0-cairo-reference.png | Bin 0 -> 7393 bytes .../geometry-transform-translate-patterns.xml | 99 ++++++++++++++++++ tests/visual_tests/test.py | 1 + 13 files changed, 283 insertions(+), 58 deletions(-) create mode 100644 tests/visual_tests/grids/geometry-transform-translate-patterns-200-200-1.0-grid-reference.json create mode 100644 tests/visual_tests/images/geometry-transform-translate-patterns-200-200-1.0-agg-reference.png create mode 100644 tests/visual_tests/images/geometry-transform-translate-patterns-200-200-1.0-cairo-reference.png create mode 100644 tests/visual_tests/images/geometry-transform-translate-patterns-200-200-2.0-agg-reference.png create mode 100644 tests/visual_tests/images/geometry-transform-translate-patterns-200-200-2.0-cairo-reference.png create mode 100644 tests/visual_tests/styles/geometry-transform-translate-patterns.xml diff --git a/src/agg/process_line_pattern_symbolizer.cpp b/src/agg/process_line_pattern_symbolizer.cpp index c79410fb2..c2e466375 100644 --- a/src/agg/process_line_pattern_symbolizer.cpp +++ b/src/agg/process_line_pattern_symbolizer.cpp @@ -140,7 +140,7 @@ void agg_renderer::process(line_pattern_symbolizer const& sym, clip_box.pad(padding); } - typedef boost::mpl::vector conv_types; + typedef boost::mpl::vector conv_types; vertex_converter, rasterizer_type, line_pattern_symbolizer, CoordTransform, proj_transform, agg::trans_affine, conv_types> converter(clip_box,ras,sym,t_,prj_trans,tr,scale_factor_); @@ -149,6 +149,7 @@ void agg_renderer::process(line_pattern_symbolizer const& sym, converter.set(); //always transform if (sym.simplify_tolerance() > 0.0) converter.set(); // optional simplify converter if (std::fabs(sym.offset()) > 0.0) converter.set(); // parallel offset + converter.set(); // optional affine transform if (sym.smooth() > 0.0) converter.set(); // optional smooth converter BOOST_FOREACH(geometry_type & geom, feature.paths()) diff --git a/src/agg/process_polygon_pattern_symbolizer.cpp b/src/agg/process_polygon_pattern_symbolizer.cpp index 95ff2e056..ae82660d0 100644 --- a/src/agg/process_polygon_pattern_symbolizer.cpp +++ b/src/agg/process_polygon_pattern_symbolizer.cpp @@ -148,13 +148,14 @@ void agg_renderer::process(polygon_pattern_symbolizer const& sym, agg::trans_affine tr; evaluate_transform(tr, feature, sym.get_transform()); - typedef boost::mpl::vector conv_types; + typedef boost::mpl::vector conv_types; vertex_converter, rasterizer, polygon_pattern_symbolizer, CoordTransform, proj_transform, agg::trans_affine, conv_types> converter(clip_box,*ras_ptr,sym,t_,prj_trans,tr,scale_factor_); if (prj_trans.equal() && sym.clip()) converter.set(); //optional clip (default: true) converter.set(); //always transform + converter.set(); // optional affine transform if (sym.simplify_tolerance() > 0.0) converter.set(); // optional simplify converter if (sym.smooth() > 0.0) converter.set(); // optional smooth converter diff --git a/src/grid/process_line_pattern_symbolizer.cpp b/src/grid/process_line_pattern_symbolizer.cpp index b79e39dd0..eeaa700a9 100644 --- a/src/grid/process_line_pattern_symbolizer.cpp +++ b/src/grid/process_line_pattern_symbolizer.cpp @@ -27,6 +27,10 @@ #include #include #include +#include +#include +#include +#include // agg #include "agg_rasterizer_scanline_aa.h" @@ -45,10 +49,27 @@ void grid_renderer::process(line_pattern_symbolizer const& sym, mapnik::feature_impl & feature, proj_transform const& prj_trans) { + std::string filename = path_processor_type::evaluate( *sym.get_filename(), feature); + + boost::optional mark = marker_cache::instance().find(filename,true); + if (!mark) return; + + if (!(*mark)->is_bitmap()) + { + MAPNIK_LOG_DEBUG(agg_renderer) << "agg_renderer: Only images (not '" << filename << "') are supported in the line_pattern_symbolizer"; + return; + } + + boost::optional pat = (*mark)->get_bitmap_data(); + if (!pat) return; + typedef coord_transform path_type; typedef typename grid_renderer_base_type::pixfmt_type pixfmt_type; typedef typename grid_renderer_base_type::pixfmt_type::color_type color_type; typedef agg::renderer_scanline_bin_solid renderer_type; + typedef boost::mpl::vector conv_types; agg::scanline_bin sl; grid_rendering_buffer buf(pixmap_.raw_data(), width_, height_, width_); @@ -59,19 +80,45 @@ void grid_renderer::process(line_pattern_symbolizer const& sym, ras_ptr->reset(); - // TODO - actually handle image dimensions - int stroke_width = 2; + int stroke_width = (*pat)->width(); - for (std::size_t i=0;i clipping_extent = query_extent_; + if (sym.clip()) + { + double padding = (double)(query_extent_.width()/pixmap_.width()); + double half_stroke = stroke_width/2.0; + if (half_stroke > 1) + padding *= half_stroke; + if (std::fabs(sym.offset()) > 0) + padding *= std::fabs(sym.offset()) * 1.2; + padding *= scale_factor_; + clipping_extent.pad(padding); + } + + // to avoid the complexity of using an agg pattern filter instead + // we create a line_symbolizer in order to fake the pattern + stroke str; + str.set_width(stroke_width); + line_symbolizer line(str); + vertex_converter, grid_rasterizer, line_symbolizer, + CoordTransform, proj_transform, agg::trans_affine, conv_types> + converter(clipping_extent,*ras_ptr,line,t_,prj_trans,tr,scale_factor_); + if (sym.clip()) converter.set(); // optional clip (default: true) + converter.set(); // always transform + if (std::fabs(sym.offset()) > 0.0) converter.set(); // parallel offset + converter.set(); // optional affine transform + if (sym.simplify_tolerance() > 0.0) converter.set(); // optional simplify converter + if (sym.smooth() > 0.0) converter.set(); // optional smooth converter + converter.set(); //always stroke + + BOOST_FOREACH( geometry_type & geom, feature.paths()) { - geometry_type & geom = feature.get_geometry(i); if (geom.size() > 1) { - path_type path(t_,geom,prj_trans); - agg::conv_stroke stroke(path); - stroke.generator().miter_limit(4.0); - stroke.generator().width(stroke_width * scale_factor_); - ras_ptr->add_path(stroke); + converter.apply(geom); } } diff --git a/src/grid/process_polygon_pattern_symbolizer.cpp b/src/grid/process_polygon_pattern_symbolizer.cpp index 38145858f..da012dada 100644 --- a/src/grid/process_polygon_pattern_symbolizer.cpp +++ b/src/grid/process_polygon_pattern_symbolizer.cpp @@ -31,6 +31,9 @@ #include #include #include +#include +#include +#include // agg #include "agg_rasterizer_scanline_aa.h" @@ -48,6 +51,20 @@ void grid_renderer::process(polygon_pattern_symbolizer const& sym, mapnik::feature_impl & feature, proj_transform const& prj_trans) { + std::string filename = path_processor_type::evaluate( *sym.get_filename(), feature); + + boost::optional mark = marker_cache::instance().find(filename,true); + if (!mark) return; + + if (!(*mark)->is_bitmap()) + { + MAPNIK_LOG_DEBUG(agg_renderer) << "agg_renderer: Only images (not '" << filename << "') are supported in the line_pattern_symbolizer"; + return; + } + + boost::optional pat = (*mark)->get_bitmap_data(); + if (!pat) return; + ras_ptr->reset(); agg::trans_affine tr; diff --git a/tests/visual_tests/grids/geometry-transform-translate-patterns-200-200-1.0-grid-reference.json b/tests/visual_tests/grids/geometry-transform-translate-patterns-200-200-1.0-grid-reference.json new file mode 100644 index 000000000..5a7be5994 --- /dev/null +++ b/tests/visual_tests/grids/geometry-transform-translate-patterns-200-200-1.0-grid-reference.json @@ -0,0 +1,59 @@ +{ + "keys": [ + "", + "1" + ], + "data": {}, + "grid": [ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ", + " !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ", + " !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ", + " !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ", + " !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ", + " !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ", + " !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ", + " !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ", + " !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ", + " !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ", + " !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ", + " !!!!!!!!!!! !!!!!!!!!!! ", + " !!!!!!!!!!! !!!!!!!!!!! ", + " !!!!!!!!!!! !!!!!!!!!!! ", + " !!!!!!!!!!! !!!!!!!!!!! ", + " !!!!!!!!!!! !!!!!!!!!!! ", + " !!!!!!!!!!! !!!!!!!!!!! ", + " !!!!!!!!!!! !!!!!!!!!!! ", + " !!!!!!!!!!! !!!!!!!!!!! ", + " !!!!!!!!!!! !!!!!!!!!!! ", + " !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ", + " !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ", + " !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ", + " !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ", + " !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ", + " !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ", + " !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ", + " !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ", + " !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ", + " !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ", + " !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + ] +} \ No newline at end of file diff --git a/tests/visual_tests/grids/line-pattern-symbolizer-900-250-1.0-grid-reference.json b/tests/visual_tests/grids/line-pattern-symbolizer-900-250-1.0-grid-reference.json index c6af26426..8d2d83b97 100644 --- a/tests/visual_tests/grids/line-pattern-symbolizer-900-250-1.0-grid-reference.json +++ b/tests/visual_tests/grids/line-pattern-symbolizer-900-250-1.0-grid-reference.json @@ -32,33 +32,33 @@ " ", " ", " ", - " ", - " !!!!! ########### $$$$$$$$$$ %%%%%%% ", - " !!! !!! ### ### $$$ $$$ %%%% %%% ", - " !! !! ## ## $$ $$ %% %%% ", - " !! !! ## ## $ $$ %% % ", - " !! ! # # $$ $ % %% ", - " ! !! # # $$ $ %% % ", - " ! !! # # $ $ %% % ", - " !! ! # # $ $ % % ", - " ! ! # # $ $ % % ", - " ! ! # # $ $ % % ", - " ! ! # # $ $ % % ", - " ! ! &&&&& # $ $ % % ", - " ! '''''''''''''''''''''''''''''' # # $ $ % (((((((((((( ", - " ! ! # # $ $ % % ", - " ! ! # $ $ % ", - " ! # # $ % ", - " ! ! ## # $ $ % % ", - " ! ! # # $ $ % % ", - " !! ! # # $ $ % % ", - " !! ! ## ## $$ $ % % ", - " ! !! # # $ $$ %% %% ", - " !! !! ## ### $$ $$ %% %% ", - " !! !! ### ### $$$ $$$ %%% %%% ", - " !!!!! !!!!!! ######### $$$$$$$$$$ %%%%%%%%%%%% ", - " ", - " ", + " !!!!!!!!! ############# $$$$$$$$$$$$ %%%%%%%%%%% ", + " !!!!!!!!!!!!!!!!! ##################### $$$$$$$$$$$$$$$$$$$$ %%%%%%%%%%%%%%%%%%% ", + " !!!!!!!!!!!!!!!!!!!!!!! ######################### $$$$$$$$$$$$$$$$$$$$$$$$ %%%%%%%%%%%%%%%%%%%%%%% ", + " !!!!!!!!!!! !!!!!!!!!!!! ######## ######### $$$$$$$$$ $$$$$$$$$$ %%%%%%%%%% %%%%%%%%%% ", + " !!!!!!! !!!!!!! ####### ####### $$$$$$ $$$$$$$ %%%%%%% %%%%%%%% ", + " !!!!!! !!!!!! ###### ###### $$$$$ $$$$$$ %%%%% %%%%%% ", + " !!!!!! !!!!! ##### ##### $$$$$ $$$$$ %%%%% %%%%% ", + " !!!! !!!!! ##### ##### $$$$ $$$$$ %%%% %%%%% ", + " !!!! !!!! #### #### $$$$ $$$$ %%%% %%%% ", + " !!!! !!!! #### #### $$$ $$$$ %%%% %%%% ", + " !!!! !!!! #### #### $$$$ $$$ %%%% %%%% ", + " !!! !!!! ### ### $$$$ $$$ %%%% %%% ", + " !!! !!! #&&&&& ### $$$ $$$ %%% %%% ", + " !!! ''''''''''''''''''''''''''''''! ### ### $$$ $$$ %%% ((((((((((((% ", + " !!! !!! ### ### $$$$ $$$ %%% %%% ", + " !!! !!!! #### #### $$$$ $$$ %%%% %%% ", + " !!!! !!! ### #### $$$ $$$$ %%% %%%% ", + " !!!! !!!! #### #### $$$$ $$$$ %%%% %%%% ", + " !!!! !!!!! #### #### $$$$ $$$$$ %%%% %%%%% ", + " !!!!! !!!!! ##### ##### $$$$ $$$$$ %%%%% %%%%% ", + " !!!!! !!!!! ###### ###### $$$$$$ $$$$$$ %%%%%% %%%%% ", + " !!!!!! !!!!!! ####### ####### $$$$$$ $$$$$$$ %%%%%%% %%%%%% ", + " !!!!!!!! !!!!!!!! ########## ########## $$$$$$$$$ $$$$$$$$$ %%%%%%%% %%%%%%%%% ", + " !!!!!!!!!!!!!!!!!!!!!!!!! ####################### $$$$$$$$$$$$$$$$$$$$$$$$ %%%%%%%%%%%%%%%%%%%%%%%%% ", + " !!!!!!!!!!!!!!!!!!!!! ################### $$$$$$$$$$$$$$$$$$$$ %%%%%%%%%%%%%%%%%%%%% ", + " !!!!!!!!!!!!!!! ########### $$$$$$$$$$$$$ %%%%%%%%%%%%%% ", + " !!! ", " ", " ", " ", diff --git a/tests/visual_tests/grids/line-pattern-symbolizer-opacity-512-512-1.0-grid-reference.json b/tests/visual_tests/grids/line-pattern-symbolizer-opacity-512-512-1.0-grid-reference.json index 1efa6d583..686cdf599 100644 --- a/tests/visual_tests/grids/line-pattern-symbolizer-opacity-512-512-1.0-grid-reference.json +++ b/tests/visual_tests/grids/line-pattern-symbolizer-opacity-512-512-1.0-grid-reference.json @@ -1,12 +1,12 @@ { "keys": [ "", - "4", "3", + "4", "2", "1", - "8", "7", + "8", "6", "5" ], @@ -67,24 +67,24 @@ " ", " ", " ", - " ", - " !!!!!!!! ##### ##### $$$$$$$$$$ %%%%%%%%% ", - " !! !! ### ## $$ $$ %% %% ", - " !! ! # # $$ $$ %% %% ", - " !! !! # # $$ $ % % ", - " ! !! # # $ $ % % ", - " ! ! # # $ $ % %", - "! ! # $ $ % ", - "! ! # $ $ % ", - "&&&&&&&&&&&&&&&&&&&&&&&&&& ''''''''''''''''''''''# (((((((((((((((((((((((((( )))))))))))))))))))))))))", - "! ! $ $ % ", - "! ! # # $ $ % %", - " ! ! ## # $ $ %% %", - " !! ! # # $ $ % % ", - " !! !! ## ## $ $ %% % ", - " ! ! ## # $$ $$ %% %% ", - " !!! !!! ### ### $$$ $$ %%% %% ", - " !!!!!!!!!! ##### $$$$$$$$ %%%%%%%% ", + " !! ", + " ########## !!!!!!!!!!!!! $$$$$$$$$$$$ %%%%%%%%%%% ", + " #### #### !!! !!! $$$ $$$ %%%% %%%% ", + " ### ### !!! !!! $$$ $$ %% %%% ", + " ## ## !! !! $$ $$ %% %% ", + " ## ## !! !! $$ $$ %% %%", + " # ## ! ! $$ $$ %% %", + "## # !! !! $ $ % %", + "# # !&&&& ! $ $ %% ", + "'''''''''''''''''''''''''' !&&&&&&&&&&&&&&&&&&&&&&&&&! (((((((((((((((((((((((((( %)))))))))))))))))))))))))", + "# # !! !! $ $ %% ", + "# # ! ! $$ $ % %", + "## ## !! !! $ $ %% %", + " ## ## !! !! $$ $$ %% %%", + " ## ## !! !! $$$ $$ %% %%% ", + " ### ### !!! !!! $$ $$$ %%% %% ", + " #### #### !!!!! !!!!! $$$$$ $$$$$ %%%% %%%%% ", + " ############ !!!!!!!!! $$$$$$$$$$ %%%%%%%%%%% ", " ", " ", " ", diff --git a/tests/visual_tests/images/geometry-transform-translate-patterns-200-200-1.0-agg-reference.png b/tests/visual_tests/images/geometry-transform-translate-patterns-200-200-1.0-agg-reference.png new file mode 100644 index 0000000000000000000000000000000000000000..69c3659440d4658186b5eeb5ebbe8bae4c5b689b GIT binary patch literal 8607 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 literal 0 HcmV?d00001 diff --git a/tests/visual_tests/images/geometry-transform-translate-patterns-200-200-1.0-cairo-reference.png b/tests/visual_tests/images/geometry-transform-translate-patterns-200-200-1.0-cairo-reference.png new file mode 100644 index 0000000000000000000000000000000000000000..a2987030665f474164de27aa374ae86d944412b1 GIT binary patch literal 7238 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 HYaaGLJ|gd? literal 0 HcmV?d00001 diff --git a/tests/visual_tests/styles/geometry-transform-translate-patterns.xml b/tests/visual_tests/styles/geometry-transform-translate-patterns.xml new file mode 100644 index 000000000..16702b98d --- /dev/null +++ b/tests/visual_tests/styles/geometry-transform-translate-patterns.xml @@ -0,0 +1,99 @@ + + + + + + + + polygon + + csv + +wkt +"POLYGON ((1 1, 4 1, 4 4, 1 4, 1 1), (2 2, 2 3, 3 3, 3 2, 2 2))" + + + + + + line + + csv + +wkt +"LINESTRING (0.5 0.5, 4.5 4.5)" + + + + + + point + + csv + +wkt +"POINT (1 4)" + + + + + + + + + + frame + + csv + +x,y +0,0 +5,0 +0,5 +5,5 + + + + + diff --git a/tests/visual_tests/test.py b/tests/visual_tests/test.py index c2a3498ef..80bfea546 100755 --- a/tests/visual_tests/test.py +++ b/tests/visual_tests/test.py @@ -100,6 +100,7 @@ files = { 'shield-on-polygon': {'sizes':[(600,400)]}, 'shield-on-line-spacing-eq-width': {'sizes':[(600,400)]}, 'geometry-transform-translate': {'sizes':[(200,200)]}, + 'geometry-transform-translate-patterns': {'sizes':[(200,200)]}, 'marker-svg-opacity':{}, 'marker-svg-opacity2':{}, 'marker-svg-empty-g-element':{},