mirror of https://github.com/CGAL/cgal
make the crossing point computation deterministic
This commit is contained in:
parent
fb764adef8
commit
f6f2b28b0e
|
|
@ -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<int, 2> 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<K>::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<typename K::Point_2, 4> 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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue