]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/geometry/algorithms/convert.hpp
update sources to v12.2.3
[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 // 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 {
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
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 {
104 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 {
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
122 template <typename Segment, typename Range>
123 struct 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
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
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
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
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
231 template <typename Single, typename Multi, typename Policy>
232 struct 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
243 template <typename Multi1, typename Multi2, typename Policy>
244 struct 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
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
293 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 {
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
386 template <typename Point, typename Box, std::size_t DimensionCount>
387 struct 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
403 template <typename Ring, typename Polygon, std::size_t DimensionCount>
404 struct 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
419 template <typename Polygon, typename Ring, std::size_t DimensionCount>
420 struct 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
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 {
495 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
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
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>
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