mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 19:04:02 +00:00
refactor(ui,voice,annotations,scenes): take vector maths from src/geo
Move the Cartesian3/Cartographic/Matrix4/Transforms/Ellipsoid/Math calls of the second batch (cockpit camera, context and controller; camera orientation controls; application shell; location navigation; the annotation resolver and engine; voice actions and pointer pick; the scene director; the embed app) to src/geo. Behaviour is unchanged: same argument order, same `result` semantics. Kept on Cesium: out-of-scope classes (HeadingPitchRange, BoundingSphere, Intersect, EllipsoidalOccluder, EasingFunction, SceneTransforms, JulianDate), WGS84 where it goes into pickEllipsoid or EllipsoidalOccluder, Matrix4.IDENTITY handed to lookAtTransform, and the Cartesian2 window positions that reach scene.pickPosition: Cesium keys its per-frame pick cache on windowPosition.toString(), which a plain object would collapse to one "[object Object]" key. The Contacts-subject harness in gevActions.test stubbed Cesium.Cartographic.fromCartesian to place its subject; it now builds a real subject position at the same coordinates with geo.cartesian3.fromDegrees. The cockpit-controls and scenes package-boundary groups now own the src/geo files.
This commit is contained in:
1 parent
d886be68a8
commit
1a69368ae6
14 files changed
+216
-200
No files matched your search
@@ -520,7 +520,21 @@
|
||||
"src/cockpitMath.js",
|
||||
"src/cockpitUtilityLayout.js",
|
||||
"src/cockpitVisionPolicy.js",
|
||||
"src/ui/panelRailGeometry.js"
|
||||
"src/ui/panelRailGeometry.js",
|
||||
"src/geo/index.js",
|
||||
"src/geo/math.js",
|
||||
"src/geo/ellipsoid.js",
|
||||
"src/geo/cartographic.js",
|
||||
"src/geo/cartesian2.js",
|
||||
"src/geo/cartesian3.js",
|
||||
"src/geo/matrix3.js",
|
||||
"src/geo/matrix4.js",
|
||||
"src/geo/quaternion.js",
|
||||
"src/geo/transforms.js",
|
||||
"src/geo/scaleToGeodeticSurface.js",
|
||||
"src/geo/check.js",
|
||||
"src/geo/debug.js",
|
||||
"src/geo/developerError.js"
|
||||
],
|
||||
"external": ["cesium"]
|
||||
},
|
||||
@@ -788,7 +802,21 @@
|
||||
"src/director/authoring.js",
|
||||
"src/scenes/sharing.js",
|
||||
"src/ui/sceneSharing.js",
|
||||
"src/data/cameraArrival.js"
|
||||
"src/data/cameraArrival.js",
|
||||
"src/geo/index.js",
|
||||
"src/geo/math.js",
|
||||
"src/geo/ellipsoid.js",
|
||||
"src/geo/cartographic.js",
|
||||
"src/geo/cartesian2.js",
|
||||
"src/geo/cartesian3.js",
|
||||
"src/geo/matrix3.js",
|
||||
"src/geo/matrix4.js",
|
||||
"src/geo/quaternion.js",
|
||||
"src/geo/transforms.js",
|
||||
"src/geo/scaleToGeodeticSurface.js",
|
||||
"src/geo/check.js",
|
||||
"src/geo/debug.js",
|
||||
"src/geo/developerError.js"
|
||||
],
|
||||
"external": ["cesium"]
|
||||
},
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { isUnavailableCapability } from '../sources/capability.js';
|
||||
import { defaultGeospatial } from '../search/defaults.js';
|
||||
import * as Cesium from 'cesium';
|
||||
import * as geo from '../geo/index.js';
|
||||
import {
|
||||
holdContinuousRender,
|
||||
releaseContinuousRender,
|
||||
@@ -1013,13 +1014,13 @@ export function createAnnotationEngine({
|
||||
return;
|
||||
}
|
||||
const cart = points.map((p) =>
|
||||
Cesium.Cartesian3.fromDegrees(p.lon, p.lat, p.height || 0),
|
||||
geo.cartesian3.fromDegrees(p.lon, p.lat, p.height || 0),
|
||||
);
|
||||
const sphere = Cesium.BoundingSphere.fromPoints(cart);
|
||||
viewer.camera.flyToBoundingSphere(sphere, {
|
||||
offset: new Cesium.HeadingPitchRange(
|
||||
viewer.camera.heading,
|
||||
Cesium.Math.toRadians(-35),
|
||||
geo.math.toRadians(-35),
|
||||
Math.max(900, sphere.radius * 2.6),
|
||||
),
|
||||
duration: 1.6,
|
||||
@@ -1034,7 +1035,7 @@ export function createAnnotationEngine({
|
||||
function isPointOnScreen(p) {
|
||||
try {
|
||||
const camera = viewer.camera;
|
||||
const pos = Cesium.Cartesian3.fromDegrees(p.lon, p.lat, p.height || 0);
|
||||
const pos = geo.cartesian3.fromDegrees(p.lon, p.lat, p.height || 0);
|
||||
const cv = camera.frustum.computeCullingVolume(
|
||||
camera.position,
|
||||
camera.direction,
|
||||
@@ -1075,7 +1076,7 @@ export function createAnnotationEngine({
|
||||
: viewportRange(anno.viewport) || 600;
|
||||
viewer.camera.flyToBoundingSphere(
|
||||
new Cesium.BoundingSphere(
|
||||
Cesium.Cartesian3.fromDegrees(
|
||||
geo.cartesian3.fromDegrees(
|
||||
target.lon,
|
||||
target.lat,
|
||||
anno.anchor.height || 0,
|
||||
@@ -1085,7 +1086,7 @@ export function createAnnotationEngine({
|
||||
{
|
||||
offset: new Cesium.HeadingPitchRange(
|
||||
viewer.camera.heading,
|
||||
Cesium.Math.toRadians(-35),
|
||||
geo.math.toRadians(-35),
|
||||
range * 2.4,
|
||||
),
|
||||
duration: 1.8,
|
||||
@@ -1275,10 +1276,10 @@ export function createAnnotationEngine({
|
||||
if (destroyed) return;
|
||||
try {
|
||||
viewer.camera.flyTo({
|
||||
destination: Cesium.Cartesian3.fromDegrees(lon, lat, height),
|
||||
destination: geo.cartesian3.fromDegrees(lon, lat, height),
|
||||
orientation: {
|
||||
heading: Cesium.Math.toRadians(heading),
|
||||
pitch: Cesium.Math.toRadians(pitch),
|
||||
heading: geo.math.toRadians(heading),
|
||||
pitch: geo.math.toRadians(pitch),
|
||||
roll: 0,
|
||||
},
|
||||
duration,
|
||||
@@ -1395,9 +1396,9 @@ const VIEWPORT_ASSIST_RANGE_CAP_M = 120000;
|
||||
function viewportRange(vp) {
|
||||
if (!vp?.low || !vp?.high) return null;
|
||||
try {
|
||||
const span = Cesium.Cartesian3.distance(
|
||||
Cesium.Cartesian3.fromDegrees(vp.low.longitude, vp.low.latitude),
|
||||
Cesium.Cartesian3.fromDegrees(vp.high.longitude, vp.high.latitude),
|
||||
const span = geo.cartesian3.distance(
|
||||
geo.cartesian3.fromDegrees(vp.low.longitude, vp.low.latitude),
|
||||
geo.cartesian3.fromDegrees(vp.high.longitude, vp.high.latitude),
|
||||
);
|
||||
return Number.isFinite(span) && span > 0
|
||||
? Math.max(300, Math.min(span * 0.7, VIEWPORT_ASSIST_RANGE_CAP_M))
|
||||
@@ -1422,9 +1423,9 @@ function ringRange(ring) {
|
||||
if (lon < minLon) minLon = lon;
|
||||
if (lon > maxLon) maxLon = lon;
|
||||
}
|
||||
const span = Cesium.Cartesian3.distance(
|
||||
Cesium.Cartesian3.fromDegrees(minLon, minLat),
|
||||
Cesium.Cartesian3.fromDegrees(maxLon, maxLat),
|
||||
const span = geo.cartesian3.distance(
|
||||
geo.cartesian3.fromDegrees(minLon, minLat),
|
||||
geo.cartesian3.fromDegrees(maxLon, maxLat),
|
||||
);
|
||||
return Math.max(300, span * 0.7);
|
||||
}
|
||||
|
||||
+14
-13
@@ -14,6 +14,7 @@ import {
|
||||
} from '../sources/featureGeometry.js';
|
||||
import { defaultGeospatial } from '../search/defaults.js';
|
||||
import * as Cesium from 'cesium';
|
||||
import * as geo from '../geo/index.js';
|
||||
import { lookupNeighborhoodRing } from '../data/neighborhoodPolygons.js';
|
||||
import {
|
||||
lookupNaturalRegionOutline,
|
||||
@@ -1835,8 +1836,8 @@ export function createAnnotationResolver({
|
||||
try {
|
||||
const carto = viewer?.camera?.positionCartographic;
|
||||
if (!carto) return null;
|
||||
const lat = Cesium.Math.toDegrees(carto.latitude);
|
||||
const lon = Cesium.Math.toDegrees(carto.longitude);
|
||||
const lat = geo.math.toDegrees(carto.latitude);
|
||||
const lon = geo.math.toDegrees(carto.longitude);
|
||||
const radiusKm = Math.max((carto.height / 1000) * 3, 5);
|
||||
if (![lat, lon, radiusKm].every(Number.isFinite)) return null;
|
||||
return { lat, lon, radiusKm };
|
||||
@@ -1850,10 +1851,10 @@ export function createAnnotationResolver({
|
||||
try {
|
||||
const rect = viewer?.camera?.computeViewRectangle?.();
|
||||
if (!rect) return null;
|
||||
const swLat = Cesium.Math.toDegrees(rect.south).toFixed(4);
|
||||
const swLng = Cesium.Math.toDegrees(rect.west).toFixed(4);
|
||||
const neLat = Cesium.Math.toDegrees(rect.north).toFixed(4);
|
||||
const neLng = Cesium.Math.toDegrees(rect.east).toFixed(4);
|
||||
const swLat = geo.math.toDegrees(rect.south).toFixed(4);
|
||||
const swLng = geo.math.toDegrees(rect.west).toFixed(4);
|
||||
const neLat = geo.math.toDegrees(rect.north).toFixed(4);
|
||||
const neLng = geo.math.toDegrees(rect.east).toFixed(4);
|
||||
if ([swLat, swLng, neLat, neLng].some((v) => v === 'NaN')) return null;
|
||||
return `${swLat},${swLng}|${neLat},${neLng}`;
|
||||
} catch {
|
||||
@@ -1953,11 +1954,11 @@ export function createAnnotationResolver({
|
||||
}
|
||||
}
|
||||
if (!isPickedWorldPosition(cart)) return null;
|
||||
const carto = Cesium.Cartographic.fromCartesian(cart);
|
||||
const carto = geo.cartographic.fromCartesian(cart);
|
||||
if (!carto) return null;
|
||||
return {
|
||||
lat: Cesium.Math.toDegrees(carto.latitude),
|
||||
lon: Cesium.Math.toDegrees(carto.longitude),
|
||||
lat: geo.math.toDegrees(carto.latitude),
|
||||
lon: geo.math.toDegrees(carto.longitude),
|
||||
// The height the pick actually landed on — a roof, a hillside, or 0 on
|
||||
// the ellipsoid. Callers that only want a coordinate ignore it; the draw
|
||||
// tool's live preview needs it, or the rubber band sinks to sea level
|
||||
@@ -1979,11 +1980,11 @@ export function createAnnotationResolver({
|
||||
scene.clampToHeightSupported &&
|
||||
typeof scene.clampToHeight === 'function'
|
||||
) {
|
||||
const carto = Cesium.Cartographic.fromDegrees(lon, lat);
|
||||
const surface = Cesium.Cartographic.toCartesian(carto);
|
||||
const carto = geo.cartographic.fromDegrees(lon, lat);
|
||||
const surface = geo.cartographic.toCartesian(carto);
|
||||
const clamped = scene.clampToHeight(surface);
|
||||
if (clamped) {
|
||||
const h = Cesium.Cartographic.fromCartesian(clamped).height;
|
||||
const h = geo.cartographic.fromCartesian(clamped).height;
|
||||
if (Number.isFinite(h)) return h;
|
||||
}
|
||||
}
|
||||
@@ -1991,7 +1992,7 @@ export function createAnnotationResolver({
|
||||
/* tiles not ready — fall through */
|
||||
}
|
||||
const globeHeight = scene.globe?.getHeight?.(
|
||||
Cesium.Cartographic.fromDegrees(lon, lat),
|
||||
geo.cartographic.fromDegrees(lon, lat),
|
||||
);
|
||||
return Number.isFinite(globeHeight) && globeHeight > 0 ? globeHeight : 0;
|
||||
}
|
||||
|
||||
+4
-4
@@ -11,7 +11,7 @@
|
||||
* embedded or not.
|
||||
*/
|
||||
|
||||
import * as Cesium from 'cesium';
|
||||
import * as geo from '../geo/index.js';
|
||||
import { announceNavigationAuthority } from '../navigationPolicy.js';
|
||||
import { annotationsFromParams, createView } from '../view/index.js';
|
||||
|
||||
@@ -126,14 +126,14 @@ function flyTo(viewer, camera) {
|
||||
announceNavigationAuthority('embed-view');
|
||||
return new Promise((resolve) => {
|
||||
viewer.camera.flyTo({
|
||||
destination: Cesium.Cartesian3.fromDegrees(
|
||||
destination: geo.cartesian3.fromDegrees(
|
||||
camera.lon,
|
||||
camera.lat,
|
||||
camera.altitude_m,
|
||||
),
|
||||
orientation: {
|
||||
heading: Cesium.Math.toRadians(camera.heading_deg),
|
||||
pitch: Cesium.Math.toRadians(camera.pitch_deg),
|
||||
heading: geo.math.toRadians(camera.heading_deg),
|
||||
pitch: geo.math.toRadians(camera.pitch_deg),
|
||||
roll: 0,
|
||||
},
|
||||
duration: FLIGHT_SECONDS,
|
||||
|
||||
@@ -20,6 +20,7 @@ import { SceneControls } from '../ui/scenes.js';
|
||||
import { buildPlaybackQueue, playSceneQueue } from '../director/playback.js';
|
||||
import { createScenePlaybackAdapter } from './playbackAdapter.js';
|
||||
import * as Cesium from 'cesium';
|
||||
import * as geo from '../geo/index.js';
|
||||
import {
|
||||
SCENE_APPEND_RECIPES,
|
||||
SCENE_RECIPES,
|
||||
@@ -1577,15 +1578,15 @@ export class SceneDirector {
|
||||
this.styleManager?.clearSearchedLocation?.();
|
||||
this.viewer.camera.cancelFlight?.();
|
||||
this.viewer.camera.setView({
|
||||
destination: Cesium.Cartesian3.fromDegrees(
|
||||
destination: geo.cartesian3.fromDegrees(
|
||||
cameraState.lon,
|
||||
cameraState.lat,
|
||||
cameraState.alt,
|
||||
),
|
||||
orientation: {
|
||||
heading: Cesium.Math.toRadians(cameraState.heading || 0),
|
||||
pitch: Cesium.Math.toRadians(cameraState.pitch ?? -35),
|
||||
roll: Cesium.Math.toRadians(cameraState.roll || 0),
|
||||
heading: geo.math.toRadians(cameraState.heading || 0),
|
||||
pitch: geo.math.toRadians(cameraState.pitch ?? -35),
|
||||
roll: geo.math.toRadians(cameraState.roll || 0),
|
||||
},
|
||||
});
|
||||
return true;
|
||||
@@ -2268,7 +2269,7 @@ export class SceneDirector {
|
||||
0.2,
|
||||
Number(durationSec) || DEFAULT_SHOT_DURATION_SEC,
|
||||
);
|
||||
const destination = Cesium.Cartesian3.fromDegrees(
|
||||
const destination = geo.cartesian3.fromDegrees(
|
||||
cameraState.lon,
|
||||
cameraState.lat,
|
||||
cameraState.alt,
|
||||
@@ -2288,9 +2289,9 @@ export class SceneDirector {
|
||||
this.viewer.camera.flyTo({
|
||||
destination,
|
||||
orientation: {
|
||||
heading: Cesium.Math.toRadians(cameraState.heading || 0),
|
||||
pitch: Cesium.Math.toRadians(cameraState.pitch ?? -35),
|
||||
roll: Cesium.Math.toRadians(cameraState.roll || 0),
|
||||
heading: geo.math.toRadians(cameraState.heading || 0),
|
||||
pitch: geo.math.toRadians(cameraState.pitch ?? -35),
|
||||
roll: geo.math.toRadians(cameraState.roll || 0),
|
||||
},
|
||||
duration,
|
||||
easingFunction: Cesium.EasingFunction.CUBIC_IN_OUT,
|
||||
|
||||
@@ -30,6 +30,7 @@ import {
|
||||
} from './cyberSonarControls.js';
|
||||
|
||||
import * as Cesium from 'cesium';
|
||||
import * as geo from '../geo/index.js';
|
||||
|
||||
import { aircraftTrackingTarget } from '../cockpitTracking.js';
|
||||
|
||||
@@ -1317,12 +1318,12 @@ export class StyleManager extends ShellFacade {
|
||||
const carto = this.viewer.camera.positionCartographic;
|
||||
if (!carto) return null;
|
||||
return {
|
||||
lat: Cesium.Math.toDegrees(carto.latitude),
|
||||
lon: Cesium.Math.toDegrees(carto.longitude),
|
||||
lat: geo.math.toDegrees(carto.latitude),
|
||||
lon: geo.math.toDegrees(carto.longitude),
|
||||
alt: carto.height,
|
||||
heading: Cesium.Math.toDegrees(this.viewer.camera.heading),
|
||||
pitch: Cesium.Math.toDegrees(this.viewer.camera.pitch),
|
||||
roll: Cesium.Math.toDegrees(this.viewer.camera.roll),
|
||||
heading: geo.math.toDegrees(this.viewer.camera.heading),
|
||||
pitch: geo.math.toDegrees(this.viewer.camera.pitch),
|
||||
roll: geo.math.toDegrees(this.viewer.camera.roll),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1335,15 +1336,15 @@ export class StyleManager extends ShellFacade {
|
||||
applyCameraState(cameraState, duration = 2.8) {
|
||||
if (!cameraState) return;
|
||||
this.viewer.camera.flyTo({
|
||||
destination: Cesium.Cartesian3.fromDegrees(
|
||||
destination: geo.cartesian3.fromDegrees(
|
||||
cameraState.lon,
|
||||
cameraState.lat,
|
||||
cameraState.alt,
|
||||
),
|
||||
orientation: {
|
||||
heading: Cesium.Math.toRadians(cameraState.heading || 0),
|
||||
pitch: Cesium.Math.toRadians(cameraState.pitch || -35),
|
||||
roll: Cesium.Math.toRadians(cameraState.roll || 0),
|
||||
heading: geo.math.toRadians(cameraState.heading || 0),
|
||||
pitch: geo.math.toRadians(cameraState.pitch || -35),
|
||||
roll: geo.math.toRadians(cameraState.roll || 0),
|
||||
},
|
||||
duration: Math.max(0.2, duration || 0),
|
||||
easingFunction: Cesium.EasingFunction.CUBIC_IN_OUT,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as Cesium from 'cesium';
|
||||
import * as geo from '../geo/index.js';
|
||||
import { isPickedWorldPosition } from '../data/scenePick.js';
|
||||
|
||||
function trackedTarget(viewer) {
|
||||
@@ -11,17 +12,13 @@ function trackedTarget(viewer) {
|
||||
);
|
||||
}
|
||||
|
||||
export const OBLIQUE_PITCH = Cesium.Math.toRadians(-35);
|
||||
export const STRAIGHT_DOWN_PITCH = Cesium.Math.toRadians(-89);
|
||||
const OBLIQUE_THRESHOLD = Cesium.Math.toRadians(-60);
|
||||
export const OBLIQUE_PITCH = geo.math.toRadians(-35);
|
||||
export const STRAIGHT_DOWN_PITCH = geo.math.toRadians(-89);
|
||||
const OBLIQUE_THRESHOLD = geo.math.toRadians(-60);
|
||||
|
||||
function normalizedHeading(heading) {
|
||||
const wrapped = Cesium.Math.zeroToTwoPi(
|
||||
Number.isFinite(heading) ? heading : 0,
|
||||
);
|
||||
return Math.abs(wrapped - Cesium.Math.TWO_PI) < Cesium.Math.EPSILON10
|
||||
? 0
|
||||
: wrapped;
|
||||
const wrapped = geo.math.zeroToTwoPi(Number.isFinite(heading) ? heading : 0);
|
||||
return Math.abs(wrapped - geo.math.TWO_PI) < geo.math.EPSILON10 ? 0 : wrapped;
|
||||
}
|
||||
|
||||
/** Return the world position under the center of the canvas, when available. */
|
||||
@@ -79,20 +76,20 @@ export function readCameraTargetFrame(viewer) {
|
||||
if (!camera || !target || !isPickedWorldPosition(camera.positionWC))
|
||||
return null;
|
||||
|
||||
const transform = Cesium.Transforms.eastNorthUpToFixedFrame(target);
|
||||
const inverse = Cesium.Matrix4.inverseTransformation(
|
||||
const transform = geo.transforms.eastNorthUpToFixedFrame(target);
|
||||
const inverse = geo.matrix4.inverseTransformation(
|
||||
transform,
|
||||
new Cesium.Matrix4(),
|
||||
geo.matrix4.create(),
|
||||
);
|
||||
const localOffset = Cesium.Matrix4.multiplyByPoint(
|
||||
const localOffset = geo.matrix4.multiplyByPoint(
|
||||
inverse,
|
||||
camera.positionWC,
|
||||
new Cesium.Cartesian3(),
|
||||
geo.cartesian3.create(),
|
||||
);
|
||||
const range = Cesium.Cartesian3.magnitude(localOffset);
|
||||
const range = geo.cartesian3.magnitude(localOffset);
|
||||
if (!Number.isFinite(range) || range < 1) return null;
|
||||
|
||||
const pitch = -Math.asin(Cesium.Math.clamp(localOffset.z / range, -1, 1));
|
||||
const pitch = -Math.asin(geo.math.clamp(localOffset.z / range, -1, 1));
|
||||
// Cesium places a lookAt camera at range * (-sin h cos p, -cos h cos p,
|
||||
// -sin p) in the target's east-north-up frame, so recovering h means
|
||||
// negating BOTH horizontal components. Negating only the north one reads
|
||||
@@ -100,7 +97,7 @@ export function readCameraTargetFrame(viewer) {
|
||||
// make north-up rotate the wrong way from three quarters of the compass.
|
||||
const targetHeading = Math.atan2(-localOffset.x, -localOffset.y);
|
||||
const heading = normalizedHeading(
|
||||
pitch < Cesium.Math.toRadians(-88.5) ? camera.heading : targetHeading,
|
||||
pitch < geo.math.toRadians(-88.5) ? camera.heading : targetHeading,
|
||||
);
|
||||
return { target, range, heading, pitch };
|
||||
}
|
||||
@@ -111,7 +108,7 @@ export function setCameraTargetFrame(viewer, frame) {
|
||||
if (!camera || !frame?.target || !Number.isFinite(frame.range)) return false;
|
||||
try {
|
||||
const trackedTransform = viewer.trackedEntity
|
||||
? Cesium.Matrix4.clone(camera.transform)
|
||||
? geo.matrix4.clone(camera.transform)
|
||||
: null;
|
||||
camera.lookAt(
|
||||
frame.target,
|
||||
@@ -128,9 +125,9 @@ export function setCameraTargetFrame(viewer, frame) {
|
||||
viewer.scene?.requestRender?.();
|
||||
return true;
|
||||
}
|
||||
const destination = Cesium.Cartesian3.clone(camera.positionWC);
|
||||
const direction = Cesium.Cartesian3.clone(camera.directionWC);
|
||||
const up = Cesium.Cartesian3.clone(camera.upWC);
|
||||
const destination = geo.cartesian3.clone(camera.positionWC);
|
||||
const direction = geo.cartesian3.clone(camera.directionWC);
|
||||
const up = geo.cartesian3.clone(camera.upWC);
|
||||
camera.lookAtTransform(Cesium.Matrix4.IDENTITY);
|
||||
if (destination && direction && up) {
|
||||
camera.setView({ destination, orientation: { direction, up } });
|
||||
@@ -179,7 +176,7 @@ export function resetCameraNorth(viewer) {
|
||||
}
|
||||
|
||||
function headingDegrees(camera) {
|
||||
return Cesium.Math.toDegrees(normalizedHeading(camera?.heading));
|
||||
return geo.math.toDegrees(normalizedHeading(camera?.heading));
|
||||
}
|
||||
|
||||
/** Ease an orbit without handing off the entity that owns the follow camera. */
|
||||
@@ -201,7 +198,7 @@ export function createCameraOrientationAnimator(
|
||||
const entity = viewer.trackedEntity;
|
||||
pending = destination;
|
||||
const start = now();
|
||||
const headingDelta = Cesium.Math.negativePiToPi(
|
||||
const headingDelta = geo.math.negativePiToPi(
|
||||
destination.heading - frame.heading,
|
||||
);
|
||||
remove = viewer.scene.preUpdate.addEventListener(() => {
|
||||
@@ -209,7 +206,7 @@ export function createCameraOrientationAnimator(
|
||||
cancel();
|
||||
return;
|
||||
}
|
||||
const progress = Cesium.Math.clamp((now() - start) / duration, 0, 1);
|
||||
const progress = geo.math.clamp((now() - start) / duration, 0, 1);
|
||||
const eased = Cesium.EasingFunction.CUBIC_IN_OUT(progress);
|
||||
const target = entity ? trackedTarget(viewer) : frame.target;
|
||||
if (
|
||||
@@ -218,7 +215,7 @@ export function createCameraOrientationAnimator(
|
||||
...frame,
|
||||
target,
|
||||
heading: frame.heading + headingDelta * eased,
|
||||
pitch: Cesium.Math.lerp(frame.pitch, destination.pitch, eased),
|
||||
pitch: geo.math.lerp(frame.pitch, destination.pitch, eased),
|
||||
})
|
||||
) {
|
||||
cancel();
|
||||
|
||||
+41
-45
@@ -1,5 +1,5 @@
|
||||
/** Camera placement, ground acquisition and motion correction for the Cockpit controller. */
|
||||
import * as Cesium from 'cesium';
|
||||
import * as geo from '../geo/index.js';
|
||||
import {
|
||||
cockpitAnchorCorrectionStep,
|
||||
cockpitGroundSafeHeight,
|
||||
@@ -77,7 +77,7 @@ export function update() {
|
||||
}
|
||||
|
||||
if (!this.cockpitAnchorValid) {
|
||||
Cesium.Cartesian3.clone(target, this.cockpitAnchor);
|
||||
geo.cartesian3.clone(target, this.cockpitAnchor);
|
||||
this.cockpitAnchorValid = true;
|
||||
}
|
||||
|
||||
@@ -88,8 +88,8 @@ export function update() {
|
||||
// display position at a bounded rate. This preserves the layer's required
|
||||
// 15/30-second interpolation and per-frame cache without exposing its
|
||||
// sample-boundary corrections to the camera.
|
||||
const headingRad = Cesium.Math.toRadians(this.heading ?? 0);
|
||||
const pitchRad = Cesium.Math.toRadians(COCKPIT_VIEW_PITCH_DEG);
|
||||
const headingRad = geo.math.toRadians(this.heading ?? 0);
|
||||
const pitchRad = geo.math.toRadians(COCKPIT_VIEW_PITCH_DEG);
|
||||
const speedMps = Number.isFinite(info.velocityMps)
|
||||
? Math.max(0, info.velocityMps)
|
||||
: 0;
|
||||
@@ -98,38 +98,34 @@ export function update() {
|
||||
// A feed backoff has no authoritative velocity epoch to advance from.
|
||||
// Hold the cockpit on the exact layer-rendered position so the camera
|
||||
// cannot coast away while the icon correctly remains fixed.
|
||||
Cesium.Cartesian3.clone(target, this.cockpitAnchor);
|
||||
geo.cartesian3.clone(target, this.cockpitAnchor);
|
||||
} else {
|
||||
Cesium.Transforms.eastNorthUpToFixedFrame(
|
||||
geo.transforms.eastNorthUpToFixedFrame(
|
||||
this.cockpitAnchor,
|
||||
Cesium.Ellipsoid.WGS84,
|
||||
geo.ellipsoid.WGS84,
|
||||
this.scratchEnu,
|
||||
);
|
||||
this.scratchLocal.x = Math.sin(headingRad);
|
||||
this.scratchLocal.y = Math.cos(headingRad);
|
||||
this.scratchLocal.z = 0;
|
||||
Cesium.Matrix4.multiplyByPointAsVector(
|
||||
geo.matrix4.multiplyByPointAsVector(
|
||||
this.scratchEnu,
|
||||
this.scratchLocal,
|
||||
this.scratchHorizontal,
|
||||
);
|
||||
Cesium.Cartesian3.normalize(this.scratchHorizontal, this.scratchHorizontal);
|
||||
Cesium.Cartesian3.multiplyByScalar(
|
||||
geo.cartesian3.normalize(this.scratchHorizontal, this.scratchHorizontal);
|
||||
geo.cartesian3.multiplyByScalar(
|
||||
this.scratchHorizontal,
|
||||
speedMps * dtSec,
|
||||
this.scratchAdvance,
|
||||
);
|
||||
Cesium.Cartesian3.add(
|
||||
geo.cartesian3.add(
|
||||
this.cockpitAnchor,
|
||||
this.scratchAdvance,
|
||||
this.cockpitAnchor,
|
||||
);
|
||||
Cesium.Cartesian3.subtract(
|
||||
target,
|
||||
this.cockpitAnchor,
|
||||
this.scratchCorrection,
|
||||
);
|
||||
const correctionDistanceM = Cesium.Cartesian3.magnitude(
|
||||
geo.cartesian3.subtract(target, this.cockpitAnchor, this.scratchCorrection);
|
||||
const correctionDistanceM = geo.cartesian3.magnitude(
|
||||
this.scratchCorrection,
|
||||
);
|
||||
const correctionStepM = cockpitAnchorCorrectionStep(
|
||||
@@ -138,12 +134,12 @@ export function update() {
|
||||
dtSec,
|
||||
);
|
||||
if (correctionStepM > 0 && correctionDistanceM > 0) {
|
||||
Cesium.Cartesian3.multiplyByScalar(
|
||||
geo.cartesian3.multiplyByScalar(
|
||||
this.scratchCorrection,
|
||||
correctionStepM / correctionDistanceM,
|
||||
this.scratchCorrection,
|
||||
);
|
||||
Cesium.Cartesian3.add(
|
||||
geo.cartesian3.add(
|
||||
this.cockpitAnchor,
|
||||
this.scratchCorrection,
|
||||
this.cockpitAnchor,
|
||||
@@ -156,14 +152,14 @@ export function update() {
|
||||
// between fixes. Clamp it against the same mesh-first shared floor used by
|
||||
// aircraft rendering. For a slow contact whose floor cell is still cold,
|
||||
// its already-clamped render position is a conservative temporary floor.
|
||||
const anchorCartographic = Cesium.Cartographic.fromCartesian(
|
||||
const anchorCartographic = geo.cartographic.fromCartesian(
|
||||
this.cockpitAnchor,
|
||||
Cesium.Ellipsoid.WGS84,
|
||||
geo.ellipsoid.WGS84,
|
||||
this.scratchAnchorCartographic,
|
||||
);
|
||||
const targetCartographic = Cesium.Cartographic.fromCartesian(
|
||||
const targetCartographic = geo.cartographic.fromCartesian(
|
||||
target,
|
||||
Cesium.Ellipsoid.WGS84,
|
||||
geo.ellipsoid.WGS84,
|
||||
this.scratchTargetCartographic,
|
||||
);
|
||||
let cockpitFloorM = this.services.cachedGroundFloor(
|
||||
@@ -189,8 +185,8 @@ export function update() {
|
||||
const viewerCartographic = this.viewer.camera.positionCartographic;
|
||||
this.services.sampleMeshFloorCells(this.viewer.scene, groundPoint, {
|
||||
excludeObjects: [this.trackedEntity],
|
||||
viewerLat: Cesium.Math.toDegrees(viewerCartographic.latitude),
|
||||
viewerLon: Cesium.Math.toDegrees(viewerCartographic.longitude),
|
||||
viewerLat: geo.math.toDegrees(viewerCartographic.latitude),
|
||||
viewerLon: geo.math.toDegrees(viewerCartographic.longitude),
|
||||
});
|
||||
}
|
||||
cockpitFloorM = this.services.cachedMeshFloor(
|
||||
@@ -252,7 +248,7 @@ export function update() {
|
||||
);
|
||||
if (minimumAnchorHeightM !== anchorCartographic.height) {
|
||||
anchorCartographic.height = minimumAnchorHeightM;
|
||||
Cesium.Ellipsoid.WGS84.cartographicToCartesian(
|
||||
geo.ellipsoid.WGS84.cartographicToCartesian(
|
||||
anchorCartographic,
|
||||
this.cockpitAnchor,
|
||||
);
|
||||
@@ -260,59 +256,59 @@ export function update() {
|
||||
}
|
||||
|
||||
// Rebuild the local frame at the stabilized anchor after advancing it.
|
||||
Cesium.Transforms.eastNorthUpToFixedFrame(
|
||||
geo.transforms.eastNorthUpToFixedFrame(
|
||||
this.cockpitAnchor,
|
||||
Cesium.Ellipsoid.WGS84,
|
||||
geo.ellipsoid.WGS84,
|
||||
this.scratchEnu,
|
||||
);
|
||||
this.scratchLocal.x = Math.sin(headingRad);
|
||||
this.scratchLocal.y = Math.cos(headingRad);
|
||||
this.scratchLocal.z = 0;
|
||||
Cesium.Matrix4.multiplyByPointAsVector(
|
||||
geo.matrix4.multiplyByPointAsVector(
|
||||
this.scratchEnu,
|
||||
this.scratchLocal,
|
||||
this.scratchHorizontal,
|
||||
);
|
||||
Cesium.Cartesian3.normalize(this.scratchHorizontal, this.scratchHorizontal);
|
||||
geo.cartesian3.normalize(this.scratchHorizontal, this.scratchHorizontal);
|
||||
|
||||
this.scratchLocal.x = Math.sin(headingRad) * Math.cos(pitchRad);
|
||||
this.scratchLocal.y = Math.cos(headingRad) * Math.cos(pitchRad);
|
||||
this.scratchLocal.z = Math.sin(pitchRad);
|
||||
Cesium.Matrix4.multiplyByPointAsVector(
|
||||
geo.matrix4.multiplyByPointAsVector(
|
||||
this.scratchEnu,
|
||||
this.scratchLocal,
|
||||
this.scratchForward,
|
||||
);
|
||||
Cesium.Cartesian3.normalize(this.scratchForward, this.scratchForward);
|
||||
geo.cartesian3.normalize(this.scratchForward, this.scratchForward);
|
||||
|
||||
this.scratchLocal.x = -Math.sin(headingRad) * Math.sin(pitchRad);
|
||||
this.scratchLocal.y = -Math.cos(headingRad) * Math.sin(pitchRad);
|
||||
this.scratchLocal.z = Math.cos(pitchRad);
|
||||
Cesium.Matrix4.multiplyByPointAsVector(
|
||||
geo.matrix4.multiplyByPointAsVector(
|
||||
this.scratchEnu,
|
||||
this.scratchLocal,
|
||||
this.scratchUp,
|
||||
);
|
||||
Cesium.Cartesian3.normalize(this.scratchUp, this.scratchUp);
|
||||
geo.cartesian3.normalize(this.scratchUp, this.scratchUp);
|
||||
|
||||
Cesium.Cartesian3.multiplyByScalar(
|
||||
geo.cartesian3.multiplyByScalar(
|
||||
this.scratchHorizontal,
|
||||
COCKPIT_FORWARD_OFFSET_M,
|
||||
this.scratchCamera,
|
||||
);
|
||||
Cesium.Cartesian3.add(
|
||||
geo.cartesian3.add(
|
||||
this.cockpitAnchor,
|
||||
this.scratchCamera,
|
||||
this.scratchCamera,
|
||||
);
|
||||
Cesium.Matrix4.getTranslation(this.scratchEnu, this.scratchTarget);
|
||||
Cesium.Cartesian3.normalize(this.scratchTarget, this.scratchTarget);
|
||||
Cesium.Cartesian3.multiplyByScalar(
|
||||
geo.matrix4.getTranslation(this.scratchEnu, this.scratchTarget);
|
||||
geo.cartesian3.normalize(this.scratchTarget, this.scratchTarget);
|
||||
geo.cartesian3.multiplyByScalar(
|
||||
this.scratchTarget,
|
||||
COCKPIT_UP_OFFSET_M,
|
||||
this.scratchTarget,
|
||||
);
|
||||
Cesium.Cartesian3.add(
|
||||
geo.cartesian3.add(
|
||||
this.scratchCamera,
|
||||
this.scratchTarget,
|
||||
this.scratchCamera,
|
||||
@@ -320,14 +316,14 @@ export function update() {
|
||||
|
||||
// Recheck at the final forward-offset camera coordinate because a taxiing
|
||||
// aircraft can cross into an adjacent coarse floor cell between updates.
|
||||
const cameraCartographic = Cesium.Cartographic.fromCartesian(
|
||||
const cameraCartographic = geo.cartographic.fromCartesian(
|
||||
this.scratchCamera,
|
||||
Cesium.Ellipsoid.WGS84,
|
||||
geo.ellipsoid.WGS84,
|
||||
this.scratchCameraCartographic,
|
||||
);
|
||||
if (cameraCartographic) {
|
||||
const cameraLat = Cesium.Math.toDegrees(cameraCartographic.latitude);
|
||||
const cameraLon = Cesium.Math.toDegrees(cameraCartographic.longitude);
|
||||
const cameraLat = geo.math.toDegrees(cameraCartographic.latitude);
|
||||
const cameraLon = geo.math.toDegrees(cameraCartographic.longitude);
|
||||
const cameraFloorM = this.services.cachedGroundFloor(cameraLat, cameraLon);
|
||||
if (Number.isFinite(cameraFloorM)) {
|
||||
cockpitFloorM = Math.max(
|
||||
@@ -342,7 +338,7 @@ export function update() {
|
||||
);
|
||||
if (safeHeightM !== cameraCartographic.height) {
|
||||
cameraCartographic.height = safeHeightM;
|
||||
Cesium.Ellipsoid.WGS84.cartographicToCartesian(
|
||||
geo.ellipsoid.WGS84.cartographicToCartesian(
|
||||
cameraCartographic,
|
||||
this.scratchCamera,
|
||||
);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/** Contact readouts and nearby-signal presentation for the Cockpit controller. */
|
||||
import * as Cesium from 'cesium';
|
||||
import * as geo from '../geo/index.js';
|
||||
import {
|
||||
bearingBetweenCoordinates,
|
||||
formatCockpitContextScope,
|
||||
@@ -117,13 +117,13 @@ export function updateContext(info, heading) {
|
||||
Number.isFinite(info.latitude) &&
|
||||
Number.isFinite(info.longitude)
|
||||
) {
|
||||
const cartographic = Cesium.Cartographic.fromCartesian(closest.position);
|
||||
const cartographic = geo.cartographic.fromCartesian(closest.position);
|
||||
const bearing = cartographic
|
||||
? bearingBetweenCoordinates(
|
||||
info.latitude,
|
||||
info.longitude,
|
||||
Cesium.Math.toDegrees(cartographic.latitude),
|
||||
Cesium.Math.toDegrees(cartographic.longitude),
|
||||
geo.math.toDegrees(cartographic.latitude),
|
||||
geo.math.toDegrees(cartographic.longitude),
|
||||
)
|
||||
: null;
|
||||
relative = relativeBearing(bearing, heading);
|
||||
|
||||
+14
-14
@@ -44,7 +44,7 @@ import {
|
||||
syncSignalLayout,
|
||||
} from './cockpitLayout.js';
|
||||
import { onKeyDown } from './cockpitInput.js';
|
||||
import * as Cesium from 'cesium';
|
||||
import * as geo from '../geo/index.js';
|
||||
|
||||
export class CockpitViewController {
|
||||
constructor(
|
||||
@@ -209,20 +209,20 @@ export class CockpitViewController {
|
||||
this.regionalBriefSubjectId = null;
|
||||
this.contextLayoutFrame = null;
|
||||
this.contextLayoutStamp = null;
|
||||
this.scratchTarget = new Cesium.Cartesian3();
|
||||
this.cockpitAnchor = new Cesium.Cartesian3();
|
||||
this.scratchTarget = geo.cartesian3.create();
|
||||
this.cockpitAnchor = geo.cartesian3.create();
|
||||
this.cockpitAnchorValid = false;
|
||||
this.scratchCamera = new Cesium.Cartesian3();
|
||||
this.scratchAdvance = new Cesium.Cartesian3();
|
||||
this.scratchCorrection = new Cesium.Cartesian3();
|
||||
this.scratchForward = new Cesium.Cartesian3();
|
||||
this.scratchHorizontal = new Cesium.Cartesian3();
|
||||
this.scratchUp = new Cesium.Cartesian3();
|
||||
this.scratchLocal = new Cesium.Cartesian3();
|
||||
this.scratchEnu = new Cesium.Matrix4();
|
||||
this.scratchAnchorCartographic = new Cesium.Cartographic();
|
||||
this.scratchCameraCartographic = new Cesium.Cartographic();
|
||||
this.scratchTargetCartographic = new Cesium.Cartographic();
|
||||
this.scratchCamera = geo.cartesian3.create();
|
||||
this.scratchAdvance = geo.cartesian3.create();
|
||||
this.scratchCorrection = geo.cartesian3.create();
|
||||
this.scratchForward = geo.cartesian3.create();
|
||||
this.scratchHorizontal = geo.cartesian3.create();
|
||||
this.scratchUp = geo.cartesian3.create();
|
||||
this.scratchLocal = geo.cartesian3.create();
|
||||
this.scratchEnu = geo.matrix4.create();
|
||||
this.scratchAnchorCartographic = geo.cartographic.create();
|
||||
this.scratchCameraCartographic = geo.cartographic.create();
|
||||
this.scratchTargetCartographic = geo.cartographic.create();
|
||||
this._listenerRemovers = [];
|
||||
|
||||
// Camera mutations belong before scene update/culling. Changing the camera
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as Cesium from 'cesium';
|
||||
import * as geo from '../geo/index.js';
|
||||
import { createStateChannel } from '../app/stateChannel.js';
|
||||
import { LocationControls } from './location.js';
|
||||
|
||||
@@ -373,8 +374,8 @@ export class LocationNavigation {
|
||||
cancelled,
|
||||
heightKm: Math.round(GLOBE_VIEW.heightM / 1000),
|
||||
centeredOn: {
|
||||
latitude: Number(Cesium.Math.toDegrees(carto.latitude).toFixed(2)),
|
||||
longitude: Number(Cesium.Math.toDegrees(carto.longitude).toFixed(2)),
|
||||
latitude: Number(geo.math.toDegrees(carto.latitude).toFixed(2)),
|
||||
longitude: Number(geo.math.toDegrees(carto.longitude).toFixed(2)),
|
||||
},
|
||||
};
|
||||
this._resetGlobeBtn?.setAttribute(
|
||||
|
||||
+45
-50
@@ -9,6 +9,7 @@ import { resolveDeicticArgs } from './deixis.js';
|
||||
export { readLayerLifecycleSummary } from './layerSummary.js';
|
||||
import { defaultGeospatial } from '../search/defaults.js';
|
||||
import * as Cesium from 'cesium';
|
||||
import * as geo from '../geo/index.js';
|
||||
import {
|
||||
CITY_POIS,
|
||||
findPoiByName,
|
||||
@@ -2454,7 +2455,7 @@ async function frameOverhead(viewer, dataManager, styleManager, args = {}) {
|
||||
.filter((entry) => entry.position)
|
||||
.map((entry) => ({
|
||||
...entry,
|
||||
distance: Cesium.Cartesian3.distance(center, entry.position),
|
||||
distance: geo.cartesian3.distance(center, entry.position),
|
||||
}))
|
||||
.filter((entry) => entry.distance <= radiusKm * 1000)
|
||||
.sort((a, b) => a.distance - b.distance)
|
||||
@@ -2475,7 +2476,7 @@ async function frameOverhead(viewer, dataManager, styleManager, args = {}) {
|
||||
entries.map((entry) => entry.position),
|
||||
);
|
||||
sphere.radius = Math.max(sphere.radius * 1.25, 8000);
|
||||
const pitch = Cesium.Math.toRadians(isSatellites ? -35 : -62);
|
||||
const pitch = geo.math.toRadians(isSatellites ? -35 : -62);
|
||||
return runManagedVoiceNavigation(
|
||||
styleManager,
|
||||
'frame',
|
||||
@@ -2583,8 +2584,8 @@ export async function getBasemapLabelContext(
|
||||
};
|
||||
}
|
||||
|
||||
const latitude = Number(Cesium.Math.toDegrees(target.latitude).toFixed(6));
|
||||
const longitude = Number(Cesium.Math.toDegrees(target.longitude).toFixed(6));
|
||||
const latitude = Number(geo.math.toDegrees(target.latitude).toFixed(6));
|
||||
const longitude = Number(geo.math.toDegrees(target.longitude).toFixed(6));
|
||||
const cachedViewportPlaces = viewportPlacesFromCache(
|
||||
samples,
|
||||
cameraHeightM,
|
||||
@@ -2695,11 +2696,11 @@ function adjustCameraZoom(viewer, args) {
|
||||
if (!fraction) throw new Error(`Unknown zoom amount: ${args.amount}`);
|
||||
|
||||
const camera = viewer.camera;
|
||||
const beforePosition = Cesium.Cartesian3.clone(camera.positionWC);
|
||||
const beforePosition = geo.cartesian3.clone(camera.positionWC);
|
||||
const beforeHeightM = camera.positionCartographic.height;
|
||||
const target = getViewTargetCartesian(viewer);
|
||||
const targetDistanceM = target
|
||||
? Cesium.Cartesian3.distance(beforePosition, target)
|
||||
? geo.cartesian3.distance(beforePosition, target)
|
||||
: Math.max(100, beforeHeightM);
|
||||
const minimumDistanceM = direction === 'in' ? 20 : 50;
|
||||
const movementM = Math.max(minimumDistanceM, targetDistanceM * fraction);
|
||||
@@ -2726,7 +2727,7 @@ function adjustCameraZoom(viewer, args) {
|
||||
viewer.scene.requestRender();
|
||||
|
||||
const afterPosition = camera.positionWC;
|
||||
const movedM = Cesium.Cartesian3.distance(beforePosition, afterPosition);
|
||||
const movedM = geo.cartesian3.distance(beforePosition, afterPosition);
|
||||
const afterHeightM = camera.positionCartographic.height;
|
||||
const moved = movedM >= 0.5;
|
||||
return {
|
||||
@@ -2771,8 +2772,8 @@ function nextIssPass(viewer, dataManager, args) {
|
||||
if (latDeg == null || lonDeg == null) {
|
||||
const carto = viewer?.camera?.positionCartographic;
|
||||
if (!carto) throw new Error('Camera position unavailable');
|
||||
latDeg = Cesium.Math.toDegrees(carto.latitude);
|
||||
lonDeg = Cesium.Math.toDegrees(carto.longitude);
|
||||
latDeg = geo.math.toDegrees(carto.latitude);
|
||||
lonDeg = geo.math.toDegrees(carto.longitude);
|
||||
}
|
||||
const minElevDeg = Number.isFinite(args.minElevationDeg)
|
||||
? args.minElevationDeg
|
||||
@@ -3199,15 +3200,13 @@ function getCurrentViewState(
|
||||
dataManager,
|
||||
sceneDirector = null,
|
||||
) {
|
||||
const cartographic = Cesium.Cartographic.fromCartesian(
|
||||
viewer.camera.positionWC,
|
||||
);
|
||||
const cartographic = geo.cartographic.fromCartesian(viewer.camera.positionWC);
|
||||
return {
|
||||
ok: true,
|
||||
action: 'get_current_view_state',
|
||||
camera: {
|
||||
latitude: Cesium.Math.toDegrees(cartographic.latitude),
|
||||
longitude: Cesium.Math.toDegrees(cartographic.longitude),
|
||||
latitude: geo.math.toDegrees(cartographic.latitude),
|
||||
longitude: geo.math.toDegrees(cartographic.longitude),
|
||||
heightM: cartographic.height,
|
||||
},
|
||||
style: styleManager.activeStyle || 'normal',
|
||||
@@ -3440,7 +3439,7 @@ async function getTargetContext(
|
||||
}
|
||||
const hasPosition = Number.isFinite(lat) && Number.isFinite(lon);
|
||||
const viewTarget = hasPosition
|
||||
? Cesium.Cartographic.fromDegrees(lon, lat)
|
||||
? geo.cartographic.fromDegrees(lon, lat)
|
||||
: getViewTargetCartographic(viewer);
|
||||
const selected = describeTargetEntity(dataManager, target);
|
||||
const scene = await getSceneContext(
|
||||
@@ -3565,10 +3564,10 @@ async function aircraftProximityWindowForQuery(
|
||||
let lon = record?.lon;
|
||||
if (!Number.isFinite(lat) || !Number.isFinite(lon)) {
|
||||
const carto = item.position
|
||||
? Cesium.Cartographic.fromCartesian(item.position)
|
||||
? geo.cartographic.fromCartesian(item.position)
|
||||
: null;
|
||||
lat = carto ? Cesium.Math.toDegrees(carto.latitude) : null;
|
||||
lon = carto ? Cesium.Math.toDegrees(carto.longitude) : null;
|
||||
lat = carto ? geo.math.toDegrees(carto.latitude) : null;
|
||||
lon = carto ? geo.math.toDegrees(carto.longitude) : null;
|
||||
}
|
||||
const row = {
|
||||
...(record || {
|
||||
@@ -3727,10 +3726,10 @@ const SUBJECT_CENTER_TOLERANCE_KM = 1;
|
||||
function centerMatchesSubject(center, subjectPosition) {
|
||||
if (!Number.isFinite(center?.lat) || !Number.isFinite(center?.lon))
|
||||
return false;
|
||||
const carto = Cesium.Cartographic.fromCartesian(subjectPosition);
|
||||
const carto = geo.cartographic.fromCartesian(subjectPosition);
|
||||
if (!carto) return false;
|
||||
const subjectLat = Cesium.Math.toDegrees(carto.latitude);
|
||||
const subjectLon = Cesium.Math.toDegrees(carto.longitude);
|
||||
const subjectLat = geo.math.toDegrees(carto.latitude);
|
||||
const subjectLon = geo.math.toDegrees(carto.longitude);
|
||||
return (
|
||||
haversineKm(subjectLat, subjectLon, center.lat, center.lon) <=
|
||||
SUBJECT_CENTER_TOLERANCE_KM
|
||||
@@ -3758,8 +3757,8 @@ function visibleEntityContexts(
|
||||
const height = canvas.clientHeight || canvas.height || 0;
|
||||
const centerX = width / 2;
|
||||
const centerY = height / 2;
|
||||
const targetLat = target ? Cesium.Math.toDegrees(target.latitude) : null;
|
||||
const targetLon = target ? Cesium.Math.toDegrees(target.longitude) : null;
|
||||
const targetLat = target ? geo.math.toDegrees(target.latitude) : null;
|
||||
const targetLon = target ? geo.math.toDegrees(target.longitude) : null;
|
||||
const store = getContextStore();
|
||||
const enabledLayerIds = new Set(
|
||||
dataManager
|
||||
@@ -3850,9 +3849,7 @@ async function getSceneContext(
|
||||
viewTarget = null,
|
||||
service = defaultGeospatial,
|
||||
) {
|
||||
const cartographic = Cesium.Cartographic.fromCartesian(
|
||||
viewer.camera.positionWC,
|
||||
);
|
||||
const cartographic = geo.cartographic.fromCartesian(viewer.camera.positionWC);
|
||||
const basemap = await getBasemapContext(viewer, viewTarget, service);
|
||||
const enabledLayers = dataManager
|
||||
.getAll()
|
||||
@@ -3865,10 +3862,8 @@ async function getSceneContext(
|
||||
}));
|
||||
return {
|
||||
camera: {
|
||||
latitude: Number(Cesium.Math.toDegrees(cartographic.latitude).toFixed(6)),
|
||||
longitude: Number(
|
||||
Cesium.Math.toDegrees(cartographic.longitude).toFixed(6),
|
||||
),
|
||||
latitude: Number(geo.math.toDegrees(cartographic.latitude).toFixed(6)),
|
||||
longitude: Number(geo.math.toDegrees(cartographic.longitude).toFixed(6)),
|
||||
heightM: Math.round(cartographic.height),
|
||||
},
|
||||
basemap,
|
||||
@@ -3885,7 +3880,7 @@ async function getBasemapContext(
|
||||
const { reverseGeocodeCache, nearbyPlacesCache } = cachesFor(service);
|
||||
const target = viewTarget;
|
||||
const samples = sampleViewportCartographics(viewer);
|
||||
const cameraCartographic = Cesium.Cartographic.fromCartesian(
|
||||
const cameraCartographic = geo.cartographic.fromCartesian(
|
||||
viewer.camera.positionWC,
|
||||
);
|
||||
const cameraHeightM = cameraCartographic.height;
|
||||
@@ -3915,8 +3910,8 @@ async function getBasemapContext(
|
||||
};
|
||||
}
|
||||
|
||||
const latitude = Number(Cesium.Math.toDegrees(target.latitude).toFixed(6));
|
||||
const longitude = Number(Cesium.Math.toDegrees(target.longitude).toFixed(6));
|
||||
const latitude = Number(geo.math.toDegrees(target.latitude).toFixed(6));
|
||||
const longitude = Number(geo.math.toDegrees(target.longitude).toFixed(6));
|
||||
const inferredCountry = inferCountryFromSamples(samples);
|
||||
const knownLandmarks = nearbyKnownLandmarks(
|
||||
latitude,
|
||||
@@ -4039,7 +4034,7 @@ function nearbyKnownLandmarks(latitude, longitude, cameraHeightM) {
|
||||
}
|
||||
|
||||
function haversineKm(lat1, lon1, lat2, lon2) {
|
||||
const toRad = (value) => Cesium.Math.toRadians(value);
|
||||
const toRad = (value) => geo.math.toRadians(value);
|
||||
const radiusKm = 6371.0088;
|
||||
const dLat = toRad(lat2 - lat1);
|
||||
const dLon = toRad(lon2 - lon1);
|
||||
@@ -4095,7 +4090,7 @@ function getViewTargetCartographic(viewer) {
|
||||
// center to project; normalize that to the same "no target" null the callers
|
||||
// already handle for a missed pick.
|
||||
const target = position
|
||||
? Cesium.Cartographic.fromCartesian(position) || null
|
||||
? geo.cartographic.fromCartesian(position) || null
|
||||
: null;
|
||||
viewTargetCache.set(viewer, {
|
||||
signature,
|
||||
@@ -4109,8 +4104,8 @@ function cameraViewSignature(viewer) {
|
||||
const camera = viewer.camera;
|
||||
const cartographic = camera.positionCartographic;
|
||||
return [
|
||||
Cesium.Math.toDegrees(cartographic.latitude).toFixed(5),
|
||||
Cesium.Math.toDegrees(cartographic.longitude).toFixed(5),
|
||||
geo.math.toDegrees(cartographic.latitude).toFixed(5),
|
||||
geo.math.toDegrees(cartographic.longitude).toFixed(5),
|
||||
Math.round(cartographic.height / 2),
|
||||
camera.heading.toFixed(3),
|
||||
camera.pitch.toFixed(3),
|
||||
@@ -4189,15 +4184,15 @@ function sampleViewportCartographics(viewer) {
|
||||
const samples = [];
|
||||
for (const [x, y] of points) {
|
||||
const cartesian = viewer.camera.pickEllipsoid(
|
||||
new Cesium.Cartesian2(width * x, height * y),
|
||||
geo.cartesian2.create(width * x, height * y),
|
||||
Cesium.Ellipsoid.WGS84,
|
||||
);
|
||||
if (!isPickedWorldPosition(cartesian)) continue;
|
||||
const carto = Cesium.Cartographic.fromCartesian(cartesian);
|
||||
const carto = geo.cartographic.fromCartesian(cartesian);
|
||||
if (!carto) continue;
|
||||
samples.push({
|
||||
latitude: Number(Cesium.Math.toDegrees(carto.latitude).toFixed(4)),
|
||||
longitude: Number(Cesium.Math.toDegrees(carto.longitude).toFixed(4)),
|
||||
latitude: Number(geo.math.toDegrees(carto.latitude).toFixed(4)),
|
||||
longitude: Number(geo.math.toDegrees(carto.longitude).toFixed(4)),
|
||||
});
|
||||
}
|
||||
return samples;
|
||||
@@ -4466,7 +4461,7 @@ async function resolveWithin(promise, timeoutMs, fallback) {
|
||||
function approximateCoordinateDistanceSq(latA, lonA, latB, lonB) {
|
||||
const latDelta = latB - latA;
|
||||
const lonDelta =
|
||||
(lonB - lonA) * Math.cos(Cesium.Math.toRadians((latA + latB) / 2));
|
||||
(lonB - lonA) * Math.cos(geo.math.toRadians((latA + latB) / 2));
|
||||
return latDelta * latDelta + lonDelta * lonDelta;
|
||||
}
|
||||
|
||||
@@ -4515,17 +4510,17 @@ function summarizeEntity(viewer, entity, { includeProperties = false } = {}) {
|
||||
entity.__localBaseCartesian ||
|
||||
entity.position?.getValue?.(now) ||
|
||||
polygonCenter(entity, now);
|
||||
const carto = position ? Cesium.Cartographic.fromCartesian(position) : null;
|
||||
const carto = position ? geo.cartographic.fromCartesian(position) : null;
|
||||
return {
|
||||
id: String(entity.id || ''),
|
||||
name: label || layerTitle(layerId),
|
||||
layerId,
|
||||
layerName: layerTitle(layerId),
|
||||
latitude: carto
|
||||
? Number(Cesium.Math.toDegrees(carto.latitude).toFixed(6))
|
||||
? Number(geo.math.toDegrees(carto.latitude).toFixed(6))
|
||||
: null,
|
||||
longitude: carto
|
||||
? Number(Cesium.Math.toDegrees(carto.longitude).toFixed(6))
|
||||
? Number(geo.math.toDegrees(carto.longitude).toFixed(6))
|
||||
: null,
|
||||
properties: includeProperties ? compactProperties(props) : undefined,
|
||||
};
|
||||
@@ -4747,11 +4742,11 @@ function analystProviders(
|
||||
?.module?.getContextSnapshot?.();
|
||||
const subject = snapshot?.subject;
|
||||
if (!subject?.position) return null;
|
||||
const carto = Cesium.Cartographic.fromCartesian(subject.position);
|
||||
const carto = geo.cartographic.fromCartesian(subject.position);
|
||||
if (!carto) return null;
|
||||
return {
|
||||
lat: Cesium.Math.toDegrees(carto.latitude),
|
||||
lon: Cesium.Math.toDegrees(carto.longitude),
|
||||
lat: geo.math.toDegrees(carto.latitude),
|
||||
lon: geo.math.toDegrees(carto.longitude),
|
||||
label: subject.label || subject.id || null,
|
||||
};
|
||||
},
|
||||
@@ -4762,8 +4757,8 @@ function analystProviders(
|
||||
// country-level asks sweep wide. Clamped so "in view" is never absurd.
|
||||
const viewRadiusKm = Math.max(25, Math.min(2500, altKm * 1.6));
|
||||
return {
|
||||
lat: Cesium.Math.toDegrees(carto.latitude),
|
||||
lon: Cesium.Math.toDegrees(carto.longitude),
|
||||
lat: geo.math.toDegrees(carto.latitude),
|
||||
lon: geo.math.toDegrees(carto.longitude),
|
||||
viewRadiusKm,
|
||||
};
|
||||
},
|
||||
|
||||
@@ -3,6 +3,7 @@ import { createStandalonePlaceSearch } from '../standalone/placeSearch.js';
|
||||
import { test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import * as Cesium from 'cesium';
|
||||
import * as geo from '../geo/index.js';
|
||||
import { CCTV_FOCUS_RESULT } from '../data/cctv.js';
|
||||
import { getContextStore, registerEntityContext } from '../data/contextStore.js';
|
||||
import { DataLayerManager } from '../data/manager.js';
|
||||
@@ -2820,7 +2821,8 @@ test('a nested Cockpit rollback result is translated too', async () => {
|
||||
* analyst's 2 000-record last-fix slice). These pin the unified engine.
|
||||
*/
|
||||
function awarenessSubjectHarness({ subject, flights = [], military = [] }) {
|
||||
const position = subject ? { __subject: true } : null;
|
||||
// The Contacts subject sits at 29.9 N, 97.9 W, 9 000 m.
|
||||
const position = subject ? geo.cartesian3.fromDegrees(-97.9, 29.9, 9000) : null;
|
||||
const snapshotFlights = flights.slice(0, 20_000);
|
||||
const snapshotMilitary = military.slice(0, 20_000);
|
||||
return {
|
||||
@@ -2887,7 +2889,6 @@ async function withAwareness(harness, run) {
|
||||
aircraftSnapshot: awareness.getAircraftQuerySnapshot,
|
||||
flightsNearby: flightsLayer.getNearby,
|
||||
militaryNearby: militaryLayer.getNearby,
|
||||
cartoFrom: Cesium.Cartographic.fromCartesian,
|
||||
};
|
||||
awareness.getContextSnapshot = () => harness.snapshot;
|
||||
awareness.getAircraftQuerySnapshot = () => {
|
||||
@@ -2920,11 +2921,6 @@ async function withAwareness(harness, run) {
|
||||
};
|
||||
flightsLayer.getNearby = () => harness.flights.slice();
|
||||
militaryLayer.getNearby = () => harness.military.slice();
|
||||
Cesium.Cartographic.fromCartesian = (value) => (
|
||||
value?.__subject
|
||||
? { latitude: Cesium.Math.toRadians(29.9), longitude: Cesium.Math.toRadians(-97.9), height: 9000 }
|
||||
: originals.cartoFrom(value)
|
||||
);
|
||||
try {
|
||||
return await run(awareness);
|
||||
} finally {
|
||||
@@ -2932,7 +2928,6 @@ async function withAwareness(harness, run) {
|
||||
awareness.getAircraftQuerySnapshot = originals.aircraftSnapshot;
|
||||
flightsLayer.getNearby = originals.flightsNearby;
|
||||
militaryLayer.getNearby = originals.militaryNearby;
|
||||
Cesium.Cartographic.fromCartesian = originals.cartoFrom;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import * as Cesium from 'cesium';
|
||||
import * as geo from '../geo/index.js';
|
||||
import { resolvePickedContext } from '../data/pickedContext.js';
|
||||
import { cameraPoseKey } from './pointerContext.js';
|
||||
import * as defaultAnnotationResolver from '../annotations/annotationResolver.js';
|
||||
@@ -34,7 +34,7 @@ export function createPointerPicker({
|
||||
if (!width || !height) return null;
|
||||
let picked = null;
|
||||
try {
|
||||
picked = scene.pick(new Cesium.Cartesian2(x, y));
|
||||
picked = scene.pick(geo.cartesian2.create(x, y));
|
||||
} catch {
|
||||
picked = null;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user