From 5652236a27b5292c7094207eabb6bf4d7eef9d24 Mon Sep 17 00:00:00 2001 From: Sameh Khamis Date: Thu, 5 Nov 2026 14:01:57 -0800 Subject: [PATCH] Read the agent world packet's camera through src/geo The world packet converts the eye position with toLonLatH instead of Cesium's Cartographic, so the agent-world-packet group no longer needs cesium. Degree conversions use precomputed factors, as Cesium.Math does, so results stay bit for bit the same. --- scripts/package-boundaries.json | 10 +++++++++- src/agent/worldPacket.js | 12 +++++------- src/geo/geo.test.mjs | 9 +++++++++ src/geo/vector.js | 8 ++++++-- 4 files changed, 29 insertions(+), 10 deletions(-) diff --git a/scripts/package-boundaries.json b/scripts/package-boundaries.json index 5a1b4e55f..3ce02469e 100644 --- a/scripts/package-boundaries.json +++ b/scripts/package-boundaries.json @@ -2355,6 +2355,10 @@ "./standalone/catalog" ], "modules": [ + "src/geo/index.js", + "src/geo/vector.js", + "src/geo/ellipsoid.js", + "src/geo/frames.js", "src/layers/flights/icons.js", "src/data/aircraftIconLayer.js", "src/data/aircraftModelLayer.js", @@ -5112,6 +5116,10 @@ "agent-world-packet": { "exports": ["./agent/world-packet"], "modules": [ + "src/geo/index.js", + "src/geo/vector.js", + "src/geo/ellipsoid.js", + "src/geo/frames.js", "src/agent/worldPacket.js", "src/data/layerSnapshot.js", "src/data/feedState.js", @@ -5120,7 +5128,7 @@ "src/data/installationFeedback.js", "src/i18n/marker.js" ], - "external": ["cesium"] + "external": [] }, "heights": { "exports": ["./queries/heights"], diff --git a/src/agent/worldPacket.js b/src/agent/worldPacket.js index 4f8dad144..ec8234340 100644 --- a/src/agent/worldPacket.js +++ b/src/agent/worldPacket.js @@ -1,4 +1,4 @@ -import * as Cesium from 'cesium'; +import { toLonLatH } from '../geo/index.js'; import { feedProvenanceEnvelope, layerSnapshot, @@ -109,9 +109,7 @@ export function getWorldPacket(options = {}) { if (!dataManager || typeof dataManager.getAll !== 'function') throw new TypeError('World Packet requires a data manager'); - const cartographic = Cesium.Cartographic.fromCartesian( - viewer.camera.positionWC, - ); + const eye = toLonLatH(viewer.camera.positionWC); // Read the roster once. Voice must not rewalk disabled layers: preserving the // current enabled-only view keeps the model's context budget bounded. const rows = dataManager.getAll(); @@ -126,9 +124,9 @@ export function getWorldPacket(options = {}) { ok: true, action: 'get_current_view_state', camera: { - latitude: Cesium.Math.toDegrees(cartographic.latitude), - longitude: Cesium.Math.toDegrees(cartographic.longitude), - heightM: cartographic.height, + latitude: eye.lat, + longitude: eye.lon, + heightM: eye.height, }, style: styleManager?.activeStyle || 'normal', context: contextState diff --git a/src/geo/geo.test.mjs b/src/geo/geo.test.mjs index 4085918ce..9e0ad1a58 100644 --- a/src/geo/geo.test.mjs +++ b/src/geo/geo.test.mjs @@ -7,7 +7,9 @@ import { geodeticSurfaceNormal, scaleToGeodeticSurface, toCartographicRadians, + toDegrees, toLonLatH, + toRadians, } from './index.js'; /** A seeded generator, so a failure names a reproducible point. */ @@ -47,6 +49,13 @@ const closeVec = (a, b, tolerance, message) => { close(a.z, b.z, tolerance, `${message} z`); }; +test("angle conversions are bit for bit the default renderer's", () => { + for (const p of points()) { + assert.equal(toRadians(p.lon), Cesium.Math.toRadians(p.lon)); + assert.equal(toDegrees(p.lat / 57), Cesium.Math.toDegrees(p.lat / 57)); + } +}); + test('geodetic to ECEF matches the default renderer', () => { for (const p of points()) { const ours = fromDegrees(p.lon, p.lat, p.height); diff --git a/src/geo/vector.js b/src/geo/vector.js index ad4ef8963..e020dd5cc 100644 --- a/src/geo/vector.js +++ b/src/geo/vector.js @@ -24,8 +24,12 @@ export function normalize(a) { return vec(a.x / m, a.y / m, a.z / m); } -export const toRadians = (degrees) => (degrees * Math.PI) / 180; -export const toDegrees = (radians) => (radians * 180) / Math.PI; +// As the default renderer converts: by a precomputed factor, so results are +// bit for bit its own. +export const RADIANS_PER_DEGREE = Math.PI / 180; +export const DEGREES_PER_RADIAN = 180 / Math.PI; +export const toRadians = (degrees) => degrees * RADIANS_PER_DEGREE; +export const toDegrees = (radians) => radians * DEGREES_PER_RADIAN; export const clamp = (v, lo, hi) => Math.min(hi, Math.max(lo, v)); export const acosClamped = (v) => Math.acos(clamp(v, -1, 1)); export const equalsEpsilon = (a, b, eps) => Math.abs(a - b) <= eps;