1 // Boost.Geometry (aka GGL, Generic Geometry Library)
3 // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
5 // Use, modification and distribution is subject to the Boost Software License,
6 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
7 // http://www.boost.org/LICENSE_1_0.txt)
9 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HPP
10 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HPP
13 #include <boost/assert.hpp>
14 #include <boost/geometry/core/access.hpp>
15 #include <boost/geometry/strategies/intersection.hpp>
17 #include <boost/geometry/algorithms/convert.hpp>
18 #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
19 #include <boost/geometry/algorithms/detail/recalculate.hpp>
21 #include <boost/geometry/geometries/segment.hpp>
23 #include <boost/geometry/policies/robustness/robust_point_type.hpp>
24 #include <boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp>
26 // Silence warning C4127: conditional expression is constant
29 #pragma warning(disable : 4127)
33 namespace boost { namespace geometry
36 #if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW)
37 class turn_info_exception : public geometry::exception
42 // NOTE: "char" will be replaced by enum in future version
43 inline turn_info_exception(char const method)
45 message = "Boost.Geometry Turn exception: ";
49 virtual ~turn_info_exception() throw()
52 virtual char const* what() const throw()
54 return message.c_str();
59 #ifndef DOXYGEN_NO_DETAIL
60 namespace detail { namespace overlay
63 struct base_turn_handler
65 // Returns true if both sides are opposite
66 static inline bool opposite(int side1, int side2)
68 // We cannot state side1 == -side2, because 0 == -0
69 // So either side1*side2==-1 or side1==-side2 && side1 != 0
70 return side1 * side2 == -1;
73 // Same side of a segment (not being 0)
74 static inline bool same(int side1, int side2)
76 return side1 * side2 == 1;
80 template <typename TurnInfo>
81 static inline void both(TurnInfo& ti, operation_type const op)
83 ti.operations[0].operation = op;
84 ti.operations[1].operation = op;
87 // If condition, first union/second intersection, else vice versa
88 template <typename TurnInfo>
89 static inline void ui_else_iu(bool condition, TurnInfo& ti)
91 ti.operations[0].operation = condition
92 ? operation_union : operation_intersection;
93 ti.operations[1].operation = condition
94 ? operation_intersection : operation_union;
97 // If condition, both union, else both intersection
98 template <typename TurnInfo>
99 static inline void uu_else_ii(bool condition, TurnInfo& ti)
101 both(ti, condition ? operation_union : operation_intersection);
104 template <typename TurnInfo, typename IntersectionInfo>
105 static inline void assign_point(TurnInfo& ti,
107 IntersectionInfo const& info, int index)
110 BOOST_ASSERT(index >= 0 && unsigned(index) < info.count); // TODO remove this
111 geometry::convert(info.intersections[index], ti.point);
112 ti.operations[0].fraction = info.fractions[index].robust_ra;
113 ti.operations[1].fraction = info.fractions[index].robust_rb;
116 template <typename IntersectionInfo>
117 static inline int non_opposite_to_index(IntersectionInfo const& info)
119 return info.fractions[0].robust_rb < info.fractions[1].robust_rb
130 struct touch_interior : public base_turn_handler
132 // Index: 0, P is the interior, Q is touching and vice versa
138 typename IntersectionInfo,
142 static inline void apply(
143 Point1 const& , Point1 const& , Point1 const& ,
144 Point2 const& , Point2 const& , Point2 const& ,
146 IntersectionInfo const& intersection_info,
147 DirInfo const& dir_info,
148 SidePolicy const& side)
150 assign_point(ti, method_touch_interior, intersection_info, 0);
152 // Both segments of q touch segment p somewhere in its interior
153 // 1) We know: if q comes from LEFT or RIGHT
154 // (i.e. dir_info.sides.get<Index,0>() == 1 or -1)
155 // 2) Important is: if q_k goes to LEFT, RIGHT, COLLINEAR
156 // and, if LEFT/COLL, if it is lying LEFT or RIGHT w.r.t. q_i
158 static int const index_p = Index;
159 static int const index_q = 1 - Index;
161 int const side_qi_p = dir_info.sides.template get<index_q, 0>();
162 int const side_qk_p = side.qk_wrt_p1();
164 if (side_qi_p == -side_qk_p)
166 // Q crosses P from left->right or from right->left (test "ML1")
167 // Union: folow P (left->right) or Q (right->left)
168 // Intersection: other turn
169 int index = side_qk_p == -1 ? index_p : index_q;
170 ti.operations[index].operation = operation_union;
171 ti.operations[1 - index].operation = operation_intersection;
175 int const side_qk_q = side.qk_wrt_q1();
177 if (side_qi_p == -1 && side_qk_p == -1 && side_qk_q == 1)
179 // Q turns left on the right side of P (test "MR3")
180 // Both directions for "intersection"
181 both(ti, operation_intersection);
183 else if (side_qi_p == 1 && side_qk_p == 1 && side_qk_q == -1)
185 // Q turns right on the left side of P (test "ML3")
186 // Union: take both operation
187 // Intersection: skip
188 both(ti, operation_union);
190 else if (side_qi_p == side_qk_p && side_qi_p == side_qk_q)
192 // Q turns left on the left side of P (test "ML2")
193 // or Q turns right on the right side of P (test "MR2")
194 // Union: take left turn (Q if Q turns left, P if Q turns right)
195 // Intersection: other turn
196 int index = side_qk_q == 1 ? index_q : index_p;
197 ti.operations[index].operation = operation_union;
198 ti.operations[1 - index].operation = operation_intersection;
200 else if (side_qk_p == 0)
202 // Q intersects on interior of P and continues collinearly
203 if (side_qk_q == side_qi_p)
205 // Collinearly in the same direction
206 // (Q comes from left of P and turns left,
207 // OR Q comes from right of P and turns right)
208 // Omit intersection point.
209 // Union: just continue
210 // Intersection: just continue
211 both(ti, operation_continue);
215 // Opposite direction, which is never travelled.
216 // If Q turns left, P continues for intersection
217 // If Q turns right, P continues for union
218 ti.operations[Index].operation = side_qk_q == 1
219 ? operation_intersection
221 ti.operations[1 - Index].operation = operation_blocked;
227 ti.method = method_error;
237 struct touch : public base_turn_handler
239 static inline bool between(int side1, int side2, int turn)
241 return side1 == side2 && ! opposite(side1, turn);
244 /*static inline void block_second(bool block, TurnInfo& ti)
248 ti.operations[1].operation = operation_blocked;
257 typename IntersectionInfo,
261 static inline void apply(
262 Point1 const& , Point1 const& , Point1 const& ,
263 Point2 const& , Point2 const& , Point2 const& ,
265 IntersectionInfo const& intersection_info,
266 DirInfo const& dir_info,
267 SidePolicy const& side)
269 assign_point(ti, method_touch, intersection_info, 0);
271 int const side_qi_p1 = dir_info.sides.template get<1, 0>();
272 int const side_qk_p1 = side.qk_wrt_p1();
275 // If Qi and Qk are both at same side of Pi-Pj,
276 // or collinear (so: not opposite sides)
277 if (! opposite(side_qi_p1, side_qk_p1))
279 int const side_pk_q2 = side.pk_wrt_q2();
280 int const side_pk_p = side.pk_wrt_p1();
281 int const side_qk_q = side.qk_wrt_q1();
283 bool const q_turns_left = side_qk_q == 1;
284 bool const block_q = side_qk_p1 == 0
285 && ! same(side_qi_p1, side_qk_q)
288 // If Pk at same side as Qi/Qk
289 // (the "or" is for collinear case)
290 // or Q is fully collinear && P turns not to left
291 if (side_pk_p == side_qi_p1
292 || side_pk_p == side_qk_p1
293 || (side_qi_p1 == 0 && side_qk_p1 == 0 && side_pk_p != -1)
296 // Collinear -> lines join, continue
298 if (side_pk_q2 == 0 && ! block_q)
300 both(ti, operation_continue);
304 int const side_pk_q1 = side.pk_wrt_q1();
307 // Collinear opposite case -> block P
311 ti.operations[0].operation = operation_blocked;
312 // Q turns right -> union (both independent),
313 // Q turns left -> intersection
314 ti.operations[1].operation = block_q ? operation_blocked
315 : q_turns_left ? operation_intersection
320 // Pk between Qi and Qk
322 if (between(side_pk_q1, side_pk_q2, side_qk_q))
324 ui_else_iu(q_turns_left, ti);
327 ti.operations[1].operation = operation_blocked;
329 //block_second(block_q, ti);
333 // Pk between Qk and P, so left of Qk (if Q turns right) and vv
335 if (side_pk_q2 == -side_qk_q)
337 ui_else_iu(! q_turns_left, ti);
343 if (side_pk_q1 == -side_qk_q)
345 uu_else_ii(! q_turns_left, ti);
348 ti.operations[1].operation = operation_blocked;
350 //block_second(block_q, ti);
356 // Pk at other side than Qi/Pk
357 ti.operations[0].operation = q_turns_left
358 ? operation_intersection
360 ti.operations[1].operation = block_q
362 : side_qi_p1 == 1 || side_qk_p1 == 1
364 : operation_intersection;
371 // From left to right or from right to left
372 int const side_pk_p = side.pk_wrt_p1();
373 bool const right_to_left = side_qk_p1 == 1;
375 // If p turns into direction of qi (1,2)
376 if (side_pk_p == side_qi_p1)
378 int const side_pk_q1 = side.pk_wrt_q1();
380 // Collinear opposite case -> block P
383 ti.operations[0].operation = operation_blocked;
384 ti.operations[1].operation = right_to_left
385 ? operation_union : operation_intersection;
389 if (side_pk_q1 == side_qk_p1)
391 uu_else_ii(right_to_left, ti);
396 // If p turns into direction of qk (4,5)
397 if (side_pk_p == side_qk_p1)
399 int const side_pk_q2 = side.pk_wrt_q2();
401 // Collinear case -> lines join, continue
404 both(ti, operation_continue);
407 if (side_pk_q2 == side_qk_p1)
409 ui_else_iu(right_to_left, ti);
414 ui_else_iu(! right_to_left, ti);
418 #ifdef BOOST_GEOMETRY_DEBUG_GET_TURNS
419 // Normally a robustness issue.
420 // TODO: more research if still occuring
421 std::cout << "Not yet handled" << std::endl
422 << "pi " << get<0>(pi) << " , " << get<1>(pi)
423 << " pj " << get<0>(pj) << " , " << get<1>(pj)
424 << " pk " << get<0>(pk) << " , " << get<1>(pk)
426 << "qi " << get<0>(qi) << " , " << get<1>(qi)
427 << " qj " << get<0>(qj) << " , " << get<1>(qj)
428 << " qk " << get<0>(qk) << " , " << get<1>(qk)
440 struct equal : public base_turn_handler
446 typename IntersectionInfo,
450 static inline void apply(
451 Point1 const& , Point1 const& , Point1 const& ,
452 Point2 const& , Point2 const& , Point2 const& ,
454 IntersectionInfo const& info,
456 SidePolicy const& side)
458 // Copy the intersection point in TO direction
459 assign_point(ti, method_equal, info, non_opposite_to_index(info));
461 int const side_pk_q2 = side.pk_wrt_q2();
462 int const side_pk_p = side.pk_wrt_p1();
463 int const side_qk_p = side.qk_wrt_p1();
466 // If pk is collinear with qj-qk, they continue collinearly.
467 // This can be on either side of p1 (== q1), or collinear
468 // The second condition checks if they do not continue
470 if (side_pk_q2 == 0 && side_pk_p == side_qk_p)
472 both(ti, operation_continue);
478 // If they turn to same side (not opposite sides)
479 if (! opposite(side_pk_p, side_qk_p))
481 // If pk is left of q2 or collinear: p: union, q: intersection
482 ui_else_iu(side_pk_q2 != -1, ti);
486 // They turn opposite sides. If p turns left (or collinear),
487 // p: union, q: intersection
488 ui_else_iu(side_pk_p != -1, ti);
497 typename AssignPolicy
499 struct equal_opposite : public base_turn_handler
505 typename OutputIterator,
506 typename IntersectionInfo,
509 static inline void apply(Point1 const& pi, Point2 const& qi,
510 /* by value: */ TurnInfo tp,
512 IntersectionInfo const& intersection_info,
513 DirInfo const& dir_info)
515 // For equal-opposite segments, normally don't do anything.
516 if (AssignPolicy::include_opposite)
518 tp.method = method_equal;
519 for (int i = 0; i < 2; i++)
521 tp.operations[i].operation = operation_opposite;
523 for (unsigned int i = 0; i < intersection_info.count; i++)
525 assign_point(tp, method_none, intersection_info, i);
526 AssignPolicy::apply(tp, pi, qi, intersection_info, dir_info);
537 struct collinear : public base_turn_handler
540 arrival P pk//p1 qk//q1 product* case result
554 *product = arrival * (pk//p1 or qk//q1)
557 - if P arrives: look at turn P
558 - if Q arrives: look at turn Q
559 - if P arrives and P turns left: union for P
560 - if P arrives and P turns right: intersection for P
561 - if Q arrives and Q turns left: union for Q (=intersection for P)
562 - if Q arrives and Q turns right: intersection for Q (=union for P)
564 ROBUSTNESS: p and q are collinear, so you would expect
565 that side qk//p1 == pk//q1. But that is not always the case
566 in near-epsilon ranges. Then decision logic is different.
567 If p arrives, q is further, so the angle qk//p1 is (normally)
568 more precise than pk//p1
575 typename IntersectionInfo,
579 static inline void apply(
580 Point1 const& , Point1 const& , Point1 const& ,
581 Point2 const& , Point2 const& , Point2 const& ,
583 IntersectionInfo const& info,
584 DirInfo const& dir_info,
585 SidePolicy const& side)
587 // Copy the intersection point in TO direction
588 assign_point(ti, method_collinear, info, non_opposite_to_index(info));
590 int const arrival = dir_info.arrival[0];
591 // Should not be 0, this is checked before
592 BOOST_ASSERT(arrival != 0);
594 int const side_p = side.pk_wrt_p1();
595 int const side_q = side.qk_wrt_q1();
597 // If p arrives, use p, else use q
598 int const side_p_or_q = arrival == 1
603 // See comments above,
604 // resulting in a strange sort of mathematic rule here:
605 // The arrival-info multiplied by the relevant side
606 // delivers a consistent result.
608 int const product = arrival * side_p_or_q;
612 both(ti, operation_continue);
616 ui_else_iu(product == 1, ti);
625 typename AssignPolicy
627 struct collinear_opposite : public base_turn_handler
631 arrival P arrival Q pk//p1 qk//q1 case result2 result
632 --------------------------------------------------------------
637 1 1 0 -1 CCO1 (xx) xu
638 1 1 0 0 CCO2 (xx) (xx)
642 1 1 -1 0 CRO2 ux (xx)
659 typename IntersectionInfo
661 static inline bool set_tp(Point1 const& , Point1 const& , Point1 const& , int side_rk_r,
662 bool const handle_robustness,
663 Point2 const& , Point2 const& , int side_rk_s,
664 TurnInfo& tp, IntersectionInfo const& intersection_info)
666 boost::ignore_unused_variable_warning(handle_robustness);
667 boost::ignore_unused_variable_warning(side_rk_s);
669 operation_type blocked = operation_blocked;
674 // Turning left on opposite collinear: intersection
675 tp.operations[Index].operation = operation_intersection;
678 // Turning right on opposite collinear: union
679 tp.operations[Index].operation = operation_union;
682 // No turn on opposite collinear: block, do not traverse
683 // But this "xx" is usually ignored, it is useless to include
684 // two operations blocked, so the whole point does not need
686 // So return false to indicate nothing is to be done.
687 if (AssignPolicy::include_opposite)
689 tp.operations[Index].operation = operation_opposite;
690 blocked = operation_opposite;
699 // The other direction is always blocked when collinear opposite
700 tp.operations[1 - Index].operation = blocked;
702 // If P arrives within Q, set info on P (which is done above, index=0),
703 // this turn-info belongs to the second intersection point, index=1
704 // (see e.g. figure CLO1)
705 assign_point(tp, method_collinear, intersection_info, 1 - Index);
710 static inline void empty_transformer(TurnInfo &) {}
716 typename OutputIterator,
717 typename IntersectionInfo,
721 static inline void apply(
722 Point1 const& pi, Point1 const& pj, Point1 const& pk,
723 Point2 const& qi, Point2 const& qj, Point2 const& qk,
725 // Opposite collinear can deliver 2 intersection points,
726 TurnInfo const& tp_model,
729 IntersectionInfo const& intersection_info,
730 DirInfo const& dir_info,
731 SidePolicy const& side)
733 apply(pi, pj, pk, qi, qj, qk, tp_model, out, intersection_info, dir_info, side, empty_transformer);
741 typename OutputIterator,
742 typename IntersectionInfo,
745 typename TurnTransformer
747 static inline void apply(
748 Point1 const& pi, Point1 const& pj, Point1 const& pk,
749 Point2 const& qi, Point2 const& qj, Point2 const& qk,
751 // Opposite collinear can deliver 2 intersection points,
752 TurnInfo const& tp_model,
755 IntersectionInfo const& intersection_info,
756 DirInfo const& dir_info,
757 SidePolicy const& side,
758 TurnTransformer turn_transformer,
759 bool const is_pk_valid = true, bool const is_qk_valid = true)
761 TurnInfo tp = tp_model;
763 // If P arrives within Q, there is a turn dependent on P
764 if ( dir_info.arrival[0] == 1
766 && set_tp<0>(pi, pj, pk, side.pk_wrt_p1(), true, qi, qj, side.pk_wrt_q1(), tp, intersection_info) )
768 turn_transformer(tp);
770 AssignPolicy::apply(tp, pi, qi, intersection_info, dir_info);
774 // If Q arrives within P, there is a turn dependent on Q
775 if ( dir_info.arrival[1] == 1
777 && set_tp<1>(qi, qj, qk, side.qk_wrt_q1(), false, pi, pj, side.qk_wrt_p1(), tp, intersection_info) )
779 turn_transformer(tp);
781 AssignPolicy::apply(tp, pi, qi, intersection_info, dir_info);
785 if (AssignPolicy::include_opposite)
787 // Handle cases not yet handled above
788 if ((dir_info.arrival[1] == -1 && dir_info.arrival[0] == 0)
789 || (dir_info.arrival[0] == -1 && dir_info.arrival[1] == 0))
791 for (int i = 0; i < 2; i++)
793 tp.operations[i].operation = operation_opposite;
795 for (unsigned int i = 0; i < intersection_info.count; i++)
797 assign_point(tp, method_collinear, intersection_info, i);
798 AssignPolicy::apply(tp, pi, qi, intersection_info, dir_info);
812 struct crosses : public base_turn_handler
818 typename IntersectionInfo,
821 static inline void apply(
822 Point1 const& , Point1 const& , Point1 const& ,
823 Point2 const& , Point2 const& , Point2 const& ,
825 IntersectionInfo const& intersection_info,
826 DirInfo const& dir_info)
828 assign_point(ti, method_crosses, intersection_info, 0);
831 // If Q crosses P from left to right
833 // Intersection: take Q
834 // Otherwise: vice versa
835 int const side_qi_p1 = dir_info.sides.template get<1, 0>();
836 int const index = side_qi_p1 == 1 ? 0 : 1;
837 ti.operations[index].operation = operation_union;
838 ti.operations[1 - index].operation = operation_intersection;
842 struct only_convert : public base_turn_handler
844 template<typename TurnInfo, typename IntersectionInfo>
845 static inline void apply(TurnInfo& ti, IntersectionInfo const& intersection_info)
847 assign_point(ti, method_none, intersection_info, 0); // was collinear
848 ti.operations[0].operation = operation_continue;
849 ti.operations[1].operation = operation_continue;
854 \brief Policy doing nothing
855 \details get_turn_info can have an optional policy to get/assign some
856 extra information. By default it does not, and this class
859 struct assign_null_policy
861 static bool const include_no_turn = false;
862 static bool const include_degenerate = false;
863 static bool const include_opposite = false;
870 typename IntersectionInfo,
873 static inline void apply(Info& , Point1 const& , Point2 const&, IntersectionInfo const&, DirInfo const&)
880 \brief Turn information: intersection point, method, and turn information
881 \details Information necessary for traversal phase (a phase
882 of the overlay process). The information is gathered during the
883 get_turns (segment intersection) phase.
884 \tparam Point1 point type of first segment
885 \tparam Point2 point type of second segment
886 \tparam TurnInfo type of class getting intersection and turn info
887 \tparam AssignPolicy policy to assign extra info,
888 e.g. to calculate distance from segment's first points
889 to intersection points.
890 It also defines if a certain class of points
891 (degenerate, non-turns) should be included.
893 template<typename AssignPolicy>
896 // Intersect pi-pj with qi-qj
897 // The points pk and qk are used do determine more information
898 // about the turn (turn left/right)
904 typename RobustPolicy,
905 typename OutputIterator
907 static inline OutputIterator apply(
908 Point1 const& pi, Point1 const& pj, Point1 const& pk,
909 Point2 const& qi, Point2 const& qj, Point2 const& qk,
910 bool /*is_p_first*/, bool /*is_p_last*/,
911 bool /*is_q_first*/, bool /*is_q_last*/,
912 TurnInfo const& tp_model,
913 RobustPolicy const& robust_policy,
916 typedef intersection_info<Point1, Point2, typename TurnInfo::point_type, RobustPolicy>
919 inters_info inters(pi, pj, pk, qi, qj, qk, robust_policy);
921 char const method = inters.d_info().how;
923 // Copy, to copy possibly extended fields
924 TurnInfo tp = tp_model;
926 // Select method and apply
929 case 'a' : // collinear, "at"
930 case 'f' : // collinear, "from"
931 case 's' : // starts from the middle
932 if (AssignPolicy::include_no_turn
933 && inters.i_info().count > 0)
935 only_convert::apply(tp, inters.i_info());
936 AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
941 case 'd' : // disjoint: never do anything
946 typedef touch_interior
951 // If Q (1) arrives (1)
952 if ( inters.d_info().arrival[1] == 1 )
954 policy::template apply<0>(pi, pj, pk, qi, qj, qk,
955 tp, inters.i_info(), inters.d_info(),
963 typename inters_info::robust_point2_type,
964 typename inters_info::robust_point1_type
965 > swapped_side_calc(inters.rqi(), inters.rqj(), inters.rqk(),
966 inters.rpi(), inters.rpj(), inters.rpk());
967 policy::template apply<1>(qi, qj, qk, pi, pj, pk,
968 tp, inters.i_info(), inters.d_info(),
971 AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
977 crosses<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
978 tp, inters.i_info(), inters.d_info());
979 AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
985 // Both touch (both arrive there)
986 touch<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
987 tp, inters.i_info(), inters.d_info(), inters.sides());
988 AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
994 if ( ! inters.d_info().opposite )
997 // or collinear-and-ending at intersection point
998 equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
999 tp, inters.i_info(), inters.d_info(), inters.sides());
1000 AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
1010 tp, out, inters.i_info(), inters.d_info());
1017 if ( ! inters.d_info().opposite )
1020 if ( inters.d_info().arrival[0] == 0 )
1022 // Collinear, but similar thus handled as equal
1023 equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
1024 tp, inters.i_info(), inters.d_info(), inters.sides());
1026 // override assigned method
1027 tp.method = method_collinear;
1031 collinear<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
1032 tp, inters.i_info(), inters.d_info(), inters.sides());
1035 AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
1044 >::apply(pi, pj, pk, qi, qj, qk,
1045 tp, out, inters.i_info(), inters.d_info(), inters.sides());
1051 // degenerate points
1052 if (AssignPolicy::include_degenerate)
1054 only_convert::apply(tp, inters.i_info());
1055 AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
1062 #if defined(BOOST_GEOMETRY_DEBUG_ROBUSTNESS)
1063 std::cout << "TURN: Unknown method: " << method << std::endl;
1065 #if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW)
1066 throw turn_info_exception(method);
1077 }} // namespace detail::overlay
1078 #endif //DOXYGEN_NO_DETAIL
1081 }} // namespace boost::geometry
1084 #if defined(_MSC_VER)
1085 #pragma warning(pop)
1088 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HPP