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_CONVERT_HPP Chris@16: #define BOOST_GEOMETRY_ALGORITHMS_CONVERT_HPP Chris@16: Chris@16: Chris@16: #include Chris@16: Chris@16: #include Chris@16: #include 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@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@101: #include Chris@16: Chris@16: #include Chris@16: #include Chris@16: Chris@101: #include Chris@101: Chris@16: #include Chris@16: #include Chris@16: #include Chris@101: #include Chris@101: Chris@16: #include Chris@16: Chris@16: Chris@16: namespace boost { namespace geometry Chris@16: { Chris@16: Chris@16: // Silence warning C4127: conditional expression is constant Chris@16: // Silence warning C4512: assignment operator could not be generated Chris@16: #if defined(_MSC_VER) Chris@101: #pragma warning(push) Chris@16: #pragma warning(disable : 4127 4512) Chris@16: #endif Chris@16: Chris@16: Chris@16: #ifndef DOXYGEN_NO_DETAIL Chris@16: namespace detail { namespace conversion Chris@16: { Chris@16: Chris@16: template Chris@16: < Chris@16: typename Point, Chris@16: typename Box, Chris@16: std::size_t Index, Chris@16: std::size_t Dimension, Chris@16: std::size_t DimensionCount Chris@16: > Chris@16: struct point_to_box Chris@16: { Chris@16: static inline void apply(Point const& point, Box& box) Chris@16: { Chris@16: typedef typename coordinate_type::type coordinate_type; Chris@16: Chris@16: set(box, Chris@16: boost::numeric_cast(get(point))); Chris@16: point_to_box Chris@16: < Chris@16: Point, Box, Chris@16: Index, Dimension + 1, DimensionCount Chris@16: >::apply(point, box); Chris@16: } Chris@16: }; Chris@16: Chris@16: Chris@16: template Chris@16: < Chris@16: typename Point, Chris@16: typename Box, Chris@16: std::size_t Index, Chris@16: std::size_t DimensionCount Chris@16: > Chris@16: struct point_to_box Chris@16: { Chris@16: static inline void apply(Point const& , Box& ) Chris@16: {} Chris@16: }; Chris@16: Chris@16: template Chris@16: struct box_to_range Chris@16: { Chris@16: static inline void apply(Box const& box, Range& range) Chris@16: { Chris@16: traits::resize::apply(range, Close ? 5 : 4); Chris@16: assign_box_corners_oriented(box, range); Chris@16: if (Close) Chris@16: { Chris@101: range::at(range, 4) = range::at(range, 0); Chris@16: } Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: struct segment_to_range Chris@16: { Chris@16: static inline void apply(Segment const& segment, Range& range) Chris@16: { Chris@16: traits::resize::apply(range, 2); Chris@16: Chris@16: typename boost::range_iterator::type it = boost::begin(range); Chris@16: Chris@16: assign_point_from_index<0>(segment, *it); Chris@16: ++it; Chris@16: assign_point_from_index<1>(segment, *it); Chris@16: } Chris@16: }; Chris@16: Chris@101: template Chris@16: < Chris@101: typename Range1, Chris@101: typename Range2, Chris@16: bool Reverse = false Chris@16: > Chris@16: struct range_to_range Chris@16: { Chris@16: typedef typename reversible_view Chris@16: < Chris@101: Range1 const, Chris@16: Reverse ? iterate_reverse : iterate_forward Chris@16: >::type rview_type; Chris@16: typedef typename closeable_view Chris@16: < Chris@101: rview_type const, Chris@16: geometry::closure::value Chris@16: >::type view_type; Chris@16: Chris@16: static inline void apply(Range1 const& source, Range2& destination) Chris@16: { Chris@16: geometry::clear(destination); Chris@16: Chris@16: rview_type rview(source); Chris@16: Chris@16: // We consider input always as closed, and skip last Chris@16: // point for open output. Chris@16: view_type view(rview); Chris@16: Chris@101: typedef typename boost::range_size::type size_type; Chris@101: size_type n = boost::size(view); Chris@16: if (geometry::closure::value == geometry::open) Chris@16: { Chris@16: n--; Chris@16: } Chris@16: Chris@101: // If size == 0 && geometry::open <=> n = numeric_limits::max() Chris@101: // but ok, sice below it == end() Chris@101: Chris@101: size_type i = 0; Chris@16: for (typename boost::range_iterator::type it Chris@16: = boost::begin(view); Chris@16: it != boost::end(view) && i < n; Chris@16: ++it, ++i) Chris@16: { Chris@16: geometry::append(destination, *it); Chris@16: } Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: struct polygon_to_polygon Chris@16: { Chris@16: typedef range_to_range Chris@16: < Chris@101: typename geometry::ring_type::type, Chris@16: typename geometry::ring_type::type, Chris@16: geometry::point_order::value Chris@16: != geometry::point_order::value Chris@16: > per_ring; Chris@16: Chris@16: static inline void apply(Polygon1 const& source, Polygon2& destination) Chris@16: { Chris@16: // Clearing managed per ring, and in the resizing of interior rings Chris@16: Chris@101: per_ring::apply(geometry::exterior_ring(source), Chris@16: geometry::exterior_ring(destination)); Chris@16: Chris@16: // Container should be resizeable 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(destination), num_interior_rings(source)); Chris@16: Chris@101: typename interior_return_type::type Chris@101: rings_source = interior_rings(source); Chris@101: typename interior_return_type::type Chris@101: rings_dest = interior_rings(destination); Chris@16: Chris@101: typename detail::interior_iterator::type Chris@101: it_source = boost::begin(rings_source); Chris@101: typename detail::interior_iterator::type Chris@101: it_dest = boost::begin(rings_dest); Chris@16: Chris@16: for ( ; it_source != boost::end(rings_source); ++it_source, ++it_dest) Chris@16: { Chris@16: per_ring::apply(*it_source, *it_dest); Chris@16: } Chris@16: } Chris@16: }; Chris@16: Chris@101: template Chris@101: struct single_to_multi: private Policy Chris@101: { Chris@101: static inline void apply(Single const& single, Multi& multi) Chris@101: { Chris@101: traits::resize::apply(multi, 1); Chris@101: Policy::apply(single, *boost::begin(multi)); Chris@101: } Chris@101: }; Chris@101: Chris@101: Chris@101: Chris@101: template Chris@101: struct multi_to_multi: private Policy Chris@101: { Chris@101: static inline void apply(Multi1 const& multi1, Multi2& multi2) 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: Policy::apply(*it1, *it2); Chris@101: } Chris@101: } Chris@101: }; Chris@101: Chris@16: Chris@16: }} // namespace detail::conversion 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: std::size_t DimensionCount = dimension::type::value, Chris@16: bool UseAssignment = boost::is_same::value Chris@16: && !boost::is_array::value Chris@16: > Chris@101: struct convert: not_implemented > Chris@16: {}; Chris@16: Chris@16: Chris@16: template Chris@16: < Chris@16: typename Geometry1, typename Geometry2, Chris@16: typename Tag, Chris@16: std::size_t DimensionCount Chris@16: > Chris@16: struct convert Chris@16: { Chris@16: // Same geometry type -> copy whole geometry Chris@16: static inline void apply(Geometry1 const& source, Geometry2& destination) Chris@16: { Chris@16: destination = source; Chris@16: } Chris@16: }; Chris@16: Chris@16: Chris@16: template Chris@16: < Chris@16: typename Geometry1, typename Geometry2, Chris@16: std::size_t DimensionCount Chris@16: > Chris@16: struct convert Chris@16: : detail::conversion::point_to_point Chris@16: {}; Chris@16: Chris@16: Chris@16: template Chris@16: < Chris@16: typename Box1, typename Box2, Chris@16: std::size_t DimensionCount Chris@16: > Chris@16: struct convert Chris@16: : detail::conversion::indexed_to_indexed Chris@16: {}; Chris@16: Chris@16: Chris@16: template Chris@16: < Chris@16: typename Segment1, typename Segment2, Chris@16: std::size_t DimensionCount Chris@16: > Chris@16: struct convert Chris@16: : detail::conversion::indexed_to_indexed Chris@16: {}; Chris@16: Chris@16: Chris@16: template Chris@16: struct convert Chris@16: : detail::conversion::segment_to_range Chris@16: {}; Chris@16: Chris@16: Chris@16: template Chris@16: struct convert Chris@16: : detail::conversion::range_to_range Chris@101: < Chris@101: Ring1, Chris@16: Ring2, Chris@16: geometry::point_order::value Chris@16: != geometry::point_order::value Chris@16: > Chris@16: {}; Chris@16: Chris@16: template Chris@16: struct convert Chris@16: : detail::conversion::range_to_range Chris@16: {}; Chris@16: Chris@16: template Chris@16: struct convert Chris@16: : detail::conversion::polygon_to_polygon Chris@16: {}; Chris@16: Chris@16: template Chris@16: struct convert Chris@16: : detail::conversion::box_to_range Chris@16: < Chris@101: Box, Chris@101: Ring, Chris@16: geometry::closure::value == closed, Chris@16: geometry::point_order::value == counterclockwise Chris@16: > Chris@16: {}; Chris@16: Chris@16: Chris@16: template Chris@16: struct convert Chris@16: { Chris@16: static inline void apply(Box const& box, Polygon& polygon) Chris@16: { Chris@16: typedef typename ring_type::type ring_type; Chris@16: Chris@16: convert Chris@16: < Chris@16: Box, ring_type, Chris@16: box_tag, ring_tag, Chris@16: 2, false Chris@16: >::apply(box, exterior_ring(polygon)); Chris@16: } Chris@16: }; Chris@16: Chris@16: Chris@16: template Chris@16: struct convert Chris@16: { Chris@16: static inline void apply(Point const& point, Box& box) Chris@16: { Chris@16: detail::conversion::point_to_box Chris@16: < Chris@16: Point, Box, min_corner, 0, DimensionCount Chris@16: >::apply(point, box); Chris@16: detail::conversion::point_to_box Chris@16: < Chris@16: Point, Box, max_corner, 0, DimensionCount Chris@16: >::apply(point, box); Chris@16: } Chris@16: }; Chris@16: Chris@16: Chris@16: template Chris@16: struct convert Chris@16: { Chris@16: static inline void apply(Ring const& ring, Polygon& polygon) Chris@16: { Chris@16: typedef typename ring_type::type ring_type; Chris@16: convert Chris@16: < Chris@16: Ring, ring_type, Chris@16: ring_tag, ring_tag, Chris@16: DimensionCount, false Chris@16: >::apply(ring, exterior_ring(polygon)); Chris@16: } Chris@16: }; Chris@16: Chris@16: Chris@16: template Chris@16: struct convert Chris@16: { Chris@16: static inline void apply(Polygon const& polygon, Ring& ring) Chris@16: { Chris@16: typedef typename ring_type::type ring_type; Chris@16: Chris@16: convert Chris@16: < Chris@16: ring_type, Ring, Chris@16: ring_tag, ring_tag, Chris@16: DimensionCount, false Chris@16: >::apply(exterior_ring(polygon), ring); Chris@16: } Chris@16: }; Chris@16: Chris@16: Chris@101: // Dispatch for multi <-> multi, specifying their single-version as policy. Chris@101: // Note that, even if the multi-types are mutually different, their single Chris@101: // version types might be the same and therefore we call boost::is_same again Chris@101: Chris@101: template Chris@101: struct convert Chris@101: : detail::conversion::multi_to_multi Chris@101: < Chris@101: Multi1, Chris@101: Multi2, Chris@101: convert Chris@101: < Chris@101: typename boost::range_value::type, Chris@101: typename boost::range_value::type, Chris@101: typename single_tag_of Chris@101: < Chris@101: typename tag::type Chris@101: >::type, Chris@101: typename single_tag_of Chris@101: < Chris@101: typename tag::type Chris@101: >::type, Chris@101: DimensionCount Chris@101: > Chris@101: > Chris@101: {}; Chris@101: Chris@101: Chris@101: template Chris@101: struct convert Chris@101: : detail::conversion::single_to_multi Chris@101: < Chris@101: Single, Chris@101: Multi, Chris@101: convert Chris@101: < Chris@101: Single, Chris@101: typename boost::range_value::type, Chris@101: typename tag::type, Chris@101: typename single_tag_of Chris@101: < Chris@101: typename tag::type Chris@101: >::type, Chris@101: DimensionCount, Chris@101: false Chris@101: > Chris@101: > Chris@101: {}; Chris@101: Chris@101: Chris@101: } // namespace dispatch Chris@101: #endif // DOXYGEN_NO_DISPATCH Chris@101: Chris@101: Chris@101: namespace resolve_variant { Chris@101: Chris@16: template Chris@101: struct convert Chris@16: { Chris@16: static inline void apply(Geometry1 const& geometry1, Geometry2& geometry2) Chris@16: { Chris@16: concept::check_concepts_and_equal_dimensions(); Chris@101: dispatch::convert::apply(geometry1, geometry2); Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@101: struct convert, Geometry2> Chris@16: { Chris@16: struct visitor: static_visitor Chris@16: { Chris@16: Geometry2& m_geometry2; Chris@16: Chris@16: visitor(Geometry2& geometry2) Chris@16: : m_geometry2(geometry2) Chris@16: {} Chris@16: Chris@16: template Chris@16: inline void operator()(Geometry1 const& geometry1) const Chris@16: { Chris@101: convert::apply(geometry1, m_geometry2); Chris@16: } Chris@16: }; Chris@16: Chris@16: static inline void apply( Chris@16: boost::variant const& geometry1, Chris@16: Geometry2& geometry2 Chris@16: ) Chris@16: { Chris@16: apply_visitor(visitor(geometry2), geometry1); Chris@16: } Chris@16: }; Chris@16: Chris@101: } Chris@16: Chris@16: Chris@16: /*! Chris@16: \brief Converts one geometry to another geometry Chris@16: \details The convert algorithm converts one geometry, e.g. a BOX, to another Chris@16: geometry, e.g. a RING. This only works if it is possible and applicable. Chris@101: If the point-order is different, or the closure is different between two Chris@101: geometry types, it will be converted correctly by explicitly reversing the Chris@16: points or closing or opening the polygon rings. Chris@16: \ingroup convert Chris@16: \tparam Geometry1 \tparam_geometry Chris@16: \tparam Geometry2 \tparam_geometry Chris@16: \param geometry1 \param_geometry (source) Chris@16: \param geometry2 \param_geometry (target) Chris@16: Chris@16: \qbk{[include reference/algorithms/convert.qbk]} Chris@16: */ Chris@16: template Chris@16: inline void convert(Geometry1 const& geometry1, Geometry2& geometry2) Chris@16: { Chris@101: resolve_variant::convert::apply(geometry1, geometry2); Chris@16: } Chris@16: Chris@16: #if defined(_MSC_VER) Chris@16: #pragma warning(pop) Chris@16: #endif Chris@16: Chris@16: }} // namespace boost::geometry Chris@16: Chris@16: #endif // BOOST_GEOMETRY_ALGORITHMS_CONVERT_HPP