1 // Boost.Geometry (aka GGL, Generic Geometry Library)
3 // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
4 // Copyright (c) 2014-2017 Adam Wulkiewicz, Lodz, Poland.
6 // This file was modified by Oracle on 2014, 2016, 2017, 2018.
7 // Modifications copyright (c) 2014-2018 Oracle and/or its affiliates.
9 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
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)
15 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURNS_HPP
16 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURNS_HPP
22 #include <boost/array.hpp>
23 #include <boost/concept_check.hpp>
24 #include <boost/core/ignore_unused.hpp>
25 #include <boost/mpl/if.hpp>
26 #include <boost/mpl/vector_c.hpp>
27 #include <boost/range.hpp>
29 #include <boost/geometry/core/access.hpp>
30 #include <boost/geometry/core/assert.hpp>
31 #include <boost/geometry/core/coordinate_dimension.hpp>
32 #include <boost/geometry/core/exterior_ring.hpp>
33 #include <boost/geometry/core/interior_rings.hpp>
34 #include <boost/geometry/core/reverse_dispatch.hpp>
35 #include <boost/geometry/core/ring_type.hpp>
36 #include <boost/geometry/core/tags.hpp>
38 #include <boost/geometry/geometries/concepts/check.hpp>
40 #include <boost/geometry/util/math.hpp>
41 #include <boost/geometry/views/closeable_view.hpp>
42 #include <boost/geometry/views/reversible_view.hpp>
43 #include <boost/geometry/views/detail/range_type.hpp>
45 #include <boost/geometry/geometries/box.hpp>
46 #include <boost/geometry/geometries/segment.hpp>
48 #include <boost/geometry/iterators/ever_circling_iterator.hpp>
50 #include <boost/geometry/strategies/intersection_strategies.hpp>
51 #include <boost/geometry/strategies/intersection_result.hpp>
53 #include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
54 #include <boost/geometry/algorithms/detail/disjoint/point_point.hpp>
56 #include <boost/geometry/algorithms/detail/interior_iterator.hpp>
57 #include <boost/geometry/algorithms/detail/partition.hpp>
58 #include <boost/geometry/algorithms/detail/recalculate.hpp>
59 #include <boost/geometry/algorithms/detail/sections/section_box_policies.hpp>
61 #include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
62 #include <boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp>
63 #include <boost/geometry/algorithms/detail/overlay/get_turn_info_la.hpp>
64 #include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp>
66 #include <boost/geometry/algorithms/detail/sections/range_by_section.hpp>
67 #include <boost/geometry/algorithms/detail/sections/sectionalize.hpp>
68 #include <boost/geometry/algorithms/detail/sections/section_functions.hpp>
70 #ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION
72 # include <boost/geometry/io/dsv/write.hpp>
76 namespace boost { namespace geometry
79 // Silence warning C4127: conditional expression is constant
82 #pragma warning(disable : 4127)
86 #ifndef DOXYGEN_NO_DETAIL
87 namespace detail { namespace get_turns
91 struct no_interrupt_policy
93 static bool const enabled = false;
95 // variable required by self_get_turn_points::get_turns
96 static bool const has_intersections = false;
98 template <typename Range>
99 static inline bool apply(Range const&)
110 typename CircularIterator,
111 typename IntersectionStrategy,
112 typename RobustPolicy
114 struct unique_sub_range_from_section
116 typedef Point point_type;
118 unique_sub_range_from_section(Section const& section, signed_size_type index,
119 CircularIterator circular_iterator,
120 Point const& previous, Point const& current,
121 RobustPolicy const& robust_policy)
124 , m_previous_point(previous)
125 , m_current_point(current)
126 , m_circular_iterator(circular_iterator)
127 , m_point_retrieved(false)
128 , m_robust_policy(robust_policy)
132 inline bool is_first_segment() const
134 return !IsAreal && m_section.is_non_duplicate_first && m_index == m_section.begin_index;
136 inline bool is_last_segment() const
141 inline std::size_t size() const
144 : m_section.is_non_duplicate_last && m_index + 1 >= m_section.end_index ? 2 : 3;
147 inline Point const& at(std::size_t index) const
149 BOOST_GEOMETRY_ASSERT(index < size());
152 case 0 : return m_previous_point;
153 case 1 : return m_current_point;
154 case 2 : return get_next_point();
155 default : return m_previous_point;
160 inline Point const& get_next_point() const
162 if (! m_point_retrieved)
164 advance_to_non_duplicate_next(m_current_point, m_circular_iterator);
165 m_point = *m_circular_iterator;
166 m_point_retrieved = true;
171 inline void advance_to_non_duplicate_next(Point const& current, CircularIterator& circular_iterator) const
173 typedef typename IntersectionStrategy::point_in_point_strategy_type disjoint_strategy_type;
174 typedef typename robust_point_type<Point, RobustPolicy>::type robust_point_type;
175 robust_point_type current_robust_point;
176 robust_point_type next_robust_point;
177 geometry::recalculate(current_robust_point, current, m_robust_policy);
178 geometry::recalculate(next_robust_point, *circular_iterator, m_robust_policy);
180 // To see where the next segments bend to, in case of touch/intersections
181 // on end points, we need (in case of degenerate/duplicate points) an extra
182 // iterator which moves to the REAL next point, so non duplicate.
183 // This needs an extra comparison (disjoint).
184 // (Note that within sections, non duplicate points are already asserted,
185 // by the sectionalize process).
187 // So advance to the "non duplicate next"
188 // (the check is defensive, to avoid endless loops)
189 std::size_t check = 0;
190 while(! detail::disjoint::disjoint_point_point
192 current_robust_point, next_robust_point,
193 disjoint_strategy_type()
195 && check++ < m_section.range_count)
198 geometry::recalculate(next_robust_point, *circular_iterator, m_robust_policy);
202 Section const& m_section;
203 signed_size_type m_index;
204 Point const& m_previous_point;
205 Point const& m_current_point;
206 mutable CircularIterator m_circular_iterator;
207 mutable Point m_point;
208 mutable bool m_point_retrieved;
209 RobustPolicy m_robust_policy;
214 typename Geometry1, typename Geometry2,
215 bool Reverse1, bool Reverse2,
216 typename Section1, typename Section2,
219 class get_turns_in_sections
221 typedef typename closeable_view
223 typename range_type<Geometry1>::type const,
224 closure<Geometry1>::value
226 typedef typename closeable_view
228 typename range_type<Geometry2>::type const,
229 closure<Geometry2>::value
232 typedef typename reversible_view
235 Reverse1 ? iterate_reverse : iterate_forward
237 typedef typename reversible_view
240 Reverse2 ? iterate_reverse : iterate_forward
243 typedef typename boost::range_iterator
246 >::type range1_iterator;
248 typedef typename boost::range_iterator
251 >::type range2_iterator;
253 typedef ever_circling_iterator<range1_iterator> circular1_iterator;
254 typedef ever_circling_iterator<range2_iterator> circular2_iterator;
256 template <typename Geometry, typename Section>
257 static inline bool adjacent(Section const& section,
258 signed_size_type index1, signed_size_type index2)
261 // (square: range_count=5, indices 0,1,2,3
262 // -> 0-3 are adjacent, don't check on intersections)
263 // Also tested for open polygons, and/or duplicates
264 // About first condition: will be optimized by compiler (static)
265 // It checks if it is areal (box, ring, (multi)polygon)
266 signed_size_type const n = static_cast<signed_size_type>(section.range_count);
268 boost::ignore_unused(n, index1, index2);
270 return boost::is_same
274 typename geometry::tag<Geometry>::type,
286 // Returns true if terminated, false if interrupted
287 template <typename IntersectionStrategy, typename RobustPolicy, typename Turns, typename InterruptPolicy>
288 static inline bool apply(
289 int source_id1, Geometry1 const& geometry1, Section1 const& sec1,
290 int source_id2, Geometry2 const& geometry2, Section2 const& sec2,
291 bool skip_larger, bool skip_adjacent,
292 IntersectionStrategy const& intersection_strategy,
293 RobustPolicy const& robust_policy,
295 InterruptPolicy& interrupt_policy)
297 boost::ignore_unused(interrupt_policy);
299 static bool const areal1 = boost::is_same
301 typename tag_cast<typename tag<Geometry1>::type, areal_tag>::type,
304 static bool const areal2 = boost::is_same
306 typename tag_cast<typename tag<Geometry2>::type, areal_tag>::type,
311 if ((sec1.duplicate && (sec1.count + 1) < sec1.range_count)
312 || (sec2.duplicate && (sec2.count + 1) < sec2.range_count))
314 // Skip sections containig only duplicates.
315 // They are still important (can indicate non-disjointness)
316 // but they will be found processing adjacent sections.
317 // Do NOT skip if they are the ONLY section
321 cview_type1 cview1(range_by_section(geometry1, sec1));
322 cview_type2 cview2(range_by_section(geometry2, sec2));
323 view_type1 view1(cview1);
324 view_type2 view2(cview2);
326 range1_iterator begin_range_1 = boost::begin(view1);
327 range1_iterator end_range_1 = boost::end(view1);
329 range2_iterator begin_range_2 = boost::begin(view2);
330 range2_iterator end_range_2 = boost::end(view2);
332 int const dir1 = sec1.directions[0];
333 int const dir2 = sec2.directions[0];
334 signed_size_type index1 = sec1.begin_index;
335 signed_size_type ndi1 = sec1.non_duplicate_index;
337 range1_iterator prev1, it1, end1;
339 get_start_point_iterator(sec1, view1, prev1, it1, end1,
340 index1, ndi1, dir1, sec2.bounding_box, robust_policy);
342 // We need a circular iterator because it might run through the closing point.
343 // One circle is actually enough but this one is just convenient.
344 ever_circling_iterator<range1_iterator> next1(begin_range_1, end_range_1, it1, true);
347 // Walk through section and stop if we exceed the other box
348 // section 2: [--------------]
349 // section 1: |----|---|---|---|---|
350 for (prev1 = it1++, next1++;
351 it1 != end1 && ! detail::section::exceeding<0>(dir1, *prev1, sec1.bounding_box, sec2.bounding_box, robust_policy);
352 ++prev1, ++it1, ++index1, ++next1, ++ndi1)
354 unique_sub_range_from_section
356 areal1, Section1, point1_type, circular1_iterator,
357 IntersectionStrategy, RobustPolicy
358 > unique_sub_range1(sec1, index1,
359 circular1_iterator(begin_range_1, end_range_1, next1, true),
363 signed_size_type index2 = sec2.begin_index;
364 signed_size_type ndi2 = sec2.non_duplicate_index;
366 range2_iterator prev2, it2, end2;
368 get_start_point_iterator(sec2, view2, prev2, it2, end2,
369 index2, ndi2, dir2, sec1.bounding_box, robust_policy);
370 ever_circling_iterator<range2_iterator> next2(begin_range_2, end_range_2, it2, true);
373 for (prev2 = it2++, next2++;
374 it2 != end2 && ! detail::section::exceeding<0>(dir2, *prev2, sec2.bounding_box, sec1.bounding_box, robust_policy);
375 ++prev2, ++it2, ++index2, ++next2, ++ndi2)
379 if (source_id1 == source_id2
380 && sec1.ring_id.multi_index == sec2.ring_id.multi_index
381 && sec1.ring_id.ring_index == sec2.ring_id.ring_index)
383 // Sources and rings are the same
385 if (skip_larger && index1 >= index2)
387 // Skip to avoid getting all intersections twice
390 else if (skip_adjacent)
392 // In some cases (dissolve, has_self_intersections)
393 // neighbouring segments should be checked
394 // (for example to detect spikes properly)
396 // skip if it is a neighbouring segment.
397 // (including, for areas, first-last segment
398 // and two segments with one or more degenerate/duplicate
399 // (zero-length) segments in between)
400 skip = ndi2 == ndi1 + 1
401 || adjacent<Geometry1>(sec1, index1, index2);
407 unique_sub_range_from_section
409 areal2, Section2, point2_type, circular2_iterator,
410 IntersectionStrategy, RobustPolicy
411 > unique_sub_range2(sec2, index2,
412 circular2_iterator(begin_range_2, end_range_2, next2),
416 typedef typename boost::range_value<Turns>::type turn_info;
419 ti.operations[0].seg_id
420 = segment_identifier(source_id1, sec1.ring_id.multi_index,
421 sec1.ring_id.ring_index, index1);
422 ti.operations[1].seg_id
423 = segment_identifier(source_id2, sec2.ring_id.multi_index,
424 sec2.ring_id.ring_index, index2);
426 std::size_t const size_before = boost::size(turns);
428 TurnPolicy::apply(unique_sub_range1, unique_sub_range2,
429 ti, intersection_strategy, robust_policy,
430 std::back_inserter(turns));
432 if (InterruptPolicy::enabled)
434 if (interrupt_policy.apply(
435 std::make_pair(range::pos(turns, size_before),
449 typedef typename geometry::point_type<Geometry1>::type point1_type;
450 typedef typename geometry::point_type<Geometry2>::type point2_type;
451 typedef typename model::referring_segment<point1_type const> segment1_type;
452 typedef typename model::referring_segment<point2_type const> segment2_type;
454 // It is NOT possible to have section-iterators here
455 // because of the logistics of "index" (the section-iterator automatically
456 // skips to the begin-point, we loose the index or have to recalculate it)
457 // So we mimic it here
458 template <typename Range, typename Section, typename Box, typename RobustPolicy>
459 static inline void get_start_point_iterator(Section const& section,
461 typename boost::range_iterator<Range const>::type& it,
462 typename boost::range_iterator<Range const>::type& prev,
463 typename boost::range_iterator<Range const>::type& end,
464 signed_size_type& index, signed_size_type& ndi,
465 int dir, Box const& other_bounding_box, RobustPolicy const& robust_policy)
467 it = boost::begin(range) + section.begin_index;
468 end = boost::begin(range) + section.end_index + 1;
470 // Mimic section-iterator:
471 // Skip to point such that section interects other box
473 for(; it != end && detail::section::preceding<0>(dir, *it, section.bounding_box, other_bounding_box, robust_policy);
474 prev = it++, index++, ndi++)
476 // Go back one step because we want to start completely preceding
483 typename Geometry1, typename Geometry2,
484 bool Reverse1, bool Reverse2,
486 typename IntersectionStrategy,
487 typename RobustPolicy,
489 typename InterruptPolicy
491 struct section_visitor
494 Geometry1 const& m_geometry1;
496 Geometry2 const& m_geometry2;
497 IntersectionStrategy const& m_intersection_strategy;
498 RobustPolicy const& m_rescale_policy;
500 InterruptPolicy& m_interrupt_policy;
502 section_visitor(int id1, Geometry1 const& g1,
503 int id2, Geometry2 const& g2,
504 IntersectionStrategy const& intersection_strategy,
505 RobustPolicy const& robust_policy,
508 : m_source_id1(id1), m_geometry1(g1)
509 , m_source_id2(id2), m_geometry2(g2)
510 , m_intersection_strategy(intersection_strategy)
511 , m_rescale_policy(robust_policy)
513 , m_interrupt_policy(ip)
516 template <typename Section>
517 inline bool apply(Section const& sec1, Section const& sec2)
519 if (! detail::disjoint::disjoint_box_box(sec1.bounding_box,
521 m_intersection_strategy.get_disjoint_box_box_strategy()))
523 // false if interrupted
524 return get_turns_in_sections
531 >::apply(m_source_id1, m_geometry1, sec1,
532 m_source_id2, m_geometry2, sec2,
534 m_intersection_strategy,
536 m_turns, m_interrupt_policy);
545 typename Geometry1, typename Geometry2,
546 bool Reverse1, bool Reverse2,
549 class get_turns_generic
553 template <typename IntersectionStrategy, typename RobustPolicy, typename Turns, typename InterruptPolicy>
554 static inline void apply(
555 int source_id1, Geometry1 const& geometry1,
556 int source_id2, Geometry2 const& geometry2,
557 IntersectionStrategy const& intersection_strategy,
558 RobustPolicy const& robust_policy,
560 InterruptPolicy& interrupt_policy)
562 // First create monotonic sections...
563 typedef typename boost::range_value<Turns>::type ip_type;
564 typedef typename ip_type::point_type point_type;
568 typename geometry::robust_point_type
570 point_type, RobustPolicy
573 typedef geometry::sections<box_type, 2> sections_type;
575 sections_type sec1, sec2;
576 typedef boost::mpl::vector_c<std::size_t, 0, 1> dimensions;
578 typename IntersectionStrategy::envelope_strategy_type const
579 envelope_strategy = intersection_strategy.get_envelope_strategy();
580 typename IntersectionStrategy::expand_strategy_type const
581 expand_strategy = intersection_strategy.get_expand_strategy();
583 geometry::sectionalize<Reverse1, dimensions>(geometry1, robust_policy,
584 sec1, envelope_strategy, expand_strategy, 0);
585 geometry::sectionalize<Reverse2, dimensions>(geometry2, robust_policy,
586 sec2, envelope_strategy, expand_strategy, 1);
588 // ... and then partition them, intersecting overlapping sections in visitor method
591 Geometry1, Geometry2,
594 IntersectionStrategy, RobustPolicy,
595 Turns, InterruptPolicy
596 > visitor(source_id1, geometry1, source_id2, geometry2,
597 intersection_strategy, robust_policy,
598 turns, interrupt_policy);
600 typedef detail::section::get_section_box
602 typename IntersectionStrategy::expand_box_strategy_type
603 > get_section_box_type;
604 typedef detail::section::overlaps_section_box
606 typename IntersectionStrategy::disjoint_box_box_strategy_type
607 > overlaps_section_box_type;
612 >::apply(sec1, sec2, visitor,
613 get_section_box_type(),
614 overlaps_section_box_type());
619 // Get turns for a range with a box, following Cohen-Sutherland (cs) approach
622 typename Range, typename Box,
623 bool ReverseRange, bool ReverseBox,
628 typedef typename geometry::point_type<Range>::type range_point_type;
629 typedef typename geometry::point_type<Box>::type box_point_type;
630 typedef boost::array<box_point_type, 4> box_array;
632 typedef typename closeable_view
635 closure<Range>::value
638 typedef typename reversible_view
641 ReverseRange ? iterate_reverse : iterate_forward
644 typedef typename boost::range_iterator
647 >::type iterator_type;
649 struct unique_sub_range_from_box_policy
651 typedef box_point_type point_type;
653 unique_sub_range_from_box_policy(box_array const& box)
658 static inline bool is_first_segment() { return false; }
659 static inline bool is_last_segment() { return false; }
660 static inline std::size_t size() { return 4; }
662 inline box_point_type const& at(std::size_t index) const
664 BOOST_GEOMETRY_ASSERT(index < size());
665 return m_box[(m_index + index) % 4];
674 box_array const& m_box;
678 struct unique_sub_range_from_view_policy
680 typedef range_point_type point_type;
682 unique_sub_range_from_view_policy(view_type const& view, point_type const& pi, point_type const& pj, iterator_type it)
686 , m_circular_iterator(boost::begin(view), boost::end(view), it, true)
688 ++m_circular_iterator;
691 static inline bool is_first_segment() { return false; }
692 static inline bool is_last_segment() { return false; }
693 static inline std::size_t size() { return 3; }
695 inline point_type const& at(std::size_t index) const
697 BOOST_GEOMETRY_ASSERT(index < size());
700 case 0 : return m_pi;
701 case 1 : return m_pj;
702 case 2 : return *m_circular_iterator;
703 default : return m_pi;
708 view_type const& m_view;
709 point_type const& m_pi;
710 point_type const& m_pj;
711 ever_circling_iterator<iterator_type> m_circular_iterator;
714 template <typename IntersectionStrategy, typename RobustPolicy, typename Turns, typename InterruptPolicy>
715 static inline void apply(
716 int source_id1, Range const& range,
717 int source_id2, Box const& box,
718 IntersectionStrategy const& intersection_strategy,
719 RobustPolicy const& robust_policy,
721 InterruptPolicy& interrupt_policy,
722 signed_size_type multi_index = -1,
723 signed_size_type ring_index = -1)
725 if ( boost::size(range) <= 1)
730 box_array box_points;
731 assign_box_corners_oriented<ReverseBox>(box, box_points);
733 cview_type cview(range);
734 view_type view(cview);
736 // TODO: in this code, possible duplicate points are not yet taken
737 // into account (not in the iterator, nor in the retrieve policy)
738 iterator_type it = boost::begin(view);
742 //char previous_side[2] = {0, 0};
744 signed_size_type index = 0;
746 for (iterator_type prev = it++;
747 it != boost::end(view);
748 prev = it++, index++)
750 segment_identifier seg_id(source_id1,
751 multi_index, ring_index, index);
753 unique_sub_range_from_view_policy view_unique_sub_range(view, *prev, *it, it);
757 previous_side[0] = get_side<0>(box, *prev);
758 previous_side[1] = get_side<1>(box, *prev);
761 char current_side[2];
762 current_side[0] = get_side<0>(box, *it);
763 current_side[1] = get_side<1>(box, *it);
765 // There can NOT be intersections if
766 // 1) EITHER the two points are lying on one side of the box (! 0 && the same)
767 // 2) OR same in Y-direction
768 // 3) OR all points are inside the box (0)
770 (current_side[0] != 0 && current_side[0] == previous_side[0])
771 || (current_side[1] != 0 && current_side[1] == previous_side[1])
772 || (current_side[0] == 0
773 && current_side[1] == 0
774 && previous_side[0] == 0
775 && previous_side[1] == 0)
780 get_turns_with_box(seg_id, source_id2,
781 view_unique_sub_range,
783 intersection_strategy,
787 // Future performance enhancement:
788 // return if told by the interrupt policy
794 template<std::size_t Index, typename Point>
795 static inline int get_side(Box const& box, Point const& point)
798 // Outside -> -1 (left/below) or 1 (right/above)
799 // On border -> -2 (left/lower) or 2 (right/upper)
800 // The only purpose of the value is to not be the same,
801 // and to denote if it is inside (0)
803 typename coordinate_type<Point>::type const& c = get<Index>(point);
804 typename coordinate_type<Box>::type const& left = get<min_corner, Index>(box);
805 typename coordinate_type<Box>::type const& right = get<max_corner, Index>(box);
807 if (geometry::math::equals(c, left)) return -2;
808 else if (geometry::math::equals(c, right)) return 2;
809 else if (c < left) return -1;
810 else if (c > right) return 1;
816 typename IntersectionStrategy,
818 typename InterruptPolicy,
819 typename RobustPolicy
821 static inline void get_turns_with_box(segment_identifier const& seg_id, int source_id2,
822 unique_sub_range_from_view_policy const& range_unique_sub_range,
823 box_array const& box,
824 IntersectionStrategy const& intersection_strategy,
825 RobustPolicy const& robust_policy,
828 InterruptPolicy& interrupt_policy)
830 boost::ignore_unused(interrupt_policy);
832 // Depending on code some relations can be left out
834 typedef typename boost::range_value<Turns>::type turn_info;
837 ti.operations[0].seg_id = seg_id;
839 unique_sub_range_from_box_policy box_unique_sub_range(box);
840 ti.operations[1].seg_id = segment_identifier(source_id2, -1, -1, 0);
841 TurnPolicy::apply(range_unique_sub_range, box_unique_sub_range,
842 ti, intersection_strategy, robust_policy,
843 std::back_inserter(turns));
845 ti.operations[1].seg_id = segment_identifier(source_id2, -1, -1, 1);
846 box_unique_sub_range.next();
847 TurnPolicy::apply(range_unique_sub_range, box_unique_sub_range,
848 ti, intersection_strategy, robust_policy,
849 std::back_inserter(turns));
851 ti.operations[1].seg_id = segment_identifier(source_id2, -1, -1, 2);
852 box_unique_sub_range.next();
853 TurnPolicy::apply(range_unique_sub_range, box_unique_sub_range,
854 ti, intersection_strategy, robust_policy,
855 std::back_inserter(turns));
857 ti.operations[1].seg_id = segment_identifier(source_id2, -1, -1, 3);
858 box_unique_sub_range.next();
859 TurnPolicy::apply(range_unique_sub_range, box_unique_sub_range,
860 ti, intersection_strategy, robust_policy,
861 std::back_inserter(turns));
863 if (InterruptPolicy::enabled)
865 interrupt_policy.apply(turns);
875 typename Polygon, typename Box,
876 bool Reverse, bool ReverseBox,
879 struct get_turns_polygon_cs
881 template <typename IntersectionStrategy, typename RobustPolicy, typename Turns, typename InterruptPolicy>
882 static inline void apply(
883 int source_id1, Polygon const& polygon,
884 int source_id2, Box const& box,
885 IntersectionStrategy const& intersection_strategy,
886 RobustPolicy const& robust_policy,
888 InterruptPolicy& interrupt_policy,
889 signed_size_type multi_index = -1)
891 typedef typename geometry::ring_type<Polygon>::type ring_type;
893 typedef detail::get_turns::get_turns_cs
900 intersector_type::apply(
901 source_id1, geometry::exterior_ring(polygon),
903 intersection_strategy,
909 signed_size_type i = 0;
911 typename interior_return_type<Polygon const>::type
912 rings = interior_rings(polygon);
913 for (typename detail::interior_iterator<Polygon const>::type
914 it = boost::begin(rings); it != boost::end(rings); ++it, ++i)
916 intersector_type::apply(
919 intersection_strategy,
921 turns, interrupt_policy,
931 typename Multi, typename Box,
932 bool Reverse, bool ReverseBox,
935 struct get_turns_multi_polygon_cs
937 template <typename IntersectionStrategy, typename RobustPolicy, typename Turns, typename InterruptPolicy>
938 static inline void apply(
939 int source_id1, Multi const& multi,
940 int source_id2, Box const& box,
941 IntersectionStrategy const& intersection_strategy,
942 RobustPolicy const& robust_policy,
944 InterruptPolicy& interrupt_policy)
946 typedef typename boost::range_iterator
949 >::type iterator_type;
951 signed_size_type i = 0;
952 for (iterator_type it = boost::begin(multi);
953 it != boost::end(multi);
956 // Call its single version
959 typename boost::range_value<Multi>::type, Box,
962 >::apply(source_id1, *it, source_id2, box,
963 intersection_strategy, robust_policy,
964 turns, interrupt_policy, i);
970 // GET_TURN_INFO_TYPE
972 template <typename Geometry>
973 struct topological_tag_base
975 typedef typename tag_cast<typename tag<Geometry>::type, pointlike_tag, linear_tag, areal_tag>::type type;
978 template <typename Geometry1, typename Geometry2, typename AssignPolicy,
979 typename Tag1 = typename tag<Geometry1>::type, typename Tag2 = typename tag<Geometry2>::type,
980 typename TagBase1 = typename topological_tag_base<Geometry1>::type, typename TagBase2 = typename topological_tag_base<Geometry2>::type>
981 struct get_turn_info_type
982 : overlay::get_turn_info<AssignPolicy>
985 template <typename Geometry1, typename Geometry2, typename AssignPolicy, typename Tag1, typename Tag2>
986 struct get_turn_info_type<Geometry1, Geometry2, AssignPolicy, Tag1, Tag2, linear_tag, linear_tag>
987 : overlay::get_turn_info_linear_linear<AssignPolicy>
990 template <typename Geometry1, typename Geometry2, typename AssignPolicy, typename Tag1, typename Tag2>
991 struct get_turn_info_type<Geometry1, Geometry2, AssignPolicy, Tag1, Tag2, linear_tag, areal_tag>
992 : overlay::get_turn_info_linear_areal<AssignPolicy>
995 template <typename Geometry1, typename Geometry2, typename SegmentRatio,
996 typename Tag1 = typename tag<Geometry1>::type, typename Tag2 = typename tag<Geometry2>::type,
997 typename TagBase1 = typename topological_tag_base<Geometry1>::type, typename TagBase2 = typename topological_tag_base<Geometry2>::type>
998 struct turn_operation_type
1000 typedef overlay::turn_operation<typename point_type<Geometry1>::type, SegmentRatio> type;
1003 template <typename Geometry1, typename Geometry2, typename SegmentRatio, typename Tag1, typename Tag2>
1004 struct turn_operation_type<Geometry1, Geometry2, SegmentRatio, Tag1, Tag2, linear_tag, linear_tag>
1006 typedef overlay::turn_operation_linear<typename point_type<Geometry1>::type, SegmentRatio> type;
1009 template <typename Geometry1, typename Geometry2, typename SegmentRatio, typename Tag1, typename Tag2>
1010 struct turn_operation_type<Geometry1, Geometry2, SegmentRatio, Tag1, Tag2, linear_tag, areal_tag>
1012 typedef overlay::turn_operation_linear<typename point_type<Geometry1>::type, SegmentRatio> type;
1015 }} // namespace detail::get_turns
1016 #endif // DOXYGEN_NO_DETAIL
1019 #ifndef DOXYGEN_NO_DISPATCH
1023 // Because this is "detail" method, and most implementations will use "generic",
1024 // we take the freedom to derive it from "generic".
1027 typename GeometryTag1, typename GeometryTag2,
1028 typename Geometry1, typename Geometry2,
1029 bool Reverse1, bool Reverse2,
1033 : detail::get_turns::get_turns_generic
1035 Geometry1, Geometry2,
1044 typename Polygon, typename Box,
1045 bool ReversePolygon, bool ReverseBox,
1050 polygon_tag, box_tag,
1052 ReversePolygon, ReverseBox,
1054 > : detail::get_turns::get_turns_polygon_cs
1057 ReversePolygon, ReverseBox,
1065 typename Ring, typename Box,
1066 bool ReverseRing, bool ReverseBox,
1073 ReverseRing, ReverseBox,
1075 > : detail::get_turns::get_turns_cs
1077 Ring, Box, ReverseRing, ReverseBox,
1086 typename MultiPolygon,
1088 bool ReverseMultiPolygon, bool ReverseBox,
1093 multi_polygon_tag, box_tag,
1095 ReverseMultiPolygon, ReverseBox,
1098 : detail::get_turns::get_turns_multi_polygon_cs
1101 ReverseMultiPolygon, ReverseBox,
1109 typename GeometryTag1, typename GeometryTag2,
1110 typename Geometry1, typename Geometry2,
1111 bool Reverse1, bool Reverse2,
1114 struct get_turns_reversed
1116 template <typename IntersectionStrategy, typename RobustPolicy, typename Turns, typename InterruptPolicy>
1117 static inline void apply(int source_id1, Geometry1 const& g1,
1118 int source_id2, Geometry2 const& g2,
1119 IntersectionStrategy const& intersection_strategy,
1120 RobustPolicy const& robust_policy,
1122 InterruptPolicy& interrupt_policy)
1126 GeometryTag2, GeometryTag1,
1127 Geometry2, Geometry1,
1130 >::apply(source_id2, g2, source_id1, g1,
1131 intersection_strategy, robust_policy,
1132 turns, interrupt_policy);
1137 } // namespace dispatch
1138 #endif // DOXYGEN_NO_DISPATCH
1143 \brief \brief_calc2{turn points}
1145 \tparam Geometry1 \tparam_geometry
1146 \tparam Geometry2 \tparam_geometry
1147 \tparam Turns type of turn-container (e.g. vector of "intersection/turn point"'s)
1148 \param geometry1 \param_geometry
1149 \param geometry2 \param_geometry
1150 \param intersection_strategy segments intersection strategy
1151 \param robust_policy policy to handle robustness issues
1152 \param turns container which will contain turn points
1153 \param interrupt_policy policy determining if process is stopped
1154 when intersection is found
1158 bool Reverse1, bool Reverse2,
1159 typename AssignPolicy,
1162 typename IntersectionStrategy,
1163 typename RobustPolicy,
1165 typename InterruptPolicy
1167 inline void get_turns(Geometry1 const& geometry1,
1168 Geometry2 const& geometry2,
1169 IntersectionStrategy const& intersection_strategy,
1170 RobustPolicy const& robust_policy,
1172 InterruptPolicy& interrupt_policy)
1174 concepts::check_concepts_and_equal_dimensions<Geometry1 const, Geometry2 const>();
1176 typedef detail::overlay::get_turn_info<AssignPolicy> TurnPolicy;
1177 //typedef detail::get_turns::get_turn_info_type<Geometry1, Geometry2, AssignPolicy> TurnPolicy;
1181 reverse_dispatch<Geometry1, Geometry2>::type::value,
1182 dispatch::get_turns_reversed
1184 typename tag<Geometry1>::type,
1185 typename tag<Geometry2>::type,
1186 Geometry1, Geometry2,
1192 typename tag<Geometry1>::type,
1193 typename tag<Geometry2>::type,
1194 Geometry1, Geometry2,
1198 >::type::apply(0, geometry1,
1200 intersection_strategy,
1202 turns, interrupt_policy);
1205 #if defined(_MSC_VER)
1206 #pragma warning(pop)
1209 }} // namespace boost::geometry
1211 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURNS_HPP