From 632005d221f2a5c60045769208c4b442d69cf3e5 Mon Sep 17 00:00:00 2001 From: Rudy Celekli Date: Sun, 11 Oct 2026 09:33:27 -0400 Subject: [PATCH] fix(director): seek camera longitude across the shortest dateline arc --- CHANGELOG.md | 2 ++ docs/CURRENT-STATE.md | 5 ++++ src/director/director-dateline-seek.test.mjs | 26 ++++++++++++++++++++ src/director/timeline.js | 8 +++++- 4 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 src/director/director-dateline-seek.test.mjs diff --git a/CHANGELOG.md b/CHANGELOG.md index 7acdedf6b..2075effa9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ the five borough cores load and `CCTV_NYC_MAX_SOURCES` changes the cap. The catalog-wide ceiling is unchanged; extra cameras share it round-robin with the other packs. +- Director timeline seeks cross the dateline along the short longitude arc. + - Treat explicitly current, complete empty vessel coverage as a successful update, clearing obsolete contacts while retaining stale or incomplete snapshots. diff --git a/docs/CURRENT-STATE.md b/docs/CURRENT-STATE.md index c77d1d8e3..cb0b43c54 100644 --- a/docs/CURRENT-STATE.md +++ b/docs/CURRENT-STATE.md @@ -5310,3 +5310,8 @@ datacenters, dams and the Nepal locator retain that shared credit while displaye Military fragments stitch by source identity. Different mapped parcels merge only when their footprints touch or contain one another, never across a seam tolerance gap. + + +### fix(director): seek camera longitude across the shortest dateline arc + +Interpolate longitude with the existing shortest-angle easing, normalize intermediate longitudes, and preserve exact authored endpoints at progress zero and one. diff --git a/src/director/director-dateline-seek.test.mjs b/src/director/director-dateline-seek.test.mjs new file mode 100644 index 000000000..f950814f3 --- /dev/null +++ b/src/director/director-dateline-seek.test.mjs @@ -0,0 +1,26 @@ +import test from 'node:test'; +import assert from 'node:assert/strict'; +import { cameraAtProgress } from './timeline.js'; +const camera = (lon) => ({ + lat: 10, + lon, + alt: 1000, + heading: 0, + pitch: -40, + roll: 0, +}); +test('director seek follows the short dateline arc in both directions', () => { + for (const [a, b] of [ + [179, -179], + [-179, 179], + ]) { + assert.equal( + Math.abs(cameraAtProgress(camera(a), camera(b), 0.5).lon), + 180, + ); + assert.equal(cameraAtProgress(camera(a), camera(b), 0).lon, a); + assert.equal(cameraAtProgress(camera(a), camera(b), 1).lon, b); + assert.ok(Math.abs(cameraAtProgress(camera(a), camera(b), 0.25).lon) > 179); + } + assert.equal(cameraAtProgress(camera(20), camera(24), 0.5).lon, 22); +}); diff --git a/src/director/timeline.js b/src/director/timeline.js index 7fd4cbbae..1da08d498 100644 --- a/src/director/timeline.js +++ b/src/director/timeline.js @@ -45,7 +45,13 @@ export function cameraAtProgress(fromCamera, toCamera, progress) { }; return { lat: lerp(source.lat, target.lat), - lon: lerp(source.lon, target.lon), + lon: + t === 0 + ? Number(source.lon) + : t === 1 + ? Number(target.lon) + : ((((lerpAngle(source.lon, target.lon) + 180) % 360) + 360) % 360) - + 180, alt: lerp(source.alt, target.alt), heading: lerpAngle(source.heading, target.heading), pitch: lerp(source.pitch, target.pitch),