1515#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HPP
1616#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HPP
1717
18-
1918#include < boost/core/ignore_unused.hpp>
2019#include < boost/throw_exception.hpp>
2120
2827#include < boost/geometry/algorithms/detail/overlay/get_distance_measure.hpp>
2928#include < boost/geometry/algorithms/detail/overlay/turn_info.hpp>
3029
31- #include < boost/geometry/geometries/segment.hpp>
32-
33- #include < boost/geometry/policies/robustness/robust_point_type.hpp>
3430#include < boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp>
3531
3632// Silence warning C4127: conditional expression is constant
@@ -131,15 +127,7 @@ struct base_turn_handler
131127 return 0 ;
132128 }
133129
134- typedef typename select_coordinate_type
135- <
136- typename UniqueSubRange1::point_type,
137- typename UniqueSubRange2::point_type
138- >::type coordinate_type;
139-
140- typedef detail::distance_measure<coordinate_type> dm_type;
141-
142- dm_type const dm = get_distance_measure (range_p.at (range_index), range_p.at (range_index + 1 ), range_q.at (point_index));
130+ auto const dm = get_distance_measure (range_p.at (range_index), range_p.at (range_index + 1 ), range_q.at (point_index));
143131 return dm.measure == 0 ? 0 : dm.measure > 0 ? 1 : -1 ;
144132 }
145133
@@ -186,7 +174,8 @@ struct base_turn_handler
186174 {
187175 ti.method = method;
188176
189- // For touch/touch interior always take the intersection point 0 (there is only one).
177+ // For touch/touch interior always take the intersection point 0
178+ // (usually there is only one - but if collinear is handled as touch, both could be taken).
190179 static int const index = 0 ;
191180
192181 geometry::convert (info.intersections [index], ti.point );
@@ -225,9 +214,8 @@ struct base_turn_handler
225214 {
226215 // TODO: use comparable distance for point-point instead - but that
227216 // causes currently cycling include problems
228- typedef typename geometry::coordinate_type<Point1>::type ctype;
229- ctype const dx = get<0 >(a) - get<0 >(b);
230- ctype const dy = get<1 >(a) - get<1 >(b);
217+ auto const dx = get<0 >(a) - get<0 >(b);
218+ auto const dy = get<1 >(a) - get<1 >(b);
231219 return dx * dx + dy * dy;
232220 }
233221
@@ -259,19 +247,10 @@ struct base_turn_handler
259247 // pk/q2 is considered as collinear, but there might be
260248 // a tiny measurable difference. If so, use that.
261249 // Calculate pk // qj-qk
262- typedef detail::distance_measure
263- <
264- typename select_coordinate_type
265- <
266- typename UniqueSubRange1::point_type,
267- typename UniqueSubRange2::point_type
268- >::type
269- > dm_type;
270-
271- const bool p_closer =
250+ bool const p_closer =
272251 ti.operations [IndexP].remaining_distance
273252 < ti.operations [IndexQ].remaining_distance ;
274- dm_type const dm
253+ auto const dm
275254 = p_closer
276255 ? get_distance_measure (range_q.at (index_q - 1 ),
277256 range_q.at (index_q), range_p.at (index_p))
@@ -282,8 +261,7 @@ struct base_turn_handler
282261 {
283262 // Not truely collinear, distinguish for union/intersection
284263 // If p goes left (positive), take that for a union
285-
286- bool p_left = p_closer ? dm.is_positive () : dm.is_negative ();
264+ bool const p_left = p_closer ? dm.is_positive () : dm.is_negative ();
287265
288266 ti.operations [IndexP].operation = p_left
289267 ? operation_union : operation_intersection;
@@ -347,14 +325,9 @@ struct touch_interior : public base_turn_handler
347325 // Therefore handle it as a normal touch (two segments arrive at the
348326 // intersection point). It currently checks for zero, but even a
349327 // distance a little bit larger would do.
350- typedef typename geometry::coordinate_type
351- <
352- typename UniqueSubRange::point_type
353- >::type coor_t ;
354-
355- coor_t const location = distance_measure (info.intersections [0 ], non_touching_range.at (1 ));
356- coor_t const zero = 0 ;
357- bool const result = math::equals (location, zero);
328+ auto const dm = distance_measure (info.intersections [0 ], non_touching_range.at (1 ));
329+ decltype (dm) const zero = 0 ;
330+ bool const result = math::equals (dm, zero);
358331 return result;
359332 }
360333
@@ -540,16 +513,8 @@ struct touch : public base_turn_handler
540513 // >----->P qj is LEFT of P1 and pi is LEFT of Q2
541514 // (the other way round is also possible)
542515
543- typedef typename select_coordinate_type
544- <
545- typename UniqueSubRange1::point_type,
546- typename UniqueSubRange2::point_type
547- >::type coordinate_type;
548-
549- typedef detail::distance_measure<coordinate_type> dm_type;
550-
551- dm_type const dm_qj_p1 = get_distance_measure (range_p.at (0 ), range_p.at (1 ), range_q.at (1 ));
552- dm_type const dm_pi_q2 = get_distance_measure (range_q.at (1 ), range_q.at (2 ), range_p.at (0 ));
516+ auto const dm_qj_p1 = get_distance_measure (range_p.at (0 ), range_p.at (1 ), range_q.at (1 ));
517+ auto const dm_pi_q2 = get_distance_measure (range_q.at (1 ), range_q.at (2 ), range_p.at (0 ));
553518
554519 if (dm_qj_p1.measure > 0 && dm_pi_q2.measure > 0 )
555520 {
@@ -564,8 +529,8 @@ struct touch : public base_turn_handler
564529 return true ;
565530 }
566531
567- dm_type const dm_pj_q1 = get_distance_measure (range_q.at (0 ), range_q.at (1 ), range_p.at (1 ));
568- dm_type const dm_qi_p2 = get_distance_measure (range_p.at (1 ), range_p.at (2 ), range_q.at (0 ));
532+ auto const dm_pj_q1 = get_distance_measure (range_q.at (0 ), range_q.at (1 ), range_p.at (1 ));
533+ auto const dm_qi_p2 = get_distance_measure (range_p.at (1 ), range_p.at (2 ), range_q.at (0 ));
569534
570535 if (dm_pj_q1.measure > 0 && dm_qi_p2.measure > 0 )
571536 {
@@ -813,17 +778,9 @@ struct equal : public base_turn_handler
813778 // They turn to the same side, or continue both collinearly
814779 // Without rescaling, to check for union/intersection,
815780 // try to check side values (without any thresholds)
816- typedef typename select_coordinate_type
817- <
818- typename UniqueSubRange1::point_type,
819- typename UniqueSubRange2::point_type
820- >::type coordinate_type;
821-
822- typedef detail::distance_measure<coordinate_type> dm_type;
823-
824- dm_type const dm_pk_q2
781+ auto const dm_pk_q2
825782 = get_distance_measure (range_q.at (1 ), range_q.at (2 ), range_p.at (2 ));
826- dm_type const dm_qk_p2
783+ auto const dm_qk_p2
827784 = get_distance_measure (range_p.at (1 ), range_p.at (2 ), range_q.at (2 ));
828785
829786 if (dm_qk_p2.measure != dm_pk_q2.measure )
@@ -965,8 +922,57 @@ template
965922>
966923struct collinear : public base_turn_handler
967924{
925+ template
926+ <
927+ typename IntersectionInfo,
928+ typename UniqueSubRange1,
929+ typename UniqueSubRange2,
930+ typename DirInfo
931+ >
932+ static bool handle_as_equal (IntersectionInfo const & info,
933+ UniqueSubRange1 const & range_p,
934+ UniqueSubRange2 const & range_q,
935+ DirInfo const & dir_info)
936+ {
937+ #if defined(BOOST_GEOMETRY_USE_RESCALING)
938+ return false ;
939+ #endif
940+ int const arrival_p = dir_info.arrival [0 ];
941+ int const arrival_q = dir_info.arrival [1 ];
942+ if (arrival_p * arrival_q != -1 || info.count != 2 )
943+ {
944+ // Code below assumes that either p or q arrives in the other segment
945+ return false ;
946+ }
947+
948+ auto const dm = distance_measure (info.intersections [1 ],
949+ arrival_p == 1 ? range_q.at (1 ) : range_p.at (1 ));
950+ decltype (dm) const zero = 0 ;
951+ return math::equals (dm, zero);
952+ }
953+
968954 /*
969- arrival P pk//p1 qk//q1 product* case result
955+ Either P arrives within Q (arrival_p == -1) or Q arrives within P.
956+
957+ Typical situation:
958+ ^q2
959+ /
960+ ^q1
961+ / ____ ip[1]
962+ //|p1 } this section of p/q is colllinear
963+ q0// | } ____ ip[0]
964+ / |
965+ / v
966+ p0 p2
967+
968+ P arrives (at p1) in segment Q (between q0 and q1).
969+ Therefore arrival_p == 1
970+ P (p2) goes to the right (-1). Follow P for intersection, or follow Q for union.
971+ Therefore if (arrival_p==1) and side_p==-1, result = iu
972+
973+ Complete table:
974+
975+ arrival P pk//p1 qk//q1 product case result
970976 1 1 1 CLL1 ui
971977 -1 1 -1 CLL2 iu
972978 1 1 1 CLR1 ui
@@ -980,7 +986,9 @@ struct collinear : public base_turn_handler
980986 1 0 0 CC1 cc
981987 -1 0 0 CC2 cc
982988
983- *product = arrival * (pk//p1 or qk//q1)
989+ Resulting in the rule:
990+ The arrival-info multiplied by the relevant side delivers the result.
991+ product = arrival * (pk//p1 or qk//q1)
984992
985993 Stated otherwise:
986994 - if P arrives: look at turn P
@@ -989,13 +997,6 @@ struct collinear : public base_turn_handler
989997 - if P arrives and P turns right: intersection for P
990998 - if Q arrives and Q turns left: union for Q (=intersection for P)
991999 - if Q arrives and Q turns right: intersection for Q (=union for P)
992-
993- ROBUSTNESS: p and q are collinear, so you would expect
994- that side qk//p1 == pk//q1. But that is not always the case
995- in near-epsilon ranges. Then decision logic is different.
996- If p arrives, q is further, so the angle qk//p1 is (normally)
997- more precise than pk//p1
998-
9991000 */
10001001 template
10011002 <
@@ -1016,29 +1017,25 @@ struct collinear : public base_turn_handler
10161017 // Copy the intersection point in TO direction
10171018 assign_point (ti, method_collinear, info, non_opposite_to_index (info));
10181019
1019- int const arrival = dir_info.arrival [0 ];
1020+ int const arrival_p = dir_info.arrival [0 ];
10201021 // Should not be 0, this is checked before
1021- BOOST_GEOMETRY_ASSERT (arrival != 0 );
1022+ BOOST_GEOMETRY_ASSERT (arrival_p != 0 );
10221023
10231024 bool const has_pk = ! range_p.is_last_segment ();
10241025 bool const has_qk = ! range_q.is_last_segment ();
10251026 int const side_p = has_pk ? side.pk_wrt_p1 () : 0 ;
10261027 int const side_q = has_qk ? side.qk_wrt_q1 () : 0 ;
10271028
10281029 // If p arrives, use p, else use q
1029- int const side_p_or_q = arrival == 1
1030+ int const side_p_or_q = arrival_p == 1
10301031 ? side_p
10311032 : side_q
10321033 ;
10331034
1034- // See comments above,
1035- // resulting in a strange sort of mathematic rule here:
1036- // The arrival-info multiplied by the relevant side
1037- // delivers a consistent result.
1035+ // Calculate product according to comments above.
1036+ int const product = arrival_p * side_p_or_q;
10381037
1039- int const product = arrival * side_p_or_q;
1040-
1041- if (product == 0 )
1038+ if (product == 0 )
10421039 {
10431040 both (ti, operation_continue);
10441041 }
@@ -1186,11 +1183,11 @@ private :
11861183 {
11871184 TurnInfo tp = tp_model;
11881185
1189- int const p_arrival = info.d_info ().arrival [0 ];
1190- int const q_arrival = info.d_info ().arrival [1 ];
1186+ int const arrival_p = info.d_info ().arrival [0 ];
1187+ int const arrival_q = info.d_info ().arrival [1 ];
11911188
11921189 // If P arrives within Q, there is a turn dependent on P
1193- if ( p_arrival == 1
1190+ if ( arrival_p == 1
11941191 && ! range_p.is_last_segment ()
11951192 && set_tp<0 >(side.pk_wrt_p1 (), tp, info.i_info ()) )
11961193 {
@@ -1200,7 +1197,7 @@ private :
12001197 }
12011198
12021199 // If Q arrives within P, there is a turn dependent on Q
1203- if ( q_arrival == 1
1200+ if ( arrival_q == 1
12041201 && ! range_q.is_last_segment ()
12051202 && set_tp<1 >(side.qk_wrt_q1 (), tp, info.i_info ()) )
12061203 {
@@ -1212,8 +1209,8 @@ private :
12121209 if (AssignPolicy::include_opposite)
12131210 {
12141211 // Handle cases not yet handled above
1215- if ((q_arrival == -1 && p_arrival == 0 )
1216- || (p_arrival == -1 && q_arrival == 0 ))
1212+ if ((arrival_q == -1 && arrival_p == 0 )
1213+ || (arrival_p == -1 && arrival_q == 0 ))
12171214 {
12181215 for (unsigned int i = 0 ; i < 2 ; i++)
12191216 {
@@ -1420,9 +1417,10 @@ struct get_turn_info
14201417 // Collinear
14211418 if ( ! inters.d_info ().opposite )
14221419 {
1423-
1424- if ( inters.d_info (). arrival [ 0 ] == 0 )
1420+ if (inters. d_info (). arrival [ 0 ] == 0
1421+ || collinear<TurnInfo>:: handle_as_equal ( inters.i_info (), range_p, range_q, inters. d_info ()) )
14251422 {
1423+ // Both segments arrive at the second intersection point
14261424 handle_as_equal = true ;
14271425 }
14281426 else
0 commit comments