Chris@16: // Boost.Geometry (aka GGL, Generic Geometry Library) Chris@16: Chris@16: // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. Chris@16: // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. Chris@16: // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. Chris@101: // Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland. Chris@16: Chris@16: // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library Chris@16: // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. Chris@16: Chris@16: // Use, modification and distribution is subject to the Boost Software License, Chris@16: // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at Chris@16: // http://www.boost.org/LICENSE_1_0.txt) Chris@16: Chris@16: #ifndef BOOST_GEOMETRY_ALGORITHMS_TRANSFORM_HPP Chris@16: #define BOOST_GEOMETRY_ALGORITHMS_TRANSFORM_HPP Chris@16: Chris@16: #include Chris@16: #include Chris@16: Chris@16: #include Chris@101: #include Chris@101: Chris@101: #include Chris@101: #include Chris@101: #include Chris@16: Chris@16: #include Chris@16: #include Chris@101: #include Chris@16: #include Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@101: #include Chris@16: #include Chris@101: #include Chris@16: #include Chris@16: Chris@16: Chris@16: namespace boost { namespace geometry Chris@16: { Chris@16: Chris@16: #ifndef DOXYGEN_NO_DETAIL Chris@16: namespace detail { namespace transform Chris@16: { Chris@16: Chris@16: struct transform_point Chris@16: { Chris@16: template Chris@16: static inline bool apply(Point1 const& p1, Point2& p2, Chris@16: Strategy const& strategy) Chris@16: { Chris@16: return strategy.apply(p1, p2); Chris@16: } Chris@16: }; Chris@16: Chris@16: Chris@16: struct transform_box Chris@16: { Chris@16: template Chris@16: static inline bool apply(Box1 const& b1, Box2& b2, Chris@16: Strategy const& strategy) Chris@16: { Chris@16: typedef typename point_type::type point_type1; Chris@16: typedef typename point_type::type point_type2; Chris@16: Chris@16: point_type1 lower_left, upper_right; Chris@16: detail::assign::assign_box_2d_corner( Chris@16: b1, lower_left); Chris@16: detail::assign::assign_box_2d_corner( Chris@16: b1, upper_right); Chris@16: Chris@16: point_type2 p1, p2; Chris@16: if (strategy.apply(lower_left, p1) && strategy.apply(upper_right, p2)) Chris@16: { Chris@16: // Create a valid box and therefore swap if necessary Chris@16: typedef typename coordinate_type::type coordinate_type; Chris@16: coordinate_type x1 = geometry::get<0>(p1) Chris@16: , y1 = geometry::get<1>(p1) Chris@16: , x2 = geometry::get<0>(p2) Chris@16: , y2 = geometry::get<1>(p2); Chris@16: Chris@16: if (x1 > x2) { std::swap(x1, x2); } Chris@16: if (y1 > y2) { std::swap(y1, y2); } Chris@16: Chris@16: set(b2, x1); Chris@16: set(b2, y1); Chris@16: set(b2, x2); Chris@16: set(b2, y2); Chris@16: Chris@16: return true; Chris@16: } Chris@16: return false; Chris@16: } Chris@16: }; Chris@16: Chris@16: struct transform_box_or_segment Chris@16: { Chris@16: template Chris@16: static inline bool apply(Geometry1 const& source, Geometry2& target, Chris@16: Strategy const& strategy) Chris@16: { Chris@16: typedef typename point_type::type point_type1; Chris@16: typedef typename point_type::type point_type2; Chris@16: Chris@16: point_type1 source_point[2]; Chris@16: geometry::detail::assign_point_from_index<0>(source, source_point[0]); Chris@16: geometry::detail::assign_point_from_index<1>(source, source_point[1]); Chris@16: Chris@16: point_type2 target_point[2]; Chris@16: if (strategy.apply(source_point[0], target_point[0]) Chris@16: && strategy.apply(source_point[1], target_point[1])) Chris@16: { Chris@16: geometry::detail::assign_point_to_index<0>(target_point[0], target); Chris@16: geometry::detail::assign_point_to_index<1>(target_point[1], target); Chris@16: return true; Chris@16: } Chris@16: return false; Chris@16: } Chris@16: }; Chris@16: Chris@16: Chris@16: template Chris@16: < Chris@16: typename PointOut, Chris@16: typename OutputIterator, Chris@16: typename Range, Chris@16: typename Strategy Chris@16: > Chris@16: inline bool transform_range_out(Range const& range, Chris@16: OutputIterator out, Strategy const& strategy) Chris@16: { Chris@16: PointOut point_out; Chris@16: for(typename boost::range_iterator::type Chris@16: it = boost::begin(range); Chris@16: it != boost::end(range); Chris@16: ++it) Chris@16: { Chris@16: if (! transform_point::apply(*it, point_out, strategy)) Chris@16: { Chris@16: return false; Chris@16: } Chris@16: *out++ = point_out; Chris@16: } Chris@16: return true; Chris@16: } Chris@16: Chris@16: Chris@16: struct transform_polygon Chris@16: { Chris@16: template Chris@16: static inline bool apply(Polygon1 const& poly1, Polygon2& poly2, Chris@16: Strategy const& strategy) Chris@16: { Chris@16: typedef typename point_type::type point2_type; Chris@16: Chris@16: geometry::clear(poly2); Chris@16: Chris@16: if (!transform_range_out(exterior_ring(poly1), Chris@16: std::back_inserter(exterior_ring(poly2)), strategy)) Chris@16: { Chris@16: return false; Chris@16: } Chris@16: Chris@16: // Note: here a resizeable container is assumed. Chris@16: traits::resize Chris@16: < Chris@16: typename boost::remove_reference Chris@16: < Chris@16: typename traits::interior_mutable_type::type Chris@16: >::type Chris@16: >::apply(interior_rings(poly2), num_interior_rings(poly1)); Chris@16: Chris@101: typename interior_return_type::type Chris@101: rings1 = interior_rings(poly1); Chris@101: typename interior_return_type::type Chris@101: rings2 = interior_rings(poly2); Chris@101: Chris@101: typename detail::interior_iterator::type Chris@101: it1 = boost::begin(rings1); Chris@101: typename detail::interior_iterator::type Chris@101: it2 = boost::begin(rings2); Chris@101: for ( ; it1 != boost::end(rings1); ++it1, ++it2) Chris@16: { Chris@101: if ( ! transform_range_out(*it1, Chris@101: std::back_inserter(*it2), Chris@101: strategy) ) Chris@16: { Chris@16: return false; Chris@16: } Chris@16: } Chris@16: Chris@16: return true; Chris@16: } Chris@16: }; Chris@16: Chris@16: Chris@16: template Chris@16: struct select_strategy Chris@16: { Chris@16: typedef typename strategy::transform::services::default_strategy Chris@16: < Chris@16: typename cs_tag::type, Chris@16: typename cs_tag::type, Chris@16: typename coordinate_system::type, Chris@16: typename coordinate_system::type, Chris@16: dimension::type::value, Chris@16: dimension::type::value, Chris@16: typename point_type::type, Chris@16: typename point_type::type Chris@16: >::type type; Chris@16: }; Chris@16: Chris@16: struct transform_range Chris@16: { Chris@16: template Chris@16: static inline bool apply(Range1 const& range1, Chris@16: Range2& range2, Strategy const& strategy) Chris@16: { Chris@16: typedef typename point_type::type point_type; Chris@16: Chris@16: // Should NOT be done here! Chris@16: // geometry::clear(range2); Chris@16: return transform_range_out(range1, Chris@16: std::back_inserter(range2), strategy); Chris@16: } Chris@16: }; Chris@16: Chris@101: Chris@101: /*! Chris@101: \brief Is able to transform any multi-geometry, calling the single-version as policy Chris@101: */ Chris@101: template Chris@101: struct transform_multi Chris@101: { Chris@101: template Chris@101: static inline bool apply(Multi1 const& multi1, Multi2& multi2, S const& strategy) Chris@101: { Chris@101: traits::resize::apply(multi2, boost::size(multi1)); Chris@101: Chris@101: typename boost::range_iterator::type it1 Chris@101: = boost::begin(multi1); Chris@101: typename boost::range_iterator::type it2 Chris@101: = boost::begin(multi2); Chris@101: Chris@101: for (; it1 != boost::end(multi1); ++it1, ++it2) Chris@101: { Chris@101: if (! Policy::apply(*it1, *it2, strategy)) Chris@101: { Chris@101: return false; Chris@101: } Chris@101: } Chris@101: Chris@101: return true; Chris@101: } Chris@101: }; Chris@101: Chris@101: Chris@16: }} // namespace detail::transform Chris@16: #endif // DOXYGEN_NO_DETAIL Chris@16: Chris@16: Chris@16: #ifndef DOXYGEN_NO_DISPATCH Chris@16: namespace dispatch Chris@16: { Chris@16: Chris@16: template Chris@16: < Chris@16: typename Geometry1, typename Geometry2, Chris@16: typename Tag1 = typename tag_cast::type, multi_tag>::type, Chris@16: typename Tag2 = typename tag_cast::type, multi_tag>::type Chris@16: > Chris@16: struct transform {}; Chris@16: Chris@16: template Chris@16: struct transform Chris@16: : detail::transform::transform_point Chris@16: { Chris@16: }; Chris@16: Chris@16: Chris@16: template Chris@16: struct transform Chris@16: < Chris@16: Linestring1, Linestring2, Chris@16: linestring_tag, linestring_tag Chris@16: > Chris@16: : detail::transform::transform_range Chris@16: { Chris@16: }; Chris@16: Chris@16: template Chris@16: struct transform Chris@16: : detail::transform::transform_range Chris@16: { Chris@16: }; Chris@16: Chris@16: template Chris@16: struct transform Chris@16: : detail::transform::transform_polygon Chris@16: { Chris@16: }; Chris@16: Chris@16: template Chris@16: struct transform Chris@16: : detail::transform::transform_box Chris@16: { Chris@16: }; Chris@16: Chris@16: template Chris@16: struct transform Chris@16: : detail::transform::transform_box_or_segment Chris@16: { Chris@16: }; Chris@16: Chris@101: template Chris@101: struct transform Chris@101: < Chris@101: Multi1, Multi2, Chris@101: multi_tag, multi_tag Chris@101: > Chris@101: : detail::transform::transform_multi Chris@101: < Chris@101: dispatch::transform Chris@101: < Chris@101: typename boost::range_value::type, Chris@101: typename boost::range_value::type Chris@101: > Chris@101: > Chris@101: {}; Chris@101: Chris@16: Chris@16: } // namespace dispatch Chris@16: #endif // DOXYGEN_NO_DISPATCH Chris@16: Chris@16: Chris@101: namespace resolve_strategy { Chris@101: Chris@101: struct transform Chris@101: { Chris@101: template Chris@101: static inline bool apply(Geometry1 const& geometry1, Chris@101: Geometry2& geometry2, Chris@101: Strategy const& strategy) Chris@101: { Chris@101: concept::check(); Chris@101: concept::check(); Chris@101: Chris@101: return dispatch::transform::apply( Chris@101: geometry1, Chris@101: geometry2, Chris@101: strategy Chris@101: ); Chris@101: } Chris@101: Chris@101: template Chris@101: static inline bool apply(Geometry1 const& geometry1, Chris@101: Geometry2& geometry2, Chris@101: default_strategy) Chris@101: { Chris@101: return apply( Chris@101: geometry1, Chris@101: geometry2, Chris@101: typename detail::transform::select_strategy::type() Chris@101: ); Chris@101: } Chris@101: }; Chris@101: Chris@101: } // namespace resolve_strategy Chris@101: Chris@101: Chris@101: namespace resolve_variant { Chris@101: Chris@101: template Chris@101: struct transform Chris@101: { Chris@101: template Chris@101: static inline bool apply(Geometry1 const& geometry1, Chris@101: Geometry2& geometry2, Chris@101: Strategy const& strategy) Chris@101: { Chris@101: return resolve_strategy::transform::apply( Chris@101: geometry1, Chris@101: geometry2, Chris@101: strategy Chris@101: ); Chris@101: } Chris@101: }; Chris@101: Chris@101: template Chris@101: struct transform, Geometry2> Chris@101: { Chris@101: template Chris@101: struct visitor: static_visitor Chris@101: { Chris@101: Geometry2& m_geometry2; Chris@101: Strategy const& m_strategy; Chris@101: Chris@101: visitor(Geometry2& geometry2, Strategy const& strategy) Chris@101: : m_geometry2(geometry2) Chris@101: , m_strategy(strategy) Chris@101: {} Chris@101: Chris@101: template Chris@101: inline bool operator()(Geometry1 const& geometry1) const Chris@101: { Chris@101: return transform::apply( Chris@101: geometry1, Chris@101: m_geometry2, Chris@101: m_strategy Chris@101: ); Chris@101: } Chris@101: }; Chris@101: Chris@101: template Chris@101: static inline bool apply( Chris@101: boost::variant const& geometry1, Chris@101: Geometry2& geometry2, Chris@101: Strategy const& strategy Chris@101: ) Chris@101: { Chris@101: return apply_visitor(visitor(geometry2, strategy), geometry1); Chris@101: } Chris@101: }; Chris@101: Chris@101: } // namespace resolve_variant Chris@101: Chris@101: Chris@16: /*! Chris@16: \brief Transforms from one geometry to another geometry \brief_strategy Chris@16: \ingroup transform Chris@16: \tparam Geometry1 \tparam_geometry Chris@16: \tparam Geometry2 \tparam_geometry Chris@16: \tparam Strategy strategy Chris@16: \param geometry1 \param_geometry Chris@16: \param geometry2 \param_geometry Chris@16: \param strategy The strategy to be used for transformation Chris@16: \return True if the transformation could be done Chris@16: Chris@16: \qbk{distinguish,with strategy} Chris@16: Chris@16: \qbk{[include reference/algorithms/transform_with_strategy.qbk]} Chris@16: */ Chris@16: template Chris@16: inline bool transform(Geometry1 const& geometry1, Geometry2& geometry2, Chris@16: Strategy const& strategy) Chris@16: { Chris@101: return resolve_variant::transform Chris@101: ::apply(geometry1, geometry2, strategy); Chris@16: } Chris@16: Chris@16: Chris@16: /*! Chris@16: \brief Transforms from one geometry to another geometry using a strategy Chris@16: \ingroup transform Chris@16: \tparam Geometry1 \tparam_geometry Chris@16: \tparam Geometry2 \tparam_geometry Chris@16: \param geometry1 \param_geometry Chris@16: \param geometry2 \param_geometry Chris@16: \return True if the transformation could be done Chris@16: Chris@16: \qbk{[include reference/algorithms/transform.qbk]} Chris@16: */ Chris@16: template Chris@16: inline bool transform(Geometry1 const& geometry1, Geometry2& geometry2) Chris@16: { Chris@101: return transform(geometry1, geometry2, default_strategy()); Chris@16: } Chris@16: Chris@16: Chris@16: }} // namespace boost::geometry Chris@16: Chris@16: Chris@16: #endif // BOOST_GEOMETRY_ALGORITHMS_TRANSFORM_HPP