]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/geometry/algorithms/convert.hpp
import quincy beta 17.1.0
[ceph.git] / ceph / src / boost / boost / geometry / algorithms / convert.hpp
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 // 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
11
12 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
13 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
14
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)
18
19 #ifndef BOOST_GEOMETRY_ALGORITHMS_CONVERT_HPP
20 #define BOOST_GEOMETRY_ALGORITHMS_CONVERT_HPP
21
22
23 #include <cstddef>
24 #include <type_traits>
25
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>
34
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>
43
44 #include <boost/geometry/views/closeable_view.hpp>
45 #include <boost/geometry/views/reversible_view.hpp>
46
47 #include <boost/geometry/util/range.hpp>
48
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>
53
54 #include <boost/geometry/geometries/concepts/check.hpp>
55
56
57 namespace boost { namespace geometry
58 {
59
60 // Silence warning C4127: conditional expression is constant
61 // Silence warning C4512: assignment operator could not be generated
62 #if defined(_MSC_VER)
63 #pragma warning(push)
64 #pragma warning(disable : 4127 4512)
65 #endif
66
67
68 #ifndef DOXYGEN_NO_DETAIL
69 namespace detail { namespace conversion
70 {
71
72 template
73 <
74 typename Point,
75 typename Box,
76 std::size_t Index,
77 std::size_t Dimension,
78 std::size_t DimensionCount
79 >
80 struct point_to_box
81 {
82 static inline void apply(Point const& point, Box& box)
83 {
84 typedef typename coordinate_type<Box>::type coordinate_type;
85
86 set<Index, Dimension>(box,
87 boost::numeric_cast<coordinate_type>(get<Dimension>(point)));
88 point_to_box
89 <
90 Point, Box,
91 Index, Dimension + 1, DimensionCount
92 >::apply(point, box);
93 }
94 };
95
96
97 template
98 <
99 typename Point,
100 typename Box,
101 std::size_t Index,
102 std::size_t DimensionCount
103 >
104 struct point_to_box<Point, Box, Index, DimensionCount, DimensionCount>
105 {
106 static inline void apply(Point const& , Box& )
107 {}
108 };
109
110 template <typename Box, typename Range, bool Close, bool Reverse>
111 struct box_to_range
112 {
113 static inline void apply(Box const& box, Range& range)
114 {
115 traits::resize<Range>::apply(range, Close ? 5 : 4);
116 assign_box_corners_oriented<Reverse>(box, range);
117 if (Close)
118 {
119 range::at(range, 4) = range::at(range, 0);
120 }
121 }
122 };
123
124 template <typename Segment, typename Range>
125 struct segment_to_range
126 {
127 static inline void apply(Segment const& segment, Range& range)
128 {
129 traits::resize<Range>::apply(range, 2);
130
131 typename boost::range_iterator<Range>::type it = boost::begin(range);
132
133 assign_point_from_index<0>(segment, *it);
134 ++it;
135 assign_point_from_index<1>(segment, *it);
136 }
137 };
138
139 template
140 <
141 typename Range1,
142 typename Range2,
143 bool Reverse = false
144 >
145 struct range_to_range
146 {
147 typedef typename reversible_view
148 <
149 Range1 const,
150 Reverse ? iterate_reverse : iterate_forward
151 >::type rview_type;
152 typedef typename closeable_view
153 <
154 rview_type const,
155 geometry::closure<Range1>::value
156 >::type view_type;
157
158 struct default_policy
159 {
160 template <typename Point1, typename Point2>
161 static inline void apply(Point1 const& point1, Point2 & point2)
162 {
163 geometry::detail::conversion::convert_point_to_point(point1, point2);
164 }
165 };
166
167 static inline void apply(Range1 const& source, Range2& destination)
168 {
169 apply(source, destination, default_policy());
170 }
171
172 template <typename ConvertPointPolicy>
173 static inline ConvertPointPolicy apply(Range1 const& source, Range2& destination,
174 ConvertPointPolicy convert_point)
175 {
176 geometry::clear(destination);
177
178 rview_type rview(source);
179
180 // We consider input always as closed, and skip last
181 // point for open output.
182 view_type view(rview);
183
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)
187 {
188 n--;
189 }
190
191 // If size == 0 && geometry::open <=> n = numeric_limits<size_type>::max()
192 // but ok, sice below it == end()
193
194 size_type i = 0;
195 for (typename boost::range_iterator<view_type const>::type it
196 = boost::begin(view);
197 it != boost::end(view) && i < n;
198 ++it, ++i)
199 {
200 typename boost::range_value<Range2>::type point;
201 convert_point.apply(*it, point);
202 range::push_back(destination, point);
203 }
204
205 return convert_point;
206 }
207 };
208
209 template <typename Polygon1, typename Polygon2>
210 struct polygon_to_polygon
211 {
212 typedef range_to_range
213 <
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
218 > per_ring;
219
220 static inline void apply(Polygon1 const& source, Polygon2& destination)
221 {
222 // Clearing managed per ring, and in the resizing of interior rings
223
224 per_ring::apply(geometry::exterior_ring(source),
225 geometry::exterior_ring(destination));
226
227 // Container should be resizeable
228 traits::resize
229 <
230 typename std::remove_reference
231 <
232 typename traits::interior_mutable_type<Polygon2>::type
233 >::type
234 >::apply(interior_rings(destination), num_interior_rings(source));
235
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);
240
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);
245
246 for ( ; it_source != boost::end(rings_source); ++it_source, ++it_dest)
247 {
248 per_ring::apply(*it_source, *it_dest);
249 }
250 }
251 };
252
253 template <typename Single, typename Multi, typename Policy>
254 struct single_to_multi: private Policy
255 {
256 static inline void apply(Single const& single, Multi& multi)
257 {
258 traits::resize<Multi>::apply(multi, 1);
259 Policy::apply(single, *boost::begin(multi));
260 }
261 };
262
263
264
265 template <typename Multi1, typename Multi2, typename Policy>
266 struct multi_to_multi: private Policy
267 {
268 static inline void apply(Multi1 const& multi1, Multi2& multi2)
269 {
270 traits::resize<Multi2>::apply(multi2, boost::size(multi1));
271
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);
276
277 for (; it1 != boost::end(multi1); ++it1, ++it2)
278 {
279 Policy::apply(*it1, *it2);
280 }
281 }
282 };
283
284
285 }} // namespace detail::conversion
286 #endif // DOXYGEN_NO_DETAIL
287
288
289 #ifndef DOXYGEN_NO_DISPATCH
290 namespace dispatch
291 {
292
293 template
294 <
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
301 >
302 struct convert
303 : not_implemented
304 <
305 Tag1, Tag2,
306 std::integral_constant<std::size_t, DimensionCount>
307 >
308 {};
309
310
311 template
312 <
313 typename Geometry1, typename Geometry2,
314 typename Tag,
315 std::size_t DimensionCount
316 >
317 struct convert<Geometry1, Geometry2, Tag, Tag, DimensionCount, true>
318 {
319 // Same geometry type -> copy whole geometry
320 static inline void apply(Geometry1 const& source, Geometry2& destination)
321 {
322 destination = source;
323 }
324 };
325
326
327 template
328 <
329 typename Geometry1, typename Geometry2,
330 std::size_t DimensionCount
331 >
332 struct convert<Geometry1, Geometry2, point_tag, point_tag, DimensionCount, false>
333 : detail::conversion::point_to_point<Geometry1, Geometry2, 0, DimensionCount>
334 {};
335
336
337 template
338 <
339 typename Box1, typename Box2,
340 std::size_t DimensionCount
341 >
342 struct convert<Box1, Box2, box_tag, box_tag, DimensionCount, false>
343 : detail::conversion::indexed_to_indexed<Box1, Box2, 0, DimensionCount>
344 {};
345
346
347 template
348 <
349 typename Segment1, typename Segment2,
350 std::size_t DimensionCount
351 >
352 struct convert<Segment1, Segment2, segment_tag, segment_tag, DimensionCount, false>
353 : detail::conversion::indexed_to_indexed<Segment1, Segment2, 0, DimensionCount>
354 {};
355
356
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>
360 {};
361
362
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
366 <
367 Ring1,
368 Ring2,
369 geometry::point_order<Ring1>::value
370 != geometry::point_order<Ring2>::value
371 >
372 {};
373
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>
377 {};
378
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>
382 {};
383
384 template <typename Box, typename Ring>
385 struct convert<Box, Ring, box_tag, ring_tag, 2, false>
386 : detail::conversion::box_to_range
387 <
388 Box,
389 Ring,
390 geometry::closure<Ring>::value == closed,
391 geometry::point_order<Ring>::value == counterclockwise
392 >
393 {};
394
395
396 template <typename Box, typename Polygon>
397 struct convert<Box, Polygon, box_tag, polygon_tag, 2, false>
398 {
399 static inline void apply(Box const& box, Polygon& polygon)
400 {
401 typedef typename ring_type<Polygon>::type ring_type;
402
403 convert
404 <
405 Box, ring_type,
406 box_tag, ring_tag,
407 2, false
408 >::apply(box, exterior_ring(polygon));
409 }
410 };
411
412
413 template <typename Point, typename Box, std::size_t DimensionCount>
414 struct convert<Point, Box, point_tag, box_tag, DimensionCount, false>
415 {
416 static inline void apply(Point const& point, Box& box)
417 {
418 detail::conversion::point_to_box
419 <
420 Point, Box, min_corner, 0, DimensionCount
421 >::apply(point, box);
422 detail::conversion::point_to_box
423 <
424 Point, Box, max_corner, 0, DimensionCount
425 >::apply(point, box);
426 }
427 };
428
429
430 template <typename Ring, typename Polygon, std::size_t DimensionCount>
431 struct convert<Ring, Polygon, ring_tag, polygon_tag, DimensionCount, false>
432 {
433 static inline void apply(Ring const& ring, Polygon& polygon)
434 {
435 typedef typename ring_type<Polygon>::type ring_type;
436 convert
437 <
438 Ring, ring_type,
439 ring_tag, ring_tag,
440 DimensionCount, false
441 >::apply(ring, exterior_ring(polygon));
442 }
443 };
444
445
446 template <typename Polygon, typename Ring, std::size_t DimensionCount>
447 struct convert<Polygon, Ring, polygon_tag, ring_tag, DimensionCount, false>
448 {
449 static inline void apply(Polygon const& polygon, Ring& ring)
450 {
451 typedef typename ring_type<Polygon>::type ring_type;
452
453 convert
454 <
455 ring_type, Ring,
456 ring_tag, ring_tag,
457 DimensionCount, false
458 >::apply(exterior_ring(polygon), ring);
459 }
460 };
461
462
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
466
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
470 <
471 Multi1,
472 Multi2,
473 convert
474 <
475 typename boost::range_value<Multi1>::type,
476 typename boost::range_value<Multi2>::type,
477 typename single_tag_of
478 <
479 typename tag<Multi1>::type
480 >::type,
481 typename single_tag_of
482 <
483 typename tag<Multi2>::type
484 >::type,
485 DimensionCount
486 >
487 >
488 {};
489
490
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
494 <
495 Single,
496 Multi,
497 convert
498 <
499 Single,
500 typename boost::range_value<Multi>::type,
501 typename tag<Single>::type,
502 typename single_tag_of
503 <
504 typename tag<Multi>::type
505 >::type,
506 DimensionCount,
507 false
508 >
509 >
510 {};
511
512
513 } // namespace dispatch
514 #endif // DOXYGEN_NO_DISPATCH
515
516
517 namespace resolve_variant {
518
519 template <typename Geometry1, typename Geometry2>
520 struct convert
521 {
522 static inline void apply(Geometry1 const& geometry1, Geometry2& geometry2)
523 {
524 concepts::check_concepts_and_equal_dimensions<Geometry1 const, Geometry2>();
525 dispatch::convert<Geometry1, Geometry2>::apply(geometry1, geometry2);
526 }
527 };
528
529 template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
530 struct convert<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
531 {
532 struct visitor: static_visitor<void>
533 {
534 Geometry2& m_geometry2;
535
536 visitor(Geometry2& geometry2)
537 : m_geometry2(geometry2)
538 {}
539
540 template <typename Geometry1>
541 inline void operator()(Geometry1 const& geometry1) const
542 {
543 convert<Geometry1, Geometry2>::apply(geometry1, m_geometry2);
544 }
545 };
546
547 static inline void apply(
548 boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
549 Geometry2& geometry2
550 )
551 {
552 boost::apply_visitor(visitor(geometry2), geometry1);
553 }
554 };
555
556 }
557
558
559 /*!
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.
566 \ingroup convert
567 \tparam Geometry1 \tparam_geometry
568 \tparam Geometry2 \tparam_geometry
569 \param geometry1 \param_geometry (source)
570 \param geometry2 \param_geometry (target)
571
572 \qbk{[include reference/algorithms/convert.qbk]}
573 */
574 template <typename Geometry1, typename Geometry2>
575 inline void convert(Geometry1 const& geometry1, Geometry2& geometry2)
576 {
577 resolve_variant::convert<Geometry1, Geometry2>::apply(geometry1, geometry2);
578 }
579
580 #if defined(_MSC_VER)
581 #pragma warning(pop)
582 #endif
583
584 }} // namespace boost::geometry
585
586 #endif // BOOST_GEOMETRY_ALGORITHMS_CONVERT_HPP