Skip to content

fix(engine): the visibility graph dropped every edge running along a wall - #7691

Merged
DennisOSRM merged 2 commits into
masterfrom
fix-area-visibility-walls
Aug 14, 2026
Merged

fix(engine): the visibility graph dropped every edge running along a wall#7691
DennisOSRM merged 2 commits into
masterfrom
fix-area-visibility-walls

Conversation

@DennisOSRM

Copy link
Copy Markdown
Collaborator

The defect

visible_vertices() decides whether a candidate segment runs through the interior by
testing its midpoint with inside_area(), which is strict about the boundary. Ray casting
on a point lying exactly on an edge answers arbitrarily, and the midpoint of two adjacent
ring vertices is always on the ring between them, so the commonest pair there is was read
as leaving the area.

The walls were therefore missing from the graph, and a planner with no edge along a wall
cannot route past an obstacle, only around it.

What it cost

Measured over a random corpus of plazas:

  • 1096 of 9114 clear vertex pairs were absent from the graph.
  • One portal to portal path came out 2.65 times the straight line, bending at two plaza
    corners, where the correct path is 1.28 times and hugs the obstacle.

This affects the geodesic and area snapping at query time.

The extractor is not affected

VisibilityGraph::visible_vertices in the extractor is a rotational sweep, a different
algorithm with no midpoint test. It omits ring edges deliberately and AreaMesher puts
them back with with_ring_edges(), so the stored mesh has its walls.

Tests

Every existing test in area_visibility.cpp asks from a point in the interior. The callers
ask from vertices, which is where the defect lives, so two new tests ask along a wall.

The third is the property the suite was missing. The existing tests say that no reported
line crosses an obstacle, which bounds the graph from one side only and is satisfied by an
oracle that reports nothing at all. The converse, that every clear line is reported, is what
finds a missing edge. Its clearance oracle uses orientation predicates that share no code
with intersect(), because an oracle built on the code under test agrees with it whatever
it says.

All three fail on master and pass here.

Cost

The geodesic gets slower, by about 24% on area-geodesic-bench: at 104 vertices, 6485 us
to 8043 us for graph plus Dijkstra, and 40 vertices goes from 567 us to 700 us, still
inside the roughly 1 ms budget. GEODESIC_MAX_VERTICES is unchanged.

That is the cost of doing work that was being skipped rather than an inefficiency in the
fix. Wall-adjacent pairs used to be rejected by the midpoint test before the crossing test
ran on them at all, and there are now 12% more edges for the search to relax.

One existing assertion changed

geodesic_threads_a_one_metre_gap required the path to be at least half as long again as
the 600 m straight line. That was the length the solver produced when it could not turn at
the two corners of the wall's western face in succession and had to leave by a longer
route: 894 m, where the true geodesic is 630 m. The number was measured from the behaviour
rather than derived, so it held the defect in place.

It now names the two corners the path has to turn at, which is what threading the gap
means.

🤖 Claude Code, Claude Opus 5

…wall

visible_vertices() decides whether a candidate segment runs through the
interior by testing its midpoint with inside_area(), which is strict about
the boundary. Ray casting on a point lying exactly on an edge answers
arbitrarily, and the midpoint of two adjacent ring vertices is always on the
ring between them, so the commonest pair there is was read as leaving the
area.

The walls were therefore missing from the graph, and a planner with no edge
along a wall cannot route past an obstacle, only around it. On a random
corpus of plazas, 1096 of 9114 clear vertex pairs were absent and one portal
to portal path came out 2.65 times the straight line, bending at two plaza
corners, where the correct path is 1.28 times and hugs the obstacle. This
affects the geodesic and area snapping at query time.

The midpoint test now accepts a point on the boundary.

The extractor's own visibility sweep is a different algorithm and does not
share the defect: it omits ring edges deliberately and AreaMesher puts them
back with with_ring_edges(), so the stored mesh has its walls.

Adds the tests that would have caught it. Every existing test asked from a
point in the interior, and the callers ask from vertices. Two now ask along
a wall, and one checks the converse property the suite was missing: the
tests here said no reported line crosses an obstacle, which bounds the graph
from one side only and is satisfied by an oracle that reports nothing at
all. Its clearance oracle uses orientation predicates that share no code
with intersect(), since an oracle built on the code under test agrees with
it whatever it says.

Also corrects geodesic_threads_a_one_metre_gap, whose assertion encoded the
defect. It required the path to be at least half as long again as the
straight line, which is what the solver produced when it could not turn at
the two corners of the wall's western face in succession and had to leave by
a longer route: 894 m where the true geodesic is 630 m. The number was
measured from the behaviour rather than derived. It now names the two
corners the path has to turn at, which is what threading the gap means.
Copilot AI lite review requested due to automatic review settings August 14, 2026 10:37

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a correctness bug in the engine-side area visibility graph where edges that run exactly along polygon boundaries (“walls”) could be incorrectly dropped due to strict midpoint containment checks, which in turn caused geodesic routing to take unnecessarily long detours.

Changes:

  • Treat midpoints that lie on any ring boundary as valid (not “outside”) when determining segment visibility in visible_vertices().
  • Add targeted unit tests for wall-adjacent visibility and a stronger “completeness” property test to catch missing clear edges.
  • Update one geodesic unit test assertion to validate the intended corner-turning behavior rather than relying on a length bound that encoded the old defect.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
src/engine/area_visibility.cpp Adjusts visibility blocking logic to tolerate boundary midpoints by detecting “on ring” cases with a small tolerance.
unit_tests/engine/area_visibility.cpp Adds new regression/property tests covering vertex-on-wall visibility and completeness of reported clear lines.
unit_tests/engine/area_geodesic.cpp Replaces a defect-preserving path-length assertion with checks that the path turns at the expected wall corners and remains near-optimal.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread unit_tests/engine/area_visibility.cpp
@codecov

codecov Bot commented Aug 14, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.83%. Comparing base (11191ca) to head (b537e21).

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #7691      +/-   ##
==========================================
- Coverage   94.73%   91.83%   -2.91%     
==========================================
  Files         519      519              
  Lines       41435    41534      +99     
==========================================
- Hits        39252    38141    -1111     
- Misses       2183     3393    +1210     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@DennisOSRM
DennisOSRM merged commit 551f3f0 into master Aug 14, 2026
42 of 43 checks passed
@DennisOSRM
DennisOSRM deleted the fix-area-visibility-walls branch August 14, 2026 16:13
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.

2 participants