diff --git a/source/collision/line_tracer.cpp b/source/collision/line_tracer.cpp index 74aa308..5bf7837 100644 --- a/source/collision/line_tracer.cpp +++ b/source/collision/line_tracer.cpp @@ -59,7 +59,7 @@ namespace omath::collision if (tHit <= kEpsilon) return ray.end; } - else if (tHit <= kEpsilon || tHit >= 1.0f - kEpsilon) + else if (tHit <= kEpsilon || tHit > 1.0f - kEpsilon) return ray.end; return ray.start + rayDir * tHit; diff --git a/tests/general/unit_test_line_trace.cpp b/tests/general/unit_test_line_trace.cpp index 600a18b..9472494 100644 --- a/tests/general/unit_test_line_trace.cpp +++ b/tests/general/unit_test_line_trace.cpp @@ -13,88 +13,109 @@ using namespace omath::collision; using Vec3 = Vector3; -namespace { - -// ----------------------------------------------------------------------------- -// Constants & helpers -// ----------------------------------------------------------------------------- -constexpr float kTol = 1e-5f; - -bool VecEqual(const Vec3& a, const Vec3& b, float tol = kTol) +namespace { - 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 right‑angled triangle in the XY plane. -// ----------------------------------------------------------------------------- -class LineTracerFixture : public ::testing::Test -{ -protected: - LineTracerFixture() - : triangle({0.f, 0.f, 0.f}, {1.f, 0.f, 0.f}, {0.f, 1.f, 0.f}) {} + // ----------------------------------------------------------------------------- + // Constants & helpers + // ----------------------------------------------------------------------------- + constexpr float kTol = 1e-5f; - Triangle 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; + } -// ----------------------------------------------------------------------------- -// Data‑driven tests for CanTraceLine -// ----------------------------------------------------------------------------- -struct TraceCase -{ - Ray ray; - bool expected_clear; // true => segment does NOT hit the triangle -}; + // ----------------------------------------------------------------------------- + // Fixture with one canonical right‑angled triangle in the XY plane. + // ----------------------------------------------------------------------------- + class LineTracerFixture : public ::testing::Test + { + protected: + LineTracerFixture() : + triangle({0.f, 0.f, 0.f}, {1.f, 0.f, 0.f}, {0.f, 1.f, 0.f}) + { + } -class CanTraceLineParam : public LineTracerFixture, - public ::testing::WithParamInterface {}; + Triangle triangle; + }; -TEST_P(CanTraceLineParam, VariousRays) -{ - const auto& p = GetParam(); - EXPECT_EQ(LineTracer::CanTraceLine(p.ray, triangle), p.expected_clear); -} + // ----------------------------------------------------------------------------- + // Data‑driven tests for CanTraceLine + // ----------------------------------------------------------------------------- + struct TraceCase + { + Ray ray; + bool expected_clear; // true => segment does NOT hit the triangle + }; -INSTANTIATE_TEST_SUITE_P( - BasicScenarios, - 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 - ) -); + class CanTraceLineParam : public LineTracerFixture, + public ::testing::WithParamInterface + { + }; -// ----------------------------------------------------------------------------- -// Validate that the reported hit point is correct for a genuine intersection. -// ----------------------------------------------------------------------------- -TEST_F(LineTracerFixture, HitPointCorrect) -{ - Ray ray{{0.3f, 0.3f, -1.f}, {0.3f, 0.3f, 1.f}}; - Vec3 expected{0.3f, 0.3f, 0.f}; + TEST_P(CanTraceLineParam, VariousRays) + { + const auto& p = GetParam(); + EXPECT_EQ(LineTracer::CanTraceLine(p.ray, triangle), p.expected_clear); + } - Vec3 hit = LineTracer::GetRayHitPoint(ray, triangle); - ASSERT_FALSE(VecEqual(hit, ray.end)); - EXPECT_TRUE(VecEqual(hit, expected)); -} + INSTANTIATE_TEST_SUITE_P( + BasicScenarios, + 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. -// ----------------------------------------------------------------------------- -TEST_F(LineTracerFixture, DistantTriangleClear) -{ - Ray short_ray{{0.f, 0.f, 0.f}, {0.f, 0.f, 1.f}}; - Triangle distant{{1000.f,1000.f,1000.f}, - {1001.f,1000.f,1000.f}, - {1000.f,1001.f,1000.f}}; + // ----------------------------------------------------------------------------- + // Validate that the reported hit point is correct for a genuine intersection. + // ----------------------------------------------------------------------------- + TEST_F(LineTracerFixture, HitPointCorrect) + { + constexpr Ray ray{{0.3f, 0.3f, -1.f}, {0.3f, 0.3f, 1.f}}; + constexpr Vec3 expected{0.3f, 0.3f, 0.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 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> 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> 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