Follow-up to ISS-120's known limitation: a plane mid-crossing used the snapshot's wrapped lat/lon, so its marker jumped +179.x → −179.x between polls (a 360° teleport) while its route line stayed continuous. planesGeoJson now takes the airport index and unwraps each flying plane's longitude against its departure airport — the same anchor greatCircleArc keeps for its first sample — via a new module-private unwrapLon shared with unwrapLons. The unwrap applies only when both leg endpoints exist, mirroring routesGeoJson's guard: a marker is unwrapped iff its line is drawn. Grounded planes and non-crossing legs are byte-identical to before.
Tests: unit +6 in lib/mapData.test.ts (incl. the key invariant — every arc sample fed back as a wrapped snapshot position comes out exactly on that arc's own sample); e2e +1 in e2e/map-interactions.spec.ts (chain-relocate the starter to NZAA, fly the hook-created NZAA→NFTF crossing at scale 1000, sample marker lons from the planes source — no consecutive pair may differ by ≥ 180°, some sample must sit on the east world copy).
Closes #124
Follow-up to ISS-120's known limitation: a plane mid-crossing used the snapshot's wrapped lat/lon, so its marker jumped +179.x → −179.x between polls (a 360° teleport) while its route line stayed continuous. `planesGeoJson` now takes the airport index and unwraps each flying plane's longitude against its departure airport — the same anchor `greatCircleArc` keeps for its first sample — via a new module-private `unwrapLon` shared with `unwrapLons`. The unwrap applies only when both leg endpoints exist, mirroring `routesGeoJson`'s guard: a marker is unwrapped iff its line is drawn. Grounded planes and non-crossing legs are byte-identical to before.
Tests: unit +6 in `lib/mapData.test.ts` (incl. the key invariant — every arc sample fed back as a wrapped snapshot position comes out exactly on that arc's own sample); e2e +1 in `e2e/map-interactions.spec.ts` (chain-relocate the starter to NZAA, fly the hook-created NZAA→NFTF crossing at scale 1000, sample marker lons from the planes source — no consecutive pair may differ by ≥ 180°, some sample must sit on the east world copy).
planesGeoJson now takes the airport index and unwraps each flying plane's
longitude against its departure airport (unwrapLon, shared with unwrapLons),
mirroring routesGeoJson's both-endpoints guard so a marker is unwrapped iff
its line is drawn. Map.tsx passes airportsIndexRef at both call sites.
Unit +6 in lib/mapData.test.ts; e2e +1 in e2e/map-interactions.spec.ts
(chain-relocate to NZAA, fly the NZAA→NFTF crossing, sample marker lons).
kamilkrzywda
scheduled this pull request to auto merge when all checks succeed 2026-09-22 23:36:30 +02:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Closes #124
Follow-up to ISS-120's known limitation: a plane mid-crossing used the snapshot's wrapped lat/lon, so its marker jumped +179.x → −179.x between polls (a 360° teleport) while its route line stayed continuous.
planesGeoJsonnow takes the airport index and unwraps each flying plane's longitude against its departure airport — the same anchorgreatCircleArckeeps for its first sample — via a new module-privateunwrapLonshared withunwrapLons. The unwrap applies only when both leg endpoints exist, mirroringroutesGeoJson's guard: a marker is unwrapped iff its line is drawn. Grounded planes and non-crossing legs are byte-identical to before.Tests: unit +6 in
lib/mapData.test.ts(incl. the key invariant — every arc sample fed back as a wrapped snapshot position comes out exactly on that arc's own sample); e2e +1 ine2e/map-interactions.spec.ts(chain-relocate the starter to NZAA, fly the hook-created NZAA→NFTF crossing at scale 1000, sample marker lons from the planes source — no consecutive pair may differ by ≥ 180°, some sample must sit on the east world copy).