Add PointCloudHashGrid: uniform-grid counterpart to PointCloudBVH#108
Draft
rmrsk wants to merge 3 commits into
Draft
Add PointCloudHashGrid: uniform-grid counterpart to PointCloudBVH#108rmrsk wants to merge 3 commits into
rmrsk wants to merge 3 commits into
Conversation
rmrsk
added a commit
that referenced
this pull request
Jul 11, 2026
Dev/ held the four superseded point-cloud examples (replaced by ClosestPointBVH/NearestNeighborBVH on this branch) and the GridNN prototype (promoted to the PointCloudHashGrid class, PR #108). It was always marked DELETE_BEFORE_MERGE; removing it now, along with the temporary Dev/** annotation block in REUSE.toml. reuse lint stays compliant. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HS5LFQihKoMrE6nbPaQW9R
…issue #107) PointCloudHashGrid answers the same nearest-neighbor / closest-point queries over a particle cloud as PointCloudBVH and exposes the same public interface (same Hit, same closestPoint/closestPoints/nearestNeighbor/nearestNeighbors/allNearestNeighbors, same O(N) brute-force references and position()/metadata() accessors), so the two are drop-in interchangeable -- but it circumvents the tree entirely. Points are counting-sorted into a dense CSR bucket array keyed by integer cell coordinates (an O(N) build, no tree). Queries are an expanding-shell search from the query point's cell with an exact stopping rule -- after searching Chebyshev radius R the world region within the covered faces is fully searched, so once the k-th best distance is inside that bound no neighbor can be missed. Handles external queries and queries outside the grid box (clamped cell). k>1 carries a sorted k-best set through the shells. For a near-uniform 500k cloud this builds ~5x faster and queries ~2x faster than PointCloudBVH (Examples/NearestNeighborHashGrid: build ~16 ms, query ~0.29 us/pt vs the BVH's ~76 ms / ~0.55). The class docs and ImplemBVH.rst spell out the trade-off: a global cell size only suits near-uniform density, the dense grid is bounded-domain (O(bboxVol/h^3) cells), and it is not a BVH (no composition into an outer BVH/CSG) -- prefer PointCloudBVH for clustered clouds, external-heavy workloads, and composition. Adds the class (header + implem), EBGeometry.hpp include, InstantiateAll coverage, TestPointCloudHashGrid (independent brute-force oracle, both precisions, incl. the outside-the-box case), the NearestNeighborHashGrid example, and docs. Follow-up to PointCloudBVH; the Dev/GridNN prototype this grew out of is superseded. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HS5LFQihKoMrE6nbPaQW9R
Match the terse, intrinsic style of the sibling example READMEs: drop the speedup-extrapolation and the detailed grid-vs-tree performance breakdown, keeping the functional description, the brief intrinsic guidance on when the grid vs the BVH fits, and the brute-force correctness check. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HS5LFQihKoMrE6nbPaQW9R
a1f0b7b to
2309355
Compare
Both TestPointCloudBVH.cpp and TestPointCloudHashGrid.cpp declared the comparison margin as `const T tol = tightMargin<T>()`, but tightMargin<T>() returns double and withinAbsT()'s margin parameter is double -- so with T=float every withinAbsT(target, tol) promoted tol float->double at the call site, which clang's -Wdouble-promotion flags under -Werror (the Sanitizers CI job, EBGEOMETRY_TEST_BOTH_PRECISIONS). Declare tol as double in both. Verified: both build clean under clang++-18 with both precisions and -Wdouble-promotion -Werror, and still pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HS5LFQihKoMrE6nbPaQW9R
Open
8 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #107
Background
PointCloudBVH(on theparticle_soa_pr3branch, PR #106) gives turnkey nearest-neighbor /closest-point queries over a particle cloud, backed by a BVH. While finishing that work we prototyped
a uniform spatial grid as an alternative that circumvents the tree entirely, and found it clearly
faster on near-uniform clouds (~7× build, ~1.4× query). Issue #107 proposed promoting that prototype
into a first-class class mirroring
PointCloudBVH. This PR does so.Stacked on top of #106 (base branch
particle_soa_pr3), since it mirrorsPointCloudBVHand the newexample/docs reference it.
Solution
Adds
PointCloudHashGrid<T, Meta>, which answers the same queries asPointCloudBVHand exposesthe same public interface — same
Hit, sameclosestPoint/closestPoints/nearestNeighbor/
nearestNeighbors/allNearestNeighbors, sameO(N)brute-force reference queries, sameposition()/metadata()/numParticles()accessors — so the two are drop-in interchangeable.coordinates (
O(N), no tree). Cell size is derived from a target average occupancy (~1particle/cell by default).
rule — after searching Chebyshev radius
R, the world region within the covered cell faces is fullysearched, so once the k-th best distance is inside that bound no neighbor can be missed. Handles
external queries and queries outside the grid box (clamped cell);
k > 1carries a sorted k-bestset through the shells.
On a near-uniform 500k cloud the grid builds ~5× faster and queries ~2× faster than
PointCloudBVH(
Examples/NearestNeighborHashGrid: build ~16 ms, query ~0.29 µs/pt, vs the BVH's ~76 ms / ~0.55).Also included:
EBGeometry.hppinclude,Tests/InstantiateAll.cppcoverage,TestPointCloudHashGrid(checked against an independent brute-force oracle in both precisions, including the outside-the-box
case), the
Examples/NearestNeighborHashGridexample, and documentation (aPointCloudHashGridsection in
ImplemBVH.rstand full doxygen).The two point-cloud examples were also renamed for clarity now that there are two backing structures:
ClosestPoint→ClosestPointBVH,NearestNeighbor→NearestNeighborBVH(that rename is part ofthe base
particle_soa_pr3branch).Side-effects
PointCloudBVHit cannot be composed as a primitive inside anouter BVH/CSG union. It serves only point queries.
O(bboxVolume / h³)memory — fine for a compact cloud, wasteful for one sparse but spread over a large box.
clouds. For clustered / multi-scale clouds
PointCloudBVH's density adaptivity is the better choice— documented in the class comments,
ImplemBVH.rst, and the example README so callers can pick.Alternative solutions
PointCloudBVHandPointCloudHashGridso callers canselect a structure polymorphically. Deferred — the two share an interface by convention here; a
formal shared interface is a separate refactor (noted in Add a PointCloudHashGrid class: uniform-grid counterpart to PointCloudBVH for nearest-neighbor queries #107).
unordered_map<cellId, bucket>) instead of a dense array, to bound memoryto
O(N)on unbounded/sparse domains. Deferred; the dense grid is the fast bounded-domain case andthe natural first cut. Same query logic would apply.
k-best path is already fast for k=1.