From 6a324e8c0e27ffcb445f75947ed46ebfe1a53c56 Mon Sep 17 00:00:00 2001 From: Orange Date: Mon, 6 Jan 2025 04:42:43 +0300 Subject: [PATCH 1/4] improvement --- include/omath/Triangle.hpp | 59 ++++++++++++++++++++++++++ include/omath/Triangle3d.hpp | 36 ---------------- include/omath/collision/LineTracer.hpp | 6 +-- source/CMakeLists.txt | 1 - source/Triangle3d.cpp | 40 ----------------- source/collision/LineTracer.cpp | 8 ++-- tests/CMakeLists.txt | 1 + tests/general/UnitTestTriangle.cpp | 4 ++ 8 files changed, 71 insertions(+), 84 deletions(-) create mode 100644 include/omath/Triangle.hpp delete mode 100644 include/omath/Triangle3d.hpp delete mode 100644 source/Triangle3d.cpp create mode 100644 tests/general/UnitTestTriangle.cpp diff --git a/include/omath/Triangle.hpp b/include/omath/Triangle.hpp new file mode 100644 index 0000000..68a8894 --- /dev/null +++ b/include/omath/Triangle.hpp @@ -0,0 +1,59 @@ +// +// Created by Orange on 11/13/2024. +// +#pragma once +#include "omath/Vector3.hpp" + +namespace omath +{ + template + class Triangle final + { + public: + constexpr Triangle(const Vector& vertex1, const Vector& vertex2, const Vector& vertex3) + : m_vertex1(vertex1), m_vertex2(vertex2), m_vertex3(vertex3) + { + + } + + Vector3 m_vertex1; + Vector3 m_vertex2; + Vector3 m_vertex3; + + [[nodiscard]] + constexpr Vector3 CalculateNormal() const + { + return (m_vertex1 - m_vertex2).Cross(m_vertex3 - m_vertex1).Normalized(); + } + + [[nodiscard]] + constexpr float SideALength() const + { + return m_vertex1.DistTo(m_vertex2); + } + + [[nodiscard]] + constexpr float SideBLength() const + { + return m_vertex3.DistTo(m_vertex2); + } + + [[nodiscard]] + constexpr Vector3 SideAVector() const + { + return m_vertex1 - m_vertex2; + } + + [[nodiscard]] + constexpr Vector3 SideBVector() const + { + return m_vertex3 - m_vertex2; + } + + [[nodiscard]] + constexpr Vector3 MidPoint() const + { + return (m_vertex1 + m_vertex2 + m_vertex3) / 3; + } + }; +} // namespace omath diff --git a/include/omath/Triangle3d.hpp b/include/omath/Triangle3d.hpp deleted file mode 100644 index de71a80..0000000 --- a/include/omath/Triangle3d.hpp +++ /dev/null @@ -1,36 +0,0 @@ -// -// Created by Orange on 11/13/2024. -// -#pragma once -#include "omath/Vector3.hpp" - -namespace omath -{ - class Triangle3d final - { - public: - Triangle3d(const Vector3& vertex1, const Vector3& vertex2, const Vector3& vertex3); - - Vector3 m_vertex1; - Vector3 m_vertex2; - Vector3 m_vertex3; - - [[nodiscard]] - Vector3 CalculateNormal() const; - - [[nodiscard]] - float SideALength() const; - - [[nodiscard]] - float SideBLength() const; - - [[nodiscard]] - Vector3 SideAVector() const; - - [[nodiscard]] - Vector3 SideBVector() const; - - [[nodiscard]] - Vector3 MidPoint() const; - }; -} diff --git a/include/omath/collision/LineTracer.hpp b/include/omath/collision/LineTracer.hpp index e86f1dd..33b81a2 100644 --- a/include/omath/collision/LineTracer.hpp +++ b/include/omath/collision/LineTracer.hpp @@ -4,7 +4,7 @@ #pragma once #include "omath/Vector3.hpp" -#include "omath/Triangle3d.hpp" +#include "omath/Triangle.hpp" namespace omath::collision { @@ -27,12 +27,12 @@ namespace omath::collision [[nodiscard]] - static bool CanTraceLine(const Ray& ray, const Triangle3d& triangle); + static bool CanTraceLine(const Ray& ray, const Triangle& triangle); // Realization of Möller–Trumbore intersection algorithm // https://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm [[nodiscard]] - static Vector3 GetRayHitPoint(const Ray& ray, const Triangle3d& triangle); + static Vector3 GetRayHitPoint(const Ray& ray, const Triangle& triangle); }; } diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 0e0ea74..fe42cba 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -4,7 +4,6 @@ target_sources(omath PRIVATE color.cpp Vector4.cpp Vector2.cpp - Triangle3d.cpp ) add_subdirectory(prediction) diff --git a/source/Triangle3d.cpp b/source/Triangle3d.cpp deleted file mode 100644 index aacabc8..0000000 --- a/source/Triangle3d.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "omath/Triangle3d.hpp" - - -namespace omath -{ - Triangle3d::Triangle3d(const Vector3 &vertex1, const Vector3 &vertex2, const Vector3 &vertex3) - : m_vertex1(vertex1), m_vertex2(vertex2), m_vertex3(vertex3) - { - - } - - Vector3 Triangle3d::CalculateNormal() const - { - return (m_vertex1 - m_vertex2).Cross(m_vertex3 - m_vertex1).Normalized(); - } - - float Triangle3d::SideALength() const - { - return m_vertex1.DistTo(m_vertex2); - } - - float Triangle3d::SideBLength() const - { - return m_vertex3.DistTo(m_vertex2); - } - - Vector3 Triangle3d::SideAVector() const - { - return m_vertex1 - m_vertex2; - } - - Vector3 Triangle3d::SideBVector() const - { - return m_vertex3 - m_vertex2; - } - Vector3 Triangle3d::MidPoint() const - { - return (m_vertex1 + m_vertex2 + m_vertex3) / 3; - } -} // namespace omath diff --git a/source/collision/LineTracer.cpp b/source/collision/LineTracer.cpp index 83bcdd2..5f8c5b6 100644 --- a/source/collision/LineTracer.cpp +++ b/source/collision/LineTracer.cpp @@ -5,7 +5,7 @@ namespace omath::collision { - bool LineTracer::CanTraceLine(const Ray &ray, const Triangle3d &triangle) + bool LineTracer::CanTraceLine(const Ray& ray, const Triangle& triangle) { return GetRayHitPoint(ray, triangle) == ray.end; } @@ -19,7 +19,7 @@ namespace omath::collision return DirectionVector().Normalized(); } - Vector3 LineTracer::GetRayHitPoint(const Ray &ray, const Triangle3d &triangle) + Vector3 LineTracer::GetRayHitPoint(const Ray& ray, const Triangle& triangle) { constexpr float kEpsilon = std::numeric_limits::epsilon(); @@ -41,7 +41,7 @@ namespace omath::collision const auto u = t.Dot(p) * invDet; - if ((u < 0 && std::abs(u) > kEpsilon) || (u > 1 && std::abs(u-1) > kEpsilon)) + if ((u < 0 && std::abs(u) > kEpsilon) || (u > 1 && std::abs(u - 1) > kEpsilon)) return ray.end; const auto q = t.Cross(sideA); @@ -59,4 +59,4 @@ namespace omath::collision return ray.start + rayDir * tHit; } -} +} // namespace omath::collision diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 77c9508..aa377b8 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -18,6 +18,7 @@ add_executable(unit-tests general/UnitTestAngles.cpp general/UnitTestViewAngles.cpp general/UnitTestAngle.cpp + general/UnitTestTriangle.cpp engines/UnitTestOpenGL.cpp engines/UnitTestUnityEngine.cpp diff --git a/tests/general/UnitTestTriangle.cpp b/tests/general/UnitTestTriangle.cpp new file mode 100644 index 0000000..b7f486f --- /dev/null +++ b/tests/general/UnitTestTriangle.cpp @@ -0,0 +1,4 @@ +// +// Created by Orange on 1/6/2025. +// +#include "omath/Triangle.hpp" From 29629a737d287a2700d039f787993b9e89fdb176 Mon Sep 17 00:00:00 2001 From: Orange Date: Mon, 6 Jan 2025 05:08:32 +0300 Subject: [PATCH 2/4] added some methods --- include/omath/Triangle.hpp | 24 +++++- tests/general/UnitTestLineTrace.cpp | 6 +- tests/general/UnitTestTriangle.cpp | 129 ++++++++++++++++++++++++++++ 3 files changed, 152 insertions(+), 7 deletions(-) diff --git a/include/omath/Triangle.hpp b/include/omath/Triangle.hpp index 68a8894..77c1532 100644 --- a/include/omath/Triangle.hpp +++ b/include/omath/Triangle.hpp @@ -10,6 +10,7 @@ namespace omath class Triangle final { public: + constexpr Triangle() = default; constexpr Triangle(const Vector& vertex1, const Vector& vertex2, const Vector& vertex3) : m_vertex1(vertex1), m_vertex2(vertex2), m_vertex3(vertex3) { @@ -23,17 +24,19 @@ namespace omath [[nodiscard]] constexpr Vector3 CalculateNormal() const { - return (m_vertex1 - m_vertex2).Cross(m_vertex3 - m_vertex1).Normalized(); + const auto b = SideBVector(); + const auto a = SideAVector(); + return b.Cross(a).Normalized(); } [[nodiscard]] - constexpr float SideALength() const + float SideALength() const { return m_vertex1.DistTo(m_vertex2); } [[nodiscard]] - constexpr float SideBLength() const + float SideBLength() const { return m_vertex3.DistTo(m_vertex2); } @@ -44,12 +47,25 @@ namespace omath return m_vertex1 - m_vertex2; } + [[nodiscard]] + constexpr float Hypot() const + { + return m_vertex1.DistTo(m_vertex3); + } + [[nodiscard]] + constexpr bool IsRectangular() const + { + const auto sideA = SideALength(); + const auto sideB = SideBLength(); + const auto hypot = Hypot(); + + return sideA*sideA + sideB*sideB == hypot*hypot; + } [[nodiscard]] constexpr Vector3 SideBVector() const { return m_vertex3 - m_vertex2; } - [[nodiscard]] constexpr Vector3 MidPoint() const { diff --git a/tests/general/UnitTestLineTrace.cpp b/tests/general/UnitTestLineTrace.cpp index 67884d9..4e37916 100644 --- a/tests/general/UnitTestLineTrace.cpp +++ b/tests/general/UnitTestLineTrace.cpp @@ -1,6 +1,6 @@ #include "gtest/gtest.h" #include "omath/collision/LineTracer.hpp" -#include "omath/Triangle3d.hpp" +#include "omath/Triangle.hpp" #include "omath/Vector3.hpp" using namespace omath; @@ -13,7 +13,7 @@ protected: Vector3 vertex1{0.0f, 0.0f, 0.0f}; Vector3 vertex2{1.0f, 0.0f, 0.0f}; Vector3 vertex3{0.0f, 1.0f, 0.0f}; - Triangle3d triangle{vertex1, vertex2, vertex3}; + Triangle triangle{vertex1, vertex2, vertex3}; }; // Test that a ray intersecting the triangle returns false for CanTraceLine @@ -71,7 +71,7 @@ TEST_F(LineTracerTest, TriangleFarBeyondRayEndPoint) constexpr Ray ray{{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 1.0f}}; // Define a triangle far beyond the ray's endpoint - const Triangle3d distantTriangle{ + constexpr Triangle distantTriangle{ {1000.0f, 1000.0f, 1000.0f}, {1001.0f, 1000.0f, 1000.0f}, {1000.0f, 1001.0f, 1000.0f} }; diff --git a/tests/general/UnitTestTriangle.cpp b/tests/general/UnitTestTriangle.cpp index b7f486f..8fc1aa6 100644 --- a/tests/general/UnitTestTriangle.cpp +++ b/tests/general/UnitTestTriangle.cpp @@ -2,3 +2,132 @@ // Created by Orange on 1/6/2025. // #include "omath/Triangle.hpp" +#include +#include +#include // For std::sqrt, std::isinf, std::isnan + + +using namespace omath; + +class UnitTestTriangle : public ::testing::Test +{ +protected: + // Define some Triangles to use in tests + Triangle t1; + Triangle t2; + Triangle t3; + + constexpr void SetUp() override + { + // Triangle with vertices (0, 0, 0), (1, 0, 0), (0, 1, 0) + t1 = Triangle( + Vector3(0.0f, 0.0f, 0.0f), + Vector3(1.0f, 0.0f, 0.0f), + Vector3(0.0f, 1.0f, 0.0f) + ); + + // Triangle with vertices (1, 2, 3), (4, 5, 6), (7, 8, 9) + t2 = Triangle( + Vector3(1.0f, 2.0f, 3.0f), + Vector3(4.0f, 5.0f, 6.0f), + Vector3(7.0f, 8.0f, 9.0f) + ); + + // An isosceles right triangle + t3 = Triangle( + Vector3(0.0f, 0.0f, 0.0f), + Vector3(2.0f, 0.0f, 0.0f), + Vector3(0.0f, 2.0f, 0.0f) + ); + } +}; + +// Test constructor and vertices +TEST_F(UnitTestTriangle, Constructor) +{ + constexpr Triangle t( + Vector3(1.0f, 2.0f, 3.0f), + Vector3(4.0f, 5.0f, 6.0f), + Vector3(7.0f, 8.0f, 9.0f) + ); + + EXPECT_FLOAT_EQ(t.m_vertex1.x, 1.0f); + EXPECT_FLOAT_EQ(t.m_vertex1.y, 2.0f); + EXPECT_FLOAT_EQ(t.m_vertex1.z, 3.0f); + + EXPECT_FLOAT_EQ(t.m_vertex2.x, 4.0f); + EXPECT_FLOAT_EQ(t.m_vertex2.y, 5.0f); + EXPECT_FLOAT_EQ(t.m_vertex2.z, 6.0f); + + EXPECT_FLOAT_EQ(t.m_vertex3.x, 7.0f); + EXPECT_FLOAT_EQ(t.m_vertex3.y, 8.0f); + EXPECT_FLOAT_EQ(t.m_vertex3.z, 9.0f); +} + +// Test CalculateNormal +TEST_F(UnitTestTriangle, CalculateNormal) +{ + // For t1, the normal should point in the +Z direction (0, 0, 1) or (0, 0, -1) + const Vector3 normal_t1 = t1.CalculateNormal(); + // Check if it's normalized and pointed along Z (sign can differ, so use absolute check) + EXPECT_NEAR(std::fabs(normal_t1.z), 1.0f, 1e-5f); + EXPECT_NEAR(normal_t1.Length(), 1.0f, 1e-5f); + + + // For t3, we expect the normal to be along +Z as well + const Vector3 normal_t3 = t3.CalculateNormal(); + EXPECT_NEAR(std::fabs(normal_t3.z), 1.0f, 1e-5f); +} + +// Test side lengths +TEST_F(UnitTestTriangle, SideLengths) +{ + // For t1 side lengths + EXPECT_FLOAT_EQ(t1.SideALength(), std::sqrt(1.0f)); // distance between (0,0,0) and (1,0,0) + EXPECT_FLOAT_EQ(t1.SideBLength(), std::sqrt(1.0f + 1.0f)); // distance between (4,5,6) & (7,8,9)... but we are testing t1, so let's be accurate: + // Actually, for t1: vertex2=(1,0,0), vertex3=(0,1,0) + // Dist between (0,1,0) and (1,0,0) = sqrt((1-0)^2 + (0-1)^2) = sqrt(1 + 1) = sqrt(2) + EXPECT_FLOAT_EQ(t1.SideBLength(), std::sqrt(2.0f)); + + // For t3, side a = distance between vertex1=(0,0,0) and vertex2=(2,0,0), which is 2 + // side b = distance between vertex3=(0,2,0) and vertex2=(2,0,0), which is sqrt(2^2 + (-2)^2)= sqrt(8)= 2.828... + // We'll just check side a first: + EXPECT_FLOAT_EQ(t3.SideALength(), 2.0f); + // Then side b: + EXPECT_FLOAT_EQ(t3.SideBLength(), std::sqrt(8.0f)); +} + +// Test side vectors +TEST_F(UnitTestTriangle, SideVectors) +{ + const Vector3 sideA_t1 = t1.SideAVector(); // m_vertex1 - m_vertex2 + EXPECT_FLOAT_EQ(sideA_t1.x, 0.0f - 1.0f); + EXPECT_FLOAT_EQ(sideA_t1.y, 0.0f - 0.0f); + EXPECT_FLOAT_EQ(sideA_t1.z, 0.0f - 0.0f); + + const Vector3 sideB_t1 = t1.SideBVector(); // m_vertex3 - m_vertex2 + EXPECT_FLOAT_EQ(sideB_t1.x, 0.0f - 1.0f); + EXPECT_FLOAT_EQ(sideB_t1.y, 1.0f - 0.0f); + EXPECT_FLOAT_EQ(sideB_t1.z, 0.0f - 0.0f); +} + +TEST_F(UnitTestTriangle, IsRectangular) +{ + EXPECT_TRUE(t1.IsRectangular()); + EXPECT_TRUE(t3.IsRectangular()); +} +// Test midpoint +TEST_F(UnitTestTriangle, MidPoint) +{ + // For t1, midpoint of (0,0,0), (1,0,0), (0,1,0) + const Vector3 mid1 = t1.MidPoint(); + EXPECT_FLOAT_EQ(mid1.x, (0.0f + 1.0f + 0.0f) / 3.0f); + EXPECT_FLOAT_EQ(mid1.y, (0.0f + 0.0f + 1.0f) / 3.0f); + EXPECT_FLOAT_EQ(mid1.z, 0.0f); + + // For t2, midpoint of (1,2,3), (4,5,6), (7,8,9) + const Vector3 mid2 = t2.MidPoint(); + EXPECT_FLOAT_EQ(mid2.x, (1.0f + 4.0f + 7.0f) / 3.0f); + EXPECT_FLOAT_EQ(mid2.y, (2.0f + 5.0f + 8.0f) / 3.0f); + EXPECT_FLOAT_EQ(mid2.z, (3.0f + 6.0f + 9.0f) / 3.0f); +} From 835fd110ba9a3d5b660548f01d22aac04a5e6b1a Mon Sep 17 00:00:00 2001 From: Orange Date: Mon, 6 Jan 2025 05:15:12 +0300 Subject: [PATCH 3/4] fix --- include/omath/Triangle.hpp | 2 +- tests/general/UnitTestTriangle.cpp | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/include/omath/Triangle.hpp b/include/omath/Triangle.hpp index 77c1532..8107938 100644 --- a/include/omath/Triangle.hpp +++ b/include/omath/Triangle.hpp @@ -59,7 +59,7 @@ namespace omath const auto sideB = SideBLength(); const auto hypot = Hypot(); - return sideA*sideA + sideB*sideB == hypot*hypot; + return std::abs(sideA*sideA + sideB*sideB - hypot*hypot) <= 0.0001f; } [[nodiscard]] constexpr Vector3 SideBVector() const diff --git a/tests/general/UnitTestTriangle.cpp b/tests/general/UnitTestTriangle.cpp index 8fc1aa6..258cb97 100644 --- a/tests/general/UnitTestTriangle.cpp +++ b/tests/general/UnitTestTriangle.cpp @@ -113,8 +113,7 @@ TEST_F(UnitTestTriangle, SideVectors) TEST_F(UnitTestTriangle, IsRectangular) { - EXPECT_TRUE(t1.IsRectangular()); - EXPECT_TRUE(t3.IsRectangular()); + EXPECT_TRUE(Triangle({2,0,0}, {}, {0,2,0}).IsRectangular()); } // Test midpoint TEST_F(UnitTestTriangle, MidPoint) From afcfed483439bd0ed64fd7f78a7589289ebbdb94 Mon Sep 17 00:00:00 2001 From: Orange Date: Mon, 6 Jan 2025 05:17:42 +0300 Subject: [PATCH 4/4] path --- include/omath/Triangle.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/include/omath/Triangle.hpp b/include/omath/Triangle.hpp index 8107938..e9e3665 100644 --- a/include/omath/Triangle.hpp +++ b/include/omath/Triangle.hpp @@ -14,7 +14,6 @@ namespace omath constexpr Triangle(const Vector& vertex1, const Vector& vertex2, const Vector& vertex3) : m_vertex1(vertex1), m_vertex2(vertex2), m_vertex3(vertex3) { - } Vector3 m_vertex1;