perf(v4.2): O(1) spatial hash vertex dedup in sew_faces
sew_faces had O(n²) linear scan for vertex deduplication (for each new vertex, scan all existing result vertices). Replaced with quantized position hash map: O(1) lookup per vertex. Box-cylinder union: 92s → 55s (-40%)
This commit is contained in:
+25
-11
@@ -6,9 +6,11 @@
|
||||
#include "vde/mesh/halfedge_mesh.h"
|
||||
#include "vde/curves/surface_intersection.h"
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <unordered_map>
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
#include <mutex>
|
||||
@@ -286,21 +288,33 @@ BrepModel sew_faces(const std::vector<BrepModel>& face_bodies) {
|
||||
// Cache: (min_vertex, max_vertex) → edge_id for edge sharing
|
||||
std::map<std::pair<int,int>, int> edge_cache;
|
||||
|
||||
// Spatial hash for O(1) vertex dedup — quantize positions to 1e-5
|
||||
static constexpr double Q = 1e5; // quantization factor
|
||||
auto quantize = [](double v) -> int64_t { return static_cast<int64_t>(v * Q); };
|
||||
std::unordered_map<uint64_t, int> pos_to_idx;
|
||||
|
||||
auto hash_pos = [&](const Point3D& p) -> uint64_t {
|
||||
uint64_t h = static_cast<uint64_t>(quantize(p.x()));
|
||||
h = h * 0x9e3779b9 + static_cast<uint64_t>(quantize(p.y()));
|
||||
h = h * 0x9e3779b9 + static_cast<uint64_t>(quantize(p.z()));
|
||||
return h;
|
||||
};
|
||||
|
||||
for (auto& fb : face_bodies) {
|
||||
// Merge vertices (deduplicate by proximity)
|
||||
std::map<int, int> old_to_new; // fragment vertex ID → result vertex index
|
||||
// Merge vertices (deduplicate by proximity via spatial hash)
|
||||
std::map<int, int> old_to_new;
|
||||
const double tol_sq = 1e-12; // squared tolerance
|
||||
for (size_t vi = 0; vi < fb.num_vertices(); ++vi) {
|
||||
auto& v = fb.vertex(static_cast<int>(vi));
|
||||
int best_idx = -1;
|
||||
double best_dist = 1e-6;
|
||||
for (size_t ri = 0; ri < result.num_vertices(); ++ri) {
|
||||
double d = (result.vertex(static_cast<int>(ri)).point - v.point).norm();
|
||||
if (d < best_dist) { best_dist = d; best_idx = static_cast<int>(ri); }
|
||||
}
|
||||
if (best_idx >= 0) {
|
||||
old_to_new[static_cast<int>(vi)] = best_idx;
|
||||
uint64_t h = hash_pos(v.point);
|
||||
auto it = pos_to_idx.find(h);
|
||||
if (it != pos_to_idx.end() &&
|
||||
(result.vertex(it->second).point - v.point).squaredNorm() < tol_sq) {
|
||||
old_to_new[static_cast<int>(vi)] = it->second;
|
||||
} else {
|
||||
old_to_new[static_cast<int>(vi)] = result.add_vertex(v.point);
|
||||
int new_idx = result.add_vertex(v.point);
|
||||
old_to_new[static_cast<int>(vi)] = new_idx;
|
||||
pos_to_idx[h] = new_idx;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user