Skip to content

Commit e97be8c

Browse files
authored
Merge pull request #108 from orange-cpp/fearure/epa_pmr
Fearure/epa pmr
2 parents 1aff083 + e97d097 commit e97be8c

File tree

2 files changed

+33
-26
lines changed

2 files changed

+33
-26
lines changed

include/omath/collision/epa_algorithm.hpp

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,11 @@
55
#include <cmath>
66
#include <cstdint>
77
#include <limits>
8+
#include <memory>
89
#include <queue>
10+
#include <utility>
911
#include <vector>
12+
#include <memory_resource>
1013

1114
namespace omath::collision
1215
{
@@ -46,17 +49,19 @@ namespace omath::collision
4649
// Precondition: simplex.size()==4 and contains the origin.
4750
[[nodiscard]]
4851
static std::optional<Result> solve(const ColliderType& a, const ColliderType& b,
49-
const Simplex<VectorType>& simplex, const Params params = {})
52+
const Simplex<VectorType>& simplex, const Params params = {},
53+
std::shared_ptr<std::pmr::memory_resource> mem_resource = {
54+
std::shared_ptr<void>{}, std::pmr::get_default_resource()})
5055
{
5156
// --- Build initial polytope from simplex (4 points) ---
52-
std::vector<VectorType> vertexes;
53-
vertexes.reserve(64);
57+
std::pmr::vector<VectorType> vertexes{mem_resource.get()};
58+
vertexes.reserve(simplex.size());
5459
for (std::size_t i = 0; i < simplex.size(); ++i)
55-
vertexes.push_back(simplex[i]);
60+
vertexes.emplace_back(simplex[i]);
5661

5762
// Initial tetra faces (windings corrected in make_face)
58-
std::vector<Face> faces;
59-
faces.reserve(128);
63+
std::pmr::vector<Face> faces{mem_resource.get()};
64+
faces.reserve(4);
6065
faces.emplace_back(make_face(vertexes, 0, 1, 2));
6166
faces.emplace_back(make_face(vertexes, 0, 2, 3));
6267
faces.emplace_back(make_face(vertexes, 0, 3, 1));
@@ -83,7 +88,7 @@ namespace omath::collision
8388
const int fidx = heap.top().idx;
8489
const Face f = faces[fidx];
8590

86-
// Get farthest point in face normal direction
91+
// Get the furthest point in face normal direction
8792
const VectorType p = support_point(a, b, f.n);
8893
const float p_dist = f.n.dot(p);
8994

@@ -105,11 +110,11 @@ namespace omath::collision
105110

106111
// Add new vertex
107112
const int new_idx = static_cast<int>(vertexes.size());
108-
vertexes.push_back(p);
113+
vertexes.emplace_back(p);
109114

110115
// Mark faces visible from p and collect their horizon
111-
std::vector<char> to_delete(faces.size(), 0);
112-
std::vector<Edge> boundary;
116+
std::pmr::vector<bool> to_delete(faces.size(), false, mem_resource.get()); // uses single bits
117+
std::pmr::vector<Edge> boundary{mem_resource.get()};
113118
boundary.reserve(faces.size() * 2);
114119

115120
for (int i = 0; i < static_cast<int>(faces.size()); ++i)
@@ -119,24 +124,24 @@ namespace omath::collision
119124
if (visible_from(faces[i], p))
120125
{
121126
const auto& rf = faces[i];
122-
to_delete[i] = 1;
127+
to_delete[i] = true;
123128
add_edge_boundary(boundary, rf.i0, rf.i1);
124129
add_edge_boundary(boundary, rf.i1, rf.i2);
125130
add_edge_boundary(boundary, rf.i2, rf.i0);
126131
}
127132
}
128133

129134
// Remove visible faces
130-
std::vector<Face> new_faces;
135+
std::pmr::vector<Face> new_faces{mem_resource.get()};
131136
new_faces.reserve(faces.size() + boundary.size());
132137
for (int i = 0; i < static_cast<int>(faces.size()); ++i)
133138
if (!to_delete[i])
134-
new_faces.push_back(faces[i]);
139+
new_faces.emplace_back(faces[i]);
135140
faces.swap(new_faces);
136141

137142
// Stitch new faces around the horizon
138143
for (const auto& e : boundary)
139-
faces.push_back(make_face(vertexes, e.a, e.b, new_idx));
144+
faces.emplace_back(make_face(vertexes, e.a, e.b, new_idx));
140145

141146
// Rebuild heap after topology change
142147
heap = rebuild_heap(faces);
@@ -188,42 +193,42 @@ namespace omath::collision
188193
};
189194
struct HeapCmp final
190195
{
191-
bool operator()(const HeapItem& lhs, const HeapItem& rhs) const noexcept
196+
[[nodiscard]]
197+
static bool operator()(const HeapItem& lhs, const HeapItem& rhs) noexcept
192198
{
193199
return lhs.d > rhs.d; // min-heap by distance
194200
}
195201
};
196202
using Heap = std::priority_queue<HeapItem, std::vector<HeapItem>, HeapCmp>;
197203

198204
[[nodiscard]]
199-
static Heap rebuild_heap(const std::vector<Face>& faces)
205+
static Heap rebuild_heap(const std::pmr::vector<Face>& faces)
200206
{
201207
Heap h;
202208
for (int i = 0; i < static_cast<int>(faces.size()); ++i)
203-
h.push({faces[i].d, i});
209+
h.emplace(faces[i].d, i);
204210
return h;
205211
}
206212

207213
[[nodiscard]]
208214
static bool visible_from(const Face& f, const VectorType& p)
209215
{
210216
// positive if p is in front of the face
211-
return (f.n.dot(p) - f.d) > 1e-7f;
217+
return f.n.dot(p) - f.d > 1e-7f;
212218
}
213219

214-
static void add_edge_boundary(std::vector<Edge>& boundary, int a, int b)
220+
static void add_edge_boundary(std::pmr::vector<Edge>& boundary, int a, int b)
215221
{
216222
// Keep edges that appear only once; erase if opposite already present
217-
auto itb =
218-
std::find_if(boundary.begin(), boundary.end(), [&](const Edge& e) { return e.a == b && e.b == a; });
223+
auto itb = std::ranges::find_if(boundary, [&](const Edge& e) { return e.a == b && e.b == a; });
219224
if (itb != boundary.end())
220225
boundary.erase(itb); // internal edge cancels out
221226
else
222-
boundary.push_back({a, b}); // horizon edge (directed)
227+
boundary.emplace_back(a, b); // horizon edge (directed)
223228
}
224229

225230
[[nodiscard]]
226-
static Face make_face(const std::vector<VectorType>& vertexes, int i0, int i1, int i2)
231+
static Face make_face(const std::pmr::vector<VectorType>& vertexes, int i0, int i1, int i2)
227232
{
228233
const VectorType& a0 = vertexes[i0];
229234
const VectorType& a1 = vertexes[i1];

tests/general/unit_test_epa.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "omath/engines/source_engine/mesh.hpp"
66
#include "omath/linear_algebra/vector3.hpp"
77
#include <gtest/gtest.h>
8+
#include <memory_resource>
89

910
using Mesh = omath::source_engine::Mesh;
1011
using Collider = omath::source_engine::MeshCollider;
@@ -41,9 +42,10 @@ TEST(UnitTestEpa, TestCollisionTrue)
4142

4243
// EPA
4344
EPA::Params params;
45+
auto pool = std::make_shared<std::pmr::monotonic_buffer_resource>(1024);
4446
params.max_iterations = 64;
4547
params.tolerance = 1e-4f;
46-
auto epa = EPA::solve(A, B, gjk.simplex, params);
48+
auto epa = EPA::solve(A, B, gjk.simplex, params, pool);
4749
ASSERT_TRUE(epa.has_value()) << "EPA should converge";
4850

4951
// Normal is unit
@@ -112,12 +114,12 @@ TEST(UnitTestEpa, TestCollisionTrue2)
112114
// --- GJK must detect collision and provide simplex ---
113115
auto gjk = GJK::is_collide_with_simplex_info(A, B);
114116
ASSERT_TRUE(gjk.hit) << "GJK should report collision for overlapping cubes";
115-
116117
// --- EPA penetration ---
117118
EPA::Params params;
118119
params.max_iterations = 64;
119120
params.tolerance = 1e-4f;
120-
auto epa = EPA::solve(A, B, gjk.simplex, params);
121+
auto pool = std::make_shared<std::pmr::monotonic_buffer_resource>(1024);
122+
auto epa = EPA::solve(A, B, gjk.simplex, params, pool);
121123
ASSERT_TRUE(epa.has_value()) << "EPA should converge";
122124

123125
// Normal is unit-length

0 commit comments

Comments
 (0)