]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 |