geom/ray: make ray intersections more robust

This commit is contained in:
Danny Robson 2018-05-04 17:06:32 +10:00
parent 3e5c89f643
commit c33a679e81
3 changed files with 31 additions and 38 deletions

View File

@ -90,8 +90,13 @@ namespace util::geom {
///////////////////////////////////////////////////////////////////////////
// returns the distance along a ray to an aabb
//
// the return value may be negative if the plane lies behind the ray.
// the return value may be infinity in the case the ray and plane are parallel
// the distance will never be negative
//
// the origin point of the ray does not provoke an intersection, so the
// returned distances _should_ always be strictly positive.
//
// if a forward intersection cannot be found then 'infinity' is returned
// instead.
template <size_t S, typename T>
constexpr T
distance (const ray<S,T> r, const aabb<S,T> b)
@ -105,12 +110,17 @@ namespace util::geom {
const auto tmax = min (max (t1, t2));
// did not intersect
if (tmin > tmax)
if (tmin >= tmax)
return std::numeric_limits<T>::infinity ();
// closest is behind us
if (tmin < 0)
return tmax;
if (tmin <= 0) {
if (tmax <= 0) {
return std::numeric_limits<T>::infinity ();
} else {
return tmax;
}
}
// closest is in front of us
return tmin;

View File

@ -12,7 +12,7 @@ main (int, char**)
util::TAP::logger tap;
{
const auto upright = normalised (util::vector2f {1});
static struct {
util::point2f lo;
@ -25,12 +25,24 @@ main (int, char**)
const char *message;
} const TESTS[] {
{
{ 0, 0 }, { 1, 1 },
{ 0, 0 }, upright,
std::sqrt (2.f),
"ray on aabb corner, pointing to opposite corner",
},
{
{ 0, 0 }, { 1, 1 },
{ 0, 1 }, upright,
INFINITY,
"ray on aabb implied corner, pointing away",
},
{
{ 1, 1 }, { 9, 9 },
{ 2, 2 }, { 1/std::sqrt (2.f), 1/std::sqrt (2.f) },
{ 2, 2 }, upright,
std::sqrt (7.f * 7 * 2),
"ray doesn't give negative distance to closest edge"
}
"ray inside aabb, close to one corner and pointing to far corner",
},
};
for (auto const &t: TESTS) {

View File

@ -20,34 +20,6 @@ test_intersect_plane (util::TAP::logger &tap)
}
//-----------------------------------------------------------------------------
void
test_intersect_aabb (util::TAP::logger &tap)
{
using util::geom::aabb2f;
// trivial case: unit aabb at origin, ray from (0.5,-0.5) upwards
const aabb2f box {
{ 0.f, 0.f },
{ 1.f, 1.f }
};
const ray2f forward {
util::point2f { 0.5f, -0.5f },
util::vector2f { 0.0f, 1.0f }
};
tap.expect_eq (distance (forward, box), 0.5f, "ray-aabb intersect");
const ray2f behind {
util::point2f { 0.5f, 2.0f },
util::vector2f { 0.0f, 1.0f }
};
tap.expect_eq (distance (behind, box), -1.f, "ray-aabb intersect behind");
}
//-----------------------------------------------------------------------------
int
main (void)
@ -55,7 +27,6 @@ main (void)
util::TAP::logger tap;
test_intersect_plane (tap);
test_intersect_aabb (tap);
return tap.status ();
}