/***************************************************************************** * * 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 * *****************************************************************************/ #ifndef MAPNIK_TRANSFORM_PROCESSOR_HPP #define MAPNIK_TRANSFORM_PROCESSOR_HPP // mapnik #include #include #include #include #include #pragma GCC diagnostic push #include #include #pragma GCC diagnostic pop // stl #include namespace mapnik { class feature_impl; template struct expression_attributes; template struct transform_processor { using feature_type = T; using variable_type = T1; using transform_type = agg::trans_affine; template struct attribute_collector { expression_attributes collect_; attribute_collector(Container& names) : collect_(names) {} void operator() (identity_node const&) const { } void operator() (matrix_node const& node) const { util::apply_visitor(collect_, node.a_); util::apply_visitor(collect_, node.b_); util::apply_visitor(collect_, node.c_); util::apply_visitor(collect_, node.d_); util::apply_visitor(collect_, node.e_); util::apply_visitor(collect_, node.f_); } void operator() (translate_node const& node) const { util::apply_visitor(collect_, node.tx_); util::apply_visitor(collect_, node.ty_); } void operator() (scale_node const& node) const { util::apply_visitor(collect_, node.sx_); util::apply_visitor(collect_, node.sy_); } void operator() (rotate_node const& node) const { util::apply_visitor(collect_, node.angle_); util::apply_visitor(collect_, node.cx_); util::apply_visitor(collect_, node.cy_); } void operator() (skewX_node const& node) const { util::apply_visitor(collect_, node.angle_); } void operator() (skewY_node const& node) const { util::apply_visitor(collect_, node.angle_); } }; struct node_evaluator { node_evaluator(transform_type& tr, feature_type const& feat, variable_type const& v, double scale_factor) : transform_(tr), feature_(feat), vars_(v), scale_factor_(scale_factor) {} void operator() (identity_node const&) const { } void operator() (matrix_node const& node) const { double a = eval(node.a_); // scale x; double b = eval(node.b_); double c = eval(node.c_); double d = eval(node.d_); // scale y; double e = eval(node.e_) * scale_factor_; // translate x double f = eval(node.f_) * scale_factor_; // translate y transform_.multiply(agg::trans_affine(a, b, c, d, e, f)); } void operator() (translate_node const& node) const { double tx = eval(node.tx_) * scale_factor_; double ty = eval(node.ty_, 0.0) * scale_factor_; transform_.translate(tx, ty); } void operator() (scale_node const& node) const { double sx = eval(node.sx_); double sy = eval(node.sy_, sx); transform_.scale(sx, sy); } void operator() (rotate_node const& node) const { 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) const { auto degrees = std::fmod(eval(node.angle_),90.0); if (degrees < -89.0) degrees = -89.0; else if (degrees > 89.0) degrees = 89.0; auto angle = deg2rad(degrees); transform_.multiply(agg::trans_affine_skewing(angle, 0.0)); } void operator() (skewY_node const& node) const { auto degrees = std::fmod(eval(node.angle_),90.0); if (degrees < -89.0) degrees = -89.0; else if (degrees > 89.0) degrees = 89.0; auto angle = deg2rad(degrees); 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_,vars_); return util::apply_visitor(e, x).to_double(); } double eval(expr_node const& x, double def) const { return detail::is_null_node(x) ? def : eval(x); } transform_type& transform_; feature_type const& feature_; variable_type const& vars_; double scale_factor_; }; template static void collect_attributes(Container& names, transform_list const& list) { attribute_collector collect(names); for (transform_node const& node : list) { util::apply_visitor(collect, *node); } } static void evaluate(transform_type& tr, feature_type const& feat, variable_type const& vars, transform_list const& list, double scale_factor) { node_evaluator eval(tr, feat, vars, scale_factor); transform_list::const_reverse_iterator rit; for (rit = list.rbegin(); rit!= list.rend(); ++rit) { util::apply_visitor(eval, *(*rit)); } } 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); } }; using transform_processor_type = mapnik::transform_processor; } // namespace mapnik #endif // MAPNIK_TRANSFORM_PROCESSOR_HPP