mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 18:34:02 +00:00
175 lines
6.0 KiB
JavaScript
175 lines
6.0 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import test from 'node:test';
|
|
import * as Cesium from 'cesium';
|
|
import { routePlausible } from './routePlausible.js';
|
|
import { createTracking } from '../layers/flights/tracking.js';
|
|
|
|
const SFO = { lat: 37.6188, lon: -122.3754, code: 'SFO' };
|
|
const LAX = { lat: 33.9416, lon: -118.4085, code: 'LAX' };
|
|
const beyond = { lat: -35.818227816411174, lon: -66.16647396367095 };
|
|
const behind = { lat: 35.818227816411174, lon: 113.83352603632906 };
|
|
const antipode = { lat: -SFO.lat, lon: SFO.lon + 180 };
|
|
const midpoint = { lat: 35.8, lon: -120.4 };
|
|
|
|
const plausible = (position, origin = SFO, destination = LAX) =>
|
|
routePlausible({
|
|
latDeg: position.lat,
|
|
lonDeg: position.lon,
|
|
altitudeM: 10000,
|
|
verticalRateMps: 0,
|
|
origin,
|
|
destination,
|
|
});
|
|
|
|
// Independent spherical oracle: native unit-vector angular distances, without
|
|
// the production bearing/cross-track/along-track calculations.
|
|
const unit = ({ lat, lon }) => {
|
|
const latitude = Cesium.Math.toRadians(lat);
|
|
const longitude = Cesium.Math.toRadians(lon);
|
|
return new Cesium.Cartesian3(
|
|
Math.cos(latitude) * Math.cos(longitude),
|
|
Math.cos(latitude) * Math.sin(longitude),
|
|
Math.sin(latitude),
|
|
);
|
|
};
|
|
const angle = (a, b) => Cesium.Cartesian3.angleBetween(unit(a), unit(b));
|
|
const excess = (position, origin, destination) =>
|
|
angle(origin, position) +
|
|
angle(position, destination) -
|
|
angle(origin, destination);
|
|
|
|
test('a short airport route cannot describe a plane thousands of kilometres beyond its destination', () => {
|
|
assert.ok(excess(beyond, SFO, LAX) > 2.9);
|
|
assert.equal(plausible(beyond), false);
|
|
});
|
|
|
|
test('backwards and antipodal extensions are not the scheduled airport leg', () => {
|
|
for (const position of [behind, antipode]) {
|
|
assert.ok(excess(position, SFO, LAX) > 3);
|
|
assert.equal(plausible(position), false);
|
|
}
|
|
});
|
|
|
|
test('ordinary route offsets and generous endpoint extensions stay plausible', () => {
|
|
assert.ok(excess(midpoint, SFO, LAX) < 0.001);
|
|
for (const position of [midpoint, SFO, LAX, { lat: 36.5, lon: -119.5 }]) {
|
|
assert.equal(plausible(position), true);
|
|
}
|
|
// ~167 km past either endpoint is outside the 130 km endpoint circle,
|
|
// but remains inside the 200 km coarse-route tolerance.
|
|
const origin = { lat: 0, lon: 0 };
|
|
const destination = { lat: 0, lon: 10 };
|
|
assert.equal(plausible({ lat: 0, lon: -1.5 }, origin, destination), true);
|
|
assert.equal(plausible({ lat: 0, lon: 11.5 }, origin, destination), true);
|
|
});
|
|
|
|
test('the generous endpoint tolerance still excludes a clearly different leg', () => {
|
|
const origin = { lat: 0, lon: 0 };
|
|
const destination = { lat: 0, lon: 10 };
|
|
assert.equal(plausible({ lat: 0, lon: -2.5 }, origin, destination), false);
|
|
assert.equal(plausible({ lat: 0, lon: 12.5 }, origin, destination), false);
|
|
});
|
|
|
|
test('minor-arc admission works across the antimeridian and near the pole', () => {
|
|
const dateline = [
|
|
{ lat: 10, lon: 170 },
|
|
{ lat: 10, lon: -170 },
|
|
];
|
|
assert.equal(plausible({ lat: 10.15, lon: 180 }, ...dateline), true);
|
|
assert.equal(plausible({ lat: -10.15, lon: 0 }, ...dateline), false);
|
|
const polar = [
|
|
{ lat: 80, lon: -60 },
|
|
{ lat: 80, lon: 60 },
|
|
];
|
|
const top = { lat: 84.96163122670251, lon: 0 };
|
|
assert.ok(excess(top, ...polar) < 1e-8);
|
|
assert.equal(plausible(top, ...polar), true);
|
|
assert.equal(plausible({ lat: -top.lat, lon: 180 }, ...polar), false);
|
|
});
|
|
|
|
test('the forward tolerance survives the signed-angle branch cut in both directions', () => {
|
|
const origin = { lat: 0, lon: 0 };
|
|
for (const direction of [-1, 1]) {
|
|
const destination = { lat: 0, lon: direction * 179.9 };
|
|
const within = { lat: 0, lon: direction * -178.8 };
|
|
const endpointGapKm = angle(destination, within) * 6371.0088;
|
|
assert.ok(endpointGapKm > 130 && endpointGapKm < 200);
|
|
assert.equal(plausible(within, origin, destination), true);
|
|
assert.equal(
|
|
plausible({ lat: 0, lon: direction * -178 }, origin, destination),
|
|
false,
|
|
);
|
|
}
|
|
});
|
|
|
|
test('unjudgeable endpoint geometry and missing coordinates keep the loose contract', () => {
|
|
assert.equal(
|
|
plausible({ lat: 0, lon: -90 }, { lat: 0, lon: 0 }, { lat: 0, lon: 180 }),
|
|
true,
|
|
);
|
|
assert.equal(
|
|
plausible({ lat: 45, lon: 0 }, { lat: 0, lon: 0 }, { lat: 0, lon: 0 }),
|
|
true,
|
|
);
|
|
assert.equal(plausible(beyond, SFO, null), true);
|
|
assert.equal(plausible(beyond, null, null), true);
|
|
});
|
|
|
|
test('the actual native tracked label hides the wrong leg and keeps a healthy route', (t) => {
|
|
const collection = new Cesium.BillboardCollection();
|
|
t.after(() => collection.destroy());
|
|
const flightState = {
|
|
records: { data: new Map(), missingPolls: new Map() },
|
|
feed: { _backoff: false },
|
|
_billboards: new Map(),
|
|
_scratchCarto: new Cesium.Cartographic(),
|
|
};
|
|
// Only application host services are supplied. Route admission, WGS84
|
|
// billboard conversion and tracked-label formatting are the actual owners.
|
|
const services = Object.fromEntries(
|
|
[
|
|
'context',
|
|
'trails',
|
|
'geoid',
|
|
'groundFloor',
|
|
'focus',
|
|
'militaryRegistry',
|
|
'readout',
|
|
'camera',
|
|
'picking',
|
|
].map((name) => [name, {}]),
|
|
);
|
|
services.aircraftPresentation = { isTr3b: () => false };
|
|
const parts = { queries: { _contactLabel: (_, info) => info.callsign } };
|
|
const tracking = createTracking({ flightState, services, parts });
|
|
for (const [position, expected] of [
|
|
[beyond, false],
|
|
[midpoint, true],
|
|
]) {
|
|
const id = 'abc001';
|
|
const route = { origin: SFO, destination: LAX };
|
|
flightState.records.data.set(id, {
|
|
callsign: 'OWNED001',
|
|
altitude: 10000,
|
|
verticalRate: 0,
|
|
route,
|
|
});
|
|
flightState._billboards.set(
|
|
id,
|
|
collection.add({
|
|
id,
|
|
position: Cesium.Cartesian3.fromDegrees(
|
|
position.lon,
|
|
position.lat,
|
|
10000,
|
|
),
|
|
}),
|
|
);
|
|
assert.equal(
|
|
tracking._trackedLabelText(id).includes('SFO → LAX'),
|
|
expected,
|
|
);
|
|
assert.equal(tracking._routeIsPlausible(id, route), expected);
|
|
}
|
|
});
|