Wall Detection
"/home/yossef/notes/git/projects/maplibra/flows/Wall Detection.md"
path: maplibra/flows/Wall Detection.md
- **fileName**: Wall Detection
- **Created on**: 2026-06-16 00:48:42
Wall Detection
Purpose: How the system determines if a path segment crosses walls or obstacles.
Related: ../Home.md, ../Architecture.md, ../modules/Route Smoothing.md, ../decisions/Sampling vs Intersection.md
Three Layers of Wall Detection
1. Offline Graph Build (scripts/build-routing-graph.js)
During graph construction, candidate edges are rejected if any sampled point lands inside a buffered obstacle:
- Sample step:
edgeStepMeters(capped at 0.4m after fix, was ~0.83m) - Checks:
isPointBlocked()→ nonwalkable buffer OR obstacle buffer (wall/object) - Exception: wall buffer check skipped if point is near a door (
isNearDoor)
2. Runtime JS (src/pathfinding/walkable-areas.js)
During smoothing, shortcut segments are validated:
- Sample step:
Math.min(smoothSampleDistance, 0.2)meters (was 0.5m before fix) - Two checks per sample point:
isPointWalkable(coords, floorId)— must be inside a walkable polygonisPointBlockedSmooth(coords, floorId)— must NOT be inside a blocker buffer
3. WASM Kernel (native/routing/route_smoothing.c)
C equivalent for performance-critical paths:
routing_is_segment_walkable(startLng, startLat, endLng, endLat, floorIndex, sampleCount)- Sample count: computed by bridge as
ceil(distance / 0.5) + 2, min 4 (was 2 before fix) - Each sample checks: inside walkable polygon? If not → blocked. Inside blocker polygon? → blocked.
The Fundamental Approach: Point Sampling
All three layers use the SAME technique: sample discrete points along a segment and check each one.
This is NOT geometric line-polygon intersection. It has a known weakness:
If a wall is thinner than the sample step, it can slip between sample points undetected.
See ../decisions/Sampling vs Intersection.md for why this was chosen and what the tradeoffs are.
Blocker Buffer Sizes
| Kind | Buffer Distance | Applied When |
|---|---|---|
| Wall | 0.6m | kinds/{floor}.json has "wall" |
| Object | 0.4m | kinds/{floor}.json has "object" |
| Nonwalkable | 0.4m | Listed in nonwalkable/{floor}.json |
| Inaccessible | 0.4m (merged into nonwalkable) | Style anchors in InaccessibleRooms etc. |
Flow Diagram
isSegmentWalkable(start, end, floorId)
│
├── compute sampleStep = min(smoothSampleDistance, 0.2)
├── steps = max(2, ceil(distance / sampleStep))
│
└── for i = 0 to steps:
t = i / steps
coords = lerp(start, end, t)
│
├── isPointWalkable(coords, floorId)?
│ └── booleanPointInPolygon vs walkable polygons
│
└── isPointBlockedSmooth(coords, floorId)?
└── booleanPointInPolygon vs buffered blockers
Important Files
-
src/pathfinding/walkable-areas.js:152-183— JS segment check -
native/routing/route_smoothing.c:153-173— C segment check -
src/pathfinding/route-smoothing.js:373-401— Blocker point check -
scripts/build-routing-graph.js:440-455— Offline edge blockingcontinue:[[]]
before:[[]]