1 // Boost.Geometry (aka GGL, Generic Geometry Library)
3 // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
4 // Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
5 // Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
6 // Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
8 // This file was modified by Oracle on 2017-2020.
9 // Modifications copyright (c) 2017-2020, Oracle and/or its affiliates.
10 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
12 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
13 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
15 // Use, modification and distribution is subject to the Boost Software License,
16 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
17 // http://www.boost.org/LICENSE_1_0.txt)
19 #ifndef BOOST_GEOMETRY_ALGORITHMS_CONVERT_HPP
20 #define BOOST_GEOMETRY_ALGORITHMS_CONVERT_HPP
24 #include <type_traits>
26 #include <boost/numeric/conversion/cast.hpp>
27 #include <boost/range/begin.hpp>
28 #include <boost/range/end.hpp>
29 #include <boost/range/size.hpp>
30 #include <boost/range/value_type.hpp>
31 #include <boost/variant/apply_visitor.hpp>
32 #include <boost/variant/static_visitor.hpp>
33 #include <boost/variant/variant_fwd.hpp>
35 #include <boost/geometry/arithmetic/arithmetic.hpp>
36 #include <boost/geometry/algorithms/not_implemented.hpp>
37 #include <boost/geometry/algorithms/clear.hpp>
38 #include <boost/geometry/algorithms/detail/assign_box_corners.hpp>
39 #include <boost/geometry/algorithms/detail/assign_indexed_point.hpp>
40 #include <boost/geometry/algorithms/detail/convert_point_to_point.hpp>
41 #include <boost/geometry/algorithms/detail/convert_indexed_to_indexed.hpp>
42 #include <boost/geometry/algorithms/detail/interior_iterator.hpp>
44 #include <boost/geometry/views/closeable_view.hpp>
45 #include <boost/geometry/views/reversible_view.hpp>
47 #include <boost/geometry/util/range.hpp>
49 #include <boost/geometry/core/cs.hpp>
50 #include <boost/geometry/core/closure.hpp>
51 #include <boost/geometry/core/point_order.hpp>
52 #include <boost/geometry/core/tags.hpp>
54 #include <boost/geometry/geometries/concepts/check.hpp>
57 namespace boost { namespace geometry
60 // Silence warning C4127: conditional expression is constant
61 // Silence warning C4512: assignment operator could not be generated
64 #pragma warning(disable : 4127 4512)
68 #ifndef DOXYGEN_NO_DETAIL
69 namespace detail { namespace conversion
77 std::size_t Dimension,
78 std::size_t DimensionCount
82 static inline void apply(Point const& point, Box& box)
84 typedef typename coordinate_type<Box>::type coordinate_type;
86 set<Index, Dimension>(box,
87 boost::numeric_cast<coordinate_type>(get<Dimension>(point)));
91 Index, Dimension + 1, DimensionCount
102 std::size_t DimensionCount
104 struct point_to_box<Point, Box, Index, DimensionCount, DimensionCount>
106 static inline void apply(Point const& , Box& )
110 template <typename Box, typename Range, bool Close, bool Reverse>
113 static inline void apply(Box const& box, Range& range)
115 traits::resize<Range>::apply(range, Close ? 5 : 4);
116 assign_box_corners_oriented<Reverse>(box, range);
119 range::at(range, 4) = range::at(range, 0);
124 template <typename Segment, typename Range>
125 struct segment_to_range
127 static inline void apply(Segment const& segment, Range& range)
129 traits::resize<Range>::apply(range, 2);
131 typename boost::range_iterator<Range>::type it = boost::begin(range);
133 assign_point_from_index<0>(segment, *it);
135 assign_point_from_index<1>(segment, *it);
145 struct range_to_range
147 typedef typename reversible_view
150 Reverse ? iterate_reverse : iterate_forward
152 typedef typename closeable_view
155 geometry::closure<Range1>::value
158 struct default_policy
160 template <typename Point1, typename Point2>
161 static inline void apply(Point1 const& point1, Point2 & point2)
163 geometry::detail::conversion::convert_point_to_point(point1, point2);
167 static inline void apply(Range1 const& source, Range2& destination)
169 apply(source, destination, default_policy());
172 template <typename ConvertPointPolicy>
173 static inline ConvertPointPolicy apply(Range1 const& source, Range2& destination,
174 ConvertPointPolicy convert_point)
176 geometry::clear(destination);
178 rview_type rview(source);
180 // We consider input always as closed, and skip last
181 // point for open output.
182 view_type view(rview);
184 typedef typename boost::range_size<Range1>::type size_type;
185 size_type n = boost::size(view);
186 if (geometry::closure<Range2>::value == geometry::open)
191 // If size == 0 && geometry::open <=> n = numeric_limits<size_type>::max()
192 // but ok, sice below it == end()
195 for (typename boost::range_iterator<view_type const>::type it
196 = boost::begin(view);
197 it != boost::end(view) && i < n;
200 typename boost::range_value<Range2>::type point;
201 convert_point.apply(*it, point);
202 range::push_back(destination, point);
205 return convert_point;
209 template <typename Polygon1, typename Polygon2>
210 struct polygon_to_polygon
212 typedef range_to_range
214 typename geometry::ring_type<Polygon1>::type,
215 typename geometry::ring_type<Polygon2>::type,
216 geometry::point_order<Polygon1>::value
217 != geometry::point_order<Polygon2>::value
220 static inline void apply(Polygon1 const& source, Polygon2& destination)
222 // Clearing managed per ring, and in the resizing of interior rings
224 per_ring::apply(geometry::exterior_ring(source),
225 geometry::exterior_ring(destination));
227 // Container should be resizeable
230 typename std::remove_reference
232 typename traits::interior_mutable_type<Polygon2>::type
234 >::apply(interior_rings(destination), num_interior_rings(source));
236 typename interior_return_type<Polygon1 const>::type
237 rings_source = interior_rings(source);
238 typename interior_return_type<Polygon2>::type
239 rings_dest = interior_rings(destination);
241 typename detail::interior_iterator<Polygon1 const>::type
242 it_source = boost::begin(rings_source);
243 typename detail::interior_iterator<Polygon2>::type
244 it_dest = boost::begin(rings_dest);
246 for ( ; it_source != boost::end(rings_source); ++it_source, ++it_dest)
248 per_ring::apply(*it_source, *it_dest);
253 template <typename Single, typename Multi, typename Policy>
254 struct single_to_multi: private Policy
256 static inline void apply(Single const& single, Multi& multi)
258 traits::resize<Multi>::apply(multi, 1);
259 Policy::apply(single, *boost::begin(multi));
265 template <typename Multi1, typename Multi2, typename Policy>
266 struct multi_to_multi: private Policy
268 static inline void apply(Multi1 const& multi1, Multi2& multi2)
270 traits::resize<Multi2>::apply(multi2, boost::size(multi1));
272 typename boost::range_iterator<Multi1 const>::type it1
273 = boost::begin(multi1);
274 typename boost::range_iterator<Multi2>::type it2
275 = boost::begin(multi2);
277 for (; it1 != boost::end(multi1); ++it1, ++it2)
279 Policy::apply(*it1, *it2);
285 }} // namespace detail::conversion
286 #endif // DOXYGEN_NO_DETAIL
289 #ifndef DOXYGEN_NO_DISPATCH
295 typename Geometry1, typename Geometry2,
296 typename Tag1 = typename tag_cast<typename tag<Geometry1>::type, multi_tag>::type,
297 typename Tag2 = typename tag_cast<typename tag<Geometry2>::type, multi_tag>::type,
298 std::size_t DimensionCount = dimension<Geometry1>::type::value,
299 bool UseAssignment = std::is_same<Geometry1, Geometry2>::value
300 && !std::is_array<Geometry1>::value
306 std::integral_constant<std::size_t, DimensionCount>
313 typename Geometry1, typename Geometry2,
315 std::size_t DimensionCount
317 struct convert<Geometry1, Geometry2, Tag, Tag, DimensionCount, true>
319 // Same geometry type -> copy whole geometry
320 static inline void apply(Geometry1 const& source, Geometry2& destination)
322 destination = source;
329 typename Geometry1, typename Geometry2,
330 std::size_t DimensionCount
332 struct convert<Geometry1, Geometry2, point_tag, point_tag, DimensionCount, false>
333 : detail::conversion::point_to_point<Geometry1, Geometry2, 0, DimensionCount>
339 typename Box1, typename Box2,
340 std::size_t DimensionCount
342 struct convert<Box1, Box2, box_tag, box_tag, DimensionCount, false>
343 : detail::conversion::indexed_to_indexed<Box1, Box2, 0, DimensionCount>
349 typename Segment1, typename Segment2,
350 std::size_t DimensionCount
352 struct convert<Segment1, Segment2, segment_tag, segment_tag, DimensionCount, false>
353 : detail::conversion::indexed_to_indexed<Segment1, Segment2, 0, DimensionCount>
357 template <typename Segment, typename LineString, std::size_t DimensionCount>
358 struct convert<Segment, LineString, segment_tag, linestring_tag, DimensionCount, false>
359 : detail::conversion::segment_to_range<Segment, LineString>
363 template <typename Ring1, typename Ring2, std::size_t DimensionCount>
364 struct convert<Ring1, Ring2, ring_tag, ring_tag, DimensionCount, false>
365 : detail::conversion::range_to_range
369 geometry::point_order<Ring1>::value
370 != geometry::point_order<Ring2>::value
374 template <typename LineString1, typename LineString2, std::size_t DimensionCount>
375 struct convert<LineString1, LineString2, linestring_tag, linestring_tag, DimensionCount, false>
376 : detail::conversion::range_to_range<LineString1, LineString2>
379 template <typename Polygon1, typename Polygon2, std::size_t DimensionCount>
380 struct convert<Polygon1, Polygon2, polygon_tag, polygon_tag, DimensionCount, false>
381 : detail::conversion::polygon_to_polygon<Polygon1, Polygon2>
384 template <typename Box, typename Ring>
385 struct convert<Box, Ring, box_tag, ring_tag, 2, false>
386 : detail::conversion::box_to_range
390 geometry::closure<Ring>::value == closed,
391 geometry::point_order<Ring>::value == counterclockwise
396 template <typename Box, typename Polygon>
397 struct convert<Box, Polygon, box_tag, polygon_tag, 2, false>
399 static inline void apply(Box const& box, Polygon& polygon)
401 typedef typename ring_type<Polygon>::type ring_type;
408 >::apply(box, exterior_ring(polygon));
413 template <typename Point, typename Box, std::size_t DimensionCount>
414 struct convert<Point, Box, point_tag, box_tag, DimensionCount, false>
416 static inline void apply(Point const& point, Box& box)
418 detail::conversion::point_to_box
420 Point, Box, min_corner, 0, DimensionCount
421 >::apply(point, box);
422 detail::conversion::point_to_box
424 Point, Box, max_corner, 0, DimensionCount
425 >::apply(point, box);
430 template <typename Ring, typename Polygon, std::size_t DimensionCount>
431 struct convert<Ring, Polygon, ring_tag, polygon_tag, DimensionCount, false>
433 static inline void apply(Ring const& ring, Polygon& polygon)
435 typedef typename ring_type<Polygon>::type ring_type;
440 DimensionCount, false
441 >::apply(ring, exterior_ring(polygon));
446 template <typename Polygon, typename Ring, std::size_t DimensionCount>
447 struct convert<Polygon, Ring, polygon_tag, ring_tag, DimensionCount, false>
449 static inline void apply(Polygon const& polygon, Ring& ring)
451 typedef typename ring_type<Polygon>::type ring_type;
457 DimensionCount, false
458 >::apply(exterior_ring(polygon), ring);
463 // Dispatch for multi <-> multi, specifying their single-version as policy.
464 // Note that, even if the multi-types are mutually different, their single
465 // version types might be the same and therefore we call std::is_same again
467 template <typename Multi1, typename Multi2, std::size_t DimensionCount>
468 struct convert<Multi1, Multi2, multi_tag, multi_tag, DimensionCount, false>
469 : detail::conversion::multi_to_multi
475 typename boost::range_value<Multi1>::type,
476 typename boost::range_value<Multi2>::type,
477 typename single_tag_of
479 typename tag<Multi1>::type
481 typename single_tag_of
483 typename tag<Multi2>::type
491 template <typename Single, typename Multi, typename SingleTag, std::size_t DimensionCount>
492 struct convert<Single, Multi, SingleTag, multi_tag, DimensionCount, false>
493 : detail::conversion::single_to_multi
500 typename boost::range_value<Multi>::type,
501 typename tag<Single>::type,
502 typename single_tag_of
504 typename tag<Multi>::type
513 } // namespace dispatch
514 #endif // DOXYGEN_NO_DISPATCH
517 namespace resolve_variant {
519 template <typename Geometry1, typename Geometry2>
522 static inline void apply(Geometry1 const& geometry1, Geometry2& geometry2)
524 concepts::check_concepts_and_equal_dimensions<Geometry1 const, Geometry2>();
525 dispatch::convert<Geometry1, Geometry2>::apply(geometry1, geometry2);
529 template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
530 struct convert<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
532 struct visitor: static_visitor<void>
534 Geometry2& m_geometry2;
536 visitor(Geometry2& geometry2)
537 : m_geometry2(geometry2)
540 template <typename Geometry1>
541 inline void operator()(Geometry1 const& geometry1) const
543 convert<Geometry1, Geometry2>::apply(geometry1, m_geometry2);
547 static inline void apply(
548 boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
552 boost::apply_visitor(visitor(geometry2), geometry1);
560 \brief Converts one geometry to another geometry
561 \details The convert algorithm converts one geometry, e.g. a BOX, to another
562 geometry, e.g. a RING. This only works if it is possible and applicable.
563 If the point-order is different, or the closure is different between two
564 geometry types, it will be converted correctly by explicitly reversing the
565 points or closing or opening the polygon rings.
567 \tparam Geometry1 \tparam_geometry
568 \tparam Geometry2 \tparam_geometry
569 \param geometry1 \param_geometry (source)
570 \param geometry2 \param_geometry (target)
572 \qbk{[include reference/algorithms/convert.qbk]}
574 template <typename Geometry1, typename Geometry2>
575 inline void convert(Geometry1 const& geometry1, Geometry2& geometry2)
577 resolve_variant::convert<Geometry1, Geometry2>::apply(geometry1, geometry2);
580 #if defined(_MSC_VER)
584 }} // namespace boost::geometry
586 #endif // BOOST_GEOMETRY_ALGORITHMS_CONVERT_HPP