1 // Boost.Geometry (aka GGL, Generic Geometry Library)
3 // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
5 // This file was modified by Oracle on 2015.
6 // Modifications copyright (c) 2015 Oracle and/or its affiliates.
8 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
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)
14 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HPP
15 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HPP
18 #include <boost/core/ignore_unused.hpp>
20 #include <boost/geometry/core/access.hpp>
21 #include <boost/geometry/core/assert.hpp>
22 #include <boost/geometry/strategies/intersection_strategies.hpp>
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>
28 #include <boost/geometry/geometries/segment.hpp>
30 #include <boost/geometry/policies/robustness/robust_point_type.hpp>
31 #include <boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp>
33 // Silence warning C4127: conditional expression is constant
36 #pragma warning(disable : 4127)
40 namespace boost { namespace geometry
43 #if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW)
44 class turn_info_exception : public geometry::exception
49 // NOTE: "char" will be replaced by enum in future version
50 inline turn_info_exception(char const method)
52 message = "Boost.Geometry Turn exception: ";
56 virtual ~turn_info_exception() throw()
59 virtual char const* what() const throw()
61 return message.c_str();
66 #ifndef DOXYGEN_NO_DETAIL
67 namespace detail { namespace overlay
70 struct base_turn_handler
72 // Returns true if both sides are opposite
73 static inline bool opposite(int side1, int side2)
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;
80 // Same side of a segment (not being 0)
81 static inline bool same(int side1, int side2)
83 return side1 * side2 == 1;
87 template <typename TurnInfo>
88 static inline void both(TurnInfo& ti, operation_type const op)
90 ti.operations[0].operation = op;
91 ti.operations[1].operation = op;
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)
98 ti.operations[0].operation = condition
99 ? operation_union : operation_intersection;
100 ti.operations[1].operation = condition
101 ? operation_intersection : operation_union;
104 // If condition, both union, else both intersection
105 template <typename TurnInfo>
106 static inline void uu_else_ii(bool condition, TurnInfo& ti)
108 both(ti, condition ? operation_union : operation_intersection);
111 template <typename TurnInfo, typename IntersectionInfo>
112 static inline void assign_point(TurnInfo& ti,
114 IntersectionInfo const& info, unsigned int index)
118 BOOST_GEOMETRY_ASSERT(index < info.count);
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;
125 template <typename IntersectionInfo>
126 static inline unsigned int non_opposite_to_index(IntersectionInfo const& info)
128 return info.fractions[0].robust_rb < info.fractions[1].robust_rb
139 struct touch_interior : public base_turn_handler
141 // Index: 0, P is the interior, Q is touching and vice versa
147 typename IntersectionInfo,
151 static inline void apply(
152 Point1 const& , Point1 const& , Point1 const& ,
153 Point2 const& , Point2 const& , Point2 const& ,
155 IntersectionInfo const& intersection_info,
156 DirInfo const& dir_info,
157 SidePolicy const& side)
159 assign_point(ti, method_touch_interior, intersection_info, 0);
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
167 BOOST_STATIC_ASSERT(Index <= 1);
168 static unsigned int const index_p = Index;
169 static unsigned int const index_q = 1 - Index;
171 int const side_qi_p = dir_info.sides.template get<index_q, 0>();
172 int const side_qk_p = side.qk_wrt_p1();
174 if (side_qi_p == -side_qk_p)
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;
185 int const side_qk_q = side.qk_wrt_q1();
187 if (side_qi_p == -1 && side_qk_p == -1 && side_qk_q == 1)
189 // Q turns left on the right side of P (test "MR3")
190 // Both directions for "intersection"
191 both(ti, operation_intersection);
193 else if (side_qi_p == 1 && side_qk_p == 1 && side_qk_q == -1)
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);
200 else if (side_qi_p == side_qk_p && side_qi_p == side_qk_q)
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;
210 else if (side_qk_p == 0)
212 // Q intersects on interior of P and continues collinearly
213 if (side_qk_q == side_qi_p)
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);
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
231 ti.operations[index_q].operation = operation_blocked;
237 ti.method = method_error;
247 struct touch : public base_turn_handler
249 static inline bool between(int side1, int side2, int turn)
251 return side1 == side2 && ! opposite(side1, turn);
254 /*static inline void block_second(bool block, TurnInfo& ti)
258 ti.operations[1].operation = operation_blocked;
267 typename IntersectionInfo,
271 static inline void apply(
272 Point1 const& , Point1 const& , Point1 const& ,
273 Point2 const& , Point2 const& , Point2 const& ,
275 IntersectionInfo const& intersection_info,
276 DirInfo const& dir_info,
277 SidePolicy const& side)
279 assign_point(ti, method_touch, intersection_info, 0);
281 int const side_qi_p1 = dir_info.sides.template get<1, 0>();
282 int const side_qk_p1 = side.qk_wrt_p1();
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))
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();
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)
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)
306 // Collinear -> lines join, continue
308 if (side_pk_q2 == 0 && ! block_q)
310 both(ti, operation_continue);
314 int const side_pk_q1 = side.pk_wrt_q1();
317 // Collinear opposite case -> block P
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
330 // Pk between Qi and Qk
332 if (between(side_pk_q1, side_pk_q2, side_qk_q))
334 ui_else_iu(q_turns_left, ti);
337 ti.operations[1].operation = operation_blocked;
339 //block_second(block_q, ti);
343 // Pk between Qk and P, so left of Qk (if Q turns right) and vv
345 if (side_pk_q2 == -side_qk_q)
347 ui_else_iu(! q_turns_left, ti);
353 if (side_pk_q1 == -side_qk_q)
355 uu_else_ii(! q_turns_left, ti);
358 ti.operations[1].operation = operation_blocked;
360 //block_second(block_q, ti);
366 // Pk at other side than Qi/Pk
367 ti.operations[0].operation = q_turns_left
368 ? operation_intersection
370 ti.operations[1].operation = block_q
372 : side_qi_p1 == 1 || side_qk_p1 == 1
374 : operation_intersection;
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;
385 // If p turns into direction of qi (1,2)
386 if (side_pk_p == side_qi_p1)
388 int const side_pk_q1 = side.pk_wrt_q1();
390 // Collinear opposite case -> block P
393 ti.operations[0].operation = operation_blocked;
394 ti.operations[1].operation = right_to_left
395 ? operation_union : operation_intersection;
399 if (side_pk_q1 == side_qk_p1)
401 uu_else_ii(right_to_left, ti);
406 // If p turns into direction of qk (4,5)
407 if (side_pk_p == side_qk_p1)
409 int const side_pk_q2 = side.pk_wrt_q2();
411 // Collinear case -> lines join, continue
414 both(ti, operation_continue);
417 if (side_pk_q2 == side_qk_p1)
419 ui_else_iu(right_to_left, ti);
424 ui_else_iu(! right_to_left, ti);
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)
436 << "qi " << get<0>(qi) << " , " << get<1>(qi)
437 << " qj " << get<0>(qj) << " , " << get<1>(qj)
438 << " qk " << get<0>(qk) << " , " << get<1>(qk)
450 struct equal : public base_turn_handler
456 typename IntersectionInfo,
460 static inline void apply(
461 Point1 const& , Point1 const& , Point1 const& ,
462 Point2 const& , Point2 const& , Point2 const& ,
464 IntersectionInfo const& info,
466 SidePolicy const& side)
468 // Copy the intersection point in TO direction
469 assign_point(ti, method_equal, info, non_opposite_to_index(info));
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();
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
480 if (side_pk_q2 == 0 && side_pk_p == side_qk_p)
482 both(ti, operation_continue);
488 // If they turn to same side (not opposite sides)
489 if (! opposite(side_pk_p, side_qk_p))
491 // If pk is left of q2 or collinear: p: union, q: intersection
492 ui_else_iu(side_pk_q2 != -1, ti);
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);
507 typename AssignPolicy
509 struct equal_opposite : public base_turn_handler
515 typename OutputIterator,
516 typename IntersectionInfo
518 static inline void apply(Point1 const& pi, Point2 const& qi,
519 /* by value: */ TurnInfo tp,
521 IntersectionInfo const& intersection_info)
523 // For equal-opposite segments, normally don't do anything.
524 if (AssignPolicy::include_opposite)
526 tp.method = method_equal;
527 for (unsigned int i = 0; i < 2; i++)
529 tp.operations[i].operation = operation_opposite;
531 for (unsigned int i = 0; i < intersection_info.i_info().count; i++)
533 assign_point(tp, method_none, intersection_info.i_info(), i);
534 AssignPolicy::apply(tp, pi, qi, intersection_info);
545 struct collinear : public base_turn_handler
548 arrival P pk//p1 qk//q1 product* case result
562 *product = arrival * (pk//p1 or qk//q1)
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)
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
583 typename IntersectionInfo,
587 static inline void apply(
588 Point1 const& , Point1 const& pj, Point1 const& pk,
589 Point2 const& , Point2 const& qj, Point2 const& qk,
591 IntersectionInfo const& info,
592 DirInfo const& dir_info,
593 SidePolicy const& side)
595 // Copy the intersection point in TO direction
596 assign_point(ti, method_collinear, info, non_opposite_to_index(info));
598 int const arrival = dir_info.arrival[0];
599 // Should not be 0, this is checked before
600 BOOST_GEOMETRY_ASSERT(arrival != 0);
602 int const side_p = side.pk_wrt_p1();
603 int const side_q = side.qk_wrt_q1();
605 // If p arrives, use p, else use q
606 int const side_p_or_q = arrival == 1
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.
616 int const product = arrival * side_p_or_q;
620 both(ti, operation_continue);
624 ui_else_iu(product == 1, ti);
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
631 ? distance_measure(ti.point, pk)
632 : distance_measure(ti.point, pj);
633 ti.operations[1].remaining_distance
635 ? distance_measure(ti.point, qk)
636 : distance_measure(ti.point, qj);
639 template <typename Point1, typename Point2>
640 static inline typename geometry::coordinate_type<Point1>::type
641 distance_measure(Point1 const& a, Point2 const& b)
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;
655 typename AssignPolicy
657 struct collinear_opposite : public base_turn_handler
661 arrival P arrival Q pk//p1 qk//q1 case result2 result
662 --------------------------------------------------------------
667 1 1 0 -1 CCO1 (xx) xu
668 1 1 0 0 CCO2 (xx) (xx)
672 1 1 -1 0 CRO2 ux (xx)
689 typename IntersectionInfo
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)
696 BOOST_STATIC_ASSERT(Index <= 1);
698 boost::ignore_unused(handle_robustness, side_rk_s);
700 operation_type blocked = operation_blocked;
705 // Turning left on opposite collinear: intersection
706 tp.operations[Index].operation = operation_intersection;
709 // Turning right on opposite collinear: union
710 tp.operations[Index].operation = operation_union;
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
717 // So return false to indicate nothing is to be done.
718 if (AssignPolicy::include_opposite)
720 tp.operations[Index].operation = operation_opposite;
721 blocked = operation_opposite;
730 // The other direction is always blocked when collinear opposite
731 tp.operations[1 - Index].operation = blocked;
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);
741 static inline void empty_transformer(TurnInfo &) {}
747 typename OutputIterator,
748 typename IntersectionInfo,
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,
755 // Opposite collinear can deliver 2 intersection points,
756 TurnInfo const& tp_model,
759 IntersectionInfo const& intersection_info,
760 SidePolicy const& side)
762 apply(pi, pj, pk, qi, qj, qk, tp_model, out, intersection_info, side, empty_transformer);
770 typename OutputIterator,
771 typename IntersectionInfo,
773 typename TurnTransformer
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,
779 // Opposite collinear can deliver 2 intersection points,
780 TurnInfo const& tp_model,
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)
788 TurnInfo tp = tp_model;
790 int const p_arrival = info.d_info().arrival[0];
791 int const q_arrival = info.d_info().arrival[1];
793 // If P arrives within Q, there is a turn dependent on P
796 && set_tp<0>(pi, pj, pk, side.pk_wrt_p1(), true, qi, qj, side.pk_wrt_q1(), tp, info.i_info()) )
798 turn_transformer(tp);
800 AssignPolicy::apply(tp, pi, qi, info);
804 // If Q arrives within P, there is a turn dependent on Q
807 && set_tp<1>(qi, qj, qk, side.qk_wrt_q1(), false, pi, pj, side.qk_wrt_p1(), tp, info.i_info()) )
809 turn_transformer(tp);
811 AssignPolicy::apply(tp, pi, qi, info);
815 if (AssignPolicy::include_opposite)
817 // Handle cases not yet handled above
818 if ((q_arrival == -1 && p_arrival == 0)
819 || (p_arrival == -1 && q_arrival == 0))
821 for (unsigned int i = 0; i < 2; i++)
823 tp.operations[i].operation = operation_opposite;
825 for (unsigned int i = 0; i < info.i_info().count; i++)
827 assign_point(tp, method_collinear, info.i_info(), i);
828 AssignPolicy::apply(tp, pi, qi, info);
842 struct crosses : public base_turn_handler
848 typename IntersectionInfo,
851 static inline void apply(
852 Point1 const& , Point1 const& , Point1 const& ,
853 Point2 const& , Point2 const& , Point2 const& ,
855 IntersectionInfo const& intersection_info,
856 DirInfo const& dir_info)
858 assign_point(ti, method_crosses, intersection_info, 0);
861 // If Q crosses P from left to right
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;
872 struct only_convert : public base_turn_handler
874 template<typename TurnInfo, typename IntersectionInfo>
875 static inline void apply(TurnInfo& ti, IntersectionInfo const& intersection_info)
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;
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
889 struct assign_null_policy
891 static bool const include_no_turn = false;
892 static bool const include_degenerate = false;
893 static bool const include_opposite = false;
900 typename IntersectionInfo
902 static inline void apply(Info& , Point1 const& , Point2 const&, IntersectionInfo const&)
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.
922 template<typename AssignPolicy>
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)
933 typename RobustPolicy,
934 typename OutputIterator
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,
945 typedef intersection_info<Point1, Point2, typename TurnInfo::point_type, RobustPolicy>
948 inters_info inters(pi, pj, pk, qi, qj, qk, robust_policy);
950 char const method = inters.d_info().how;
952 // Copy, to copy possibly extended fields
953 TurnInfo tp = tp_model;
955 // Select method and apply
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)
964 only_convert::apply(tp, inters.i_info());
965 AssignPolicy::apply(tp, pi, qi, inters);
970 case 'd' : // disjoint: never do anything
975 typedef touch_interior
980 // If Q (1) arrives (1)
981 if ( inters.d_info().arrival[1] == 1 )
983 policy::template apply<0>(pi, pj, pk, qi, qj, qk,
984 tp, inters.i_info(), inters.d_info(),
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(),
1001 AssignPolicy::apply(tp, pi, qi, inters);
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);
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);
1024 if ( ! inters.d_info().opposite )
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);
1047 if ( ! inters.d_info().opposite )
1050 if ( inters.d_info().arrival[0] == 0 )
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());
1056 // override assigned method
1057 tp.method = method_collinear;
1061 collinear<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
1062 tp, inters.i_info(), inters.d_info(), inters.sides());
1065 AssignPolicy::apply(tp, pi, qi, inters);
1074 >::apply(pi, pj, pk, qi, qj, qk,
1075 tp, out, inters, inters.sides());
1081 // degenerate points
1082 if (AssignPolicy::include_degenerate)
1084 only_convert::apply(tp, inters.i_info());
1085 AssignPolicy::apply(tp, pi, qi, inters);
1092 #if defined(BOOST_GEOMETRY_DEBUG_ROBUSTNESS)
1093 std::cout << "TURN: Unknown method: " << method << std::endl;
1095 #if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW)
1096 throw turn_info_exception(method);
1107 }} // namespace detail::overlay
1108 #endif //DOXYGEN_NO_DETAIL
1111 }} // namespace boost::geometry
1114 #if defined(_MSC_VER)
1115 #pragma warning(pop)
1118 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HPP