mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-06 11:24:00 +00:00
Load the Cesium SDK from index.html again, since engine-neutral modules read its global when they load
This reverts ae13a56f. In the production build every 'cesium' import is the global that Cesium.js defines; with the script loaded only when a Cesium globe started, modules evaluated at boot (cesiumConstants, annotationEngine) threw ReferenceError and neither engine started. A cold Navara start loading Cesium.js stays a known gap.
This commit is contained in:
1 parent
9cc108835e
commit
125fbc5a3b
27 files changed
+116
-266
No files matched your search
+1
-3
@@ -186,9 +186,7 @@ export function createBrowserViteConfig({
|
|||||||
apiResponseHeadersPlugin(),
|
apiResponseHeadersPlugin(),
|
||||||
// Next, so no provider route answers a Host the server does not allow.
|
// Next, so no provider route answers a Host the server does not allow.
|
||||||
hostCheckPlugin(),
|
hostCheckPlugin(),
|
||||||
// Keep the SDK asset serving/copying and external imports, but let the
|
cesium(),
|
||||||
// scene load the script and stylesheet only when Cesium is requested.
|
|
||||||
{ ...cesium(), transformIndexHtml: undefined },
|
|
||||||
// Application views are Vue single-file components.
|
// Application views are Vue single-file components.
|
||||||
vue(VUE_PLUGIN_OPTIONS),
|
vue(VUE_PLUGIN_OPTIONS),
|
||||||
...plugins,
|
...plugins,
|
||||||
|
|||||||
@@ -1984,7 +1984,6 @@
|
|||||||
"traffic-layer": {
|
"traffic-layer": {
|
||||||
"exports": ["./layers/traffic"],
|
"exports": ["./layers/traffic"],
|
||||||
"modules": [
|
"modules": [
|
||||||
"src/layers/shared/color.js",
|
|
||||||
"src/data/cameraSensitivity.js",
|
"src/data/cameraSensitivity.js",
|
||||||
"src/data/flowMatch.js",
|
"src/data/flowMatch.js",
|
||||||
"src/data/tomtomTiles.js",
|
"src/data/tomtomTiles.js",
|
||||||
@@ -2658,7 +2657,6 @@
|
|||||||
"src/app/layers/traffic.js",
|
"src/app/layers/traffic.js",
|
||||||
"src/app/operations.js",
|
"src/app/operations.js",
|
||||||
"src/app/scene.js",
|
"src/app/scene.js",
|
||||||
"src/app/loadCesium.js",
|
|
||||||
"src/sources/sourceSlot.js",
|
"src/sources/sourceSlot.js",
|
||||||
"src/app/sources.js",
|
"src/app/sources.js",
|
||||||
"src/app/startupChrome.js",
|
"src/app/startupChrome.js",
|
||||||
|
|||||||
@@ -46,10 +46,10 @@ const PALETTE = {
|
|||||||
*
|
*
|
||||||
* BOTH paints onto terrain AND onto 3D tiles, so one value covers both worlds.
|
* BOTH paints onto terrain AND onto 3D tiles, so one value covers both worlds.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export function createWorldAnnotationRenderer(viewer) {
|
|
||||||
const CLASSIFY = Cesium.ClassificationType.BOTH;
|
const CLASSIFY = Cesium.ClassificationType.BOTH;
|
||||||
const CLAMP = Cesium.HeightReference.CLAMP_TO_GROUND;
|
const CLAMP = Cesium.HeightReference.CLAMP_TO_GROUND;
|
||||||
|
|
||||||
|
export function createWorldAnnotationRenderer(viewer) {
|
||||||
const dataSource = new Cesium.CustomDataSource('gev-annotations');
|
const dataSource = new Cesium.CustomDataSource('gev-annotations');
|
||||||
viewer.dataSources.add(dataSource);
|
viewer.dataSources.add(dataSource);
|
||||||
const osmAnnotations = new Set();
|
const osmAnnotations = new Set();
|
||||||
|
|||||||
@@ -1,52 +0,0 @@
|
|||||||
// The production build externalizes Cesium; the dev server imports its ESM
|
|
||||||
// package. Both load widget CSS only when a native viewer is requested.
|
|
||||||
export function createCesiumLoader({
|
|
||||||
document = globalThis.document,
|
|
||||||
globals = globalThis,
|
|
||||||
base = `${import.meta.env?.BASE_URL ?? '/'}cesium/`,
|
|
||||||
script = import.meta.env?.PROD === true,
|
|
||||||
} = {}) {
|
|
||||||
let pending;
|
|
||||||
return () => {
|
|
||||||
if (pending) return pending;
|
|
||||||
globals.CESIUM_BASE_URL ??= base;
|
|
||||||
const root = globals.CESIUM_BASE_URL.replace(/\/?$/, '/');
|
|
||||||
const elements = [];
|
|
||||||
const load = (tag, url) =>
|
|
||||||
new Promise((resolve, reject) => {
|
|
||||||
const element = document.createElement(tag);
|
|
||||||
elements.push(element);
|
|
||||||
if (tag === 'script') element.src = url;
|
|
||||||
else {
|
|
||||||
element.rel = 'stylesheet';
|
|
||||||
element.href = url;
|
|
||||||
}
|
|
||||||
element.onload = () => {
|
|
||||||
element.onload = element.onerror = null;
|
|
||||||
resolve();
|
|
||||||
};
|
|
||||||
element.onerror = () => reject(new Error(`Could not load ${url}`));
|
|
||||||
document.head.append(element);
|
|
||||||
});
|
|
||||||
pending = Promise.all([
|
|
||||||
load('link', `${root}Widgets/widgets.css`),
|
|
||||||
...(script && !globals.Cesium
|
|
||||||
? [load('script', `${root}Cesium.js`)]
|
|
||||||
: []),
|
|
||||||
]).catch((error) => {
|
|
||||||
for (const element of elements) {
|
|
||||||
element.onload = element.onerror = null;
|
|
||||||
element.remove();
|
|
||||||
}
|
|
||||||
pending = null;
|
|
||||||
throw error;
|
|
||||||
});
|
|
||||||
return pending;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
let load;
|
|
||||||
export function loadCesium() {
|
|
||||||
load ??= createCesiumLoader();
|
|
||||||
return load();
|
|
||||||
}
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
import assert from 'node:assert/strict';
|
|
||||||
import test from 'node:test';
|
|
||||||
import { spawnSync } from 'node:child_process';
|
|
||||||
import { createCesiumLoader } from './loadCesium.js';
|
|
||||||
|
|
||||||
function fixture(globals = {}) {
|
|
||||||
const elements = [];
|
|
||||||
const document = {
|
|
||||||
createElement: (tag) => ({
|
|
||||||
tag,
|
|
||||||
remove() {
|
|
||||||
elements.splice(elements.indexOf(this), 1);
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
head: { append: (element) => elements.push(element) },
|
|
||||||
};
|
|
||||||
return {
|
|
||||||
elements,
|
|
||||||
globals,
|
|
||||||
load: createCesiumLoader({
|
|
||||||
document,
|
|
||||||
globals,
|
|
||||||
base: '/app/cesium/',
|
|
||||||
script: true,
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
test('Cesium assets load together only on demand and are shared across starts', async () => {
|
|
||||||
const { elements, globals, load } = fixture();
|
|
||||||
assert.equal(elements.length, 0);
|
|
||||||
const first = load();
|
|
||||||
assert.equal(load(), first);
|
|
||||||
assert.equal(globals.CESIUM_BASE_URL, '/app/cesium/');
|
|
||||||
assert.deepEqual(
|
|
||||||
elements.map((e) => e.href ?? e.src),
|
|
||||||
['/app/cesium/Widgets/widgets.css', '/app/cesium/Cesium.js'],
|
|
||||||
);
|
|
||||||
elements.forEach((e) => e.onload());
|
|
||||||
await first;
|
|
||||||
await load();
|
|
||||||
assert.equal(elements.length, 2);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('a failed Cesium asset load can be retried and preserves the configured base', async () => {
|
|
||||||
const { elements, globals, load } = fixture({ CESIUM_BASE_URL: '/custom/' });
|
|
||||||
const failed = load();
|
|
||||||
elements[1].onerror();
|
|
||||||
await assert.rejects(failed, /Could not load/);
|
|
||||||
assert.equal(elements.length, 0);
|
|
||||||
const retried = load();
|
|
||||||
assert.equal(globals.CESIUM_BASE_URL, '/custom/');
|
|
||||||
assert.equal(elements[1].src, '/custom/Cesium.js');
|
|
||||||
elements.forEach((e) => e.onload());
|
|
||||||
await retried;
|
|
||||||
});
|
|
||||||
|
|
||||||
test('the standalone startup graph can be imported before the Cesium SDK exists', () => {
|
|
||||||
// Empty SDK exports make any boot-time native constructor or enum read fail.
|
|
||||||
// mgrs is CJS in Node; its browser named export is unrelated to this gate.
|
|
||||||
const script = `
|
|
||||||
import { registerHooks } from 'node:module';
|
|
||||||
registerHooks({ resolve(specifier, context, next) {
|
|
||||||
const code = specifier === 'cesium'
|
|
||||||
? 'export const Axis=undefined,ScreenSpaceEventType=undefined,BoundingSphere=undefined,Color=undefined,PostProcessStage=undefined;'
|
|
||||||
: specifier === 'mgrs' ? 'export function forward() {}' : null;
|
|
||||||
return code ? { url: 'data:text/javascript,' + encodeURIComponent(code), shortCircuit: true } : next(specifier, context);
|
|
||||||
}});
|
|
||||||
await import('./src/standalone/application.js');
|
|
||||||
const { registerNavaraLayerRenderers } = await import('./src/app/navaraMode.js');
|
|
||||||
await registerNavaraLayerRenderers();
|
|
||||||
const { createStandaloneCatalog } = await import('./src/standalone/catalog.js');
|
|
||||||
const lifetime = new AbortController();
|
|
||||||
const catalog = createStandaloneCatalog({ engineKind: 'navara', signal: lifetime.signal });
|
|
||||||
if (catalog.layers.length !== 33) throw new Error('Incomplete cold Navara catalog');
|
|
||||||
lifetime.abort();
|
|
||||||
`;
|
|
||||||
const result = spawnSync(
|
|
||||||
process.execPath,
|
|
||||||
['--import=./build/registerVue.js', '--input-type=module', '-e', script],
|
|
||||||
{ encoding: 'utf8' },
|
|
||||||
);
|
|
||||||
assert.equal(result.status, 0, result.stderr);
|
|
||||||
});
|
|
||||||
@@ -17,7 +17,6 @@ import {
|
|||||||
import { describeError } from './errors.js';
|
import { describeError } from './errors.js';
|
||||||
import { createSceneEngine } from './globeEngine.js';
|
import { createSceneEngine } from './globeEngine.js';
|
||||||
import { onLocaleChange, t } from '../i18n/index.js';
|
import { onLocaleChange, t } from '../i18n/index.js';
|
||||||
import { loadCesium } from './loadCesium.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct the application globe using the caller's local configuration.
|
* Construct the application globe using the caller's local configuration.
|
||||||
@@ -140,8 +139,6 @@ async function createRenderer({
|
|||||||
}
|
}
|
||||||
if (engineKind !== 'cesium')
|
if (engineKind !== 'cesium')
|
||||||
throw new TypeError(`Unknown globe engine: ${engineKind}`);
|
throw new TypeError(`Unknown globe engine: ${engineKind}`);
|
||||||
await loadCesium();
|
|
||||||
signal.throwIfAborted();
|
|
||||||
loaderStatus.textContent = t('Configuring viewer...');
|
loaderStatus.textContent = t('Configuring viewer...');
|
||||||
// Provider attribution stays visible, including clean-view and recording.
|
// Provider attribution stays visible, including clean-view and recording.
|
||||||
const creditContainer = document.createElement('div');
|
const creditContainer = document.createElement('div');
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
import { LayerBindings } from './ui/layerBindings.js';
|
import { LayerBindings } from './ui/layerBindings.js';
|
||||||
import { ScreenSpaceEventType } from 'cesium';
|
|
||||||
import { FIRMS_LEFT_CLICK } from './layers/firms/render/cesium.js';
|
|
||||||
import { readShellSource, shellMethod } from './testSupport/readShellSource.mjs';
|
import { readShellSource, shellMethod } from './testSupport/readShellSource.mjs';
|
||||||
import { readLayerSource } from './testSupport/readLayerSource.mjs';
|
import { readLayerSource } from './testSupport/readLayerSource.mjs';
|
||||||
import { enter as cockpitEnter, navigateContext } from './ui/cockpitTrackingController.js';
|
import { enter as cockpitEnter, navigateContext } from './ui/cockpitTrackingController.js';
|
||||||
@@ -418,7 +416,7 @@ test('vessel and fire layers announce valid clicks and never fly cameras', () =>
|
|||||||
);
|
);
|
||||||
assert.match(vesselFocus, /requestWorldFocus\(\{/);
|
assert.match(vesselFocus, /requestWorldFocus\(\{/);
|
||||||
assert.match(firms, /const clickType\s*=\s*layerState\._renderer\?\.clickType\s*\?\?\s*config\.leftClickEventType/);
|
assert.match(firms, /const clickType\s*=\s*layerState\._renderer\?\.clickType\s*\?\?\s*config\.leftClickEventType/);
|
||||||
assert.equal(FIRMS_LEFT_CLICK, ScreenSpaceEventType.LEFT_CLICK);
|
assert.match(firms, /FIRMS_LEFT_CLICK = Cesium\.ScreenSpaceEventType\.LEFT_CLICK/);
|
||||||
const fireClick = body(
|
const fireClick = body(
|
||||||
firms,
|
firms,
|
||||||
/_clickHandler\.setInputAction\(\(click\) => \{([\s\S]*?)\n \}, clickType\);/,
|
/_clickHandler\.setInputAction\(\(click\) => \{([\s\S]*?)\n \}, clickType\);/,
|
||||||
|
|||||||
@@ -9,7 +9,14 @@ export const CYBER_SONAR_CESIUM_VERSION = '1.138.0';
|
|||||||
// Follow every public DrawCommand setter, including pick/shadow/culling flags.
|
// Follow every public DrawCommand setter, including pick/shadow/culling flags.
|
||||||
// Copying native.dirty would keep derived pipelines dirty forever: the scene
|
// Copying native.dirty would keep derived pipelines dirty forever: the scene
|
||||||
// consumes our command, so it never clears that flag on the native command.
|
// consumes our command, so it never clears that flag on the native command.
|
||||||
let commandProperties;
|
const commandProperties = Object.entries(
|
||||||
|
Object.getOwnPropertyDescriptors(Cesium.DrawCommand.prototype),
|
||||||
|
)
|
||||||
|
.filter(
|
||||||
|
([key, descriptor]) =>
|
||||||
|
descriptor.set && key !== 'shaderProgram' && key !== 'uniformMap',
|
||||||
|
)
|
||||||
|
.map(([key]) => key);
|
||||||
|
|
||||||
export function syncCyberSonarCommand(
|
export function syncCyberSonarCommand(
|
||||||
native,
|
native,
|
||||||
@@ -18,14 +25,6 @@ export function syncCyberSonarCommand(
|
|||||||
uniforms,
|
uniforms,
|
||||||
labelBackground,
|
labelBackground,
|
||||||
) {
|
) {
|
||||||
commandProperties ??= Object.entries(
|
|
||||||
Object.getOwnPropertyDescriptors(Cesium.DrawCommand.prototype),
|
|
||||||
)
|
|
||||||
.filter(
|
|
||||||
([key, descriptor]) =>
|
|
||||||
descriptor.set && key !== 'shaderProgram' && key !== 'uniformMap',
|
|
||||||
)
|
|
||||||
.map(([key]) => key);
|
|
||||||
if (!record.command) {
|
if (!record.command) {
|
||||||
record.command = new Cesium.DrawCommand();
|
record.command = new Cesium.DrawCommand();
|
||||||
record.uniformMap = {
|
record.uniformMap = {
|
||||||
|
|||||||
@@ -47,9 +47,8 @@ const SCENE_PATH_RENDER_HOLD = 'bhote-koshi-scene-path-travel';
|
|||||||
const SCENE_MEDIA_MIN_PLAYBACK_SECONDS = 6;
|
const SCENE_MEDIA_MIN_PLAYBACK_SECONDS = 6;
|
||||||
const SCENE_MEDIA_EXIT_SECONDS = 0.65;
|
const SCENE_MEDIA_EXIT_SECONDS = 0.65;
|
||||||
const BHOTE_EVENT_ACCENT = WORLD_OVERLAY_STYLE.accent;
|
const BHOTE_EVENT_ACCENT = WORLD_OVERLAY_STYLE.accent;
|
||||||
const FLOOD_COLOR = () =>
|
const FLOOD_COLOR = Cesium.Color.fromCssColorString('#d8954e').withAlpha(0.68);
|
||||||
Cesium.Color.fromCssColorString('#d8954e').withAlpha(0.68);
|
const SURGE_COLOR = Cesium.Color.fromCssColorString('#e8b47c');
|
||||||
const SURGE_COLOR = () => Cesium.Color.fromCssColorString('#e8b47c');
|
|
||||||
const CINEMATIC_INPUT_EVENTS = Object.freeze(['pointerdown', 'wheel']);
|
const CINEMATIC_INPUT_EVENTS = Object.freeze(['pointerdown', 'wheel']);
|
||||||
const CINEMATIC_VIEW_SPECS = Object.freeze([
|
const CINEMATIC_VIEW_SPECS = Object.freeze([
|
||||||
{
|
{
|
||||||
@@ -1078,8 +1077,8 @@ export function createBhoteKoshiEventLayer({
|
|||||||
let _cinematicKeyframes = [];
|
let _cinematicKeyframes = [];
|
||||||
let _cinematicActive = false;
|
let _cinematicActive = false;
|
||||||
let _cinematicReplayArmed = false;
|
let _cinematicReplayArmed = false;
|
||||||
let _cinematicPose = { target: { x: 0, y: 0, z: 0 } };
|
let _cinematicPose = { target: new Cesium.Cartesian3() };
|
||||||
let _cinematicOffset = { heading: 0, pitch: 0, range: 0 };
|
let _cinematicOffset = new Cesium.HeadingPitchRange();
|
||||||
let _lastCinematicProgress = null;
|
let _lastCinematicProgress = null;
|
||||||
let _cameraInputTarget = null;
|
let _cameraInputTarget = null;
|
||||||
let _evidenceClickTarget = null;
|
let _evidenceClickTarget = null;
|
||||||
@@ -2571,11 +2570,11 @@ export function createBhoteKoshiEventLayer({
|
|||||||
const tileSafe = usesPhotorealFloodSurface();
|
const tileSafe = usesPhotorealFloodSurface();
|
||||||
_floodSurfaceMode = tileSafe ? 'tiles' : 'terrain';
|
_floodSurfaceMode = tileSafe ? 'tiles' : 'terrain';
|
||||||
const haloMaterial = new Cesium.PolylineDashMaterialProperty({
|
const haloMaterial = new Cesium.PolylineDashMaterialProperty({
|
||||||
color: FLOOD_COLOR().withAlpha(0.38),
|
color: FLOOD_COLOR.withAlpha(0.38),
|
||||||
dashLength: 18,
|
dashLength: 18,
|
||||||
});
|
});
|
||||||
const coreMaterial = new Cesium.PolylineGlowMaterialProperty({
|
const coreMaterial = new Cesium.PolylineGlowMaterialProperty({
|
||||||
color: FLOOD_COLOR().withAlpha(0.96),
|
color: FLOOD_COLOR.withAlpha(0.96),
|
||||||
glowPower: 0.24,
|
glowPower: 0.24,
|
||||||
taperPower: 0.7,
|
taperPower: 0.7,
|
||||||
});
|
});
|
||||||
@@ -2620,7 +2619,7 @@ export function createBhoteKoshiEventLayer({
|
|||||||
position: Cesium.Cartesian3.ZERO,
|
position: Cesium.Cartesian3.ZERO,
|
||||||
point: {
|
point: {
|
||||||
pixelSize: 11,
|
pixelSize: 11,
|
||||||
color: SURGE_COLOR(),
|
color: SURGE_COLOR,
|
||||||
outlineColor: Cesium.Color.BLACK.withAlpha(0.85),
|
outlineColor: Cesium.Color.BLACK.withAlpha(0.85),
|
||||||
outlineWidth: 3,
|
outlineWidth: 3,
|
||||||
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
|
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
|
||||||
|
|||||||
@@ -144,10 +144,10 @@ const NEARBY_CITIES = Object.freeze([
|
|||||||
placement: 'right-lower',
|
placement: 'right-lower',
|
||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
const BORDER_COLOR = () => Cesium.Color.fromCssColorString('#20e7f2');
|
const BORDER_COLOR = Cesium.Color.fromCssColorString('#20e7f2');
|
||||||
const BORDER_ACCENT = '#20e7f2';
|
const BORDER_ACCENT = '#20e7f2';
|
||||||
const INCIDENT_ACCENT = '#ffad55';
|
const INCIDENT_ACCENT = '#ffad55';
|
||||||
const INCIDENT_COLOR = () => Cesium.Color.fromCssColorString(INCIDENT_ACCENT);
|
const INCIDENT_COLOR = Cesium.Color.fromCssColorString(INCIDENT_ACCENT);
|
||||||
|
|
||||||
const DEFAULT_OVERLAY_HOST = Object.freeze({
|
const DEFAULT_OVERLAY_HOST = Object.freeze({
|
||||||
setEntries: setOverlayEntries,
|
setEntries: setOverlayEntries,
|
||||||
@@ -521,7 +521,7 @@ export function createBhoteKoshiLocatorLayer({
|
|||||||
sequenceStartedAt,
|
sequenceStartedAt,
|
||||||
visibleAfterMs = 0,
|
visibleAfterMs = 0,
|
||||||
) {
|
) {
|
||||||
addCallout(dataSource, INCIDENT, INCIDENT_COLOR(), {
|
addCallout(dataSource, INCIDENT, INCIDENT_COLOR, {
|
||||||
sequenceStartedAt,
|
sequenceStartedAt,
|
||||||
visibleAfterMs,
|
visibleAfterMs,
|
||||||
});
|
});
|
||||||
@@ -555,12 +555,12 @@ export function createBhoteKoshiLocatorLayer({
|
|||||||
false,
|
false,
|
||||||
),
|
),
|
||||||
color: new Cesium.CallbackProperty((_time, result) => {
|
color: new Cesium.CallbackProperty((_time, result) => {
|
||||||
const color = Cesium.Color.clone(INCIDENT_COLOR(), result);
|
const color = Cesium.Color.clone(INCIDENT_COLOR, result);
|
||||||
color.alpha = 0.16 * (1 - pulseProgress());
|
color.alpha = 0.16 * (1 - pulseProgress());
|
||||||
return color;
|
return color;
|
||||||
}, false),
|
}, false),
|
||||||
outlineColor: new Cesium.CallbackProperty((_time, result) => {
|
outlineColor: new Cesium.CallbackProperty((_time, result) => {
|
||||||
const color = Cesium.Color.clone(INCIDENT_COLOR(), result);
|
const color = Cesium.Color.clone(INCIDENT_COLOR, result);
|
||||||
color.alpha = isVisible() ? 0.08 + 0.78 * (1 - pulseProgress()) : 0;
|
color.alpha = isVisible() ? 0.08 + 0.78 * (1 - pulseProgress()) : 0;
|
||||||
return color;
|
return color;
|
||||||
}, false),
|
}, false),
|
||||||
@@ -705,7 +705,7 @@ export function createBhoteKoshiLocatorLayer({
|
|||||||
labelPlacement = 'right',
|
labelPlacement = 'right',
|
||||||
{ showAnchor = true } = {},
|
{ showAnchor = true } = {},
|
||||||
) {
|
) {
|
||||||
addCallout(dataSource, NEPAL, BORDER_COLOR(), {
|
addCallout(dataSource, NEPAL, BORDER_COLOR, {
|
||||||
labelPlacement,
|
labelPlacement,
|
||||||
sequenceStartedAt,
|
sequenceStartedAt,
|
||||||
showAnchor,
|
showAnchor,
|
||||||
@@ -820,12 +820,12 @@ export function createBhoteKoshiLocatorLayer({
|
|||||||
false,
|
false,
|
||||||
),
|
),
|
||||||
color: new Cesium.CallbackProperty((_time, result) => {
|
color: new Cesium.CallbackProperty((_time, result) => {
|
||||||
const color = Cesium.Color.clone(INCIDENT_COLOR(), result);
|
const color = Cesium.Color.clone(INCIDENT_COLOR, result);
|
||||||
color.alpha = 0.16 * (1 - pulseProgress());
|
color.alpha = 0.16 * (1 - pulseProgress());
|
||||||
return color;
|
return color;
|
||||||
}, false),
|
}, false),
|
||||||
outlineColor: new Cesium.CallbackProperty((_time, result) => {
|
outlineColor: new Cesium.CallbackProperty((_time, result) => {
|
||||||
const color = Cesium.Color.clone(INCIDENT_COLOR(), result);
|
const color = Cesium.Color.clone(INCIDENT_COLOR, result);
|
||||||
color.alpha = 0.08 + 0.78 * (1 - pulseProgress());
|
color.alpha = 0.08 + 0.78 * (1 - pulseProgress());
|
||||||
return color;
|
return color;
|
||||||
}, false),
|
}, false),
|
||||||
@@ -890,7 +890,7 @@ export function createBhoteKoshiLocatorLayer({
|
|||||||
positions: animatedPositions,
|
positions: animatedPositions,
|
||||||
width: 3.5,
|
width: 3.5,
|
||||||
clampToGround: true,
|
clampToGround: true,
|
||||||
material: BORDER_COLOR().withAlpha(0.96),
|
material: BORDER_COLOR.withAlpha(0.96),
|
||||||
classificationType: Cesium.ClassificationType.BOTH,
|
classificationType: Cesium.ClassificationType.BOTH,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -915,7 +915,7 @@ export function createBhoteKoshiLocatorLayer({
|
|||||||
show: new Cesium.CallbackProperty(() => now() >= drawStartedAt, false),
|
show: new Cesium.CallbackProperty(() => now() >= drawStartedAt, false),
|
||||||
polygon: {
|
polygon: {
|
||||||
hierarchy,
|
hierarchy,
|
||||||
material: BORDER_COLOR().withAlpha(0.055),
|
material: BORDER_COLOR.withAlpha(0.055),
|
||||||
classificationType: Cesium.ClassificationType.BOTH,
|
classificationType: Cesium.ClassificationType.BOTH,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -925,7 +925,7 @@ export function createBhoteKoshiLocatorLayer({
|
|||||||
positions: animatedPositions,
|
positions: animatedPositions,
|
||||||
width: 5,
|
width: 5,
|
||||||
clampToGround: true,
|
clampToGround: true,
|
||||||
material: BORDER_COLOR().withAlpha(0.12),
|
material: BORDER_COLOR.withAlpha(0.12),
|
||||||
classificationType: Cesium.ClassificationType.BOTH,
|
classificationType: Cesium.ClassificationType.BOTH,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -935,7 +935,7 @@ export function createBhoteKoshiLocatorLayer({
|
|||||||
positions: animatedPositions,
|
positions: animatedPositions,
|
||||||
width: 2.5,
|
width: 2.5,
|
||||||
clampToGround: true,
|
clampToGround: true,
|
||||||
material: BORDER_COLOR().withAlpha(0.96),
|
material: BORDER_COLOR.withAlpha(0.96),
|
||||||
classificationType: Cesium.ClassificationType.BOTH,
|
classificationType: Cesium.ClassificationType.BOTH,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -21,8 +21,6 @@ const STYLE = [
|
|||||||
'imageSubRegion',
|
'imageSubRegion',
|
||||||
];
|
];
|
||||||
|
|
||||||
/** Own static imported pins without a per-frame Entity visualizer walk. */
|
|
||||||
export function createImportedPins(dataSource, viewer) {
|
|
||||||
class ImportedBillboards extends Cesium.BillboardCollection {
|
class ImportedBillboards extends Cesium.BillboardCollection {
|
||||||
update(frameState) {
|
update(frameState) {
|
||||||
// Height queries should find the map, never another imported marker.
|
// Height queries should find the map, never another imported marker.
|
||||||
@@ -32,6 +30,8 @@ export function createImportedPins(dataSource, viewer) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Own static imported pins without a per-frame Entity visualizer walk. */
|
||||||
|
export function createImportedPins(dataSource, viewer) {
|
||||||
const all = dataSource.entities.values.slice();
|
const all = dataSource.entities.values.slice();
|
||||||
const now = Cesium.JulianDate.now();
|
const now = Cesium.JulianDate.now();
|
||||||
const pins = all.filter((entity) => entity.billboard && entity.position);
|
const pins = all.filter((entity) => entity.billboard && entity.position);
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { modelAxis } from './render/cesiumConstants.js';
|
||||||
import * as geo from '../geo/index.js';
|
import * as geo from '../geo/index.js';
|
||||||
/**
|
/**
|
||||||
* Model-space visual centres measured from the shipped GLBs' scene-space AABBs.
|
* Model-space visual centres measured from the shipped GLBs' scene-space AABBs.
|
||||||
@@ -70,9 +71,17 @@ export const MODEL_TRAIL_ANCHOR_NATIVE = Object.freeze({
|
|||||||
'/models/atr72.glb': Object.freeze([12.9785, -1.2935, 0]),
|
'/models/atr72.glb': Object.freeze([12.9785, -1.2935, 0]),
|
||||||
});
|
});
|
||||||
|
|
||||||
// glTF Y-up/Z-forward to the model frame: Cesium's Y_UP_TO_Z_UP ×
|
/** @constant Cesium's OWN axis correction for a glTF loaded with the
|
||||||
// Z_UP_TO_X_UP, shared with Navara before the Cesium SDK is loaded.
|
* `Model.fromGltfAsync` defaults (upAxis Y, forwardAxis Z), assembled from its
|
||||||
const AXIS_CORRECTION = [0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1];
|
* exported constants rather than restated as numbers here. `ModelSceneGraph`
|
||||||
|
* renders with `modelMatrix x components.transform x axisCorrection`, and the
|
||||||
|
* trail anchor has to ride the same chain or it lands on a different axis than
|
||||||
|
* the aircraft it is supposed to be attached to. */
|
||||||
|
const AXIS_CORRECTION = geo.matrix4.multiplyTransformation(
|
||||||
|
modelAxis.Y_UP_TO_Z_UP,
|
||||||
|
modelAxis.Z_UP_TO_X_UP,
|
||||||
|
geo.matrix4.create(),
|
||||||
|
);
|
||||||
const _anchorScratch = geo.cartesian3.create();
|
const _anchorScratch = geo.cartesian3.create();
|
||||||
const _chainScratch = geo.matrix4.create();
|
const _chainScratch = geo.matrix4.create();
|
||||||
|
|
||||||
|
|||||||
@@ -6,12 +6,11 @@ export function worldToWindowCoordinates(scene, position, result) {
|
|||||||
result,
|
result,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
let occluder;
|
const occluder = new Cesium.EllipsoidalOccluder(
|
||||||
export function horizonOccluder(camera) {
|
|
||||||
occluder ??= new Cesium.EllipsoidalOccluder(
|
|
||||||
Cesium.Ellipsoid.WGS84,
|
Cesium.Ellipsoid.WGS84,
|
||||||
new Cesium.Cartesian3(),
|
new Cesium.Cartesian3(),
|
||||||
);
|
);
|
||||||
|
export function horizonOccluder(camera) {
|
||||||
occluder.cameraPosition = camera.positionWC;
|
occluder.cameraPosition = camera.positionWC;
|
||||||
return occluder;
|
return occluder;
|
||||||
}
|
}
|
||||||
@@ -9,11 +9,11 @@ import { toCesium2, toCesium3, toGeo3 } from './convert.js';
|
|||||||
import { createCesiumFollow } from './follow.js';
|
import { createCesiumFollow } from './follow.js';
|
||||||
|
|
||||||
const { math } = geo;
|
const { math } = geo;
|
||||||
const easings = () => ({
|
const EASINGS = {
|
||||||
cubicInOut: Cesium.EasingFunction.CUBIC_IN_OUT,
|
cubicInOut: Cesium.EasingFunction.CUBIC_IN_OUT,
|
||||||
sinusoidalInOut: Cesium.EasingFunction.SINUSOIDAL_IN_OUT,
|
sinusoidalInOut: Cesium.EasingFunction.SINUSOIDAL_IN_OUT,
|
||||||
linear: Cesium.EasingFunction.LINEAR_NONE,
|
linear: Cesium.EasingFunction.LINEAR_NONE,
|
||||||
});
|
};
|
||||||
|
|
||||||
// Cesium reports heading and roll in [0, 2π]; the contract wants [0, 2π).
|
// Cesium reports heading and roll in [0, 2π]; the contract wants [0, 2π).
|
||||||
function wrapAngle(angle) {
|
function wrapAngle(angle) {
|
||||||
@@ -43,7 +43,7 @@ const cesiumDestination = (destination) =>
|
|||||||
)
|
)
|
||||||
: toCesium3(destination);
|
: toCesium3(destination);
|
||||||
|
|
||||||
const cesiumEasing = (easing) => (easing ? easings()[easing] : undefined);
|
const cesiumEasing = (easing) => (easing ? EASINGS[easing] : undefined);
|
||||||
|
|
||||||
// A HeadingPitchRange or a Cartesian offset, as Cesium's lookAt takes them.
|
// A HeadingPitchRange or a Cartesian offset, as Cesium's lookAt takes them.
|
||||||
const cesiumOffset = (offset) =>
|
const cesiumOffset = (offset) =>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
import * as Cesium from 'cesium';
|
import * as Cesium from 'cesium';
|
||||||
import { bridgeEvent } from './events.js';
|
import { bridgeEvent } from './events.js';
|
||||||
|
|
||||||
let scratchGregorian;
|
const scratchGregorian = new Cesium.GregorianDate();
|
||||||
|
|
||||||
// JulianDate.toDate(time).getTime() without the Date: frame events must not
|
// JulianDate.toDate(time).getTime() without the Date: frame events must not
|
||||||
// allocate. A raise without a time (not Cesium's own) reads the clock.
|
// allocate. A raise without a time (not Cesium's own) reads the clock.
|
||||||
@@ -27,7 +27,6 @@ function unixMilliseconds(scene, time) {
|
|||||||
* @returns {{ frames: object, destroy: () => void }}
|
* @returns {{ frames: object, destroy: () => void }}
|
||||||
*/
|
*/
|
||||||
export function createCesiumFrames(viewer) {
|
export function createCesiumFrames(viewer) {
|
||||||
scratchGregorian ??= new Cesium.GregorianDate();
|
|
||||||
const { scene } = viewer;
|
const { scene } = viewer;
|
||||||
const bridges = ['preUpdate', 'preRender', 'postRender'].map((name) => [
|
const bridges = ['preUpdate', 'preRender', 'postRender'].map((name) => [
|
||||||
name,
|
name,
|
||||||
|
|||||||
+13
-13
@@ -6,6 +6,19 @@ import { normalizeInputOptions } from '../contract.js';
|
|||||||
import { createPickDelivery } from '../pickDelivery.js';
|
import { createPickDelivery } from '../pickDelivery.js';
|
||||||
import { toGeo2 } from './convert.js';
|
import { toGeo2 } from './convert.js';
|
||||||
|
|
||||||
|
const TYPES = {
|
||||||
|
click: Cesium.ScreenSpaceEventType.LEFT_CLICK,
|
||||||
|
doubleClick: Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK,
|
||||||
|
move: Cesium.ScreenSpaceEventType.MOUSE_MOVE,
|
||||||
|
down: Cesium.ScreenSpaceEventType.LEFT_DOWN,
|
||||||
|
up: Cesium.ScreenSpaceEventType.LEFT_UP,
|
||||||
|
};
|
||||||
|
const KEYS = {
|
||||||
|
ctrl: Cesium.KeyboardEventModifier.CTRL,
|
||||||
|
shift: Cesium.KeyboardEventModifier.SHIFT,
|
||||||
|
alt: Cesium.KeyboardEventModifier.ALT,
|
||||||
|
};
|
||||||
|
|
||||||
// Cesium reuses its event objects; listeners get geo copies.
|
// Cesium reuses its event objects; listeners get geo copies.
|
||||||
const toEvent = (event) => {
|
const toEvent = (event) => {
|
||||||
const result = {};
|
const result = {};
|
||||||
@@ -31,19 +44,6 @@ export function createCesiumInput(
|
|||||||
scheduleFrame = (run) => requestAnimationFrame(run),
|
scheduleFrame = (run) => requestAnimationFrame(run),
|
||||||
} = {},
|
} = {},
|
||||||
) {
|
) {
|
||||||
const TYPES = {
|
|
||||||
click: Cesium.ScreenSpaceEventType.LEFT_CLICK,
|
|
||||||
doubleClick: Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK,
|
|
||||||
move: Cesium.ScreenSpaceEventType.MOUSE_MOVE,
|
|
||||||
down: Cesium.ScreenSpaceEventType.LEFT_DOWN,
|
|
||||||
up: Cesium.ScreenSpaceEventType.LEFT_UP,
|
|
||||||
};
|
|
||||||
const KEYS = {
|
|
||||||
ctrl: Cesium.KeyboardEventModifier.CTRL,
|
|
||||||
shift: Cesium.KeyboardEventModifier.SHIFT,
|
|
||||||
alt: Cesium.KeyboardEventModifier.ALT,
|
|
||||||
};
|
|
||||||
|
|
||||||
const { scene } = viewer;
|
const { scene } = viewer;
|
||||||
let handler = null;
|
let handler = null;
|
||||||
let destroyed = false;
|
let destroyed = false;
|
||||||
|
|||||||
@@ -8,12 +8,12 @@
|
|||||||
import * as Cesium from 'cesium';
|
import * as Cesium from 'cesium';
|
||||||
import { createMoverRegistry } from '../movers.js';
|
import { createMoverRegistry } from '../movers.js';
|
||||||
|
|
||||||
let scratchPosition;
|
const scratchPosition = new Cesium.Cartesian3();
|
||||||
let scratchColor;
|
const scratchColor = new Cesium.Color();
|
||||||
let scratchQuaternion;
|
const scratchQuaternion = new Cesium.Quaternion();
|
||||||
let scratchRotation;
|
const scratchRotation = new Cesium.Matrix3();
|
||||||
// Model.modelMatrix and Model.color copy what they are given.
|
// Model.modelMatrix and Model.color copy what they are given.
|
||||||
let scratchModelMatrix;
|
const scratchModelMatrix = new Cesium.Matrix4();
|
||||||
|
|
||||||
/** The atlas cells as canvases, by key (a DOM canvas or image source). */
|
/** The atlas cells as canvases, by key (a DOM canvas or image source). */
|
||||||
async function cropAtlasCells(atlas, keys) {
|
async function cropAtlasCells(atlas, keys) {
|
||||||
@@ -287,11 +287,6 @@ export function createCesiumMovers(
|
|||||||
viewer,
|
viewer,
|
||||||
{ requestRender = () => viewer.scene.requestRender(), factories = {} } = {},
|
{ requestRender = () => viewer.scene.requestRender(), factories = {} } = {},
|
||||||
) {
|
) {
|
||||||
scratchPosition ??= new Cesium.Cartesian3();
|
|
||||||
scratchColor ??= new Cesium.Color();
|
|
||||||
scratchQuaternion ??= new Cesium.Quaternion();
|
|
||||||
scratchRotation ??= new Cesium.Matrix3();
|
|
||||||
scratchModelMatrix ??= new Cesium.Matrix4();
|
|
||||||
const make = { ...DEFAULT_FACTORIES, ...factories };
|
const make = { ...DEFAULT_FACTORIES, ...factories };
|
||||||
const { scene } = viewer;
|
const { scene } = viewer;
|
||||||
let root = null;
|
let root = null;
|
||||||
|
|||||||
@@ -68,11 +68,10 @@ export function presentRoutingFailure(error) {
|
|||||||
|
|
||||||
/** Route colour — the annotation palette's cyan, so voice routes and Directions match. */
|
/** Route colour — the annotation palette's cyan, so voice routes and Directions match. */
|
||||||
export const DIRECTIONS_ROUTE_COLOR = '#39d0ff';
|
export const DIRECTIONS_ROUTE_COLOR = '#39d0ff';
|
||||||
const MARKER_A_COLOR = () => Cesium.Color.fromCssColorString('#5dff9f');
|
const MARKER_A_COLOR = Cesium.Color.fromCssColorString('#5dff9f');
|
||||||
const MARKER_B_COLOR = () => Cesium.Color.fromCssColorString('#ff6b6b');
|
const MARKER_B_COLOR = Cesium.Color.fromCssColorString('#ff6b6b');
|
||||||
const STEP_COLOR = () => Cesium.Color.WHITE.withAlpha(0.95);
|
const STEP_COLOR = Cesium.Color.WHITE.withAlpha(0.95);
|
||||||
const STEP_OUTLINE = () =>
|
const STEP_OUTLINE = Cesium.Color.fromCssColorString(DIRECTIONS_ROUTE_COLOR);
|
||||||
Cesium.Color.fromCssColorString(DIRECTIONS_ROUTE_COLOR);
|
|
||||||
const STEP_PIXEL_SIZE = 8;
|
const STEP_PIXEL_SIZE = 8;
|
||||||
const STEP_SELECTED_PIXEL_SIZE = 13;
|
const STEP_SELECTED_PIXEL_SIZE = 13;
|
||||||
/** Route request timeout (ms) — the proxy itself gives OSRM 12 s. */
|
/** Route request timeout (ms) — the proxy itself gives OSRM 12 s. */
|
||||||
@@ -1027,10 +1026,10 @@ export function createDirectionsLayer({
|
|||||||
if (!_viewer && !_native) return;
|
if (!_viewer && !_native) return;
|
||||||
if (letter === 'a') {
|
if (letter === 'a') {
|
||||||
removeEntity(_markerA);
|
removeEntity(_markerA);
|
||||||
_markerA = markerEntity('A', point, MARKER_A_COLOR());
|
_markerA = markerEntity('A', point, MARKER_A_COLOR);
|
||||||
} else {
|
} else {
|
||||||
removeEntity(_markerB);
|
removeEntity(_markerB);
|
||||||
_markerB = markerEntity('B', point, MARKER_B_COLOR());
|
_markerB = markerEntity('B', point, MARKER_B_COLOR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1137,9 +1136,9 @@ export function createDirectionsLayer({
|
|||||||
_stepPoints.add({
|
_stepPoints.add({
|
||||||
id: `directions:step:${index}`,
|
id: `directions:step:${index}`,
|
||||||
position: Cesium.Cartesian3.fromDegrees(step.lon, step.lat, 0),
|
position: Cesium.Cartesian3.fromDegrees(step.lon, step.lat, 0),
|
||||||
color: STEP_COLOR(),
|
color: STEP_COLOR,
|
||||||
pixelSize: STEP_PIXEL_SIZE,
|
pixelSize: STEP_PIXEL_SIZE,
|
||||||
outlineColor: STEP_OUTLINE(),
|
outlineColor: STEP_OUTLINE,
|
||||||
outlineWidth: 2,
|
outlineWidth: 2,
|
||||||
show: false,
|
show: false,
|
||||||
// The shared ground floor is a coarse cell, and on the photoreal stack
|
// The shared ground floor is a coarse cell, and on the photoreal stack
|
||||||
|
|||||||
@@ -4,8 +4,7 @@ import {
|
|||||||
horizonOccluder,
|
horizonOccluder,
|
||||||
} from '../../../data/render/cesiumProjection.js';
|
} from '../../../data/render/cesiumProjection.js';
|
||||||
|
|
||||||
// Cesium ScreenSpaceEventType.LEFT_CLICK; available before the SDK loads.
|
export const FIRMS_LEFT_CLICK = Cesium.ScreenSpaceEventType.LEFT_CLICK;
|
||||||
export const FIRMS_LEFT_CLICK = 2;
|
|
||||||
export const projectFirmsWindow = worldToWindowCoordinates;
|
export const projectFirmsWindow = worldToWindowCoordinates;
|
||||||
export const firmsHorizonOccluder = horizonOccluder;
|
export const firmsHorizonOccluder = horizonOccluder;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,17 @@
|
|||||||
import * as Cesium from 'cesium';
|
import * as Cesium from 'cesium';
|
||||||
import { GNSS_LEVEL_COLORS } from '../records.js';
|
import { GNSS_LEVEL_COLORS } from '../records.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GroundPrimitive allowPicking:false suppresses ids but still submits stencil
|
||||||
|
* commands in Cesium's pick pass, erasing picks of overlapping ground geometry.
|
||||||
|
* This fill participates only in rendering, so sibling polygons remain pickable.
|
||||||
|
*/
|
||||||
|
class GnssGroundFill extends Cesium.GroundPrimitive {
|
||||||
|
update(frameState) {
|
||||||
|
if (!frameState.passes.pick) super.update(frameState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Degrees at the centre of the current view, or null before the camera settles. */
|
/** Degrees at the centre of the current view, or null before the camera settles. */
|
||||||
export function defaultGnssViewAnchor(viewer) {
|
export function defaultGnssViewAnchor(viewer) {
|
||||||
const canvas = viewer?.scene?.canvas;
|
const canvas = viewer?.scene?.canvas;
|
||||||
@@ -33,14 +44,6 @@ export function createGnssCesiumRenderer({
|
|||||||
viewer,
|
viewer,
|
||||||
viewAnchor = defaultGnssViewAnchor,
|
viewAnchor = defaultGnssViewAnchor,
|
||||||
}) {
|
}) {
|
||||||
// GroundPrimitive allowPicking:false still submits stencil commands in
|
|
||||||
// the pick pass. Keep this fill from erasing overlapping geometry's picks.
|
|
||||||
class GnssGroundFill extends Cesium.GroundPrimitive {
|
|
||||||
update(frameState) {
|
|
||||||
if (!frameState.passes.pick) super.update(frameState);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const primitives = new Cesium.PrimitiveCollection();
|
const primitives = new Cesium.PrimitiveCollection();
|
||||||
primitives.id = 'gnss-integrity';
|
primitives.id = 'gnss-integrity';
|
||||||
primitives.show = false;
|
primitives.show = false;
|
||||||
|
|||||||
@@ -227,7 +227,11 @@ export function viewFocus(
|
|||||||
* (NYC −22 m), and an occluder at 0 m would hide the cones around it.
|
* (NYC −22 m), and an occluder at 0 m would hide the cones around it.
|
||||||
*/
|
*/
|
||||||
const HORIZON_CULL_DEPTH_M = 1000;
|
const HORIZON_CULL_DEPTH_M = 1000;
|
||||||
let HORIZON_CULL_ELLIPSOID;
|
const HORIZON_CULL_ELLIPSOID = new Cesium.Ellipsoid(
|
||||||
|
Cesium.Ellipsoid.WGS84.radii.x - HORIZON_CULL_DEPTH_M,
|
||||||
|
Cesium.Ellipsoid.WGS84.radii.y - HORIZON_CULL_DEPTH_M,
|
||||||
|
Cesium.Ellipsoid.WGS84.radii.z - HORIZON_CULL_DEPTH_M,
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hide billboards and points behind the horizon: they skip the depth test, so
|
* Hide billboards and points behind the horizon: they skip the depth test, so
|
||||||
@@ -236,18 +240,12 @@ let HORIZON_CULL_ELLIPSOID;
|
|||||||
* @param {{getViewer: () => object|null, items: () => Iterable<{position: object, show: boolean}>, onChange?: () => void}} options
|
* @param {{getViewer: () => object|null, items: () => Iterable<{position: object, show: boolean}>, onChange?: () => void}} options
|
||||||
*/
|
*/
|
||||||
export function createHorizonCull({ getViewer, items, onChange }) {
|
export function createHorizonCull({ getViewer, items, onChange }) {
|
||||||
let occluder;
|
const occluder = new Cesium.EllipsoidalOccluder(HORIZON_CULL_ELLIPSOID);
|
||||||
let from = null;
|
let from = null;
|
||||||
let stopListening = null;
|
let stopListening = null;
|
||||||
|
|
||||||
/** Show what is in front of the horizon, hide the rest; the count seen. */
|
/** Show what is in front of the horizon, hide the rest; the count seen. */
|
||||||
function cull(list, position) {
|
function cull(list, position) {
|
||||||
HORIZON_CULL_ELLIPSOID ??= new Cesium.Ellipsoid(
|
|
||||||
Cesium.Ellipsoid.WGS84.radii.x - HORIZON_CULL_DEPTH_M,
|
|
||||||
Cesium.Ellipsoid.WGS84.radii.y - HORIZON_CULL_DEPTH_M,
|
|
||||||
Cesium.Ellipsoid.WGS84.radii.z - HORIZON_CULL_DEPTH_M,
|
|
||||||
);
|
|
||||||
occluder ??= new Cesium.EllipsoidalOccluder(HORIZON_CULL_ELLIPSOID);
|
|
||||||
occluder.cameraPosition = position;
|
occluder.cameraPosition = position;
|
||||||
let seen = 0;
|
let seen = 0;
|
||||||
let changed = false;
|
let changed = false;
|
||||||
|
|||||||
@@ -86,15 +86,11 @@ export const CABLE_GLOBE_STACK_IDS = Object.freeze(
|
|||||||
export const MARKER_COLLECTION_EXPECTATIONS = Object.freeze([
|
export const MARKER_COLLECTION_EXPECTATIONS = Object.freeze([
|
||||||
Object.freeze({
|
Object.freeze({
|
||||||
key: '_billboardCollection',
|
key: '_billboardCollection',
|
||||||
get type() {
|
type: Cesium.BillboardCollection,
|
||||||
return Cesium.BillboardCollection;
|
|
||||||
},
|
|
||||||
}),
|
}),
|
||||||
Object.freeze({
|
Object.freeze({
|
||||||
key: '_pointCollection',
|
key: '_pointCollection',
|
||||||
get type() {
|
type: Cesium.PointPrimitiveCollection,
|
||||||
return Cesium.PointPrimitiveCollection;
|
|
||||||
},
|
|
||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ export function createReticleFootprint() {
|
|||||||
const pixels = Array.from({ length: 25 }, () => geo.cartesian2.create());
|
const pixels = Array.from({ length: 25 }, () => geo.cartesian2.create());
|
||||||
const hits = Array.from({ length: 25 }, () => geo.cartesian3.create());
|
const hits = Array.from({ length: 25 }, () => geo.cartesian3.create());
|
||||||
const carto = geo.cartographic.create();
|
const carto = geo.cartographic.create();
|
||||||
let ray;
|
const ray = new Cesium.Ray();
|
||||||
return (viewer, altitude, engine) => {
|
return (viewer, altitude, engine) => {
|
||||||
const camera = engine?.camera ?? viewer?.camera;
|
const camera = engine?.camera ?? viewer?.camera;
|
||||||
if (!camera?.getPickRay && !camera?.pickRay) return null;
|
if (!camera?.getPickRay && !camera?.pickRay) return null;
|
||||||
@@ -91,9 +91,7 @@ export function createReticleFootprint() {
|
|||||||
p = pixels[i];
|
p = pixels[i];
|
||||||
p.x = left + (side * col) / 4;
|
p.x = left + (side * col) / 4;
|
||||||
p.y = top + (side * row) / 4;
|
p.y = top + (side * row) / 4;
|
||||||
const hit = engine
|
const hit = camera.pickEllipsoid(p, Cesium.Ellipsoid.WGS84, hits[i]);
|
||||||
? camera.pickEllipsoid(p)
|
|
||||||
: camera.pickEllipsoid(p, Cesium.Ellipsoid.WGS84, hits[i]);
|
|
||||||
let dx, dy;
|
let dx, dy;
|
||||||
if (hit) {
|
if (hit) {
|
||||||
geo.cartographic.fromCartesian(hit, geo.ellipsoid.WGS84, carto);
|
geo.cartographic.fromCartesian(hit, geo.ellipsoid.WGS84, carto);
|
||||||
@@ -104,7 +102,7 @@ export function createReticleFootprint() {
|
|||||||
} else {
|
} else {
|
||||||
const picked = engine
|
const picked = engine
|
||||||
? camera.pickRay(p)
|
? camera.pickRay(p)
|
||||||
: camera.getPickRay(p, (ray ??= new Cesium.Ray())) || ray;
|
: camera.getPickRay(p, ray) || ray;
|
||||||
if (!picked) continue;
|
if (!picked) continue;
|
||||||
const d = picked.direction;
|
const d = picked.direction;
|
||||||
dx =
|
dx =
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { rgbaFromCss } from '../shared/color.js';
|
import * as Cesium from 'cesium';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @file Street Traffic selects TomTom, OpenMapTiles or Hybrid motor roads,
|
* @file Street Traffic selects TomTom, OpenMapTiles or Hybrid motor roads,
|
||||||
@@ -112,9 +112,9 @@ export const SIZE_BY_TYPE = {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
export const FLOW_BUCKET_COLORS = {
|
export const FLOW_BUCKET_COLORS = {
|
||||||
free: rgbaFromCss('#2ecc71').withAlpha(0.9),
|
free: Cesium.Color.fromCssColorString('#2ecc71').withAlpha(0.9),
|
||||||
slow: rgbaFromCss('#f0b23e').withAlpha(0.9),
|
slow: Cesium.Color.fromCssColorString('#f0b23e').withAlpha(0.9),
|
||||||
jam: rgbaFromCss('#e05252').withAlpha(0.9),
|
jam: Cesium.Color.fromCssColorString('#e05252').withAlpha(0.9),
|
||||||
};
|
};
|
||||||
|
|
||||||
// ─── Jam-viz prototype (live mode only — see 2026-07-21 design doc) ────────
|
// ─── Jam-viz prototype (live mode only — see 2026-07-21 design doc) ────────
|
||||||
@@ -140,11 +140,12 @@ export const HEAT_JAM_PULSE_ALPHA = 0.2;
|
|||||||
|
|
||||||
/** @const {Cesium.Color} Jam corridor color (bucket red, alpha pulsed live). */
|
/** @const {Cesium.Color} Jam corridor color (bucket red, alpha pulsed live). */
|
||||||
|
|
||||||
export const HEAT_JAM_COLOR = rgbaFromCss('#e05252');
|
export const HEAT_JAM_COLOR = Cesium.Color.fromCssColorString('#e05252');
|
||||||
|
|
||||||
/** @const {Cesium.Color} Slow corridor color (bucket amber, faint + static). */
|
/** @const {Cesium.Color} Slow corridor color (bucket amber, faint + static). */
|
||||||
|
|
||||||
export const HEAT_SLOW_COLOR = rgbaFromCss('#f0b23e').withAlpha(0.2);
|
export const HEAT_SLOW_COLOR =
|
||||||
|
Cesium.Color.fromCssColorString('#f0b23e').withAlpha(0.2);
|
||||||
|
|
||||||
/** @const {number} Far-distance scale floor for jam dots (shipped: 0.3). */
|
/** @const {number} Far-distance scale floor for jam dots (shipped: 0.3). */
|
||||||
|
|
||||||
|
|||||||
@@ -12,10 +12,10 @@ export function roadIdentity(road) {
|
|||||||
/** Retain one road and its dot population across tile and surface publications. */
|
/** Retain one road and its dot population across tile and surface publications. */
|
||||||
export function createRetention({ state, parts }) {
|
export function createRetention({ state, parts }) {
|
||||||
const records = new Map();
|
const records = new Map();
|
||||||
const heightStep = { x: 0, y: 0, z: 0 };
|
const heightStep = new Cesium.Cartesian3();
|
||||||
const screenFrom = { x: 0, y: 0 };
|
const screenFrom = new Cesium.Cartesian2();
|
||||||
const screenTo = { x: 0, y: 0 };
|
const screenTo = new Cesium.Cartesian2();
|
||||||
const eye = { x: 0, y: 0, z: 0 };
|
const eye = new Cesium.Cartesian3();
|
||||||
function projectSafely(scene, point, screen) {
|
function projectSafely(scene, point, screen) {
|
||||||
if (scene.project) return Boolean(scene.project(point, screen));
|
if (scene.project) return Boolean(scene.project(point, screen));
|
||||||
if (scene.camera.viewMatrix) {
|
if (scene.camera.viewMatrix) {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { normalizeRoadMode } from './roadModes.js';
|
import { normalizeRoadMode } from './roadModes.js';
|
||||||
|
import * as Cesium from 'cesium';
|
||||||
import { FLOW_BUCKET_COLORS } from './policy.js';
|
import { FLOW_BUCKET_COLORS } from './policy.js';
|
||||||
|
|
||||||
export function createState({ services }) {
|
export function createState({ services }) {
|
||||||
@@ -293,7 +294,7 @@ export function createState({ services }) {
|
|||||||
|
|
||||||
/** Reusable scratch Cartesian3 to avoid per-frame allocation / GC pressure */
|
/** Reusable scratch Cartesian3 to avoid per-frame allocation / GC pressure */
|
||||||
|
|
||||||
layerState._scratchLerp = { x: 0, y: 0, z: 0 };
|
layerState._scratchLerp = new Cesium.Cartesian3();
|
||||||
|
|
||||||
// ─── Animation ─────────────────────────────────────────────
|
// ─── Animation ─────────────────────────────────────────────
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -1,4 +1,4 @@
|
|||||||
// Ion world imagery asset IDs; the catalog is available before the SDK loads.
|
import * as Cesium from 'cesium';
|
||||||
export const MAP_STACKS = [
|
export const MAP_STACKS = [
|
||||||
{
|
{
|
||||||
id: 'photoreal',
|
id: 'photoreal',
|
||||||
@@ -12,7 +12,7 @@ export const MAP_STACKS = [
|
|||||||
label: 'Bing Aerial', // i18n-ignore: imagery product name
|
label: 'Bing Aerial', // i18n-ignore: imagery product name
|
||||||
shortLabel: 'Aerial',
|
shortLabel: 'Aerial',
|
||||||
kind: 'ion',
|
kind: 'ion',
|
||||||
style: 2,
|
style: Cesium.IonWorldImageryStyle.AERIAL,
|
||||||
requiresIon: true,
|
requiresIon: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -20,7 +20,7 @@ export const MAP_STACKS = [
|
|||||||
label: 'Bing Labels', // i18n-ignore: imagery product name
|
label: 'Bing Labels', // i18n-ignore: imagery product name
|
||||||
shortLabel: 'Labels',
|
shortLabel: 'Labels',
|
||||||
kind: 'ion',
|
kind: 'ion',
|
||||||
style: 3,
|
style: Cesium.IonWorldImageryStyle.AERIAL_WITH_LABELS,
|
||||||
requiresIon: true,
|
requiresIon: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in new issue
Block a user