mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-06 11:24:00 +00:00
refactor(camera,data): take vector maths from src/geo
Move the Cartesian3/Cartographic/Matrix/Quaternion/Transforms/Math calls of the first batch (src/data motion, anchor, tracked-camera and icon helpers; the root camera, locations, HUD, share-link, world-focus, ground-guard, orbit and cloud modules; services/groundSnap) to src/geo. Behaviour is unchanged: same argument order, same `result` semantics. Kept on Cesium: out-of-scope classes (JulianDate, Axis, HeadingPitchRange, BoundingSphere, Rectangle, EasingFunction, EllipsoidalOccluder with its WGS84 and seed vector, SceneTransforms) and Matrix4.IDENTITY wherever it is handed straight to a Cesium camera call (locations.test pins its identity). synthesizeForwardKinematicsFix now returns a plain position, so the two snapshot renderers clone it with the static Cesium.Cartesian3.clone instead of the instance method. The package-boundary groups that reach these modules now own the src/geo files.
This commit is contained in:
1 parent
4a92ed8377
commit
d886be68a8
17 files changed
+481
-285
No files matched your search
+210
-14
@@ -668,7 +668,21 @@
|
|||||||
"src/ui/localSdrControls.js",
|
"src/ui/localSdrControls.js",
|
||||||
"src/layers/localAdsb/feedNames.js",
|
"src/layers/localAdsb/feedNames.js",
|
||||||
"src/ui/localSdrPresentation.js",
|
"src/ui/localSdrPresentation.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"]
|
||||||
},
|
},
|
||||||
@@ -828,7 +842,21 @@
|
|||||||
"src/layers/flights/snapshotRenderer.js",
|
"src/layers/flights/snapshotRenderer.js",
|
||||||
"src/layers/flights/modelSpec.js",
|
"src/layers/flights/modelSpec.js",
|
||||||
"src/data/inputOwnership.js",
|
"src/data/inputOwnership.js",
|
||||||
"src/data/modelEligibility.js"
|
"src/data/modelEligibility.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"]
|
||||||
},
|
},
|
||||||
@@ -867,7 +895,21 @@
|
|||||||
"src/layers/military/recordPolicy.js",
|
"src/layers/military/recordPolicy.js",
|
||||||
"src/layers/military/snapshotRenderer.js",
|
"src/layers/military/snapshotRenderer.js",
|
||||||
"src/data/inputOwnership.js",
|
"src/data/inputOwnership.js",
|
||||||
"src/data/modelEligibility.js"
|
"src/data/modelEligibility.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"]
|
||||||
},
|
},
|
||||||
@@ -894,7 +936,21 @@
|
|||||||
"src/data/trackingClickGesture.js",
|
"src/data/trackingClickGesture.js",
|
||||||
"src/layers/aircraft/classification.js",
|
"src/layers/aircraft/classification.js",
|
||||||
"src/layers/aircraft/index.js",
|
"src/layers/aircraft/index.js",
|
||||||
"src/data/inputOwnership.js"
|
"src/data/inputOwnership.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"]
|
||||||
},
|
},
|
||||||
@@ -920,7 +976,21 @@
|
|||||||
"src/layers/vessels/records.js",
|
"src/layers/vessels/records.js",
|
||||||
"src/layers/vessels/recordPolicy.js",
|
"src/layers/vessels/recordPolicy.js",
|
||||||
"src/layers/vessels/snapshotRenderer.js",
|
"src/layers/vessels/snapshotRenderer.js",
|
||||||
"src/data/inputOwnership.js"
|
"src/data/inputOwnership.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"]
|
||||||
},
|
},
|
||||||
@@ -966,7 +1036,21 @@
|
|||||||
"src/layers/firms/source.js",
|
"src/layers/firms/source.js",
|
||||||
"src/layers/firms/state.js",
|
"src/layers/firms/state.js",
|
||||||
"src/layers/firms/viewport.js",
|
"src/layers/firms/viewport.js",
|
||||||
"src/data/inputOwnership.js"
|
"src/data/inputOwnership.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"]
|
||||||
},
|
},
|
||||||
@@ -1081,7 +1165,21 @@
|
|||||||
"src/layers/awareness/state.js",
|
"src/layers/awareness/state.js",
|
||||||
"src/layers/awareness/subject.js",
|
"src/layers/awareness/subject.js",
|
||||||
"src/layers/awareness/testing.js",
|
"src/layers/awareness/testing.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"]
|
||||||
},
|
},
|
||||||
@@ -1186,7 +1284,21 @@
|
|||||||
"src/overlays/worldOverlayTokens.js",
|
"src/overlays/worldOverlayTokens.js",
|
||||||
"src/data/cctvFootprint.js",
|
"src/data/cctvFootprint.js",
|
||||||
"src/data/inputOwnership.js",
|
"src/data/inputOwnership.js",
|
||||||
"src/layers/cctv/sourcePolicy.js"
|
"src/layers/cctv/sourcePolicy.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": ["hls.js", "cesium"]
|
"external": ["hls.js", "cesium"]
|
||||||
},
|
},
|
||||||
@@ -1287,7 +1399,21 @@
|
|||||||
"src/layers/radio/tuningNoise.js",
|
"src/layers/radio/tuningNoise.js",
|
||||||
"src/layers/radio/volume.js",
|
"src/layers/radio/volume.js",
|
||||||
"src/ui/radioTunerModel.js",
|
"src/ui/radioTunerModel.js",
|
||||||
"src/data/inputOwnership.js"
|
"src/data/inputOwnership.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"]
|
||||||
},
|
},
|
||||||
@@ -2209,7 +2335,21 @@
|
|||||||
"src/tools/functions.js",
|
"src/tools/functions.js",
|
||||||
"src/voice/actionSchemas.js",
|
"src/voice/actionSchemas.js",
|
||||||
"src/view/index.js",
|
"src/view/index.js",
|
||||||
"src/app/embed.js"
|
"src/app/embed.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": [
|
"external": [
|
||||||
"hls.js",
|
"hls.js",
|
||||||
@@ -2736,7 +2876,21 @@
|
|||||||
"src/data/local_data/osm_military_names/names.json",
|
"src/data/local_data/osm_military_names/names.json",
|
||||||
"src/layers/installations/namedMarkers.js",
|
"src/layers/installations/namedMarkers.js",
|
||||||
"src/data/infrastructureOverlayEntry.js",
|
"src/data/infrastructureOverlayEntry.js",
|
||||||
"src/sources/infrastructureData.js"
|
"src/sources/infrastructureData.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": [
|
"external": [
|
||||||
"hls.js",
|
"hls.js",
|
||||||
@@ -2801,7 +2955,21 @@
|
|||||||
"src/sources/overpassFeatures.js",
|
"src/sources/overpassFeatures.js",
|
||||||
"src/sources/featureSource.js",
|
"src/sources/featureSource.js",
|
||||||
"src/sources/capability.js",
|
"src/sources/capability.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": [
|
"external": [
|
||||||
"cesium",
|
"cesium",
|
||||||
@@ -3238,7 +3406,21 @@
|
|||||||
"src/sources/overpassFeaturesRecords.js",
|
"src/sources/overpassFeaturesRecords.js",
|
||||||
"src/sources/overpassFeatures.js",
|
"src/sources/overpassFeatures.js",
|
||||||
"src/sources/featureSource.js",
|
"src/sources/featureSource.js",
|
||||||
"src/sources/capability.js"
|
"src/sources/capability.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", "egm96-universal", "pbf"]
|
"external": ["cesium", "egm96-universal", "pbf"]
|
||||||
},
|
},
|
||||||
@@ -3275,7 +3457,21 @@
|
|||||||
"scripts/qa-transit-controls.mjs",
|
"scripts/qa-transit-controls.mjs",
|
||||||
"scripts/qa-transit-browser.mjs",
|
"scripts/qa-transit-browser.mjs",
|
||||||
"src/layers/transit/source.js",
|
"src/layers/transit/source.js",
|
||||||
"src/sources/transitHistory.js"
|
"src/sources/transitHistory.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", "pbf"]
|
"external": ["cesium", "pbf"]
|
||||||
},
|
},
|
||||||
|
|||||||
+16
-15
@@ -1,4 +1,5 @@
|
|||||||
import * as Cesium from 'cesium';
|
import * as Cesium from 'cesium';
|
||||||
|
import * as geo from './geo/index.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Camera presets for notable locations.
|
* Camera presets for notable locations.
|
||||||
@@ -6,26 +7,26 @@ import * as Cesium from 'cesium';
|
|||||||
*/
|
*/
|
||||||
export const CAMERA_PRESETS = {
|
export const CAMERA_PRESETS = {
|
||||||
austin: {
|
austin: {
|
||||||
destination: Cesium.Cartesian3.fromDegrees(-97.7431, 30.2672, 800),
|
destination: geo.cartesian3.fromDegrees(-97.7431, 30.2672, 800),
|
||||||
orientation: {
|
orientation: {
|
||||||
heading: Cesium.Math.toRadians(0),
|
heading: geo.math.toRadians(0),
|
||||||
pitch: Cesium.Math.toRadians(-35),
|
pitch: geo.math.toRadians(-35),
|
||||||
roll: 0.0,
|
roll: 0.0,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
sf: {
|
sf: {
|
||||||
destination: Cesium.Cartesian3.fromDegrees(-122.4194, 37.7749, 1000),
|
destination: geo.cartesian3.fromDegrees(-122.4194, 37.7749, 1000),
|
||||||
orientation: {
|
orientation: {
|
||||||
heading: Cesium.Math.toRadians(30),
|
heading: geo.math.toRadians(30),
|
||||||
pitch: Cesium.Math.toRadians(-30),
|
pitch: geo.math.toRadians(-30),
|
||||||
roll: 0.0,
|
roll: 0.0,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
nyc: {
|
nyc: {
|
||||||
destination: Cesium.Cartesian3.fromDegrees(-73.9857, 40.7484, 1200),
|
destination: geo.cartesian3.fromDegrees(-73.9857, 40.7484, 1200),
|
||||||
orientation: {
|
orientation: {
|
||||||
heading: Cesium.Math.toRadians(-20),
|
heading: geo.math.toRadians(-20),
|
||||||
pitch: Cesium.Math.toRadians(-30),
|
pitch: geo.math.toRadians(-30),
|
||||||
roll: 0.0,
|
roll: 0.0,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -53,10 +54,10 @@ export function flyToPreset(viewer, presetName, duration = 3.0) {
|
|||||||
export function flyToAustin(viewer) {
|
export function flyToAustin(viewer) {
|
||||||
// Start from a high altitude, then fly down
|
// Start from a high altitude, then fly down
|
||||||
viewer.camera.setView({
|
viewer.camera.setView({
|
||||||
destination: Cesium.Cartesian3.fromDegrees(-97.7431, 30.2672, 25000),
|
destination: geo.cartesian3.fromDegrees(-97.7431, 30.2672, 25000),
|
||||||
orientation: {
|
orientation: {
|
||||||
heading: Cesium.Math.toRadians(0),
|
heading: geo.math.toRadians(0),
|
||||||
pitch: Cesium.Math.toRadians(-90),
|
pitch: geo.math.toRadians(-90),
|
||||||
roll: 0.0,
|
roll: 0.0,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -65,10 +66,10 @@ export function flyToAustin(viewer) {
|
|||||||
const timer = setTimeout(() => {
|
const timer = setTimeout(() => {
|
||||||
if (viewer.isDestroyed()) return;
|
if (viewer.isDestroyed()) return;
|
||||||
viewer.camera.flyTo({
|
viewer.camera.flyTo({
|
||||||
destination: Cesium.Cartesian3.fromDegrees(-97.7431, 30.2672, 600),
|
destination: geo.cartesian3.fromDegrees(-97.7431, 30.2672, 600),
|
||||||
orientation: {
|
orientation: {
|
||||||
heading: Cesium.Math.toRadians(15),
|
heading: geo.math.toRadians(15),
|
||||||
pitch: Cesium.Math.toRadians(-30),
|
pitch: geo.math.toRadians(-30),
|
||||||
roll: 0.0,
|
roll: 0.0,
|
||||||
},
|
},
|
||||||
duration: 4.0,
|
duration: 4.0,
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
* held, so the correction reads as the shot settling.
|
* held, so the correction reads as the shot settling.
|
||||||
*/
|
*/
|
||||||
import * as Cesium from 'cesium';
|
import * as Cesium from 'cesium';
|
||||||
|
import * as geo from './geo/index.js';
|
||||||
import { ownCameraArrival } from './data/cameraArrival.js';
|
import { ownCameraArrival } from './data/cameraArrival.js';
|
||||||
|
|
||||||
/** Minimum eye height above the rendered surface for a usable view. */
|
/** Minimum eye height above the rendered surface for a usable view. */
|
||||||
@@ -25,7 +26,7 @@ export const GUARD_INTERVAL_MS = 600;
|
|||||||
/** Ignore sub-metre noise rather than nudging the camera forever. */
|
/** Ignore sub-metre noise rather than nudging the camera forever. */
|
||||||
const GUARD_EPSILON_M = 2;
|
const GUARD_EPSILON_M = 2;
|
||||||
|
|
||||||
const probeScratch = new Cesium.Cartographic();
|
const probeScratch = geo.cartographic.create();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Highest rendered surface across a few cells, with how many cells answered.
|
* Highest rendered surface across a few cells, with how many cells answered.
|
||||||
@@ -41,7 +42,7 @@ function sampleSurfaceM(scene, cells) {
|
|||||||
for (const cell of cells) {
|
for (const cell of cells) {
|
||||||
try {
|
try {
|
||||||
const height = scene.sampleHeight(
|
const height = scene.sampleHeight(
|
||||||
Cesium.Cartographic.fromDegrees(cell.lon, cell.lat, 0, probeScratch),
|
geo.cartographic.fromDegrees(cell.lon, cell.lat, 0, probeScratch),
|
||||||
);
|
);
|
||||||
if (!Number.isFinite(height)) continue;
|
if (!Number.isFinite(height)) continue;
|
||||||
sampled += 1;
|
sampled += 1;
|
||||||
@@ -152,8 +153,8 @@ export function guardCameraAboveGround(viewer, at, options = {}) {
|
|||||||
const carto = camera.positionCartographic;
|
const carto = camera.positionCartographic;
|
||||||
// The eye must clear both the framed target and the ground beneath it.
|
// The eye must clear both the framed target and the ground beneath it.
|
||||||
const below = {
|
const below = {
|
||||||
lat: Cesium.Math.toDegrees(carto.latitude),
|
lat: geo.math.toDegrees(carto.latitude),
|
||||||
lon: Cesium.Math.toDegrees(carto.longitude),
|
lon: geo.math.toDegrees(carto.longitude),
|
||||||
};
|
};
|
||||||
const { heightM, sampled } = sampleSurfaceM(viewer.scene, [
|
const { heightM, sampled } = sampleSurfaceM(viewer.scene, [
|
||||||
{ lat: at.lat, lon: at.lon },
|
{ lat: at.lat, lon: at.lon },
|
||||||
@@ -168,7 +169,7 @@ export function guardCameraAboveGround(viewer, at, options = {}) {
|
|||||||
if (deficit > 0) {
|
if (deficit > 0) {
|
||||||
stop();
|
stop();
|
||||||
camera.flyTo({
|
camera.flyTo({
|
||||||
destination: Cesium.Cartesian3.fromRadians(
|
destination: geo.cartesian3.fromRadians(
|
||||||
carto.longitude,
|
carto.longitude,
|
||||||
carto.latitude,
|
carto.latitude,
|
||||||
carto.height + deficit,
|
carto.height + deficit,
|
||||||
|
|||||||
+97
-105
@@ -16,6 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import * as Cesium from 'cesium';
|
import * as Cesium from 'cesium';
|
||||||
|
import * as geo from './geo/index.js';
|
||||||
import {
|
import {
|
||||||
holdContinuousRender,
|
holdContinuousRender,
|
||||||
releaseContinuousRender,
|
releaseContinuousRender,
|
||||||
@@ -36,8 +37,8 @@ const ONCE = {
|
|||||||
panViewFraction: 0.25,
|
panViewFraction: 0.25,
|
||||||
durationS: 0.9,
|
durationS: 0.9,
|
||||||
};
|
};
|
||||||
const PITCH_MIN = Cesium.Math.toRadians(-89);
|
const PITCH_MIN = geo.math.toRadians(-89);
|
||||||
const PITCH_MAX = Cesium.Math.toRadians(-5);
|
const PITCH_MAX = geo.math.toRadians(-5);
|
||||||
|
|
||||||
/* ── Route dolly: cinematic tuning ──────────────────────────────────────────
|
/* ── Route dolly: cinematic tuning ──────────────────────────────────────────
|
||||||
* Every knob an owner may want to retune lives in this block. The shaping is
|
* Every knob an owner may want to retune lives in this block. The shaping is
|
||||||
@@ -296,30 +297,30 @@ export const ROUTE_CINEMA = Object.freeze({
|
|||||||
|
|
||||||
/* ── Route dolly geometry ────────────────────────────────────────────────── */
|
/* ── Route dolly geometry ────────────────────────────────────────────────── */
|
||||||
|
|
||||||
const _arcA = new Cesium.Cartesian3();
|
const _arcA = geo.cartesian3.create();
|
||||||
const _arcB = new Cesium.Cartesian3();
|
const _arcB = geo.cartesian3.create();
|
||||||
const _chordVertical = new Cesium.Cartesian3();
|
const _chordVertical = geo.cartesian3.create();
|
||||||
const _turnCross = new Cesium.Cartesian3();
|
const _turnCross = geo.cartesian3.create();
|
||||||
const _framePos = new Cesium.Cartesian3();
|
const _framePos = geo.cartesian3.create();
|
||||||
const _frameAheadPos = new Cesium.Cartesian3();
|
const _frameAheadPos = geo.cartesian3.create();
|
||||||
const _frameUp = new Cesium.Cartesian3();
|
const _frameUp = geo.cartesian3.create();
|
||||||
const _frameIn = new Cesium.Cartesian3();
|
const _frameIn = geo.cartesian3.create();
|
||||||
const _frameOut = new Cesium.Cartesian3();
|
const _frameOut = geo.cartesian3.create();
|
||||||
const _frameGaze = new Cesium.Cartesian3();
|
const _frameGaze = geo.cartesian3.create();
|
||||||
const _frameRight = new Cesium.Cartesian3();
|
const _frameRight = geo.cartesian3.create();
|
||||||
const _frameLevelUp = new Cesium.Cartesian3();
|
const _frameLevelUp = geo.cartesian3.create();
|
||||||
const _frameDir = new Cesium.Cartesian3();
|
const _frameDir = geo.cartesian3.create();
|
||||||
const _frameEye = new Cesium.Cartesian3();
|
const _frameEye = geo.cartesian3.create();
|
||||||
const _frameBankedUp = new Cesium.Cartesian3();
|
const _frameBankedUp = geo.cartesian3.create();
|
||||||
const _frameCarto = new Cesium.Cartographic();
|
const _frameCarto = geo.cartographic.create();
|
||||||
const _frameAheadCarto = new Cesium.Cartographic();
|
const _frameAheadCarto = geo.cartographic.create();
|
||||||
const _bankQuat = new Cesium.Quaternion();
|
const _bankQuat = geo.quaternion.create();
|
||||||
const _bankMatrix = new Cesium.Matrix3();
|
const _bankMatrix = geo.matrix3.create();
|
||||||
const _headingQuat = new Cesium.Quaternion();
|
const _headingQuat = geo.quaternion.create();
|
||||||
const _headingMatrix = new Cesium.Matrix3();
|
const _headingMatrix = geo.matrix3.create();
|
||||||
const _warmPos = new Cesium.Cartesian3();
|
const _warmPos = geo.cartesian3.create();
|
||||||
const _warmCarto = new Cesium.Cartographic();
|
const _warmCarto = geo.cartographic.create();
|
||||||
const _probeCarto = new Cesium.Cartographic();
|
const _probeCarto = geo.cartographic.create();
|
||||||
|
|
||||||
/** Point at arc length `s` along the polyline (binary search — queries jump
|
/** Point at arc length `s` along the polyline (binary search — queries jump
|
||||||
* backwards for the inbound chord, so a forward cursor would not do). */
|
* backwards for the inbound chord, so a forward cursor would not do). */
|
||||||
@@ -336,23 +337,23 @@ function arcPoint(state, s, result) {
|
|||||||
const segLen = cumM[lo + 1] - cumM[lo];
|
const segLen = cumM[lo + 1] - cumM[lo];
|
||||||
const t =
|
const t =
|
||||||
segLen > 1e-6 ? Math.min(1, Math.max(0, (clamped - cumM[lo]) / segLen)) : 0;
|
segLen > 1e-6 ? Math.min(1, Math.max(0, (clamped - cumM[lo]) / segLen)) : 0;
|
||||||
return Cesium.Cartesian3.lerp(pts[lo], pts[lo + 1], t, result);
|
return geo.cartesian3.lerp(pts[lo], pts[lo + 1], t, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Unit horizontal direction from arc `sA` to arc `sB`, or null when degenerate. */
|
/** Unit horizontal direction from arc `sA` to arc `sB`, or null when degenerate. */
|
||||||
function horizontalChord(state, sA, sB, up, result) {
|
function horizontalChord(state, sA, sB, up, result) {
|
||||||
const a = arcPoint(state, sA, _arcA);
|
const a = arcPoint(state, sA, _arcA);
|
||||||
const b = arcPoint(state, sB, _arcB);
|
const b = arcPoint(state, sB, _arcB);
|
||||||
Cesium.Cartesian3.subtract(b, a, result);
|
geo.cartesian3.subtract(b, a, result);
|
||||||
const vertical = Cesium.Cartesian3.multiplyByScalar(
|
const vertical = geo.cartesian3.multiplyByScalar(
|
||||||
up,
|
up,
|
||||||
Cesium.Cartesian3.dot(result, up),
|
geo.cartesian3.dot(result, up),
|
||||||
_chordVertical,
|
_chordVertical,
|
||||||
);
|
);
|
||||||
Cesium.Cartesian3.subtract(result, vertical, result);
|
geo.cartesian3.subtract(result, vertical, result);
|
||||||
const len = Cesium.Cartesian3.magnitude(result);
|
const len = geo.cartesian3.magnitude(result);
|
||||||
if (!(len > 1e-3)) return null;
|
if (!(len > 1e-3)) return null;
|
||||||
return Cesium.Cartesian3.divideByScalar(result, len, result);
|
return geo.cartesian3.divideByScalar(result, len, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -368,9 +369,9 @@ function horizontalChord(state, sA, sB, up, result) {
|
|||||||
* @returns {number} Radians, + = right.
|
* @returns {number} Radians, + = right.
|
||||||
*/
|
*/
|
||||||
export function signedTurnRad(a, b, up) {
|
export function signedTurnRad(a, b, up) {
|
||||||
const cross = Cesium.Cartesian3.cross(a, b, _turnCross);
|
const cross = geo.cartesian3.cross(a, b, _turnCross);
|
||||||
const sinLeft = Cesium.Cartesian3.dot(cross, up);
|
const sinLeft = geo.cartesian3.dot(cross, up);
|
||||||
const cosTurn = Cesium.Cartesian3.dot(a, b);
|
const cosTurn = geo.cartesian3.dot(a, b);
|
||||||
if (cosTurn <= -1 + ANTIPODAL_EPS && Math.abs(sinLeft) < ANTIPODAL_EPS)
|
if (cosTurn <= -1 + ANTIPODAL_EPS && Math.abs(sinLeft) < ANTIPODAL_EPS)
|
||||||
return Math.PI;
|
return Math.PI;
|
||||||
return -Math.atan2(sinLeft, cosTurn);
|
return -Math.atan2(sinLeft, cosTurn);
|
||||||
@@ -403,13 +404,13 @@ export function routeCorridorCells(
|
|||||||
s += ROUTE_WARM_STEP_M
|
s += ROUTE_WARM_STEP_M
|
||||||
) {
|
) {
|
||||||
const point = arcPoint(state, s, _warmPos);
|
const point = arcPoint(state, s, _warmPos);
|
||||||
const carto = Cesium.Cartographic.fromCartesian(
|
const carto = geo.cartographic.fromCartesian(
|
||||||
point,
|
point,
|
||||||
Cesium.Ellipsoid.WGS84,
|
geo.ellipsoid.WGS84,
|
||||||
_warmCarto,
|
_warmCarto,
|
||||||
);
|
);
|
||||||
const lat = Number(Cesium.Math.toDegrees(carto.latitude).toFixed(3));
|
const lat = Number(geo.math.toDegrees(carto.latitude).toFixed(3));
|
||||||
const lon = Number(Cesium.Math.toDegrees(carto.longitude).toFixed(3));
|
const lon = Number(geo.math.toDegrees(carto.longitude).toFixed(3));
|
||||||
const key = `${lat},${lon}`;
|
const key = `${lat},${lon}`;
|
||||||
if (seen.has(key)) continue;
|
if (seen.has(key)) continue;
|
||||||
seen.add(key);
|
seen.add(key);
|
||||||
@@ -555,7 +556,7 @@ export function probeMeshFloorM(scene, cells) {
|
|||||||
let sampled = 0;
|
let sampled = 0;
|
||||||
for (const cell of cells) {
|
for (const cell of cells) {
|
||||||
try {
|
try {
|
||||||
const carto = Cesium.Cartographic.fromDegrees(
|
const carto = geo.cartographic.fromDegrees(
|
||||||
cell.lon,
|
cell.lon,
|
||||||
cell.lat,
|
cell.lat,
|
||||||
0,
|
0,
|
||||||
@@ -604,9 +605,9 @@ export function createRouteFlight({
|
|||||||
// the mean: routes under 10 m (slow) / 20 m (normal) / 45 m (fast) fly slower
|
// the mean: routes under 10 m (slow) / 20 m (normal) / 45 m (fast) fly slower
|
||||||
// than asked. Those are shorter than the camera is tall — nothing to see.
|
// than asked. Those are shorter than the camera is tall — nothing to see.
|
||||||
const durationS = Math.max(0.5, totalM / cruiseMps);
|
const durationS = Math.max(0.5, totalM / cruiseMps);
|
||||||
const pathHeightM = Cesium.Cartographic.fromCartesian(
|
const pathHeightM = geo.cartographic.fromCartesian(
|
||||||
pts[0],
|
pts[0],
|
||||||
Cesium.Ellipsoid.WGS84,
|
geo.ellipsoid.WGS84,
|
||||||
_warmCarto,
|
_warmCarto,
|
||||||
).height;
|
).height;
|
||||||
const state = {
|
const state = {
|
||||||
@@ -702,12 +703,12 @@ export function advanceRouteFlight(state, dt) {
|
|||||||
state.groundSpeedMps = cruiseMps * profile.speed;
|
state.groundSpeedMps = cruiseMps * profile.speed;
|
||||||
|
|
||||||
const pos = arcPoint(state, traveled, _framePos);
|
const pos = arcPoint(state, traveled, _framePos);
|
||||||
const carto = Cesium.Cartographic.fromCartesian(
|
const carto = geo.cartographic.fromCartesian(
|
||||||
pos,
|
pos,
|
||||||
Cesium.Ellipsoid.WGS84,
|
geo.ellipsoid.WGS84,
|
||||||
_frameCarto,
|
_frameCarto,
|
||||||
);
|
);
|
||||||
const up = Cesium.Ellipsoid.WGS84.geodeticSurfaceNormalCartographic(
|
const up = geo.ellipsoid.WGS84.geodeticSurfaceNormalCartographic(
|
||||||
carto,
|
carto,
|
||||||
_frameUp,
|
_frameUp,
|
||||||
);
|
);
|
||||||
@@ -731,7 +732,7 @@ export function advanceRouteFlight(state, dt) {
|
|||||||
);
|
);
|
||||||
const turnRateDegS =
|
const turnRateDegS =
|
||||||
inbound && outbound
|
inbound && outbound
|
||||||
? Cesium.Math.toDegrees(signedTurnRad(inbound, outbound, up)) /
|
? geo.math.toDegrees(signedTurnRad(inbound, outbound, up)) /
|
||||||
ROUTE_BANK_WINDOW_S
|
ROUTE_BANK_WINDOW_S
|
||||||
: 0;
|
: 0;
|
||||||
const bankTarget = routeBankTargetDeg(turnRateDegS, state.reducedMotion);
|
const bankTarget = routeBankTargetDeg(turnRateDegS, state.reducedMotion);
|
||||||
@@ -763,8 +764,7 @@ export function advanceRouteFlight(state, dt) {
|
|||||||
horizontalChord(state, traveled, traveled + lookaheadM, up, _frameGaze) ||
|
horizontalChord(state, traveled, traveled + lookaheadM, up, _frameGaze) ||
|
||||||
outbound ||
|
outbound ||
|
||||||
inbound;
|
inbound;
|
||||||
if (gaze && !state.headingDir)
|
if (gaze && !state.headingDir) state.headingDir = geo.cartesian3.clone(gaze);
|
||||||
state.headingDir = Cesium.Cartesian3.clone(gaze);
|
|
||||||
else if (gaze) {
|
else if (gaze) {
|
||||||
// Rotate the heading TOWARD the gaze about the local up, rather than
|
// Rotate the heading TOWARD the gaze about the local up, rather than
|
||||||
// lerping the two vectors. A Cartesian lerp cannot cross an antipodal pair
|
// lerping the two vectors. A Cartesian lerp cannot cross an antipodal pair
|
||||||
@@ -775,66 +775,62 @@ export function advanceRouteFlight(state, dt) {
|
|||||||
const turnToGaze = signedTurnRad(state.headingDir, gaze, up);
|
const turnToGaze = signedTurnRad(state.headingDir, gaze, up);
|
||||||
// signedTurnRad is + for a RIGHT turn; a positive rotation about up is a
|
// signedTurnRad is + for a RIGHT turn; a positive rotation about up is a
|
||||||
// LEFT turn, so the step is negated.
|
// LEFT turn, so the step is negated.
|
||||||
const rotation = Cesium.Matrix3.fromQuaternion(
|
const rotation = geo.matrix3.fromQuaternion(
|
||||||
Cesium.Quaternion.fromAxisAngle(up, -turnToGaze * k, _headingQuat),
|
geo.quaternion.fromAxisAngle(up, -turnToGaze * k, _headingQuat),
|
||||||
_headingMatrix,
|
_headingMatrix,
|
||||||
);
|
);
|
||||||
const turned = Cesium.Matrix3.multiplyByVector(
|
const turned = geo.matrix3.multiplyByVector(
|
||||||
rotation,
|
rotation,
|
||||||
state.headingDir,
|
state.headingDir,
|
||||||
_frameDir,
|
_frameDir,
|
||||||
);
|
);
|
||||||
const vertical = Cesium.Cartesian3.multiplyByScalar(
|
const vertical = geo.cartesian3.multiplyByScalar(
|
||||||
up,
|
up,
|
||||||
Cesium.Cartesian3.dot(turned, up),
|
geo.cartesian3.dot(turned, up),
|
||||||
_chordVertical,
|
_chordVertical,
|
||||||
);
|
);
|
||||||
Cesium.Cartesian3.subtract(turned, vertical, turned);
|
geo.cartesian3.subtract(turned, vertical, turned);
|
||||||
if (Cesium.Cartesian3.magnitude(turned) > 1e-6) {
|
if (geo.cartesian3.magnitude(turned) > 1e-6) {
|
||||||
Cesium.Cartesian3.normalize(turned, state.headingDir);
|
geo.cartesian3.normalize(turned, state.headingDir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// A path with no horizontal extent (identical lat/lon, differing heights)
|
// A path with no horizontal extent (identical lat/lon, differing heights)
|
||||||
// has no azimuth to fly: point east so the frame stays orthonormal.
|
// has no azimuth to fly: point east so the frame stays orthonormal.
|
||||||
if (!state.headingDir) {
|
if (!state.headingDir) {
|
||||||
const east = Cesium.Cartesian3.fromElements(-pos.y, pos.x, 0, _frameGaze);
|
const east = geo.cartesian3.fromElements(-pos.y, pos.x, 0, _frameGaze);
|
||||||
state.headingDir =
|
state.headingDir =
|
||||||
Cesium.Cartesian3.magnitude(east) > 1e-6
|
geo.cartesian3.magnitude(east) > 1e-6
|
||||||
? Cesium.Cartesian3.normalize(east, new Cesium.Cartesian3())
|
? geo.cartesian3.normalize(east, geo.cartesian3.create())
|
||||||
: Cesium.Cartesian3.fromElements(1, 0, 0, new Cesium.Cartesian3());
|
: geo.cartesian3.fromElements(1, 0, 0, geo.cartesian3.create());
|
||||||
}
|
}
|
||||||
const heading = state.headingDir;
|
const heading = state.headingDir;
|
||||||
|
|
||||||
// Locked pitch: heading gives the azimuth, the pitch never wanders.
|
// Locked pitch: heading gives the azimuth, the pitch never wanders.
|
||||||
const pitch = Cesium.Math.toRadians(ROUTE_PITCH_DEG);
|
const pitch = geo.math.toRadians(ROUTE_PITCH_DEG);
|
||||||
const direction = Cesium.Cartesian3.normalize(
|
const direction = geo.cartesian3.normalize(
|
||||||
Cesium.Cartesian3.add(
|
geo.cartesian3.add(
|
||||||
Cesium.Cartesian3.multiplyByScalar(heading, Math.cos(pitch), _frameDir),
|
geo.cartesian3.multiplyByScalar(heading, Math.cos(pitch), _frameDir),
|
||||||
Cesium.Cartesian3.multiplyByScalar(up, Math.sin(pitch), _frameLevelUp),
|
geo.cartesian3.multiplyByScalar(up, Math.sin(pitch), _frameLevelUp),
|
||||||
_frameDir,
|
_frameDir,
|
||||||
),
|
),
|
||||||
_frameDir,
|
_frameDir,
|
||||||
);
|
);
|
||||||
// Orthonormal camera frame, then roll it about its own forward axis: a
|
// Orthonormal camera frame, then roll it about its own forward axis: a
|
||||||
// positive rotation drops the right wing, which is what a right turn wants.
|
// positive rotation drops the right wing, which is what a right turn wants.
|
||||||
const right = Cesium.Cartesian3.normalize(
|
const right = geo.cartesian3.normalize(
|
||||||
Cesium.Cartesian3.cross(direction, up, _frameRight),
|
geo.cartesian3.cross(direction, up, _frameRight),
|
||||||
_frameRight,
|
_frameRight,
|
||||||
);
|
);
|
||||||
const levelUp = Cesium.Cartesian3.normalize(
|
const levelUp = geo.cartesian3.normalize(
|
||||||
Cesium.Cartesian3.cross(right, direction, _frameLevelUp),
|
geo.cartesian3.cross(right, direction, _frameLevelUp),
|
||||||
_frameLevelUp,
|
_frameLevelUp,
|
||||||
);
|
);
|
||||||
const bankRad = Cesium.Math.toRadians(appliedBankDeg);
|
const bankRad = geo.math.toRadians(appliedBankDeg);
|
||||||
let bankedUp = levelUp;
|
let bankedUp = levelUp;
|
||||||
if (Math.abs(bankRad) > 1e-6) {
|
if (Math.abs(bankRad) > 1e-6) {
|
||||||
const quat = Cesium.Quaternion.fromAxisAngle(direction, bankRad, _bankQuat);
|
const quat = geo.quaternion.fromAxisAngle(direction, bankRad, _bankQuat);
|
||||||
const rotation = Cesium.Matrix3.fromQuaternion(quat, _bankMatrix);
|
const rotation = geo.matrix3.fromQuaternion(quat, _bankMatrix);
|
||||||
bankedUp = Cesium.Matrix3.multiplyByVector(
|
bankedUp = geo.matrix3.multiplyByVector(rotation, levelUp, _frameBankedUp);
|
||||||
rotation,
|
|
||||||
levelUp,
|
|
||||||
_frameBankedUp,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keep the corridor ahead of the camera warm. The batch dedupes to coarse
|
// Keep the corridor ahead of the camera warm. The batch dedupes to coarse
|
||||||
@@ -850,19 +846,19 @@ export function advanceRouteFlight(state, dt) {
|
|||||||
let sampledFloor = Number.NaN;
|
let sampledFloor = Number.NaN;
|
||||||
if (typeof state.floorFn === 'function') {
|
if (typeof state.floorFn === 'function') {
|
||||||
const aheadPos = arcPoint(state, traveled + lookaheadM / 2, _frameAheadPos);
|
const aheadPos = arcPoint(state, traveled + lookaheadM / 2, _frameAheadPos);
|
||||||
const aheadCarto = Cesium.Cartographic.fromCartesian(
|
const aheadCarto = geo.cartographic.fromCartesian(
|
||||||
aheadPos,
|
aheadPos,
|
||||||
Cesium.Ellipsoid.WGS84,
|
geo.ellipsoid.WGS84,
|
||||||
_frameAheadCarto,
|
_frameAheadCarto,
|
||||||
);
|
);
|
||||||
try {
|
try {
|
||||||
const here = state.floorFn(
|
const here = state.floorFn(
|
||||||
Cesium.Math.toDegrees(carto.latitude),
|
geo.math.toDegrees(carto.latitude),
|
||||||
Cesium.Math.toDegrees(carto.longitude),
|
geo.math.toDegrees(carto.longitude),
|
||||||
);
|
);
|
||||||
const ahead = state.floorFn(
|
const ahead = state.floorFn(
|
||||||
Cesium.Math.toDegrees(aheadCarto.latitude),
|
geo.math.toDegrees(aheadCarto.latitude),
|
||||||
Cesium.Math.toDegrees(aheadCarto.longitude),
|
geo.math.toDegrees(aheadCarto.longitude),
|
||||||
);
|
);
|
||||||
const warm = [here, ahead].filter((value) => Number.isFinite(value));
|
const warm = [here, ahead].filter((value) => Number.isFinite(value));
|
||||||
if (warm.length) sampledFloor = Math.max(...warm);
|
if (warm.length) sampledFloor = Math.max(...warm);
|
||||||
@@ -926,11 +922,11 @@ export function advanceRouteFlight(state, dt) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
state.appliedHeightM = heightM;
|
state.appliedHeightM = heightM;
|
||||||
const eye = Cesium.Cartesian3.fromRadians(
|
const eye = geo.cartesian3.fromRadians(
|
||||||
carto.longitude,
|
carto.longitude,
|
||||||
carto.latitude,
|
carto.latitude,
|
||||||
heightM,
|
heightM,
|
||||||
Cesium.Ellipsoid.WGS84,
|
geo.ellipsoid.WGS84,
|
||||||
_frameEye,
|
_frameEye,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1019,7 +1015,7 @@ function levelCameraRoll() {
|
|||||||
try {
|
try {
|
||||||
const cam = _viewer?.camera;
|
const cam = _viewer?.camera;
|
||||||
if (!cam || typeof cam.setView !== 'function') return false;
|
if (!cam || typeof cam.setView !== 'function') return false;
|
||||||
const roll = Cesium.Math.negativePiToPi(cam.roll || 0);
|
const roll = geo.math.negativePiToPi(cam.roll || 0);
|
||||||
if (Math.abs(roll) < 1e-5) return false;
|
if (Math.abs(roll) < 1e-5) return false;
|
||||||
cam.setView({
|
cam.setView({
|
||||||
orientation: { heading: cam.heading, pitch: cam.pitch, roll: 0 },
|
orientation: { heading: cam.heading, pitch: cam.pitch, roll: 0 },
|
||||||
@@ -1123,9 +1119,9 @@ function onTick() {
|
|||||||
const target = _getTarget?.(_viewer);
|
const target = _getTarget?.(_viewer);
|
||||||
if (!target) return;
|
if (!target) return;
|
||||||
const cam2 = _viewer.camera;
|
const cam2 = _viewer.camera;
|
||||||
const range = Cesium.Cartesian3.distance(cam2.positionWC, target);
|
const range = geo.cartesian3.distance(cam2.positionWC, target);
|
||||||
const carto2 = Cesium.Cartographic.fromCartesian(cam2.positionWC);
|
const carto2 = geo.cartographic.fromCartesian(cam2.positionWC);
|
||||||
const tCarto2 = Cesium.Cartographic.fromCartesian(target);
|
const tCarto2 = geo.cartographic.fromCartesian(target);
|
||||||
const dh2 = carto2.height - tCarto2.height;
|
const dh2 = carto2.height - tCarto2.height;
|
||||||
m.target = target;
|
m.target = target;
|
||||||
m.hpr = new Cesium.HeadingPitchRange(
|
m.hpr = new Cesium.HeadingPitchRange(
|
||||||
@@ -1140,12 +1136,11 @@ function onTick() {
|
|||||||
}
|
}
|
||||||
if (m.kind === 'orbit') {
|
if (m.kind === 'orbit') {
|
||||||
const rate =
|
const rate =
|
||||||
Cesium.Math.toRadians(ORBIT_DEG_S[m.speed]) *
|
geo.math.toRadians(ORBIT_DEG_S[m.speed]) *
|
||||||
(m.direction === 'left' ? -1 : 1);
|
(m.direction === 'left' ? -1 : 1);
|
||||||
if (m.mode === 'once') {
|
if (m.mode === 'once') {
|
||||||
const total =
|
const total =
|
||||||
Cesium.Math.toRadians(ONCE.orbitDeg) *
|
geo.math.toRadians(ONCE.orbitDeg) * (m.direction === 'left' ? -1 : 1);
|
||||||
(m.direction === 'left' ? -1 : 1);
|
|
||||||
m.hpr.heading = m.hprStartHeading + total * scale;
|
m.hpr.heading = m.hprStartHeading + total * scale;
|
||||||
} else {
|
} else {
|
||||||
m.hpr.heading += rate * dt;
|
m.hpr.heading += rate * dt;
|
||||||
@@ -1166,11 +1161,11 @@ function onTick() {
|
|||||||
const degS = TILT_DEG_S[m.speed];
|
const degS = TILT_DEG_S[m.speed];
|
||||||
const stepRad =
|
const stepRad =
|
||||||
m.mode === 'once'
|
m.mode === 'once'
|
||||||
? Cesium.Math.toRadians(
|
? geo.math.toRadians(
|
||||||
m.kind === 'tilt' ? ONCE.tiltDeg : ONCE.rotateDeg,
|
m.kind === 'tilt' ? ONCE.tiltDeg : ONCE.rotateDeg,
|
||||||
) *
|
) *
|
||||||
(scale - (m.lastScale || 0))
|
(scale - (m.lastScale || 0))
|
||||||
: Cesium.Math.toRadians(degS) * dt;
|
: geo.math.toRadians(degS) * dt;
|
||||||
m.lastScale = scale;
|
m.lastScale = scale;
|
||||||
if (m.kind === 'tilt') {
|
if (m.kind === 'tilt') {
|
||||||
const up = m.direction === 'up';
|
const up = m.direction === 'up';
|
||||||
@@ -1298,7 +1293,7 @@ export function moveCamera(args = {}, runNavigation = null) {
|
|||||||
// Honest limits: at the clamp a tilt is a no-op — say so instead of
|
// Honest limits: at the clamp a tilt is a no-op — say so instead of
|
||||||
// reporting success and letting the model gaslight itself (field test).
|
// reporting success and letting the model gaslight itself (field test).
|
||||||
const pitch = _viewer.camera.pitch;
|
const pitch = _viewer.camera.pitch;
|
||||||
if (direction === 'up' && pitch >= PITCH_MAX - Cesium.Math.toRadians(0.5)) {
|
if (direction === 'up' && pitch >= PITCH_MAX - geo.math.toRadians(0.5)) {
|
||||||
return {
|
return {
|
||||||
ok: false,
|
ok: false,
|
||||||
action: 'move_camera',
|
action: 'move_camera',
|
||||||
@@ -1306,10 +1301,7 @@ export function moveCamera(args = {}, runNavigation = null) {
|
|||||||
'Already at the upper tilt limit (near the horizon) — tilt down, or zoom/pan instead.',
|
'Already at the upper tilt limit (near the horizon) — tilt down, or zoom/pan instead.',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (
|
if (direction === 'down' && pitch <= PITCH_MIN + geo.math.toRadians(0.5)) {
|
||||||
direction === 'down' &&
|
|
||||||
pitch <= PITCH_MIN + Cesium.Math.toRadians(0.5)
|
|
||||||
) {
|
|
||||||
return {
|
return {
|
||||||
ok: false,
|
ok: false,
|
||||||
action: 'move_camera',
|
action: 'move_camera',
|
||||||
@@ -1389,10 +1381,10 @@ export function moveCamera(args = {}, runNavigation = null) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
const cam = _viewer.camera;
|
const cam = _viewer.camera;
|
||||||
const range = Cesium.Cartesian3.distance(cam.positionWC, target);
|
const range = geo.cartesian3.distance(cam.positionWC, target);
|
||||||
// Pitch from geometry so lookAt reproduces the CURRENT framing exactly.
|
// Pitch from geometry so lookAt reproduces the CURRENT framing exactly.
|
||||||
const carto = Cesium.Cartographic.fromCartesian(cam.positionWC);
|
const carto = geo.cartographic.fromCartesian(cam.positionWC);
|
||||||
const tCarto = Cesium.Cartographic.fromCartesian(target);
|
const tCarto = geo.cartographic.fromCartesian(target);
|
||||||
const dh = carto.height - tCarto.height;
|
const dh = carto.height - tCarto.height;
|
||||||
const pitch = -Math.asin(
|
const pitch = -Math.asin(
|
||||||
Math.min(1, Math.max(-1, dh / Math.max(1, range))),
|
Math.min(1, Math.max(-1, dh / Math.max(1, range))),
|
||||||
@@ -1505,11 +1497,11 @@ export function flyRoute(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
const pts = route.path.map((p) =>
|
const pts = route.path.map((p) =>
|
||||||
Cesium.Cartesian3.fromDegrees(p.lon, p.lat, p.height || 0),
|
geo.cartesian3.fromDegrees(p.lon, p.lat, p.height || 0),
|
||||||
);
|
);
|
||||||
const cumM = [0];
|
const cumM = [0];
|
||||||
for (let i = 1; i < pts.length; i += 1) {
|
for (let i = 1; i < pts.length; i += 1) {
|
||||||
cumM.push(cumM[i - 1] + Cesium.Cartesian3.distance(pts[i - 1], pts[i]));
|
cumM.push(cumM[i - 1] + geo.cartesian3.distance(pts[i - 1], pts[i]));
|
||||||
}
|
}
|
||||||
if (!Number.isFinite(cumM.at(-1)) || cumM.at(-1) <= 0) {
|
if (!Number.isFinite(cumM.at(-1)) || cumM.at(-1) <= 0) {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { applicationServices } from './services/application.js';
|
import { applicationServices } from './services/application.js';
|
||||||
import * as Cesium from 'cesium';
|
import * as geo from './geo/index.js';
|
||||||
import {
|
import {
|
||||||
deriveWeatherEffectProfile,
|
deriveWeatherEffectProfile,
|
||||||
weatherAltitudeFactors,
|
weatherAltitudeFactors,
|
||||||
@@ -133,10 +133,10 @@ function greatCircleM(a, b) {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
return Infinity;
|
return Infinity;
|
||||||
const latitudeA = Cesium.Math.toRadians(a.latitude);
|
const latitudeA = geo.math.toRadians(a.latitude);
|
||||||
const latitudeB = Cesium.Math.toRadians(b.latitude);
|
const latitudeB = geo.math.toRadians(b.latitude);
|
||||||
const latitudeDelta = Cesium.Math.toRadians(b.latitude - a.latitude);
|
const latitudeDelta = geo.math.toRadians(b.latitude - a.latitude);
|
||||||
const longitudeDelta = Cesium.Math.toRadians(b.longitude - a.longitude);
|
const longitudeDelta = geo.math.toRadians(b.longitude - a.longitude);
|
||||||
const haversine =
|
const haversine =
|
||||||
Math.sin(latitudeDelta / 2) ** 2 +
|
Math.sin(latitudeDelta / 2) ** 2 +
|
||||||
Math.cos(latitudeA) *
|
Math.cos(latitudeA) *
|
||||||
@@ -342,8 +342,8 @@ export class CockpitCloudEffectsController {
|
|||||||
cameraPoint() {
|
cameraPoint() {
|
||||||
const cartographic = this.viewer?.camera?.positionCartographic;
|
const cartographic = this.viewer?.camera?.positionCartographic;
|
||||||
if (!cartographic) return null;
|
if (!cartographic) return null;
|
||||||
const latitude = Cesium.Math.toDegrees(cartographic.latitude);
|
const latitude = geo.math.toDegrees(cartographic.latitude);
|
||||||
const longitude = Cesium.Math.toDegrees(cartographic.longitude);
|
const longitude = geo.math.toDegrees(cartographic.longitude);
|
||||||
if (![latitude, longitude].every(Number.isFinite)) return null;
|
if (![latitude, longitude].every(Number.isFinite)) return null;
|
||||||
return {
|
return {
|
||||||
latitude,
|
latitude,
|
||||||
@@ -541,7 +541,7 @@ export class CockpitCloudEffectsController {
|
|||||||
render(timeSec) {
|
render(timeSec) {
|
||||||
const gl = this.gl;
|
const gl = this.gl;
|
||||||
if (!gl || !this.program || !this.locations) return;
|
if (!gl || !this.program || !this.locations) return;
|
||||||
const windRadians = Cesium.Math.toRadians(this.windDirectionDeg);
|
const windRadians = geo.math.toRadians(this.windDirectionDeg);
|
||||||
const windScale = 0.008 + this.windStrength * 0.022;
|
const windScale = 0.008 + this.windStrength * 0.022;
|
||||||
gl.useProgram(this.program);
|
gl.useProgram(this.program);
|
||||||
gl.uniform2f(
|
gl.uniform2f(
|
||||||
|
|||||||
+22
-21
@@ -22,6 +22,7 @@
|
|||||||
* unverified math swap, decides whether exact projection becomes preferred.
|
* unverified math swap, decides whether exact projection becomes preferred.
|
||||||
*/
|
*/
|
||||||
import * as Cesium from 'cesium';
|
import * as Cesium from 'cesium';
|
||||||
|
import * as geo from '../geo/index.js';
|
||||||
|
|
||||||
/** Meters used to give the course vector a stable projection magnitude. */
|
/** Meters used to give the course vector a stable projection magnitude. */
|
||||||
const FORWARD_PROBE_M = 2000;
|
const FORWARD_PROBE_M = 2000;
|
||||||
@@ -31,11 +32,11 @@ const FORWARD_PROBE_M = 2000;
|
|||||||
*/
|
*/
|
||||||
const MIN_SCREEN_COMPONENT_M = 0.5;
|
const MIN_SCREEN_COMPONENT_M = 0.5;
|
||||||
/** Ignore sub-degree projection noise while retaining deliberate camera-orbit rotation. */
|
/** Ignore sub-degree projection noise while retaining deliberate camera-orbit rotation. */
|
||||||
const ROTATION_DEADBAND_RAD = Cesium.Math.toRadians(0.5);
|
const ROTATION_DEADBAND_RAD = geo.math.toRadians(0.5);
|
||||||
|
|
||||||
const _scratchEnu = new Cesium.Matrix4();
|
const _scratchEnu = geo.matrix4.create();
|
||||||
const _scratchForward = new Cesium.Cartesian3();
|
const _scratchForward = geo.cartesian3.create();
|
||||||
const _scratchWorldForward = new Cesium.Cartesian3();
|
const _scratchWorldForward = geo.cartesian3.create();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Computes the billboard rotation (radians, CCW-positive, for
|
* Computes the billboard rotation (radians, CCW-positive, for
|
||||||
@@ -58,19 +59,19 @@ export function screenProjectedRotation(
|
|||||||
const camera = scene?.camera;
|
const camera = scene?.camera;
|
||||||
if (!camera?.rightWC || !camera?.upWC || !position) return previous;
|
if (!camera?.rightWC || !camera?.upWC || !position) return previous;
|
||||||
|
|
||||||
const courseRad = Cesium.Math.toRadians(courseDeg || 0);
|
const courseRad = geo.math.toRadians(courseDeg || 0);
|
||||||
Cesium.Cartesian3.fromElements(
|
geo.cartesian3.fromElements(
|
||||||
Math.sin(courseRad) * FORWARD_PROBE_M,
|
Math.sin(courseRad) * FORWARD_PROBE_M,
|
||||||
Math.cos(courseRad) * FORWARD_PROBE_M,
|
Math.cos(courseRad) * FORWARD_PROBE_M,
|
||||||
0,
|
0,
|
||||||
_scratchForward,
|
_scratchForward,
|
||||||
);
|
);
|
||||||
const enu = Cesium.Transforms.eastNorthUpToFixedFrame(
|
const enu = geo.transforms.eastNorthUpToFixedFrame(
|
||||||
position,
|
position,
|
||||||
Cesium.Ellipsoid.WGS84,
|
geo.ellipsoid.WGS84,
|
||||||
_scratchEnu,
|
_scratchEnu,
|
||||||
);
|
);
|
||||||
Cesium.Matrix4.multiplyByPointAsVector(
|
geo.matrix4.multiplyByPointAsVector(
|
||||||
enu,
|
enu,
|
||||||
_scratchForward,
|
_scratchForward,
|
||||||
_scratchWorldForward,
|
_scratchWorldForward,
|
||||||
@@ -79,8 +80,8 @@ export function screenProjectedRotation(
|
|||||||
// Screen x follows camera-right. Window y grows downward, the opposite of
|
// Screen x follows camera-right. Window y grows downward, the opposite of
|
||||||
// camera-up. Projecting the vector itself avoids clipping/behind-camera
|
// camera-up. Projecting the vector itself avoids clipping/behind-camera
|
||||||
// failure modes from the old forward-point worldToWindowCoordinates probe.
|
// failure modes from the old forward-point worldToWindowCoordinates probe.
|
||||||
const dx = Cesium.Cartesian3.dot(_scratchWorldForward, camera.rightWC);
|
const dx = geo.cartesian3.dot(_scratchWorldForward, camera.rightWC);
|
||||||
const dy = -Cesium.Cartesian3.dot(_scratchWorldForward, camera.upWC);
|
const dy = -geo.cartesian3.dot(_scratchWorldForward, camera.upWC);
|
||||||
if (dx * dx + dy * dy < MIN_SCREEN_COMPONENT_M * MIN_SCREEN_COMPONENT_M)
|
if (dx * dx + dy * dy < MIN_SCREEN_COMPONENT_M * MIN_SCREEN_COMPONENT_M)
|
||||||
return previous;
|
return previous;
|
||||||
|
|
||||||
@@ -129,7 +130,7 @@ const _occluder = new Cesium.EllipsoidalOccluder(
|
|||||||
*/
|
*/
|
||||||
export const HORIZON_FEATHER_RAD = 0.019;
|
export const HORIZON_FEATHER_RAD = 0.019;
|
||||||
|
|
||||||
const _wgs84OneOverRadii = Cesium.Ellipsoid.WGS84.oneOverRadii;
|
const _wgs84OneOverRadii = geo.ellipsoid.WGS84.oneOverRadii;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* How much SKY sits behind a world point from this camera: 0 (planet behind)
|
* How much SKY sits behind a world point from this camera: 0 (planet behind)
|
||||||
@@ -271,9 +272,9 @@ export function cameraPoseSignature(camera) {
|
|||||||
* frustum the vehicle is nowhere near.
|
* frustum the vehicle is nowhere near.
|
||||||
*/
|
*/
|
||||||
const NEAR_PROBE_M = 30;
|
const NEAR_PROBE_M = 30;
|
||||||
const _scratchProbe = new Cesium.Cartesian3();
|
const _scratchProbe = geo.cartesian3.create();
|
||||||
const _scratchWindowAt = new Cesium.Cartesian2();
|
const _scratchWindowAt = geo.cartesian2.create();
|
||||||
const _scratchWindowAhead = new Cesium.Cartesian2();
|
const _scratchWindowAhead = geo.cartesian2.create();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Billboard rotation for a SURFACE contact, projected exactly — perspective
|
* Billboard rotation for a SURFACE contact, projected exactly — perspective
|
||||||
@@ -311,24 +312,24 @@ export function perspectiveProjectedRotation(
|
|||||||
if (!scene?.camera || !position || !Number.isFinite(courseDeg)) {
|
if (!scene?.camera || !position || !Number.isFinite(courseDeg)) {
|
||||||
return previous;
|
return previous;
|
||||||
}
|
}
|
||||||
const courseRad = Cesium.Math.toRadians(courseDeg);
|
const courseRad = geo.math.toRadians(courseDeg);
|
||||||
Cesium.Cartesian3.fromElements(
|
geo.cartesian3.fromElements(
|
||||||
Math.sin(courseRad) * NEAR_PROBE_M,
|
Math.sin(courseRad) * NEAR_PROBE_M,
|
||||||
Math.cos(courseRad) * NEAR_PROBE_M,
|
Math.cos(courseRad) * NEAR_PROBE_M,
|
||||||
0,
|
0,
|
||||||
_scratchForward,
|
_scratchForward,
|
||||||
);
|
);
|
||||||
const enu = Cesium.Transforms.eastNorthUpToFixedFrame(
|
const enu = geo.transforms.eastNorthUpToFixedFrame(
|
||||||
position,
|
position,
|
||||||
Cesium.Ellipsoid.WGS84,
|
geo.ellipsoid.WGS84,
|
||||||
_scratchEnu,
|
_scratchEnu,
|
||||||
);
|
);
|
||||||
Cesium.Matrix4.multiplyByPointAsVector(
|
geo.matrix4.multiplyByPointAsVector(
|
||||||
enu,
|
enu,
|
||||||
_scratchForward,
|
_scratchForward,
|
||||||
_scratchWorldForward,
|
_scratchWorldForward,
|
||||||
);
|
);
|
||||||
Cesium.Cartesian3.add(position, _scratchWorldForward, _scratchProbe);
|
geo.cartesian3.add(position, _scratchWorldForward, _scratchProbe);
|
||||||
|
|
||||||
const at = Cesium.SceneTransforms.worldToWindowCoordinates(
|
const at = Cesium.SceneTransforms.worldToWindowCoordinates(
|
||||||
scene,
|
scene,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import * as Cesium from 'cesium';
|
import * as Cesium from 'cesium';
|
||||||
|
import * as geo from '../geo/index.js';
|
||||||
/**
|
/**
|
||||||
* Model-space visual centres measured from the shipped GLBs' scene-space AABBs.
|
* Model-space visual centres measured from the shipped GLBs' scene-space AABBs.
|
||||||
*
|
*
|
||||||
@@ -76,13 +77,13 @@ export const MODEL_TRAIL_ANCHOR_NATIVE = Object.freeze({
|
|||||||
* renders with `modelMatrix x components.transform x axisCorrection`, and the
|
* renders with `modelMatrix x components.transform x axisCorrection`, and the
|
||||||
* trail anchor has to ride the same chain or it lands on a different axis than
|
* trail anchor has to ride the same chain or it lands on a different axis than
|
||||||
* the aircraft it is supposed to be attached to. */
|
* the aircraft it is supposed to be attached to. */
|
||||||
const AXIS_CORRECTION = Cesium.Matrix4.multiplyTransformation(
|
const AXIS_CORRECTION = geo.matrix4.multiplyTransformation(
|
||||||
Cesium.Axis.Y_UP_TO_Z_UP,
|
Cesium.Axis.Y_UP_TO_Z_UP,
|
||||||
Cesium.Axis.Z_UP_TO_X_UP,
|
Cesium.Axis.Z_UP_TO_X_UP,
|
||||||
new Cesium.Matrix4(),
|
geo.matrix4.create(),
|
||||||
);
|
);
|
||||||
const _anchorScratch = new Cesium.Cartesian3();
|
const _anchorScratch = geo.cartesian3.create();
|
||||||
const _chainScratch = new Cesium.Matrix4();
|
const _chainScratch = geo.matrix4.create();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* World position of a model-local anchor, through the SAME transform chain
|
* World position of a model-local anchor, through the SAME transform chain
|
||||||
@@ -121,17 +122,17 @@ export function modelAnchorWorld(model, nativeAnchor, result) {
|
|||||||
// correction. Read from the instance rather than assumed, so an asset with a
|
// correction. Read from the instance rather than assumed, so an asset with a
|
||||||
// baked root transform is carried too.
|
// baked root transform is carried too.
|
||||||
const components = model?.sceneGraph?.components?.transform;
|
const components = model?.sceneGraph?.components?.transform;
|
||||||
Cesium.Matrix4.multiplyTransformation(
|
geo.matrix4.multiplyTransformation(
|
||||||
model.modelMatrix,
|
model.modelMatrix,
|
||||||
components || Cesium.Matrix4.IDENTITY,
|
components || geo.matrix4.IDENTITY,
|
||||||
_chainScratch,
|
_chainScratch,
|
||||||
);
|
);
|
||||||
Cesium.Matrix4.multiplyTransformation(
|
geo.matrix4.multiplyTransformation(
|
||||||
_chainScratch,
|
_chainScratch,
|
||||||
AXIS_CORRECTION,
|
AXIS_CORRECTION,
|
||||||
_chainScratch,
|
_chainScratch,
|
||||||
);
|
);
|
||||||
return Cesium.Matrix4.multiplyByPoint(_chainScratch, _anchorScratch, result);
|
return geo.matrix4.multiplyByPoint(_chainScratch, _anchorScratch, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+18
-17
@@ -7,10 +7,11 @@
|
|||||||
* skylight (https://github.com/cpaczek/skylight, MIT) shared/src/aim.ts.
|
* skylight (https://github.com/cpaczek/skylight, MIT) shared/src/aim.ts.
|
||||||
*/
|
*/
|
||||||
import * as Cesium from 'cesium';
|
import * as Cesium from 'cesium';
|
||||||
|
import * as geo from '../geo/index.js';
|
||||||
|
|
||||||
const DEG = Math.PI / 180;
|
const DEG = Math.PI / 180;
|
||||||
const _mmCarto = new Cesium.Cartographic();
|
const _mmCarto = geo.cartographic.create();
|
||||||
const _mmCandidateCarto = new Cesium.Cartographic();
|
const _mmCandidateCarto = geo.cartographic.create();
|
||||||
|
|
||||||
export function norm360(deg) {
|
export function norm360(deg) {
|
||||||
return ((deg % 360) + 360) % 360;
|
return ((deg % 360) + 360) % 360;
|
||||||
@@ -28,22 +29,22 @@ export function norm360(deg) {
|
|||||||
*/
|
*/
|
||||||
export function liftRepeatedGroundFix(newest, candidatePosition, onGround) {
|
export function liftRepeatedGroundFix(newest, candidatePosition, onGround) {
|
||||||
if (!onGround || !newest?.position || !candidatePosition) return false;
|
if (!onGround || !newest?.position || !candidatePosition) return false;
|
||||||
const stored = Cesium.Cartographic.fromCartesian(
|
const stored = geo.cartographic.fromCartesian(
|
||||||
newest.position,
|
newest.position,
|
||||||
Cesium.Ellipsoid.WGS84,
|
geo.ellipsoid.WGS84,
|
||||||
_mmCarto,
|
_mmCarto,
|
||||||
);
|
);
|
||||||
const candidate = Cesium.Cartographic.fromCartesian(
|
const candidate = geo.cartographic.fromCartesian(
|
||||||
candidatePosition,
|
candidatePosition,
|
||||||
Cesium.Ellipsoid.WGS84,
|
geo.ellipsoid.WGS84,
|
||||||
_mmCandidateCarto,
|
_mmCandidateCarto,
|
||||||
);
|
);
|
||||||
if (!stored || !candidate || candidate.height <= stored.height) return false;
|
if (!stored || !candidate || candidate.height <= stored.height) return false;
|
||||||
Cesium.Cartesian3.fromRadians(
|
geo.cartesian3.fromRadians(
|
||||||
stored.longitude,
|
stored.longitude,
|
||||||
stored.latitude,
|
stored.latitude,
|
||||||
candidate.height,
|
candidate.height,
|
||||||
Cesium.Ellipsoid.WGS84,
|
geo.ellipsoid.WGS84,
|
||||||
newest.position,
|
newest.position,
|
||||||
);
|
);
|
||||||
return true;
|
return true;
|
||||||
@@ -66,9 +67,9 @@ export function courseBetweenCartesians(from, to, minChordM = 25) {
|
|||||||
const dy = to.y - from.y;
|
const dy = to.y - from.y;
|
||||||
const dz = to.z - from.z;
|
const dz = to.z - from.z;
|
||||||
if (dx * dx + dy * dy + dz * dz < minChordM * minChordM) return null;
|
if (dx * dx + dy * dy + dz * dz < minChordM * minChordM) return null;
|
||||||
const carto = Cesium.Cartographic.fromCartesian(
|
const carto = geo.cartographic.fromCartesian(
|
||||||
from,
|
from,
|
||||||
Cesium.Ellipsoid.WGS84,
|
geo.ellipsoid.WGS84,
|
||||||
_mmCarto,
|
_mmCarto,
|
||||||
);
|
);
|
||||||
if (!carto) return null;
|
if (!carto) return null;
|
||||||
@@ -436,8 +437,8 @@ export function arcOffsetEnu(speedMps, trackDeg, turnRateDps, dtSec, result) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const _forwardFixArc = { east: 0, north: 0, endCourseDeg: 0 };
|
const _forwardFixArc = { east: 0, north: 0, endCourseDeg: 0 };
|
||||||
const _forwardFixEnu = new Cesium.Matrix4();
|
const _forwardFixEnu = geo.matrix4.create();
|
||||||
const _forwardFixOffset = new Cesium.Cartesian3();
|
const _forwardFixOffset = geo.cartesian3.create();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a forward-only synthetic fix when a repeated position epoch carries
|
* Create a forward-only synthetic fix when a repeated position epoch carries
|
||||||
@@ -474,21 +475,21 @@ export function synthesizeForwardKinematicsFix(newest, next = {}) {
|
|||||||
dtSec,
|
dtSec,
|
||||||
_forwardFixArc,
|
_forwardFixArc,
|
||||||
);
|
);
|
||||||
Cesium.Cartesian3.fromElements(
|
geo.cartesian3.fromElements(
|
||||||
_forwardFixArc.east,
|
_forwardFixArc.east,
|
||||||
_forwardFixArc.north,
|
_forwardFixArc.north,
|
||||||
0,
|
0,
|
||||||
_forwardFixOffset,
|
_forwardFixOffset,
|
||||||
);
|
);
|
||||||
const enu = Cesium.Transforms.eastNorthUpToFixedFrame(
|
const enu = geo.transforms.eastNorthUpToFixedFrame(
|
||||||
newest.position,
|
newest.position,
|
||||||
Cesium.Ellipsoid.WGS84,
|
geo.ellipsoid.WGS84,
|
||||||
_forwardFixEnu,
|
_forwardFixEnu,
|
||||||
);
|
);
|
||||||
const position = Cesium.Matrix4.multiplyByPoint(
|
const position = geo.matrix4.multiplyByPoint(
|
||||||
enu,
|
enu,
|
||||||
_forwardFixOffset,
|
_forwardFixOffset,
|
||||||
new Cesium.Cartesian3(),
|
geo.cartesian3.create(),
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
time: Cesium.JulianDate.fromDate(new Date(next.epochMs)),
|
time: Cesium.JulianDate.fromDate(new Date(next.epochMs)),
|
||||||
|
|||||||
+20
-20
@@ -1,4 +1,4 @@
|
|||||||
import * as Cesium from 'cesium';
|
import * as geo from '../geo/index.js';
|
||||||
|
|
||||||
const MAX_FRAME_ATTEMPTS = 120;
|
const MAX_FRAME_ATTEMPTS = 120;
|
||||||
const MIN_TRACKED_RANGE_M = 150;
|
const MIN_TRACKED_RANGE_M = 150;
|
||||||
@@ -59,7 +59,7 @@ export function trackedModelScaleForPixelCap({
|
|||||||
export function trackedDisplayPositionForCamera(entity, time, result) {
|
export function trackedDisplayPositionForCamera(entity, time, result) {
|
||||||
const displayedPosition = entity?.gevDisplayPosition?.();
|
const displayedPosition = entity?.gevDisplayPosition?.();
|
||||||
return displayedPosition
|
return displayedPosition
|
||||||
? Cesium.Cartesian3.clone(displayedPosition, result)
|
? geo.cartesian3.clone(displayedPosition, result)
|
||||||
: entity?.position?.getValue(time, result);
|
: entity?.position?.getValue(time, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,15 +106,15 @@ export function clampTrackedCameraPosition(
|
|||||||
minimumRangeM = MIN_TRACKED_RANGE_M,
|
minimumRangeM = MIN_TRACKED_RANGE_M,
|
||||||
) {
|
) {
|
||||||
const crossedOrigin =
|
const crossedOrigin =
|
||||||
Cesium.Cartesian3.dot(camera.position, previousPosition) <= 0;
|
geo.cartesian3.dot(camera.position, previousPosition) <= 0;
|
||||||
const forwardDistance = -Cesium.Cartesian3.dot(
|
const forwardDistance = -geo.cartesian3.dot(
|
||||||
camera.position,
|
camera.position,
|
||||||
camera.direction,
|
camera.direction,
|
||||||
);
|
);
|
||||||
const rangeSquared = Cesium.Cartesian3.magnitudeSquared(camera.position);
|
const rangeSquared = geo.cartesian3.magnitudeSquared(camera.position);
|
||||||
if (crossedOrigin) {
|
if (crossedOrigin) {
|
||||||
Cesium.Cartesian3.normalize(previousPosition, camera.position);
|
geo.cartesian3.normalize(previousPosition, camera.position);
|
||||||
Cesium.Cartesian3.multiplyByScalar(
|
geo.cartesian3.multiplyByScalar(
|
||||||
camera.position,
|
camera.position,
|
||||||
minimumRangeM,
|
minimumRangeM,
|
||||||
camera.position,
|
camera.position,
|
||||||
@@ -125,7 +125,7 @@ export function clampTrackedCameraPosition(
|
|||||||
forwardDistance < minimumRangeM ||
|
forwardDistance < minimumRangeM ||
|
||||||
rangeSquared < minimumRangeM * minimumRangeM
|
rangeSquared < minimumRangeM * minimumRangeM
|
||||||
) {
|
) {
|
||||||
Cesium.Cartesian3.multiplyByScalar(
|
geo.cartesian3.multiplyByScalar(
|
||||||
camera.direction,
|
camera.direction,
|
||||||
-minimumRangeM,
|
-minimumRangeM,
|
||||||
camera.position,
|
camera.position,
|
||||||
@@ -155,11 +155,11 @@ export function clampTrackedCameraPosition(
|
|||||||
export function applyTrackedCameraFrame(viewer, entity, viewFrom) {
|
export function applyTrackedCameraFrame(viewer, entity, viewFrom) {
|
||||||
if (!viewer || !entity || !viewFrom) return;
|
if (!viewer || !entity || !viewFrom) return;
|
||||||
let attempts = 0;
|
let attempts = 0;
|
||||||
const trackedTransform = new Cesium.Matrix4();
|
const trackedTransform = geo.matrix4.create();
|
||||||
const trackedPosition = new Cesium.Cartesian3();
|
const trackedPosition = geo.cartesian3.create();
|
||||||
const resolvedViewFrom = new Cesium.Cartesian3();
|
const resolvedViewFrom = geo.cartesian3.create();
|
||||||
const cameraOffset = new Cesium.Cartesian3();
|
const cameraOffset = geo.cartesian3.create();
|
||||||
const previousCameraPosition = new Cesium.Cartesian3();
|
const previousCameraPosition = geo.cartesian3.create();
|
||||||
let framed = false;
|
let framed = false;
|
||||||
const restoreZoomInertia = acquireStableTrackedZoom(
|
const restoreZoomInertia = acquireStableTrackedZoom(
|
||||||
viewer.scene.screenSpaceCameraController,
|
viewer.scene.screenSpaceCameraController,
|
||||||
@@ -201,24 +201,24 @@ export function applyTrackedCameraFrame(viewer, entity, viewFrom) {
|
|||||||
if (attempts >= MAX_FRAME_ATTEMPTS) stop();
|
if (attempts >= MAX_FRAME_ATTEMPTS) stop();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const transform = Cesium.Transforms.eastNorthUpToFixedFrame(
|
const transform = geo.transforms.eastNorthUpToFixedFrame(
|
||||||
position,
|
position,
|
||||||
Cesium.Ellipsoid.WGS84,
|
geo.ellipsoid.WGS84,
|
||||||
trackedTransform,
|
trackedTransform,
|
||||||
);
|
);
|
||||||
const offset =
|
const offset =
|
||||||
typeof viewFrom.getValue === 'function'
|
typeof viewFrom.getValue === 'function'
|
||||||
? viewFrom.getValue(viewer.clock.currentTime, resolvedViewFrom)
|
? viewFrom.getValue(viewer.clock.currentTime, resolvedViewFrom)
|
||||||
: Cesium.Cartesian3.clone(viewFrom, resolvedViewFrom);
|
: geo.cartesian3.clone(viewFrom, resolvedViewFrom);
|
||||||
if (
|
if (
|
||||||
!offset ||
|
!offset ||
|
||||||
Cesium.Cartesian3.magnitudeSquared(offset) < Cesium.Math.EPSILON12
|
geo.cartesian3.magnitudeSquared(offset) < geo.math.EPSILON12
|
||||||
) {
|
) {
|
||||||
stop();
|
stop();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
viewer.camera.lookAtTransform(transform, offset);
|
viewer.camera.lookAtTransform(transform, offset);
|
||||||
Cesium.Cartesian3.clone(viewer.camera.position, previousCameraPosition);
|
geo.cartesian3.clone(viewer.camera.position, previousCameraPosition);
|
||||||
framed = true;
|
framed = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -227,10 +227,10 @@ export function applyTrackedCameraFrame(viewer, entity, viewFrom) {
|
|||||||
// continuous camera writer. Only a programmatic zoom that bypasses the
|
// continuous camera writer. Only a programmatic zoom that bypasses the
|
||||||
// controller's minimumZoomDistance needs correction.
|
// controller's minimumZoomDistance needs correction.
|
||||||
if (clampTrackedCameraPosition(viewer.camera, previousCameraPosition)) {
|
if (clampTrackedCameraPosition(viewer.camera, previousCameraPosition)) {
|
||||||
Cesium.Cartesian3.clone(viewer.camera.position, cameraOffset);
|
geo.cartesian3.clone(viewer.camera.position, cameraOffset);
|
||||||
viewer.camera.lookAtTransform(viewer.camera.transform, cameraOffset);
|
viewer.camera.lookAtTransform(viewer.camera.transform, cameraOffset);
|
||||||
}
|
}
|
||||||
Cesium.Cartesian3.clone(viewer.camera.position, previousCameraPosition);
|
geo.cartesian3.clone(viewer.camera.position, previousCameraPosition);
|
||||||
});
|
});
|
||||||
return stop;
|
return stop;
|
||||||
}
|
}
|
||||||
+15
-15
@@ -14,7 +14,7 @@ import { applicationServices } from './services/application.js';
|
|||||||
* Color theming is driven by the active shader mode via CSS custom properties.
|
* Color theming is driven by the active shader mode via CSS custom properties.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as Cesium from 'cesium';
|
import * as geo from './geo/index.js';
|
||||||
import { forward as toMGRS } from 'mgrs';
|
import { forward as toMGRS } from 'mgrs';
|
||||||
import { CITY_POIS } from './locations.js';
|
import { CITY_POIS } from './locations.js';
|
||||||
import { composeLocalityTag } from './hudLocality.js';
|
import { composeLocalityTag } from './hudLocality.js';
|
||||||
@@ -341,8 +341,8 @@ export class IntelHUD {
|
|||||||
const cartographic = camera.positionCartographic;
|
const cartographic = camera.positionCartographic;
|
||||||
if (!cartographic) return;
|
if (!cartographic) return;
|
||||||
|
|
||||||
const lonDeg = Cesium.Math.toDegrees(cartographic.longitude);
|
const lonDeg = geo.math.toDegrees(cartographic.longitude);
|
||||||
const latDeg = Cesium.Math.toDegrees(cartographic.latitude);
|
const latDeg = geo.math.toDegrees(cartographic.latitude);
|
||||||
const altM = cartographic.height;
|
const altM = cartographic.height;
|
||||||
const latDMS = this._toDMS(latDeg, 'lat');
|
const latDMS = this._toDMS(latDeg, 'lat');
|
||||||
const lonDMS = this._toDMS(lonDeg, 'lon');
|
const lonDMS = this._toDMS(lonDeg, 'lon');
|
||||||
@@ -407,7 +407,7 @@ export class IntelHUD {
|
|||||||
|
|
||||||
// Off-nadir angle (ONA): camera pitch of -90 deg is nadir (straight down),
|
// Off-nadir angle (ONA): camera pitch of -90 deg is nadir (straight down),
|
||||||
// so ONA = 90 + pitch gives 0 at nadir and increases toward the horizon.
|
// so ONA = 90 + pitch gives 0 at nadir and increases toward the horizon.
|
||||||
const pitchDeg = Cesium.Math.toDegrees(camera.pitch);
|
const pitchDeg = geo.math.toDegrees(camera.pitch);
|
||||||
const ona = Math.max(0, 90 + pitchDeg);
|
const ona = Math.max(0, 90 + pitchDeg);
|
||||||
const onaEl = document.getElementById('hud-ona');
|
const onaEl = document.getElementById('hud-ona');
|
||||||
if (onaEl) onaEl.textContent = `ONA: ${ona.toFixed(1)}°`;
|
if (onaEl) onaEl.textContent = `ONA: ${ona.toFixed(1)}°`;
|
||||||
@@ -512,19 +512,19 @@ export class IntelHUD {
|
|||||||
const declination =
|
const declination =
|
||||||
23.45 *
|
23.45 *
|
||||||
Math.sin(
|
Math.sin(
|
||||||
Cesium.Math.toRadians(
|
geo.math.toRadians(
|
||||||
(360 / 365) * (now.getUTCDate() + 30 * now.getUTCMonth() - 81),
|
(360 / 365) * (now.getUTCDate() + 30 * now.getUTCMonth() - 81),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
const latRad = Cesium.Math.toRadians(lat);
|
const latRad = geo.math.toRadians(lat);
|
||||||
const decRad = Cesium.Math.toRadians(declination);
|
const decRad = geo.math.toRadians(declination);
|
||||||
const haRad = Cesium.Math.toRadians(hourAngle);
|
const haRad = geo.math.toRadians(hourAngle);
|
||||||
// Standard formula: sin(el) = sin(lat)*sin(dec) + cos(lat)*cos(dec)*cos(ha)
|
// Standard formula: sin(el) = sin(lat)*sin(dec) + cos(lat)*cos(dec)*cos(ha)
|
||||||
const sinEl =
|
const sinEl =
|
||||||
Math.sin(latRad) * Math.sin(decRad) +
|
Math.sin(latRad) * Math.sin(decRad) +
|
||||||
Math.cos(latRad) * Math.cos(decRad) * Math.cos(haRad);
|
Math.cos(latRad) * Math.cos(decRad) * Math.cos(haRad);
|
||||||
// Clamp to [-1,1] to guard against floating-point drift before asin
|
// Clamp to [-1,1] to guard against floating-point drift before asin
|
||||||
return Cesium.Math.toDegrees(Math.asin(Math.max(-1, Math.min(1, sinEl))));
|
return geo.math.toDegrees(Math.asin(Math.max(-1, Math.min(1, sinEl))));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -571,10 +571,10 @@ export class IntelHUD {
|
|||||||
_viewWindowKm(latDeg) {
|
_viewWindowKm(latDeg) {
|
||||||
const rect = this.viewer.camera.computeViewRectangle();
|
const rect = this.viewer.camera.computeViewRectangle();
|
||||||
if (!rect) return null;
|
if (!rect) return null;
|
||||||
const north = Cesium.Math.toDegrees(rect.north);
|
const north = geo.math.toDegrees(rect.north);
|
||||||
const south = Cesium.Math.toDegrees(rect.south);
|
const south = geo.math.toDegrees(rect.south);
|
||||||
let east = Cesium.Math.toDegrees(rect.east);
|
let east = geo.math.toDegrees(rect.east);
|
||||||
let west = Cesium.Math.toDegrees(rect.west);
|
let west = geo.math.toDegrees(rect.west);
|
||||||
let lonSpan = Math.abs(east - west);
|
let lonSpan = Math.abs(east - west);
|
||||||
// Handle antimeridian wrap: if span exceeds 180 deg, take the shorter arc
|
// Handle antimeridian wrap: if span exceeds 180 deg, take the shorter arc
|
||||||
if (lonSpan > 180) lonSpan = 360 - lonSpan;
|
if (lonSpan > 180) lonSpan = 360 - lonSpan;
|
||||||
@@ -583,7 +583,7 @@ export class IntelHUD {
|
|||||||
// longitude distance is scaled by cos(lat) to account for meridian convergence.
|
// longitude distance is scaled by cos(lat) to account for meridian convergence.
|
||||||
const widthKm = Math.max(
|
const widthKm = Math.max(
|
||||||
0,
|
0,
|
||||||
lonSpan * 111 * Math.cos(Cesium.Math.toRadians(latDeg)),
|
lonSpan * 111 * Math.cos(geo.math.toRadians(latDeg)),
|
||||||
);
|
);
|
||||||
const heightKm = Math.max(0, latSpan * 111);
|
const heightKm = Math.max(0, latSpan * 111);
|
||||||
return { widthKm, heightKm };
|
return { widthKm, heightKm };
|
||||||
@@ -599,7 +599,7 @@ export class IntelHUD {
|
|||||||
* @returns {number} Distance in kilometers.
|
* @returns {number} Distance in kilometers.
|
||||||
*/
|
*/
|
||||||
_haversineKm(lat1, lon1, lat2, lon2) {
|
_haversineKm(lat1, lon1, lat2, lon2) {
|
||||||
const toRad = (deg) => Cesium.Math.toRadians(deg);
|
const toRad = (deg) => geo.math.toRadians(deg);
|
||||||
const dLat = toRad(lat2 - lat1);
|
const dLat = toRad(lat2 - lat1);
|
||||||
const dLon = toRad(lon2 - lon1);
|
const dLon = toRad(lon2 - lon1);
|
||||||
const a =
|
const a =
|
||||||
|
|||||||
@@ -147,7 +147,10 @@ export function createFlightSnapshotRenderer({
|
|||||||
history.push(synthetic);
|
history.push(synthetic);
|
||||||
if (history.length > POSITION_HISTORY_LIMIT) history.shift();
|
if (history.length > POSITION_HISTORY_LIMIT) history.shift();
|
||||||
meta.turnRateDps = turnRateFromFixHistory(history);
|
meta.turnRateDps = turnRateFromFixHistory(history);
|
||||||
if (isTracked) tracking._appendTrailFix(synthetic.position.clone());
|
if (isTracked)
|
||||||
|
tracking._appendTrailFix(
|
||||||
|
Cesium.Cartesian3.clone(synthetic.position),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -118,7 +118,10 @@ export function createMilitarySnapshotRenderer({
|
|||||||
history.push(synthetic);
|
history.push(synthetic);
|
||||||
if (history.length > POSITION_HISTORY_LIMIT) history.shift();
|
if (history.length > POSITION_HISTORY_LIMIT) history.shift();
|
||||||
meta.turnRateDps = turnRateFromFixHistory(history);
|
meta.turnRateDps = turnRateFromFixHistory(history);
|
||||||
if (isTracked) tracking._appendTrailFix(synthetic.position.clone());
|
if (isTracked)
|
||||||
|
tracking._appendTrailFix(
|
||||||
|
Cesium.Cartesian3.clone(synthetic.position),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-17
@@ -2,6 +2,7 @@ import { isUnavailableCapability } from './sources/capability.js';
|
|||||||
import { createOverpassFeatureSource } from './sources/overpassFeatures.js';
|
import { createOverpassFeatureSource } from './sources/overpassFeatures.js';
|
||||||
import { applicationServices } from './services/application.js';
|
import { applicationServices } from './services/application.js';
|
||||||
import * as Cesium from 'cesium';
|
import * as Cesium from 'cesium';
|
||||||
|
import * as geo from './geo/index.js';
|
||||||
import {
|
import {
|
||||||
viewportBias,
|
viewportBias,
|
||||||
placesNearViewRecovery,
|
placesNearViewRecovery,
|
||||||
@@ -543,18 +544,18 @@ export const GLOBE_VIEW = Object.freeze({
|
|||||||
*/
|
*/
|
||||||
export function flyToGlobeView(viewer, options = {}) {
|
export function flyToGlobeView(viewer, options = {}) {
|
||||||
const carto = viewer.camera.positionCartographic;
|
const carto = viewer.camera.positionCartographic;
|
||||||
const longitude = Cesium.Math.toDegrees(carto.longitude);
|
const longitude = geo.math.toDegrees(carto.longitude);
|
||||||
const latitude = Cesium.Math.toDegrees(carto.latitude);
|
const latitude = geo.math.toDegrees(carto.latitude);
|
||||||
viewer.camera.cancelFlight();
|
viewer.camera.cancelFlight();
|
||||||
viewer.camera.flyTo({
|
viewer.camera.flyTo({
|
||||||
destination: Cesium.Cartesian3.fromDegrees(
|
destination: geo.cartesian3.fromDegrees(
|
||||||
longitude,
|
longitude,
|
||||||
latitude,
|
latitude,
|
||||||
GLOBE_VIEW.heightM,
|
GLOBE_VIEW.heightM,
|
||||||
),
|
),
|
||||||
orientation: {
|
orientation: {
|
||||||
heading: 0,
|
heading: 0,
|
||||||
pitch: Cesium.Math.toRadians(GLOBE_VIEW.pitchDeg),
|
pitch: geo.math.toRadians(GLOBE_VIEW.pitchDeg),
|
||||||
roll: 0,
|
roll: 0,
|
||||||
},
|
},
|
||||||
duration: finitePositive(options.duration) || GLOBE_VIEW.durationS,
|
duration: finitePositive(options.duration) || GLOBE_VIEW.durationS,
|
||||||
@@ -614,7 +615,7 @@ export function flyToLandmark(viewer, lat, lon, options = {}) {
|
|||||||
} = options;
|
} = options;
|
||||||
|
|
||||||
// Sample terrain height (sync — uses loaded tiles; 0 if globe/terrain not ready)
|
// Sample terrain height (sync — uses loaded tiles; 0 if globe/terrain not ready)
|
||||||
const targetCartographic = Cesium.Cartographic.fromDegrees(lon, lat);
|
const targetCartographic = geo.cartographic.fromDegrees(lon, lat);
|
||||||
const sampledHeight = viewer.scene.globe?.getHeight(targetCartographic);
|
const sampledHeight = viewer.scene.globe?.getHeight(targetCartographic);
|
||||||
|
|
||||||
// Use sampled height if available, otherwise the cached ground-floor
|
// Use sampled height if available, otherwise the cached ground-floor
|
||||||
@@ -641,7 +642,7 @@ export function flyToLandmark(viewer, lat, lon, options = {}) {
|
|||||||
const targetHeight = bounds
|
const targetHeight = bounds
|
||||||
? terrainHeight + bounds.height / 2
|
? terrainHeight + bounds.height / 2
|
||||||
: terrainHeight + buildingHeight;
|
: terrainHeight + buildingHeight;
|
||||||
const targetPosition = Cesium.Cartesian3.fromDegrees(lon, lat, targetHeight);
|
const targetPosition = geo.cartesian3.fromDegrees(lon, lat, targetHeight);
|
||||||
const boundingRadius = bounds ? buildingBoundingRadius(bounds) : 0;
|
const boundingRadius = bounds ? buildingBoundingRadius(bounds) : 0;
|
||||||
const framingRange = bounds
|
const framingRange = bounds
|
||||||
? Math.max(
|
? Math.max(
|
||||||
@@ -651,8 +652,8 @@ export function flyToLandmark(viewer, lat, lon, options = {}) {
|
|||||||
: range;
|
: range;
|
||||||
|
|
||||||
const hpr = new Cesium.HeadingPitchRange(
|
const hpr = new Cesium.HeadingPitchRange(
|
||||||
Cesium.Math.toRadians(heading),
|
geo.math.toRadians(heading),
|
||||||
Cesium.Math.toRadians(pitch),
|
geo.math.toRadians(pitch),
|
||||||
framingRange,
|
framingRange,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1095,7 +1096,7 @@ export function viewportMetrics(viewport) {
|
|||||||
|
|
||||||
const latSpanKm = Math.abs(latSpanDeg) * KM_PER_DEGREE;
|
const latSpanKm = Math.abs(latSpanDeg) * KM_PER_DEGREE;
|
||||||
const lonSpanKm =
|
const lonSpanKm =
|
||||||
lonSpanDeg * KM_PER_DEGREE * Math.cos(Cesium.Math.toRadians(centerLat));
|
lonSpanDeg * KM_PER_DEGREE * Math.cos(geo.math.toRadians(centerLat));
|
||||||
return {
|
return {
|
||||||
latSpanDeg,
|
latSpanDeg,
|
||||||
lonSpanDeg,
|
lonSpanDeg,
|
||||||
@@ -1157,12 +1158,12 @@ const PLACE_FALLBACK_HALF_SPAN_KM = 20;
|
|||||||
|
|
||||||
/** Great-circle distance in km (small enough here that the spherical model is fine). */
|
/** Great-circle distance in km (small enough here that the spherical model is fine). */
|
||||||
function greatCircleKm(lat1, lng1, lat2, lng2) {
|
function greatCircleKm(lat1, lng1, lat2, lng2) {
|
||||||
const dLat = Cesium.Math.toRadians(lat2 - lat1);
|
const dLat = geo.math.toRadians(lat2 - lat1);
|
||||||
const dLng = Cesium.Math.toRadians(lng2 - lng1);
|
const dLng = geo.math.toRadians(lng2 - lng1);
|
||||||
const a =
|
const a =
|
||||||
Math.sin(dLat / 2) ** 2 +
|
Math.sin(dLat / 2) ** 2 +
|
||||||
Math.cos(Cesium.Math.toRadians(lat1)) *
|
Math.cos(geo.math.toRadians(lat1)) *
|
||||||
Math.cos(Cesium.Math.toRadians(lat2)) *
|
Math.cos(geo.math.toRadians(lat2)) *
|
||||||
Math.sin(dLng / 2) ** 2;
|
Math.sin(dLng / 2) ** 2;
|
||||||
return 6371 * 2 * Math.asin(Math.min(1, Math.sqrt(a)));
|
return 6371 * 2 * Math.asin(Math.min(1, Math.sqrt(a)));
|
||||||
}
|
}
|
||||||
@@ -1210,7 +1211,7 @@ export function placeFramingViewport(
|
|||||||
|
|
||||||
const latHalfDeg = PLACE_FALLBACK_HALF_SPAN_KM / KM_PER_DEGREE;
|
const latHalfDeg = PLACE_FALLBACK_HALF_SPAN_KM / KM_PER_DEGREE;
|
||||||
// Guard the cosine so a near-polar anchor cannot blow the longitude half-extent up.
|
// Guard the cosine so a near-polar anchor cannot blow the longitude half-extent up.
|
||||||
const cosLat = Math.max(0.05, Math.cos(Cesium.Math.toRadians(anchorLat)));
|
const cosLat = Math.max(0.05, Math.cos(geo.math.toRadians(anchorLat)));
|
||||||
const lngHalfDeg = PLACE_FALLBACK_HALF_SPAN_KM / (KM_PER_DEGREE * cosLat);
|
const lngHalfDeg = PLACE_FALLBACK_HALF_SPAN_KM / (KM_PER_DEGREE * cosLat);
|
||||||
const wrapLng = (lng) => ((((lng + 180) % 360) + 360) % 360) - 180;
|
const wrapLng = (lng) => ((((lng + 180) % 360) + 360) % 360) - 180;
|
||||||
return {
|
return {
|
||||||
@@ -1349,7 +1350,7 @@ function flyToViewportBounds(viewer, viewport, options = {}) {
|
|||||||
// Same short-way-round rule for the reported centre: averaging raw longitudes
|
// Same short-way-round rule for the reported centre: averaging raw longitudes
|
||||||
// puts a dateline-crossing box's centre on the opposite side of the planet.
|
// puts a dateline-crossing box's centre on the opposite side of the planet.
|
||||||
return {
|
return {
|
||||||
targetPosition: Cesium.Cartesian3.fromDegrees(
|
targetPosition: geo.cartesian3.fromDegrees(
|
||||||
metrics.centerLng,
|
metrics.centerLng,
|
||||||
metrics.centerLat,
|
metrics.centerLat,
|
||||||
0,
|
0,
|
||||||
@@ -1379,7 +1380,7 @@ function buildingBoundingRadius(bounds) {
|
|||||||
|
|
||||||
function rangeForBoundingSphere(viewer, radius) {
|
function rangeForBoundingSphere(viewer, radius) {
|
||||||
const frustum = viewer.camera.frustum;
|
const frustum = viewer.camera.frustum;
|
||||||
const verticalFov = Number(frustum?.fov) || Cesium.Math.toRadians(60);
|
const verticalFov = Number(frustum?.fov) || geo.math.toRadians(60);
|
||||||
const aspectRatio = Math.max(0.5, Number(frustum?.aspectRatio) || 1);
|
const aspectRatio = Math.max(0.5, Number(frustum?.aspectRatio) || 1);
|
||||||
const horizontalFov = 2 * Math.atan(Math.tan(verticalFov / 2) * aspectRatio);
|
const horizontalFov = 2 * Math.atan(Math.tan(verticalFov / 2) * aspectRatio);
|
||||||
const limitingFov = Math.min(verticalFov, horizontalFov);
|
const limitingFov = Math.min(verticalFov, horizontalFov);
|
||||||
@@ -1537,7 +1538,7 @@ function pointInPolygon(lon, lat, coordinates) {
|
|||||||
function approximateDistanceM(latA, lonA, latB, lonB) {
|
function approximateDistanceM(latA, lonA, latB, lonB) {
|
||||||
const latitudeScale = 111320;
|
const latitudeScale = 111320;
|
||||||
const longitudeScale =
|
const longitudeScale =
|
||||||
latitudeScale * Math.cos(Cesium.Math.toRadians((latA + latB) / 2));
|
latitudeScale * Math.cos(geo.math.toRadians((latA + latB) / 2));
|
||||||
return Math.hypot(
|
return Math.hypot(
|
||||||
(latB - latA) * latitudeScale,
|
(latB - latA) * latitudeScale,
|
||||||
(lonB - lonA) * longitudeScale,
|
(lonB - lonA) * longitudeScale,
|
||||||
|
|||||||
+4
-3
@@ -1,4 +1,5 @@
|
|||||||
import * as Cesium from 'cesium';
|
import * as Cesium from 'cesium';
|
||||||
|
import * as geo from './geo/index.js';
|
||||||
import {
|
import {
|
||||||
holdContinuousRender,
|
holdContinuousRender,
|
||||||
releaseContinuousRender,
|
releaseContinuousRender,
|
||||||
@@ -16,7 +17,7 @@ export class OrbitController {
|
|||||||
this.target = null;
|
this.target = null;
|
||||||
this.radius = 500;
|
this.radius = 500;
|
||||||
this.pitch = -30;
|
this.pitch = -30;
|
||||||
this.speed = Cesium.Math.toRadians(6); // ~6°/sec → full rotation in ~60s
|
this.speed = geo.math.toRadians(6); // ~6°/sec → full rotation in ~60s
|
||||||
this.angle = 0;
|
this.angle = 0;
|
||||||
this._removeListener = null;
|
this._removeListener = null;
|
||||||
}
|
}
|
||||||
@@ -35,7 +36,7 @@ export class OrbitController {
|
|||||||
this.target = targetCartesian;
|
this.target = targetCartesian;
|
||||||
this.radius = options.radius || this.radius;
|
this.radius = options.radius || this.radius;
|
||||||
this.pitch = options.pitch || this.pitch;
|
this.pitch = options.pitch || this.pitch;
|
||||||
this.speed = Cesium.Math.toRadians(options.speed || 6);
|
this.speed = geo.math.toRadians(options.speed || 6);
|
||||||
this.active = true;
|
this.active = true;
|
||||||
// Orbit mutates the camera from preRender — without a hold the loop
|
// Orbit mutates the camera from preRender — without a hold the loop
|
||||||
// starves after its first idle frame. (perf wave 2)
|
// starves after its first idle frame. (perf wave 2)
|
||||||
@@ -56,7 +57,7 @@ export class OrbitController {
|
|||||||
|
|
||||||
const hpr = new Cesium.HeadingPitchRange(
|
const hpr = new Cesium.HeadingPitchRange(
|
||||||
this.angle,
|
this.angle,
|
||||||
Cesium.Math.toRadians(this.pitch),
|
geo.math.toRadians(this.pitch),
|
||||||
this.radius,
|
this.radius,
|
||||||
);
|
);
|
||||||
this.viewer.camera.lookAt(this.target, hpr);
|
this.viewer.camera.lookAt(this.target, hpr);
|
||||||
|
|||||||
+16
-16
@@ -46,7 +46,7 @@
|
|||||||
* are per-layer, keyed by that layer's icao space).
|
* are per-layer, keyed by that layer's icao space).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as Cesium from 'cesium';
|
import * as geo from '../geo/index.js';
|
||||||
|
|
||||||
/** Taxi threshold: a cached snap answers directly for moves up to this far from
|
/** Taxi threshold: a cached snap answers directly for moves up to this far from
|
||||||
* the sampled spot (m). Past it the value is demoted to a held last-known and a
|
* the sampled spot (m). Past it the value is demoted to a held last-known and a
|
||||||
@@ -178,13 +178,13 @@ export function createGroundSnap({ groundFloor }) {
|
|||||||
const entries = new Map();
|
const entries = new Map();
|
||||||
let windowStartMs = 0;
|
let windowStartMs = 0;
|
||||||
let windowCount = 0;
|
let windowCount = 0;
|
||||||
const scratchCarto = new Cesium.Cartographic();
|
const scratchCarto = geo.cartographic.create();
|
||||||
const scratchSurfacePos = new Cesium.Cartesian3();
|
const scratchSurfacePos = geo.cartesian3.create();
|
||||||
/** Separate from `scratchCarto`: the held-evidence check runs on paths that
|
/** Separate from `scratchCarto`: the held-evidence check runs on paths that
|
||||||
* return BEFORE the sample writes `scratchCarto`, and on the sampling path it
|
* return BEFORE the sample writes `scratchCarto`, and on the sampling path it
|
||||||
* must not disturb the cartographic that `reportValidatedMeshFloorCell` reads
|
* must not disturb the cartographic that `reportValidatedMeshFloorCell` reads
|
||||||
* back after the sample lands. */
|
* back after the sample lands. */
|
||||||
const scratchHeldCarto = new Cesium.Cartographic();
|
const scratchHeldCarto = geo.cartographic.create();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The last measurement for a contact whose fresh snap has been demoted — it
|
* The last measurement for a contact whose fresh snap has been demoted — it
|
||||||
@@ -205,7 +205,7 @@ export function createGroundSnap({ groundFloor }) {
|
|||||||
if (!entry || !entry.held || entry.h == null || !entry.samplePos)
|
if (!entry || !entry.held || entry.h == null || !entry.samplePos)
|
||||||
return null;
|
return null;
|
||||||
if (
|
if (
|
||||||
Cesium.Cartesian3.distanceSquared(surfacePos, entry.samplePos) >
|
geo.cartesian3.distanceSquared(surfacePos, entry.samplePos) >
|
||||||
HELD_SNAP_MAX_DRIFT_M * HELD_SNAP_MAX_DRIFT_M
|
HELD_SNAP_MAX_DRIFT_M * HELD_SNAP_MAX_DRIFT_M
|
||||||
) {
|
) {
|
||||||
return dropHold(entry);
|
return dropHold(entry);
|
||||||
@@ -253,15 +253,15 @@ export function createGroundSnap({ groundFloor }) {
|
|||||||
* @returns {number|null}
|
* @returns {number|null}
|
||||||
*/
|
*/
|
||||||
function freshMeasuredFloorAt(surfacePos) {
|
function freshMeasuredFloorAt(surfacePos) {
|
||||||
const carto = Cesium.Cartographic.fromCartesian(
|
const carto = geo.cartographic.fromCartesian(
|
||||||
surfacePos,
|
surfacePos,
|
||||||
Cesium.Ellipsoid.WGS84,
|
geo.ellipsoid.WGS84,
|
||||||
scratchHeldCarto,
|
scratchHeldCarto,
|
||||||
);
|
);
|
||||||
if (!carto) return null;
|
if (!carto) return null;
|
||||||
return cachedMeshFloor(
|
return cachedMeshFloor(
|
||||||
Cesium.Math.toDegrees(carto.latitude),
|
geo.math.toDegrees(carto.latitude),
|
||||||
Cesium.Math.toDegrees(carto.longitude),
|
geo.math.toDegrees(carto.longitude),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -284,7 +284,7 @@ export function createGroundSnap({ groundFloor }) {
|
|||||||
* @returns {number|null}
|
* @returns {number|null}
|
||||||
*/
|
*/
|
||||||
function heightFor(viewer, icao, pos, getExclusions) {
|
function heightFor(viewer, icao, pos, getExclusions) {
|
||||||
const surfacePos = Cesium.Ellipsoid.WGS84.scaleToGeodeticSurface(
|
const surfacePos = geo.ellipsoid.WGS84.scaleToGeodeticSurface(
|
||||||
pos,
|
pos,
|
||||||
scratchSurfacePos,
|
scratchSurfacePos,
|
||||||
);
|
);
|
||||||
@@ -292,7 +292,7 @@ export function createGroundSnap({ groundFloor }) {
|
|||||||
const cached = entries.get(icao);
|
const cached = entries.get(icao);
|
||||||
if (cached && cached.h != null && cached.samplePos && !cached.held) {
|
if (cached && cached.h != null && cached.samplePos && !cached.held) {
|
||||||
if (
|
if (
|
||||||
Cesium.Cartesian3.distanceSquared(surfacePos, cached.samplePos) <=
|
geo.cartesian3.distanceSquared(surfacePos, cached.samplePos) <=
|
||||||
MOVE_INVALIDATE_M * MOVE_INVALIDATE_M
|
MOVE_INVALIDATE_M * MOVE_INVALIDATE_M
|
||||||
) {
|
) {
|
||||||
return cached.h;
|
return cached.h;
|
||||||
@@ -339,9 +339,9 @@ export function createGroundSnap({ groundFloor }) {
|
|||||||
windowCount += 1;
|
windowCount += 1;
|
||||||
let sampled;
|
let sampled;
|
||||||
try {
|
try {
|
||||||
const carto = Cesium.Cartographic.fromCartesian(
|
const carto = geo.cartographic.fromCartesian(
|
||||||
pos,
|
pos,
|
||||||
Cesium.Ellipsoid.WGS84,
|
geo.ellipsoid.WGS84,
|
||||||
scratchCarto,
|
scratchCarto,
|
||||||
);
|
);
|
||||||
// sampleHeight throws when unsupported (no depth textures) — that's a miss.
|
// sampleHeight throws when unsupported (no depth textures) — that's a miss.
|
||||||
@@ -357,8 +357,8 @@ export function createGroundSnap({ groundFloor }) {
|
|||||||
if (!Number.isFinite(sampled) || sampled < -150) return miss();
|
if (!Number.isFinite(sampled) || sampled < -150) return miss();
|
||||||
if (meshFloorPreferred()) {
|
if (meshFloorPreferred()) {
|
||||||
reportValidatedMeshFloorCell(
|
reportValidatedMeshFloorCell(
|
||||||
Cesium.Math.toDegrees(scratchCarto.latitude),
|
geo.math.toDegrees(scratchCarto.latitude),
|
||||||
Cesium.Math.toDegrees(scratchCarto.longitude),
|
geo.math.toDegrees(scratchCarto.longitude),
|
||||||
sampled,
|
sampled,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -366,7 +366,7 @@ export function createGroundSnap({ groundFloor }) {
|
|||||||
// contact is now, and it outranks a memory of where it was.
|
// contact is now, and it outranks a memory of where it was.
|
||||||
entries.set(icao, {
|
entries.set(icao, {
|
||||||
h: sampled,
|
h: sampled,
|
||||||
samplePos: Cesium.Cartesian3.clone(surfacePos),
|
samplePos: geo.cartesian3.clone(surfacePos),
|
||||||
held: false,
|
held: false,
|
||||||
nextRetryMs: 0,
|
nextRetryMs: 0,
|
||||||
misses: 0,
|
misses: 0,
|
||||||
|
|||||||
+10
-16
@@ -1,4 +1,5 @@
|
|||||||
import * as Cesium from 'cesium';
|
import * as Cesium from 'cesium';
|
||||||
|
import * as geo from './geo/index.js';
|
||||||
import { BLOOM_INTENSITY_DEFAULT, BLOOM_SCALE_VERSION } from './bloom.js';
|
import { BLOOM_INTENSITY_DEFAULT, BLOOM_SCALE_VERSION } from './bloom.js';
|
||||||
import {
|
import {
|
||||||
migrateDetectionState,
|
migrateDetectionState,
|
||||||
@@ -263,15 +264,11 @@ export class ShareLinkManager {
|
|||||||
if (this._destroyed || !state)
|
if (this._destroyed || !state)
|
||||||
return { succeeded: false, reason: 'unavailable' };
|
return { succeeded: false, reason: 'unavailable' };
|
||||||
const view = {
|
const view = {
|
||||||
destination: Cesium.Cartesian3.fromDegrees(
|
destination: geo.cartesian3.fromDegrees(state.lon, state.lat, state.alt),
|
||||||
state.lon,
|
|
||||||
state.lat,
|
|
||||||
state.alt,
|
|
||||||
),
|
|
||||||
orientation: {
|
orientation: {
|
||||||
heading: Cesium.Math.toRadians(state.heading),
|
heading: geo.math.toRadians(state.heading),
|
||||||
pitch: Cesium.Math.toRadians(state.pitch),
|
pitch: geo.math.toRadians(state.pitch),
|
||||||
roll: Cesium.Math.toRadians(state.roll),
|
roll: geo.math.toRadians(state.roll),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let cameraPromise = Promise.resolve({
|
let cameraPromise = Promise.resolve({
|
||||||
@@ -548,21 +545,18 @@ export class ShareLinkManager {
|
|||||||
|
|
||||||
const params = new URLSearchParams();
|
const params = new URLSearchParams();
|
||||||
params.set('v', '2');
|
params.set('v', '2');
|
||||||
params.set('lat', Cesium.Math.toDegrees(carto.latitude).toFixed(4));
|
params.set('lat', geo.math.toDegrees(carto.latitude).toFixed(4));
|
||||||
params.set('lon', Cesium.Math.toDegrees(carto.longitude).toFixed(4));
|
params.set('lon', geo.math.toDegrees(carto.longitude).toFixed(4));
|
||||||
params.set('alt', Math.round(carto.height).toString());
|
params.set('alt', Math.round(carto.height).toString());
|
||||||
params.set(
|
params.set(
|
||||||
'heading',
|
'heading',
|
||||||
Math.round(Cesium.Math.toDegrees(camera.heading)).toString(),
|
Math.round(geo.math.toDegrees(camera.heading)).toString(),
|
||||||
);
|
);
|
||||||
params.set(
|
params.set(
|
||||||
'pitch',
|
'pitch',
|
||||||
Math.round(Cesium.Math.toDegrees(camera.pitch)).toString(),
|
Math.round(geo.math.toDegrees(camera.pitch)).toString(),
|
||||||
);
|
|
||||||
params.set(
|
|
||||||
'roll',
|
|
||||||
Math.round(Cesium.Math.toDegrees(camera.roll)).toString(),
|
|
||||||
);
|
);
|
||||||
|
params.set('roll', Math.round(geo.math.toDegrees(camera.roll)).toString());
|
||||||
params.set('style', STYLE_TO_URL[this._currentStyle] || 'normal');
|
params.set('style', STYLE_TO_URL[this._currentStyle] || 'normal');
|
||||||
params.set('bloom', this._bloomEnabled ? '1' : '0');
|
params.set('bloom', this._bloomEnabled ? '1' : '0');
|
||||||
params.set('sharpen', this._sharpenEnabled ? '1' : '0');
|
params.set('sharpen', this._sharpenEnabled ? '1' : '0');
|
||||||
|
|||||||
+4
-3
@@ -2,6 +2,7 @@
|
|||||||
* One-click camera transfer for layer-owned world targets.
|
* One-click camera transfer for layer-owned world targets.
|
||||||
*/
|
*/
|
||||||
import * as Cesium from 'cesium';
|
import * as Cesium from 'cesium';
|
||||||
|
import * as geo from './geo/index.js';
|
||||||
|
|
||||||
export const WORLD_FOCUS_REQUEST_EVENT = 'gev:world-request-focus';
|
export const WORLD_FOCUS_REQUEST_EVENT = 'gev:world-request-focus';
|
||||||
export const WORLD_CLICK_FOCUS_DURATION_SEC = 1.9;
|
export const WORLD_CLICK_FOCUS_DURATION_SEC = 1.9;
|
||||||
@@ -26,10 +27,10 @@ export function isValidWorldFocusTarget(detail) {
|
|||||||
// Vessel and fire targets are surface-anchored Earth positions. Merely
|
// Vessel and fire targets are surface-anchored Earth positions. Merely
|
||||||
// finite coordinates near the ECEF origin cannot be flown to, and must be
|
// finite coordinates near the ECEF origin cannot be flown to, and must be
|
||||||
// rejected before the camera policy releases a current follow owner.
|
// rejected before the camera policy releases a current follow owner.
|
||||||
const magnitude = Cesium.Cartesian3.magnitude(position);
|
const magnitude = geo.cartesian3.magnitude(position);
|
||||||
return (
|
return (
|
||||||
Number.isFinite(magnitude) &&
|
Number.isFinite(magnitude) &&
|
||||||
magnitude >= Cesium.Ellipsoid.WGS84.minimumRadius * 0.95
|
magnitude >= geo.ellipsoid.WGS84.minimumRadius * 0.95
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,7 +86,7 @@ export function flyToWorldTarget(viewer, target = {}) {
|
|||||||
{
|
{
|
||||||
offset: new Cesium.HeadingPitchRange(
|
offset: new Cesium.HeadingPitchRange(
|
||||||
heading,
|
heading,
|
||||||
Cesium.Math.toRadians(framing.pitchDeg),
|
geo.math.toRadians(framing.pitchDeg),
|
||||||
framing.rangeM,
|
framing.rangeM,
|
||||||
),
|
),
|
||||||
duration,
|
duration,
|
||||||
|
|||||||
Reference in new issue
Block a user