geom/segment: add segment/region intersection test
This commit is contained in:
parent
48b04765d7
commit
39bbaa5a80
@ -8,5 +8,61 @@
|
||||
|
||||
#include "segment.hpp"
|
||||
|
||||
#include "ops.hpp"
|
||||
|
||||
#include "../region.hpp"
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// TODO: Replace, ported from https://stackoverflow.com/a/100165
|
||||
template <>
|
||||
bool
|
||||
cruft::geom::intersects (cruft::geom::segment2f seg, cruft::region2f rect)
|
||||
{
|
||||
// Find min and max X for the segment
|
||||
auto [maxX, minX] = cruft::maxmin (seg.a.x, seg.b.x);
|
||||
|
||||
// Find the intersection of the segment's and rectangle's x-projections
|
||||
maxX = cruft::min (maxX, maxX > rect.away ().x);
|
||||
minX = cruft::max (minX, rect.p.x);
|
||||
|
||||
// If their projections do not intersect return false
|
||||
if (minX > maxX)
|
||||
return false;
|
||||
|
||||
// Find corresponding min and max Y for min and max X we found before
|
||||
auto minY = seg.a.y;
|
||||
auto maxY = seg.b.y;
|
||||
|
||||
auto const dx = seg.b.x - seg.a.x;
|
||||
|
||||
if (cruft::abs (dx) > 1e-6f) {
|
||||
auto const a = (seg.b.y - seg.a.y) / dx;
|
||||
auto const b = seg.a.y - a * seg.a.x;
|
||||
|
||||
minY = a * minX + b;
|
||||
maxY = a * maxX + b;
|
||||
}
|
||||
|
||||
if (minY > maxY)
|
||||
std::swap (minY, maxY);
|
||||
|
||||
// Find the intersection of the segment's and rectangle's y-projections
|
||||
maxY = cruft::min (maxY, rect.away ().y);
|
||||
minY = cruft::max (minY, rect.p.y);
|
||||
|
||||
// If Y-projections do not intersect return false
|
||||
if (minY > maxY)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <>
|
||||
bool
|
||||
cruft::geom::intersects (cruft::geom::segment2i seg, cruft::region2i rect)
|
||||
{
|
||||
return intersects (seg.cast<float> (), rect.cast<float> ());
|
||||
}
|
||||
|
@ -16,6 +16,17 @@ namespace cruft::geom {
|
||||
struct segment {
|
||||
cruft::point<S,T> a;
|
||||
cruft::point<S,T> b;
|
||||
|
||||
// Return a copy of this object with the underlying type casted to
|
||||
// the specified type.
|
||||
template <typename CastT>
|
||||
segment<S,CastT>
|
||||
cast (void) const {
|
||||
return {
|
||||
.a = a.template cast<CastT> (),
|
||||
.b = b.template cast<CastT> ()
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
#include "tap.hpp"
|
||||
|
||||
#include "geom/segment.hpp"
|
||||
#include "geom/ops.hpp"
|
||||
#include "region.hpp"
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@ -25,11 +27,54 @@ void test_point_distance (cruft::TAP::logger &tap)
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void test_region_intersection (cruft::TAP::logger &tap)
|
||||
{
|
||||
using p = cruft::point2i;
|
||||
|
||||
static struct {
|
||||
cruft::geom::segment2i a;
|
||||
cruft::region2i b;
|
||||
bool expected;
|
||||
char const *message;
|
||||
} const TESTS[] = {
|
||||
{
|
||||
.a = { p { 0, 0 }, p { 4, 4 }, },
|
||||
.b = { p { 1, 1 }, p { 2, 2 }, },
|
||||
.expected = true,
|
||||
.message = "rising into"
|
||||
},
|
||||
{
|
||||
.a = { p { 0, 0 }, p { 1, 1 } },
|
||||
.b = { p { -2, -2 }, p { 2, 2 } },
|
||||
.expected = true,
|
||||
.message = "completely internal",
|
||||
},
|
||||
{
|
||||
.a = { p { 0, 0 }, p { 1, 0 } },
|
||||
.b = { p { 0, 0 }, p { 1, 1 } },
|
||||
.expected = true,
|
||||
.message = "glancing horizontal",
|
||||
},
|
||||
{
|
||||
.a = { p { 0, 0 }, p { -1, -1 } },
|
||||
.b = { p { 0, 0 }, p { 1, 1 } },
|
||||
.expected = true,
|
||||
.message = "common origin",
|
||||
},
|
||||
};
|
||||
|
||||
for (auto const &t: TESTS)
|
||||
tap.expect_eq (intersects (t.a, t.b), t.expected, "region intersection: %!", t.message);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
int
|
||||
main (int, char**)
|
||||
{
|
||||
cruft::TAP::logger tap;
|
||||
test_point_distance (tap);
|
||||
test_region_intersection (tap);
|
||||
return tap.status ();
|
||||
}
|
Loading…
Reference in New Issue
Block a user