sphere: move ray tests into sphere's unit

This commit is contained in:
Danny Robson 2018-04-13 18:46:37 +10:00
parent 28148dd890
commit bef0aa4929
5 changed files with 89 additions and 51 deletions

View File

@ -494,6 +494,7 @@ if (TESTS)
geom/aabb
geom/ray
geom/frustum
geom/sphere
hash/checksum
hash/crc
hash/fasthash

View File

@ -11,7 +11,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
* Copyright 2015-2018 Danny Robson <danny@nerdcruft.net>
*/
#ifndef __UTIL_GEOM_RAY_HPP
@ -19,7 +19,6 @@
#include "aabb.hpp"
#include "plane.hpp"
#include "sphere.hpp"
#include "../vector.hpp"
#include "../point.hpp"
@ -108,34 +107,6 @@ namespace util::geom {
}
///////////////////////////////////////////////////////////////////////////
/// 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>

View File

@ -11,7 +11,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
* Copyright 2015-2018 Danny Robson <danny@nerdcruft.net>
*/
#ifndef __UTIL_GEOM_SPHERE_HPP
@ -19,6 +19,8 @@
#include "../point.hpp"
#include "ray.hpp"
///////////////////////////////////////////////////////////////////////////////
namespace util::geom {
@ -30,6 +32,36 @@ namespace util::geom {
typedef sphere<2,float> sphere2f;
typedef sphere<3,float> sphere3f;
///////////////////////////////////////////////////////////////////////////
/// 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 INFINITY;
auto t_ = std::sqrt (D);
auto t0 = -b + t_;
auto t1 = -b - t_;
return t1 >= 0 ? t1 :
t0 >= 0 ? t0 :
INFINITY;
}
}
#endif

View File

@ -47,25 +47,6 @@ test_intersect_aabb (util::TAP::logger &tap)
}
//-----------------------------------------------------------------------------
void
test_intersect_sphere (util::TAP::logger &tap)
{
using util::geom::sphere3f;
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 (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 (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 (distance (r2, s), "ray-sphere no-intersect");
}
//-----------------------------------------------------------------------------
int
main (void)
@ -74,7 +55,6 @@ main (void)
test_intersect_plane (tap);
test_intersect_aabb (tap);
test_intersect_sphere (tap);
return tap.status ();
}

54
test/geom/sphere.cpp Normal file
View File

@ -0,0 +1,54 @@
#include "tap.hpp"
#include "geom/sphere.hpp"
using util::geom::ray2f;
using util::geom::ray3f;
///////////////////////////////////////////////////////////////////////////////
void
test_intersect (util::TAP::logger &tap)
{
using util::geom::sphere3f;
static const struct {
float d;
sphere3f s;
ray3f r;
const char *message;
} TESTS[] = {
{
1.f,
{ util::point3f {0.f}, 1.f },
{ util::point3f {0, 2, 0}, util::vector3f {0,-1,0} },
"straight towards unit-origin sphere"
},
{
0.f,
{ util::point3f {0}, 1.f },
{ util::point3f {0,1,0}, util::vector3f {0,1,0} },
"ray origin coincides with unit-origin sphere",
},
{
INFINITY,
{ util::point3f {0}, 1 },
{ util::point3f {0,2,0}, util::vector3f {0,1,0} },
"offset ray never intersects unit-origin sphere"
}
};
for (const auto &[d,s,r,msg]: TESTS) {
tap.expect_eq (d, distance (r, s), "%!", msg);
}
}
///////////////////////////////////////////////////////////////////////////////
int
main ()
{
util::TAP::logger tap;
test_intersect (tap);
return tap.status ();
}