/***************************************************************************** * * 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_GEOMETRY_STRATEGY_HPP #define MAPNIK_GEOMETRY_STRATEGY_HPP #include #include namespace mapnik { namespace geometry { namespace helper { template struct index {}; template struct gen_seq : gen_seq {}; template struct gen_seq<0, Ts...> : index {}; } // Groups a set of strategies at runtime, the conversion from P1 to P2 will take place on the LAST strategy. template struct strategy_group { strategy_group(Strategies const& ... ops) : ops_(ops ...) {} template inline bool apply(P1 const& p1, P2 & p2) const { bool status = true; p2 = execute_start(p1, status, ops_); return status; } template inline P2 execute_start(P1 const & p1, bool & status, std::tuple const& tup, helper::index) const { return execute(p1, status, std::get(tup)...); } template inline P2 execute_start(P1 const& p, bool & status, std::tuple const& tup) const { return execute_start(p, status, tup, helper::gen_seq {} ); } template inline P2 execute(P1 const& p, bool & status, T const& strat, Args const& ... args) const { return execute(strat.template execute(p, status), status, args...); } template inline P2 execute(P1 const& p, bool & status, T const& strat) const { return strat.template execute(p, status); } private: std::tuple ops_; }; // The difference between this strategy group and the previous is that the conversion from P1 to P2 happens // in the first strategy rather then the last strategy. template struct strategy_group_first { strategy_group_first(Strategies const& ... ops) : ops_(ops ...) {} template inline bool apply(P1 const& p1, P2 & p2) const { bool status = true; p2 = execute_start(p1, status, ops_); return status; } template inline P2 execute_start(P1 const & p1, bool & status, std::tuple const& tup, helper::index) const { return execute_first(p1, status, std::get(tup)...); } template inline P2 execute_start(P1 const& p, bool & status, std::tuple const& tup) const { return execute_start(p, status, tup, helper::gen_seq {} ); } template inline P2 execute_first(P1 const& p, bool & status, T const& strat, Args const& ... args) const { return execute(strat.template execute(p, status), status, args...); } template inline P2 execute(P2 const& p, bool & status, T const& strat, Args const& ... args) const { return execute(strat.template execute(p, status), status, args...); } template inline P2 execute(P2 const& p, bool & status, T const& strat) const { return strat.template execute(p, status); } template inline P2 execute(P2 const& p, bool & status) const { return p; } private: std::tuple ops_; }; struct scale_strategy { scale_strategy(double scale, double offset = 0) : scale_(scale), offset_(offset) {} template inline bool apply(P1 const & p1, P2 & p2) const { using p2_type = typename boost::geometry::coordinate_type::type; double x = (boost::geometry::get<0>(p1) * scale_) + offset_; double y = (boost::geometry::get<1>(p1) * scale_) + offset_; boost::geometry::set<0>(p2, static_cast(x)); boost::geometry::set<1>(p2, static_cast(y)); return true; } template inline P2 execute(P1 const& p1, bool & status) const { P2 p2; status = apply(p1, p2); return p2; } private: double scale_; double offset_; }; struct scale_rounding_strategy { scale_rounding_strategy(double scale, double offset = 0) : scale_(scale), offset_(offset) {} template inline bool apply(P1 const & p1, P2 & p2) const { using p2_type = typename boost::geometry::coordinate_type::type; double x = (boost::geometry::get<0>(p1) * scale_) + offset_; double y = (boost::geometry::get<1>(p1) * scale_) + offset_; boost::geometry::set<0>(p2, static_cast(std::round(x))); boost::geometry::set<1>(p2, static_cast(std::round(y))); return true; } template inline P2 execute(P1 const& p1, bool & status) const { P2 p2; status = apply(p1, p2); return p2; } private: double scale_; double offset_; }; } // end geometry ns } // end mapnik ns #endif //MAPNIK_GEOMETRY_STRATEGY_HPP