fix(cockpit): no swath readout while the orbital view looks past the Earth's limb

This commit is contained in:
Sameh Khamis committed 2026-11-08 15:55:02 -08:00
1 parent 5c25bc54e6
commit 6ca53febad
3 files changed
+37 -4

No files matched your search

+15
View File
@@ -364,6 +364,21 @@ export function offNadirAngleDeg({ northDeg = 0, eastDeg = 0 } = {}) {
return (Math.acos(cosine) * 180) / Math.PI; return (Math.acos(cosine) * 180) / Math.PI;
} }
/**
* Whether the view's centre, tilted off nadir, still meets the Earth: its
* angle from nadir (`offNadirAngleDeg`) is within the Earth's angular radius
* from the satellite, asin(R / (R + altitude)).
* @param {number} altitudeM
* @param {{northDeg?: number, eastDeg?: number}} [offset]
* @returns {boolean}
*/
export function offNadirCentreMeetsEarth(altitudeM, offset = {}) {
if (!Number.isFinite(altitudeM) || altitudeM <= 0) return false;
const R = ORBITAL_EARTH_RADIUS_M;
const limbDeg = (Math.asin(R / (R + altitudeM)) * 180) / Math.PI;
return offNadirAngleDeg(offset) < limbDeg;
}
/** /**
* Roughly how much wider the ground across the frame is at the centre of a * Roughly how much wider the ground across the frame is at the centre of a
* tilted view than at nadir, on a flat Earth: tilting across the frame (east, * tilted view than at nadir, on a flat Earth: tilting across the frame (east,
+14
View File
@@ -13,6 +13,7 @@ import {
nadirOrientation, nadirOrientation,
nextOrbitalZoom, nextOrbitalZoom,
offNadirAngleDeg, offNadirAngleDeg,
offNadirCentreMeetsEarth,
offNadirSwathScale, offNadirSwathScale,
offNadirOrientation, offNadirOrientation,
orbitalBaseFovRad, orbitalBaseFovRad,
@@ -300,3 +301,16 @@ test("a tilted view's width grows faster across the frame than along it", () =>
} }
assert.equal(offNadirSwathScale({ northDeg: Number.NaN }), 1); assert.equal(offNadirSwathScale({ northDeg: Number.NaN }), 1);
}); });
test('a view tilted past the limb no longer meets the Earth', () => {
// GEO: the Earth spans about 8.7 degrees either side of nadir.
assert.equal(offNadirCentreMeetsEarth(35_786_000, { northDeg: 5 }), true);
assert.equal(offNadirCentreMeetsEarth(35_786_000, { northDeg: 15 }), false);
// LEO: a 30 degree tilt still lands on the ground.
assert.equal(
offNadirCentreMeetsEarth(420_000, { northDeg: 20, eastDeg: 20 }),
true,
);
assert.equal(offNadirCentreMeetsEarth(420_000, { eastDeg: 80 }), false);
assert.equal(offNadirCentreMeetsEarth(NaN, {}), false);
});
+8 -4
View File
@@ -14,6 +14,7 @@ import {
nextOrbitalZoom, nextOrbitalZoom,
offNadirAngleDeg, offNadirAngleDeg,
offNadirOrientation, offNadirOrientation,
offNadirCentreMeetsEarth,
offNadirSwathScale, offNadirSwathScale,
orbitalBaseFovRad, orbitalBaseFovRad,
previousOrbitalZoom, previousOrbitalZoom,
@@ -410,9 +411,12 @@ export function publishOrbitalView(info, transition = IDLE_TRANSITION) {
const settledFov = fovForZoom(orbitalBaseFovRad(info.altitudeM), state.zoom); const settledFov = fovForZoom(orbitalBaseFovRad(info.altitudeM), state.zoom);
const footprintKm = footprintWidthKm(info.altitudeM, settledFov, aspect); const footprintKm = footprintWidthKm(info.altitudeM, settledFov, aspect);
const trackUp = Number.isFinite(info.groundTrackDeg); const trackUp = Number.isFinite(info.groundTrackDeg);
const swathScale = offset const tilt = offset
? offNadirSwathScale(lookTilt(orbitalLookReadoutParts(state.lookTarget))) ? lookTilt(orbitalLookReadoutParts(state.lookTarget))
: 1; : null;
const swathScale = offset ? offNadirSwathScale(tilt) : 1;
// Tilted past the limb, the view's centre looks into space: no swath.
const seesEarth = !offset || offNadirCentreMeetsEarth(info.altitudeM, tilt);
this.publishOrbital({ this.publishOrbital({
name: info.name, name: info.name,
classLabel: info.classLabel || '', classLabel: info.classLabel || '',
@@ -432,7 +436,7 @@ export function publishOrbitalView(info, transition = IDLE_TRANSITION) {
// the nadir footprint (`offNadirSwathScale`); 1 and null at nadir. // the nadir footprint (`offNadirSwathScale`); 1 and null at nadir.
swathScale, swathScale,
swathKm: swathKm:
offset && Number.isFinite(footprintKm) offset && seesEarth && Number.isFinite(footprintKm)
? footprintKm * swathScale ? footprintKm * swathScale
: null, : null,
}, },