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
55namespace 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
67namespace detail { namespace conversion
68{
69
70template
71<
72 typename Point,
73 typename Box,
74 std::size_t Index,
75 std::size_t Dimension,
76 std::size_t DimensionCount
77>
78struct point_to_box
79{
80 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
95template
96<
97 typename Point,
98 typename Box,
99 std::size_t Index,
100 std::size_t DimensionCount
101>
102struct point_to_box<Point, Box, Index, DimensionCount, DimensionCount>
103{
104 static inline void apply(Point const& , Box& )
105 {}
106};
107
108template <typename Box, typename Range, bool Close, bool Reverse>
109struct box_to_range
110{
111 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
122template <typename Segment, typename Range>
123struct segment_to_range
124{
125 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
137template
138<
139 typename Range1,
140 typename Range2,
141 bool Reverse = false
142>
143struct 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
156 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
187template <typename Polygon1, typename Polygon2>
188struct 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
198 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
231template <typename Single, typename Multi, typename Policy>
232struct single_to_multi: private Policy
233{
234 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
243template <typename Multi1, typename Multi2, typename Policy>
244struct multi_to_multi: private Policy
245{
246 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
268namespace dispatch
269{
270
271template
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>
280struct convert: not_implemented<Tag1, Tag2, boost::mpl::int_<DimensionCount> >
281{};
282
283
284template
285<
286 typename Geometry1, typename Geometry2,
287 typename Tag,
288 std::size_t DimensionCount
289>
290struct convert<Geometry1, Geometry2, Tag, Tag, DimensionCount, true>
291{
292 // Same geometry type -> copy whole geometry
293 static inline void apply(Geometry1 const& source, Geometry2& destination)
294 {
295 destination = source;
296 }
297};
298
299
300template
301<
302 typename Geometry1, typename Geometry2,
303 std::size_t DimensionCount
304>
305struct convert<Geometry1, Geometry2, point_tag, point_tag, DimensionCount, false>
306 : detail::conversion::point_to_point<Geometry1, Geometry2, 0, DimensionCount>
307{};
308
309
310template
311<
312 typename Box1, typename Box2,
313 std::size_t DimensionCount
314>
315struct convert<Box1, Box2, box_tag, box_tag, DimensionCount, false>
316 : detail::conversion::indexed_to_indexed<Box1, Box2, 0, DimensionCount>
317{};
318
319
320template
321<
322 typename Segment1, typename Segment2,
323 std::size_t DimensionCount
324>
325struct convert<Segment1, Segment2, segment_tag, segment_tag, DimensionCount, false>
326 : detail::conversion::indexed_to_indexed<Segment1, Segment2, 0, DimensionCount>
327{};
328
329
330template <typename Segment, typename LineString, std::size_t DimensionCount>
331struct convert<Segment, LineString, segment_tag, linestring_tag, DimensionCount, false>
332 : detail::conversion::segment_to_range<Segment, LineString>
333{};
334
335
336template <typename Ring1, typename Ring2, std::size_t DimensionCount>
337struct 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
347template <typename LineString1, typename LineString2, std::size_t DimensionCount>
348struct convert<LineString1, LineString2, linestring_tag, linestring_tag, DimensionCount, false>
349 : detail::conversion::range_to_range<LineString1, LineString2>
350{};
351
352template <typename Polygon1, typename Polygon2, std::size_t DimensionCount>
353struct convert<Polygon1, Polygon2, polygon_tag, polygon_tag, DimensionCount, false>
354 : detail::conversion::polygon_to_polygon<Polygon1, Polygon2>
355{};
356
357template <typename Box, typename Ring>
358struct 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
369template <typename Box, typename Polygon>
370struct convert<Box, Polygon, box_tag, polygon_tag, 2, false>
371{
372 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
386template <typename Point, typename Box, std::size_t DimensionCount>
387struct convert<Point, Box, point_tag, box_tag, DimensionCount, false>
388{
389 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
403template <typename Ring, typename Polygon, std::size_t DimensionCount>
404struct convert<Ring, Polygon, ring_tag, polygon_tag, DimensionCount, false>
405{
406 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
419template <typename Polygon, typename Ring, std::size_t DimensionCount>
420struct convert<Polygon, Ring, polygon_tag, ring_tag, DimensionCount, false>
421{
422 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
440template <typename Multi1, typename Multi2, std::size_t DimensionCount>
441struct 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
464template <typename Single, typename Multi, typename SingleTag, std::size_t DimensionCount>
465struct 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
490namespace resolve_variant {
491
492template <typename Geometry1, typename Geometry2>
493struct convert
494{
495 static inline void apply(Geometry1 const& geometry1, Geometry2& geometry2)
496 {
497 concept::check_concepts_and_equal_dimensions<Geometry1 const, Geometry2>();
498 dispatch::convert<Geometry1, Geometry2>::apply(geometry1, geometry2);
499 }
500};
501
502template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
503struct convert<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
504{
505 struct visitor: static_visitor<void>
506 {
507 Geometry2& m_geometry2;
508
509 visitor(Geometry2& geometry2)
510 : m_geometry2(geometry2)
511 {}
512
513 template <typename Geometry1>
514 inline void operator()(Geometry1 const& geometry1) const
515 {
516 convert<Geometry1, Geometry2>::apply(geometry1, m_geometry2);
517 }
518 };
519
520 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
535geometry, e.g. a RING. This only works if it is possible and applicable.
536If the point-order is different, or the closure is different between two
537geometry types, it will be converted correctly by explicitly reversing the
538points 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 */
547template <typename Geometry1, typename Geometry2>
548inline 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