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 | concept::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 |
560 | |