diff --git a/Intersections_2/include/CGAL/Intersections_2/Segment_2_Segment_2.h b/Intersections_2/include/CGAL/Intersections_2/Segment_2_Segment_2.h index d912b2faf30..19cfb0c0548 100644 --- a/Intersections_2/include/CGAL/Intersections_2/Segment_2_Segment_2.h +++ b/Intersections_2/include/CGAL/Intersections_2/Segment_2_Segment_2.h @@ -34,6 +34,22 @@ namespace Intersections { namespace internal { +// indices of lexicographically smallest endpoints +// depending on config parameter of S2S2_inter_info. +// {s1_id0,s1_id1,s2_id0,s2_id1} +constexpr int s2s2_id[8][4] = +{ +// seg1 seg2 + { 0,1, 0,1 }, + { 0,1, 1,0 }, + { 1,0, 0,1 }, + { 1,0, 1,0 }, + { 0,1, 0,1 }, + { 1,0, 0,1 }, + { 0,1, 1,0 }, + { 1,0, 1,0 } +}; + // struct used to report the combinaric of the intersection // of 2 2D segments. // More information could be gathered if exposed in do_intersect. @@ -43,9 +59,20 @@ struct S2S2_inter_info bool inter = false; bool dim = 0; std::array pt_ids = {-1,-1}; + // integer in [0,7] indicating segment endpoint ordering for determinism + // 0: p0 < p1 - p2 < p3 - p0 < p2 + // 1: p0 < p1 - p3 < p2 - p0 < p3 + // 2: p1 < p0 - p2 < p3 - p1 < p2 + // 3: p1 < p0 - p3 < p2 - p1 < p3 + // 4: p2 < p3 - p0 < p1 - p2 < p0 + // 5: p2 < p3 - p1 < p0 - p2 < p1 + // 6: p3 < p2 - p0 < p1 - p3 < p0 + // 7: p3 < p2 - p1 < p0 - p3 < p1 + int config; - S2S2_inter_info(bool inter) + S2S2_inter_info(bool inter, int c=-1) : inter(inter) + , config(c) {} // intersection is an input endpoint @@ -77,7 +104,7 @@ seg_seg_do_intersect_crossing( const typename K::Point_2& p1, const typename K::Point_2& p2, const typename K::Point_2& p3, const typename K::Point_2& p4, int /* i1 */, int i2, int i3, int /* i4 */, - const K& k, bool extra_test) + const K& k, bool extra_test, int config) { switch (make_certain(k.orientation_2_object()(p1,p2,p3))) { case LEFT_TURN: @@ -89,7 +116,7 @@ seg_seg_do_intersect_crossing( case RIGHT_TURN: return S2S2_inter_info(false); case LEFT_TURN: - return S2S2_inter_info(true); + return S2S2_inter_info(true, config); default: CGAL_unreachable(); } @@ -101,7 +128,7 @@ seg_seg_do_intersect_crossing( case COLLINEAR: return S2S2_inter_info(i2); case RIGHT_TURN: - return S2S2_inter_info(true); + return S2S2_inter_info(true, config); case LEFT_TURN: return S2S2_inter_info(false); default: @@ -138,7 +165,7 @@ seg_seg_do_intersect_contained( const typename K::Point_2& p1, const typename K::Point_2& p2, const typename K::Point_2& p3, const typename K::Point_2& p4, int /* i1 */, int /* i2 */, int i3, int i4, - const K& k, bool extra_test) + const K& k, bool extra_test, int config) { switch (make_certain(k.orientation_2_object()(p1,p2,p3))) { case LEFT_TURN: @@ -148,7 +175,7 @@ seg_seg_do_intersect_contained( case COLLINEAR: return S2S2_inter_info(i4); case RIGHT_TURN: - return S2S2_inter_info(true); + return S2S2_inter_info(true, config); case LEFT_TURN: return S2S2_inter_info(false); default: @@ -164,7 +191,7 @@ seg_seg_do_intersect_contained( case RIGHT_TURN: return S2S2_inter_info(false); case LEFT_TURN: - return S2S2_inter_info(true); + return S2S2_inter_info(true, config); default: CGAL_unreachable(); } @@ -215,8 +242,8 @@ do_intersect_with_info(const typename K::Segment_2 &seg1, typename K::Compare_xy_2 compare_xy; // first try to filter using the bbox of the segments - if (less_xy(A2,B1) - || less_xy(B2,A1)) + if (certainly(less_xy(A2,B1)) + || certainly(less_xy(B2,A1))) return S2S2_inter_info(false); switch(make_certain(compare_xy(A1,B1))) { @@ -229,14 +256,14 @@ do_intersect_with_info(const typename K::Segment_2 &seg1, case LARGER: switch(make_certain(compare_xy(A2,B2))) { case SMALLER: - return seg_seg_do_intersect_crossing(A1,A2,B1,B2, A1_id,A2_id,B1_id+2,B2_id+2, k, extra_test); + return seg_seg_do_intersect_crossing(A1,A2,B1,B2, A1_id,A2_id,B1_id+2,B2_id+2, k, extra_test, (seg1_is_left_to_right ? 0:2) + (seg2_is_left_to_right ? 0:1) ); case EQUAL: // A1 < B1 < B2 = A1 if (extra_test && k.collinear_2_object()(A1, A2, B1)) return S2S2_inter_info(B1_id+2, B2_id+2); // DI_MORE_INFO_TAG: A2==B2 but only B2 is reported return S2S2_inter_info(A2_id); // DI_MORE_INFO_TAG: A2==B2 but only A2 is reported case LARGER: - return seg_seg_do_intersect_contained(A1,A2,B1,B2, A1_id,A2_id,B1_id+2,B2_id+2, k, extra_test); + return seg_seg_do_intersect_contained(A1,A2,B1,B2, A1_id,A2_id,B1_id+2,B2_id+2, k, extra_test, (seg1_is_left_to_right ? 0:2) + (seg2_is_left_to_right ? 0:1)); default: CGAL_unreachable(); } @@ -275,14 +302,14 @@ do_intersect_with_info(const typename K::Segment_2 &seg1, case LARGER: switch(make_certain(compare_xy(B2,A2))) { case SMALLER: - return seg_seg_do_intersect_crossing(B1,B2,A1,A2, B1_id+2,B2_id+2,A1_id,A2_id, k, extra_test); + return seg_seg_do_intersect_crossing(B1,B2,A1,A2, B1_id+2,B2_id+2,A1_id,A2_id, k, extra_test, 4 + (seg1_is_left_to_right ? 0:1) + (seg2_is_left_to_right ? 0:2)); case EQUAL: // B1 < A1 < A2 = B2 if (extra_test && k.collinear_2_object()(B1, A1, B2)) return S2S2_inter_info(A1_id, A2_id); // DI_MORE_INFO_TAG: A2==B2 but only A2 is reported return S2S2_inter_info(A2_id); // DI_MORE_INFO_TAG: A2==B2 but only A2 is reported case LARGER: - return seg_seg_do_intersect_contained(B1,B2,A1,A2, B1_id+2,B2_id+2,A1_id,A2_id, k, extra_test); + return seg_seg_do_intersect_contained(B1,B2,A1,A2, B1_id+2,B2_id+2,A1_id,A2_id, k, extra_test, 4 + (seg1_is_left_to_right ? 0:1) + (seg2_is_left_to_right ? 0:2)); default: CGAL_unreachable(); } @@ -366,15 +393,22 @@ Segment_2_Segment_2_pair::intersection_type() const } // segments intersect in their interiors - typename K::FT s1_dx = _seg1->point(0).x() - _seg1->point(1).x(), - s1_dy = _seg1->point(0).y() - _seg1->point(1).y(), - s2_dx = _seg2->point(1).x() - _seg2->point(0).x(), - s2_dy = _seg2->point(1).y() - _seg2->point(0).y(), - lx = _seg2->point(1).x() - _seg1->point(1).x(), - ly = _seg2->point(1).y() - _seg1->point(1).y(); + int c = inter_info.config; + std::array pts = c < 4 + ? CGAL::make_array( _seg1->point(s2s2_id[c][0]), _seg1->point(s2s2_id[c][1]), + _seg2->point(s2s2_id[c][2]), _seg2->point(s2s2_id[c][3]) ) + : CGAL::make_array( _seg2->point(s2s2_id[c][2]), _seg2->point(s2s2_id[c][3]), + _seg1->point(s2s2_id[c][0]), _seg1->point(s2s2_id[c][1]) ); + + typename K::FT s1_dx = pts[0].x() - pts[1].x(), + s1_dy = pts[0].y() - pts[1].y(), + s2_dx = pts[3].x() - pts[2].x(), + s2_dy = pts[3].y() - pts[2].y(), + lx = pts[3].x() - pts[1].x(), + ly = pts[3].y() - pts[1].y(); typename K::FT alpha = (lx*s2_dy-ly*s2_dx)/(s1_dx*s2_dy-s1_dy*s2_dx); - _intersection_point = K().construct_barycenter_2_object()(_seg1->point(0), alpha, _seg1->point(1)); + _intersection_point = K().construct_barycenter_2_object()(pts[0], alpha, pts[1]); return _result; }