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