Merge pull request #146 from orange-cpp/feature/line_tracer_template

improvement
This commit is contained in:
2026-02-06 00:14:15 +03:00
committed by GitHub
10 changed files with 108 additions and 125 deletions

View File

@@ -8,43 +8,96 @@
namespace omath::collision namespace omath::collision
{ {
class Ray template<class T = Vector3<float>>
class Ray final
{ {
public: public:
Vector3<float> start; using VectorType = T;
Vector3<float> end; VectorType start;
VectorType end;
bool infinite_length = false; bool infinite_length = false;
[[nodiscard]] [[nodiscard]]
Vector3<float> direction_vector() const noexcept; constexpr VectorType direction_vector() const noexcept
{
return end - start;
}
[[nodiscard]] [[nodiscard]]
Vector3<float> direction_vector_normalized() const noexcept; constexpr VectorType direction_vector_normalized() const noexcept
{
return direction_vector().normalized();
}
}; };
class LineTracer
template<class RayType = Ray<>>
class LineTracer final
{ {
using TriangleType = Triangle<typename RayType::VectorType>;
public: public:
LineTracer() = delete; LineTracer() = delete;
[[nodiscard]] [[nodiscard]]
static bool can_trace_line(const Ray& ray, const Triangle<Vector3<float>>& triangle) noexcept; constexpr static bool can_trace_line(const RayType& ray, const TriangleType& triangle) noexcept
{
return get_ray_hit_point(ray, triangle) == ray.end;
}
// Realization of MöllerTrumbore intersection algorithm // Realization of MöllerTrumbore intersection algorithm
// https://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm // https://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm
[[nodiscard]] [[nodiscard]]
static Vector3<float> get_ray_hit_point(const Ray& ray, const Triangle<Vector3<float>>& triangle) noexcept; constexpr static auto get_ray_hit_point(const RayType& ray, const TriangleType& triangle) noexcept
{
constexpr float k_epsilon = std::numeric_limits<float>::epsilon();
const auto side_a = triangle.side_a_vector();
const auto side_b = triangle.side_b_vector();
const auto ray_dir = ray.direction_vector();
const auto p = ray_dir.cross(side_b);
const auto det = side_a.dot(p);
if (std::abs(det) < k_epsilon)
return ray.end;
const auto inv_det = 1 / det;
const auto t = ray.start - triangle.m_vertex2;
const auto u = t.dot(p) * inv_det;
if ((u < 0 && std::abs(u) > k_epsilon) || (u > 1 && std::abs(u - 1) > k_epsilon))
return ray.end;
const auto q = t.cross(side_a);
// ReSharper disable once CppTooWideScopeInitStatement
const auto v = ray_dir.dot(q) * inv_det;
if ((v < 0 && std::abs(v) > k_epsilon) || (u + v > 1 && std::abs(u + v - 1) > k_epsilon))
return ray.end;
const auto t_hit = side_b.dot(q) * inv_det;
if (ray.infinite_length && t_hit <= k_epsilon)
return ray.end;
if (t_hit <= k_epsilon || t_hit > 1 - k_epsilon)
return ray.end;
return ray.start + ray_dir * t_hit;
}
template<class MeshType> template<class MeshType>
[[nodiscard]] [[nodiscard]]
static Vector3<float> get_ray_hit_point(const Ray& ray, const MeshType& mesh) noexcept constexpr static auto get_ray_hit_point(const RayType& ray, const MeshType& mesh) noexcept
{ {
Vector3<float> mesh_hit = ray.end; auto mesh_hit = ray.end;
auto begin = mesh.m_element_buffer_object.cbegin(); const auto begin = mesh.m_element_buffer_object.cbegin();
auto end = mesh.m_element_buffer_object.cend(); const auto end = mesh.m_element_buffer_object.cend();
for (auto current = begin; current < end; current = std::next(current)) for (auto current = begin; current < end; current = std::next(current))
{ {
auto face = mesh.make_face_in_world_space(current); const auto face = mesh.make_face_in_world_space(current);
auto ray_stop_point = get_ray_hit_point(ray, face); auto ray_stop_point = get_ray_hit_point(ray, face);
if (ray_stop_point.distance_to(ray.start) < mesh_hit.distance_to(ray.start)) if (ray_stop_point.distance_to(ray.start) < mesh_hit.distance_to(ray.start))

View File

@@ -130,7 +130,7 @@ namespace omath::collision
template<class V> template<class V>
[[nodiscard]] [[nodiscard]]
static constexpr bool near_zero(const V& v, const float eps = 1e-7f) static constexpr bool near_zero(const V& v, const float eps = 1e-7f) noexcept
{ {
return v.dot(v) <= eps * eps; return v.dot(v) <= eps * eps;
} }
@@ -146,7 +146,7 @@ namespace omath::collision
} }
[[nodiscard]] [[nodiscard]]
constexpr bool handle_line(VectorType& direction) constexpr bool handle_line(VectorType& direction) noexcept
{ {
const auto& a = m_points[0]; const auto& a = m_points[0];
const auto& b = m_points[1]; const auto& b = m_points[1];
@@ -158,21 +158,11 @@ namespace omath::collision
{ {
// ReSharper disable once CppTooWideScopeInitStatement // ReSharper disable once CppTooWideScopeInitStatement
auto n = ab.cross(ao); // Needed to valid handle collision if colliders placed at same origin pos auto n = ab.cross(ao); // Needed to valid handle collision if colliders placed at same origin pos
if (near_zero(n)) direction = near_zero(n) ? any_perp(ab) : n.cross(ab);
{ return false;
// collinear: origin lies on ray AB (often on segment), pick any perp to escape
direction = any_perp(ab);
}
else
{
direction = n.cross(ab);
}
}
else
{
*this = {a};
direction = ao;
} }
*this = {a};
direction = ao;
return false; return false;
} }

View File

@@ -1,61 +0,0 @@
//
// Created by Orange on 11/13/2024.
//
#include "omath/collision/line_tracer.hpp"
namespace omath::collision
{
bool LineTracer::can_trace_line(const Ray& ray, const Triangle<Vector3<float>>& triangle) noexcept
{
return get_ray_hit_point(ray, triangle) == ray.end;
}
Vector3<float> Ray::direction_vector() const noexcept
{
return end - start;
}
Vector3<float> Ray::direction_vector_normalized() const noexcept
{
return direction_vector().normalized();
}
Vector3<float> LineTracer::get_ray_hit_point(const Ray& ray, const Triangle<Vector3<float>>& triangle) noexcept
{
constexpr float k_epsilon = std::numeric_limits<float>::epsilon();
const auto side_a = triangle.side_a_vector();
const auto side_b = triangle.side_b_vector();
const auto ray_dir = ray.direction_vector();
const auto p = ray_dir.cross(side_b);
const auto det = side_a.dot(p);
if (std::abs(det) < k_epsilon)
return ray.end;
const auto inv_det = 1.0f / det;
const auto t = ray.start - triangle.m_vertex2;
const auto u = t.dot(p) * inv_det;
if ((u < 0 && std::abs(u) > k_epsilon) || (u > 1 && std::abs(u - 1) > k_epsilon))
return ray.end;
const auto q = t.cross(side_a);
// ReSharper disable once CppTooWideScopeInitStatement
const auto v = ray_dir.dot(q) * inv_det;
if ((v < 0 && std::abs(v) > k_epsilon) || (u + v > 1 && std::abs(u + v - 1) > k_epsilon))
return ray.end;
const auto t_hit = side_b.dot(q) * inv_det;
if (ray.infinite_length && t_hit <= k_epsilon)
return ray.end;
if (t_hit <= k_epsilon || t_hit > 1.0f - k_epsilon)
return ray.end;
return ray.start + ray_dir * t_hit;
}
} // namespace omath::collision

View File

@@ -47,7 +47,7 @@ namespace
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
struct TraceCase struct TraceCase
{ {
Ray ray; Ray<> ray;
bool expected_clear; // true => segment does NOT hit the triangle bool expected_clear; // true => segment does NOT hit the triangle
friend std::ostream& operator<<(std::ostream& os, const TraceCase& tc) friend std::ostream& operator<<(std::ostream& os, const TraceCase& tc)
{ {
@@ -66,7 +66,7 @@ namespace
TEST_P(CanTraceLineParam, VariousRays) TEST_P(CanTraceLineParam, VariousRays)
{ {
const auto& [ray, expected_clear] = GetParam(); const auto& [ray, expected_clear] = GetParam();
EXPECT_EQ(LineTracer::can_trace_line(ray, triangle), expected_clear); EXPECT_EQ(LineTracer<>::can_trace_line(ray, triangle), expected_clear);
} }
INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P(
@@ -91,7 +91,7 @@ namespace
constexpr Ray ray{{0.3f, 0.3f, -1.f}, {0.3f, 0.3f, 1.f}}; constexpr Ray ray{{0.3f, 0.3f, -1.f}, {0.3f, 0.3f, 1.f}};
constexpr Vec3 expected{0.3f, 0.3f, 0.f}; constexpr Vec3 expected{0.3f, 0.3f, 0.f};
const Vec3 hit = LineTracer::get_ray_hit_point(ray, triangle); const Vec3 hit = LineTracer<>::get_ray_hit_point(ray, triangle);
ASSERT_FALSE(vec_equal(hit, ray.end)); ASSERT_FALSE(vec_equal(hit, ray.end));
EXPECT_TRUE(vec_equal(hit, expected)); EXPECT_TRUE(vec_equal(hit, expected));
} }
@@ -106,7 +106,7 @@ namespace
{1001.f, 1000.f, 1000.f}, {1001.f, 1000.f, 1000.f},
{1000.f, 1001.f, 1000.f}}; {1000.f, 1001.f, 1000.f}};
EXPECT_TRUE(LineTracer::can_trace_line(short_ray, distant)); EXPECT_TRUE(LineTracer<>::can_trace_line(short_ray, distant));
} }
TEST(unit_test_unity_engine, CantHit) TEST(unit_test_unity_engine, CantHit)
@@ -115,13 +115,13 @@ namespace
constexpr Ray ray{{}, {1.0, 0, 0}, false}; constexpr Ray ray{{}, {1.0, 0, 0}, false};
EXPECT_TRUE(omath::collision::LineTracer::can_trace_line(ray, triangle)); EXPECT_TRUE(omath::collision::LineTracer<>::can_trace_line(ray, triangle));
} }
TEST(unit_test_unity_engine, CanHit) TEST(unit_test_unity_engine, CanHit)
{ {
constexpr omath::Triangle<Vector3<float>> triangle{{2, 0, 0}, {2, 2, 0}, {2, 2, 2}}; constexpr omath::Triangle<Vector3<float>> triangle{{2, 0, 0}, {2, 2, 0}, {2, 2, 2}};
constexpr Ray ray{{}, {2.1, 0, 0}, false}; constexpr Ray ray{{}, {2.1, 0, 0}, false};
EXPECT_FALSE(omath::collision::LineTracer::can_trace_line(ray, triangle)); EXPECT_FALSE(omath::collision::LineTracer<>::can_trace_line(ray, triangle));
} }
} // namespace } // namespace

View File

@@ -15,9 +15,9 @@ TEST(LineTracerTests, ParallelRayReturnsEnd)
ray.end = Vector3<float>{1.f,1.f,1.f}; ray.end = Vector3<float>{1.f,1.f,1.f};
// For a ray parallel to the triangle plane the algorithm should return ray.end // For a ray parallel to the triangle plane the algorithm should return ray.end
const auto hit = omath::collision::LineTracer::get_ray_hit_point(ray, tri); const auto hit = omath::collision::LineTracer<>::get_ray_hit_point(ray, tri);
EXPECT_TRUE(hit == ray.end); EXPECT_TRUE(hit == ray.end);
EXPECT_TRUE(omath::collision::LineTracer::can_trace_line(ray, tri)); EXPECT_TRUE(omath::collision::LineTracer<>::can_trace_line(ray, tri));
} }
TEST(LineTracerTests, MissesTriangleReturnsEnd) TEST(LineTracerTests, MissesTriangleReturnsEnd)
@@ -27,7 +27,7 @@ TEST(LineTracerTests, MissesTriangleReturnsEnd)
ray.start = Vector3<float>{2.f,2.f,-1.f}; ray.start = Vector3<float>{2.f,2.f,-1.f};
ray.end = Vector3<float>{2.f,2.f,1.f}; // passes above the triangle area ray.end = Vector3<float>{2.f,2.f,1.f}; // passes above the triangle area
const auto hit = omath::collision::LineTracer::get_ray_hit_point(ray, tri); const auto hit = omath::collision::LineTracer<>::get_ray_hit_point(ray, tri);
EXPECT_TRUE(hit == ray.end); EXPECT_TRUE(hit == ray.end);
} }
@@ -38,7 +38,7 @@ TEST(LineTracerTests, HitTriangleReturnsPointInsideSegment)
ray.start = Vector3<float>{0.25f,0.25f,-1.f}; ray.start = Vector3<float>{0.25f,0.25f,-1.f};
ray.end = Vector3<float>{0.25f,0.25f,1.f}; ray.end = Vector3<float>{0.25f,0.25f,1.f};
const auto hit = omath::collision::LineTracer::get_ray_hit_point(ray, tri); const auto hit = omath::collision::LineTracer<>::get_ray_hit_point(ray, tri);
// Should return a point between start and end (z approximately 0) // Should return a point between start and end (z approximately 0)
EXPECT_NE(hit, ray.end); EXPECT_NE(hit, ray.end);
EXPECT_NEAR(hit.z, 0.f, 1e-4f); EXPECT_NEAR(hit.z, 0.f, 1e-4f);
@@ -60,6 +60,6 @@ TEST(LineTracerTests, InfiniteLengthEarlyOut)
// If t_hit <= epsilon the algorithm should return ray.end when infinite_length is true. // If t_hit <= epsilon the algorithm should return ray.end when infinite_length is true.
// Using start on the triangle plane should produce t_hit <= epsilon. // Using start on the triangle plane should produce t_hit <= epsilon.
const auto hit = omath::collision::LineTracer::get_ray_hit_point(ray, tri); const auto hit = omath::collision::LineTracer<>::get_ray_hit_point(ray, tri);
EXPECT_TRUE(hit == ray.end); EXPECT_TRUE(hit == ray.end);
} }

View File

@@ -10,7 +10,7 @@ TEST(LineTracerExtra, MissParallel)
{ {
constexpr Triangle<Vector3<float>> tri({0,0,0},{1,0,0},{0,1,0}); constexpr Triangle<Vector3<float>> tri({0,0,0},{1,0,0},{0,1,0});
constexpr Ray ray{ {0.3f,0.3f,1.f}, {0.3f,0.3f,2.f}, false }; // parallel above triangle constexpr Ray ray{ {0.3f,0.3f,1.f}, {0.3f,0.3f,2.f}, false }; // parallel above triangle
const auto hit = LineTracer::get_ray_hit_point(ray, tri); const auto hit = LineTracer<>::get_ray_hit_point(ray, tri);
EXPECT_EQ(hit, ray.end); EXPECT_EQ(hit, ray.end);
} }
@@ -18,7 +18,7 @@ TEST(LineTracerExtra, HitCenter)
{ {
constexpr Triangle<Vector3<float>> tri({0,0,0},{1,0,0},{0,1,0}); constexpr Triangle<Vector3<float>> tri({0,0,0},{1,0,0},{0,1,0});
constexpr Ray ray{ {0.3f,0.3f,-1.f}, {0.3f,0.3f,1.f}, false }; constexpr Ray ray{ {0.3f,0.3f,-1.f}, {0.3f,0.3f,1.f}, false };
const auto hit = LineTracer::get_ray_hit_point(ray, tri); const auto hit = LineTracer<>::get_ray_hit_point(ray, tri);
ASSERT_FALSE(hit == ray.end); ASSERT_FALSE(hit == ray.end);
EXPECT_NEAR(hit.x, 0.3f, 1e-6f); EXPECT_NEAR(hit.x, 0.3f, 1e-6f);
EXPECT_NEAR(hit.y, 0.3f, 1e-6f); EXPECT_NEAR(hit.y, 0.3f, 1e-6f);
@@ -30,7 +30,7 @@ TEST(LineTracerExtra, HitOnEdge)
constexpr Triangle<Vector3<float>> tri({0,0,0},{1,0,0},{0,1,0}); constexpr Triangle<Vector3<float>> tri({0,0,0},{1,0,0},{0,1,0});
constexpr Ray ray{ {0.0f,0.0f,1.f}, {0.0f,0.0f,0.f}, false }; constexpr Ray ray{ {0.0f,0.0f,1.f}, {0.0f,0.0f,0.f}, false };
// hitting exact vertex/edge may be considered miss; ensure function handles without crash // hitting exact vertex/edge may be considered miss; ensure function handles without crash
if (const auto hit = LineTracer::get_ray_hit_point(ray, tri); hit != ray.end) if (const auto hit = LineTracer<>::get_ray_hit_point(ray, tri); hit != ray.end)
{ {
EXPECT_NEAR(hit.x, 0.0f, 1e-6f); EXPECT_NEAR(hit.x, 0.0f, 1e-6f);
EXPECT_NEAR(hit.y, 0.0f, 1e-6f); EXPECT_NEAR(hit.y, 0.0f, 1e-6f);
@@ -42,6 +42,6 @@ TEST(LineTracerExtra, InfiniteRayIgnoredIfBehind)
constexpr Triangle<Vector3<float>> tri({0,0,0},{1,0,0},{0,1,0}); constexpr Triangle<Vector3<float>> tri({0,0,0},{1,0,0},{0,1,0});
// Ray pointing away but infinite_length true should be ignored // Ray pointing away but infinite_length true should be ignored
constexpr Ray ray{ {0.5f,0.5f,-1.f}, {0.5f,0.5f,-2.f}, true }; constexpr Ray ray{ {0.5f,0.5f,-1.f}, {0.5f,0.5f,-2.f}, true };
const auto hit = LineTracer::get_ray_hit_point(ray, tri); const auto hit = LineTracer<>::get_ray_hit_point(ray, tri);
EXPECT_EQ(hit, ray.end); EXPECT_EQ(hit, ray.end);
} }

View File

@@ -14,7 +14,7 @@ TEST(LineTracerMore, ParallelRayReturnsEnd)
constexpr Triangle3 tri(Vector3<float>{0.f,0.f,0.f}, Vector3<float>{1.f,0.f,0.f}, Vector3<float>{0.f,1.f,0.f}); constexpr Triangle3 tri(Vector3<float>{0.f,0.f,0.f}, Vector3<float>{1.f,0.f,0.f}, Vector3<float>{0.f,1.f,0.f});
Ray ray; ray.start = {0.f,0.f,1.f}; ray.end = {1.f,0.f,1.f}; Ray ray; ray.start = {0.f,0.f,1.f}; ray.end = {1.f,0.f,1.f};
const auto hit = LineTracer::get_ray_hit_point(ray, tri); const auto hit = LineTracer<>::get_ray_hit_point(ray, tri);
EXPECT_EQ(hit, ray.end); EXPECT_EQ(hit, ray.end);
} }
@@ -24,7 +24,7 @@ TEST(LineTracerMore, UOutOfRangeReturnsEnd)
constexpr Triangle3 tri(Vector3<float>{0.f,0.f,0.f}, Vector3<float>{1.f,0.f,0.f}, Vector3<float>{0.f,1.f,0.f}); constexpr Triangle3 tri(Vector3<float>{0.f,0.f,0.f}, Vector3<float>{1.f,0.f,0.f}, Vector3<float>{0.f,1.f,0.f});
Ray ray; ray.start = {-1.f,-1.f,-1.f}; ray.end = {-0.5f,-1.f,1.f}; Ray ray; ray.start = {-1.f,-1.f,-1.f}; ray.end = {-0.5f,-1.f,1.f};
const auto hit = LineTracer::get_ray_hit_point(ray, tri); const auto hit = LineTracer<>::get_ray_hit_point(ray, tri);
EXPECT_EQ(hit, ray.end); EXPECT_EQ(hit, ray.end);
} }
@@ -34,7 +34,7 @@ TEST(LineTracerMore, VOutOfRangeReturnsEnd)
constexpr Triangle3 tri(Vector3<float>{0.f,0.f,0.f}, Vector3<float>{1.f,0.f,0.f}, Vector3<float>{0.f,1.f,0.f}); constexpr Triangle3 tri(Vector3<float>{0.f,0.f,0.f}, Vector3<float>{1.f,0.f,0.f}, Vector3<float>{0.f,1.f,0.f});
Ray ray; ray.start = {2.f,2.f,-1.f}; ray.end = {2.f,2.f,1.f}; Ray ray; ray.start = {2.f,2.f,-1.f}; ray.end = {2.f,2.f,1.f};
const auto hit = LineTracer::get_ray_hit_point(ray, tri); const auto hit = LineTracer<>::get_ray_hit_point(ray, tri);
EXPECT_EQ(hit, ray.end); EXPECT_EQ(hit, ray.end);
} }
@@ -43,7 +43,7 @@ TEST(LineTracerMore, THitTooSmallReturnsEnd)
constexpr Triangle3 tri(Vector3<float>{0.f,0.f,0.f}, Vector3<float>{1.f,0.f,0.f}, Vector3<float>{0.f,1.f,0.f}); constexpr Triangle3 tri(Vector3<float>{0.f,0.f,0.f}, Vector3<float>{1.f,0.f,0.f}, Vector3<float>{0.f,1.f,0.f});
Ray ray; ray.start = {0.f,0.f,0.0000000001f}; ray.end = {0.f,0.f,1.f}; Ray ray; ray.start = {0.f,0.f,0.0000000001f}; ray.end = {0.f,0.f,1.f};
const auto hit = LineTracer::get_ray_hit_point(ray, tri); const auto hit = LineTracer<>::get_ray_hit_point(ray, tri);
EXPECT_EQ(hit, ray.end); EXPECT_EQ(hit, ray.end);
} }
@@ -53,7 +53,7 @@ TEST(LineTracerMore, THitGreaterThanOneReturnsEnd)
// Choose a ray and compute t_hit locally to assert consistency // Choose a ray and compute t_hit locally to assert consistency
Ray ray; ray.start = {0.f,0.f,-1.f}; ray.end = {0.f,0.f,-0.5f}; Ray ray; ray.start = {0.f,0.f,-1.f}; ray.end = {0.f,0.f,-0.5f};
const auto hit = LineTracer::get_ray_hit_point(ray, tri); const auto hit = LineTracer<>::get_ray_hit_point(ray, tri);
constexpr float k_epsilon = std::numeric_limits<float>::epsilon(); constexpr float k_epsilon = std::numeric_limits<float>::epsilon();
constexpr auto side_a = tri.side_a_vector(); constexpr auto side_a = tri.side_a_vector();
@@ -87,7 +87,7 @@ TEST(LineTracerMore, InfiniteLengthWithSmallTHitReturnsEnd)
// Create triangle slightly behind so t_hit <= eps // Create triangle slightly behind so t_hit <= eps
tri = tri2; tri = tri2;
const auto hit = LineTracer::get_ray_hit_point(ray, tri); const auto hit = LineTracer<>::get_ray_hit_point(ray, tri);
EXPECT_EQ(hit, ray.end); EXPECT_EQ(hit, ray.end);
} }
@@ -96,7 +96,7 @@ TEST(LineTracerMore, SuccessfulHitReturnsPoint)
constexpr Triangle3 tri(Vector3<float>{0.f,0.f,0.f}, Vector3<float>{1.f,0.f,0.f}, Vector3<float>{0.f,1.f,0.f}); constexpr Triangle3 tri(Vector3<float>{0.f,0.f,0.f}, Vector3<float>{1.f,0.f,0.f}, Vector3<float>{0.f,1.f,0.f});
Ray ray; ray.start = {0.1f,0.1f,-1.f}; ray.end = {0.1f,0.1f,1.f}; Ray ray; ray.start = {0.1f,0.1f,-1.f}; ray.end = {0.1f,0.1f,1.f};
const auto hit = LineTracer::get_ray_hit_point(ray, tri); const auto hit = LineTracer<>::get_ray_hit_point(ray, tri);
EXPECT_NE(hit, ray.end); EXPECT_NE(hit, ray.end);
// Hit should be on plane z=0 and near x=0.1,y=0.1 // Hit should be on plane z=0 and near x=0.1,y=0.1
EXPECT_NEAR(hit.z, 0.f, 1e-6f); EXPECT_NEAR(hit.z, 0.f, 1e-6f);

View File

@@ -14,7 +14,7 @@ TEST(LineTracerMore2, UGreaterThanOneReturnsEnd)
// choose ray so barycentric u > 1 // choose ray so barycentric u > 1
Ray ray; ray.start = {2.f, -1.f, -1.f}; ray.end = {2.f, -1.f, 1.f}; Ray ray; ray.start = {2.f, -1.f, -1.f}; ray.end = {2.f, -1.f, 1.f};
const auto hit = LineTracer::get_ray_hit_point(ray, tri); const auto hit = LineTracer<>::get_ray_hit_point(ray, tri);
EXPECT_EQ(hit, ray.end); EXPECT_EQ(hit, ray.end);
} }
@@ -24,7 +24,7 @@ TEST(LineTracerMore2, VGreaterThanOneReturnsEnd)
// choose ray so barycentric v > 1 // choose ray so barycentric v > 1
Ray ray; ray.start = {-1.f, 2.f, -1.f}; ray.end = {-1.f, 2.f, 1.f}; Ray ray; ray.start = {-1.f, 2.f, -1.f}; ray.end = {-1.f, 2.f, 1.f};
const auto hit = LineTracer::get_ray_hit_point(ray, tri); const auto hit = LineTracer<>::get_ray_hit_point(ray, tri);
EXPECT_EQ(hit, ray.end); EXPECT_EQ(hit, ray.end);
} }
@@ -34,7 +34,7 @@ TEST(LineTracerMore2, UPlusVGreaterThanOneReturnsEnd)
// Ray aimed so u+v > 1 (outside triangle region) // Ray aimed so u+v > 1 (outside triangle region)
Ray ray; ray.start = {1.f, 1.f, -1.f}; ray.end = {1.f, 1.f, 1.f}; Ray ray; ray.start = {1.f, 1.f, -1.f}; ray.end = {1.f, 1.f, 1.f};
const auto hit = LineTracer::get_ray_hit_point(ray, tri); const auto hit = LineTracer<>::get_ray_hit_point(ray, tri);
EXPECT_EQ(hit, ray.end); EXPECT_EQ(hit, ray.end);
} }
@@ -52,6 +52,6 @@ TEST(LineTracerMore2, ZeroLengthRayHandled)
Ray ray; ray.start = {0.f,0.f,0.f}; ray.end = {0.f,0.f,0.f}; Ray ray; ray.start = {0.f,0.f,0.f}; ray.end = {0.f,0.f,0.f};
// Zero-length ray: direction length == 0; algorithm should handle without crash // Zero-length ray: direction length == 0; algorithm should handle without crash
const auto hit = LineTracer::get_ray_hit_point(ray, tri); const auto hit = LineTracer<>::get_ray_hit_point(ray, tri);
EXPECT_EQ(hit, ray.end); EXPECT_EQ(hit, ray.end);
} }

View File

@@ -19,6 +19,8 @@ namespace
constexpr std::uint32_t lc_segment = 0x1; constexpr std::uint32_t lc_segment = 0x1;
constexpr std::uint32_t lc_segment_64 = 0x19; constexpr std::uint32_t lc_segment_64 = 0x19;
constexpr std::string_view segment_name = "__TEXT";
constexpr std::string_view section_name = "__text";
#pragma pack(push, 1) #pragma pack(push, 1)
struct MachHeader64 struct MachHeader64
{ {
@@ -117,7 +119,6 @@ namespace
constexpr std::size_t segment_size = sizeof(SegmentCommand64); constexpr std::size_t segment_size = sizeof(SegmentCommand64);
constexpr std::size_t section_size = sizeof(Section64); constexpr std::size_t section_size = sizeof(Section64);
constexpr std::size_t load_cmd_size = segment_size + section_size; constexpr std::size_t load_cmd_size = segment_size + section_size;
// Section data will start after headers // Section data will start after headers
const std::size_t section_offset = header_size + load_cmd_size; const std::size_t section_offset = header_size + load_cmd_size;
@@ -138,7 +139,7 @@ namespace
SegmentCommand64 segment{}; SegmentCommand64 segment{};
segment.cmd = lc_segment_64; segment.cmd = lc_segment_64;
segment.cmdsize = static_cast<std::uint32_t>(load_cmd_size); segment.cmdsize = static_cast<std::uint32_t>(load_cmd_size);
std::strncpy(segment.segname, "__TEXT", 16); std::ranges::copy(segment_name, segment.segname);
segment.vmaddr = 0x100000000; segment.vmaddr = 0x100000000;
segment.vmsize = section_bytes.size(); segment.vmsize = section_bytes.size();
segment.fileoff = section_offset; segment.fileoff = section_offset;
@@ -152,8 +153,8 @@ namespace
// Create section // Create section
Section64 section{}; Section64 section{};
std::strncpy(section.sectname, "__text", 16); std::ranges::copy(section_name, section.sectname);
std::strncpy(section.segname, "__TEXT", 16); std::ranges::copy(segment_name, segment.segname);
section.addr = 0x100000000; section.addr = 0x100000000;
section.size = section_bytes.size(); section.size = section_bytes.size();
section.offset = static_cast<std::uint32_t>(section_offset); section.offset = static_cast<std::uint32_t>(section_offset);
@@ -188,7 +189,7 @@ namespace
constexpr std::size_t load_cmd_size = segment_size + section_size; constexpr std::size_t load_cmd_size = segment_size + section_size;
// Section data will start after headers // Section data will start after headers
const std::size_t section_offset = header_size + load_cmd_size; constexpr std::size_t section_offset = header_size + load_cmd_size;
// Create Mach-O header // Create Mach-O header
MachHeader32 header{}; MachHeader32 header{};
@@ -206,7 +207,7 @@ namespace
SegmentCommand32 segment{}; SegmentCommand32 segment{};
segment.cmd = lc_segment; segment.cmd = lc_segment;
segment.cmdsize = static_cast<std::uint32_t>(load_cmd_size); segment.cmdsize = static_cast<std::uint32_t>(load_cmd_size);
std::strncpy(segment.segname, "__TEXT", 16); std::ranges::copy(segment_name, segment.segname);
segment.vmaddr = 0x1000; segment.vmaddr = 0x1000;
segment.vmsize = static_cast<std::uint32_t>(section_bytes.size()); segment.vmsize = static_cast<std::uint32_t>(section_bytes.size());
segment.fileoff = static_cast<std::uint32_t>(section_offset); segment.fileoff = static_cast<std::uint32_t>(section_offset);
@@ -220,8 +221,8 @@ namespace
// Create section // Create section
Section32 section{}; Section32 section{};
std::strncpy(section.sectname, "__text", 16); std::ranges::copy(section_name, section.sectname);
std::strncpy(section.segname, "__TEXT", 16); std::ranges::copy(segment_name, segment.segname);
section.addr = 0x1000; section.addr = 0x1000;
section.size = static_cast<std::uint32_t>(section_bytes.size()); section.size = static_cast<std::uint32_t>(section_bytes.size());
section.offset = static_cast<std::uint32_t>(section_offset); section.offset = static_cast<std::uint32_t>(section_offset);

View File

@@ -12,5 +12,5 @@ TEST(test, test)
{0.f, 30.f, 0.f}, {}, omath::opengl_engine::k_abs_forward, omath::opengl_engine::k_abs_right); {0.f, 30.f, 0.f}, {}, omath::opengl_engine::k_abs_forward, omath::opengl_engine::k_abs_right);
omath::collision::Ray ray{.start = {0, 0, 0}, .end = {-100, 0, 0}}; omath::collision::Ray ray{.start = {0, 0, 0}, .end = {-100, 0, 0}};
std::ignore = omath::collision::LineTracer::get_ray_hit_point(ray, result); std::ignore = omath::collision::LineTracer<>::get_ray_hit_point(ray, result);
} }