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