Skip to content

Commit b90ccd6

Browse files
authored
Merge pull request #1872 from Creoox/replace-linear-search-in-AddPoint
Replace linear search in SharedPosition::AddPoint with O(1)
2 parents 860d55f + 1c4fdb5 commit b90ccd6

2 files changed

Lines changed: 216 additions & 389 deletions

File tree

src/cpp/web-ifc/geometry/operations/boolean-utils/shared-position.h

Lines changed: 65 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,30 @@
3030
using Vec2 = glm::dvec2;
3131
using Vec3 = glm::dvec3;
3232

33+
34+
// Custom hash for std::tuple<int64_t, int64_t, int64_t>
35+
// Combine the three 64-bit integers in a reasonably collision-resistant way
36+
template<>
37+
struct std::hash<std::tuple<int64_t, int64_t, int64_t>>
38+
{
39+
using argument_type = std::tuple<int64_t, int64_t, int64_t>;
40+
using result_type = std::size_t;
41+
42+
result_type operator()(const argument_type& t) const noexcept
43+
{
44+
auto [x, y, z] = t; // C++17 structured binding (preferred)
45+
46+
// Simple, fast mixing - inspired by boost::hash_combine + murmur-like finalizer
47+
std::size_t seed = 0x517cc1b727220a95ULL; // random 64-bit constant
48+
49+
seed ^= static_cast<std::size_t>(x) + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);
50+
seed ^= static_cast<std::size_t>(y) + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);
51+
seed ^= static_cast<std::size_t>(z) + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);
52+
53+
return seed;
54+
}
55+
};
56+
3357
namespace fuzzybools
3458
{
3559

@@ -680,6 +704,8 @@ namespace fuzzybools
680704
BVH relevantBVHA;
681705
BVH relevantBVHB;
682706

707+
std::unordered_map<std::tuple<int64_t, int64_t, int64_t>, std::vector<size_t>> pointGrid;
708+
683709
//============================================================================================
684710

685711
// assumes all triangleIds are connected to base with an edge and are flipped correctly
@@ -839,23 +865,53 @@ namespace fuzzybools
839865
}
840866

841867
//============================================================================================
842-
843-
size_t AddPoint(const Vec3 &newPoint)
844-
{
845-
for (auto &pt : points)
846-
{
847-
if (pt == newPoint)
848-
{
849-
return pt.id;
868+
size_t AddPoint(const Vec3& newPoint)
869+
{
870+
// 1. Compute the grid cell for the query point
871+
const double cellSize = toleranceVectorEquality; // same tolerance you already use for ==
872+
873+
auto getKey = [&](const Vec3& p) -> std::tuple<int64_t, int64_t, int64_t> {
874+
return {
875+
static_cast<int64_t>(std::floor(p.x / cellSize)),
876+
static_cast<int64_t>(std::floor(p.y / cellSize)),
877+
static_cast<int64_t>(std::floor(p.z / cellSize))
878+
};
879+
};
880+
881+
const auto centerKey = getKey(newPoint);
882+
883+
// 2. Check the point against all 27 neighbouring cells (guaranteed to contain any point
884+
// that is within toleranceVectorEquality because |delta_x|,|delta_y|,|delta_z| < tolerance)
885+
for (int dx = -1; dx <= 1; ++dx) {
886+
for (int dy = -1; dy <= 1; ++dy) {
887+
for (int dz = -1; dz <= 1; ++dz) {
888+
const std::tuple<int64_t, int64_t, int64_t> neighbourKey = {
889+
std::get<0>(centerKey) + dx,
890+
std::get<1>(centerKey) + dy,
891+
std::get<2>(centerKey) + dz
892+
};
893+
894+
auto it = pointGrid.find(neighbourKey);
895+
if (it != pointGrid.end()) {
896+
for (size_t existingId : it->second) {
897+
if (points[existingId] == newPoint) { // re-uses your existing tolerance check
898+
return existingId;
899+
}
900+
}
901+
}
902+
}
850903
}
851904
}
852905

906+
// 3. Point does not exist -> insert it
853907
Point p;
854908
p.id = points.size();
855909
p.location3D = newPoint;
856-
857910
points.push_back(p);
858911

912+
// Insert into spatial grid (same cell as the point itself)
913+
pointGrid[getKey(newPoint)].push_back(p.id);
914+
859915
return p.id;
860916
}
861917

0 commit comments

Comments
 (0)