Skip to content

Fix locate_navcel on multi-surface maps and speed up queries - #29

Merged
fmrico merged 1 commit into
rollingfrom
fix_locate_multisurface
Oct 14, 2026
Merged

fmrico merged 1 commit into
rollingfrom
fix_locate_multisurface

Conversation

@fmrico

@fmrico fmrico commented Oct 14, 2026

Copy link
Copy Markdown
Contributor

Fixes #28

locate_navcel could return the wrong floor, and with a hint it was much slower than without one. Covering the fix with randomized tests turned up four more problems in the same code path; the list is in the issue comment.

Changes in navmap_core

  • Closest surface in z. The vertical rays keep the closest hit over all surfaces, not the first surface in the list that is hit.
  • Point exactly on a surface. The rays start 1 mm past p, so a point exactly on a surface (a robot at z=0, for example) finds that surface.
  • O(1) owning surface. A NavCel -> surface index, built in rebuild_geometry_accels() and kept on copy, assign and move, replaces three linear std::find lookups. New public surface_of(cid) and kNoSurface. If the index is stale, it falls back to the linear search.
  • Hint walk.
    • It steps across the correct edge (neighbor[(i+1)%3]).
    • It re-checks height_eps on the cell where it ends.
    • The hint and search paths both project the point vertically.
  • Faster queries.
    • The closest-hit raycast visits surfaces in order of their AABB entry and stops once no surface can beat the best t.
    • The upward ray in locate is bounded by the downward hit.
    • BVH traversals use a fixed stack instead of a std::stack per query.
    • closest_navcel visits the nearer child first.

Tests

  • test_navmap_properties: random multi-surface maps, with sloped and bumpy patches overlapping in XY and interleaved NavCel ids. It checks locate_navcel (with and without hints), raycast, raycast_many and closest_navcel against brute-force references, and checks adjacency symmetry. It also has robustness cases: NaN/inf queries, empty map and empty surfaces, degenerate triangles, points on vertices and edges, every cell as a hint, a cell in two surfaces, and repeated rebuilds.
  • test_locate_multisurface: floors in normal and reversed order, points on, between, above and below floors, valid and invalid hints, hints on another floor, the hint walk, surface_of after copy, assign and move or with a stale index, and set_area / sample_layer_at on the right floor. The regression tests fail without the fix.
  • Sanitizers: all navmap_core tests also pass under ASan/UBSan.
  • Downstream packages: the tests of navmap_ros, navmap_examples and the EasyNav NavMap maps manager, planner and localizer pass unchanged.

Benchmark

Optional navmap_bench (-DNAVMAP_BUILD_BENCH=ON, off by default). 5 cm cells, before vs after:

Query Before After
locate with hint, 180k cells 2.8 us, grows with N 0.07 us, constant
closest_navcel, 180k / 540k cells 72 / 106 us 1.5 / 3.3 us
locate without hint, 3 floors, 540k cells 2.4 us, wrong floor 1.7 us

A deep copy costs about 10% more because it now copies the surface index.

locate_navcel now returns the surface closest in z, whatever the order of
the surfaces, also when the point lies exactly on a surface. A NavCel ->
surface index replaces the linear owner lookups, the hint walk steps
across the right edge and re-checks height_eps where it ends, and both the
hint and the search paths project the point vertically.

The closest-hit raycast visits surfaces by AABB entry and prunes by the
best t, BVH traversals use a fixed stack, and closest_navcel visits the
nearer child first.

Adds randomized tests against brute-force references, robustness tests,
multi-floor tests, and an optional micro-benchmark (NAVMAP_BUILD_BENCH).

Fixes #28

Signed-off-by: Francisco Martín Rico <fmrico@gmail.com>
@fmrico
fmrico merged commit bffcf66 into rolling Oct 14, 2026
1 check passed
@fmrico
fmrico deleted the fix_locate_multisurface branch October 14, 2026 10:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

locate_navcel picks the wrong surface in multi-surface maps and is slow with a hint

1 participant