geom: move distance/intersection tests outside classes
This commit is contained in:
parent
b1276519ef
commit
0646b1c13b
@ -22,7 +22,7 @@
|
||||
#include "../matrix.hpp"
|
||||
|
||||
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>
|
||||
struct plane {
|
||||
plane () = default;
|
||||
|
70
geom/ray.cpp
70
geom/ray.cpp
@ -24,76 +24,6 @@
|
||||
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
|
||||
template <size_t S, typename T>
|
||||
|
105
geom/ray.hpp
105
geom/ray.hpp
@ -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
|
||||
T closest (point<S,T>) const;
|
||||
|
||||
@ -60,20 +54,99 @@ namespace util::geom {
|
||||
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<3,float> ray3f;
|
||||
}
|
||||
|
@ -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::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");
|
||||
}
|
||||
|
||||
|
||||
@ -32,18 +32,18 @@ test_intersect_aabb (util::TAP::logger &tap)
|
||||
};
|
||||
|
||||
const ray2f forward {
|
||||
util::point2f { 0.5f, -0.5f },
|
||||
util::vector2f { 0.f, 1.f }
|
||||
util::point2f { 0.5f, -0.5f },
|
||||
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 {
|
||||
util::point2f { 0.5f, 2.f },
|
||||
util::vector2f { 0.f, 1.f }
|
||||
util::point2f { 0.5f, 2.0f },
|
||||
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 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}};
|
||||
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}};
|
||||
tap.expect_nan (r2.intersect (s), "ray-sphere no-intersect");
|
||||
tap.expect_nan (distance (r2, s), "ray-sphere no-intersect");
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user