refactor(streetLevel,traffic,transit,firms,installations,radio,bikeshare,cables,detection): take vector maths from src/geo

Street level view/cameraFollow/groundClick/index, traffic footprint/viewport/ingestion, transit viewport/trails/state/rendering, FIRMS state/viewport, installations controls/viewport/state, radio queries/navigation/state, bikeshare viewport, submarine cable overlay and data/detection now use src/geo for Math, Cartesian2/3, Cartographic and WGS84 maths. Cesium stays for Rectangle, Ray, BoundingSphere, HeadingPitchRange, EasingFunction, EllipsoidGeodesic, EllipsoidalOccluder and the Ellipsoids passed into Cesium (pickEllipsoid, occluders). traffic/state.js keeps its Cesium lerp scratch (written per frame by Cesium.Cartesian3.lerp in animation.js; a geo scratch cost +4-7% there) and traffic/timing.js stays on Cesium (a test keeps it source-equivalent to model.parseRoads, outside this batch). street-level-layer, traffic-layer, installations-layer, bikeshare-layer and submarine-cables own the src/geo files.
This commit is contained in:
German Khokhlov committed 2026-10-15 00:19:13 +04:00
1 parent a915bdb3e5
commit e3061872cc
23 files changed
+231 -162

No files matched your search

+75 -5
View File
@@ -1194,7 +1194,21 @@
"src/data/bundledJson.js", "src/data/bundledJson.js",
"src/data/retryableLoad.js", "src/data/retryableLoad.js",
"src/layers/installations/namedMarkers.js", "src/layers/installations/namedMarkers.js",
"src/data/infrastructureOverlayEntry.js" "src/data/infrastructureOverlayEntry.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"] "external": ["cesium", "@mapbox/vector-tile", "pbf"]
}, },
@@ -1276,7 +1290,21 @@
"src/sources/militaryTileGeometry.js", "src/sources/militaryTileGeometry.js",
"src/sources/vectorTiles.js", "src/sources/vectorTiles.js",
"src/sources/phaseTiming.js", "src/sources/phaseTiming.js",
"src/layers/traffic/roadModes.js" "src/layers/traffic/roadModes.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", "@mapbox/vector-tile"] "external": ["cesium", "pbf", "@mapbox/vector-tile"]
}, },
@@ -1299,7 +1327,21 @@
"src/layers/bikeshare/testing.js", "src/layers/bikeshare/testing.js",
"src/layers/bikeshare/viewport.js", "src/layers/bikeshare/viewport.js",
"src/data/inputOwnership.js", "src/data/inputOwnership.js",
"src/data/cameraSensitivity.js" "src/data/cameraSensitivity.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"]
}, },
@@ -1398,7 +1440,21 @@
"src/layers/streetLevel/providers/google/viewer.js", "src/layers/streetLevel/providers/google/viewer.js",
"src/layers/streetLevel/providers/google/mapsLoader.js", "src/layers/streetLevel/providers/google/mapsLoader.js",
"src/layers/streetLevel/providers/mapillary/source.js", "src/layers/streetLevel/providers/mapillary/source.js",
"scripts/qa-street-level.mjs" "scripts/qa-street-level.mjs",
"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", "@mapbox/vector-tile", "mapillary-js"] "external": ["cesium", "pbf", "@mapbox/vector-tile", "mapillary-js"]
}, },
@@ -1500,7 +1556,21 @@
"src/layers/submarineCables/rendering.js", "src/layers/submarineCables/rendering.js",
"src/layers/submarineCables/state.js", "src/layers/submarineCables/state.js",
"src/layers/submarineCables/surface.js", "src/layers/submarineCables/surface.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"]
}, },
+2 -2
View File
@@ -1,5 +1,5 @@
import { paintTransitBracket } from './detectionDraw.js'; import { paintTransitBracket } from './detectionDraw.js';
import * as Cesium from 'cesium'; import * as geo from '../geo/index.js';
import { governorRequestRender } from '../renderGovernor.js'; import { governorRequestRender } from '../renderGovernor.js';
import { import {
DETECTION_ENABLE_FADE_MS, DETECTION_ENABLE_FADE_MS,
@@ -1391,7 +1391,7 @@ function _drawOverlay(frame) {
let halfH; let halfH;
if (obj.type === 'AIR') { if (obj.type === 'AIR') {
const bscale = nearFarScale( const bscale = nearFarScale(
Cesium.Cartesian3.distance(camPos, obj.position), geo.cartesian3.distance(camPos, obj.position),
BILL_NEAR, BILL_NEAR,
BILL_NEAR_SCALE, BILL_NEAR_SCALE,
BILL_FAR, BILL_FAR,
+5 -4
View File
@@ -1,4 +1,5 @@
import * as Cesium from 'cesium'; import * as Cesium from 'cesium';
import * as geo from '../../geo/index.js';
import { GBFS_CITY_REGISTRY } from './registry.js'; import { GBFS_CITY_REGISTRY } from './registry.js';
import { import {
ACTIVATION_EXIT_ALTITUDE_M, ACTIVATION_EXIT_ALTITUDE_M,
@@ -37,8 +38,8 @@ export function createViewport({ state: layerState, services, parts, source }) {
if (rect) { if (rect) {
const center = Cesium.Rectangle.center(rect); const center = Cesium.Rectangle.center(rect);
return { return {
lat: Cesium.Math.toDegrees(center.latitude), lat: geo.math.toDegrees(center.latitude),
lon: Cesium.Math.toDegrees(center.longitude), lon: geo.math.toDegrees(center.longitude),
}; };
} }
@@ -46,8 +47,8 @@ export function createViewport({ state: layerState, services, parts, source }) {
const carto = viewer?.camera?.positionCartographic; const carto = viewer?.camera?.positionCartographic;
if (carto) { if (carto) {
return { return {
lat: Cesium.Math.toDegrees(carto.latitude), lat: geo.math.toDegrees(carto.latitude),
lon: Cesium.Math.toDegrees(carto.longitude), lon: geo.math.toDegrees(carto.longitude),
}; };
} }
+6 -5
View File
@@ -1,4 +1,5 @@
import * as Cesium from 'cesium'; import * as Cesium from 'cesium';
import * as geo from '../../geo/index.js';
export function createFirmsState({ services, config }) { export function createFirmsState({ services, config }) {
const layerState = {}; const layerState = {};
@@ -9,11 +10,11 @@ export function createFirmsState({ services, config }) {
layerState.scratchViewRect = new Cesium.Rectangle(); layerState.scratchViewRect = new Cesium.Rectangle();
layerState.scratchCenterA = new Cesium.Cartographic(); layerState.scratchCenterA = geo.cartographic.create();
layerState.scratchCenterB = new Cesium.Cartographic(); layerState.scratchCenterB = geo.cartographic.create();
layerState.scratchWindowCoord = new Cesium.Cartesian2(); layerState.scratchWindowCoord = geo.cartesian2.create();
layerState._viewer = null; layerState._viewer = null;
@@ -107,9 +108,9 @@ export function createFirmsState({ services, config }) {
layerState._camSnapValid = false; layerState._camSnapValid = false;
layerState._camPos = new Cesium.Cartesian3(); layerState._camPos = geo.cartesian3.create();
layerState._camDir = new Cesium.Cartesian3(); layerState._camDir = geo.cartesian3.create();
layerState.request = null; layerState.request = null;
return layerState; return layerState;
} }
+6 -5
View File
@@ -1,4 +1,5 @@
import * as Cesium from 'cesium'; import * as Cesium from 'cesium';
import * as geo from '../../geo/index.js';
import { import {
LOD_LEVELS, LOD_LEVELS,
LOD_HYSTERESIS, LOD_HYSTERESIS,
@@ -122,7 +123,7 @@ export function createViewport({
const center = Cesium.Rectangle.center(viewRect, layerState.scratchCenterB); const center = Cesium.Rectangle.center(viewRect, layerState.scratchCenterB);
const latShift = Math.abs(center.latitude - lastCenter.latitude); const latShift = Math.abs(center.latitude - lastCenter.latitude);
let lonShift = Math.abs(center.longitude - lastCenter.longitude); let lonShift = Math.abs(center.longitude - lastCenter.longitude);
if (lonShift > Math.PI) lonShift = Cesium.Math.TWO_PI - lonShift; if (lonShift > Math.PI) lonShift = geo.math.TWO_PI - lonShift;
return ( return (
latShift > lastHeight * VIEW_PADDING * 0.6 || latShift > lastHeight * VIEW_PADDING * 0.6 ||
lonShift > lastWidth * VIEW_PADDING * 0.6 lonShift > lastWidth * VIEW_PADDING * 0.6
@@ -159,13 +160,13 @@ export function createViewport({
const camera = layerState._viewer.camera; const camera = layerState._viewer.camera;
if ( if (
layerState._camSnapValid && layerState._camSnapValid &&
Cesium.Cartesian3.equalsEpsilon( geo.cartesian3.equalsEpsilon(
camera.positionWC, camera.positionWC,
layerState._camPos, layerState._camPos,
0, 0,
0.5, 0.5,
) && ) &&
Cesium.Cartesian3.equalsEpsilon( geo.cartesian3.equalsEpsilon(
camera.directionWC, camera.directionWC,
layerState._camDir, layerState._camDir,
0, 0,
@@ -174,8 +175,8 @@ export function createViewport({
) { ) {
return; return;
} }
Cesium.Cartesian3.clone(camera.positionWC, layerState._camPos); geo.cartesian3.clone(camera.positionWC, layerState._camPos);
Cesium.Cartesian3.clone(camera.directionWC, layerState._camDir); geo.cartesian3.clone(camera.directionWC, layerState._camDir);
layerState._camSnapValid = true; layerState._camSnapValid = true;
// The camera moved, so the horizon moved. A rebuild culls its own fresh // The camera moved, so the horizon moved. A rebuild culls its own fresh
// sprites (renderDetections); an early-out — same LOD band and view // sprites (renderDetections); an early-out — same LOD band and view
+12 -11
View File
@@ -1,4 +1,5 @@
import * as Cesium from 'cesium'; import * as Cesium from 'cesium';
import * as geo from '../../geo/index.js';
import { installationFeedback } from '../../data/installationFeedback.js'; import { installationFeedback } from '../../data/installationFeedback.js';
import { import {
LAYER_ID, LAYER_ID,
@@ -51,17 +52,17 @@ export function createControls({ state: layerState, services, parts, source }) {
) )
next = { latitude: position.latitude, longitude: position.longitude }; next = { latitude: position.latitude, longitude: position.longitude };
else { else {
const carto = Cesium.Cartographic.fromCartesian(position); const carto = geo.cartographic.fromCartesian(position);
if (carto) if (carto)
next = { next = {
latitude: Cesium.Math.toDegrees(carto.latitude), latitude: geo.math.toDegrees(carto.latitude),
longitude: Cesium.Math.toDegrees(carto.longitude), longitude: geo.math.toDegrees(carto.longitude),
}; };
} }
} }
// Keep the live centre even when the coarse fetch anchor has not moved. // Keep the live centre even when the coarse fetch anchor has not moved.
layerState.contextPosition = next layerState.contextPosition = next
? Cesium.Cartesian3.fromDegrees(next.longitude, next.latitude) ? geo.cartesian3.fromDegrees(next.longitude, next.latitude)
: null; : null;
const previous = layerState.contextAnchor; const previous = layerState.contextAnchor;
if (!next) { if (!next) {
@@ -73,8 +74,8 @@ export function createControls({ state: layerState, services, parts, source }) {
if ( if (
previous && previous &&
parts.model.approximateSurfaceDistanceM( parts.model.approximateSurfaceDistanceM(
Cesium.Math.toRadians(previous.latitude), geo.math.toRadians(previous.latitude),
Cesium.Math.toRadians(previous.longitude), geo.math.toRadians(previous.longitude),
next.latitude, next.latitude,
next.longitude, next.longitude,
) < ANCHOR_REFRESH_M ) < ANCHOR_REFRESH_M
@@ -88,7 +89,7 @@ export function createControls({ state: layerState, services, parts, source }) {
getNearby(center, rangeM, maxCount = 50) { getNearby(center, rangeM, maxCount = 50) {
if (!center) return []; if (!center) return [];
const range = Number.isFinite(rangeM) ? rangeM : Infinity; const range = Number.isFinite(rangeM) ? rangeM : Infinity;
const centerCartographic = Cesium.Cartographic.fromCartesian(center); const centerCartographic = geo.cartographic.fromCartesian(center);
if (!centerCartographic) return []; if (!centerCartographic) return [];
const nearby = []; const nearby = [];
const approximateLimit = Number.isFinite(range) const approximateLimit = Number.isFinite(range)
@@ -107,10 +108,10 @@ export function createControls({ state: layerState, services, parts, source }) {
continue; continue;
// The awareness disk is projected onto the ground. Confirm candidates // The awareness disk is projected onto the ground. Confirm candidates
// with an exact ellipsoidal surface distance and reusable scratch state. // with an exact ellipsoidal surface distance and reusable scratch state.
layerState.distanceEndpointScratch.longitude = Cesium.Math.toRadians( layerState.distanceEndpointScratch.longitude = geo.math.toRadians(
record.longitude, record.longitude,
); );
layerState.distanceEndpointScratch.latitude = Cesium.Math.toRadians( layerState.distanceEndpointScratch.latitude = geo.math.toRadians(
record.latitude, record.latitude,
); );
layerState.distanceEndpointScratch.height = 0; layerState.distanceEndpointScratch.height = 0;
@@ -122,7 +123,7 @@ export function createControls({ state: layerState, services, parts, source }) {
if (!Number.isFinite(distanceM) || distanceM > range) continue; if (!Number.isFinite(distanceM) || distanceM > range) continue;
nearby.push({ nearby.push({
...record, ...record,
position: Cesium.Cartesian3.fromDegrees( position: geo.cartesian3.fromDegrees(
record.longitude, record.longitude,
record.latitude, record.latitude,
parts.rendering.installationSurfaceHeightM(record), parts.rendering.installationSurfaceHeightM(record),
@@ -150,7 +151,7 @@ export function createControls({ state: layerState, services, parts, source }) {
if (!parts.selection.selectRecord(record.id)) return false; if (!parts.selection.selectRecord(record.id)) return false;
layerState.viewer.camera.flyToBoundingSphere( layerState.viewer.camera.flyToBoundingSphere(
new Cesium.BoundingSphere( new Cesium.BoundingSphere(
Cesium.Cartesian3.fromDegrees( geo.cartesian3.fromDegrees(
record.longitude, record.longitude,
record.latitude, record.latitude,
parts.rendering.installationSurfaceHeightM(record), parts.rendering.installationSurfaceHeightM(record),
+2 -1
View File
@@ -1,9 +1,10 @@
import * as Cesium from 'cesium'; import * as Cesium from 'cesium';
import * as geo from '../../geo/index.js';
export function createState({ services }) { export function createState({ services }) {
const state = {}; const state = {};
state.distanceEndpointScratch = new Cesium.Cartographic(); state.distanceEndpointScratch = geo.cartographic.create();
state.distanceGeodesicScratch = new Cesium.EllipsoidGeodesic(); state.distanceGeodesicScratch = new Cesium.EllipsoidGeodesic();
+5 -5
View File
@@ -1,4 +1,4 @@
import * as Cesium from 'cesium'; import * as geo from '../../geo/index.js';
import { REQUEST_DEBOUNCE_MS } from './policy.js'; import { REQUEST_DEBOUNCE_MS } from './policy.js';
import { installationAnchorBox } from './source.js'; import { installationAnchorBox } from './source.js';
@@ -27,10 +27,10 @@ export function createViewport({ state: layerState, services, parts, source }) {
viewer.scene.globe.ellipsoid, viewer.scene.globe.ellipsoid,
); );
if (!rectangle) return null; if (!rectangle) return null;
const south = Cesium.Math.toDegrees(rectangle.south); const south = geo.math.toDegrees(rectangle.south);
const north = Cesium.Math.toDegrees(rectangle.north); const north = geo.math.toDegrees(rectangle.north);
const west = Cesium.Math.toDegrees(rectangle.west); const west = geo.math.toDegrees(rectangle.west);
const east = Cesium.Math.toDegrees(rectangle.east); const east = geo.math.toDegrees(rectangle.east);
// Wide and dateline views use the bundled point index. // Wide and dateline views use the bundled point index.
if ( if (
!Number.isFinite(south + north + west + east) || !Number.isFinite(south + north + west + east) ||
+8 -13
View File
@@ -1,4 +1,5 @@
import * as Cesium from 'cesium'; import * as Cesium from 'cesium';
import * as geo from '../../geo/index.js';
import { import {
HORIZON_CAMERA_MOVE_EPSILON_M, HORIZON_CAMERA_MOVE_EPSILON_M,
GLOBAL_RADIO_ALTITUDE_M, GLOBAL_RADIO_ALTITUDE_M,
@@ -178,15 +179,13 @@ export function createNavigation({
); );
} else { } else {
const earthRadius = earthDiscScreenRadius( const earthRadius = earthDiscScreenRadius(
Cesium.Cartesian3.magnitude(camera.positionWC), geo.cartesian3.magnitude(camera.positionWC),
height, height,
camera.frustum?.fovy, camera.frustum?.fovy,
); );
const facingEarthCenter = const facingEarthCenter =
Cesium.Cartesian3.dot( geo.cartesian3.dot(camera.directionWC, layerState._radioEarthToCenter) >
camera.directionWC, 0;
layerState._radioEarthToCenter,
) > 0;
if (!earthRadius || facingEarthCenter) return null; if (!earthRadius || facingEarthCenter) return null;
const keyhole = getKeyholeGeometry(width, height); const keyhole = getKeyholeGeometry(width, height);
fullGlobeCapable = fullGlobeCapable =
@@ -198,7 +197,7 @@ export function createNavigation({
); );
if (recenterHeight == null) return null; if (recenterHeight == null) return null;
return { return {
destination: Cesium.Cartesian3.fromRadians( destination: geo.cartesian3.fromRadians(
cartographic.longitude, cartographic.longitude,
cartographic.latitude, cartographic.latitude,
recenterHeight, recenterHeight,
@@ -207,7 +206,7 @@ export function createNavigation({
...radioCameraState(camera), ...radioCameraState(camera),
height: recenterHeight, height: recenterHeight,
heading: 0, heading: 0,
pitch: -Cesium.Math.PI_OVER_TWO, pitch: -geo.math.PI_OVER_TWO,
roll: 0, roll: 0,
}, },
}; };
@@ -280,7 +279,7 @@ export function createNavigation({
return startRadioCameraFlight( return startRadioCameraFlight(
navigation, navigation,
{ {
destination: Cesium.Cartesian3.fromDegrees( destination: geo.cartesian3.fromDegrees(
plan.lon, plan.lon,
plan.lat, plan.lat,
plan.height, plan.height,
@@ -364,11 +363,7 @@ export function createNavigation({
return false; return false;
cancelActiveRadioCameraFlight(); cancelActiveRadioCameraFlight();
layerState._viewer.camera.flyTo({ layerState._viewer.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees( destination: geo.cartesian3.fromDegrees(station.lon, station.lat, 85_000),
station.lon,
station.lat,
85_000,
),
duration: 1.1, duration: 1.1,
}); });
return true; return true;
+9 -8
View File
@@ -1,12 +1,13 @@
import * as Cesium from 'cesium'; import * as Cesium from 'cesium';
import * as geo from '../../geo/index.js';
import { normalizeRadioCountryInput } from '../../data/radioCountry.js'; import { normalizeRadioCountryInput } from '../../data/radioCountry.js';
export function createQueries({ state: layerState, services, parts, source }) { export function createQueries({ state: layerState, services, parts, source }) {
function radioAngularDistance(station, anchor) { function radioAngularDistance(station, anchor) {
const lat1 = Cesium.Math.toRadians(Number(anchor?.lat)); const lat1 = geo.math.toRadians(Number(anchor?.lat));
const lon1 = Cesium.Math.toRadians(Number(anchor?.lon)); const lon1 = geo.math.toRadians(Number(anchor?.lon));
const lat2 = Cesium.Math.toRadians(Number(station?.lat)); const lat2 = geo.math.toRadians(Number(station?.lat));
const lon2 = Cesium.Math.toRadians(Number(station?.lon)); const lon2 = geo.math.toRadians(Number(station?.lon));
if (![lat1, lon1, lat2, lon2].every(Number.isFinite)) if (![lat1, lon1, lat2, lon2].every(Number.isFinite))
return Number.POSITIVE_INFINITY; return Number.POSITIVE_INFINITY;
const deltaLat = lat2 - lat1; const deltaLat = lat2 - lat1;
@@ -113,7 +114,7 @@ export function createQueries({ state: layerState, services, parts, source }) {
let cartographic = null; let cartographic = null;
const canvas = scene?.canvas; const canvas = scene?.canvas;
if (canvas && typeof camera.pickEllipsoid === 'function') { if (canvas && typeof camera.pickEllipsoid === 'function') {
const center = new Cesium.Cartesian2( const center = geo.cartesian2.create(
canvas.clientWidth / 2, canvas.clientWidth / 2,
canvas.clientHeight / 2, canvas.clientHeight / 2,
); );
@@ -121,13 +122,13 @@ export function createQueries({ state: layerState, services, parts, source }) {
center, center,
scene.globe?.ellipsoid || Cesium.Ellipsoid.WGS84, scene.globe?.ellipsoid || Cesium.Ellipsoid.WGS84,
); );
if (position) cartographic = Cesium.Cartographic.fromCartesian(position); if (position) cartographic = geo.cartographic.fromCartesian(position);
} }
cartographic ||= camera.positionCartographic || null; cartographic ||= camera.positionCartographic || null;
if (!cartographic) return null; if (!cartographic) return null;
return { return {
lat: Cesium.Math.toDegrees(cartographic.latitude), lat: geo.math.toDegrees(cartographic.latitude),
lon: Cesium.Math.toDegrees(cartographic.longitude), lon: geo.math.toDegrees(cartographic.longitude),
altitudeM, altitudeM,
globalView: parts.navigation.radioViewIsGlobal(altitudeM), globalView: parts.navigation.radioViewIsGlobal(altitudeM),
}; };
+3 -3
View File
@@ -1,4 +1,4 @@
import * as Cesium from 'cesium'; import * as geo from '../../geo/index.js';
import { import {
EMPTY_ACCEPTED_CATALOG_SNAPSHOT, EMPTY_ACCEPTED_CATALOG_SNAPSHOT,
DEFAULT_RADIO_FILTER, DEFAULT_RADIO_FILTER,
@@ -8,9 +8,9 @@ import {
export function createState({ services }) { export function createState({ services }) {
const layerState = {}; const layerState = {};
layerState._radioEarthScreenCenter = new Cesium.Cartesian2(); layerState._radioEarthScreenCenter = geo.cartesian2.create();
layerState._radioEarthToCenter = new Cesium.Cartesian3(); layerState._radioEarthToCenter = geo.cartesian3.create();
layerState._viewer = null; layerState._viewer = null;
+8 -7
View File
@@ -1,4 +1,5 @@
import * as Cesium from 'cesium'; import * as Cesium from 'cesium';
import * as geo from '../../geo/index.js';
import { FOLLOW_EYE_HEIGHT_M } from './policy.js'; import { FOLLOW_EYE_HEIGHT_M } from './policy.js';
/** Plausible ellipsoidal land heights: Dead Sea to Everest, with geoid slack. */ /** Plausible ellipsoidal land heights: Dead Sea to Everest, with geoid slack. */
@@ -79,7 +80,7 @@ export function createCameraFollow({ state, parts }) {
*/ */
function groundHeightAt(lon, lat, fallback) { function groundHeightAt(lon, lat, fallback) {
const scene = state.viewer?.scene; const scene = state.viewer?.scene;
const carto = Cesium.Cartographic.fromDegrees(lon, lat); const carto = geo.cartographic.fromDegrees(lon, lat);
const caster = parts?.groundCaster; const caster = parts?.groundCaster;
const dem = caster?.groundAt(lon, lat) ?? null; const dem = caster?.groundAt(lon, lat) ?? null;
if (dem === null) caster?.prepare([[lon, lat]]); if (dem === null) caster?.prepare([[lon, lat]]);
@@ -108,14 +109,14 @@ export function createCameraFollow({ state, parts }) {
if (!follow || !position || !state.viewer) return; if (!follow || !position || !state.viewer) return;
const ground = groundHeightAt(position.lon, position.lat, altitude); const ground = groundHeightAt(position.lon, position.lat, altitude);
state.viewer.camera.setView({ state.viewer.camera.setView({
destination: Cesium.Cartesian3.fromDegrees( destination: geo.cartesian3.fromDegrees(
position.lon, position.lon,
position.lat, position.lat,
ground + FOLLOW_EYE_HEIGHT_M, ground + FOLLOW_EYE_HEIGHT_M,
), ),
orientation: { orientation: {
heading: Cesium.Math.toRadians(bearing || 0), heading: geo.math.toRadians(bearing || 0),
pitch: Cesium.Math.toRadians(Number.isFinite(tilt) ? tilt : 0), pitch: geo.math.toRadians(Number.isFinite(tilt) ? tilt : 0),
roll: 0, roll: 0,
}, },
}); });
@@ -148,13 +149,13 @@ export function createCameraFollow({ state, parts }) {
}; };
state.viewer.camera.flyToBoundingSphere( state.viewer.camera.flyToBoundingSphere(
new Cesium.BoundingSphere( new Cesium.BoundingSphere(
Cesium.Cartesian3.fromDegrees(position.lon, position.lat, ground + 2), geo.cartesian3.fromDegrees(position.lon, position.lat, ground + 2),
4, 4,
), ),
{ {
offset: new Cesium.HeadingPitchRange( offset: new Cesium.HeadingPitchRange(
Cesium.Math.toRadians(bearing || 0), geo.math.toRadians(bearing || 0),
Cesium.Math.toRadians(-32), geo.math.toRadians(-32),
140, 140,
), ),
duration: 1.6, duration: 1.6,
+4 -4
View File
@@ -1,4 +1,4 @@
import * as Cesium from 'cesium'; import * as geo from '../../geo/index.js';
import { GROUND_CLICK_MAX_HEIGHT_M } from './policy.js'; import { GROUND_CLICK_MAX_HEIGHT_M } from './policy.js';
import { cameraHeightAboveGround } from './view.js'; import { cameraHeightAboveGround } from './view.js';
@@ -43,12 +43,12 @@ export function createGroundClick({
.map((entry) => entry.def.id); .map((entry) => entry.def.id);
if (!providerIds.length) return false; if (!providerIds.length) return false;
const position = scenePick.pickGroundPosition(state.viewer, screenPosition); const position = scenePick.pickGroundPosition(state.viewer, screenPosition);
const carto = position && Cesium.Cartographic.fromCartesian(position); const carto = position && geo.cartographic.fromCartesian(position);
if (!carto) return false; if (!carto) return false;
return openNearest( return openNearest(
{ {
lon: Cesium.Math.toDegrees(carto.longitude), lon: geo.math.toDegrees(carto.longitude),
lat: Cesium.Math.toDegrees(carto.latitude), lat: geo.math.toDegrees(carto.latitude),
}, },
{ providerIds, frame: false }, { providerIds, frame: false },
); );
+4 -4
View File
@@ -1,4 +1,4 @@
import * as Cesium from 'cesium'; import * as geo from '../../geo/index.js';
import { createState } from './state.js'; import { createState } from './state.js';
import { createMarker } from './marker.js'; import { createMarker } from './marker.js';
import { createCameraFollow } from './cameraFollow.js'; import { createCameraFollow } from './cameraFollow.js';
@@ -304,11 +304,11 @@ export function createStreetLevelLayer({
x: canvas.clientWidth / 2, x: canvas.clientWidth / 2,
y: canvas.clientHeight / 2, y: canvas.clientHeight / 2,
}); });
const carto = position && Cesium.Cartographic.fromCartesian(position); const carto = position && geo.cartographic.fromCartesian(position);
return carto return carto
? { ? {
lon: Cesium.Math.toDegrees(carto.longitude), lon: geo.math.toDegrees(carto.longitude),
lat: Cesium.Math.toDegrees(carto.latitude), lat: geo.math.toDegrees(carto.latitude),
} }
: null; : null;
} }
+28 -27
View File
@@ -1,4 +1,5 @@
import * as Cesium from 'cesium'; import * as Cesium from 'cesium';
import * as geo from '../../geo/index.js';
import { wrapLon } from './tileMath.js'; import { wrapLon } from './tileMath.js';
/** Equirectangular metres between {lon, lat} points, the short way round ±180°; street scale. */ /** Equirectangular metres between {lon, lat} points, the short way round ±180°; street scale. */
@@ -33,8 +34,8 @@ export function groundUnderCamera(viewer, { groundAt } = {}) {
let ground = globe?.show === false ? null : globe?.getHeight?.(carto); let ground = globe?.show === false ? null : globe?.getHeight?.(carto);
if (!Number.isFinite(ground)) if (!Number.isFinite(ground))
ground = groundAt?.( ground = groundAt?.(
Cesium.Math.toDegrees(carto.longitude), geo.math.toDegrees(carto.longitude),
Cesium.Math.toDegrees(carto.latitude), geo.math.toDegrees(carto.latitude),
); );
return Number.isFinite(ground) ? ground : null; return Number.isFinite(ground) ? ground : null;
} }
@@ -68,10 +69,10 @@ function groundHit(camera, point, ellipsoid, maxRange) {
if ( if (
Number.isFinite(maxRange) && Number.isFinite(maxRange) &&
camera.positionWC && camera.positionWC &&
Cesium.Cartesian3.distance(cartesian, camera.positionWC) > maxRange geo.cartesian3.distance(cartesian, camera.positionWC) > maxRange
) )
return null; return null;
return Cesium.Cartographic.fromCartesian(cartesian, ellipsoid) || null; return geo.cartographic.fromCartesian(cartesian, ellipsoid) || null;
} }
/** /**
@@ -96,7 +97,7 @@ export function visibleBbox(
scene.globe?.ellipsoid || Cesium.Ellipsoid.WGS84, scene.globe?.ellipsoid || Cesium.Ellipsoid.WGS84,
groundHeight, groundHeight,
); );
const point = new Cesium.Cartesian2(); const point = geo.cartesian2.create();
for (let i = 0; i <= grid; i++) { for (let i = 0; i <= grid; i++) {
for (let j = 0; j <= grid; j++) { for (let j = 0; j <= grid; j++) {
point.x = (width * i) / grid; point.x = (width * i) / grid;
@@ -112,8 +113,8 @@ export function visibleBbox(
if (Number.isFinite(nearRange) && nearRange > 0 && nadir) { if (Number.isFinite(nearRange) && nearRange > 0 && nadir) {
const dLat = nearRange / 111_320; const dLat = nearRange / 111_320;
const dLon = dLat / Math.max(0.05, Math.cos(nadir.latitude)); const dLon = dLat / Math.max(0.05, Math.cos(nadir.latitude));
const lat = Cesium.Math.toDegrees(nadir.latitude); const lat = geo.math.toDegrees(nadir.latitude);
const lon = Cesium.Math.toDegrees(nadir.longitude); const lon = geo.math.toDegrees(nadir.longitude);
for (const [dx, dy] of [ for (const [dx, dy] of [
[-1, -1], [-1, -1],
[-1, 1], [-1, 1],
@@ -121,7 +122,7 @@ export function visibleBbox(
[1, 1], [1, 1],
]) ])
hits.push( hits.push(
Cesium.Cartographic.fromDegrees( geo.cartographic.fromDegrees(
lon + dx * dLon, lon + dx * dLon,
Math.max(-85, Math.min(85, lat + dy * dLat)), Math.max(-85, Math.min(85, lat + dy * dLat)),
), ),
@@ -133,8 +134,8 @@ export function visibleBbox(
let east = -Infinity; let east = -Infinity;
let north = -Infinity; let north = -Infinity;
for (const carto of hits) { for (const carto of hits) {
const lon = Cesium.Math.toDegrees(carto.longitude); const lon = geo.math.toDegrees(carto.longitude);
const lat = Cesium.Math.toDegrees(carto.latitude); const lat = geo.math.toDegrees(carto.latitude);
west = Math.min(west, lon); west = Math.min(west, lon);
east = Math.max(east, lon); east = Math.max(east, lon);
south = Math.min(south, lat); south = Math.min(south, lat);
@@ -147,7 +148,7 @@ export function visibleBbox(
let west360 = Infinity; let west360 = Infinity;
let east360 = -Infinity; let east360 = -Infinity;
for (const carto of hits) { for (const carto of hits) {
const lon = Cesium.Math.toDegrees(carto.longitude); const lon = geo.math.toDegrees(carto.longitude);
const shifted = lon < 0 ? lon + 360 : lon; const shifted = lon < 0 ? lon + 360 : lon;
west360 = Math.min(west360, shifted); west360 = Math.min(west360, shifted);
east360 = Math.max(east360, shifted); east360 = Math.max(east360, shifted);
@@ -162,10 +163,10 @@ export function visibleBbox(
const rectangle = camera.computeViewRectangle?.(scene.globe?.ellipsoid); const rectangle = camera.computeViewRectangle?.(scene.globe?.ellipsoid);
if (!rectangle) return null; if (!rectangle) return null;
return [ return [
Cesium.Math.toDegrees(rectangle.west), geo.math.toDegrees(rectangle.west),
Cesium.Math.toDegrees(rectangle.south), geo.math.toDegrees(rectangle.south),
Cesium.Math.toDegrees(rectangle.east), geo.math.toDegrees(rectangle.east),
Cesium.Math.toDegrees(rectangle.north), geo.math.toDegrees(rectangle.north),
]; ];
} }
@@ -183,8 +184,8 @@ export function viewCentre(viewer) {
const carto = viewer.camera?.positionCartographic; const carto = viewer.camera?.positionCartographic;
if (!carto) return null; if (!carto) return null;
return { return {
lat: Cesium.Math.toDegrees(carto.latitude), lat: geo.math.toDegrees(carto.latitude),
lon: Cesium.Math.toDegrees(carto.longitude), lon: geo.math.toDegrees(carto.longitude),
}; };
} }
@@ -200,8 +201,8 @@ export function viewFocus(
const carto = camera?.positionCartographic; const carto = camera?.positionCartographic;
if (!carto) return null; if (!carto) return null;
const nadir = { const nadir = {
lon: Cesium.Math.toDegrees(carto.longitude), lon: geo.math.toDegrees(carto.longitude),
lat: Cesium.Math.toDegrees(carto.latitude), lat: geo.math.toDegrees(carto.latitude),
}; };
const canvas = viewer.scene?.canvas; const canvas = viewer.scene?.canvas;
const width = canvas?.clientWidth || canvas?.width || 0; const width = canvas?.clientWidth || canvas?.width || 0;
@@ -210,7 +211,7 @@ export function viewFocus(
if (width > 0 && height > 0) { if (width > 0 && height > 0) {
const hit = groundHit( const hit = groundHit(
camera, camera,
new Cesium.Cartesian2(width / 2, height / 2), geo.cartesian2.create(width / 2, height / 2),
raisedEllipsoid( raisedEllipsoid(
viewer.scene?.globe?.ellipsoid || Cesium.Ellipsoid.WGS84, viewer.scene?.globe?.ellipsoid || Cesium.Ellipsoid.WGS84,
groundHeight, groundHeight,
@@ -219,8 +220,8 @@ export function viewFocus(
); );
if (hit) if (hit)
ahead = { ahead = {
lon: Cesium.Math.toDegrees(hit.longitude), lon: geo.math.toDegrees(hit.longitude),
lat: Cesium.Math.toDegrees(hit.latitude), lat: geo.math.toDegrees(hit.latitude),
}; };
} }
return { nadir, ahead }; return { nadir, ahead };
@@ -232,9 +233,9 @@ export function viewFocus(
*/ */
export const HORIZON_CULL_DEPTH_M = 1000; export const HORIZON_CULL_DEPTH_M = 1000;
const HORIZON_CULL_ELLIPSOID = new Cesium.Ellipsoid( const HORIZON_CULL_ELLIPSOID = new Cesium.Ellipsoid(
Cesium.Ellipsoid.WGS84.radii.x - HORIZON_CULL_DEPTH_M, geo.ellipsoid.WGS84.radii.x - HORIZON_CULL_DEPTH_M,
Cesium.Ellipsoid.WGS84.radii.y - HORIZON_CULL_DEPTH_M, geo.ellipsoid.WGS84.radii.y - HORIZON_CULL_DEPTH_M,
Cesium.Ellipsoid.WGS84.radii.z - HORIZON_CULL_DEPTH_M, geo.ellipsoid.WGS84.radii.z - HORIZON_CULL_DEPTH_M,
); );
/** /**
@@ -267,13 +268,13 @@ export function createHorizonCull({ getViewer, items, onChange }) {
/** Cull everything from the camera at `position`; the count seen. */ /** Cull everything from the camera at `position`; the count seen. */
function cullAll(position) { function cullAll(position) {
from = Cesium.Cartesian3.clone(position, from); from = geo.cartesian3.clone(position, from);
return cull(items(), position); return cull(items(), position);
} }
function onPreRender() { function onPreRender() {
const position = getViewer()?.camera?.positionWC; const position = getViewer()?.camera?.positionWC;
if (!position || (from && Cesium.Cartesian3.equals(from, position))) return; if (!position || (from && geo.cartesian3.equals(from, position))) return;
if (!cullAll(position)) stop(); if (!cullAll(position)) stop();
} }
+9 -9
View File
@@ -1,4 +1,4 @@
import * as Cesium from 'cesium'; import * as geo from '../../geo/index.js';
import { import {
CABLE_REFERENCE_LABEL_WINNER_CAP, CABLE_REFERENCE_LABEL_WINNER_CAP,
CABLE_REFERENCE_LABEL_MAX_DISTANCE_M, CABLE_REFERENCE_LABEL_MAX_DISTANCE_M,
@@ -193,7 +193,7 @@ export function createCableReferenceSweepGate({
const motionEpsilonSq = motionEpsilonM ** 2; const motionEpsilonSq = motionEpsilonM ** 2;
// Preallocated: the probe clones into it, so a moving camera allocates // Preallocated: the probe clones into it, so a moving camera allocates
// nothing per frame. // nothing per frame.
const lastSweptPosition = new Cesium.Cartesian3(); const lastSweptPosition = geo.cartesian3.create();
let hasSweptPosition = false; let hasSweptPosition = false;
let dirty = true; let dirty = true;
let lastProbeAt = -Infinity; let lastProbeAt = -Infinity;
@@ -203,7 +203,7 @@ export function createCableReferenceSweepGate({
lastProbeAt = time; lastProbeAt = time;
const position = camera?.positionWC; const position = camera?.positionWC;
hasSweptPosition = Boolean(position); hasSweptPosition = Boolean(position);
if (position) Cesium.Cartesian3.clone(position, lastSweptPosition); if (position) geo.cartesian3.clone(position, lastSweptPosition);
return true; return true;
} }
@@ -232,7 +232,7 @@ export function createCableReferenceSweepGate({
if (!position) return false; if (!position) return false;
if ( if (
hasSweptPosition && hasSweptPosition &&
Cesium.Cartesian3.distanceSquared(position, lastSweptPosition) <= geo.cartesian3.distanceSquared(position, lastSweptPosition) <=
motionEpsilonSq motionEpsilonSq
) { ) {
return false; return false;
@@ -266,7 +266,7 @@ export function updateCableReferenceStem(
canvasHeight, canvasHeight,
fov, fov,
) { ) {
const distance = Cesium.Cartesian3.distance(cameraPositionWC, record.base); const distance = geo.cartesian3.distance(cameraPositionWC, record.base);
const effectiveDistance = Math.max(distance, 5000); const effectiveDistance = Math.max(distance, 5000);
const height = canvasHeight || 1080; const height = canvasHeight || 1080;
const fieldOfView = fov || Math.PI / 3; const fieldOfView = fov || Math.PI / 3;
@@ -275,20 +275,20 @@ export function updateCableReferenceStem(
700, 700,
Math.min(85000, effectiveDistance * metersPerPixelFactor * STEM_TARGET_PX), Math.min(85000, effectiveDistance * metersPerPixelFactor * STEM_TARGET_PX),
); );
Cesium.Cartesian3.fromDegrees( geo.cartesian3.fromDegrees(
record.reference.lon, record.reference.lon,
record.reference.lat, record.reference.lat,
tipHeight, tipHeight,
Cesium.Ellipsoid.WGS84, geo.ellipsoid.WGS84,
record.nextTip, record.nextTip,
); );
if ( if (
Cesium.Cartesian3.distanceSquared(record.tip, record.nextTip) <= geo.cartesian3.distanceSquared(record.tip, record.nextTip) <=
CABLE_STEM_TIP_EPSILON_SQ CABLE_STEM_TIP_EPSILON_SQ
) { ) {
return false; return false;
} }
Cesium.Cartesian3.clone(record.nextTip, record.tip); geo.cartesian3.clone(record.nextTip, record.tip);
record.stemPositionBufferIndex = 1 - record.stemPositionBufferIndex; record.stemPositionBufferIndex = 1 - record.stemPositionBufferIndex;
const stemPositions = const stemPositions =
record.stemPositionBuffers[record.stemPositionBufferIndex]; record.stemPositionBuffers[record.stemPositionBufferIndex];
+9 -8
View File
@@ -1,4 +1,5 @@
import * as Cesium from 'cesium'; import * as Cesium from 'cesium';
import * as geo from '../../geo/index.js';
import { tilesForBounds, tileToBBox } from '../../data/tomtomTiles.js'; import { tilesForBounds, tileToBBox } from '../../data/tomtomTiles.js';
export const RETICLE_RANGE_KM = 10; export const RETICLE_RANGE_KM = 10;
@@ -64,17 +65,17 @@ export function footprintTiles(polygon, zoom, near) {
/** Reusable camera scratch; sampled only on camera events, never in the animation loop. */ /** Reusable camera scratch; sampled only on camera events, never in the animation loop. */
export function createReticleFootprint() { export function createReticleFootprint() {
const pixels = Array.from({ length: 25 }, () => new Cesium.Cartesian2()); const pixels = Array.from({ length: 25 }, () => geo.cartesian2.create());
const hits = Array.from({ length: 25 }, () => new Cesium.Cartesian3()); const hits = Array.from({ length: 25 }, () => geo.cartesian3.create());
const carto = new Cesium.Cartographic(); const carto = geo.cartographic.create();
const ray = new Cesium.Ray(); const ray = new Cesium.Ray();
return (viewer, altitude) => { return (viewer, altitude) => {
const { camera, scene } = viewer; const { camera, scene } = viewer;
if (!camera.getPickRay) return null; if (!camera.getPickRay) return null;
const nadir = camera.positionCartographic; const nadir = camera.positionCartographic;
const near = { const near = {
lat: Cesium.Math.toDegrees(nadir.latitude), lat: geo.math.toDegrees(nadir.latitude),
lon: Cesium.Math.toDegrees(nadir.longitude), lon: geo.math.toDegrees(nadir.longitude),
}; };
const width = scene.canvas.clientWidth || scene.canvas.width, const width = scene.canvas.clientWidth || scene.canvas.width,
height = scene.canvas.clientHeight || scene.canvas.height; height = scene.canvas.clientHeight || scene.canvas.height;
@@ -91,9 +92,9 @@ export function createReticleFootprint() {
const hit = camera.pickEllipsoid(p, Cesium.Ellipsoid.WGS84, hits[i]); const hit = camera.pickEllipsoid(p, Cesium.Ellipsoid.WGS84, hits[i]);
let dx, dy; let dx, dy;
if (hit) { if (hit) {
Cesium.Cartographic.fromCartesian(hit, Cesium.Ellipsoid.WGS84, carto); geo.cartographic.fromCartesian(hit, geo.ellipsoid.WGS84, carto);
dy = (Cesium.Math.toDegrees(carto.latitude) - near.lat) * 111.195; dy = (geo.math.toDegrees(carto.latitude) - near.lat) * 111.195;
let dlon = Cesium.Math.toDegrees(carto.longitude) - near.lon; let dlon = geo.math.toDegrees(carto.longitude) - near.lon;
dlon -= 360 * Math.round(dlon / 360); dlon -= 360 * Math.round(dlon / 360);
dx = dlon * 111.195 * Math.cos(nadir.latitude); dx = dlon * 111.195 * Math.cos(nadir.latitude);
} else { } else {
+2 -2
View File
@@ -1,4 +1,4 @@
import * as Cesium from 'cesium'; import * as geo from '../../geo/index.js';
import { requestWithDeadline } from '../../sources/requestDeadline.js'; import { requestWithDeadline } from '../../sources/requestDeadline.js';
import { resolveRoadMode, ROAD_SOURCE_LABELS } from './roadModes.js'; import { resolveRoadMode, ROAD_SOURCE_LABELS } from './roadModes.js';
import { phaseTiming } from '../../sources/phaseTiming.js'; import { phaseTiming } from '../../sources/phaseTiming.js';
@@ -271,7 +271,7 @@ export function createIngestion({
const centerLat = (clamped.south + clamped.north) / 2; const centerLat = (clamped.south + clamped.north) / 2;
const centerLon = (clamped.west + clamped.east) / 2; const centerLon = (clamped.west + clamped.east) / 2;
const scene = layerState._viewer?.scene; const scene = layerState._viewer?.scene;
const location = Cesium.Cartographic.fromDegrees(centerLon, centerLat); const location = geo.cartographic.fromDegrees(centerLon, centerLat);
let estimated = services.ground?.cachedGroundFloor?.(centerLat, centerLon); let estimated = services.ground?.cachedGroundFloor?.(centerLat, centerLon);
if (!Number.isFinite(estimated)) { if (!Number.isFinite(estimated)) {
try { try {
+11 -10
View File
@@ -1,5 +1,6 @@
import { createReticleFootprint } from './footprint.js'; import { createReticleFootprint } from './footprint.js';
import * as Cesium from 'cesium'; import * as Cesium from 'cesium';
import * as geo from '../../geo/index.js';
import { import {
deriveFetchCenter, deriveFetchCenter,
clampBoundsAroundCenter, clampBoundsAroundCenter,
@@ -37,10 +38,10 @@ export function createViewport({ state: layerState, services, parts, source }) {
const rect = layerState._viewer.camera.computeViewRectangle(); const rect = layerState._viewer.camera.computeViewRectangle();
if (!rect) return null; if (!rect) return null;
return { return {
south: Cesium.Math.toDegrees(rect.south), south: geo.math.toDegrees(rect.south),
west: Cesium.Math.toDegrees(rect.west), west: geo.math.toDegrees(rect.west),
north: Cesium.Math.toDegrees(rect.north), north: geo.math.toDegrees(rect.north),
east: Cesium.Math.toDegrees(rect.east), east: geo.math.toDegrees(rect.east),
}; };
} }
@@ -61,8 +62,8 @@ export function createViewport({ state: layerState, services, parts, source }) {
function getFetchCenter() { function getFetchCenter() {
const carto = layerState._viewer.camera.positionCartographic; const carto = layerState._viewer.camera.positionCartographic;
if (!carto) return null; if (!carto) return null;
const nadirLat = Cesium.Math.toDegrees(carto.latitude); const nadirLat = geo.math.toDegrees(carto.latitude);
const nadirLon = Cesium.Math.toDegrees(carto.longitude); const nadirLon = geo.math.toDegrees(carto.longitude);
let hitLat; let hitLat;
let hitLon; let hitLon;
@@ -71,13 +72,13 @@ export function createViewport({ state: layerState, services, parts, source }) {
const height = canvas.clientHeight || canvas.height; const height = canvas.clientHeight || canvas.height;
if (width > 0 && height > 0) { if (width > 0 && height > 0) {
const hit = layerState._viewer.camera.pickEllipsoid( const hit = layerState._viewer.camera.pickEllipsoid(
new Cesium.Cartesian2(width / 2, height / 2), geo.cartesian2.create(width / 2, height / 2),
Cesium.Ellipsoid.WGS84, Cesium.Ellipsoid.WGS84,
); );
if (hit) { if (hit) {
const hitCarto = Cesium.Cartographic.fromCartesian(hit); const hitCarto = geo.cartographic.fromCartesian(hit);
hitLat = Cesium.Math.toDegrees(hitCarto.latitude); hitLat = geo.math.toDegrees(hitCarto.latitude);
hitLon = Cesium.Math.toDegrees(hitCarto.longitude); hitLon = geo.math.toDegrees(hitCarto.longitude);
} }
} }
+8 -13
View File
@@ -1,4 +1,5 @@
import * as Cesium from 'cesium'; import * as Cesium from 'cesium';
import * as geo from '../../geo/index.js';
import { import {
cameraPoseSignature, cameraPoseSignature,
perspectiveProjectedRotation, perspectiveProjectedRotation,
@@ -56,13 +57,7 @@ export function createRendering({ state, services, parts }) {
function cartesianFor(lat, lon, heightM, out) { function cartesianFor(lat, lon, heightM, out) {
// `heightM` already carries the shared floor's own lift, so nothing is // `heightM` already carries the shared floor's own lift, so nothing is
// added here: two lifts stacked is a vehicle hovering. // added here: two lifts stacked is a vehicle hovering.
return Cesium.Cartesian3.fromDegrees( return geo.cartesian3.fromDegrees(lon, lat, heightM || 0, undefined, out);
lon,
lat,
heightM || 0,
undefined,
out,
);
} }
/** Heights are aligned to work with Google 3D tiles. Rebuild both ends. */ /** Heights are aligned to work with Google 3D tiles. Rebuild both ends. */
@@ -74,13 +69,13 @@ export function createRendering({ state, services, parts }) {
entry.from.lat, entry.from.lat,
entry.from.lon, entry.from.lon,
entry.from.h, entry.from.h,
entry.fromCart || new Cesium.Cartesian3(), entry.fromCart || geo.cartesian3.create(),
); );
entry.toCart = cartesianFor( entry.toCart = cartesianFor(
entry.to.lat, entry.to.lat,
entry.to.lon, entry.to.lon,
entry.to.h, entry.to.h,
entry.toCart || new Cesium.Cartesian3(), entry.toCart || geo.cartesian3.create(),
); );
entry.endpointRevision = entry.sample.revision; entry.endpointRevision = entry.sample.revision;
entry.endpointFromSeq = entry.sample.fromSeq; entry.endpointFromSeq = entry.sample.fromSeq;
@@ -262,7 +257,7 @@ export function createRendering({ state, services, parts }) {
height: MARKER_PIXEL_SIZE, height: MARKER_PIXEL_SIZE,
color: MODE_CESIUM_COLORS[entry.mode], color: MODE_CESIUM_COLORS[entry.mode],
rotation: 0, rotation: 0,
alignedAxis: Cesium.Cartesian3.ZERO, alignedAxis: geo.cartesian3.ZERO,
disableDepthTestDistance: Number.POSITIVE_INFINITY, disableDepthTestDistance: Number.POSITIVE_INFINITY,
}); });
entry.marker = marker; entry.marker = marker;
@@ -443,8 +438,8 @@ export function createRendering({ state, services, parts }) {
const occluder = new Cesium.EllipsoidalOccluder(Cesium.Ellipsoid.WGS84); const occluder = new Cesium.EllipsoidalOccluder(Cesium.Ellipsoid.WGS84);
const sphere = new Cesium.BoundingSphere(undefined, 5); const sphere = new Cesium.BoundingSphere(undefined, 5);
const cameraPosition = new Cesium.Cartesian3(); const cameraPosition = geo.cartesian3.create();
const candidatePosition = new Cesium.Cartesian3(); const candidatePosition = geo.cartesian3.create();
/** Visibility work runs off the frame path, coalesced at four sweeps/second. */ /** Visibility work runs off the frame path, coalesced at four sweeps/second. */
function requestVisibility() { function requestVisibility() {
state._visibilityDirty = true; state._visibilityDirty = true;
@@ -471,7 +466,7 @@ export function createRendering({ state, services, parts }) {
if (!camera) return 0; if (!camera) return 0;
const position = const position =
camera.positionWC || camera.positionWC ||
Cesium.Ellipsoid.WGS84.cartographicToCartesian( geo.ellipsoid.WGS84.cartographicToCartesian(
camera.positionCartographic, camera.positionCartographic,
cameraPosition, cameraPosition,
); );
+2 -2
View File
@@ -1,4 +1,4 @@
import * as Cesium from 'cesium'; import * as geo from '../../geo/index.js';
import { createHistoryBudget } from '../../data/contactPlayback.js'; import { createHistoryBudget } from '../../data/contactPlayback.js';
/** /**
@@ -120,7 +120,7 @@ export function createState({ services }) {
state._error = null; state._error = null;
state._limitWarned = false; state._limitWarned = false;
state._scratchCartesian = new Cesium.Cartesian3(); state._scratchCartesian = geo.cartesian3.create();
return state; return state;
} }
+4 -6
View File
@@ -1,5 +1,5 @@
import { getRegisteredTransitFeed } from '../../data/transitFeeds.js'; import { getRegisteredTransitFeed } from '../../data/transitFeeds.js';
import * as Cesium from 'cesium'; import * as geo from '../../geo/index.js';
import { import {
readFix, readFix,
correctHeight, correctHeight,
@@ -154,12 +154,10 @@ export function createTrails({ state, services, parts, source }) {
// Ground polylines consume longitude/latitude and drape themselves. // Ground polylines consume longitude/latitude and drape themselves.
// Unknown floors still disqualify the marker corridor. // Unknown floors still disqualify the marker corridor.
positions.push( positions.push(
draped ? Cesium.Cartesian3.fromDegrees(point.lon, point.lat) : null, draped ? geo.cartesian3.fromDegrees(point.lon, point.lat) : null,
); );
} else } else
positions.push( positions.push(geo.cartesian3.fromDegrees(point.lon, point.lat, h));
Cesium.Cartesian3.fromDegrees(point.lon, point.lat, h),
);
} }
signature += `${a.seq}/${b.seq}:${heights.join(',')};`; signature += `${a.seq}/${b.seq}:${heights.join(',')};`;
if (retainBody) vertices += n + 1; if (retainBody) vertices += n + 1;
@@ -216,7 +214,7 @@ export function createTrails({ state, services, parts, source }) {
} }
if (sample.fromSeq === sample.toSeq) { if (sample.fromSeq === sample.toSeq) {
if (!Number.isFinite(entry.segment.from.h)) return null; if (!Number.isFinite(entry.segment.from.h)) return null;
Cesium.Cartesian3.clone(entry.fromCart, out); geo.cartesian3.clone(entry.fromCart, out);
return out; return out;
} }
const path = entry.displayPaths?.get(sample.fromSeq); const path = entry.displayPaths?.get(sample.fromSeq);
+9 -8
View File
@@ -1,4 +1,5 @@
import * as Cesium from 'cesium'; import * as Cesium from 'cesium';
import * as geo from '../../geo/index.js';
import { import {
ACTIVATION_ENTER_ALTITUDE_M, ACTIVATION_ENTER_ALTITUDE_M,
ACTIVATION_EXIT_ALTITUDE_M, ACTIVATION_EXIT_ALTITUDE_M,
@@ -29,15 +30,15 @@ export function createViewport({ state, services, parts }) {
if (rect) { if (rect) {
const center = Cesium.Rectangle.center(rect); const center = Cesium.Rectangle.center(rect);
return { return {
lat: Cesium.Math.toDegrees(center.latitude), lat: geo.math.toDegrees(center.latitude),
lon: Cesium.Math.toDegrees(center.longitude), lon: geo.math.toDegrees(center.longitude),
}; };
} }
const carto = viewer?.camera?.positionCartographic; const carto = viewer?.camera?.positionCartographic;
if (carto) { if (carto) {
return { return {
lat: Cesium.Math.toDegrees(carto.latitude), lat: geo.math.toDegrees(carto.latitude),
lon: Cesium.Math.toDegrees(carto.longitude), lon: geo.math.toDegrees(carto.longitude),
}; };
} }
return null; return null;
@@ -59,10 +60,10 @@ export function createViewport({ state, services, parts }) {
); );
state._viewBounds = rect state._viewBounds = rect
? inflateViewBounds({ ? inflateViewBounds({
south: Cesium.Math.toDegrees(rect.south), south: geo.math.toDegrees(rect.south),
north: Cesium.Math.toDegrees(rect.north), north: geo.math.toDegrees(rect.north),
west: Cesium.Math.toDegrees(rect.west), west: geo.math.toDegrees(rect.west),
east: Cesium.Math.toDegrees(rect.east), east: geo.math.toDegrees(rect.east),
}) })
: null; : null;
// The sweep itself is deferred: `marker.show` is a dirty flag, and a drag // The sweep itself is deferred: `marker.show` is a dirty flag, and a drag