]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/geometry/include/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / geometry / include / boost / geometry / algorithms / detail / overlay / get_turn_info.hpp
1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2
3 // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
4
5 // This file was modified by Oracle on 2015.
6 // Modifications copyright (c) 2015 Oracle and/or its affiliates.
7
8 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
9
10 // Use, modification and distribution is subject to the Boost Software License,
11 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
12 // http://www.boost.org/LICENSE_1_0.txt)
13
14 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HPP
15 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HPP
16
17
18 #include <boost/core/ignore_unused.hpp>
19
20 #include <boost/geometry/core/access.hpp>
21 #include <boost/geometry/core/assert.hpp>
22 #include <boost/geometry/strategies/intersection_strategies.hpp>
23
24 #include <boost/geometry/algorithms/convert.hpp>
25 #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
26 #include <boost/geometry/algorithms/detail/recalculate.hpp>
27
28 #include <boost/geometry/geometries/segment.hpp>
29
30 #include <boost/geometry/policies/robustness/robust_point_type.hpp>
31 #include <boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp>
32
33 // Silence warning C4127: conditional expression is constant
34 #if defined(_MSC_VER)
35 #pragma warning(push)
36 #pragma warning(disable : 4127)
37 #endif
38
39
40 namespace boost { namespace geometry
41 {
42
43 #if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW)
44 class turn_info_exception : public geometry::exception
45 {
46 std::string message;
47 public:
48
49 // NOTE: "char" will be replaced by enum in future version
50 inline turn_info_exception(char const method)
51 {
52 message = "Boost.Geometry Turn exception: ";
53 message += method;
54 }
55
56 virtual ~turn_info_exception() throw()
57 {}
58
59 virtual char const* what() const throw()
60 {
61 return message.c_str();
62 }
63 };
64 #endif
65
66 #ifndef DOXYGEN_NO_DETAIL
67 namespace detail { namespace overlay
68 {
69
70 struct base_turn_handler
71 {
72 // Returns true if both sides are opposite
73 static inline bool opposite(int side1, int side2)
74 {
75 // We cannot state side1 == -side2, because 0 == -0
76 // So either side1*side2==-1 or side1==-side2 && side1 != 0
77 return side1 * side2 == -1;
78 }
79
80 // Same side of a segment (not being 0)
81 static inline bool same(int side1, int side2)
82 {
83 return side1 * side2 == 1;
84 }
85
86 // Both continue
87 template <typename TurnInfo>
88 static inline void both(TurnInfo& ti, operation_type const op)
89 {
90 ti.operations[0].operation = op;
91 ti.operations[1].operation = op;
92 }
93
94 // If condition, first union/second intersection, else vice versa
95 template <typename TurnInfo>
96 static inline void ui_else_iu(bool condition, TurnInfo& ti)
97 {
98 ti.operations[0].operation = condition
99 ? operation_union : operation_intersection;
100 ti.operations[1].operation = condition
101 ? operation_intersection : operation_union;
102 }
103
104 // If condition, both union, else both intersection
105 template <typename TurnInfo>
106 static inline void uu_else_ii(bool condition, TurnInfo& ti)
107 {
108 both(ti, condition ? operation_union : operation_intersection);
109 }
110
111 template <typename TurnInfo, typename IntersectionInfo>
112 static inline void assign_point(TurnInfo& ti,
113 method_type method,
114 IntersectionInfo const& info, unsigned int index)
115 {
116 ti.method = method;
117
118 BOOST_GEOMETRY_ASSERT(index < info.count);
119
120 geometry::convert(info.intersections[index], ti.point);
121 ti.operations[0].fraction = info.fractions[index].robust_ra;
122 ti.operations[1].fraction = info.fractions[index].robust_rb;
123 }
124
125 template <typename IntersectionInfo>
126 static inline unsigned int non_opposite_to_index(IntersectionInfo const& info)
127 {
128 return info.fractions[0].robust_rb < info.fractions[1].robust_rb
129 ? 1 : 0;
130 }
131
132 };
133
134
135 template
136 <
137 typename TurnInfo
138 >
139 struct touch_interior : public base_turn_handler
140 {
141 // Index: 0, P is the interior, Q is touching and vice versa
142 template
143 <
144 unsigned int Index,
145 typename Point1,
146 typename Point2,
147 typename IntersectionInfo,
148 typename DirInfo,
149 typename SidePolicy
150 >
151 static inline void apply(
152 Point1 const& , Point1 const& , Point1 const& ,
153 Point2 const& , Point2 const& , Point2 const& ,
154 TurnInfo& ti,
155 IntersectionInfo const& intersection_info,
156 DirInfo const& dir_info,
157 SidePolicy const& side)
158 {
159 assign_point(ti, method_touch_interior, intersection_info, 0);
160
161 // Both segments of q touch segment p somewhere in its interior
162 // 1) We know: if q comes from LEFT or RIGHT
163 // (i.e. dir_info.sides.get<Index,0>() == 1 or -1)
164 // 2) Important is: if q_k goes to LEFT, RIGHT, COLLINEAR
165 // and, if LEFT/COLL, if it is lying LEFT or RIGHT w.r.t. q_i
166
167 BOOST_STATIC_ASSERT(Index <= 1);
168 static unsigned int const index_p = Index;
169 static unsigned int const index_q = 1 - Index;
170
171 int const side_qi_p = dir_info.sides.template get<index_q, 0>();
172 int const side_qk_p = side.qk_wrt_p1();
173
174 if (side_qi_p == -side_qk_p)
175 {
176 // Q crosses P from left->right or from right->left (test "ML1")
177 // Union: folow P (left->right) or Q (right->left)
178 // Intersection: other turn
179 unsigned int index = side_qk_p == -1 ? index_p : index_q;
180 ti.operations[index].operation = operation_union;
181 ti.operations[1 - index].operation = operation_intersection;
182 return;
183 }
184
185 int const side_qk_q = side.qk_wrt_q1();
186
187 if (side_qi_p == -1 && side_qk_p == -1 && side_qk_q == 1)
188 {
189 // Q turns left on the right side of P (test "MR3")
190 // Both directions for "intersection"
191 both(ti, operation_intersection);
192 }
193 else if (side_qi_p == 1 && side_qk_p == 1 && side_qk_q == -1)
194 {
195 // Q turns right on the left side of P (test "ML3")
196 // Union: take both operation
197 // Intersection: skip
198 both(ti, operation_union);
199 }
200 else if (side_qi_p == side_qk_p && side_qi_p == side_qk_q)
201 {
202 // Q turns left on the left side of P (test "ML2")
203 // or Q turns right on the right side of P (test "MR2")
204 // Union: take left turn (Q if Q turns left, P if Q turns right)
205 // Intersection: other turn
206 unsigned int index = side_qk_q == 1 ? index_q : index_p;
207 ti.operations[index].operation = operation_union;
208 ti.operations[1 - index].operation = operation_intersection;
209 }
210 else if (side_qk_p == 0)
211 {
212 // Q intersects on interior of P and continues collinearly
213 if (side_qk_q == side_qi_p)
214 {
215 // Collinearly in the same direction
216 // (Q comes from left of P and turns left,
217 // OR Q comes from right of P and turns right)
218 // Omit intersection point.
219 // Union: just continue
220 // Intersection: just continue
221 both(ti, operation_continue);
222 }
223 else
224 {
225 // Opposite direction, which is never travelled.
226 // If Q turns left, P continues for intersection
227 // If Q turns right, P continues for union
228 ti.operations[index_p].operation = side_qk_q == 1
229 ? operation_intersection
230 : operation_union;
231 ti.operations[index_q].operation = operation_blocked;
232 }
233 }
234 else
235 {
236 // Should not occur!
237 ti.method = method_error;
238 }
239 }
240 };
241
242
243 template
244 <
245 typename TurnInfo
246 >
247 struct touch : public base_turn_handler
248 {
249 static inline bool between(int side1, int side2, int turn)
250 {
251 return side1 == side2 && ! opposite(side1, turn);
252 }
253
254 /*static inline void block_second(bool block, TurnInfo& ti)
255 {
256 if (block)
257 {
258 ti.operations[1].operation = operation_blocked;
259 }
260 }*/
261
262
263 template
264 <
265 typename Point1,
266 typename Point2,
267 typename IntersectionInfo,
268 typename DirInfo,
269 typename SidePolicy
270 >
271 static inline void apply(
272 Point1 const& , Point1 const& , Point1 const& ,
273 Point2 const& , Point2 const& , Point2 const& ,
274 TurnInfo& ti,
275 IntersectionInfo const& intersection_info,
276 DirInfo const& dir_info,
277 SidePolicy const& side)
278 {
279 assign_point(ti, method_touch, intersection_info, 0);
280
281 int const side_qi_p1 = dir_info.sides.template get<1, 0>();
282 int const side_qk_p1 = side.qk_wrt_p1();
283
284
285 // If Qi and Qk are both at same side of Pi-Pj,
286 // or collinear (so: not opposite sides)
287 if (! opposite(side_qi_p1, side_qk_p1))
288 {
289 int const side_pk_q2 = side.pk_wrt_q2();
290 int const side_pk_p = side.pk_wrt_p1();
291 int const side_qk_q = side.qk_wrt_q1();
292
293 bool const q_turns_left = side_qk_q == 1;
294 bool const block_q = side_qk_p1 == 0
295 && ! same(side_qi_p1, side_qk_q)
296 ;
297
298 // If Pk at same side as Qi/Qk
299 // (the "or" is for collinear case)
300 // or Q is fully collinear && P turns not to left
301 if (side_pk_p == side_qi_p1
302 || side_pk_p == side_qk_p1
303 || (side_qi_p1 == 0 && side_qk_p1 == 0 && side_pk_p != -1)
304 )
305 {
306 // Collinear -> lines join, continue
307 // (#BRL2)
308 if (side_pk_q2 == 0 && ! block_q)
309 {
310 both(ti, operation_continue);
311 return;
312 }
313
314 int const side_pk_q1 = side.pk_wrt_q1();
315
316
317 // Collinear opposite case -> block P
318 // (#BRL4, #BLR8)
319 if (side_pk_q1 == 0)
320 {
321 ti.operations[0].operation = operation_blocked;
322 // Q turns right -> union (both independent),
323 // Q turns left -> intersection
324 ti.operations[1].operation = block_q ? operation_blocked
325 : q_turns_left ? operation_intersection
326 : operation_union;
327 return;
328 }
329
330 // Pk between Qi and Qk
331 // (#BRL3, #BRL7)
332 if (between(side_pk_q1, side_pk_q2, side_qk_q))
333 {
334 ui_else_iu(q_turns_left, ti);
335 if (block_q)
336 {
337 ti.operations[1].operation = operation_blocked;
338 }
339 //block_second(block_q, ti);
340 return;
341 }
342
343 // Pk between Qk and P, so left of Qk (if Q turns right) and vv
344 // (#BRL1)
345 if (side_pk_q2 == -side_qk_q)
346 {
347 ui_else_iu(! q_turns_left, ti);
348 return;
349 }
350
351 //
352 // (#BRL5, #BRL9)
353 if (side_pk_q1 == -side_qk_q)
354 {
355 uu_else_ii(! q_turns_left, ti);
356 if (block_q)
357 {
358 ti.operations[1].operation = operation_blocked;
359 }
360 //block_second(block_q, ti);
361 return;
362 }
363 }
364 else
365 {
366 // Pk at other side than Qi/Pk
367 ti.operations[0].operation = q_turns_left
368 ? operation_intersection
369 : operation_union;
370 ti.operations[1].operation = block_q
371 ? operation_blocked
372 : side_qi_p1 == 1 || side_qk_p1 == 1
373 ? operation_union
374 : operation_intersection;
375
376 return;
377 }
378 }
379 else
380 {
381 // From left to right or from right to left
382 int const side_pk_p = side.pk_wrt_p1();
383 bool const right_to_left = side_qk_p1 == 1;
384
385 // If p turns into direction of qi (1,2)
386 if (side_pk_p == side_qi_p1)
387 {
388 int const side_pk_q1 = side.pk_wrt_q1();
389
390 // Collinear opposite case -> block P
391 if (side_pk_q1 == 0)
392 {
393 ti.operations[0].operation = operation_blocked;
394 ti.operations[1].operation = right_to_left
395 ? operation_union : operation_intersection;
396 return;
397 }
398
399 if (side_pk_q1 == side_qk_p1)
400 {
401 uu_else_ii(right_to_left, ti);
402 return;
403 }
404 }
405
406 // If p turns into direction of qk (4,5)
407 if (side_pk_p == side_qk_p1)
408 {
409 int const side_pk_q2 = side.pk_wrt_q2();
410
411 // Collinear case -> lines join, continue
412 if (side_pk_q2 == 0)
413 {
414 both(ti, operation_continue);
415 return;
416 }
417 if (side_pk_q2 == side_qk_p1)
418 {
419 ui_else_iu(right_to_left, ti);
420 return;
421 }
422 }
423 // otherwise (3)
424 ui_else_iu(! right_to_left, ti);
425 return;
426 }
427
428 #ifdef BOOST_GEOMETRY_DEBUG_GET_TURNS
429 // Normally a robustness issue.
430 // TODO: more research if still occuring
431 std::cout << "Not yet handled" << std::endl
432 << "pi " << get<0>(pi) << " , " << get<1>(pi)
433 << " pj " << get<0>(pj) << " , " << get<1>(pj)
434 << " pk " << get<0>(pk) << " , " << get<1>(pk)
435 << std::endl
436 << "qi " << get<0>(qi) << " , " << get<1>(qi)
437 << " qj " << get<0>(qj) << " , " << get<1>(qj)
438 << " qk " << get<0>(qk) << " , " << get<1>(qk)
439 << std::endl;
440 #endif
441
442 }
443 };
444
445
446 template
447 <
448 typename TurnInfo
449 >
450 struct equal : public base_turn_handler
451 {
452 template
453 <
454 typename Point1,
455 typename Point2,
456 typename IntersectionInfo,
457 typename DirInfo,
458 typename SidePolicy
459 >
460 static inline void apply(
461 Point1 const& , Point1 const& , Point1 const& ,
462 Point2 const& , Point2 const& , Point2 const& ,
463 TurnInfo& ti,
464 IntersectionInfo const& info,
465 DirInfo const& ,
466 SidePolicy const& side)
467 {
468 // Copy the intersection point in TO direction
469 assign_point(ti, method_equal, info, non_opposite_to_index(info));
470
471 int const side_pk_q2 = side.pk_wrt_q2();
472 int const side_pk_p = side.pk_wrt_p1();
473 int const side_qk_p = side.qk_wrt_p1();
474
475
476 // If pk is collinear with qj-qk, they continue collinearly.
477 // This can be on either side of p1 (== q1), or collinear
478 // The second condition checks if they do not continue
479 // oppositely
480 if (side_pk_q2 == 0 && side_pk_p == side_qk_p)
481 {
482 both(ti, operation_continue);
483
484 return;
485 }
486
487
488 // If they turn to same side (not opposite sides)
489 if (! opposite(side_pk_p, side_qk_p))
490 {
491 // If pk is left of q2 or collinear: p: union, q: intersection
492 ui_else_iu(side_pk_q2 != -1, ti);
493 }
494 else
495 {
496 // They turn opposite sides. If p turns left (or collinear),
497 // p: union, q: intersection
498 ui_else_iu(side_pk_p != -1, ti);
499 }
500 }
501 };
502
503
504 template
505 <
506 typename TurnInfo,
507 typename AssignPolicy
508 >
509 struct equal_opposite : public base_turn_handler
510 {
511 template
512 <
513 typename Point1,
514 typename Point2,
515 typename OutputIterator,
516 typename IntersectionInfo
517 >
518 static inline void apply(Point1 const& pi, Point2 const& qi,
519 /* by value: */ TurnInfo tp,
520 OutputIterator& out,
521 IntersectionInfo const& intersection_info)
522 {
523 // For equal-opposite segments, normally don't do anything.
524 if (AssignPolicy::include_opposite)
525 {
526 tp.method = method_equal;
527 for (unsigned int i = 0; i < 2; i++)
528 {
529 tp.operations[i].operation = operation_opposite;
530 }
531 for (unsigned int i = 0; i < intersection_info.i_info().count; i++)
532 {
533 assign_point(tp, method_none, intersection_info.i_info(), i);
534 AssignPolicy::apply(tp, pi, qi, intersection_info);
535 *out++ = tp;
536 }
537 }
538 }
539 };
540
541 template
542 <
543 typename TurnInfo
544 >
545 struct collinear : public base_turn_handler
546 {
547 /*
548 arrival P pk//p1 qk//q1 product* case result
549 1 1 1 CLL1 ui
550 -1 1 -1 CLL2 iu
551 1 1 1 CLR1 ui
552 -1 -1 1 CLR2 ui
553
554 1 -1 -1 CRL1 iu
555 -1 1 -1 CRL2 iu
556 1 -1 -1 CRR1 iu
557 -1 -1 1 CRR2 ui
558
559 1 0 0 CC1 cc
560 -1 0 0 CC2 cc
561
562 *product = arrival * (pk//p1 or qk//q1)
563
564 Stated otherwise:
565 - if P arrives: look at turn P
566 - if Q arrives: look at turn Q
567 - if P arrives and P turns left: union for P
568 - if P arrives and P turns right: intersection for P
569 - if Q arrives and Q turns left: union for Q (=intersection for P)
570 - if Q arrives and Q turns right: intersection for Q (=union for P)
571
572 ROBUSTNESS: p and q are collinear, so you would expect
573 that side qk//p1 == pk//q1. But that is not always the case
574 in near-epsilon ranges. Then decision logic is different.
575 If p arrives, q is further, so the angle qk//p1 is (normally)
576 more precise than pk//p1
577
578 */
579 template
580 <
581 typename Point1,
582 typename Point2,
583 typename IntersectionInfo,
584 typename DirInfo,
585 typename SidePolicy
586 >
587 static inline void apply(
588 Point1 const& , Point1 const& pj, Point1 const& pk,
589 Point2 const& , Point2 const& qj, Point2 const& qk,
590 TurnInfo& ti,
591 IntersectionInfo const& info,
592 DirInfo const& dir_info,
593 SidePolicy const& side)
594 {
595 // Copy the intersection point in TO direction
596 assign_point(ti, method_collinear, info, non_opposite_to_index(info));
597
598 int const arrival = dir_info.arrival[0];
599 // Should not be 0, this is checked before
600 BOOST_GEOMETRY_ASSERT(arrival != 0);
601
602 int const side_p = side.pk_wrt_p1();
603 int const side_q = side.qk_wrt_q1();
604
605 // If p arrives, use p, else use q
606 int const side_p_or_q = arrival == 1
607 ? side_p
608 : side_q
609 ;
610
611 // See comments above,
612 // resulting in a strange sort of mathematic rule here:
613 // The arrival-info multiplied by the relevant side
614 // delivers a consistent result.
615
616 int const product = arrival * side_p_or_q;
617
618 if(product == 0)
619 {
620 both(ti, operation_continue);
621 }
622 else
623 {
624 ui_else_iu(product == 1, ti);
625 }
626
627 // Calculate remaining distance. If it continues collinearly it is
628 // measured until the end of the next segment
629 ti.operations[0].remaining_distance
630 = side_p == 0
631 ? distance_measure(ti.point, pk)
632 : distance_measure(ti.point, pj);
633 ti.operations[1].remaining_distance
634 = side_q == 0
635 ? distance_measure(ti.point, qk)
636 : distance_measure(ti.point, qj);
637 }
638
639 template <typename Point1, typename Point2>
640 static inline typename geometry::coordinate_type<Point1>::type
641 distance_measure(Point1 const& a, Point2 const& b)
642 {
643 // TODO: use comparable distance for point-point instead - but that
644 // causes currently cycling include problems
645 typedef typename geometry::coordinate_type<Point1>::type ctype;
646 ctype const dx = get<0>(a) - get<0>(b);
647 ctype const dy = get<1>(b) - get<1>(b);
648 return dx * dx + dy * dy;
649 }
650 };
651
652 template
653 <
654 typename TurnInfo,
655 typename AssignPolicy
656 >
657 struct collinear_opposite : public base_turn_handler
658 {
659 private :
660 /*
661 arrival P arrival Q pk//p1 qk//q1 case result2 result
662 --------------------------------------------------------------
663 1 1 1 -1 CLO1 ix xu
664 1 1 1 0 CLO2 ix (xx)
665 1 1 1 1 CLO3 ix xi
666
667 1 1 0 -1 CCO1 (xx) xu
668 1 1 0 0 CCO2 (xx) (xx)
669 1 1 0 1 CCO3 (xx) xi
670
671 1 1 -1 -1 CRO1 ux xu
672 1 1 -1 0 CRO2 ux (xx)
673 1 1 -1 1 CRO3 ux xi
674
675 -1 1 -1 CXO1 xu
676 -1 1 0 CXO2 (xx)
677 -1 1 1 CXO3 xi
678
679 1 -1 1 CXO1 ix
680 1 -1 0 CXO2 (xx)
681 1 -1 -1 CXO3 ux
682 */
683
684 template
685 <
686 unsigned int Index,
687 typename Point1,
688 typename Point2,
689 typename IntersectionInfo
690 >
691 static inline bool set_tp(Point1 const& , Point1 const& , Point1 const& , int side_rk_r,
692 bool const handle_robustness,
693 Point2 const& , Point2 const& , int side_rk_s,
694 TurnInfo& tp, IntersectionInfo const& intersection_info)
695 {
696 BOOST_STATIC_ASSERT(Index <= 1);
697
698 boost::ignore_unused(handle_robustness, side_rk_s);
699
700 operation_type blocked = operation_blocked;
701 switch(side_rk_r)
702 {
703
704 case 1 :
705 // Turning left on opposite collinear: intersection
706 tp.operations[Index].operation = operation_intersection;
707 break;
708 case -1 :
709 // Turning right on opposite collinear: union
710 tp.operations[Index].operation = operation_union;
711 break;
712 case 0 :
713 // No turn on opposite collinear: block, do not traverse
714 // But this "xx" is usually ignored, it is useless to include
715 // two operations blocked, so the whole point does not need
716 // to be generated.
717 // So return false to indicate nothing is to be done.
718 if (AssignPolicy::include_opposite)
719 {
720 tp.operations[Index].operation = operation_opposite;
721 blocked = operation_opposite;
722 }
723 else
724 {
725 return false;
726 }
727 break;
728 }
729
730 // The other direction is always blocked when collinear opposite
731 tp.operations[1 - Index].operation = blocked;
732
733 // If P arrives within Q, set info on P (which is done above, index=0),
734 // this turn-info belongs to the second intersection point, index=1
735 // (see e.g. figure CLO1)
736 assign_point(tp, method_collinear, intersection_info, 1 - Index);
737 return true;
738 }
739
740 public:
741 static inline void empty_transformer(TurnInfo &) {}
742
743 template
744 <
745 typename Point1,
746 typename Point2,
747 typename OutputIterator,
748 typename IntersectionInfo,
749 typename SidePolicy
750 >
751 static inline void apply(
752 Point1 const& pi, Point1 const& pj, Point1 const& pk,
753 Point2 const& qi, Point2 const& qj, Point2 const& qk,
754
755 // Opposite collinear can deliver 2 intersection points,
756 TurnInfo const& tp_model,
757 OutputIterator& out,
758
759 IntersectionInfo const& intersection_info,
760 SidePolicy const& side)
761 {
762 apply(pi, pj, pk, qi, qj, qk, tp_model, out, intersection_info, side, empty_transformer);
763 }
764
765 public:
766 template
767 <
768 typename Point1,
769 typename Point2,
770 typename OutputIterator,
771 typename IntersectionInfo,
772 typename SidePolicy,
773 typename TurnTransformer
774 >
775 static inline void apply(
776 Point1 const& pi, Point1 const& pj, Point1 const& pk,
777 Point2 const& qi, Point2 const& qj, Point2 const& qk,
778
779 // Opposite collinear can deliver 2 intersection points,
780 TurnInfo const& tp_model,
781 OutputIterator& out,
782
783 IntersectionInfo const& info,
784 SidePolicy const& side,
785 TurnTransformer turn_transformer,
786 bool const is_pk_valid = true, bool const is_qk_valid = true)
787 {
788 TurnInfo tp = tp_model;
789
790 int const p_arrival = info.d_info().arrival[0];
791 int const q_arrival = info.d_info().arrival[1];
792
793 // If P arrives within Q, there is a turn dependent on P
794 if ( p_arrival == 1
795 && is_pk_valid
796 && set_tp<0>(pi, pj, pk, side.pk_wrt_p1(), true, qi, qj, side.pk_wrt_q1(), tp, info.i_info()) )
797 {
798 turn_transformer(tp);
799
800 AssignPolicy::apply(tp, pi, qi, info);
801 *out++ = tp;
802 }
803
804 // If Q arrives within P, there is a turn dependent on Q
805 if ( q_arrival == 1
806 && is_qk_valid
807 && set_tp<1>(qi, qj, qk, side.qk_wrt_q1(), false, pi, pj, side.qk_wrt_p1(), tp, info.i_info()) )
808 {
809 turn_transformer(tp);
810
811 AssignPolicy::apply(tp, pi, qi, info);
812 *out++ = tp;
813 }
814
815 if (AssignPolicy::include_opposite)
816 {
817 // Handle cases not yet handled above
818 if ((q_arrival == -1 && p_arrival == 0)
819 || (p_arrival == -1 && q_arrival == 0))
820 {
821 for (unsigned int i = 0; i < 2; i++)
822 {
823 tp.operations[i].operation = operation_opposite;
824 }
825 for (unsigned int i = 0; i < info.i_info().count; i++)
826 {
827 assign_point(tp, method_collinear, info.i_info(), i);
828 AssignPolicy::apply(tp, pi, qi, info);
829 *out++ = tp;
830 }
831 }
832 }
833
834 }
835 };
836
837
838 template
839 <
840 typename TurnInfo
841 >
842 struct crosses : public base_turn_handler
843 {
844 template
845 <
846 typename Point1,
847 typename Point2,
848 typename IntersectionInfo,
849 typename DirInfo
850 >
851 static inline void apply(
852 Point1 const& , Point1 const& , Point1 const& ,
853 Point2 const& , Point2 const& , Point2 const& ,
854 TurnInfo& ti,
855 IntersectionInfo const& intersection_info,
856 DirInfo const& dir_info)
857 {
858 assign_point(ti, method_crosses, intersection_info, 0);
859
860 // In all casees:
861 // If Q crosses P from left to right
862 // Union: take P
863 // Intersection: take Q
864 // Otherwise: vice versa
865 int const side_qi_p1 = dir_info.sides.template get<1, 0>();
866 unsigned int const index = side_qi_p1 == 1 ? 0 : 1;
867 ti.operations[index].operation = operation_union;
868 ti.operations[1 - index].operation = operation_intersection;
869 }
870 };
871
872 struct only_convert : public base_turn_handler
873 {
874 template<typename TurnInfo, typename IntersectionInfo>
875 static inline void apply(TurnInfo& ti, IntersectionInfo const& intersection_info)
876 {
877 assign_point(ti, method_none, intersection_info, 0); // was collinear
878 ti.operations[0].operation = operation_continue;
879 ti.operations[1].operation = operation_continue;
880 }
881 };
882
883 /*!
884 \brief Policy doing nothing
885 \details get_turn_info can have an optional policy to get/assign some
886 extra information. By default it does not, and this class
887 is that default.
888 */
889 struct assign_null_policy
890 {
891 static bool const include_no_turn = false;
892 static bool const include_degenerate = false;
893 static bool const include_opposite = false;
894
895 template
896 <
897 typename Info,
898 typename Point1,
899 typename Point2,
900 typename IntersectionInfo
901 >
902 static inline void apply(Info& , Point1 const& , Point2 const&, IntersectionInfo const&)
903 {}
904
905 };
906
907
908 /*!
909 \brief Turn information: intersection point, method, and turn information
910 \details Information necessary for traversal phase (a phase
911 of the overlay process). The information is gathered during the
912 get_turns (segment intersection) phase.
913 \tparam Point1 point type of first segment
914 \tparam Point2 point type of second segment
915 \tparam TurnInfo type of class getting intersection and turn info
916 \tparam AssignPolicy policy to assign extra info,
917 e.g. to calculate distance from segment's first points
918 to intersection points.
919 It also defines if a certain class of points
920 (degenerate, non-turns) should be included.
921 */
922 template<typename AssignPolicy>
923 struct get_turn_info
924 {
925 // Intersect pi-pj with qi-qj
926 // The points pk and qk are used do determine more information
927 // about the turn (turn left/right)
928 template
929 <
930 typename Point1,
931 typename Point2,
932 typename TurnInfo,
933 typename RobustPolicy,
934 typename OutputIterator
935 >
936 static inline OutputIterator apply(
937 Point1 const& pi, Point1 const& pj, Point1 const& pk,
938 Point2 const& qi, Point2 const& qj, Point2 const& qk,
939 bool /*is_p_first*/, bool /*is_p_last*/,
940 bool /*is_q_first*/, bool /*is_q_last*/,
941 TurnInfo const& tp_model,
942 RobustPolicy const& robust_policy,
943 OutputIterator out)
944 {
945 typedef intersection_info<Point1, Point2, typename TurnInfo::point_type, RobustPolicy>
946 inters_info;
947
948 inters_info inters(pi, pj, pk, qi, qj, qk, robust_policy);
949
950 char const method = inters.d_info().how;
951
952 // Copy, to copy possibly extended fields
953 TurnInfo tp = tp_model;
954
955 // Select method and apply
956 switch(method)
957 {
958 case 'a' : // collinear, "at"
959 case 'f' : // collinear, "from"
960 case 's' : // starts from the middle
961 if (AssignPolicy::include_no_turn
962 && inters.i_info().count > 0)
963 {
964 only_convert::apply(tp, inters.i_info());
965 AssignPolicy::apply(tp, pi, qi, inters);
966 *out++ = tp;
967 }
968 break;
969
970 case 'd' : // disjoint: never do anything
971 break;
972
973 case 'm' :
974 {
975 typedef touch_interior
976 <
977 TurnInfo
978 > policy;
979
980 // If Q (1) arrives (1)
981 if ( inters.d_info().arrival[1] == 1 )
982 {
983 policy::template apply<0>(pi, pj, pk, qi, qj, qk,
984 tp, inters.i_info(), inters.d_info(),
985 inters.sides());
986 }
987 else
988 {
989 // Swap p/q
990 side_calculator
991 <
992 typename inters_info::cs_tag,
993 typename inters_info::robust_point2_type,
994 typename inters_info::robust_point1_type
995 > swapped_side_calc(inters.rqi(), inters.rqj(), inters.rqk(),
996 inters.rpi(), inters.rpj(), inters.rpk());
997 policy::template apply<1>(qi, qj, qk, pi, pj, pk,
998 tp, inters.i_info(), inters.d_info(),
999 swapped_side_calc);
1000 }
1001 AssignPolicy::apply(tp, pi, qi, inters);
1002 *out++ = tp;
1003 }
1004 break;
1005 case 'i' :
1006 {
1007 crosses<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
1008 tp, inters.i_info(), inters.d_info());
1009 AssignPolicy::apply(tp, pi, qi, inters);
1010 *out++ = tp;
1011 }
1012 break;
1013 case 't' :
1014 {
1015 // Both touch (both arrive there)
1016 touch<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
1017 tp, inters.i_info(), inters.d_info(), inters.sides());
1018 AssignPolicy::apply(tp, pi, qi, inters);
1019 *out++ = tp;
1020 }
1021 break;
1022 case 'e':
1023 {
1024 if ( ! inters.d_info().opposite )
1025 {
1026 // Both equal
1027 // or collinear-and-ending at intersection point
1028 equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
1029 tp, inters.i_info(), inters.d_info(), inters.sides());
1030 AssignPolicy::apply(tp, pi, qi, inters);
1031 *out++ = tp;
1032 }
1033 else
1034 {
1035 equal_opposite
1036 <
1037 TurnInfo,
1038 AssignPolicy
1039 >::apply(pi, qi,
1040 tp, out, inters);
1041 }
1042 }
1043 break;
1044 case 'c' :
1045 {
1046 // Collinear
1047 if ( ! inters.d_info().opposite )
1048 {
1049
1050 if ( inters.d_info().arrival[0] == 0 )
1051 {
1052 // Collinear, but similar thus handled as equal
1053 equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
1054 tp, inters.i_info(), inters.d_info(), inters.sides());
1055
1056 // override assigned method
1057 tp.method = method_collinear;
1058 }
1059 else
1060 {
1061 collinear<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
1062 tp, inters.i_info(), inters.d_info(), inters.sides());
1063 }
1064
1065 AssignPolicy::apply(tp, pi, qi, inters);
1066 *out++ = tp;
1067 }
1068 else
1069 {
1070 collinear_opposite
1071 <
1072 TurnInfo,
1073 AssignPolicy
1074 >::apply(pi, pj, pk, qi, qj, qk,
1075 tp, out, inters, inters.sides());
1076 }
1077 }
1078 break;
1079 case '0' :
1080 {
1081 // degenerate points
1082 if (AssignPolicy::include_degenerate)
1083 {
1084 only_convert::apply(tp, inters.i_info());
1085 AssignPolicy::apply(tp, pi, qi, inters);
1086 *out++ = tp;
1087 }
1088 }
1089 break;
1090 default :
1091 {
1092 #if defined(BOOST_GEOMETRY_DEBUG_ROBUSTNESS)
1093 std::cout << "TURN: Unknown method: " << method << std::endl;
1094 #endif
1095 #if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW)
1096 throw turn_info_exception(method);
1097 #endif
1098 }
1099 break;
1100 }
1101
1102 return out;
1103 }
1104 };
1105
1106
1107 }} // namespace detail::overlay
1108 #endif //DOXYGEN_NO_DETAIL
1109
1110
1111 }} // namespace boost::geometry
1112
1113
1114 #if defined(_MSC_VER)
1115 #pragma warning(pop)
1116 #endif
1117
1118 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HPP