mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-06 11:24:00 +00:00
refactor(launches,cctv,alpr): take vector maths from src/geo
Launches selection/replay/panel/policy/policyHelpers/state/camera, CCTV geometry/model/projection/navigation/cards/geometryQueue/state and ALPR model/visuals now use src/geo for Math, Cartesian2/3, Cartographic, Matrix3/4, Quaternion and ENU frames. launches/paths.js keeps Cesium (EllipsoidGeodesic). In camera.js, EllipsoidGeodesic, BoundingSphere.fromPoints/union and the BoundingSphere constructor stay on Cesium; the geo Cartographics passed into EllipsoidGeodesic are only read field by field and cloned there (computeProperties). The CCTV plane orientation stays a Cesium Quaternion and plane dimensions a Cesium Cartesian2 (entity ConstantProperty values). launches-layer and alpr-cameras own the src/geo files.
This commit is contained in:
1 parent
ee8b94d987
commit
a915bdb3e5
17 files changed
+215
-214
No files matched your search
@@ -1145,7 +1145,21 @@
|
||||
"src/layers/launches/source.js",
|
||||
"src/layers/launches/state.js",
|
||||
"src/layers/launches/testing.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"]
|
||||
},
|
||||
@@ -1406,7 +1420,21 @@
|
||||
"src/sources/httpBody.js",
|
||||
"src/sources/vectorTiles.js",
|
||||
"src/sources/phaseTiming.js",
|
||||
"src/layers/alpr/floors.js"
|
||||
"src/layers/alpr/floors.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", "@mapbox/vector-tile", "pbf"]
|
||||
},
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import * as Cesium from 'cesium';
|
||||
import * as geo from '../../geo/index.js';
|
||||
import { EARTH_MEAN_RADIUS_M } from './policy.js';
|
||||
export * from './records.js';
|
||||
|
||||
@@ -12,9 +12,9 @@ export * from './records.js';
|
||||
*/
|
||||
export function destinationPointDeg(latDeg, lonDeg, bearingDeg, distanceM) {
|
||||
const angularDistance = distanceM / EARTH_MEAN_RADIUS_M;
|
||||
const bearing = Cesium.Math.toRadians(bearingDeg);
|
||||
const lat1 = Cesium.Math.toRadians(latDeg);
|
||||
const lon1 = Cesium.Math.toRadians(lonDeg);
|
||||
const bearing = geo.math.toRadians(bearingDeg);
|
||||
const lat1 = geo.math.toRadians(latDeg);
|
||||
const lon1 = geo.math.toRadians(lonDeg);
|
||||
const lat2 = Math.asin(
|
||||
Math.sin(lat1) * Math.cos(angularDistance) +
|
||||
Math.cos(lat1) * Math.sin(angularDistance) * Math.cos(bearing),
|
||||
@@ -26,8 +26,8 @@ export function destinationPointDeg(latDeg, lonDeg, bearingDeg, distanceM) {
|
||||
Math.cos(angularDistance) - Math.sin(lat1) * Math.sin(lat2),
|
||||
);
|
||||
return {
|
||||
latitude: Cesium.Math.toDegrees(lat2),
|
||||
longitude: Cesium.Math.toDegrees(lon2),
|
||||
latitude: geo.math.toDegrees(lat2),
|
||||
longitude: geo.math.toDegrees(lon2),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import * as Cesium from 'cesium';
|
||||
import * as geo from '../../geo/index.js';
|
||||
import { destinationPointDeg } from './model.js';
|
||||
import {
|
||||
DIRECTION_CONE_M,
|
||||
@@ -95,13 +95,9 @@ export function directionWedgePositions(record, heightM = 0, heightAt = null) {
|
||||
return Number.isFinite(height) ? height : heightM;
|
||||
};
|
||||
return [
|
||||
Cesium.Cartesian3.fromDegrees(record.longitude, record.latitude, heightM),
|
||||
Cesium.Cartesian3.fromDegrees(left.longitude, left.latitude, corner(left)),
|
||||
Cesium.Cartesian3.fromDegrees(
|
||||
right.longitude,
|
||||
right.latitude,
|
||||
corner(right),
|
||||
),
|
||||
geo.cartesian3.fromDegrees(record.longitude, record.latitude, heightM),
|
||||
geo.cartesian3.fromDegrees(left.longitude, left.latitude, corner(left)),
|
||||
geo.cartesian3.fromDegrees(right.longitude, right.latitude, corner(right)),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
CCTV_FRAME_CANVAS_H,
|
||||
applyFrameResult,
|
||||
} from '../../data/cctvCards.js';
|
||||
import * as Cesium from 'cesium';
|
||||
import * as geo from '../../geo/index.js';
|
||||
import { horizonOccluder } from '../../data/iconOrientation.js';
|
||||
import { selectCctvLod, applyEvictionGrace } from '../../data/cctvLod.js';
|
||||
import {
|
||||
@@ -85,8 +85,8 @@ export function createCards({ state: layerState, services, parts, source }) {
|
||||
}
|
||||
const scene = layerState._viewer.scene;
|
||||
const carto = layerState._viewer.camera.positionCartographic;
|
||||
const viewerLat = carto ? Cesium.Math.toDegrees(carto.latitude) : 0;
|
||||
const viewerLon = carto ? Cesium.Math.toDegrees(carto.longitude) : 0;
|
||||
const viewerLat = carto ? geo.math.toDegrees(carto.latitude) : 0;
|
||||
const viewerLon = carto ? geo.math.toDegrees(carto.longitude) : 0;
|
||||
// The active camera is excluded from ambient selection ALWAYS (not just
|
||||
// after its async activation settles). It is published separately in the
|
||||
// protected lane below, and grace never applies to it.
|
||||
|
||||
+13
-16
@@ -1,4 +1,5 @@
|
||||
import * as Cesium from 'cesium';
|
||||
import * as geo from '../../geo/index.js';
|
||||
import { createFrustumVolumePrimitive } from '../../data/cctvViewshed.js';
|
||||
import {
|
||||
PROJECTION_VERT_ASPECT,
|
||||
@@ -272,7 +273,7 @@ export function createGeometry({ state: layerState, services, parts, source }) {
|
||||
*/
|
||||
|
||||
function frustumCartesians(geometry) {
|
||||
const at = (p) => Cesium.Cartesian3.fromDegrees(p.lon, p.lat, p.alt);
|
||||
const at = (p) => geo.cartesian3.fromDegrees(p.lon, p.lat, p.alt);
|
||||
return {
|
||||
mount: at(geometry.mount),
|
||||
capCenter: at(geometry.capCenter),
|
||||
@@ -280,7 +281,7 @@ export function createGeometry({ state: layerState, services, parts, source }) {
|
||||
tr: at(geometry.corners.tr),
|
||||
br: at(geometry.corners.br),
|
||||
bl: at(geometry.corners.bl),
|
||||
label: Cesium.Cartesian3.fromDegrees(
|
||||
label: geo.cartesian3.fromDegrees(
|
||||
geometry.topCenter.lon,
|
||||
geometry.topCenter.lat,
|
||||
geometry.topCenter.alt + 1.2,
|
||||
@@ -301,26 +302,22 @@ export function createGeometry({ state: layerState, services, parts, source }) {
|
||||
function frustumFrameEcef(camera, atPos) {
|
||||
const h = parts.model.toRad(camera.headingDeg);
|
||||
const p = parts.model.toRad(camera.pitchDeg);
|
||||
const enu = Cesium.Transforms.eastNorthUpToFixedFrame(atPos);
|
||||
const rot = Cesium.Matrix4.getMatrix3(enu, new Cesium.Matrix3());
|
||||
const enu = geo.transforms.eastNorthUpToFixedFrame(atPos);
|
||||
const rot = geo.matrix4.getMatrix3(enu, geo.matrix3.create());
|
||||
// ENU components: view axis + the perpendicular "up" of the pitched cap.
|
||||
const dirEnu = new Cesium.Cartesian3(
|
||||
const dirEnu = geo.cartesian3.create(
|
||||
Math.sin(h) * Math.cos(p),
|
||||
Math.cos(h) * Math.cos(p),
|
||||
Math.sin(p),
|
||||
);
|
||||
const upEnu = new Cesium.Cartesian3(
|
||||
const upEnu = geo.cartesian3.create(
|
||||
-Math.sin(p) * Math.sin(h),
|
||||
-Math.sin(p) * Math.cos(h),
|
||||
Math.cos(p),
|
||||
);
|
||||
return {
|
||||
dir: Cesium.Matrix3.multiplyByVector(
|
||||
rot,
|
||||
dirEnu,
|
||||
new Cesium.Cartesian3(),
|
||||
),
|
||||
up: Cesium.Matrix3.multiplyByVector(rot, upEnu, new Cesium.Cartesian3()),
|
||||
dir: geo.matrix3.multiplyByVector(rot, dirEnu, geo.cartesian3.create()),
|
||||
up: geo.matrix3.multiplyByVector(rot, upEnu, geo.cartesian3.create()),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -462,10 +459,10 @@ export function createGeometry({ state: layerState, services, parts, source }) {
|
||||
sampleMeshFloorCells(layerState._viewer?.scene, [point], {
|
||||
excludeObjects: excludeObjects.filter(Boolean),
|
||||
viewerLat: viewerCarto
|
||||
? Cesium.Math.toDegrees(viewerCarto.latitude)
|
||||
? geo.math.toDegrees(viewerCarto.latitude)
|
||||
: undefined,
|
||||
viewerLon: viewerCarto
|
||||
? Cesium.Math.toDegrees(viewerCarto.longitude)
|
||||
? geo.math.toDegrees(viewerCarto.longitude)
|
||||
: undefined,
|
||||
});
|
||||
}
|
||||
@@ -623,7 +620,7 @@ export function createGeometry({ state: layerState, services, parts, source }) {
|
||||
if (Math.abs(rangeScale - 1) > 0.0001) return; // slider overrides the clamp
|
||||
try {
|
||||
const mountAlt = parts.ground.groundAltFor(record) + camera.mountHeightM;
|
||||
const mountPos = Cesium.Cartesian3.fromDegrees(
|
||||
const mountPos = geo.cartesian3.fromDegrees(
|
||||
camera.lon,
|
||||
camera.lat,
|
||||
mountAlt,
|
||||
@@ -637,7 +634,7 @@ export function createGeometry({ state: layerState, services, parts, source }) {
|
||||
}
|
||||
const hit = scene.pickFromRay(new Cesium.Ray(mountPos, dir), exclude);
|
||||
if (!hit?.position) return;
|
||||
const dist = Cesium.Cartesian3.distance(mountPos, hit.position);
|
||||
const dist = geo.cartesian3.distance(mountPos, hit.position);
|
||||
record.probeClampRangeM = activationProbeClampRange(camera.rangeM, dist);
|
||||
} catch {
|
||||
// probe failure → keep the unclamped range
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import * as Cesium from 'cesium';
|
||||
import * as geo from '../../geo/index.js';
|
||||
import {
|
||||
GEO_PROGRESS_NOTIFY_INTERVAL_MS,
|
||||
GEO_PROGRESS_NOTIFY_BATCH_LIMIT,
|
||||
@@ -298,10 +298,10 @@ export function createGeometryQueue({
|
||||
const active = parts.selection.getActiveRecord();
|
||||
const carto = layerState._viewer?.camera?.positionCartographic;
|
||||
const refLat = carto
|
||||
? Cesium.Math.toDegrees(carto.latitude)
|
||||
? geo.math.toDegrees(carto.latitude)
|
||||
: (active?.camera.lat ?? 0);
|
||||
const refLon = carto
|
||||
? Cesium.Math.toDegrees(carto.longitude)
|
||||
? geo.math.toDegrees(carto.longitude)
|
||||
: (active?.camera.lon ?? 0);
|
||||
const pending = layerState._records
|
||||
.filter((record) => record !== active)
|
||||
|
||||
+23
-20
@@ -1,4 +1,5 @@
|
||||
import * as Cesium from 'cesium';
|
||||
import * as geo from '../../geo/index.js';
|
||||
import { staticFrameRefreshMs } from '../../data/cctvLod.js';
|
||||
import { frameFetchDue, cardFetchPolicy } from '../../data/cctvCards.js';
|
||||
import { DEFAULT_CAMERA_CALIBRATION } from './policy.js';
|
||||
@@ -13,7 +14,7 @@ export function createModel({ state: layerState, services, parts, source }) {
|
||||
*/
|
||||
|
||||
function toRad(deg) {
|
||||
return Cesium.Math.toRadians(deg);
|
||||
return geo.math.toRadians(deg);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -283,8 +284,8 @@ export function createModel({ state: layerState, services, parts, source }) {
|
||||
const lon2 = lon1 + Math.atan2(y, x);
|
||||
|
||||
return {
|
||||
lat: Cesium.Math.toDegrees(lat2),
|
||||
lon: Cesium.Math.toDegrees(lon2),
|
||||
lat: geo.math.toDegrees(lat2),
|
||||
lon: geo.math.toDegrees(lon2),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -328,8 +329,8 @@ export function createModel({ state: layerState, services, parts, source }) {
|
||||
function currentViewContext() {
|
||||
const carto = layerState._viewer?.camera?.positionCartographic;
|
||||
if (!carto) return 'none';
|
||||
const lat = Cesium.Math.toDegrees(carto.latitude);
|
||||
const lon = Cesium.Math.toDegrees(carto.longitude);
|
||||
const lat = geo.math.toDegrees(carto.latitude);
|
||||
const lon = geo.math.toDegrees(carto.longitude);
|
||||
const alt = carto.height || 0;
|
||||
const zoomBucket =
|
||||
alt < 1500
|
||||
@@ -404,24 +405,26 @@ export function createModel({ state: layerState, services, parts, source }) {
|
||||
|
||||
function planeOrientationFor(camera, capCenterPos) {
|
||||
const frame = parts.geometry.frustumFrameEcef(camera, capCenterPos);
|
||||
const right = Cesium.Cartesian3.cross(
|
||||
const right = geo.cartesian3.cross(
|
||||
frame.dir,
|
||||
frame.up,
|
||||
new Cesium.Cartesian3(),
|
||||
geo.cartesian3.create(),
|
||||
);
|
||||
const normal = Cesium.Cartesian3.negate(frame.dir, new Cesium.Cartesian3());
|
||||
const m = new Cesium.Matrix3(
|
||||
right.x,
|
||||
frame.up.x,
|
||||
normal.x,
|
||||
right.y,
|
||||
frame.up.y,
|
||||
normal.y,
|
||||
right.z,
|
||||
frame.up.z,
|
||||
normal.z,
|
||||
);
|
||||
return Cesium.Quaternion.fromRotationMatrix(m);
|
||||
const normal = geo.cartesian3.negate(frame.dir, geo.cartesian3.create());
|
||||
// Column-major rotation whose columns are right, up and normal.
|
||||
const m = geo.matrix3.create();
|
||||
m[0] = right.x;
|
||||
m[1] = right.y;
|
||||
m[2] = right.z;
|
||||
m[3] = frame.up.x;
|
||||
m[4] = frame.up.y;
|
||||
m[5] = frame.up.z;
|
||||
m[6] = normal.x;
|
||||
m[7] = normal.y;
|
||||
m[8] = normal.z;
|
||||
// The quaternion becomes an entity's ConstantProperty value, so it stays a
|
||||
// Cesium Quaternion there (that property clones and compares its value).
|
||||
return geo.quaternion.fromRotationMatrix(m, new Cesium.Quaternion());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as Cesium from 'cesium';
|
||||
import * as geo from '../../geo/index.js';
|
||||
import { CCTV_FOCUS_RESULT } from './policy.js';
|
||||
|
||||
export function createNavigation({
|
||||
@@ -15,8 +16,8 @@ export function createNavigation({
|
||||
function nearestCameraIdToViewer() {
|
||||
const carto = layerState._viewer?.camera?.positionCartographic;
|
||||
if (!carto || !layerState._records.length) return null;
|
||||
const lat = Cesium.Math.toDegrees(carto.latitude);
|
||||
const lon = Cesium.Math.toDegrees(carto.longitude);
|
||||
const lat = geo.math.toDegrees(carto.latitude);
|
||||
const lon = geo.math.toDegrees(carto.longitude);
|
||||
|
||||
let best = null;
|
||||
for (const record of layerState._records) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { attachCctvVideo } from './videoPlayback.js';
|
||||
import * as Cesium from 'cesium';
|
||||
import * as geo from '../../geo/index.js';
|
||||
import {
|
||||
CCTV_PROJECTION_OVERLAY_SOURCE_ID,
|
||||
CCTV_PROJECTION_OVERLAY_SOURCE_OPTIONS,
|
||||
@@ -77,7 +78,7 @@ export function createProjection({
|
||||
);
|
||||
}
|
||||
if (runtime.labelPosition) {
|
||||
Cesium.Cartesian3.clone(positions.label, runtime.labelPosition);
|
||||
geo.cartesian3.clone(positions.label, runtime.labelPosition);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,8 +125,8 @@ export function createProjection({
|
||||
/** Create the native monitor plane plus its cached host-label presentation. */
|
||||
|
||||
function createProjectionPlane(record, runtime, geometry, positions) {
|
||||
runtime.labelPosition ||= new Cesium.Cartesian3();
|
||||
Cesium.Cartesian3.clone(positions.label, runtime.labelPosition);
|
||||
runtime.labelPosition ||= geo.cartesian3.create();
|
||||
geo.cartesian3.clone(positions.label, runtime.labelPosition);
|
||||
runtime.cameraId = String(record.camera.id);
|
||||
runtime.overlayEntry = createCctvProjectionOverlayEntry({
|
||||
cameraId: runtime.cameraId,
|
||||
@@ -142,7 +143,7 @@ export function createProjection({
|
||||
positions.capCenter,
|
||||
),
|
||||
plane: {
|
||||
plane: new Cesium.Plane(Cesium.Cartesian3.UNIT_Z, 0.0),
|
||||
plane: new Cesium.Plane(geo.cartesian3.UNIT_Z, 0.0),
|
||||
dimensions: new Cesium.Cartesian2(
|
||||
geometry.halfW * 2,
|
||||
geometry.halfH * 2,
|
||||
@@ -186,7 +187,7 @@ export function createProjection({
|
||||
video: null,
|
||||
planeEntity: null,
|
||||
cameraId: String(record.camera.id),
|
||||
labelPosition: new Cesium.Cartesian3(),
|
||||
labelPosition: geo.cartesian3.create(),
|
||||
overlayEntry: null,
|
||||
planeMaterial: null,
|
||||
buffers: null,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import * as Cesium from 'cesium';
|
||||
import * as geo from '../../geo/index.js';
|
||||
|
||||
export function createState({ services }) {
|
||||
const {
|
||||
@@ -74,7 +74,7 @@ export function createState({ services }) {
|
||||
|
||||
layerState._activeFocusStyleCount = 0;
|
||||
|
||||
layerState._scratchFocusScreen = new Cesium.Cartesian2();
|
||||
layerState._scratchFocusScreen = geo.cartesian2.create();
|
||||
|
||||
// Staggered geometry-load queue state (see startGeometryLoadQueue).
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as Cesium from 'cesium';
|
||||
import * as geo from '../../geo/index.js';
|
||||
import {
|
||||
REPLAY_ASCENT_CAMERA_OFFSET_RAD,
|
||||
REPLAY_ORBIT_CAMERA_OFFSET_RAD,
|
||||
@@ -18,12 +19,12 @@ export function createCamera({ state: layerState, services, parts, source }) {
|
||||
if (!path?.length) return fallback;
|
||||
const current = parts.paths.samplePath(path, progress);
|
||||
const currentCartographic =
|
||||
Cesium.Ellipsoid.WGS84.cartesianToCartographic(current);
|
||||
geo.ellipsoid.WGS84.cartesianToCartographic(current);
|
||||
if (!currentCartographic) return fallback;
|
||||
for (const step of [0.01, 0.025, 0.05, 0.1, 0.2]) {
|
||||
const next = parts.paths.samplePath(path, Math.min(1, progress + step));
|
||||
const nextCartographic =
|
||||
Cesium.Ellipsoid.WGS84.cartesianToCartographic(next);
|
||||
geo.ellipsoid.WGS84.cartesianToCartographic(next);
|
||||
if (!nextCartographic) continue;
|
||||
const geodesic = new Cesium.EllipsoidGeodesic(
|
||||
currentCartographic,
|
||||
@@ -36,7 +37,7 @@ export function createCamera({ state: layerState, services, parts, source }) {
|
||||
// HeadingPitchRange positions the camera opposite its heading vector.
|
||||
// Passing the forward path heading therefore keeps the camera behind
|
||||
// the vehicle, with the remaining ascent receding into the scene.
|
||||
return Cesium.Math.zeroToTwoPi(geodesic.startHeading);
|
||||
return geo.math.zeroToTwoPi(geodesic.startHeading);
|
||||
}
|
||||
}
|
||||
return fallback;
|
||||
@@ -49,8 +50,8 @@ export function createCamera({ state: layerState, services, parts, source }) {
|
||||
*/
|
||||
|
||||
function replayInitialCameraHeading(path) {
|
||||
return Cesium.Math.zeroToTwoPi(
|
||||
cameraHeadingForPath(path, 0, Math.PI) + Cesium.Math.PI_OVER_TWO,
|
||||
return geo.math.zeroToTwoPi(
|
||||
cameraHeadingForPath(path, 0, Math.PI) + geo.math.PI_OVER_TWO,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -63,10 +64,10 @@ export function createCamera({ state: layerState, services, parts, source }) {
|
||||
*/
|
||||
|
||||
function replayChaseCameraHeading(pathHeading, orbitBlend = 0) {
|
||||
const blend = Cesium.Math.clamp(Number(orbitBlend) || 0, 0, 1);
|
||||
return Cesium.Math.zeroToTwoPi(
|
||||
const blend = geo.math.clamp(Number(orbitBlend) || 0, 0, 1);
|
||||
return geo.math.zeroToTwoPi(
|
||||
pathHeading +
|
||||
Cesium.Math.lerp(
|
||||
geo.math.lerp(
|
||||
REPLAY_ASCENT_CAMERA_OFFSET_RAD,
|
||||
REPLAY_ORBIT_CAMERA_OFFSET_RAD,
|
||||
blend,
|
||||
@@ -86,17 +87,17 @@ export function createCamera({ state: layerState, services, parts, source }) {
|
||||
function smoothReplayCameraHeading(
|
||||
previous,
|
||||
desired,
|
||||
maxStepRad = Cesium.Math.toRadians(2),
|
||||
maxStepRad = geo.math.toRadians(2),
|
||||
) {
|
||||
if (!Number.isFinite(previous)) return Cesium.Math.zeroToTwoPi(desired);
|
||||
if (!Number.isFinite(desired)) return Cesium.Math.zeroToTwoPi(previous);
|
||||
const delta = Cesium.Math.negativePiToPi(desired - previous);
|
||||
const step = Cesium.Math.clamp(
|
||||
if (!Number.isFinite(previous)) return geo.math.zeroToTwoPi(desired);
|
||||
if (!Number.isFinite(desired)) return geo.math.zeroToTwoPi(previous);
|
||||
const delta = geo.math.negativePiToPi(desired - previous);
|
||||
const step = geo.math.clamp(
|
||||
delta,
|
||||
-Math.abs(maxStepRad),
|
||||
Math.abs(maxStepRad),
|
||||
);
|
||||
return Cesium.Math.zeroToTwoPi(previous + step);
|
||||
return geo.math.zeroToTwoPi(previous + step);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -108,7 +109,7 @@ export function createCamera({ state: layerState, services, parts, source }) {
|
||||
|
||||
function missionZoomPitch(rangeM) {
|
||||
const range = Math.max(0, Number(rangeM) || 0);
|
||||
const blend = Cesium.Math.clamp(
|
||||
const blend = geo.math.clamp(
|
||||
(Math.log(Math.max(range, MISSION_CLOSE_VIEW_RANGE_M)) -
|
||||
Math.log(MISSION_CLOSE_VIEW_RANGE_M)) /
|
||||
(Math.log(MISSION_GLOBE_VIEW_RANGE_M) -
|
||||
@@ -116,11 +117,7 @@ export function createCamera({ state: layerState, services, parts, source }) {
|
||||
0,
|
||||
1,
|
||||
);
|
||||
return Cesium.Math.lerp(
|
||||
Cesium.Math.toRadians(-42),
|
||||
-Cesium.Math.PI_OVER_TWO,
|
||||
blend,
|
||||
);
|
||||
return geo.math.lerp(geo.math.toRadians(-42), -geo.math.PI_OVER_TWO, blend);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -133,48 +130,44 @@ export function createCamera({ state: layerState, services, parts, source }) {
|
||||
|
||||
function replayCameraView(state, altitudeM) {
|
||||
const altitude = Math.max(0, Number(altitudeM) || 0);
|
||||
const localRange = Cesium.Math.clamp(
|
||||
const localRange = geo.math.clamp(
|
||||
REPLAY_INITIAL_RANGE_M + altitude * 0.7,
|
||||
REPLAY_INITIAL_RANGE_M,
|
||||
REPLAY_LOCAL_MAX_RANGE_M,
|
||||
);
|
||||
const rawContextBlend = Cesium.Math.clamp(
|
||||
const rawContextBlend = geo.math.clamp(
|
||||
(altitude - 20000) / (REPLAY_CONTEXT_ALTITUDE_END_M - 20000),
|
||||
0,
|
||||
1,
|
||||
);
|
||||
const contextBlend =
|
||||
rawContextBlend * rawContextBlend * (3 - 2 * rawContextBlend);
|
||||
const contextRange = Cesium.Math.clamp(
|
||||
const contextRange = geo.math.clamp(
|
||||
180000 + altitude * 3.8,
|
||||
MISSION_CLOSE_VIEW_RANGE_M,
|
||||
REPLAY_CONTEXT_MAX_RANGE_M,
|
||||
);
|
||||
const ascentRange = Cesium.Math.lerp(
|
||||
localRange,
|
||||
contextRange,
|
||||
contextBlend,
|
||||
);
|
||||
const ascentPitch = Cesium.Math.lerp(
|
||||
Cesium.Math.toRadians(-20),
|
||||
Cesium.Math.toRadians(-34),
|
||||
const ascentRange = geo.math.lerp(localRange, contextRange, contextBlend);
|
||||
const ascentPitch = geo.math.lerp(
|
||||
geo.math.toRadians(-20),
|
||||
geo.math.toRadians(-34),
|
||||
contextBlend,
|
||||
);
|
||||
if (state?.ascending) {
|
||||
return { range: ascentRange, pitch: ascentPitch };
|
||||
}
|
||||
const rawBlend = Cesium.Math.clamp(
|
||||
const rawBlend = geo.math.clamp(
|
||||
(Number(state?.phaseProgress) || 0) / REPLAY_ORBIT_PULLBACK_FRACTION,
|
||||
0,
|
||||
1,
|
||||
);
|
||||
const blend = rawBlend * rawBlend * (3 - 2 * rawBlend);
|
||||
return {
|
||||
range: Cesium.Math.lerp(ascentRange, REPLAY_ORBIT_GLOBE_RANGE_M, blend),
|
||||
range: geo.math.lerp(ascentRange, REPLAY_ORBIT_GLOBE_RANGE_M, blend),
|
||||
// Keep an oblique tactical view of the complete orbit rather than ending
|
||||
// in a nadir view. This also prevents the camera from appearing to
|
||||
// return toward the launch site after insertion.
|
||||
pitch: Cesium.Math.lerp(ascentPitch, Cesium.Math.toRadians(-45), blend),
|
||||
pitch: geo.math.lerp(ascentPitch, geo.math.toRadians(-45), blend),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -188,16 +181,15 @@ export function createCamera({ state: layerState, services, parts, source }) {
|
||||
|
||||
function replayOrbitGlobeAnchor(position, orbitBlend = 0) {
|
||||
if (!position) return position;
|
||||
const blend = Cesium.Math.clamp(Number(orbitBlend) || 0, 0, 1);
|
||||
if (blend <= 0) return Cesium.Cartesian3.clone(position);
|
||||
const cartographic =
|
||||
Cesium.Ellipsoid.WGS84.cartesianToCartographic(position);
|
||||
if (!cartographic) return Cesium.Cartesian3.clone(position);
|
||||
const blend = geo.math.clamp(Number(orbitBlend) || 0, 0, 1);
|
||||
if (blend <= 0) return geo.cartesian3.clone(position);
|
||||
const cartographic = geo.ellipsoid.WGS84.cartesianToCartographic(position);
|
||||
if (!cartographic) return geo.cartesian3.clone(position);
|
||||
const altitude = Math.max(0, cartographic.height || 0);
|
||||
return Cesium.Cartesian3.fromRadians(
|
||||
return geo.cartesian3.fromRadians(
|
||||
cartographic.longitude,
|
||||
cartographic.latitude,
|
||||
Cesium.Math.lerp(altitude, altitude * 0.1, blend),
|
||||
geo.math.lerp(altitude, altitude * 0.1, blend),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -216,15 +208,15 @@ export function createCamera({ state: layerState, services, parts, source }) {
|
||||
|
||||
function replayOrbitCameraTarget(vehicleAnchor, frameCenter, orbitBlend = 0) {
|
||||
if (!vehicleAnchor) return vehicleAnchor;
|
||||
if (!frameCenter) return Cesium.Cartesian3.clone(vehicleAnchor);
|
||||
if (!frameCenter) return geo.cartesian3.clone(vehicleAnchor);
|
||||
const blend =
|
||||
Cesium.Math.clamp(Number(orbitBlend) || 0, 0, 1) *
|
||||
geo.math.clamp(Number(orbitBlend) || 0, 0, 1) *
|
||||
REPLAY_ORBIT_FRAME_CENTER_BLEND;
|
||||
return Cesium.Cartesian3.lerp(
|
||||
return geo.cartesian3.lerp(
|
||||
vehicleAnchor,
|
||||
frameCenter,
|
||||
blend,
|
||||
new Cesium.Cartesian3(),
|
||||
geo.cartesian3.create(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -249,63 +241,59 @@ export function createCamera({ state: layerState, services, parts, source }) {
|
||||
pitch,
|
||||
) {
|
||||
if (!position || !tangentPosition || !target) return null;
|
||||
const radial = Cesium.Cartesian3.normalize(
|
||||
Cesium.Cartesian3.clone(position),
|
||||
new Cesium.Cartesian3(),
|
||||
const radial = geo.cartesian3.normalize(
|
||||
geo.cartesian3.clone(position),
|
||||
geo.cartesian3.create(),
|
||||
);
|
||||
const tangent = Cesium.Cartesian3.subtract(
|
||||
const tangent = geo.cartesian3.subtract(
|
||||
tangentPosition,
|
||||
position,
|
||||
new Cesium.Cartesian3(),
|
||||
geo.cartesian3.create(),
|
||||
);
|
||||
if (Cesium.Cartesian3.magnitudeSquared(tangent) < 1) return null;
|
||||
Cesium.Cartesian3.normalize(tangent, tangent);
|
||||
const orbitNormal = Cesium.Cartesian3.cross(
|
||||
if (geo.cartesian3.magnitudeSquared(tangent) < 1) return null;
|
||||
geo.cartesian3.normalize(tangent, tangent);
|
||||
const orbitNormal = geo.cartesian3.cross(
|
||||
radial,
|
||||
tangent,
|
||||
new Cesium.Cartesian3(),
|
||||
geo.cartesian3.create(),
|
||||
);
|
||||
if (Cesium.Cartesian3.magnitudeSquared(orbitNormal) < 1e-12) return null;
|
||||
Cesium.Cartesian3.normalize(orbitNormal, orbitNormal);
|
||||
if (geo.cartesian3.magnitudeSquared(orbitNormal) < 1e-12) return null;
|
||||
geo.cartesian3.normalize(orbitNormal, orbitNormal);
|
||||
|
||||
const distance = Math.max(1, Number(range) || 1);
|
||||
const elevation = Cesium.Math.clamp(
|
||||
const elevation = geo.math.clamp(
|
||||
Math.abs(Number(pitch) || 0),
|
||||
Cesium.Math.toRadians(5),
|
||||
Cesium.Math.toRadians(80),
|
||||
geo.math.toRadians(5),
|
||||
geo.math.toRadians(80),
|
||||
);
|
||||
const planeOffset = Cesium.Cartesian3.multiplyByScalar(
|
||||
const planeOffset = geo.cartesian3.multiplyByScalar(
|
||||
orbitNormal,
|
||||
Math.cos(elevation) * distance,
|
||||
new Cesium.Cartesian3(),
|
||||
geo.cartesian3.create(),
|
||||
);
|
||||
const radialOffset = Cesium.Cartesian3.multiplyByScalar(
|
||||
const radialOffset = geo.cartesian3.multiplyByScalar(
|
||||
radial,
|
||||
Math.sin(elevation) * distance,
|
||||
new Cesium.Cartesian3(),
|
||||
geo.cartesian3.create(),
|
||||
);
|
||||
const destination = Cesium.Cartesian3.add(
|
||||
const destination = geo.cartesian3.add(
|
||||
target,
|
||||
planeOffset,
|
||||
new Cesium.Cartesian3(),
|
||||
geo.cartesian3.create(),
|
||||
);
|
||||
Cesium.Cartesian3.add(destination, radialOffset, destination);
|
||||
const direction = Cesium.Cartesian3.normalize(
|
||||
Cesium.Cartesian3.subtract(target, destination, new Cesium.Cartesian3()),
|
||||
new Cesium.Cartesian3(),
|
||||
geo.cartesian3.add(destination, radialOffset, destination);
|
||||
const direction = geo.cartesian3.normalize(
|
||||
geo.cartesian3.subtract(target, destination, geo.cartesian3.create()),
|
||||
geo.cartesian3.create(),
|
||||
);
|
||||
const radialAlongView = Cesium.Cartesian3.multiplyByScalar(
|
||||
const radialAlongView = geo.cartesian3.multiplyByScalar(
|
||||
direction,
|
||||
Cesium.Cartesian3.dot(radial, direction),
|
||||
new Cesium.Cartesian3(),
|
||||
geo.cartesian3.dot(radial, direction),
|
||||
geo.cartesian3.create(),
|
||||
);
|
||||
const up = Cesium.Cartesian3.normalize(
|
||||
Cesium.Cartesian3.subtract(
|
||||
radial,
|
||||
radialAlongView,
|
||||
new Cesium.Cartesian3(),
|
||||
),
|
||||
new Cesium.Cartesian3(),
|
||||
const up = geo.cartesian3.normalize(
|
||||
geo.cartesian3.subtract(radial, radialAlongView, geo.cartesian3.create()),
|
||||
geo.cartesian3.create(),
|
||||
);
|
||||
return { destination, direction, up };
|
||||
}
|
||||
@@ -321,8 +309,8 @@ export function createCamera({ state: layerState, services, parts, source }) {
|
||||
|
||||
function replayOrbitFrameSphere(orbitPath = []) {
|
||||
const earth = new Cesium.BoundingSphere(
|
||||
Cesium.Cartesian3.ZERO,
|
||||
Cesium.Ellipsoid.WGS84.maximumRadius,
|
||||
geo.cartesian3.ZERO,
|
||||
geo.ellipsoid.WGS84.maximumRadius,
|
||||
);
|
||||
if (!Array.isArray(orbitPath) || orbitPath.length < 2) return earth;
|
||||
const orbit = Cesium.BoundingSphere.fromPoints(orbitPath);
|
||||
@@ -351,13 +339,13 @@ export function createCamera({ state: layerState, services, parts, source }) {
|
||||
const range = Math.max(0, Number(baseRange) || 0);
|
||||
const altitude = Math.max(0, Number(altitudeM) || 0);
|
||||
const frameRadius = Math.max(0, Number(frameRadiusM) || 0);
|
||||
const blend = Cesium.Math.clamp(Number(orbitBlend) || 0, 0, 1);
|
||||
const blend = geo.math.clamp(Number(orbitBlend) || 0, 0, 1);
|
||||
const globeAndVehicleRange = Math.max(
|
||||
range,
|
||||
altitude + Cesium.Ellipsoid.WGS84.maximumRadius * 2.4,
|
||||
altitude + geo.ellipsoid.WGS84.maximumRadius * 2.4,
|
||||
frameRadius * 3,
|
||||
);
|
||||
return Cesium.Math.lerp(range, globeAndVehicleRange, blend);
|
||||
return geo.math.lerp(range, globeAndVehicleRange, blend);
|
||||
}
|
||||
return {
|
||||
cameraHeadingForPath,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as Cesium from 'cesium';
|
||||
import * as geo from '../../geo/index.js';
|
||||
import {
|
||||
MISSION_CLOSE_VIEW_RANGE_M,
|
||||
MISSION_GLOBE_VIEW_RANGE_M,
|
||||
@@ -360,7 +361,7 @@ export function createPanel({ state: layerState, services, parts, source }) {
|
||||
Cesium.JulianDate.now(layerState._declutterTime),
|
||||
);
|
||||
const altitudeM = position
|
||||
? Cesium.Cartographic.fromCartesian(position)?.height
|
||||
? geo.cartographic.fromCartesian(position)?.height
|
||||
: null;
|
||||
setMissionPanelField(
|
||||
'[data-mission-distance]',
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import * as Cesium from 'cesium';
|
||||
import * as geo from '../../geo/index.js';
|
||||
|
||||
export const WINDOW_DAYS = 30;
|
||||
|
||||
@@ -48,9 +48,9 @@ export const REPLAY_ORBIT_GLOBE_RANGE_M = 18000000;
|
||||
|
||||
export const REPLAY_ORBIT_PULLBACK_FRACTION = 0.2;
|
||||
|
||||
export const REPLAY_ASCENT_CAMERA_OFFSET_RAD = Cesium.Math.toRadians(30);
|
||||
export const REPLAY_ASCENT_CAMERA_OFFSET_RAD = geo.math.toRadians(30);
|
||||
|
||||
export const REPLAY_ORBIT_CAMERA_OFFSET_RAD = Cesium.Math.toRadians(45);
|
||||
export const REPLAY_ORBIT_CAMERA_OFFSET_RAD = geo.math.toRadians(45);
|
||||
|
||||
export const REPLAY_ORBIT_FRAME_CENTER_BLEND = 0.45;
|
||||
|
||||
@@ -64,7 +64,7 @@ export const MAX_POST_TLE_RETRIES = 1;
|
||||
|
||||
export const POST_TLE_RETRY_DELAY_MS = 1500;
|
||||
|
||||
export const EARTH_ROTATION_RAD_PER_SEC = Cesium.Math.TWO_PI / 86164.0905;
|
||||
export const EARTH_ROTATION_RAD_PER_SEC = geo.math.TWO_PI / 86164.0905;
|
||||
|
||||
export const PROJECTED_ASCENT_ROTATION_SEC = 600;
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as Cesium from 'cesium';
|
||||
import * as geo from '../../geo/index.js';
|
||||
import {
|
||||
SATELLITE_STANDALONE_DEFAULTS,
|
||||
LAUNCH_PAD_ZONE_MAX_CAMERA_HEIGHT_M,
|
||||
@@ -226,15 +227,11 @@ export function createPolicyHelpers({
|
||||
const range = parts.panel.missionHoverPreviewRange(
|
||||
layerState._viewer.camera.positionCartographic?.height,
|
||||
);
|
||||
const position = Cesium.Cartesian3.fromDegrees(launch.lon, launch.lat);
|
||||
const position = geo.cartesian3.fromDegrees(launch.lon, launch.lat);
|
||||
layerState._viewer.camera.flyToBoundingSphere(
|
||||
new Cesium.BoundingSphere(position, 0),
|
||||
{
|
||||
offset: new Cesium.HeadingPitchRange(
|
||||
0,
|
||||
-Cesium.Math.PI_OVER_TWO,
|
||||
range,
|
||||
),
|
||||
offset: new Cesium.HeadingPitchRange(0, -geo.math.PI_OVER_TWO, range),
|
||||
duration: 0.8,
|
||||
easingFunction: Cesium.EasingFunction.CUBIC_IN_OUT,
|
||||
},
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as Cesium from 'cesium';
|
||||
import * as geo from '../../geo/index.js';
|
||||
import {
|
||||
REPLAY_ASCENT_FALLBACK_SEC,
|
||||
REPLAY_ASCENT_MIN_SEC,
|
||||
@@ -52,10 +53,10 @@ export function createReplay({ state: layerState, services, parts, source }) {
|
||||
if (!previous || !next) return next;
|
||||
const distance = Math.hypot(next.x - previous.x, next.y - previous.y);
|
||||
if (!Number.isFinite(distance) || distance > snapDistance) return next;
|
||||
const amount = Cesium.Math.clamp(Number(alpha) || 0, 0, 1);
|
||||
const amount = geo.math.clamp(Number(alpha) || 0, 0, 1);
|
||||
return {
|
||||
x: Cesium.Math.lerp(previous.x, next.x, amount),
|
||||
y: Cesium.Math.lerp(previous.y, next.y, amount),
|
||||
x: geo.math.lerp(previous.x, next.x, amount),
|
||||
y: geo.math.lerp(previous.y, next.y, amount),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -77,13 +78,13 @@ export function createReplay({ state: layerState, services, parts, source }) {
|
||||
.slice(1)
|
||||
.reduce(
|
||||
(total, point, index) =>
|
||||
total + Cesium.Cartesian3.distance(ascentPath[index], point),
|
||||
total + geo.cartesian3.distance(ascentPath[index], point),
|
||||
0,
|
||||
);
|
||||
realAscentSeconds = Math.max(180, pathLength / 9000);
|
||||
}
|
||||
if (!realAscentSeconds) realAscentSeconds = REPLAY_ASCENT_FALLBACK_SEC * 50;
|
||||
return Cesium.Math.clamp(
|
||||
return geo.math.clamp(
|
||||
REPLAY_ASCENT_FALLBACK_SEC * (realAscentSeconds / 600),
|
||||
REPLAY_ASCENT_MIN_SEC,
|
||||
REPLAY_ASCENT_MAX_SEC,
|
||||
@@ -99,11 +100,7 @@ export function createReplay({ state: layerState, services, parts, source }) {
|
||||
function normalizeReplaySpeed(value) {
|
||||
const numeric = Number(value);
|
||||
if (!Number.isFinite(numeric)) return 1;
|
||||
const clamped = Cesium.Math.clamp(
|
||||
numeric,
|
||||
REPLAY_SPEED_MIN,
|
||||
REPLAY_SPEED_MAX,
|
||||
);
|
||||
const clamped = geo.math.clamp(numeric, REPLAY_SPEED_MIN, REPLAY_SPEED_MAX);
|
||||
return Math.round(clamped / REPLAY_SPEED_STEP) * REPLAY_SPEED_STEP;
|
||||
}
|
||||
|
||||
@@ -414,7 +411,7 @@ export function createReplay({ state: layerState, services, parts, source }) {
|
||||
track.lastCameraHeading,
|
||||
);
|
||||
const orbitBlend = !state.ascending
|
||||
? Cesium.Math.clamp(
|
||||
? geo.math.clamp(
|
||||
(Number(state.phaseProgress) || 0) /
|
||||
REPLAY_ORBIT_PULLBACK_FRACTION,
|
||||
0,
|
||||
@@ -428,16 +425,16 @@ export function createReplay({ state: layerState, services, parts, source }) {
|
||||
if (state.ascending) track.orbitCameraWorldFrame = false;
|
||||
const nowMs = performance.now();
|
||||
const frameDurationMs = Number.isFinite(lastCameraUpdateMs)
|
||||
? Cesium.Math.clamp(nowMs - lastCameraUpdateMs, 4, 50)
|
||||
? geo.math.clamp(nowMs - lastCameraUpdateMs, 4, 50)
|
||||
: 1000 / 60;
|
||||
lastCameraUpdateMs = nowMs;
|
||||
track.lastCameraHeading = parts.camera.smoothReplayCameraHeading(
|
||||
track.lastCameraHeading,
|
||||
desiredHeading,
|
||||
(Cesium.Math.toRadians(2) * frameDurationMs) / (1000 / 60),
|
||||
(geo.math.toRadians(2) * frameDurationMs) / (1000 / 60),
|
||||
);
|
||||
const cartographic =
|
||||
Cesium.Ellipsoid.WGS84.cartesianToCartographic(position);
|
||||
geo.ellipsoid.WGS84.cartesianToCartographic(position);
|
||||
const altitude = Math.max(0, cartographic?.height || 0);
|
||||
const cameraView = parts.camera.replayCameraView(state, altitude);
|
||||
const defaultOrbitTarget = !state.ascending
|
||||
@@ -518,7 +515,7 @@ export function createReplay({ state: layerState, services, parts, source }) {
|
||||
{
|
||||
offset: new Cesium.HeadingPitchRange(
|
||||
initialHeading,
|
||||
Cesium.Math.toRadians(-20),
|
||||
geo.math.toRadians(-20),
|
||||
REPLAY_INITIAL_RANGE_M,
|
||||
),
|
||||
duration: 1.4,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as Cesium from 'cesium';
|
||||
import * as geo from '../../geo/index.js';
|
||||
import { MISSION_GLOBE_VIEW_RANGE_M, MISSION_FOCUS_RANGE_M } from './policy.js';
|
||||
|
||||
export function createSelection({
|
||||
@@ -24,7 +25,7 @@ export function createSelection({
|
||||
fovy >= Math.PI
|
||||
)
|
||||
return;
|
||||
const earthRadius = Cesium.Ellipsoid.WGS84.maximumRadius;
|
||||
const earthRadius = geo.ellipsoid.WGS84.maximumRadius;
|
||||
const keyholeRadius = getKeyholeGeometry(width, height).radius;
|
||||
const targetScreenRadius = keyholeRadius * 0.61;
|
||||
const angularRadius = Math.atan(
|
||||
@@ -33,14 +34,14 @@ export function createSelection({
|
||||
const distance = earthRadius / Math.max(Math.sin(angularRadius), 1e-4);
|
||||
const altitude = Math.max(earthRadius * 1.55, distance - earthRadius);
|
||||
viewer.camera.flyTo({
|
||||
destination: Cesium.Cartesian3.fromRadians(
|
||||
destination: geo.cartesian3.fromRadians(
|
||||
cartographic.longitude,
|
||||
cartographic.latitude,
|
||||
altitude,
|
||||
),
|
||||
orientation: {
|
||||
heading: viewer.camera.heading,
|
||||
pitch: -Cesium.Math.PI_OVER_TWO,
|
||||
pitch: -geo.math.PI_OVER_TWO,
|
||||
roll: 0,
|
||||
},
|
||||
duration,
|
||||
@@ -99,7 +100,7 @@ export function createSelection({
|
||||
if (!layerState._viewer || !launch || layerState._replayCameraLaunchId)
|
||||
return;
|
||||
stopMissionZoomAnchor();
|
||||
const target = Cesium.Cartesian3.fromDegrees(launch.lon, launch.lat);
|
||||
const target = geo.cartesian3.fromDegrees(launch.lon, launch.lat);
|
||||
const range = Math.max(
|
||||
2000,
|
||||
Number(initialRange) || MISSION_GLOBE_VIEW_RANGE_M,
|
||||
@@ -127,15 +128,12 @@ export function createSelection({
|
||||
const orbitPositions = orbitEntity?.polyline?.positions?.getValue(
|
||||
Cesium.JulianDate.now(),
|
||||
);
|
||||
const launchPosition = Cesium.Cartesian3.fromDegrees(
|
||||
launch.lon,
|
||||
launch.lat,
|
||||
);
|
||||
const launchPosition = geo.cartesian3.fromDegrees(launch.lon, launch.lat);
|
||||
let range = 18000000;
|
||||
if (orbitPositions?.length > 1) {
|
||||
const canvas = layerState._viewer.scene.canvas;
|
||||
const fovy =
|
||||
layerState._viewer.camera.frustum?.fovy || Cesium.Math.toRadians(60);
|
||||
layerState._viewer.camera.frustum?.fovy || geo.math.toRadians(60);
|
||||
const aspect = Math.max(
|
||||
0.1,
|
||||
(canvas.clientWidth || canvas.width) /
|
||||
@@ -145,7 +143,7 @@ export function createSelection({
|
||||
const paddedHalfAngle = Math.min(fovy, fovx) * 0.5 * 0.62;
|
||||
const orbitExtent = orbitPositions.reduce(
|
||||
(largest, point) =>
|
||||
Math.max(largest, Cesium.Cartesian3.distance(launchPosition, point)),
|
||||
Math.max(largest, geo.cartesian3.distance(launchPosition, point)),
|
||||
0,
|
||||
);
|
||||
range = Math.max(
|
||||
@@ -153,39 +151,35 @@ export function createSelection({
|
||||
18000000,
|
||||
);
|
||||
}
|
||||
const targetNormal = Cesium.Cartesian3.normalize(
|
||||
const targetNormal = geo.cartesian3.normalize(
|
||||
launchPosition,
|
||||
new Cesium.Cartesian3(),
|
||||
geo.cartesian3.create(),
|
||||
);
|
||||
const destination = Cesium.Cartesian3.add(
|
||||
const destination = geo.cartesian3.add(
|
||||
launchPosition,
|
||||
Cesium.Cartesian3.multiplyByScalar(
|
||||
geo.cartesian3.multiplyByScalar(
|
||||
targetNormal,
|
||||
range,
|
||||
new Cesium.Cartesian3(),
|
||||
geo.cartesian3.create(),
|
||||
),
|
||||
new Cesium.Cartesian3(),
|
||||
geo.cartesian3.create(),
|
||||
);
|
||||
const direction = Cesium.Cartesian3.negate(
|
||||
const direction = geo.cartesian3.negate(
|
||||
targetNormal,
|
||||
new Cesium.Cartesian3(),
|
||||
geo.cartesian3.create(),
|
||||
);
|
||||
let right = Cesium.Cartesian3.cross(
|
||||
let right = geo.cartesian3.cross(
|
||||
direction,
|
||||
Cesium.Cartesian3.UNIT_Z,
|
||||
new Cesium.Cartesian3(),
|
||||
geo.cartesian3.UNIT_Z,
|
||||
geo.cartesian3.create(),
|
||||
);
|
||||
if (Cesium.Cartesian3.magnitudeSquared(right) < 1e-8) {
|
||||
right = Cesium.Cartesian3.cross(
|
||||
direction,
|
||||
Cesium.Cartesian3.UNIT_Y,
|
||||
right,
|
||||
);
|
||||
if (geo.cartesian3.magnitudeSquared(right) < 1e-8) {
|
||||
right = geo.cartesian3.cross(direction, geo.cartesian3.UNIT_Y, right);
|
||||
}
|
||||
Cesium.Cartesian3.normalize(right, right);
|
||||
const up = Cesium.Cartesian3.normalize(
|
||||
Cesium.Cartesian3.cross(right, direction, new Cesium.Cartesian3()),
|
||||
new Cesium.Cartesian3(),
|
||||
geo.cartesian3.normalize(right, right);
|
||||
const up = geo.cartesian3.normalize(
|
||||
geo.cartesian3.cross(right, direction, geo.cartesian3.create()),
|
||||
geo.cartesian3.create(),
|
||||
);
|
||||
layerState._viewer.camera.flyTo({
|
||||
destination,
|
||||
@@ -202,10 +196,7 @@ export function createSelection({
|
||||
if (!layerState._viewer || !launch) return;
|
||||
parts.replay.stopMissionReplay();
|
||||
stopMissionZoomAnchor();
|
||||
const launchPosition = Cesium.Cartesian3.fromDegrees(
|
||||
launch.lon,
|
||||
launch.lat,
|
||||
);
|
||||
const launchPosition = geo.cartesian3.fromDegrees(launch.lon, launch.lat);
|
||||
layerState._viewer.selectedEntity = layerState._dataSource.entities.getById(
|
||||
`rocket-launch:${launch.id}`,
|
||||
);
|
||||
@@ -214,7 +205,7 @@ export function createSelection({
|
||||
{
|
||||
offset: new Cesium.HeadingPitchRange(
|
||||
0,
|
||||
Cesium.Math.toRadians(-42),
|
||||
geo.math.toRadians(-42),
|
||||
MISSION_FOCUS_RANGE_M,
|
||||
),
|
||||
duration: 1.4,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as Cesium from 'cesium';
|
||||
import * as geo from '../../geo/index.js';
|
||||
|
||||
export function createState({ services }) {
|
||||
const { setOverlayEntries, setOverlaySourceVisible, clearOverlaySource } =
|
||||
@@ -125,7 +126,7 @@ export function createState({ services }) {
|
||||
|
||||
state._declutterOccluder = new Cesium.EllipsoidalOccluder(
|
||||
Cesium.Ellipsoid.WGS84,
|
||||
new Cesium.Cartesian3(),
|
||||
geo.cartesian3.create(),
|
||||
);
|
||||
|
||||
state._missionRingDate = new Date(0);
|
||||
|
||||
Reference in new issue
Block a user