11#pragma once
22#include " simplex.hpp"
3- #include < algorithm> // find_if
3+ #include < algorithm>
44#include < array>
55#include < cmath>
66#include < cstdint>
@@ -19,7 +19,7 @@ namespace omath::collision
1919 { a.cross (b) } -> std::same_as<V>;
2020 { a.dot (b) } -> std::same_as<float >;
2121 { -a } -> std::same_as<V>;
22- { a* s } -> std::same_as<V>;
22+ { a * s } -> std::same_as<V>;
2323 { a / s } -> std::same_as<V>;
2424 };
2525
@@ -45,29 +45,19 @@ namespace omath::collision
4545 int max_iterations{64 };
4646 float tolerance{1e-4f }; // absolute tolerance on distance growth
4747 };
48-
4948 // Precondition: simplex.size()==4 and contains the origin.
5049 [[nodiscard]]
5150 static std::optional<Result> solve (const ColliderInterfaceType& a, const ColliderInterfaceType& b,
5251 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 ()})
52+ std::pmr::memory_resource& mem_resource = *std::pmr::get_default_resource ())
5553 {
5654 // --- Build initial polytope from simplex (4 points) ---
57- std::pmr::vector<VectorType> vertexes{mem_resource.get ()};
58- vertexes.reserve (simplex.size ());
59- for (std::size_t i = 0 ; i < simplex.size (); ++i)
60- vertexes.emplace_back (simplex[i]);
55+ std::pmr::vector<VectorType> vertexes = build_initial_polytope_from_simplex (simplex, mem_resource);
6156
6257 // Initial tetra faces (windings corrected in make_face)
63- std::pmr::vector<Face> faces{mem_resource.get ()};
64- faces.reserve (4 );
65- faces.emplace_back (make_face (vertexes, 0 , 1 , 2 ));
66- faces.emplace_back (make_face (vertexes, 0 , 2 , 3 ));
67- faces.emplace_back (make_face (vertexes, 0 , 3 , 1 ));
68- faces.emplace_back (make_face (vertexes, 1 , 3 , 2 ));
58+ std::pmr::vector<Face> faces = create_initial_tetra_faces (mem_resource, vertexes);
6959
70- auto heap = rebuild_heap (faces);
60+ auto heap = rebuild_heap (faces, mem_resource );
7161
7262 Result out{};
7363
@@ -80,7 +70,7 @@ namespace omath::collision
8070 // (We could keep face handles; this is fine for small Ns.)
8171
8272 if (const auto top = heap.top (); faces[top.idx ].d != top.d )
83- heap = rebuild_heap (faces);
73+ heap = rebuild_heap (faces, mem_resource );
8474
8575 if (heap.empty ())
8676 break ;
@@ -109,62 +99,35 @@ namespace omath::collision
10999 const int new_idx = static_cast <int >(vertexes.size ());
110100 vertexes.emplace_back (p);
111101
112- // Mark faces visible from p and collect their horizon
113- std::pmr::vector<bool > to_delete (faces.size (), false , mem_resource.get ()); // uses single bits
114- std::pmr::vector<Edge> boundary{mem_resource.get ()};
115- boundary.reserve (faces.size () * 2 );
116-
117- for (int i = 0 ; i < static_cast <int >(faces.size ()); ++i)
118- {
119- if (to_delete[i])
120- continue ;
121- if (visible_from (faces[i], p))
122- {
123- const auto & rf = faces[i];
124- to_delete[i] = true ;
125- add_edge_boundary (boundary, rf.i0 , rf.i1 );
126- add_edge_boundary (boundary, rf.i1 , rf.i2 );
127- add_edge_boundary (boundary, rf.i2 , rf.i0 );
128- }
129- }
102+ const auto [to_delete, boundary] = mark_visible_and_collect_horizon (faces, p);
130103
131- // Remove visible faces
132- std::pmr::vector<Face> new_faces{mem_resource.get ()};
133- new_faces.reserve (faces.size () + boundary.size ());
134- for (int i = 0 ; i < static_cast <int >(faces.size ()); ++i)
135- if (!to_delete[i])
136- new_faces.emplace_back (faces[i]);
137- faces.swap (new_faces);
104+ erase_marked (faces, to_delete);
138105
139106 // Stitch new faces around the horizon
140107 for (const auto & e : boundary)
141108 faces.emplace_back (make_face (vertexes, e.a , e.b , new_idx));
142109
143110 // Rebuild heap after topology change
144- heap = rebuild_heap (faces);
111+ heap = rebuild_heap (faces, mem_resource );
145112
146113 if (!std::isfinite (vertexes.back ().dot (vertexes.back ())))
147114 break ; // safety
148115 out.iterations = it + 1 ;
149116 }
150117
151- // Fallback: pick closest face as best-effort answer
152- if (!faces.empty ())
153- {
154- auto best = faces[0 ];
155- for (const auto & f : faces)
156- if (f.d < best.d )
157- best = f;
158- out.normal = best.n ;
159- out.depth = best.d ;
160- out.num_vertices = static_cast <int >(vertexes.size ());
161- out.num_faces = static_cast <int >(faces.size ());
162-
163- out.penetration_vector = out.normal * out.depth ;
164-
165- return out;
166- }
167- return std::nullopt ;
118+ if (faces.empty ())
119+ return std::nullopt ;
120+
121+ const auto best = *std::ranges::min_element (faces, [](const auto & first, const auto & second)
122+ { return first.d < second.d ; });
123+ out.normal = best.n ;
124+ out.depth = best.d ;
125+ out.num_vertices = static_cast <int >(vertexes.size ());
126+ out.num_faces = static_cast <int >(faces.size ());
127+
128+ out.penetration_vector = out.normal * out.depth ;
129+
130+ return out;
168131 }
169132
170133 private:
@@ -193,15 +156,21 @@ namespace omath::collision
193156 return lhs.d > rhs.d ; // min-heap by distance
194157 }
195158 };
196- using Heap = std::priority_queue<HeapItem, std::vector<HeapItem>, HeapCmp>;
159+
160+ using Heap = std::priority_queue<HeapItem, std::pmr::vector<HeapItem>, HeapCmp>;
197161
198162 [[nodiscard]]
199- static Heap rebuild_heap (const std::pmr::vector<Face>& faces)
163+ static Heap rebuild_heap (const std::pmr::vector<Face>& faces, auto & memory_resource )
200164 {
201- Heap h;
165+ std::pmr::vector<HeapItem> storage{&memory_resource};
166+ storage.reserve (faces.size ()); // optional but recommended
167+
168+ Heap h{HeapCmp{}, std::move (storage)};
169+
202170 for (int i = 0 ; i < static_cast <int >(faces.size ()); ++i)
203171 h.emplace (faces[i].d , i);
204- return h;
172+
173+ return h; // allocator is preserved
205174 }
206175
207176 [[nodiscard]]
@@ -267,5 +236,67 @@ namespace omath::collision
267236 return d;
268237 return V{1 , 0 , 0 };
269238 }
239+ [[nodiscard]]
240+ static std::pmr::vector<Face> create_initial_tetra_faces (std::pmr::memory_resource& mem_resource,
241+ const std::pmr::vector<VectorType>& vertexes)
242+ {
243+ std::pmr::vector<Face> faces{&mem_resource};
244+ faces.reserve (4 );
245+ faces.emplace_back (make_face (vertexes, 0 , 1 , 2 ));
246+ faces.emplace_back (make_face (vertexes, 0 , 2 , 3 ));
247+ faces.emplace_back (make_face (vertexes, 0 , 3 , 1 ));
248+ faces.emplace_back (make_face (vertexes, 1 , 3 , 2 ));
249+ return faces;
250+ }
251+
252+ [[nodiscard]]
253+ static std::pmr::vector<VectorType> build_initial_polytope_from_simplex (const Simplex<VectorType>& simplex,
254+ std::pmr::memory_resource& mem_resource)
255+ {
256+ std::pmr::vector<VectorType> vertexes{&mem_resource};
257+ vertexes.reserve (simplex.size ());
258+
259+ for (std::size_t i = 0 ; i < simplex.size (); ++i)
260+ vertexes.emplace_back (simplex[i]);
261+
262+ return vertexes;
263+ }
264+ static void erase_marked (std::pmr::vector<Face>& faces, const std::pmr::vector<bool >& to_delete)
265+ {
266+ auto * mr = faces.get_allocator ().resource (); // keep same resource
267+ std::pmr::vector<Face> kept{mr};
268+ kept.reserve (faces.size ());
269+
270+ for (std::size_t i = 0 ; i < faces.size (); ++i)
271+ if (!to_delete[i])
272+ kept.emplace_back (faces[i]);
273+
274+ faces.swap (kept);
275+ }
276+ struct Horizon
277+ {
278+ std::pmr::vector<bool > to_delete;
279+ std::pmr::vector<Edge> boundary;
280+ };
281+
282+ static Horizon mark_visible_and_collect_horizon (const std::pmr::vector<Face>& faces, const VectorType& p)
283+ {
284+ auto * mr = faces.get_allocator ().resource ();
285+
286+ Horizon horizon{std::pmr::vector<bool >(faces.size (), false , mr), std::pmr::vector<Edge>(mr)};
287+ horizon.boundary .reserve (faces.size ());
288+
289+ for (std::size_t i = 0 ; i < faces.size (); ++i)
290+ if (visible_from (faces[i], p))
291+ {
292+ const auto & rf = faces[i];
293+ horizon.to_delete [i] = true ;
294+ add_edge_boundary (horizon.boundary , rf.i0 , rf.i1 );
295+ add_edge_boundary (horizon.boundary , rf.i1 , rf.i2 );
296+ add_edge_boundary (horizon.boundary , rf.i2 , rf.i0 );
297+ }
298+
299+ return horizon;
300+ }
270301 };
271302} // namespace omath::collision
0 commit comments