From 1e3c48afb1b427399b9ba8f7ee9a0daf2eadb8fe Mon Sep 17 00:00:00 2001 From: Mickey Rose Date: Thu, 7 Jun 2012 17:06:45 +0200 Subject: [PATCH 1/2] split parse_transform.hpp, set dynamic transform expression from python --- bindings/python/mapnik_svg.hpp | 15 +- include/mapnik/attribute_collector.hpp | 2 +- include/mapnik/parse_transform.hpp | 215 ++--------------------- include/mapnik/transform_processor.hpp | 232 +++++++++++++++++++++++++ src/parse_transform.cpp | 25 ++- src/symbolizer.cpp | 2 +- 6 files changed, 269 insertions(+), 222 deletions(-) create mode 100644 include/mapnik/transform_processor.hpp diff --git a/bindings/python/mapnik_svg.hpp b/bindings/python/mapnik_svg.hpp index b380bf39b..bb027e63e 100644 --- a/bindings/python/mapnik_svg.hpp +++ b/bindings/python/mapnik_svg.hpp @@ -25,15 +25,8 @@ // mapnik #include #include -#include #include -// boost -#include - -// agg -#include "agg_trans_affine.h" - namespace mapnik { using namespace boost::python; @@ -46,8 +39,8 @@ const std::string get_svg_transform(T& symbolizer) template void set_svg_transform(T& symbolizer, std::string const& transform_wkt) { - agg::trans_affine tr; - if (!mapnik::svg::parse_transform(transform_wkt.c_str(), tr)) + transform_list_ptr trans_expr = mapnik::parse_transform(transform_wkt); + if (!trans_expr) { std::stringstream ss; ss << "Could not parse transform from '" @@ -55,9 +48,7 @@ void set_svg_transform(T& symbolizer, std::string const& transform_wkt) << "', expected SVG transform attribute"; throw mapnik::value_error(ss.str()); } - transform_list_ptr trans = boost::make_shared(); - trans->push_back(matrix_node(tr)); - symbolizer.set_image_transform(trans); + symbolizer.set_image_transform(trans_expr); } } // end of namespace mapnik diff --git a/include/mapnik/attribute_collector.hpp b/include/mapnik/attribute_collector.hpp index 694765841..970dc9413 100644 --- a/include/mapnik/attribute_collector.hpp +++ b/include/mapnik/attribute_collector.hpp @@ -25,7 +25,7 @@ // mapnik #include -#include +#include // boost #include #include diff --git a/include/mapnik/parse_transform.hpp b/include/mapnik/parse_transform.hpp index 363ecc8fd..275d2a78d 100644 --- a/include/mapnik/parse_transform.hpp +++ b/include/mapnik/parse_transform.hpp @@ -25,218 +25,23 @@ // mapnik #include -#include -#include -#include -#include #include -#include - -// boost -#include -#include -#include -#include - -// agg -#include namespace mapnik { -template struct expression_attributes; template struct transform_expression_grammar; -MAPNIK_DECL transform_list_ptr parse_transform(std::string const & str); +typedef transform_expression_grammar + transform_expression_grammar__string; + +MAPNIK_DECL transform_list_ptr parse_transform(std::string const& str); + +MAPNIK_DECL transform_list_ptr parse_transform(std::string const& str, + std::string const& encoding); + MAPNIK_DECL bool parse_transform(transform_list& list, - std::string const & str, - transform_expression_grammar const& g); - - -template -struct transform_processor -{ - typedef T feature_type; - typedef agg::trans_affine transform_type; - - template - struct attribute_collector : boost::static_visitor - { - expression_attributes collect_; - - attribute_collector(Container& names) - : collect_(names) {} - - void operator() (identity_node const& node) const - { - boost::ignore_unused_variable_warning(node); - } - - void operator() (matrix_node const& node) const - { - boost::apply_visitor(collect_, node.a_); - boost::apply_visitor(collect_, node.b_); - boost::apply_visitor(collect_, node.c_); - boost::apply_visitor(collect_, node.d_); - boost::apply_visitor(collect_, node.e_); - boost::apply_visitor(collect_, node.f_); - } - - void operator() (translate_node const& node) const - { - boost::apply_visitor(collect_, node.tx_); - boost::apply_visitor(collect_, node.ty_); - } - - void operator() (scale_node const& node) const - { - boost::apply_visitor(collect_, node.sx_); - boost::apply_visitor(collect_, node.sy_); - } - - void operator() (rotate_node const& node) const - { - boost::apply_visitor(collect_, node.angle_); - boost::apply_visitor(collect_, node.cx_); - boost::apply_visitor(collect_, node.cy_); - } - - void operator() (skewX_node const& node) const - { - boost::apply_visitor(collect_, node.angle_); - } - - void operator() (skewY_node const& node) const - { - boost::apply_visitor(collect_, node.angle_); - } - }; - - struct node_evaluator : boost::static_visitor - { - node_evaluator(transform_type& tr, feature_type const& feat) - : transform_(tr), feature_(feat) {} - - void operator() (identity_node const& node) - { - boost::ignore_unused_variable_warning(node); - } - - void operator() (matrix_node const& node) - { - double a = eval(node.a_); - double b = eval(node.b_); - double c = eval(node.c_); - double d = eval(node.d_); - double e = eval(node.e_); - double f = eval(node.f_); - transform_.multiply(agg::trans_affine(a, b, c, d, e, f)); - } - - void operator() (translate_node const& node) - { - double tx = eval(node.tx_); - double ty = eval(node.ty_, 0.0); - transform_.translate(tx, ty); - } - - void operator() (scale_node const& node) - { - double sx = eval(node.sx_); - double sy = eval(node.sy_, sx); - transform_.scale(sx, sy); - } - - void operator() (rotate_node const& node) - { - double angle = deg2rad(eval(node.angle_)); - double cx = eval(node.cx_, 0.0); - double cy = eval(node.cy_, 0.0); - transform_.translate(-cx, -cy); - transform_.rotate(angle); - transform_.translate(cx, cy); - } - - void operator() (skewX_node const& node) - { - double angle = deg2rad(eval(node.angle_)); - transform_.multiply(agg::trans_affine_skewing(angle, 0.0)); - } - - void operator() (skewY_node const& node) - { - double angle = deg2rad(eval(node.angle_)); - transform_.multiply(agg::trans_affine_skewing(0.0, angle)); - } - - private: - - static double deg2rad(double d) - { - return d * M_PI / 180.0; - } - - double eval(expr_node const& x) const - { - mapnik::evaluate e(feature_); - return boost::apply_visitor(e, x).to_double(); - } - - double eval(expr_node const& x, double def) const - { - return is_null(x) ? def : eval(x); - } - - transform_type& transform_; - feature_type const& feature_; - }; - - template - static void collect_attributes(Container& names, - transform_list const& list) - { - attribute_collector collect(names); - - BOOST_FOREACH (transform_node const& node, list) - { - boost::apply_visitor(collect, *node); - } - } - - static void evaluate(transform_type& tr, feature_type const& feat, - transform_list const& list) - { - node_evaluator eval(tr, feat); - - #ifdef MAPNIK_LOG - MAPNIK_LOG_DEBUG(transform) << "transform: begin with " << to_string(matrix_node(tr)); - #endif - - BOOST_REVERSE_FOREACH (transform_node const& node, list) - { - boost::apply_visitor(eval, *node); - #ifdef MAPNIK_LOG - MAPNIK_LOG_DEBUG(transform) << "transform: apply " << to_string(*node); - MAPNIK_LOG_DEBUG(transform) << "transform: result " << to_string(matrix_node(tr)); - #endif - } - - #ifdef MAPNIK_LOG - MAPNIK_LOG_DEBUG(transform) << "transform: end"; - #endif - } - - static std::string to_string(transform_node const& node) - { - return to_expression_string(node); - } - - static std::string to_string(transform_list const& list) - { - return to_expression_string(list); - } -}; - -typedef mapnik::transform_processor transform_processor_type; + std::string const& str, + transform_expression_grammar__string const& g); } // namespace mapnik diff --git a/include/mapnik/transform_processor.hpp b/include/mapnik/transform_processor.hpp new file mode 100644 index 000000000..307ec1b3a --- /dev/null +++ b/include/mapnik/transform_processor.hpp @@ -0,0 +1,232 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2012 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_TRANSFORM_PROCESSOR_HPP +#define MAPNIK_TRANSFORM_PROCESSOR_HPP + +// mapnik +#include +#include +#include +#include +#include +#include + +// boost +#include + +// agg +#include + +namespace mapnik { + +template struct expression_attributes; + +template +struct transform_processor +{ + typedef T feature_type; + typedef agg::trans_affine transform_type; + + template + struct attribute_collector : boost::static_visitor + { + expression_attributes collect_; + + attribute_collector(Container& names) + : collect_(names) {} + + void operator() (identity_node const& node) const + { + boost::ignore_unused_variable_warning(node); + } + + void operator() (matrix_node const& node) const + { + boost::apply_visitor(collect_, node.a_); + boost::apply_visitor(collect_, node.b_); + boost::apply_visitor(collect_, node.c_); + boost::apply_visitor(collect_, node.d_); + boost::apply_visitor(collect_, node.e_); + boost::apply_visitor(collect_, node.f_); + } + + void operator() (translate_node const& node) const + { + boost::apply_visitor(collect_, node.tx_); + boost::apply_visitor(collect_, node.ty_); + } + + void operator() (scale_node const& node) const + { + boost::apply_visitor(collect_, node.sx_); + boost::apply_visitor(collect_, node.sy_); + } + + void operator() (rotate_node const& node) const + { + boost::apply_visitor(collect_, node.angle_); + boost::apply_visitor(collect_, node.cx_); + boost::apply_visitor(collect_, node.cy_); + } + + void operator() (skewX_node const& node) const + { + boost::apply_visitor(collect_, node.angle_); + } + + void operator() (skewY_node const& node) const + { + boost::apply_visitor(collect_, node.angle_); + } + }; + + struct node_evaluator : boost::static_visitor + { + node_evaluator(transform_type& tr, feature_type const& feat) + : transform_(tr), feature_(feat) {} + + void operator() (identity_node const& node) + { + boost::ignore_unused_variable_warning(node); + } + + void operator() (matrix_node const& node) + { + double a = eval(node.a_); + double b = eval(node.b_); + double c = eval(node.c_); + double d = eval(node.d_); + double e = eval(node.e_); + double f = eval(node.f_); + transform_.multiply(agg::trans_affine(a, b, c, d, e, f)); + } + + void operator() (translate_node const& node) + { + double tx = eval(node.tx_); + double ty = eval(node.ty_, 0.0); + transform_.translate(tx, ty); + } + + void operator() (scale_node const& node) + { + double sx = eval(node.sx_); + double sy = eval(node.sy_, sx); + transform_.scale(sx, sy); + } + + void operator() (rotate_node const& node) + { + double angle = deg2rad(eval(node.angle_)); + double cx = eval(node.cx_, 0.0); + double cy = eval(node.cy_, 0.0); + transform_.translate(-cx, -cy); + transform_.rotate(angle); + transform_.translate(cx, cy); + } + + void operator() (skewX_node const& node) + { + double angle = deg2rad(eval(node.angle_)); + transform_.multiply(agg::trans_affine_skewing(angle, 0.0)); + } + + void operator() (skewY_node const& node) + { + double angle = deg2rad(eval(node.angle_)); + transform_.multiply(agg::trans_affine_skewing(0.0, angle)); + } + + private: + + static double deg2rad(double d) + { + return d * M_PI / 180.0; + } + + double eval(expr_node const& x) const + { + mapnik::evaluate e(feature_); + return boost::apply_visitor(e, x).to_double(); + } + + double eval(expr_node const& x, double def) const + { + return is_null(x) ? def : eval(x); + } + + transform_type& transform_; + feature_type const& feature_; + }; + + template + static void collect_attributes(Container& names, + transform_list const& list) + { + attribute_collector collect(names); + + BOOST_FOREACH (transform_node const& node, list) + { + boost::apply_visitor(collect, *node); + } + } + + static void evaluate(transform_type& tr, feature_type const& feat, + transform_list const& list) + { + node_evaluator eval(tr, feat); + + #ifdef MAPNIK_LOG + MAPNIK_LOG_DEBUG(transform) << "transform: begin with " << to_string(matrix_node(tr)); + #endif + + BOOST_REVERSE_FOREACH (transform_node const& node, list) + { + boost::apply_visitor(eval, *node); + #ifdef MAPNIK_LOG + MAPNIK_LOG_DEBUG(transform) << "transform: apply " << to_string(*node); + MAPNIK_LOG_DEBUG(transform) << "transform: result " << to_string(matrix_node(tr)); + #endif + } + + #ifdef MAPNIK_LOG + MAPNIK_LOG_DEBUG(transform) << "transform: end"; + #endif + } + + static std::string to_string(transform_node const& node) + { + return to_expression_string(node); + } + + static std::string to_string(transform_list const& list) + { + return to_expression_string(list); + } +}; + +typedef mapnik::transform_processor transform_processor_type; + +} // namespace mapnik + +#endif // MAPNIK_TRANSFORM_PROCESSOR_HPP diff --git a/src/parse_transform.cpp b/src/parse_transform.cpp index 3b4ede837..325d440c6 100644 --- a/src/parse_transform.cpp +++ b/src/parse_transform.cpp @@ -27,9 +27,28 @@ namespace mapnik { +transform_list_ptr parse_transform(std::string const& str) +{ + return parse_transform(str, "utf-8"); +} + +transform_list_ptr parse_transform(std::string const& str, std::string const& encoding) +{ + transform_list_ptr tl = boost::make_shared(); + transcoder tc(encoding); + expression_grammar ge(tc); + transform_expression_grammar__string gte(ge); + + if (!parse_transform(*tl, str, gte)) + { + tl.reset(); + } + return tl; +} + bool parse_transform(transform_list& transform, - std::string const & str, - transform_expression_grammar const& g) + std::string const& str, + transform_expression_grammar__string const& g) { std::string::const_iterator itr = str.begin(); std::string::const_iterator end = str.end(); @@ -43,4 +62,4 @@ bool parse_transform(transform_list& transform, return (r && itr==end); } -} +} // namespace mapnik diff --git a/src/symbolizer.cpp b/src/symbolizer.cpp index d23b85e09..7825338c3 100644 --- a/src/symbolizer.cpp +++ b/src/symbolizer.cpp @@ -23,7 +23,7 @@ //mapnik #include #include -#include +#include namespace mapnik { From 2a7634693f804e3d5e0578098c80cf1605883874 Mon Sep 17 00:00:00 2001 From: Mickey Rose Date: Thu, 7 Jun 2012 17:12:15 +0200 Subject: [PATCH 2/2] add python test: set ShieldSymbolizer's transform --- tests/python_tests/object_test.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tests/python_tests/object_test.py b/tests/python_tests/object_test.py index 20776ed93..e4d7eede5 100644 --- a/tests/python_tests/object_test.py +++ b/tests/python_tests/object_test.py @@ -68,7 +68,8 @@ def test_shieldsymbolizer_init(): # strings for PathExpressions... should we pass objects? eq_(s.filename, '../data/images/dummy.png') - eq_(s.transform, 'matrix(1, 0, 0, 1, 0, 0)') + # 11c34b1: default transform list is empty, not identity matrix + eq_(s.transform, '') eq_(len(s.fontset.names), 0) @@ -79,6 +80,13 @@ def test_shieldsymbolizer_init(): #def test_shieldsymbolizer_missing_image(): # s = mapnik.ShieldSymbolizer(mapnik.Expression('[Field Name]'), 'DejaVu Sans Bold', 6, mapnik.Color('#000000'), mapnik.PathExpression('../#data/images/broken.png')) +# ShieldSymbolizer modification +def test_shieldsymbolizer_modify(): + s = mapnik.ShieldSymbolizer(mapnik.Expression('[Field Name]'), 'DejaVu Sans Bold', 6, mapnik.Color('#000000'), mapnik.PathExpression('../data/images/dummy.png')) + # transform expression + s.transform = "rotate(30+[a]) scale(2*[sx] [sy])" + eq_(s.transform, "rotate((30+[a])) scale(2*[sx], [sy])") + def test_polygonsymbolizer_init(): p = mapnik.PolygonSymbolizer()