Skip to content

feat(viewer): measure shortest route along the cave#3

Merged
MattNotarangelo merged 4 commits into
mainfrom
feat/route-measure
Jun 11, 2026
Merged

feat(viewer): measure shortest route along the cave#3
MattNotarangelo merged 4 commits into
mainfrom
feat/route-measure

Conversation

@MattNotarangelo

Copy link
Copy Markdown
Owner

Background

  • The measure tool answered "how far as the crow flies?" but cavers usually need "how far through the cave?" — for trip planning, rigging, and rescue pre-plans. This adds that as a natural extension of the existing two-station measure flow.

What Has Changed

  • New pure module src/viewer/route.ts: shortest path between two stations via single-source Dijkstra with predecessor tracking over the non-splay leg graph, early-exiting at the target. ~18 ms on the 22k-station Migovec model.
  • Measure panel gains an "Along cave" row (or "no route" when the stations aren't connected); the route is highlighted in the view as a fat cyan line drawn over the centreline (a thin line was invisible underneath the fat centreline), redrawn on vertical-exaggeration changes and disposed with the measurement.
  • Equate handling (important find): Therion .lox writes an equated station once per survey — different ids/names, identical coordinates, no joining shot. The Migovec example therefore fragments into ~600 centreline pieces, and most routes initially came back "no route". The route graph now treats coordinate-coincident stations (0.1 mm key) as one node, which fuses Migovec into a single 7,725-station connected component. Verified: a pair that previously failed now reports 424.9 m along the cave vs 134.1 m straight line.
  • Tests: 7 cases in test/route.test.ts (chain summing, loop shortest-way with reversed leg orientation, splay exclusion, disconnection, equate connectivity, self-route, bad ids). 71/71 passing.
  • README: measure-tool docs updated.

Note for a follow-up

The same .lox fragmentation affects the distance-from-entrance colour mode (entranceDistances in coloring.ts) — large parts of .lox models colour grey/unreachable today. Deliberately not fixed here to avoid conflicting with #2; worth the same canonicalization in a follow-up.

Screenshots/Video

  • {Leave for author}

Checklist

  • Self-review completed
  • Tests added or updated
  • Tested locally

🤖 Generated with Claude Code

The measure tool now also reports the through-the-cave distance between
the two picked stations and highlights the route in the view as a fat
cyan line. Route finding is single-source Dijkstra with predecessor
tracking over the non-splay leg graph (src/viewer/route.ts, pure and
unit-tested), early-exiting at the target.

Coordinate-coincident stations are treated as one graph node: Therion
.lox writes an equated station once per survey (different ids/names,
same point, no joining shot), so without this the Migovec example
fragments into ~600 centreline pieces and most routes come back "no
route"; with it the whole 47 km system is one connected component.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 11, 2026

Copy link
Copy Markdown

Deploying caveviewer with  Cloudflare Pages  Cloudflare Pages

Latest commit: 77ab47a
Status: ✅  Deploy successful!
Preview URL: https://0da581d2.caveviewer.pages.dev
Branch Preview URL: https://feat-route-measure.caveviewer.pages.dev

View logs

Therion names anonymous splay/wall endpoints "." or "-", but the .lox
parser only treated empty names as anonymous. In the Migovec example
13,858 of 22,154 stations are such wall points: invisible (splays are
hidden by default) yet pickable, so clicks near the centreline often
selected one and the measure tool reported "no route" (they hang off
splay-only legs). They are now anonymous and unlabelled, like anonymous
stations from the other parsers — excluded from picking, search, and
the survey tree. Stations genuinely NAMED with a trailing dot (e.g.
"9." in the golden fixture, where the .3d agrees) stay named.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@MattNotarangelo

Copy link
Copy Markdown
Owner Author

Testing feedback fix: clicks near the centreline often landed on invisible Therion "anonymous" wall points (stations named ./- — 13,858 of them in the Migovec example) which hang off splay-only legs, so the panel said no route. The .lox parser now flags them anonymous (unpickable), matching Therion's naming convention; pickable stations drop to the 8,294 real ones and a 34-pair sweep across the system finds a route every time. Genuinely-named stations with a trailing dot (S1.9. in the golden fixture) stay named. 73/73 tests passing.

entranceDistances now canonicalizes coordinate-coincident stations to a
single graph node, the same treatment route-finding got: Therion .lox
writes an equated station once per survey with no joining shot, so the
distance flood stopped at every survey boundary and 97.7% of the
Migovec example coloured grey (unreachable). Now 8293 of 8294 named
stations are reachable (the one remainder is genuinely isolated);
coincident stations share their canonical node's distance.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@MattNotarangelo

Copy link
Copy Markdown
Owner Author

Second testing-feedback fix: distance-from-entrance colouring suffered the same .lox equate fragmentation as routing — only 2.3% of the Migovec example was reachable from its entrances (the rest coloured grey). entranceDistances now canonicalizes coordinate-coincident stations like findRoute does: 100% reachable (8,293/8,294; the one remainder is genuinely isolated), max 3,267 m from the nearest entrance, 41 ms. This closes the follow-up flagged in the PR description. 74/74 tests passing. Note: this touches coloring.ts, which #2 also modifies in different regions — if a conflict appears when the second one merges, I'll rebase it.

Resolved test/coloring.test.ts import block (main's superset wins);
coloring.ts auto-merged — date mode and the equate-aware
entranceDistances coexist.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@MattNotarangelo MattNotarangelo merged commit 2019af3 into main Jun 11, 2026
2 checks passed
@MattNotarangelo MattNotarangelo deleted the feat/route-measure branch June 11, 2026 22:08
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.

1 participant