improvement

This commit is contained in:
2026-03-03 08:43:30 +03:00
parent bfe147ef80
commit dee705a391

View File

@@ -8,6 +8,7 @@
#include <memory> #include <memory>
#include <memory_resource> #include <memory_resource>
#include <queue> #include <queue>
#include <unordered_map>
#include <utility> #include <utility>
#include <vector> #include <vector>
@@ -64,9 +65,9 @@ namespace omath::collision
Result out{}; Result out{};
// Hoisted outside the loop to reuse the allocation across iterations. // Hoisted outside the loop to reuse bucket allocation across iterations.
std::pmr::vector<Edge> boundary{&mem_resource}; // Initial bucket count 16 covers a typical horizon without rehashing.
boundary.reserve(16); BoundaryMap boundary{16, &mem_resource};
for (int it = 0; it < params.max_iterations; ++it) for (int it = 0; it < params.max_iterations; ++it)
{ {
@@ -102,7 +103,7 @@ namespace omath::collision
// Stitch new faces around the horizon and push them directly onto the // Stitch new faces around the horizon and push them directly onto the
// heap — no full O(n log n) rebuild needed. // heap — no full O(n log n) rebuild needed.
for (const auto& e : boundary) for (const auto& [key, e] : boundary)
{ {
const int fi = static_cast<int>(faces.size()); const int fi = static_cast<int>(faces.size());
faces.emplace_back(make_face(vertexes, e.a, e.b, new_idx)); faces.emplace_back(make_face(vertexes, e.a, e.b, new_idx));
@@ -160,6 +161,16 @@ namespace omath::collision
using Heap = std::priority_queue<HeapItem, std::pmr::vector<HeapItem>, HeapCmp>; using Heap = std::priority_queue<HeapItem, std::pmr::vector<HeapItem>, HeapCmp>;
// Horizon boundary: maps packed(a,b) → Edge.
// Opposite edges cancel in O(1) via hash lookup instead of O(h) linear scan.
using BoundaryMap = std::pmr::unordered_map<int64_t, Edge>;
[[nodiscard]]
static constexpr int64_t pack_edge(int a, int b) noexcept
{
return (static_cast<int64_t>(a) << 32) | static_cast<uint32_t>(b);
}
[[nodiscard]] [[nodiscard]]
static Heap rebuild_heap(const std::pmr::vector<Face>& faces, auto& memory_resource) static Heap rebuild_heap(const std::pmr::vector<Face>& faces, auto& memory_resource)
{ {
@@ -178,14 +189,16 @@ namespace omath::collision
return f.n.dot(p) - f.d > static_cast<FloatingType>(1e-7); return f.n.dot(p) - f.d > static_cast<FloatingType>(1e-7);
} }
static void add_edge_boundary(std::pmr::vector<Edge>& boundary, int a, int b) static void add_edge_boundary(BoundaryMap& boundary, int a, int b)
{ {
// Keep edges that appear only once; cancel if opposite already present. // O(1) cancel: if the opposite edge (b→a) is already in the map it is an
auto itb = std::ranges::find_if(boundary, [&](const Edge& e) { return e.a == b && e.b == a; }); // internal edge shared by two visible faces and must be removed.
if (itb != boundary.end()) // Otherwise this is a horizon edge and we insert it.
boundary.erase(itb); const int64_t rev = pack_edge(b, a);
if (const auto it = boundary.find(rev); it != boundary.end())
boundary.erase(it);
else else
boundary.emplace_back(a, b); boundary.emplace(pack_edge(a, b), Edge{a, b});
} }
[[nodiscard]] [[nodiscard]]
@@ -266,7 +279,7 @@ namespace omath::collision
best = &f; best = &f;
return best; return best;
} }
static void tombstone_visible_faces(std::pmr::vector<Face>& faces, std::pmr::vector<Edge>& boundary, static void tombstone_visible_faces(std::pmr::vector<Face>& faces, BoundaryMap& boundary,
const VectorType& p) const VectorType& p)
{ {
boundary.clear(); boundary.clear();