geom: move distance/intersection tests outside classes
This commit is contained in:
parent
b1276519ef
commit
0646b1c13b
@ -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;
|
||||||
|
70
geom/ray.cpp
70
geom/ray.cpp
@ -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>
|
||||||
|
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
|
// 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;
|
||||||
}
|
}
|
||||||
|
@ -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");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user