Draw civil flights from an icon set moved on the GPU

Every flight is now a row in the layer's icon set. Its motion segment
follows the same regime `_deadReckon` picks (interpolate between fixes,
warm up backward from the oldest, coast forward from the newest), and
one shared `_motionRegime` makes that choice for both. The shader moves
every untracked contact between polls, so the 12 Hz fleet tick no
longer touches each billboard. It now only re-plans expired rows,
floors grounded contacts, advances focus while needed, and runs the 3D
model regime.

Grounded contacts the floor lifts are pinned to a hold at the floored
position. Their nose glides on the GPU. Contacts within 50 km re-floor
every tick, and farther ones take turns about once a second. Low
contacts are judged for the horizon at no lower than 12 m above the
ellipsoid, as before. Below hover speed a contact's nose holds. A row
whose fleet model is drawn keeps its focus updated, because the model
reads it. Untracking re-plans and re-floors the icon from the tracked
course.

On the same views with about 6,700 OpenSky flights, frame gaps at p95
drop from 28-40 ms to 17 ms, and the fleet tick from 16-37 ms to about
2 ms at most.
This commit is contained in:
Sameh Khamis committed 2026-11-03 19:40:39 -08:00
1 parent 5f36eb0e0d
commit 2c4c66c710
33 files changed
+1598 -986

No files matched your search

+101 -28
View File
@@ -14,6 +14,8 @@ import flightsLayer, {
_setTrackedFlightRefreshStateForTest,
_floorGroundedDisplayPositionForTest,
_clearDisplayFloorStateForTest,
_iconForTest,
_floorGroundedIconsForTest,
mapAnalystRecord,
} from './flights.js';
import { setMilitaryLayerActive } from './militaryRegistry.js';
@@ -225,18 +227,9 @@ test('nonempty OpenSky payload with zero usable rows cannot prove share target a
test('a newly seen aircraft appears at its delayed position, not ahead of it', async () => {
// The fleet renders RENDER_DELAY_SEC behind real time, so a fresh contact's
// first displayed position is its fix projected back to that delayed time.
// Creating the billboard at the raw fix drew it ahead until the next fleet
// Creating the icon at the raw fix drew it ahead until the next fleet
// tick, which then jumped it back about one delay of travel.
const added = [];
const billboardCollection = {
show: false,
add(options) {
const billboard = { ...options };
added.push(billboard);
return billboard;
},
remove() {},
};
const billboardCollection = { show: false };
const viewer = { camera: { positionCartographic: null }, scene: {} };
_setTrackedFlightRefreshStateForTest({
icao24: 'seed00',
@@ -293,9 +286,9 @@ test('a newly seen aircraft appears at its delayed position, not ahead of it', a
};
try {
await flightsLayer.update(viewer);
const billboard = added.find((entry) => entry.id === icao24);
assert.ok(billboard, 'the new contact gets a billboard');
const shown = Cesium.Cartographic.fromCartesian(billboard.position);
const icon = _iconForTest(icao24);
assert.ok(icon, 'the new contact gets an icon');
const shown = Cesium.Cartographic.fromCartesian(icon.position);
const fix = Cesium.Cartesian3.fromDegrees(fixLon, fixLat, 10_700);
const behindM = Cesium.Cartesian3.distance(
Cesium.Cartesian3.fromRadians(shown.longitude, shown.latitude, 10_700),
@@ -1066,21 +1059,12 @@ const _floorCarto = (pos) =>
test('a newly seen taxiing aircraft starts on the floor under its delayed position', async () => {
// A grounded contact is drawn at its delayed position lifted onto the floor
// under it. Creating the billboard without that lift started it on the
// under it. Creating the icon without that lift started it on the
// floor of its reported fix, then the next fleet tick raised it.
_clearDisplayFloorStateForTest();
_clearMeshFloorCellsForTest();
setMeshFloorPreferred(true);
const added = [];
const billboardCollection = {
show: false,
add(options) {
const billboard = { ...options };
added.push(billboard);
return billboard;
},
remove() {},
};
const billboardCollection = { show: false };
const viewer = { camera: { positionCartographic: null }, scene: {} };
_setTrackedFlightRefreshStateForTest({
icao24: 'seed00',
@@ -1142,9 +1126,9 @@ test('a newly seen taxiing aircraft starts on the floor under its delayed positi
};
try {
await flightsLayer.update(viewer);
const billboard = added.find((entry) => entry.id === icao24);
assert.ok(billboard, 'the new contact gets a billboard');
const shown = _floorCarto(billboard.position);
const icon = _iconForTest(icao24);
assert.ok(icon, 'the new contact gets an icon');
const shown = _floorCarto(icon.position);
assert.ok(
Cesium.Math.toDegrees(shown.longitude) < fixLon,
'drawn behind the fix',
@@ -1160,6 +1144,95 @@ test('a newly seen taxiing aircraft starts on the floor under its delayed positi
}
});
test('far grounded contacts take turns on the floor; near ones refloor every tick', async () => {
// The floor pass is the fleet tick's only per-contact CPU work. Past
// FLOOR_NEAR_M a contact is refloored once per FLOOR_FAR_EVERY_TICKS.
_clearDisplayFloorStateForTest();
_clearMeshFloorCellsForTest();
setMeshFloorPreferred(true);
const viewer = { camera: { positionCartographic: null }, scene: {} };
_setTrackedFlightRefreshStateForTest({
icao24: 'seed00',
entity: null,
billboard: {
show: false,
position: Cesium.Cartesian3.fromDegrees(0, 0, 0),
},
billboardCollection: { show: false },
viewer,
meta: { rawLat: 0, rawLon: 0, onGround: false },
tracked: false,
});
const icao24 = 'taxi02';
const fixLon = -97.66;
const fixLat = 30.2;
for (let k = -40; k <= 40; k += 1) {
reportMeshFloorCell(fixLat, fixLon + k * 0.0001, 131.5);
}
const nowSec = Math.floor(Date.now() / 1000);
const realFetch = globalThis.fetch;
globalThis.fetch = async (url) => {
if (!String(url).startsWith('/api/flights')) {
return { ok: true, status: 200, json: async () => ({ ac: [] }) };
}
return {
ok: true,
status: 200,
headers: { get: () => null },
json: async () => ({
time: nowSec,
states: [
[
icao24,
'TAXI02 ',
'United States',
nowSec - 2,
nowSec - 2,
fixLon,
fixLat,
null,
true,
10,
90,
0,
null,
null,
null,
null,
null,
5,
],
],
}),
};
};
try {
await flightsLayer.update(viewer);
const start = Cesium.JulianDate.now();
const at = (s) =>
Cesium.JulianDate.addSeconds(start, s, new Cesium.JulianDate());
const far = Cesium.Cartesian3.fromDegrees(fixLon, fixLat, 3_000_000);
const near = Cesium.Cartesian3.fromDegrees(fixLon, fixLat, 10_000);
let last = _iconForTest(icao24).position;
const moves = (camera, from, to) => {
let count = 0;
for (let tick = from; tick <= to; tick += 1) {
_floorGroundedIconsForTest(at(tick), camera);
const now = _iconForTest(icao24).position;
if (Cesium.Cartesian3.distance(now, last) > 1) count += 1;
last = now;
}
return count;
};
assert.equal(moves(far, 1, 24), 2, 'far: once per 12 ticks');
assert.equal(moves(near, 25, 30), 6, 'near: every tick');
} finally {
globalThis.fetch = realFetch;
_clearMeshFloorCellsForTest();
_clearDisplayFloorStateForTest();
}
});
test('display floor: a grounded contact that drifted onto a higher cell is lifted', () => {
_clearDisplayFloorStateForTest();
_clearMeshFloorCellsForTest();