geom: move distance/intersection tests outside classes

This commit is contained in:
Danny Robson 2018-03-13 23:27:37 +11:00
parent b1276519ef
commit 0646b1c13b
4 changed files with 100 additions and 97 deletions

View File

@ -22,7 +22,7 @@
#include "../matrix.hpp" #include "../matrix.hpp"
namespace util::geom { namespace util::geom {
/// represents an S dimensional plane in parametric form /// represents an S dimensional plane in parametric form: ax + by + cz + d = 0
template <size_t S, typename T> template <size_t S, typename T>
struct plane { struct plane {
plane () = default; plane () = default;

View File

@ -24,76 +24,6 @@
using util::geom::ray; using util::geom::ray;
///////////////////////////////////////////////////////////////////////////////
/// returns the distance along the ray in a ray-plane intersection
///
/// returns inf if parallel
/// returns 0 if corayar
template <size_t S, typename T>
T
ray<S,T>::intersect (plane<S,T> q) const
{
return dot (q.coefficients, origin. template redim<S+1> (1)) /
dot (q.coefficients, direction.template redim<S+1> (0));
}
///----------------------------------------------------------------------------
/// returns the distance from origin to AABB intersection
///
/// returns NaN on miss
/// returns NaN if behind
template <size_t S, typename T>
T
ray<S,T>::intersect (aabb<S,T> r) const
{
auto t1 = (r.lo - origin) / direction;
auto t2 = (r.hi - origin) / direction;
auto vmin = min (t1, t2);
auto vmax = max (t1, t2);
auto tmin = max (vmin);
auto tmax = min (vmax);
// closest intersection is behind us
if (tmax < 0)
return std::numeric_limits<T>::quiet_NaN ();
// missed intersection
if (tmin > tmax)
return std::numeric_limits<T>::quiet_NaN ();
return tmin;
}
///----------------------------------------------------------------------------
/// returns the smallest distance from ray origin to a sphere intersection
///
/// returns NaN on miss
/// returns NaN if behind
template <size_t S, typename T>
T
ray<S,T>::intersect (sphere<S,T> s) const
{
T b = dot (direction, origin - s.centre);
T c = dot (origin - s.centre, origin - s.centre) - s.radius * s.radius;
T D = b * b - c;
if (D < 0)
return std::numeric_limits<T>::quiet_NaN ();
auto t_ = std::sqrt (D);
auto t0 = -b + t_;
auto t1 = -b - t_;
return t1 >= 0 ? t1 :
t0 >= 0 ? t0 :
std::numeric_limits<T>::quiet_NaN ();
}
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
/// returns the closest parameter along the ray to a given point /// returns the closest parameter along the ray to a given point
template <size_t S, typename T> template <size_t S, typename T>

View File

@ -44,12 +44,6 @@ namespace util::geom {
} }
//---------------------------------------------------------------------
// intersection tests
T intersect (plane<S,T>) const;
T intersect (aabb<S,T>) const;
T intersect (sphere<S,T>) const;
// queries // queries
T closest (point<S,T>) const; T closest (point<S,T>) const;
@ -60,20 +54,99 @@ namespace util::geom {
vector<S,T> direction; vector<S,T> direction;
}; };
template <std::size_t S, typename T>
constexpr auto ///////////////////////////////////////////////////////////////////////////
make_ray (point<S,T> p, vector<S,T> d) noexcept /// returns the distance along the ray in a ray-plane intersection
///
/// returns inf if parallel
/// returns 0 if coplanar
template <size_t S, typename T>
constexpr T
distance (const ray<S,T> r, const plane<S,T> p)
{ {
return ray<S,T> { p, d }; return dot (p.coefficients, r.origin. template redim<S+1> (1)) /
dot (p.coefficients, r.direction.template redim<S+1> (0));
} }
template <std::size_t S, typename T>
constexpr auto
make_ray (point<S,T> p, point<S,T> q)
{
return ray<S,T> { p, q };
};
//-------------------------------------------------------------------------
template <size_t S, typename T>
constexpr bool
intersects (const ray<S,T> r, const plane<S,T> p)
{
const auto d = distance (r, p);
return d >= 0 && std::isfinite (d);
}
///////////////////////////////////////////////////////////////////////////
// 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 NaN in the case the ray and plane are parallel
template <size_t S, typename T>
constexpr T
distance (const ray<S,T> r, const aabb<S,T> b)
{
const auto t1 = (b.lo - r.origin) / r.direction;
const auto t2 = (b.hi - r.origin) / r.direction;
const auto tmin = max (min (t1, t2));
const auto tmax = min (max (t1, t2));
// did not intersect
if (tmin > tmax)
return std::numeric_limits<T>::quiet_NaN ();
// closest is behind us
if (tmax < 0)
return tmax;
// closest is in front of us
return tmin;
}
///////////////////////////////////////////////////////////////////////////
/// returns the smallest distance from a ray to a sphere intersection
///
/// returns NaN on miss
/// returns NaN if behind
template <size_t S, typename T>
constexpr T
distance (const ray<S,T> r, const sphere<S,T> s)
{
const T b = dot (r.direction, r.origin - s.centre);
const T c = dot (r.origin - s.centre, r.origin - s.centre) - s.radius * s.radius;
const T D = b * b - c;
// no intersection
if (D < 0)
return std::numeric_limits<T>::quiet_NaN ();
auto t_ = std::sqrt (D);
auto t0 = -b + t_;
auto t1 = -b - t_;
return t1 >= 0 ? t1 :
t0 >= 0 ? t0 :
std::numeric_limits<T>::quiet_NaN ();
}
//-------------------------------------------------------------------------
// convenience method to test a ray intersects an aabb
template <size_t S, typename T>
constexpr bool
intersects (const ray<S,T> r, const aabb<S,T> b)
{
return distance (r, b) >= 0;
}
///////////////////////////////////////////////////////////////////////////
typedef ray<2,float> ray2f; typedef ray<2,float> ray2f;
typedef ray<3,float> ray3f; typedef ray<3,float> ray3f;
} }

View File

@ -15,7 +15,7 @@ test_intersect_plane (util::TAP::logger &tap)
const util::geom::ray3f l (util::point3f {0,0,0}, util::vector3f {0,0, 1}); const util::geom::ray3f l (util::point3f {0,0,0}, util::vector3f {0,0, 1});
const util::geom::plane3f p (util::point3f {0,0,1}, util::vector3f {0,0,-1}); const util::geom::plane3f p (util::point3f {0,0,1}, util::vector3f {0,0,-1});
tap.expect_eq (l.intersect (p), 1.f, "ray-plane intersect"); tap.expect_eq (distance (l, p), 1.f, "ray-plane intersect");
} }
@ -33,17 +33,17 @@ test_intersect_aabb (util::TAP::logger &tap)
const ray2f forward { const ray2f forward {
util::point2f { 0.5f, -0.5f }, util::point2f { 0.5f, -0.5f },
util::vector2f { 0.f, 1.f } util::vector2f { 0.0f, 1.0f }
}; };
tap.expect_eq (forward.intersect (box), 0.5f, "ray-aabb intersect"); tap.expect_eq (distance (forward, box), 0.5f, "ray-aabb intersect");
const ray2f behind { const ray2f behind {
util::point2f { 0.5f, 2.f }, util::point2f { 0.5f, 2.0f },
util::vector2f { 0.f, 1.f } util::vector2f { 0.0f, 1.0f }
}; };
tap.expect_nan (behind.intersect (box), "ray-aabb intersect behind"); tap.expect_eq (distance (behind, box), -1.f, "ray-aabb intersect behind");
} }
@ -56,13 +56,13 @@ test_intersect_sphere (util::TAP::logger &tap)
const sphere3f s = {{0.f, 0.f, 0.f}, 1.f}; const sphere3f s = {{0.f, 0.f, 0.f}, 1.f};
const ray3f r0 {util::point3f {0.f, 2.f, 0.f}, util::vector3f {0.f, -1.f, 0.f}}; const ray3f r0 {util::point3f {0.f, 2.f, 0.f}, util::vector3f {0.f, -1.f, 0.f}};
tap.expect_eq (r0.intersect (s), 1.f, "ray-sphere simple"); tap.expect_eq (distance (r0, s), 1.f, "ray-sphere simple");
const ray3f r1 {util::point3f {0.f, 1.f, 0.f}, util::vector3f {0.f, 1.f, 0.f}}; const ray3f r1 {util::point3f {0.f, 1.f, 0.f}, util::vector3f {0.f, 1.f, 0.f}};
tap.expect_eq (r1.intersect (s), 0.f, "ray-sphere adjacent"); tap.expect_eq (distance (r1, s), 0.f, "ray-sphere adjacent");
const ray3f r2 {util::point3f {0.f, 2.f, 0.f}, util::vector3f {0.f, 1.f, 0.f}}; const ray3f r2 {util::point3f {0.f, 2.f, 0.f}, util::vector3f {0.f, 1.f, 0.f}};
tap.expect_nan (r2.intersect (s), "ray-sphere no-intersect"); tap.expect_nan (distance (r2, s), "ray-sphere no-intersect");
} }