improved tests

This commit is contained in:
2025-04-18 16:36:22 +03:00
parent f8202b116d
commit 9c934c5d9c
2 changed files with 94 additions and 73 deletions

View File

@@ -59,7 +59,7 @@ namespace omath::collision
if (tHit <= kEpsilon) if (tHit <= kEpsilon)
return ray.end; return ray.end;
} }
else if (tHit <= kEpsilon || tHit >= 1.0f - kEpsilon) else if (tHit <= kEpsilon || tHit > 1.0f - kEpsilon)
return ray.end; return ray.end;
return ray.start + rayDir * tHit; return ray.start + rayDir * tHit;

View File

@@ -13,88 +13,109 @@ using namespace omath::collision;
using Vec3 = Vector3<float>; using Vec3 = Vector3<float>;
namespace { namespace
// -----------------------------------------------------------------------------
// Constants & helpers
// -----------------------------------------------------------------------------
constexpr float kTol = 1e-5f;
bool VecEqual(const Vec3& a, const Vec3& b, float tol = kTol)
{ {
return std::fabs(a.x - b.x) < tol &&
std::fabs(a.y - b.y) < tol &&
std::fabs(a.z - b.z) < tol;
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Fixture with one canonical rightangled triangle in the XY plane. // Constants & helpers
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
class LineTracerFixture : public ::testing::Test constexpr float kTol = 1e-5f;
{
protected:
LineTracerFixture()
: triangle({0.f, 0.f, 0.f}, {1.f, 0.f, 0.f}, {0.f, 1.f, 0.f}) {}
Triangle<Vec3> triangle; bool VecEqual(const Vec3& a, const Vec3& b, float tol = kTol)
}; {
return std::fabs(a.x - b.x) < tol &&
std::fabs(a.y - b.y) < tol &&
std::fabs(a.z - b.z) < tol;
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Datadriven tests for CanTraceLine // Fixture with one canonical rightangled triangle in the XY plane.
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
struct TraceCase class LineTracerFixture : public ::testing::Test
{ {
Ray ray; protected:
bool expected_clear; // true => segment does NOT hit the triangle LineTracerFixture() :
}; triangle({0.f, 0.f, 0.f}, {1.f, 0.f, 0.f}, {0.f, 1.f, 0.f})
{
}
class CanTraceLineParam : public LineTracerFixture, Triangle<Vec3> triangle;
public ::testing::WithParamInterface<TraceCase> {}; };
TEST_P(CanTraceLineParam, VariousRays) // -----------------------------------------------------------------------------
{ // Datadriven tests for CanTraceLine
const auto& p = GetParam(); // -----------------------------------------------------------------------------
EXPECT_EQ(LineTracer::CanTraceLine(p.ray, triangle), p.expected_clear); struct TraceCase
} {
Ray ray;
bool expected_clear; // true => segment does NOT hit the triangle
};
INSTANTIATE_TEST_SUITE_P( class CanTraceLineParam : public LineTracerFixture,
BasicScenarios, public ::testing::WithParamInterface<TraceCase>
CanTraceLineParam, {
::testing::Values( };
TraceCase{Ray{{ 0.3f, 0.3f, -1.f},{ 0.3f, 0.3f, 1.f}}, false}, // hit through centre
TraceCase{Ray{{ 0.3f, 0.3f, 1.f},{ 0.3f, 0.3f, 2.f}}, true}, // parallel above
TraceCase{Ray{{ 0.3f, 0.3f, 0.f},{ 0.3f, 0.3f,-1.f}}, true}, // starts inside, goes away
TraceCase{Ray{{ 2.0f, 2.0f, -1.f},{ 2.0f, 2.0f, 1.f}}, true}, // misses entirely
TraceCase{Ray{{-1.0f,-1.0f, 0.f},{ 1.5f, 1.5f, 0.f}},true}, // lies in plane, outside tri
TraceCase{Ray{{-1.0f,-1.0f, -1.f},{ 0.0f, 0.0f, 0.f}}, true}, // endpoint on vertex
TraceCase{Ray{{-1.0f, 0.0f, -1.f},{ 0.5f, 0.0f, 0.f}}, true} // endpoint on edge
)
);
// ----------------------------------------------------------------------------- TEST_P(CanTraceLineParam, VariousRays)
// Validate that the reported hit point is correct for a genuine intersection. {
// ----------------------------------------------------------------------------- const auto& p = GetParam();
TEST_F(LineTracerFixture, HitPointCorrect) EXPECT_EQ(LineTracer::CanTraceLine(p.ray, triangle), p.expected_clear);
{ }
Ray ray{{0.3f, 0.3f, -1.f}, {0.3f, 0.3f, 1.f}};
Vec3 expected{0.3f, 0.3f, 0.f};
Vec3 hit = LineTracer::GetRayHitPoint(ray, triangle); INSTANTIATE_TEST_SUITE_P(
ASSERT_FALSE(VecEqual(hit, ray.end)); BasicScenarios,
EXPECT_TRUE(VecEqual(hit, expected)); CanTraceLineParam,
} ::testing::Values(
TraceCase{Ray{{ 0.3f, 0.3f, -1.f},{ 0.3f, 0.3f, 1.f}}, false}, // hit through centre
TraceCase{Ray{{ 0.3f, 0.3f, 1.f},{ 0.3f, 0.3f, 2.f}}, true}, // parallel above
TraceCase{Ray{{ 0.3f, 0.3f, 0.f},{ 0.3f, 0.3f,-1.f}}, true}, // starts inside, goes away
TraceCase{Ray{{ 2.0f, 2.0f, -1.f},{ 2.0f, 2.0f, 1.f}}, true}, // misses entirely
TraceCase{Ray{{-1.0f,-1.0f, 0.f},{ 1.5f, 1.5f, 0.f}},true}, // lies in plane, outside tri
TraceCase{Ray{{-1.0f,-1.0f, -1.f},{ 0.0f, 0.0f, 0.f}}, true}, // endpoint on vertex
TraceCase{Ray{{-1.0f, 0.0f, -1.f},{ 0.5f, 0.0f, 0.f}}, true} // endpoint on edge
)
);
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Triangle far beyond the ray should not block. // Validate that the reported hit point is correct for a genuine intersection.
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
TEST_F(LineTracerFixture, DistantTriangleClear) TEST_F(LineTracerFixture, HitPointCorrect)
{ {
Ray short_ray{{0.f, 0.f, 0.f}, {0.f, 0.f, 1.f}}; constexpr Ray ray{{0.3f, 0.3f, -1.f}, {0.3f, 0.3f, 1.f}};
Triangle<Vec3> distant{{1000.f,1000.f,1000.f}, constexpr Vec3 expected{0.3f, 0.3f, 0.f};
{1001.f,1000.f,1000.f},
{1000.f,1001.f,1000.f}};
EXPECT_TRUE(LineTracer::CanTraceLine(short_ray, distant)); const Vec3 hit = LineTracer::GetRayHitPoint(ray, triangle);
} ASSERT_FALSE(VecEqual(hit, ray.end));
EXPECT_TRUE(VecEqual(hit, expected));
}
// -----------------------------------------------------------------------------
// Triangle far beyond the ray should not block.
// -----------------------------------------------------------------------------
TEST_F(LineTracerFixture, DistantTriangleClear)
{
constexpr Ray short_ray{{0.f, 0.f, 0.f}, {0.f, 0.f, 1.f}};
constexpr Triangle<Vec3> distant{{1000.f, 1000.f, 1000.f},
{1001.f, 1000.f, 1000.f},
{1000.f, 1001.f, 1000.f}};
EXPECT_TRUE(LineTracer::CanTraceLine(short_ray, distant));
}
TEST(LineTracerTraceRayEdge, CantHit)
{
constexpr omath::Triangle<Vector3<float>> triangle{{2, 0, 0}, {2, 2, 0}, {2, 2, 2}};
constexpr Ray ray{{}, {1.0, 0, 0}, false};
EXPECT_TRUE(omath::collision::LineTracer::CanTraceLine(ray, triangle));
}
TEST(LineTracerTraceRayEdge, CanHit)
{
constexpr omath::Triangle<Vector3<float>> triangle{{2, 0, 0}, {2, 2, 0}, {2, 2, 2}};
constexpr Ray ray{{}, {2.1, 0, 0}, false};
auto endPoint = omath::collision::LineTracer::GetRayHitPoint(ray, triangle);
EXPECT_FALSE(omath::collision::LineTracer::CanTraceLine(ray, triangle));
}
} // namespace } // namespace