Merge pull request #1655 from bilawalsidhu/sameh/route-corridor

fix(flights): a long flight keeps its route up to 15% of its length off the great circle
This commit is contained in:
Sameh Khamis authored and GitHub committed 2026-11-10 11:53:33 -08:00
commit 3da4204e97
4 files changed
+37 -3

No files matched your search

+4
View File
@@ -0,0 +1,4 @@
- A long flight keeps its origin and destination when weather or airways take
it far off the great circle: the route check now allows 200 km or 15% of the
route's length, whichever is larger (623 km for JFK–SFO), while a short hop
still allows 200 km (Sameh Khamis, @samehkhamis, #1655).
+5 -2
View File
@@ -4304,8 +4304,11 @@ down | auth-failed` (plus the unchanged `missing-key`/`unsupported`) with
> advances dead reckoning from the host frame.
> - **Scheduled route plausibility:** Aircraft route labels and selected-route
> context reject the distant backwards, forwards and antipodal extensions of
> an airport pair's great circle. The existing 130 km endpoint admission and
> 200 km cross-track tolerance remain; a projected fix outside the finite
> an airport pair's great circle. The existing 130 km endpoint admission
> remains; the cross-track tolerance is 200 km or 15% of the route's length,
> whichever is larger (JFK–SFO allows 623 km, as airways and winds take a
> coast-to-coast flight several hundred kilometres off the great circle); a
> projected fix outside the finite
> origin-to-destination minor arc also has a generous 200 km extension at
> either end. Missing coordinates and coincident or antipodal endpoint pairs
> retain their loose, unjudgeable behavior; vertical-trend checks are unchanged.
+10 -1
View File
@@ -46,7 +46,13 @@ function alongTrackKm(position, origin, destination) {
}
const NEAR_ENDPOINT_KM = 130;
/** Least allowed distance off the great circle, and how far past either
* endpoint the plane may be along it. */
const CROSS_TRACK_KM = 200;
/** On a long route the allowed distance off the great circle grows to this
* share of its length: airways and winds take a coast-to-coast flight several
* hundred kilometres off it (JFK–SFO: 623 km). */
const CROSS_TRACK_ROUTE_FRACTION = 0.15;
const LOW_ALT_M = 3700; // ~12 000 ft
const VERT_TREND_MPS = 2; // ~400 fpm
const LOCAL_AIRPORT_KM = 150;
@@ -90,6 +96,9 @@ export function routePlausible({
// existing loose check when the segment cannot be judged reliably.
const segmentKnown =
routeKm > 0.001 && routeKm < Math.PI * EARTH_RADIUS_KM - 0.001;
const corridorKm = segmentKnown
? Math.max(CROSS_TRACK_KM, CROSS_TRACK_ROUTE_FRACTION * routeKm)
: CROSS_TRACK_KM;
geomOk =
Math.abs(
crossTrackKm(
@@ -100,7 +109,7 @@ export function routePlausible({
destination.lat,
destination.lon,
),
) < CROSS_TRACK_KM &&
) < corridorKm &&
(!segmentKnown ||
(segmentAlongKm >= -CROSS_TRACK_KM &&
segmentAlongKm <= routeKm + CROSS_TRACK_KM));
+18
View File
@@ -27,6 +27,24 @@ test('plane in London with an SFO→LAX route: implausible', () => {
}), false);
});
test('a long route allows a wider corridor; a short one does not', () => {
// JFK→SFO over Kansas, 384 km south of the great circle.
assert.equal(routePlausible({
latDeg: 38.21, lonDeg: -99.69, altitudeM: 10370, verticalRateMps: 0,
origin: JFK, destination: SFO,
}), true);
// 516 km off the 543 km SFO→LAX route is still the wrong route.
assert.equal(routePlausible({
latDeg: 37.9, lonDeg: -115.0, altitudeM: 10000, verticalRateMps: 0,
origin: SFO, destination: LAX,
}), false);
// 960 km off, past 15 % of the 4,152 km JFK→SFO route, is still wrong.
assert.equal(routePlausible({
latDeg: 33.0, lonDeg: -99.69, altitudeM: 10000, verticalRateMps: 0,
origin: JFK, destination: SFO,
}), false);
});
test('vertical trend: low climbing plane near SFO — origin must be local', () => {
const nearSfo = { latDeg: 37.7, lonDeg: -122.4, altitudeM: 2500 };
// JFK→SFO passes geometry (near destination), but a CLIMBING plane here just