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 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
9 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
11 // Use, modification and distribution is subject to the Boost Software License,
12 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
13 // http://www.boost.org/LICENSE_1_0.txt)
15 #ifndef BOOST_GEOMETRY_ALGORITHMS_CONVERT_HPP
16 #define BOOST_GEOMETRY_ALGORITHMS_CONVERT_HPP
21 #include <boost/numeric/conversion/cast.hpp>
22 #include <boost/range.hpp>
23 #include <boost/type_traits/is_array.hpp>
24 #include <boost/type_traits/remove_reference.hpp>
26 #include <boost/variant/apply_visitor.hpp>
27 #include <boost/variant/static_visitor.hpp>
28 #include <boost/variant/variant_fwd.hpp>
30 #include <boost/geometry/arithmetic/arithmetic.hpp>
31 #include <boost/geometry/algorithms/not_implemented.hpp>
32 #include <boost/geometry/algorithms/append.hpp>
33 #include <boost/geometry/algorithms/clear.hpp>
34 #include <boost/geometry/algorithms/for_each.hpp>
35 #include <boost/geometry/algorithms/detail/assign_values.hpp>
36 #include <boost/geometry/algorithms/detail/assign_box_corners.hpp>
37 #include <boost/geometry/algorithms/detail/assign_indexed_point.hpp>
38 #include <boost/geometry/algorithms/detail/convert_point_to_point.hpp>
39 #include <boost/geometry/algorithms/detail/convert_indexed_to_indexed.hpp>
40 #include <boost/geometry/algorithms/detail/interior_iterator.hpp>
42 #include <boost/geometry/views/closeable_view.hpp>
43 #include <boost/geometry/views/reversible_view.hpp>
45 #include <boost/geometry/util/range.hpp>
47 #include <boost/geometry/core/cs.hpp>
48 #include <boost/geometry/core/closure.hpp>
49 #include <boost/geometry/core/point_order.hpp>
50 #include <boost/geometry/core/tags.hpp>
52 #include <boost/geometry/geometries/concepts/check.hpp>
55 namespace boost { namespace geometry
58 // Silence warning C4127: conditional expression is constant
59 // Silence warning C4512: assignment operator could not be generated
62 #pragma warning(disable : 4127 4512)
66 #ifndef DOXYGEN_NO_DETAIL
67 namespace detail { namespace conversion
75 std::size_t Dimension,
76 std::size_t DimensionCount
80 static inline void apply(Point const& point, Box& box)
82 typedef typename coordinate_type<Box>::type coordinate_type;
84 set<Index, Dimension>(box,
85 boost::numeric_cast<coordinate_type>(get<Dimension>(point)));
89 Index, Dimension + 1, DimensionCount
100 std::size_t DimensionCount
102 struct point_to_box<Point, Box, Index, DimensionCount, DimensionCount>
104 static inline void apply(Point const& , Box& )
108 template <typename Box, typename Range, bool Close, bool Reverse>
111 static inline void apply(Box const& box, Range& range)
113 traits::resize<Range>::apply(range, Close ? 5 : 4);
114 assign_box_corners_oriented<Reverse>(box, range);
117 range::at(range, 4) = range::at(range, 0);
122 template <typename Segment, typename Range>
123 struct segment_to_range
125 static inline void apply(Segment const& segment, Range& range)
127 traits::resize<Range>::apply(range, 2);
129 typename boost::range_iterator<Range>::type it = boost::begin(range);
131 assign_point_from_index<0>(segment, *it);
133 assign_point_from_index<1>(segment, *it);
143 struct range_to_range
145 typedef typename reversible_view
148 Reverse ? iterate_reverse : iterate_forward
150 typedef typename closeable_view
153 geometry::closure<Range1>::value
156 static inline void apply(Range1 const& source, Range2& destination)
158 geometry::clear(destination);
160 rview_type rview(source);
162 // We consider input always as closed, and skip last
163 // point for open output.
164 view_type view(rview);
166 typedef typename boost::range_size<Range1>::type size_type;
167 size_type n = boost::size(view);
168 if (geometry::closure<Range2>::value == geometry::open)
173 // If size == 0 && geometry::open <=> n = numeric_limits<size_type>::max()
174 // but ok, sice below it == end()
177 for (typename boost::range_iterator<view_type const>::type it
178 = boost::begin(view);
179 it != boost::end(view) && i < n;
182 geometry::append(destination, *it);
187 template <typename Polygon1, typename Polygon2>
188 struct polygon_to_polygon
190 typedef range_to_range
192 typename geometry::ring_type<Polygon1>::type,
193 typename geometry::ring_type<Polygon2>::type,
194 geometry::point_order<Polygon1>::value
195 != geometry::point_order<Polygon2>::value
198 static inline void apply(Polygon1 const& source, Polygon2& destination)
200 // Clearing managed per ring, and in the resizing of interior rings
202 per_ring::apply(geometry::exterior_ring(source),
203 geometry::exterior_ring(destination));
205 // Container should be resizeable
208 typename boost::remove_reference
210 typename traits::interior_mutable_type<Polygon2>::type
212 >::apply(interior_rings(destination), num_interior_rings(source));
214 typename interior_return_type<Polygon1 const>::type
215 rings_source = interior_rings(source);
216 typename interior_return_type<Polygon2>::type
217 rings_dest = interior_rings(destination);
219 typename detail::interior_iterator<Polygon1 const>::type
220 it_source = boost::begin(rings_source);
221 typename detail::interior_iterator<Polygon2>::type
222 it_dest = boost::begin(rings_dest);
224 for ( ; it_source != boost::end(rings_source); ++it_source, ++it_dest)
226 per_ring::apply(*it_source, *it_dest);
231 template <typename Single, typename Multi, typename Policy>
232 struct single_to_multi: private Policy
234 static inline void apply(Single const& single, Multi& multi)
236 traits::resize<Multi>::apply(multi, 1);
237 Policy::apply(single, *boost::begin(multi));
243 template <typename Multi1, typename Multi2, typename Policy>
244 struct multi_to_multi: private Policy
246 static inline void apply(Multi1 const& multi1, Multi2& multi2)
248 traits::resize<Multi2>::apply(multi2, boost::size(multi1));
250 typename boost::range_iterator<Multi1 const>::type it1
251 = boost::begin(multi1);
252 typename boost::range_iterator<Multi2>::type it2
253 = boost::begin(multi2);
255 for (; it1 != boost::end(multi1); ++it1, ++it2)
257 Policy::apply(*it1, *it2);
263 }} // namespace detail::conversion
264 #endif // DOXYGEN_NO_DETAIL
267 #ifndef DOXYGEN_NO_DISPATCH
273 typename Geometry1, typename Geometry2,
274 typename Tag1 = typename tag_cast<typename tag<Geometry1>::type, multi_tag>::type,
275 typename Tag2 = typename tag_cast<typename tag<Geometry2>::type, multi_tag>::type,
276 std::size_t DimensionCount = dimension<Geometry1>::type::value,
277 bool UseAssignment = boost::is_same<Geometry1, Geometry2>::value
278 && !boost::is_array<Geometry1>::value
280 struct convert: not_implemented<Tag1, Tag2, boost::mpl::int_<DimensionCount> >
286 typename Geometry1, typename Geometry2,
288 std::size_t DimensionCount
290 struct convert<Geometry1, Geometry2, Tag, Tag, DimensionCount, true>
292 // Same geometry type -> copy whole geometry
293 static inline void apply(Geometry1 const& source, Geometry2& destination)
295 destination = source;
302 typename Geometry1, typename Geometry2,
303 std::size_t DimensionCount
305 struct convert<Geometry1, Geometry2, point_tag, point_tag, DimensionCount, false>
306 : detail::conversion::point_to_point<Geometry1, Geometry2, 0, DimensionCount>
312 typename Box1, typename Box2,
313 std::size_t DimensionCount
315 struct convert<Box1, Box2, box_tag, box_tag, DimensionCount, false>
316 : detail::conversion::indexed_to_indexed<Box1, Box2, 0, DimensionCount>
322 typename Segment1, typename Segment2,
323 std::size_t DimensionCount
325 struct convert<Segment1, Segment2, segment_tag, segment_tag, DimensionCount, false>
326 : detail::conversion::indexed_to_indexed<Segment1, Segment2, 0, DimensionCount>
330 template <typename Segment, typename LineString, std::size_t DimensionCount>
331 struct convert<Segment, LineString, segment_tag, linestring_tag, DimensionCount, false>
332 : detail::conversion::segment_to_range<Segment, LineString>
336 template <typename Ring1, typename Ring2, std::size_t DimensionCount>
337 struct convert<Ring1, Ring2, ring_tag, ring_tag, DimensionCount, false>
338 : detail::conversion::range_to_range
342 geometry::point_order<Ring1>::value
343 != geometry::point_order<Ring2>::value
347 template <typename LineString1, typename LineString2, std::size_t DimensionCount>
348 struct convert<LineString1, LineString2, linestring_tag, linestring_tag, DimensionCount, false>
349 : detail::conversion::range_to_range<LineString1, LineString2>
352 template <typename Polygon1, typename Polygon2, std::size_t DimensionCount>
353 struct convert<Polygon1, Polygon2, polygon_tag, polygon_tag, DimensionCount, false>
354 : detail::conversion::polygon_to_polygon<Polygon1, Polygon2>
357 template <typename Box, typename Ring>
358 struct convert<Box, Ring, box_tag, ring_tag, 2, false>
359 : detail::conversion::box_to_range
363 geometry::closure<Ring>::value == closed,
364 geometry::point_order<Ring>::value == counterclockwise
369 template <typename Box, typename Polygon>
370 struct convert<Box, Polygon, box_tag, polygon_tag, 2, false>
372 static inline void apply(Box const& box, Polygon& polygon)
374 typedef typename ring_type<Polygon>::type ring_type;
381 >::apply(box, exterior_ring(polygon));
386 template <typename Point, typename Box, std::size_t DimensionCount>
387 struct convert<Point, Box, point_tag, box_tag, DimensionCount, false>
389 static inline void apply(Point const& point, Box& box)
391 detail::conversion::point_to_box
393 Point, Box, min_corner, 0, DimensionCount
394 >::apply(point, box);
395 detail::conversion::point_to_box
397 Point, Box, max_corner, 0, DimensionCount
398 >::apply(point, box);
403 template <typename Ring, typename Polygon, std::size_t DimensionCount>
404 struct convert<Ring, Polygon, ring_tag, polygon_tag, DimensionCount, false>
406 static inline void apply(Ring const& ring, Polygon& polygon)
408 typedef typename ring_type<Polygon>::type ring_type;
413 DimensionCount, false
414 >::apply(ring, exterior_ring(polygon));
419 template <typename Polygon, typename Ring, std::size_t DimensionCount>
420 struct convert<Polygon, Ring, polygon_tag, ring_tag, DimensionCount, false>
422 static inline void apply(Polygon const& polygon, Ring& ring)
424 typedef typename ring_type<Polygon>::type ring_type;
430 DimensionCount, false
431 >::apply(exterior_ring(polygon), ring);
436 // Dispatch for multi <-> multi, specifying their single-version as policy.
437 // Note that, even if the multi-types are mutually different, their single
438 // version types might be the same and therefore we call boost::is_same again
440 template <typename Multi1, typename Multi2, std::size_t DimensionCount>
441 struct convert<Multi1, Multi2, multi_tag, multi_tag, DimensionCount, false>
442 : detail::conversion::multi_to_multi
448 typename boost::range_value<Multi1>::type,
449 typename boost::range_value<Multi2>::type,
450 typename single_tag_of
452 typename tag<Multi1>::type
454 typename single_tag_of
456 typename tag<Multi2>::type
464 template <typename Single, typename Multi, typename SingleTag, std::size_t DimensionCount>
465 struct convert<Single, Multi, SingleTag, multi_tag, DimensionCount, false>
466 : detail::conversion::single_to_multi
473 typename boost::range_value<Multi>::type,
474 typename tag<Single>::type,
475 typename single_tag_of
477 typename tag<Multi>::type
486 } // namespace dispatch
487 #endif // DOXYGEN_NO_DISPATCH
490 namespace resolve_variant {
492 template <typename Geometry1, typename Geometry2>
495 static inline void apply(Geometry1 const& geometry1, Geometry2& geometry2)
497 concepts::check_concepts_and_equal_dimensions<Geometry1 const, Geometry2>();
498 dispatch::convert<Geometry1, Geometry2>::apply(geometry1, geometry2);
502 template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
503 struct convert<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
505 struct visitor: static_visitor<void>
507 Geometry2& m_geometry2;
509 visitor(Geometry2& geometry2)
510 : m_geometry2(geometry2)
513 template <typename Geometry1>
514 inline void operator()(Geometry1 const& geometry1) const
516 convert<Geometry1, Geometry2>::apply(geometry1, m_geometry2);
520 static inline void apply(
521 boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
525 boost::apply_visitor(visitor(geometry2), geometry1);
533 \brief Converts one geometry to another geometry
534 \details The convert algorithm converts one geometry, e.g. a BOX, to another
535 geometry, e.g. a RING. This only works if it is possible and applicable.
536 If the point-order is different, or the closure is different between two
537 geometry types, it will be converted correctly by explicitly reversing the
538 points or closing or opening the polygon rings.
540 \tparam Geometry1 \tparam_geometry
541 \tparam Geometry2 \tparam_geometry
542 \param geometry1 \param_geometry (source)
543 \param geometry2 \param_geometry (target)
545 \qbk{[include reference/algorithms/convert.qbk]}
547 template <typename Geometry1, typename Geometry2>
548 inline void convert(Geometry1 const& geometry1, Geometry2& geometry2)
550 resolve_variant::convert<Geometry1, Geometry2>::apply(geometry1, geometry2);
553 #if defined(_MSC_VER)
557 }} // namespace boost::geometry
559 #endif // BOOST_GEOMETRY_ALGORITHMS_CONVERT_HPP