1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2 
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.
7 
8 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
9 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
10 
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)
14 
15 #ifndef BOOST_GEOMETRY_ALGORITHMS_CONVERT_HPP
16 #define BOOST_GEOMETRY_ALGORITHMS_CONVERT_HPP
17 
18 
19 #include <cstddef>
20 
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>
25 
26 #include <boost/variant/apply_visitor.hpp>
27 #include <boost/variant/static_visitor.hpp>
28 #include <boost/variant/variant_fwd.hpp>
29 
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>
41 
42 #include <boost/geometry/views/closeable_view.hpp>
43 #include <boost/geometry/views/reversible_view.hpp>
44 
45 #include <boost/geometry/util/range.hpp>
46 
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>
51 
52 #include <boost/geometry/geometries/concepts/check.hpp>
53 
54 
55 namespace boost { namespace geometry
56 {
57 
58 // Silence warning C4127: conditional expression is constant
59 // Silence warning C4512: assignment operator could not be generated
60 #if defined(_MSC_VER)
61 #pragma warning(push)
62 #pragma warning(disable : 4127 4512)
63 #endif
64 
65 
66 #ifndef DOXYGEN_NO_DETAIL
67 namespace detail { namespace conversion
68 {
69 
70 template
71 <
72     typename Point,
73     typename Box,
74     std::size_t Index,
75     std::size_t Dimension,
76     std::size_t DimensionCount
77 >
78 struct point_to_box
79 {
applyboost::geometry::detail::conversion::point_to_box80     static inline void apply(Point const& point, Box& box)
81     {
82         typedef typename coordinate_type<Box>::type coordinate_type;
83 
84         set<Index, Dimension>(box,
85                 boost::numeric_cast<coordinate_type>(get<Dimension>(point)));
86         point_to_box
87             <
88                 Point, Box,
89                 Index, Dimension + 1, DimensionCount
90             >::apply(point, box);
91     }
92 };
93 
94 
95 template
96 <
97     typename Point,
98     typename Box,
99     std::size_t Index,
100     std::size_t DimensionCount
101 >
102 struct point_to_box<Point, Box, Index, DimensionCount, DimensionCount>
103 {
applyboost::geometry::detail::conversion::point_to_box104     static inline void apply(Point const& , Box& )
105     {}
106 };
107 
108 template <typename Box, typename Range, bool Close, bool Reverse>
109 struct box_to_range
110 {
applyboost::geometry::detail::conversion::box_to_range111     static inline void apply(Box const& box, Range& range)
112     {
113         traits::resize<Range>::apply(range, Close ? 5 : 4);
114         assign_box_corners_oriented<Reverse>(box, range);
115         if (Close)
116         {
117             range::at(range, 4) = range::at(range, 0);
118         }
119     }
120 };
121 
122 template <typename Segment, typename Range>
123 struct segment_to_range
124 {
applyboost::geometry::detail::conversion::segment_to_range125     static inline void apply(Segment const& segment, Range& range)
126     {
127         traits::resize<Range>::apply(range, 2);
128 
129         typename boost::range_iterator<Range>::type it = boost::begin(range);
130 
131         assign_point_from_index<0>(segment, *it);
132         ++it;
133         assign_point_from_index<1>(segment, *it);
134     }
135 };
136 
137 template
138 <
139     typename Range1,
140     typename Range2,
141     bool Reverse = false
142 >
143 struct range_to_range
144 {
145     typedef typename reversible_view
146         <
147             Range1 const,
148             Reverse ? iterate_reverse : iterate_forward
149         >::type rview_type;
150     typedef typename closeable_view
151         <
152             rview_type const,
153             geometry::closure<Range1>::value
154         >::type view_type;
155 
applyboost::geometry::detail::conversion::range_to_range156     static inline void apply(Range1 const& source, Range2& destination)
157     {
158         geometry::clear(destination);
159 
160         rview_type rview(source);
161 
162         // We consider input always as closed, and skip last
163         // point for open output.
164         view_type view(rview);
165 
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)
169         {
170             n--;
171         }
172 
173         // If size == 0 && geometry::open <=> n = numeric_limits<size_type>::max()
174         // but ok, sice below it == end()
175 
176         size_type i = 0;
177         for (typename boost::range_iterator<view_type const>::type it
178             = boost::begin(view);
179             it != boost::end(view) && i < n;
180             ++it, ++i)
181         {
182             geometry::append(destination, *it);
183         }
184     }
185 };
186 
187 template <typename Polygon1, typename Polygon2>
188 struct polygon_to_polygon
189 {
190     typedef range_to_range
191         <
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
196         > per_ring;
197 
applyboost::geometry::detail::conversion::polygon_to_polygon198     static inline void apply(Polygon1 const& source, Polygon2& destination)
199     {
200         // Clearing managed per ring, and in the resizing of interior rings
201 
202         per_ring::apply(geometry::exterior_ring(source),
203             geometry::exterior_ring(destination));
204 
205         // Container should be resizeable
206         traits::resize
207             <
208                 typename boost::remove_reference
209                 <
210                     typename traits::interior_mutable_type<Polygon2>::type
211                 >::type
212             >::apply(interior_rings(destination), num_interior_rings(source));
213 
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);
218 
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);
223 
224         for ( ; it_source != boost::end(rings_source); ++it_source, ++it_dest)
225         {
226             per_ring::apply(*it_source, *it_dest);
227         }
228     }
229 };
230 
231 template <typename Single, typename Multi, typename Policy>
232 struct single_to_multi: private Policy
233 {
applyboost::geometry::detail::conversion::single_to_multi234     static inline void apply(Single const& single, Multi& multi)
235     {
236         traits::resize<Multi>::apply(multi, 1);
237         Policy::apply(single, *boost::begin(multi));
238     }
239 };
240 
241 
242 
243 template <typename Multi1, typename Multi2, typename Policy>
244 struct multi_to_multi: private Policy
245 {
applyboost::geometry::detail::conversion::multi_to_multi246     static inline void apply(Multi1 const& multi1, Multi2& multi2)
247     {
248         traits::resize<Multi2>::apply(multi2, boost::size(multi1));
249 
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);
254 
255         for (; it1 != boost::end(multi1); ++it1, ++it2)
256         {
257             Policy::apply(*it1, *it2);
258         }
259     }
260 };
261 
262 
263 }} // namespace detail::conversion
264 #endif // DOXYGEN_NO_DETAIL
265 
266 
267 #ifndef DOXYGEN_NO_DISPATCH
268 namespace dispatch
269 {
270 
271 template
272 <
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
279 >
280 struct convert: not_implemented<Tag1, Tag2, boost::mpl::int_<DimensionCount> >
281 {};
282 
283 
284 template
285 <
286     typename Geometry1, typename Geometry2,
287     typename Tag,
288     std::size_t DimensionCount
289 >
290 struct convert<Geometry1, Geometry2, Tag, Tag, DimensionCount, true>
291 {
292     // Same geometry type -> copy whole geometry
applyboost::geometry::dispatch::convert293     static inline void apply(Geometry1 const& source, Geometry2& destination)
294     {
295         destination = source;
296     }
297 };
298 
299 
300 template
301 <
302     typename Geometry1, typename Geometry2,
303     std::size_t DimensionCount
304 >
305 struct convert<Geometry1, Geometry2, point_tag, point_tag, DimensionCount, false>
306     : detail::conversion::point_to_point<Geometry1, Geometry2, 0, DimensionCount>
307 {};
308 
309 
310 template
311 <
312     typename Box1, typename Box2,
313     std::size_t DimensionCount
314 >
315 struct convert<Box1, Box2, box_tag, box_tag, DimensionCount, false>
316     : detail::conversion::indexed_to_indexed<Box1, Box2, 0, DimensionCount>
317 {};
318 
319 
320 template
321 <
322     typename Segment1, typename Segment2,
323     std::size_t DimensionCount
324 >
325 struct convert<Segment1, Segment2, segment_tag, segment_tag, DimensionCount, false>
326     : detail::conversion::indexed_to_indexed<Segment1, Segment2, 0, DimensionCount>
327 {};
328 
329 
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>
333 {};
334 
335 
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
339         <
340             Ring1,
341             Ring2,
342             geometry::point_order<Ring1>::value
343                 != geometry::point_order<Ring2>::value
344         >
345 {};
346 
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>
350 {};
351 
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>
355 {};
356 
357 template <typename Box, typename Ring>
358 struct convert<Box, Ring, box_tag, ring_tag, 2, false>
359     : detail::conversion::box_to_range
360         <
361             Box,
362             Ring,
363             geometry::closure<Ring>::value == closed,
364             geometry::point_order<Ring>::value == counterclockwise
365         >
366 {};
367 
368 
369 template <typename Box, typename Polygon>
370 struct convert<Box, Polygon, box_tag, polygon_tag, 2, false>
371 {
applyboost::geometry::dispatch::convert372     static inline void apply(Box const& box, Polygon& polygon)
373     {
374         typedef typename ring_type<Polygon>::type ring_type;
375 
376         convert
377             <
378                 Box, ring_type,
379                 box_tag, ring_tag,
380                 2, false
381             >::apply(box, exterior_ring(polygon));
382     }
383 };
384 
385 
386 template <typename Point, typename Box, std::size_t DimensionCount>
387 struct convert<Point, Box, point_tag, box_tag, DimensionCount, false>
388 {
applyboost::geometry::dispatch::convert389     static inline void apply(Point const& point, Box& box)
390     {
391         detail::conversion::point_to_box
392             <
393                 Point, Box, min_corner, 0, DimensionCount
394             >::apply(point, box);
395         detail::conversion::point_to_box
396             <
397                 Point, Box, max_corner, 0, DimensionCount
398             >::apply(point, box);
399     }
400 };
401 
402 
403 template <typename Ring, typename Polygon, std::size_t DimensionCount>
404 struct convert<Ring, Polygon, ring_tag, polygon_tag, DimensionCount, false>
405 {
applyboost::geometry::dispatch::convert406     static inline void apply(Ring const& ring, Polygon& polygon)
407     {
408         typedef typename ring_type<Polygon>::type ring_type;
409         convert
410             <
411                 Ring, ring_type,
412                 ring_tag, ring_tag,
413                 DimensionCount, false
414             >::apply(ring, exterior_ring(polygon));
415     }
416 };
417 
418 
419 template <typename Polygon, typename Ring, std::size_t DimensionCount>
420 struct convert<Polygon, Ring, polygon_tag, ring_tag, DimensionCount, false>
421 {
applyboost::geometry::dispatch::convert422     static inline void apply(Polygon const& polygon, Ring& ring)
423     {
424         typedef typename ring_type<Polygon>::type ring_type;
425 
426         convert
427             <
428                 ring_type, Ring,
429                 ring_tag, ring_tag,
430                 DimensionCount, false
431             >::apply(exterior_ring(polygon), ring);
432     }
433 };
434 
435 
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
439 
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
443         <
444             Multi1,
445             Multi2,
446             convert
447                 <
448                     typename boost::range_value<Multi1>::type,
449                     typename boost::range_value<Multi2>::type,
450                     typename single_tag_of
451                                 <
452                                     typename tag<Multi1>::type
453                                 >::type,
454                     typename single_tag_of
455                                 <
456                                     typename tag<Multi2>::type
457                                 >::type,
458                     DimensionCount
459                 >
460         >
461 {};
462 
463 
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
467         <
468             Single,
469             Multi,
470             convert
471                 <
472                     Single,
473                     typename boost::range_value<Multi>::type,
474                     typename tag<Single>::type,
475                     typename single_tag_of
476                                 <
477                                     typename tag<Multi>::type
478                                 >::type,
479                     DimensionCount,
480                     false
481                 >
482         >
483 {};
484 
485 
486 } // namespace dispatch
487 #endif // DOXYGEN_NO_DISPATCH
488 
489 
490 namespace resolve_variant {
491 
492 template <typename Geometry1, typename Geometry2>
493 struct convert
494 {
applyboost::geometry::resolve_variant::convert495     static inline void apply(Geometry1 const& geometry1, Geometry2& geometry2)
496     {
497         concepts::check_concepts_and_equal_dimensions<Geometry1 const, Geometry2>();
498         dispatch::convert<Geometry1, Geometry2>::apply(geometry1, geometry2);
499     }
500 };
501 
502 template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
503 struct convert<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
504 {
505     struct visitor: static_visitor<void>
506     {
507         Geometry2& m_geometry2;
508 
visitorboost::geometry::resolve_variant::convert::visitor509         visitor(Geometry2& geometry2)
510             : m_geometry2(geometry2)
511         {}
512 
513         template <typename Geometry1>
operator ()boost::geometry::resolve_variant::convert::visitor514         inline void operator()(Geometry1 const& geometry1) const
515         {
516             convert<Geometry1, Geometry2>::apply(geometry1, m_geometry2);
517         }
518     };
519 
applyboost::geometry::resolve_variant::convert520     static inline void apply(
521         boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
522         Geometry2& geometry2
523     )
524     {
525         boost::apply_visitor(visitor(geometry2), geometry1);
526     }
527 };
528 
529 }
530 
531 
532 /*!
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.
539 \ingroup convert
540 \tparam Geometry1 \tparam_geometry
541 \tparam Geometry2 \tparam_geometry
542 \param geometry1 \param_geometry (source)
543 \param geometry2 \param_geometry (target)
544 
545 \qbk{[include reference/algorithms/convert.qbk]}
546  */
547 template <typename Geometry1, typename Geometry2>
convert(Geometry1 const & geometry1,Geometry2 & geometry2)548 inline void convert(Geometry1 const& geometry1, Geometry2& geometry2)
549 {
550     resolve_variant::convert<Geometry1, Geometry2>::apply(geometry1, geometry2);
551 }
552 
553 #if defined(_MSC_VER)
554 #pragma warning(pop)
555 #endif
556 
557 }} // namespace boost::geometry
558 
559 #endif // BOOST_GEOMETRY_ALGORITHMS_CONVERT_HPP
560