geom/segment: add segment-segment intersection test
This commit is contained in:
parent
33816fab94
commit
0c49eb5845
@ -69,6 +69,72 @@ cruft::geom::intersects (cruft::geom::segment2i seg, cruft::region2i rect)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
template <>
|
||||||
|
bool
|
||||||
|
cruft::geom::intersects (cruft::geom::segment2f ab, cruft::point2f p)
|
||||||
|
{
|
||||||
|
auto const hi = max (ab.a, ab.b);
|
||||||
|
auto const lo = min (ab.a, ab.b);
|
||||||
|
|
||||||
|
return all (p <= hi) and all (p >= lo);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// segment-segment intersection in 2D is derived from
|
||||||
|
// https://www.geeksforgeeks.org/check-if-two-given-line-segments-intersect
|
||||||
|
//
|
||||||
|
// The idea is to check the winding of 4 triangles created by the segment.
|
||||||
|
//
|
||||||
|
// Co-linear segments need some additional tests to determine if points of one segment lie on the other.
|
||||||
|
|
||||||
|
|
||||||
|
/// \return 0 if colinear, 1 for clockwise, -1 for counter-clockwise
|
||||||
|
static int
|
||||||
|
winding (
|
||||||
|
cruft::point2f const p,
|
||||||
|
cruft::point2f const q,
|
||||||
|
cruft::point2f const r
|
||||||
|
) {
|
||||||
|
auto const qp = q - p;
|
||||||
|
auto const rq = r - q;
|
||||||
|
|
||||||
|
auto const c = cross (qp, rq);
|
||||||
|
|
||||||
|
if (cruft::exactly_zero (c))
|
||||||
|
return 0;
|
||||||
|
else if (c > 0)
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
template <>
|
||||||
|
bool
|
||||||
|
cruft::geom::intersects (
|
||||||
|
cruft::geom::segment2f const s0,
|
||||||
|
cruft::geom::segment2f const s1
|
||||||
|
) {
|
||||||
|
auto const w0 = winding (s0.a, s0.b, s1.a);
|
||||||
|
auto const w1 = winding (s0.a, s0.b, s1.b);
|
||||||
|
auto const w2 = winding (s1.a, s1.b, s0.a);
|
||||||
|
auto const w3 = winding (s1.a, s1.b, s0.b);
|
||||||
|
|
||||||
|
if (w0 != w1 and w2 != w3)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (w0 == 0 and intersects (s0, s1.a)) return true;
|
||||||
|
if (w1 == 0 and intersects (s0, s1.b)) return true;
|
||||||
|
if (w2 == 0 and intersects (s1, s0.a)) return true;
|
||||||
|
if (w3 == 0 and intersects (s1, s0.b)) return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
template <>
|
template <>
|
||||||
cruft::geom::aabb3f
|
cruft::geom::aabb3f
|
||||||
|
@ -6,7 +6,8 @@
|
|||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
void test_point_distance (cruft::TAP::logger &tap)
|
void
|
||||||
|
test_point_distance (cruft::TAP::logger &tap)
|
||||||
{
|
{
|
||||||
static struct {
|
static struct {
|
||||||
cruft::point3f a, b;
|
cruft::point3f a, b;
|
||||||
@ -27,8 +28,9 @@ void test_point_distance (cruft::TAP::logger &tap)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
void test_region_intersection (cruft::TAP::logger &tap)
|
void
|
||||||
|
test_region_intersection (cruft::TAP::logger &tap)
|
||||||
{
|
{
|
||||||
using p = cruft::point2i;
|
using p = cruft::point2i;
|
||||||
|
|
||||||
@ -70,7 +72,58 @@ void test_region_intersection (cruft::TAP::logger &tap)
|
|||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
void test_bresenham (cruft::TAP::logger &tap)
|
void
|
||||||
|
test_segment_intersection (cruft::TAP::logger &tap)
|
||||||
|
{
|
||||||
|
using cruft::geom::segment2f;
|
||||||
|
using cruft::point2f;
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
segment2f a;
|
||||||
|
segment2f b;
|
||||||
|
bool expected;
|
||||||
|
char const *message;
|
||||||
|
} TESTS[] = {
|
||||||
|
{
|
||||||
|
.a = { { 1, 1 }, { 10, 1 } },
|
||||||
|
.b = { { 1, 2 }, { 10, 2 } },
|
||||||
|
.expected = false,
|
||||||
|
.message = "parallel"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.a = { { 10, 0 }, { 0, 10 } },
|
||||||
|
.b = { { 0, 0 }, { 10, 10 } },
|
||||||
|
.expected = true,
|
||||||
|
.message = "right angles"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.a = { { -5, -5 }, { 0, 0 } },
|
||||||
|
.b = { { 1, 1 }, { 10, 10 } },
|
||||||
|
.expected = false,
|
||||||
|
.message = "co-linear stopping early",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.a = { { -5, -5 }, { 5, 5 } },
|
||||||
|
.b = { { 0, 0 }, { 10, 10 } },
|
||||||
|
.expected = true,
|
||||||
|
.message = "co-linear stopping midway",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
for (auto const &t: TESTS) {
|
||||||
|
tap.expect_eq (
|
||||||
|
t.expected,
|
||||||
|
intersects (t.a, t.b),
|
||||||
|
"segment-segment {}",
|
||||||
|
t.message
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
void
|
||||||
|
test_bresenham (cruft::TAP::logger &tap)
|
||||||
{
|
{
|
||||||
static struct {
|
static struct {
|
||||||
cruft::point2i a;
|
cruft::point2i a;
|
||||||
@ -120,6 +173,7 @@ main (int, char**)
|
|||||||
cruft::TAP::logger tap;
|
cruft::TAP::logger tap;
|
||||||
test_point_distance (tap);
|
test_point_distance (tap);
|
||||||
test_region_intersection (tap);
|
test_region_intersection (tap);
|
||||||
|
test_segment_intersection (tap);
|
||||||
test_bresenham (tap);
|
test_bresenham (tap);
|
||||||
return tap.status ();
|
return tap.status ();
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user