From 3ce3fce46f5ffd8bfdae8dd9cb153949b8ba4d35 Mon Sep 17 00:00:00 2001 From: Sameh Khamis Date: Sun, 8 Nov 2026 13:25:55 -0800 Subject: [PATCH] fix(cockpit): the bridge reads its floor where the ship is now The ground clamp read the floor at the ship's last AIS fix while the camera rode that fix dead-reckoned up to 180 s ahead, so a quay or bridge deck at the old position could lift the eye. Vessels now read the floor at the dead-reckoned target, as the water read already does; aircraft are unchanged. --- src/ui/cockpitBridge.test.mjs | 21 +++++++++++++++++++++ src/ui/cockpitCamera.js | 13 +++++++++++-- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/ui/cockpitBridge.test.mjs b/src/ui/cockpitBridge.test.mjs index 1273b5617..b73ff2a1f 100644 --- a/src/ui/cockpitBridge.test.mjs +++ b/src/ui/cockpitBridge.test.mjs @@ -1077,6 +1077,27 @@ test('the water is read where the ship is now, not at its last report', async (t assert.ok(eastM > 300 && eastM < 450, `probed ${eastM.toFixed(0)} m east`); }); +test('the bridge floor is read where the ship is now, not at its last report', async (t) => { + const clock = manualClock(t, START_MS); + // Reported a minute ago at 12 kn on course 095: since then ~370 m east. + const record = { ...RECORD, lastPositionEpoch: (START_MS - 60_000) / 1000 }; + const ship = fixture(t, { record }); + const floors = []; + const cached = ship.cockpit.services.cachedGroundFloor; + ship.cockpit.services.cachedGroundFloor = (lat, lon) => { + floors.push({ lat, lon }); + return cached(lat, lon); + }; + ship.cockpit.enter(); + await settle(); + frames(ship.cockpit, clock, ship.shots, 20); + const first = floors[0]; + assert.ok(first, 'the floor was read'); + const eastM = + (first.lon - RECORD.lon) * 111_320 * Math.cos((RECORD.lat * Math.PI) / 180); + assert.ok(eastM > 300 && eastM < 450, `read ${eastM.toFixed(0)} m east`); +}); + test('the radar centres where the camera rides, not at the last report', async (t) => { const clock = manualClock(t, START_MS); // Reported a minute ago at 12 kn on course 095: since then ~370 m east. diff --git a/src/ui/cockpitCamera.js b/src/ui/cockpitCamera.js index fd076663c..2a70ef280 100644 --- a/src/ui/cockpitCamera.js +++ b/src/ui/cockpitCamera.js @@ -401,9 +401,18 @@ function placeCamera(target, info, nowMs, dtSec, profile, look = null) { Cesium.Ellipsoid.WGS84, this.scratchTargetCartographic, ); + // A bridge's target is its fix dead-reckoned up to minutes ahead: read + // the floor where the ship is now, as its water is. + const floorAt = + info.kind === 'vessel' + ? { + latitude: Cesium.Math.toDegrees(targetCartographic.latitude), + longitude: Cesium.Math.toDegrees(targetCartographic.longitude), + } + : info; let cockpitFloorM = this.services.cachedGroundFloor( - info.latitude, - info.longitude, + floorAt.latitude, + floorAt.longitude, ); if (info.onGround === true) { const groundPoint = [{ lat: info.latitude, lon: info.longitude }];