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/mesh/halfedge_mesh.h"
|
||||||
#include "vde/curves/surface_intersection.h"
|
#include "vde/curves/surface_intersection.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <cstdint>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <unordered_map>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <mutex>
|
#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
|
// Cache: (min_vertex, max_vertex) → edge_id for edge sharing
|
||||||
std::map<std::pair<int,int>, int> edge_cache;
|
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) {
|
for (auto& fb : face_bodies) {
|
||||||
// Merge vertices (deduplicate by proximity)
|
// Merge vertices (deduplicate by proximity via spatial hash)
|
||||||
std::map<int, int> old_to_new; // fragment vertex ID → result vertex index
|
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) {
|
for (size_t vi = 0; vi < fb.num_vertices(); ++vi) {
|
||||||
auto& v = fb.vertex(static_cast<int>(vi));
|
auto& v = fb.vertex(static_cast<int>(vi));
|
||||||
int best_idx = -1;
|
uint64_t h = hash_pos(v.point);
|
||||||
double best_dist = 1e-6;
|
auto it = pos_to_idx.find(h);
|
||||||
for (size_t ri = 0; ri < result.num_vertices(); ++ri) {
|
if (it != pos_to_idx.end() &&
|
||||||
double d = (result.vertex(static_cast<int>(ri)).point - v.point).norm();
|
(result.vertex(it->second).point - v.point).squaredNorm() < tol_sq) {
|
||||||
if (d < best_dist) { best_dist = d; best_idx = static_cast<int>(ri); }
|
old_to_new[static_cast<int>(vi)] = it->second;
|
||||||
}
|
|
||||||
if (best_idx >= 0) {
|
|
||||||
old_to_new[static_cast<int>(vi)] = best_idx;
|
|
||||||
} else {
|
} 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