From 918858e2552f785ba7a382b0e391ad83d3a14e4a Mon Sep 17 00:00:00 2001 From: Orange Date: Wed, 3 Dec 2025 09:52:53 +0300 Subject: [PATCH 01/12] added poly allocators --- include/omath/collision/epa_algorithm.hpp | 20 ++++++++++++++------ tests/general/unit_test_epa.cpp | 4 ++-- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/include/omath/collision/epa_algorithm.hpp b/include/omath/collision/epa_algorithm.hpp index 4bcdb30..3ba34a4 100644 --- a/include/omath/collision/epa_algorithm.hpp +++ b/include/omath/collision/epa_algorithm.hpp @@ -24,6 +24,14 @@ namespace omath::collision class Epa final { public: + explicit Epa( std::pmr::memory_resource* mem_resource = std::pmr::get_default_resource(), + const int max_iterations = 64, const float tolerance = 1e-4f) + : m_memory_resource(mem_resource), m_max_iterations(max_iterations), m_tolerance(tolerance) + { + } + std::pmr::memory_resource* m_memory_resource; + int m_max_iterations{64}; + float m_tolerance{1e-4f}; using VectorType = ColliderType::VectorType; static_assert(EpaVector, "VertexType must satisfy EpaVector concept"); @@ -45,17 +53,17 @@ namespace omath::collision // Precondition: simplex.size()==4 and contains the origin. [[nodiscard]] - static std::optional solve(const ColliderType& a, const ColliderType& b, + std::optional solve(const ColliderType& a, const ColliderType& b, const Simplex& simplex, const Params params = {}) { // --- Build initial polytope from simplex (4 points) --- - std::vector vertexes; + std::pmr::vector vertexes{m_memory_resource}; vertexes.reserve(64); for (std::size_t i = 0; i < simplex.size(); ++i) vertexes.push_back(simplex[i]); // Initial tetra faces (windings corrected in make_face) - std::vector faces; + std::pmr::vector faces{m_memory_resource}; faces.reserve(128); faces.emplace_back(make_face(vertexes, 0, 1, 2)); faces.emplace_back(make_face(vertexes, 0, 2, 3)); @@ -127,7 +135,7 @@ namespace omath::collision } // Remove visible faces - std::vector new_faces; + std::pmr::vector new_faces; new_faces.reserve(faces.size() + boundary.size()); for (int i = 0; i < static_cast(faces.size()); ++i) if (!to_delete[i]) @@ -196,7 +204,7 @@ namespace omath::collision using Heap = std::priority_queue, HeapCmp>; [[nodiscard]] - static Heap rebuild_heap(const std::vector& faces) + static Heap rebuild_heap(const std::pmr::vector& faces) { Heap h; for (int i = 0; i < static_cast(faces.size()); ++i) @@ -223,7 +231,7 @@ namespace omath::collision } [[nodiscard]] - static Face make_face(const std::vector& vertexes, int i0, int i1, int i2) + static Face make_face(const std::pmr::vector& vertexes, int i0, int i1, int i2) { const VectorType& a0 = vertexes[i0]; const VectorType& a1 = vertexes[i1]; diff --git a/tests/general/unit_test_epa.cpp b/tests/general/unit_test_epa.cpp index 10287a3..a8e8be7 100644 --- a/tests/general/unit_test_epa.cpp +++ b/tests/general/unit_test_epa.cpp @@ -43,7 +43,7 @@ TEST(UnitTestEpa, TestCollisionTrue) EPA::Params params; params.max_iterations = 64; params.tolerance = 1e-4f; - auto epa = EPA::solve(A, B, gjk.simplex, params); + auto epa = EPA().solve(A, B, gjk.simplex, params); ASSERT_TRUE(epa.has_value()) << "EPA should converge"; // Normal is unit @@ -117,7 +117,7 @@ TEST(UnitTestEpa, TestCollisionTrue2) EPA::Params params; params.max_iterations = 64; params.tolerance = 1e-4f; - auto epa = EPA::solve(A, B, gjk.simplex, params); + auto epa = EPA().solve(A, B, gjk.simplex, params); ASSERT_TRUE(epa.has_value()) << "EPA should converge"; // Normal is unit-length From d4d8f70fff96811daf8ea560554c54a0599cae75 Mon Sep 17 00:00:00 2001 From: Orange Date: Wed, 3 Dec 2025 13:30:05 +0300 Subject: [PATCH 02/12] switched to shared_ptr --- include/omath/collision/epa_algorithm.hpp | 24 ++++++++++++----------- tests/general/unit_test_epa.cpp | 8 +++++--- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/include/omath/collision/epa_algorithm.hpp b/include/omath/collision/epa_algorithm.hpp index 3ba34a4..dc85d57 100644 --- a/include/omath/collision/epa_algorithm.hpp +++ b/include/omath/collision/epa_algorithm.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include namespace omath::collision @@ -24,12 +25,13 @@ namespace omath::collision class Epa final { public: - explicit Epa( std::pmr::memory_resource* mem_resource = std::pmr::get_default_resource(), + explicit Epa(std::shared_ptr mem_resource = {std::shared_ptr{}, + std::pmr::get_default_resource()}, const int max_iterations = 64, const float tolerance = 1e-4f) - : m_memory_resource(mem_resource), m_max_iterations(max_iterations), m_tolerance(tolerance) + : m_memory_resource(std::move(mem_resource)), m_max_iterations(max_iterations), m_tolerance(tolerance) { } - std::pmr::memory_resource* m_memory_resource; + std::shared_ptr m_memory_resource; int m_max_iterations{64}; float m_tolerance{1e-4f}; using VectorType = ColliderType::VectorType; @@ -53,17 +55,17 @@ namespace omath::collision // Precondition: simplex.size()==4 and contains the origin. [[nodiscard]] - std::optional solve(const ColliderType& a, const ColliderType& b, - const Simplex& simplex, const Params params = {}) + std::optional solve(const ColliderType& a, const ColliderType& b, const Simplex& simplex, + const Params params = {}) { // --- Build initial polytope from simplex (4 points) --- - std::pmr::vector vertexes{m_memory_resource}; + std::pmr::vector vertexes{m_memory_resource.get()}; vertexes.reserve(64); for (std::size_t i = 0; i < simplex.size(); ++i) vertexes.push_back(simplex[i]); // Initial tetra faces (windings corrected in make_face) - std::pmr::vector faces{m_memory_resource}; + std::pmr::vector faces{m_memory_resource.get()}; faces.reserve(128); faces.emplace_back(make_face(vertexes, 0, 1, 2)); faces.emplace_back(make_face(vertexes, 0, 2, 3)); @@ -116,8 +118,8 @@ namespace omath::collision vertexes.push_back(p); // Mark faces visible from p and collect their horizon - std::vector to_delete(faces.size(), 0); - std::vector boundary; + std::pmr::vector to_delete(faces.size(), 0, m_memory_resource.get()); + std::pmr::vector boundary{m_memory_resource.get()}; boundary.reserve(faces.size() * 2); for (int i = 0; i < static_cast(faces.size()); ++i) @@ -135,7 +137,7 @@ namespace omath::collision } // Remove visible faces - std::pmr::vector new_faces; + std::pmr::vector new_faces{m_memory_resource.get()}; new_faces.reserve(faces.size() + boundary.size()); for (int i = 0; i < static_cast(faces.size()); ++i) if (!to_delete[i]) @@ -219,7 +221,7 @@ namespace omath::collision return (f.n.dot(p) - f.d) > 1e-7f; } - static void add_edge_boundary(std::vector& boundary, int a, int b) + static void add_edge_boundary(std::pmr::vector& boundary, int a, int b) { // Keep edges that appear only once; erase if opposite already present auto itb = diff --git a/tests/general/unit_test_epa.cpp b/tests/general/unit_test_epa.cpp index a8e8be7..4e686be 100644 --- a/tests/general/unit_test_epa.cpp +++ b/tests/general/unit_test_epa.cpp @@ -5,6 +5,7 @@ #include "omath/engines/source_engine/mesh.hpp" #include "omath/linear_algebra/vector3.hpp" #include +#include using Mesh = omath::source_engine::Mesh; using Collider = omath::source_engine::MeshCollider; @@ -41,9 +42,10 @@ TEST(UnitTestEpa, TestCollisionTrue) // EPA EPA::Params params; + auto pool = std::make_shared(1024); params.max_iterations = 64; params.tolerance = 1e-4f; - auto epa = EPA().solve(A, B, gjk.simplex, params); + auto epa = EPA(pool).solve(A, B, gjk.simplex, params); ASSERT_TRUE(epa.has_value()) << "EPA should converge"; // Normal is unit @@ -112,12 +114,12 @@ TEST(UnitTestEpa, TestCollisionTrue2) // --- GJK must detect collision and provide simplex --- auto gjk = GJK::is_collide_with_simplex_info(A, B); ASSERT_TRUE(gjk.hit) << "GJK should report collision for overlapping cubes"; - // --- EPA penetration --- EPA::Params params; params.max_iterations = 64; params.tolerance = 1e-4f; - auto epa = EPA().solve(A, B, gjk.simplex, params); + auto pool = std::make_shared(1024); + auto epa = EPA(pool).solve(A, B, gjk.simplex, params); ASSERT_TRUE(epa.has_value()) << "EPA should converge"; // Normal is unit-length From 3685f1334438449dd676e9f84659e4ff0266bf38 Mon Sep 17 00:00:00 2001 From: Orange Date: Wed, 3 Dec 2025 13:34:35 +0300 Subject: [PATCH 03/12] back to static --- include/omath/collision/epa_algorithm.hpp | 25 ++++++++--------------- tests/general/unit_test_epa.cpp | 4 ++-- 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/include/omath/collision/epa_algorithm.hpp b/include/omath/collision/epa_algorithm.hpp index dc85d57..9dd7de5 100644 --- a/include/omath/collision/epa_algorithm.hpp +++ b/include/omath/collision/epa_algorithm.hpp @@ -25,15 +25,6 @@ namespace omath::collision class Epa final { public: - explicit Epa(std::shared_ptr mem_resource = {std::shared_ptr{}, - std::pmr::get_default_resource()}, - const int max_iterations = 64, const float tolerance = 1e-4f) - : m_memory_resource(std::move(mem_resource)), m_max_iterations(max_iterations), m_tolerance(tolerance) - { - } - std::shared_ptr m_memory_resource; - int m_max_iterations{64}; - float m_tolerance{1e-4f}; using VectorType = ColliderType::VectorType; static_assert(EpaVector, "VertexType must satisfy EpaVector concept"); @@ -55,17 +46,19 @@ namespace omath::collision // Precondition: simplex.size()==4 and contains the origin. [[nodiscard]] - std::optional solve(const ColliderType& a, const ColliderType& b, const Simplex& simplex, - const Params params = {}) + static std::optional solve(const ColliderType& a, const ColliderType& b, + const Simplex& simplex, const Params params = {}, + std::shared_ptr mem_resource = { + std::shared_ptr{}, std::pmr::get_default_resource()}) { // --- Build initial polytope from simplex (4 points) --- - std::pmr::vector vertexes{m_memory_resource.get()}; + std::pmr::vector vertexes{mem_resource.get()}; vertexes.reserve(64); for (std::size_t i = 0; i < simplex.size(); ++i) vertexes.push_back(simplex[i]); // Initial tetra faces (windings corrected in make_face) - std::pmr::vector faces{m_memory_resource.get()}; + std::pmr::vector faces{mem_resource.get()}; faces.reserve(128); faces.emplace_back(make_face(vertexes, 0, 1, 2)); faces.emplace_back(make_face(vertexes, 0, 2, 3)); @@ -118,8 +111,8 @@ namespace omath::collision vertexes.push_back(p); // Mark faces visible from p and collect their horizon - std::pmr::vector to_delete(faces.size(), 0, m_memory_resource.get()); - std::pmr::vector boundary{m_memory_resource.get()}; + std::pmr::vector to_delete(faces.size(), 0, mem_resource.get()); + std::pmr::vector boundary{mem_resource.get()}; boundary.reserve(faces.size() * 2); for (int i = 0; i < static_cast(faces.size()); ++i) @@ -137,7 +130,7 @@ namespace omath::collision } // Remove visible faces - std::pmr::vector new_faces{m_memory_resource.get()}; + std::pmr::vector new_faces{mem_resource.get()}; new_faces.reserve(faces.size() + boundary.size()); for (int i = 0; i < static_cast(faces.size()); ++i) if (!to_delete[i]) diff --git a/tests/general/unit_test_epa.cpp b/tests/general/unit_test_epa.cpp index 4e686be..1b9cd5b 100644 --- a/tests/general/unit_test_epa.cpp +++ b/tests/general/unit_test_epa.cpp @@ -45,7 +45,7 @@ TEST(UnitTestEpa, TestCollisionTrue) auto pool = std::make_shared(1024); params.max_iterations = 64; params.tolerance = 1e-4f; - auto epa = EPA(pool).solve(A, B, gjk.simplex, params); + auto epa = EPA::solve(A, B, gjk.simplex, params, pool); ASSERT_TRUE(epa.has_value()) << "EPA should converge"; // Normal is unit @@ -119,7 +119,7 @@ TEST(UnitTestEpa, TestCollisionTrue2) params.max_iterations = 64; params.tolerance = 1e-4f; auto pool = std::make_shared(1024); - auto epa = EPA(pool).solve(A, B, gjk.simplex, params); + auto epa = EPA::solve(A, B, gjk.simplex, params, pool); ASSERT_TRUE(epa.has_value()) << "EPA should converge"; // Normal is unit-length From 0788fd6122149dc606e212dffc16248c5fa39d85 Mon Sep 17 00:00:00 2001 From: Orange Date: Wed, 3 Dec 2025 14:11:29 +0300 Subject: [PATCH 04/12] replaced with emplace --- include/omath/collision/epa_algorithm.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/omath/collision/epa_algorithm.hpp b/include/omath/collision/epa_algorithm.hpp index 9dd7de5..2c070de 100644 --- a/include/omath/collision/epa_algorithm.hpp +++ b/include/omath/collision/epa_algorithm.hpp @@ -108,7 +108,7 @@ namespace omath::collision // Add new vertex const int new_idx = static_cast(vertexes.size()); - vertexes.push_back(p); + vertexes.emplace_back(p); // Mark faces visible from p and collect their horizon std::pmr::vector to_delete(faces.size(), 0, mem_resource.get()); @@ -134,12 +134,12 @@ namespace omath::collision new_faces.reserve(faces.size() + boundary.size()); for (int i = 0; i < static_cast(faces.size()); ++i) if (!to_delete[i]) - new_faces.push_back(faces[i]); + new_faces.emplace_back(faces[i]); faces.swap(new_faces); // Stitch new faces around the horizon for (const auto& e : boundary) - faces.push_back(make_face(vertexes, e.a, e.b, new_idx)); + faces.emplace_back(make_face(vertexes, e.a, e.b, new_idx)); // Rebuild heap after topology change heap = rebuild_heap(faces); @@ -203,7 +203,7 @@ namespace omath::collision { Heap h; for (int i = 0; i < static_cast(faces.size()); ++i) - h.push({faces[i].d, i}); + h.emplace(faces[i].d, i); return h; } @@ -222,7 +222,7 @@ namespace omath::collision if (itb != boundary.end()) boundary.erase(itb); // internal edge cancels out else - boundary.push_back({a, b}); // horizon edge (directed) + boundary.emplace_back(a, b); // horizon edge (directed) } [[nodiscard]] From 9e4c778e8f73bb30c9c64bcd5b58df4b30781d50 Mon Sep 17 00:00:00 2001 From: Orange Date: Thu, 4 Dec 2025 04:38:44 +0300 Subject: [PATCH 05/12] tweak --- include/omath/collision/epa_algorithm.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/omath/collision/epa_algorithm.hpp b/include/omath/collision/epa_algorithm.hpp index 2c070de..3254ef1 100644 --- a/include/omath/collision/epa_algorithm.hpp +++ b/include/omath/collision/epa_algorithm.hpp @@ -53,13 +53,13 @@ namespace omath::collision { // --- Build initial polytope from simplex (4 points) --- std::pmr::vector vertexes{mem_resource.get()}; - vertexes.reserve(64); + vertexes.reserve(simplex.size()); for (std::size_t i = 0; i < simplex.size(); ++i) - vertexes.push_back(simplex[i]); + vertexes.emplace_back(simplex[i]); // Initial tetra faces (windings corrected in make_face) std::pmr::vector faces{mem_resource.get()}; - faces.reserve(128); + faces.reserve(4); faces.emplace_back(make_face(vertexes, 0, 1, 2)); faces.emplace_back(make_face(vertexes, 0, 2, 3)); faces.emplace_back(make_face(vertexes, 0, 3, 1)); From eafefb40ec634a120f53754ee57c6c36e0067cd6 Mon Sep 17 00:00:00 2001 From: Orange Date: Thu, 4 Dec 2025 04:45:15 +0300 Subject: [PATCH 06/12] fixed typo --- include/omath/collision/epa_algorithm.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/omath/collision/epa_algorithm.hpp b/include/omath/collision/epa_algorithm.hpp index 3254ef1..1875176 100644 --- a/include/omath/collision/epa_algorithm.hpp +++ b/include/omath/collision/epa_algorithm.hpp @@ -86,7 +86,7 @@ namespace omath::collision const int fidx = heap.top().idx; const Face f = faces[fidx]; - // Get farthest point in face normal direction + // Get the furthest point in face normal direction const VectorType p = support_point(a, b, f.n); const float p_dist = f.n.dot(p); From 0e03805439a09c2890a28f227cd3a7607e295a37 Mon Sep 17 00:00:00 2001 From: Orange Date: Thu, 4 Dec 2025 04:46:00 +0300 Subject: [PATCH 07/12] added nodiscard + static --- include/omath/collision/epa_algorithm.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/omath/collision/epa_algorithm.hpp b/include/omath/collision/epa_algorithm.hpp index 1875176..ee349fa 100644 --- a/include/omath/collision/epa_algorithm.hpp +++ b/include/omath/collision/epa_algorithm.hpp @@ -191,7 +191,8 @@ namespace omath::collision }; struct HeapCmp final { - bool operator()(const HeapItem& lhs, const HeapItem& rhs) const noexcept + [[nodiscard]] + static bool operator()(const HeapItem& lhs, const HeapItem& rhs) const noexcept { return lhs.d > rhs.d; // min-heap by distance } From d7a009eb6780cc6280e53024b6b5e05c674b7fbc Mon Sep 17 00:00:00 2001 From: Orange Date: Thu, 4 Dec 2025 04:47:34 +0300 Subject: [PATCH 08/12] oops --- include/omath/collision/epa_algorithm.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/omath/collision/epa_algorithm.hpp b/include/omath/collision/epa_algorithm.hpp index ee349fa..d707beb 100644 --- a/include/omath/collision/epa_algorithm.hpp +++ b/include/omath/collision/epa_algorithm.hpp @@ -192,7 +192,7 @@ namespace omath::collision struct HeapCmp final { [[nodiscard]] - static bool operator()(const HeapItem& lhs, const HeapItem& rhs) const noexcept + static bool operator()(const HeapItem& lhs, const HeapItem& rhs) noexcept { return lhs.d > rhs.d; // min-heap by distance } From 1964d3d36fd91cb5cd745f2e972da0cea5ab6cfa Mon Sep 17 00:00:00 2001 From: Orange Date: Thu, 4 Dec 2025 04:52:22 +0300 Subject: [PATCH 09/12] replaced with bool --- include/omath/collision/epa_algorithm.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/omath/collision/epa_algorithm.hpp b/include/omath/collision/epa_algorithm.hpp index d707beb..b352f69 100644 --- a/include/omath/collision/epa_algorithm.hpp +++ b/include/omath/collision/epa_algorithm.hpp @@ -111,7 +111,7 @@ namespace omath::collision vertexes.emplace_back(p); // Mark faces visible from p and collect their horizon - std::pmr::vector to_delete(faces.size(), 0, mem_resource.get()); + std::pmr::vector to_delete(faces.size(), false, mem_resource.get()); // uses single bits std::pmr::vector boundary{mem_resource.get()}; boundary.reserve(faces.size() * 2); @@ -122,7 +122,7 @@ namespace omath::collision if (visible_from(faces[i], p)) { const auto& rf = faces[i]; - to_delete[i] = 1; + to_delete[i] = true; add_edge_boundary(boundary, rf.i0, rf.i1); add_edge_boundary(boundary, rf.i1, rf.i2); add_edge_boundary(boundary, rf.i2, rf.i0); From e1399d181426ef4a62db4df99a2814c6725d6389 Mon Sep 17 00:00:00 2001 From: Orange Date: Thu, 4 Dec 2025 05:01:52 +0300 Subject: [PATCH 10/12] fix --- include/omath/collision/epa_algorithm.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/omath/collision/epa_algorithm.hpp b/include/omath/collision/epa_algorithm.hpp index b352f69..5fbe05f 100644 --- a/include/omath/collision/epa_algorithm.hpp +++ b/include/omath/collision/epa_algorithm.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -218,8 +219,7 @@ namespace omath::collision static void add_edge_boundary(std::pmr::vector& boundary, int a, int b) { // Keep edges that appear only once; erase if opposite already present - auto itb = - std::find_if(boundary.begin(), boundary.end(), [&](const Edge& e) { return e.a == b && e.b == a; }); + auto itb = std::ranges::find_if(boundary, [&](const Edge& e) { return e.a == b && e.b == a; }); if (itb != boundary.end()) boundary.erase(itb); // internal edge cancels out else From 58aa03c4a97267efd8020d56f919587a6b743cce Mon Sep 17 00:00:00 2001 From: Orange Date: Thu, 4 Dec 2025 05:02:54 +0300 Subject: [PATCH 11/12] patch --- include/omath/collision/epa_algorithm.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/omath/collision/epa_algorithm.hpp b/include/omath/collision/epa_algorithm.hpp index 5fbe05f..2197901 100644 --- a/include/omath/collision/epa_algorithm.hpp +++ b/include/omath/collision/epa_algorithm.hpp @@ -213,7 +213,7 @@ namespace omath::collision static bool visible_from(const Face& f, const VectorType& p) { // positive if p is in front of the face - return (f.n.dot(p) - f.d) > 1e-7f; + return f.n.dot(p) - f.d > 1e-7f; } static void add_edge_boundary(std::pmr::vector& boundary, int a, int b) From e97d097b2b725305e629cbaddff32cc0d3dd53f2 Mon Sep 17 00:00:00 2001 From: Orange Date: Thu, 4 Dec 2025 05:08:01 +0300 Subject: [PATCH 12/12] fix --- include/omath/collision/epa_algorithm.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/omath/collision/epa_algorithm.hpp b/include/omath/collision/epa_algorithm.hpp index 2197901..6b1d732 100644 --- a/include/omath/collision/epa_algorithm.hpp +++ b/include/omath/collision/epa_algorithm.hpp @@ -9,6 +9,7 @@ #include #include #include +#include namespace omath::collision {