Skip to content

fix(map): draw transit routes along real roads, not straight lines - #802

Draft
smmariquit wants to merge 1 commit into
stagingfrom
fix/transit-route-geometry
Draft

fix(map): draw transit routes along real roads, not straight lines#802
smmariquit wants to merge 1 commit into
stagingfrom
fix/transit-route-geometry

Conversation

@smmariquit

Copy link
Copy Markdown
Collaborator

Problem

Seven of the nine transit routes had no entry in src/constants/jeepney-geometries.json, so Map.svelte fell back to deriveRouteLineFromStops and connected their raw stop coordinates. With 4–6 stops over 60–75 km, that drew straight lines across Laguna de Bay, Mt. Makiling and private land. Only kaliwa-kanan and forestry had real geometry.

Where the geometry came from

Route Source Detail
uplb-to-upd osm-relation Relation 17932247, DLTB, mapped end to end
upd-to-uplb osm-relation Relation 17932246
lb-to-sta-cruz osm-relation Relation 2582682 (PUJ Calamba → Santa Cruz), trimmed to the Los Baños leg
lb-to-san-pablo osm-relation Relation 1856207 (PUJ Calamba → San Pablo), trimmed
lb-to-calamba osm-relation Relation 1856209 reversed — the return relation 1856216 is tagged disused:
lb-to-buendia, buendia-to-lb routed OSRM; no relation covers this service in either direction
kaliwa-kanan, forestry routed (unchanged) Left exactly as-is

Why the campus loops were not switched to OSM. Relations 337589 / 337590 (Kaliwa / Kanan) exist and are gap-free, but they stop at the campus boundary. Our route includes the Olivarez Plaza and Robinsons town leg, so adopting them would have removed a correct part of the one route that already worked. Forestry relations 1954831 / 1954832 carry a disused: prefix and 2020 data.

Honesty over coverage

resolveRouteGeometry returns the source alongside the line, and it drives the UI:

  • osm-relation — solid line, no caveat, unless the route carries a specific one.
  • routed — solid line plus a note that it is road-routed between stops rather than traced from the operator's published route.
  • stops-only — dashed, faded, and labelled "the exact path of this route is not mapped yet". No route ships in this state today; it is the safety net for any route added without geometry, and it replaces today's confident straight line.

Three routes are sourced but still qualified, and say so in the route modal:

  • the DLTB pair: OSM maps it via SLEX/C-5/Katipunan while UPLB's own announcements describe Skyway and Quezon Ave. We cannot settle it, so the line ships as mapped and the disagreement is disclosed.
  • lb-to-calamba: the line is the mapped return trip drawn backwards.
  • the two trimmed corridors: cut at our own end points, so the ends are approximate.

The generator also refuses a relation whose stitched line misses either terminal by more than 1.5 km, and asserts the mapped direction matches what the config claims — so a bad pairing fails loudly instead of shipping as a nicer-looking wrong line.

Where it lives, and why not a column

Still the JSON keyed by route id. The geometry is generated from OSM, not editor-maintained, so a jeepney_routes.geometry column would have cost a migration, a PGlite regeneration and sync changes to buy nothing. No migration in this PR; nothing to hand-apply to prod.

scripts/generate-transit-geometry.ts replaces the stale root fetch-routes.ts (which only knew the two bundled constants routes). It reads stops read-only, caches every upstream response under data/transit-geometry-cache/ and serialises requests, so re-runs cost upstream nothing.

Lines are simplified with Ramer-Douglas-Peucker at 3 m — narrower than a lane — which takes the bundled file from 466 KB to 44 KB. The file is excluded from Biome formatting because pretty-printing coordinate pairs quadrupled it.

Data bugs found, not fixed here

Read-only pass over prod; no database writes. Three stop coordinates are wrong and now visibly so:

  • Pansol / Bagong Kalsada (14.1542, 121.1979) is ~2 km off the highway, up the Makiling foothills, on three routes. The routed lb-to-buendia line visibly detours to reach it.
  • Alaminos on lb-to-san-pablo is 7 km off-corridor; the real jeepney runs Bay → Calauan → San Pablo.
  • Victoria on lb-to-sta-cruz sits 2.9 km off the mapped corridor.
  • Separately, forestry's CPAf stop has sort_order 9 while sitting geographically mid-route, so the stop list is misnumbered.

Worth a follow-up data pass; deliberately out of scope here.

Verify

  • bun run test (439 pass), bunx vitest run (155 pass), bunx biome check clean on touched files, bun run build green.
  • New unit tests cover geometry selection, the caveat override, the empty-line guard, the too-few-stops case, and a data test asserting every entry has a source, provenance note and a drawable lon/lat-ordered line.
  • Rendered all nine routes against prod data from dist/server/entry.mjs and inspected each. Campus loops confirmed unchanged.

Notes for review

Draft, and deliberately no run/e2e — the serial CI queue is running and concurrent e2e runs exhaust the shared pooler.

Seven of the nine transit routes had no entry in jeepney-geometries.json,
so Map.svelte fell back to deriveRouteLineFromStops and joined their raw
stop coordinates. On the intercity services that meant 4-to-6-point straight
lines running across Laguna de Bay and open country.

Geometry now comes from OSM route relations where one maps the service, and
from OSRM road routing otherwise:

- uplb-to-upd / upd-to-uplb: relations 17932247 / 17932246 (DLTB, end to end)
- lb-to-sta-cruz / lb-to-san-pablo: relations 2582682 / 1856207, the mapped
  Calamba-origin corridors trimmed to the Los Banos leg
- lb-to-calamba: relation 1856209 reversed; the return relation 1856216 is
  tagged disused
- lb-to-buendia / buendia-to-lb: routed, no relation covers these
- kaliwa-kanan / forestry: untouched. The campus relations 337589/337590 stop
  at the campus boundary and would drop the Olivarez Plaza town leg

Provenance ships with each line. A routed line says so in the route modal, and
a route with no geometry at all now draws dashed and faded with an explicit
"not mapped" note instead of a confident straight line. Sourced-but-qualified
lines (reversed relation, trimmed corridor, and the SLEX/C-5 vs Skyway
disagreement on the DLTB bus) carry their own caveat.

Geometry stays in the JSON keyed by route id rather than moving to a column:
it is generated from OSM, not editor-maintained, so a migration would buy
nothing. Lines are simplified to 3 m and written one route per line, which
keeps the bundled file at 44 KB.
@vercel

vercel Bot commented Jul 26, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
saan-ang-room Ready Ready Preview, Comment Jul 26, 2026 6:34pm

Request Review

await sleep(1500);
const body = await run();
const parsed = JSON.parse(body);
writeFileSync(path, body);
await sleep(1500);
const body = await run();
const parsed = JSON.parse(body);
writeFileSync(path, body);
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