]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/geometry/algorithms/detail/overlay/get_turns.hpp
fd1e49ca243bd22c656ec80337960db907952735
[ceph.git] / ceph / src / boost / boost / geometry / algorithms / detail / overlay / get_turns.hpp
1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2
3 // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
4 // Copyright (c) 2014-2017 Adam Wulkiewicz, Lodz, Poland.
5
6 // This file was modified by Oracle on 2014, 2016, 2017.
7 // Modifications copyright (c) 2014-2017 Oracle and/or its affiliates.
8
9 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
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_DETAIL_OVERLAY_GET_TURNS_HPP
16 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURNS_HPP
17
18
19 #include <cstddef>
20 #include <map>
21
22 #include <boost/array.hpp>
23 #include <boost/concept_check.hpp>
24 #include <boost/mpl/if.hpp>
25 #include <boost/mpl/vector_c.hpp>
26 #include <boost/range.hpp>
27
28 #include <boost/geometry/core/access.hpp>
29 #include <boost/geometry/core/coordinate_dimension.hpp>
30 #include <boost/geometry/core/exterior_ring.hpp>
31 #include <boost/geometry/core/interior_rings.hpp>
32 #include <boost/geometry/core/reverse_dispatch.hpp>
33 #include <boost/geometry/core/ring_type.hpp>
34 #include <boost/geometry/core/tags.hpp>
35
36 #include <boost/geometry/geometries/concepts/check.hpp>
37
38 #include <boost/geometry/util/math.hpp>
39 #include <boost/geometry/views/closeable_view.hpp>
40 #include <boost/geometry/views/reversible_view.hpp>
41 #include <boost/geometry/views/detail/range_type.hpp>
42
43 #include <boost/geometry/geometries/box.hpp>
44 #include <boost/geometry/geometries/segment.hpp>
45
46 #include <boost/geometry/iterators/ever_circling_iterator.hpp>
47
48 #include <boost/geometry/strategies/intersection_strategies.hpp>
49 #include <boost/geometry/strategies/intersection_result.hpp>
50
51 #include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
52 #include <boost/geometry/algorithms/detail/disjoint/point_point.hpp>
53
54 #include <boost/geometry/algorithms/detail/interior_iterator.hpp>
55 #include <boost/geometry/algorithms/detail/partition.hpp>
56 #include <boost/geometry/algorithms/detail/recalculate.hpp>
57 #include <boost/geometry/algorithms/detail/sections/section_box_policies.hpp>
58
59 #include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
60 #include <boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp>
61 #include <boost/geometry/algorithms/detail/overlay/get_turn_info_la.hpp>
62 #include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp>
63
64 #include <boost/geometry/algorithms/detail/sections/range_by_section.hpp>
65 #include <boost/geometry/algorithms/detail/sections/sectionalize.hpp>
66 #include <boost/geometry/algorithms/detail/sections/section_functions.hpp>
67
68 #ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION
69 # include <sstream>
70 # include <boost/geometry/io/dsv/write.hpp>
71 #endif
72
73
74 namespace boost { namespace geometry
75 {
76
77 // Silence warning C4127: conditional expression is constant
78 #if defined(_MSC_VER)
79 #pragma warning(push)
80 #pragma warning(disable : 4127)
81 #endif
82
83
84 #ifndef DOXYGEN_NO_DETAIL
85 namespace detail { namespace get_turns
86 {
87
88
89 struct no_interrupt_policy
90 {
91 static bool const enabled = false;
92
93 // variable required by self_get_turn_points::get_turns
94 static bool const has_intersections = false;
95
96 template <typename Range>
97 static inline bool apply(Range const&)
98 {
99 return false;
100 }
101 };
102
103
104 template
105 <
106 typename Geometry1, typename Geometry2,
107 bool Reverse1, bool Reverse2,
108 typename Section1, typename Section2,
109 typename TurnPolicy
110 >
111 class get_turns_in_sections
112 {
113 typedef typename closeable_view
114 <
115 typename range_type<Geometry1>::type const,
116 closure<Geometry1>::value
117 >::type cview_type1;
118 typedef typename closeable_view
119 <
120 typename range_type<Geometry2>::type const,
121 closure<Geometry2>::value
122 >::type cview_type2;
123
124 typedef typename reversible_view
125 <
126 cview_type1 const,
127 Reverse1 ? iterate_reverse : iterate_forward
128 >::type view_type1;
129 typedef typename reversible_view
130 <
131 cview_type2 const,
132 Reverse2 ? iterate_reverse : iterate_forward
133 >::type view_type2;
134
135 typedef typename boost::range_iterator
136 <
137 view_type1 const
138 >::type range1_iterator;
139
140 typedef typename boost::range_iterator
141 <
142 view_type2 const
143 >::type range2_iterator;
144
145
146 template <typename Geometry, typename Section>
147 static inline bool adjacent(Section const& section,
148 signed_size_type index1, signed_size_type index2)
149 {
150 // About n-2:
151 // (square: range_count=5, indices 0,1,2,3
152 // -> 0-3 are adjacent, don't check on intersections)
153 // Also tested for open polygons, and/or duplicates
154 // About first condition: will be optimized by compiler (static)
155 // It checks if it is areal (box, ring, (multi)polygon)
156 signed_size_type const n = static_cast<signed_size_type>(section.range_count);
157
158 boost::ignore_unused_variable_warning(n);
159 boost::ignore_unused_variable_warning(index1);
160 boost::ignore_unused_variable_warning(index2);
161
162 return boost::is_same
163 <
164 typename tag_cast
165 <
166 typename geometry::tag<Geometry>::type,
167 areal_tag
168 >::type,
169 areal_tag
170 >::value
171 && index1 == 0
172 && index2 >= n - 2
173 ;
174 }
175
176
177 public :
178 // Returns true if terminated, false if interrupted
179 template <typename IntersectionStrategy, typename RobustPolicy, typename Turns, typename InterruptPolicy>
180 static inline bool apply(
181 int source_id1, Geometry1 const& geometry1, Section1 const& sec1,
182 int source_id2, Geometry2 const& geometry2, Section2 const& sec2,
183 bool skip_larger, bool skip_adjacent,
184 IntersectionStrategy const& intersection_strategy,
185 RobustPolicy const& robust_policy,
186 Turns& turns,
187 InterruptPolicy& interrupt_policy)
188 {
189 boost::ignore_unused_variable_warning(interrupt_policy);
190
191 if ((sec1.duplicate && (sec1.count + 1) < sec1.range_count)
192 || (sec2.duplicate && (sec2.count + 1) < sec2.range_count))
193 {
194 // Skip sections containig only duplicates.
195 // They are still important (can indicate non-disjointness)
196 // but they will be found processing adjacent sections.
197 // Do NOT skip if they are the ONLY section
198 return true;
199 }
200
201 cview_type1 cview1(range_by_section(geometry1, sec1));
202 cview_type2 cview2(range_by_section(geometry2, sec2));
203 view_type1 view1(cview1);
204 view_type2 view2(cview2);
205
206 range1_iterator begin_range_1 = boost::begin(view1);
207 range1_iterator end_range_1 = boost::end(view1);
208
209 range2_iterator begin_range_2 = boost::begin(view2);
210 range2_iterator end_range_2 = boost::end(view2);
211
212 int const dir1 = sec1.directions[0];
213 int const dir2 = sec2.directions[0];
214 signed_size_type index1 = sec1.begin_index;
215 signed_size_type ndi1 = sec1.non_duplicate_index;
216
217 range1_iterator prev1, it1, end1;
218
219 get_start_point_iterator(sec1, view1, prev1, it1, end1,
220 index1, ndi1, dir1, sec2.bounding_box, robust_policy);
221
222 // We need a circular iterator because it might run through the closing point.
223 // One circle is actually enough but this one is just convenient.
224 ever_circling_iterator<range1_iterator> next1(begin_range_1, end_range_1, it1, true);
225 next1++;
226
227 // Walk through section and stop if we exceed the other box
228 // section 2: [--------------]
229 // section 1: |----|---|---|---|---|
230 for (prev1 = it1++, next1++;
231 it1 != end1 && ! detail::section::exceeding<0>(dir1, *prev1, sec1.bounding_box, sec2.bounding_box, robust_policy);
232 ++prev1, ++it1, ++index1, ++next1, ++ndi1)
233 {
234 ever_circling_iterator<range1_iterator> nd_next1(
235 begin_range_1, end_range_1, next1, true);
236 advance_to_non_duplicate_next(nd_next1, it1, sec1, robust_policy);
237
238 signed_size_type index2 = sec2.begin_index;
239 signed_size_type ndi2 = sec2.non_duplicate_index;
240
241 range2_iterator prev2, it2, end2;
242
243 get_start_point_iterator(sec2, view2, prev2, it2, end2,
244 index2, ndi2, dir2, sec1.bounding_box, robust_policy);
245 ever_circling_iterator<range2_iterator> next2(begin_range_2, end_range_2, it2, true);
246 next2++;
247
248 for (prev2 = it2++, next2++;
249 it2 != end2 && ! detail::section::exceeding<0>(dir2, *prev2, sec2.bounding_box, sec1.bounding_box, robust_policy);
250 ++prev2, ++it2, ++index2, ++next2, ++ndi2)
251 {
252 bool skip = false;
253
254 if (source_id1 == source_id2
255 && sec1.ring_id.multi_index == sec2.ring_id.multi_index
256 && sec1.ring_id.ring_index == sec2.ring_id.ring_index)
257 {
258 // Sources and rings are the same
259
260 if (skip_larger && index1 >= index2)
261 {
262 // Skip to avoid getting all intersections twice
263 skip = true;
264 }
265 else if (skip_adjacent)
266 {
267 // In some cases (dissolve, has_self_intersections)
268 // neighbouring segments should be checked
269 // (for example to detect spikes properly)
270
271 // skip if it is a neighbouring segment.
272 // (including, for areas, first-last segment
273 // and two segments with one or more degenerate/duplicate
274 // (zero-length) segments in between)
275 skip = ndi2 == ndi1 + 1
276 || adjacent<Geometry1>(sec1, index1, index2);
277 }
278 }
279
280 if (! skip)
281 {
282 // Move to the "non duplicate next"
283 ever_circling_iterator<range2_iterator> nd_next2(
284 begin_range_2, end_range_2, next2, true);
285 advance_to_non_duplicate_next(nd_next2, it2, sec2, robust_policy);
286
287 typedef typename boost::range_value<Turns>::type turn_info;
288
289 turn_info ti;
290 ti.operations[0].seg_id
291 = segment_identifier(source_id1, sec1.ring_id.multi_index,
292 sec1.ring_id.ring_index, index1);
293 ti.operations[1].seg_id
294 = segment_identifier(source_id2, sec2.ring_id.multi_index,
295 sec2.ring_id.ring_index, index2);
296
297 std::size_t const size_before = boost::size(turns);
298
299 bool const is_1_first = sec1.is_non_duplicate_first && index1 == sec1.begin_index;
300 bool const is_1_last = sec1.is_non_duplicate_last && index1+1 >= sec1.end_index;
301 bool const is_2_first = sec2.is_non_duplicate_first && index2 == sec2.begin_index;
302 bool const is_2_last = sec2.is_non_duplicate_last && index2+1 >= sec2.end_index;
303
304 TurnPolicy::apply(*prev1, *it1, *nd_next1, *prev2, *it2, *nd_next2,
305 is_1_first, is_1_last, is_2_first, is_2_last,
306 ti, intersection_strategy, robust_policy,
307 std::back_inserter(turns));
308
309 if (InterruptPolicy::enabled)
310 {
311 if (interrupt_policy.apply(
312 std::make_pair(range::pos(turns, size_before),
313 boost::end(turns))))
314 {
315 return false;
316 }
317 }
318 }
319 }
320 }
321 return true;
322 }
323
324
325 private :
326 typedef typename geometry::point_type<Geometry1>::type point1_type;
327 typedef typename geometry::point_type<Geometry2>::type point2_type;
328 typedef typename model::referring_segment<point1_type const> segment1_type;
329 typedef typename model::referring_segment<point2_type const> segment2_type;
330
331 template <typename Iterator, typename RangeIterator, typename Section, typename RobustPolicy>
332 static inline void advance_to_non_duplicate_next(Iterator& next,
333 RangeIterator const& it, Section const& section, RobustPolicy const& robust_policy)
334 {
335 typedef typename robust_point_type<point1_type, RobustPolicy>::type robust_point_type;
336 robust_point_type robust_point_from_it;
337 robust_point_type robust_point_from_next;
338 geometry::recalculate(robust_point_from_it, *it, robust_policy);
339 geometry::recalculate(robust_point_from_next, *next, robust_policy);
340
341 // To see where the next segments bend to, in case of touch/intersections
342 // on end points, we need (in case of degenerate/duplicate points) an extra
343 // iterator which moves to the REAL next point, so non duplicate.
344 // This needs an extra comparison (disjoint).
345 // (Note that within sections, non duplicate points are already asserted,
346 // by the sectionalize process).
347
348 // So advance to the "non duplicate next"
349 // (the check is defensive, to avoid endless loops)
350 std::size_t check = 0;
351 while(! detail::disjoint::disjoint_point_point
352 (
353 robust_point_from_it, robust_point_from_next
354 )
355 && check++ < section.range_count)
356 {
357 next++;
358 geometry::recalculate(robust_point_from_next, *next, robust_policy);
359 }
360 }
361
362 // It is NOT possible to have section-iterators here
363 // because of the logistics of "index" (the section-iterator automatically
364 // skips to the begin-point, we loose the index or have to recalculate it)
365 // So we mimic it here
366 template <typename Range, typename Section, typename Box, typename RobustPolicy>
367 static inline void get_start_point_iterator(Section const& section,
368 Range const& range,
369 typename boost::range_iterator<Range const>::type& it,
370 typename boost::range_iterator<Range const>::type& prev,
371 typename boost::range_iterator<Range const>::type& end,
372 signed_size_type& index, signed_size_type& ndi,
373 int dir, Box const& other_bounding_box, RobustPolicy const& robust_policy)
374 {
375 it = boost::begin(range) + section.begin_index;
376 end = boost::begin(range) + section.end_index + 1;
377
378 // Mimic section-iterator:
379 // Skip to point such that section interects other box
380 prev = it++;
381 for(; it != end && detail::section::preceding<0>(dir, *it, section.bounding_box, other_bounding_box, robust_policy);
382 prev = it++, index++, ndi++)
383 {}
384 // Go back one step because we want to start completely preceding
385 it = prev;
386 }
387 };
388
389 template
390 <
391 typename Geometry1, typename Geometry2,
392 bool Reverse1, bool Reverse2,
393 typename TurnPolicy,
394 typename IntersectionStrategy,
395 typename RobustPolicy,
396 typename Turns,
397 typename InterruptPolicy
398 >
399 struct section_visitor
400 {
401 int m_source_id1;
402 Geometry1 const& m_geometry1;
403 int m_source_id2;
404 Geometry2 const& m_geometry2;
405 IntersectionStrategy const& m_intersection_strategy;
406 RobustPolicy const& m_rescale_policy;
407 Turns& m_turns;
408 InterruptPolicy& m_interrupt_policy;
409
410 section_visitor(int id1, Geometry1 const& g1,
411 int id2, Geometry2 const& g2,
412 IntersectionStrategy const& intersection_strategy,
413 RobustPolicy const& robust_policy,
414 Turns& turns,
415 InterruptPolicy& ip)
416 : m_source_id1(id1), m_geometry1(g1)
417 , m_source_id2(id2), m_geometry2(g2)
418 , m_intersection_strategy(intersection_strategy)
419 , m_rescale_policy(robust_policy)
420 , m_turns(turns)
421 , m_interrupt_policy(ip)
422 {}
423
424 template <typename Section>
425 inline bool apply(Section const& sec1, Section const& sec2)
426 {
427 if (! detail::disjoint::disjoint_box_box(sec1.bounding_box, sec2.bounding_box))
428 {
429 // false if interrupted
430 return get_turns_in_sections
431 <
432 Geometry1,
433 Geometry2,
434 Reverse1, Reverse2,
435 Section, Section,
436 TurnPolicy
437 >::apply(m_source_id1, m_geometry1, sec1,
438 m_source_id2, m_geometry2, sec2,
439 false, false,
440 m_intersection_strategy,
441 m_rescale_policy,
442 m_turns, m_interrupt_policy);
443 }
444 return true;
445 }
446
447 };
448
449 template
450 <
451 typename Geometry1, typename Geometry2,
452 bool Reverse1, bool Reverse2,
453 typename TurnPolicy
454 >
455 class get_turns_generic
456 {
457
458 public:
459 template <typename IntersectionStrategy, typename RobustPolicy, typename Turns, typename InterruptPolicy>
460 static inline void apply(
461 int source_id1, Geometry1 const& geometry1,
462 int source_id2, Geometry2 const& geometry2,
463 IntersectionStrategy const& intersection_strategy,
464 RobustPolicy const& robust_policy,
465 Turns& turns,
466 InterruptPolicy& interrupt_policy)
467 {
468 // First create monotonic sections...
469 typedef typename boost::range_value<Turns>::type ip_type;
470 typedef typename ip_type::point_type point_type;
471
472 typedef model::box
473 <
474 typename geometry::robust_point_type
475 <
476 point_type, RobustPolicy
477 >::type
478 > box_type;
479 typedef geometry::sections<box_type, 2> sections_type;
480
481 sections_type sec1, sec2;
482 typedef boost::mpl::vector_c<std::size_t, 0, 1> dimensions;
483
484 typename IntersectionStrategy::envelope_strategy_type const
485 envelope_strategy = intersection_strategy.get_envelope_strategy();
486
487 geometry::sectionalize<Reverse1, dimensions>(geometry1, robust_policy,
488 sec1, envelope_strategy, 0);
489 geometry::sectionalize<Reverse2, dimensions>(geometry2, robust_policy,
490 sec2, envelope_strategy, 1);
491
492 // ... and then partition them, intersecting overlapping sections in visitor method
493 section_visitor
494 <
495 Geometry1, Geometry2,
496 Reverse1, Reverse2,
497 TurnPolicy,
498 IntersectionStrategy, RobustPolicy,
499 Turns, InterruptPolicy
500 > visitor(source_id1, geometry1, source_id2, geometry2,
501 intersection_strategy, robust_policy,
502 turns, interrupt_policy);
503
504 geometry::partition
505 <
506 box_type
507 >::apply(sec1, sec2, visitor,
508 detail::section::get_section_box(),
509 detail::section::overlaps_section_box());
510 }
511 };
512
513
514 // Get turns for a range with a box, following Cohen-Sutherland (cs) approach
515 template
516 <
517 typename Range, typename Box,
518 bool ReverseRange, bool ReverseBox,
519 typename TurnPolicy
520 >
521 struct get_turns_cs
522 {
523 typedef typename geometry::point_type<Range>::type point_type;
524 typedef typename geometry::point_type<Box>::type box_point_type;
525
526 typedef typename closeable_view
527 <
528 Range const,
529 closure<Range>::value
530 >::type cview_type;
531
532 typedef typename reversible_view
533 <
534 cview_type const,
535 ReverseRange ? iterate_reverse : iterate_forward
536 >::type view_type;
537
538 typedef typename boost::range_iterator
539 <
540 view_type const
541 >::type iterator_type;
542
543
544 template <typename IntersectionStrategy, typename RobustPolicy, typename Turns, typename InterruptPolicy>
545 static inline void apply(
546 int source_id1, Range const& range,
547 int source_id2, Box const& box,
548 IntersectionStrategy const& intersection_strategy,
549 RobustPolicy const& robust_policy,
550 Turns& turns,
551 InterruptPolicy& interrupt_policy,
552 signed_size_type multi_index = -1,
553 signed_size_type ring_index = -1)
554 {
555 if ( boost::size(range) <= 1)
556 {
557 return;
558 }
559
560 boost::array<box_point_type,4> bp;
561 assign_box_corners_oriented<ReverseBox>(box, bp);
562
563 cview_type cview(range);
564 view_type view(cview);
565
566 typedef typename boost::range_size<view_type>::type size_type;
567 size_type segments_count1 = boost::size(view) - 1;
568
569 iterator_type it = boost::begin(view);
570
571 ever_circling_iterator<iterator_type> next(
572 boost::begin(view), boost::end(view), it, true);
573 next++;
574 next++;
575
576 //bool first = true;
577
578 //char previous_side[2] = {0, 0};
579
580 signed_size_type index = 0;
581
582 for (iterator_type prev = it++;
583 it != boost::end(view);
584 prev = it++, next++, index++)
585 {
586 segment_identifier seg_id(source_id1,
587 multi_index, ring_index, index);
588
589 /*if (first)
590 {
591 previous_side[0] = get_side<0>(box, *prev);
592 previous_side[1] = get_side<1>(box, *prev);
593 }
594
595 char current_side[2];
596 current_side[0] = get_side<0>(box, *it);
597 current_side[1] = get_side<1>(box, *it);
598
599 // There can NOT be intersections if
600 // 1) EITHER the two points are lying on one side of the box (! 0 && the same)
601 // 2) OR same in Y-direction
602 // 3) OR all points are inside the box (0)
603 if (! (
604 (current_side[0] != 0 && current_side[0] == previous_side[0])
605 || (current_side[1] != 0 && current_side[1] == previous_side[1])
606 || (current_side[0] == 0
607 && current_side[1] == 0
608 && previous_side[0] == 0
609 && previous_side[1] == 0)
610 )
611 )*/
612 if (true)
613 {
614 get_turns_with_box(seg_id, source_id2,
615 *prev, *it, *next,
616 bp[0], bp[1], bp[2], bp[3],
617 // NOTE: some dummy values could be passed below since this would be called only for Polygons and Boxes
618 index == 0,
619 size_type(index) == segments_count1,
620 intersection_strategy,
621 robust_policy,
622 turns,
623 interrupt_policy);
624 // Future performance enhancement:
625 // return if told by the interrupt policy
626 }
627 }
628 }
629
630 private:
631 template<std::size_t Index, typename Point>
632 static inline int get_side(Box const& box, Point const& point)
633 {
634 // Inside -> 0
635 // Outside -> -1 (left/below) or 1 (right/above)
636 // On border -> -2 (left/lower) or 2 (right/upper)
637 // The only purpose of the value is to not be the same,
638 // and to denote if it is inside (0)
639
640 typename coordinate_type<Point>::type const& c = get<Index>(point);
641 typename coordinate_type<Box>::type const& left = get<min_corner, Index>(box);
642 typename coordinate_type<Box>::type const& right = get<max_corner, Index>(box);
643
644 if (geometry::math::equals(c, left)) return -2;
645 else if (geometry::math::equals(c, right)) return 2;
646 else if (c < left) return -1;
647 else if (c > right) return 1;
648 else return 0;
649 }
650
651 template <typename IntersectionStrategy, typename RobustPolicy, typename Turns, typename InterruptPolicy>
652 static inline void get_turns_with_box(segment_identifier const& seg_id, int source_id2,
653 // Points from a range:
654 point_type const& rp0,
655 point_type const& rp1,
656 point_type const& rp2,
657 // Points from the box
658 box_point_type const& bp0,
659 box_point_type const& bp1,
660 box_point_type const& bp2,
661 box_point_type const& bp3,
662 bool const is_range_first,
663 bool const is_range_last,
664 IntersectionStrategy const& intersection_strategy,
665 RobustPolicy const& robust_policy,
666 // Output
667 Turns& turns,
668 InterruptPolicy& interrupt_policy)
669 {
670 boost::ignore_unused_variable_warning(interrupt_policy);
671
672 // Depending on code some relations can be left out
673
674 typedef typename boost::range_value<Turns>::type turn_info;
675
676 turn_info ti;
677 ti.operations[0].seg_id = seg_id;
678
679 ti.operations[1].seg_id = segment_identifier(source_id2, -1, -1, 0);
680 TurnPolicy::apply(rp0, rp1, rp2, bp0, bp1, bp2,
681 is_range_first, is_range_last,
682 true, false,
683 ti, intersection_strategy, robust_policy,
684 std::back_inserter(turns));
685
686 ti.operations[1].seg_id = segment_identifier(source_id2, -1, -1, 1);
687 TurnPolicy::apply(rp0, rp1, rp2, bp1, bp2, bp3,
688 is_range_first, is_range_last,
689 false, false,
690 ti, intersection_strategy, robust_policy,
691 std::back_inserter(turns));
692
693 ti.operations[1].seg_id = segment_identifier(source_id2, -1, -1, 2);
694 TurnPolicy::apply(rp0, rp1, rp2, bp2, bp3, bp0,
695 is_range_first, is_range_last,
696 false, false,
697 ti, intersection_strategy, robust_policy,
698 std::back_inserter(turns));
699
700 ti.operations[1].seg_id = segment_identifier(source_id2, -1, -1, 3);
701 TurnPolicy::apply(rp0, rp1, rp2, bp3, bp0, bp1,
702 is_range_first, is_range_last,
703 false, true,
704 ti, intersection_strategy, robust_policy,
705 std::back_inserter(turns));
706
707 if (InterruptPolicy::enabled)
708 {
709 interrupt_policy.apply(turns);
710 }
711
712 }
713
714 };
715
716
717 template
718 <
719 typename Polygon, typename Box,
720 bool Reverse, bool ReverseBox,
721 typename TurnPolicy
722 >
723 struct get_turns_polygon_cs
724 {
725 template <typename IntersectionStrategy, typename RobustPolicy, typename Turns, typename InterruptPolicy>
726 static inline void apply(
727 int source_id1, Polygon const& polygon,
728 int source_id2, Box const& box,
729 IntersectionStrategy const& intersection_strategy,
730 RobustPolicy const& robust_policy,
731 Turns& turns,
732 InterruptPolicy& interrupt_policy,
733 signed_size_type multi_index = -1)
734 {
735 typedef typename geometry::ring_type<Polygon>::type ring_type;
736
737 typedef detail::get_turns::get_turns_cs
738 <
739 ring_type, Box,
740 Reverse, ReverseBox,
741 TurnPolicy
742 > intersector_type;
743
744 intersector_type::apply(
745 source_id1, geometry::exterior_ring(polygon),
746 source_id2, box,
747 intersection_strategy,
748 robust_policy,
749 turns,
750 interrupt_policy,
751 multi_index, -1);
752
753 signed_size_type i = 0;
754
755 typename interior_return_type<Polygon const>::type
756 rings = interior_rings(polygon);
757 for (typename detail::interior_iterator<Polygon const>::type
758 it = boost::begin(rings); it != boost::end(rings); ++it, ++i)
759 {
760 intersector_type::apply(
761 source_id1, *it,
762 source_id2, box,
763 intersection_strategy,
764 robust_policy,
765 turns, interrupt_policy,
766 multi_index, i);
767 }
768
769 }
770 };
771
772
773 template
774 <
775 typename Multi, typename Box,
776 bool Reverse, bool ReverseBox,
777 typename TurnPolicy
778 >
779 struct get_turns_multi_polygon_cs
780 {
781 template <typename IntersectionStrategy, typename RobustPolicy, typename Turns, typename InterruptPolicy>
782 static inline void apply(
783 int source_id1, Multi const& multi,
784 int source_id2, Box const& box,
785 IntersectionStrategy const& intersection_strategy,
786 RobustPolicy const& robust_policy,
787 Turns& turns,
788 InterruptPolicy& interrupt_policy)
789 {
790 typedef typename boost::range_iterator
791 <
792 Multi const
793 >::type iterator_type;
794
795 signed_size_type i = 0;
796 for (iterator_type it = boost::begin(multi);
797 it != boost::end(multi);
798 ++it, ++i)
799 {
800 // Call its single version
801 get_turns_polygon_cs
802 <
803 typename boost::range_value<Multi>::type, Box,
804 Reverse, ReverseBox,
805 TurnPolicy
806 >::apply(source_id1, *it, source_id2, box,
807 intersection_strategy, robust_policy,
808 turns, interrupt_policy, i);
809 }
810 }
811 };
812
813
814 // GET_TURN_INFO_TYPE
815
816 template <typename Geometry>
817 struct topological_tag_base
818 {
819 typedef typename tag_cast<typename tag<Geometry>::type, pointlike_tag, linear_tag, areal_tag>::type type;
820 };
821
822 template <typename Geometry1, typename Geometry2, typename AssignPolicy,
823 typename Tag1 = typename tag<Geometry1>::type, typename Tag2 = typename tag<Geometry2>::type,
824 typename TagBase1 = typename topological_tag_base<Geometry1>::type, typename TagBase2 = typename topological_tag_base<Geometry2>::type>
825 struct get_turn_info_type
826 : overlay::get_turn_info<AssignPolicy>
827 {};
828
829 template <typename Geometry1, typename Geometry2, typename AssignPolicy, typename Tag1, typename Tag2>
830 struct get_turn_info_type<Geometry1, Geometry2, AssignPolicy, Tag1, Tag2, linear_tag, linear_tag>
831 : overlay::get_turn_info_linear_linear<AssignPolicy>
832 {};
833
834 template <typename Geometry1, typename Geometry2, typename AssignPolicy, typename Tag1, typename Tag2>
835 struct get_turn_info_type<Geometry1, Geometry2, AssignPolicy, Tag1, Tag2, linear_tag, areal_tag>
836 : overlay::get_turn_info_linear_areal<AssignPolicy>
837 {};
838
839 template <typename Geometry1, typename Geometry2, typename SegmentRatio,
840 typename Tag1 = typename tag<Geometry1>::type, typename Tag2 = typename tag<Geometry2>::type,
841 typename TagBase1 = typename topological_tag_base<Geometry1>::type, typename TagBase2 = typename topological_tag_base<Geometry2>::type>
842 struct turn_operation_type
843 {
844 typedef overlay::turn_operation<typename point_type<Geometry1>::type, SegmentRatio> type;
845 };
846
847 template <typename Geometry1, typename Geometry2, typename SegmentRatio, typename Tag1, typename Tag2>
848 struct turn_operation_type<Geometry1, Geometry2, SegmentRatio, Tag1, Tag2, linear_tag, linear_tag>
849 {
850 typedef overlay::turn_operation_linear<typename point_type<Geometry1>::type, SegmentRatio> type;
851 };
852
853 template <typename Geometry1, typename Geometry2, typename SegmentRatio, typename Tag1, typename Tag2>
854 struct turn_operation_type<Geometry1, Geometry2, SegmentRatio, Tag1, Tag2, linear_tag, areal_tag>
855 {
856 typedef overlay::turn_operation_linear<typename point_type<Geometry1>::type, SegmentRatio> type;
857 };
858
859 }} // namespace detail::get_turns
860 #endif // DOXYGEN_NO_DETAIL
861
862
863 #ifndef DOXYGEN_NO_DISPATCH
864 namespace dispatch
865 {
866
867 // Because this is "detail" method, and most implementations will use "generic",
868 // we take the freedom to derive it from "generic".
869 template
870 <
871 typename GeometryTag1, typename GeometryTag2,
872 typename Geometry1, typename Geometry2,
873 bool Reverse1, bool Reverse2,
874 typename TurnPolicy
875 >
876 struct get_turns
877 : detail::get_turns::get_turns_generic
878 <
879 Geometry1, Geometry2,
880 Reverse1, Reverse2,
881 TurnPolicy
882 >
883 {};
884
885
886 template
887 <
888 typename Polygon, typename Box,
889 bool ReversePolygon, bool ReverseBox,
890 typename TurnPolicy
891 >
892 struct get_turns
893 <
894 polygon_tag, box_tag,
895 Polygon, Box,
896 ReversePolygon, ReverseBox,
897 TurnPolicy
898 > : detail::get_turns::get_turns_polygon_cs
899 <
900 Polygon, Box,
901 ReversePolygon, ReverseBox,
902 TurnPolicy
903 >
904 {};
905
906
907 template
908 <
909 typename Ring, typename Box,
910 bool ReverseRing, bool ReverseBox,
911 typename TurnPolicy
912 >
913 struct get_turns
914 <
915 ring_tag, box_tag,
916 Ring, Box,
917 ReverseRing, ReverseBox,
918 TurnPolicy
919 > : detail::get_turns::get_turns_cs
920 <
921 Ring, Box, ReverseRing, ReverseBox,
922 TurnPolicy
923 >
924
925 {};
926
927
928 template
929 <
930 typename MultiPolygon,
931 typename Box,
932 bool ReverseMultiPolygon, bool ReverseBox,
933 typename TurnPolicy
934 >
935 struct get_turns
936 <
937 multi_polygon_tag, box_tag,
938 MultiPolygon, Box,
939 ReverseMultiPolygon, ReverseBox,
940 TurnPolicy
941 >
942 : detail::get_turns::get_turns_multi_polygon_cs
943 <
944 MultiPolygon, Box,
945 ReverseMultiPolygon, ReverseBox,
946 TurnPolicy
947 >
948 {};
949
950
951 template
952 <
953 typename GeometryTag1, typename GeometryTag2,
954 typename Geometry1, typename Geometry2,
955 bool Reverse1, bool Reverse2,
956 typename TurnPolicy
957 >
958 struct get_turns_reversed
959 {
960 template <typename IntersectionStrategy, typename RobustPolicy, typename Turns, typename InterruptPolicy>
961 static inline void apply(int source_id1, Geometry1 const& g1,
962 int source_id2, Geometry2 const& g2,
963 IntersectionStrategy const& intersection_strategy,
964 RobustPolicy const& robust_policy,
965 Turns& turns,
966 InterruptPolicy& interrupt_policy)
967 {
968 get_turns
969 <
970 GeometryTag2, GeometryTag1,
971 Geometry2, Geometry1,
972 Reverse2, Reverse1,
973 TurnPolicy
974 >::apply(source_id2, g2, source_id1, g1,
975 intersection_strategy, robust_policy,
976 turns, interrupt_policy);
977 }
978 };
979
980
981 } // namespace dispatch
982 #endif // DOXYGEN_NO_DISPATCH
983
984
985
986 /*!
987 \brief \brief_calc2{turn points}
988 \ingroup overlay
989 \tparam Geometry1 \tparam_geometry
990 \tparam Geometry2 \tparam_geometry
991 \tparam Turns type of turn-container (e.g. vector of "intersection/turn point"'s)
992 \param geometry1 \param_geometry
993 \param geometry2 \param_geometry
994 \param intersection_strategy segments intersection strategy
995 \param robust_policy policy to handle robustness issues
996 \param turns container which will contain turn points
997 \param interrupt_policy policy determining if process is stopped
998 when intersection is found
999 */
1000 template
1001 <
1002 bool Reverse1, bool Reverse2,
1003 typename AssignPolicy,
1004 typename Geometry1,
1005 typename Geometry2,
1006 typename IntersectionStrategy,
1007 typename RobustPolicy,
1008 typename Turns,
1009 typename InterruptPolicy
1010 >
1011 inline void get_turns(Geometry1 const& geometry1,
1012 Geometry2 const& geometry2,
1013 IntersectionStrategy const& intersection_strategy,
1014 RobustPolicy const& robust_policy,
1015 Turns& turns,
1016 InterruptPolicy& interrupt_policy)
1017 {
1018 concepts::check_concepts_and_equal_dimensions<Geometry1 const, Geometry2 const>();
1019
1020 typedef detail::overlay::get_turn_info<AssignPolicy> TurnPolicy;
1021 //typedef detail::get_turns::get_turn_info_type<Geometry1, Geometry2, AssignPolicy> TurnPolicy;
1022
1023 boost::mpl::if_c
1024 <
1025 reverse_dispatch<Geometry1, Geometry2>::type::value,
1026 dispatch::get_turns_reversed
1027 <
1028 typename tag<Geometry1>::type,
1029 typename tag<Geometry2>::type,
1030 Geometry1, Geometry2,
1031 Reverse1, Reverse2,
1032 TurnPolicy
1033 >,
1034 dispatch::get_turns
1035 <
1036 typename tag<Geometry1>::type,
1037 typename tag<Geometry2>::type,
1038 Geometry1, Geometry2,
1039 Reverse1, Reverse2,
1040 TurnPolicy
1041 >
1042 >::type::apply(0, geometry1,
1043 1, geometry2,
1044 intersection_strategy,
1045 robust_policy,
1046 turns, interrupt_policy);
1047 }
1048
1049 #if defined(_MSC_VER)
1050 #pragma warning(pop)
1051 #endif
1052
1053 }} // namespace boost::geometry
1054
1055 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURNS_HPP