mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 02:44:02 +00:00
refactor: own application request operations and surface caches
This commit is contained in:
1 parent
310809e8f1
commit
ac977bd8bc
53 files changed
+4388
-3317
No files matched your search
@@ -47,6 +47,7 @@ const SOURCE_METHODS = Object.freeze({
|
||||
* The manager owns layer destruction, while abort releases classification even if startup fails.
|
||||
*/
|
||||
export function createApplicationCatalog({
|
||||
surface,
|
||||
sources,
|
||||
signal,
|
||||
metadata = LAYER_STATE_REGISTRY,
|
||||
@@ -56,6 +57,9 @@ export function createApplicationCatalog({
|
||||
if (!signal?.addEventListener)
|
||||
throw new TypeError('An application lifetime signal is required');
|
||||
signal.throwIfAborted();
|
||||
if (!surface?.groundFloor || !surface?.terrain)
|
||||
throw new TypeError('Application surface services are required');
|
||||
|
||||
for (const [name, methods] of Object.entries(SOURCE_METHODS)) {
|
||||
if (
|
||||
methods.some((method) => typeof sources?.[name]?.[method] !== 'function')
|
||||
@@ -71,11 +75,13 @@ export function createApplicationCatalog({
|
||||
try {
|
||||
militaryRegistry.configureSource(sources.military, { signal });
|
||||
const flights = createApplicationFlights({
|
||||
surface,
|
||||
source: sources.flights,
|
||||
militaryRegistry,
|
||||
resolveAsset,
|
||||
});
|
||||
const military = createApplicationMilitary({
|
||||
surface,
|
||||
source: sources.military,
|
||||
militaryRegistry,
|
||||
resolveAsset,
|
||||
@@ -85,6 +91,7 @@ export function createApplicationCatalog({
|
||||
options: vesselOptions,
|
||||
});
|
||||
const installations = createApplicationInstallations({
|
||||
surface,
|
||||
source: sources.installations,
|
||||
});
|
||||
const satellites = createApplicationSatellites({
|
||||
@@ -95,12 +102,12 @@ export function createApplicationCatalog({
|
||||
flights,
|
||||
military,
|
||||
createApplicationEarthquakes({ source: sources.earthquakes }),
|
||||
createApplicationAlpr({ source: sources.alpr }),
|
||||
createApplicationAlpr({ surface, source: sources.alpr }),
|
||||
satellites,
|
||||
createApplicationLaunches({ source: sources.launches, satellites }),
|
||||
createApplicationTraffic({ source: sources.traffic }),
|
||||
createApplicationCctv({ source: sources.cctv }),
|
||||
createApplicationRadio({ source: sources.radio }),
|
||||
createApplicationCctv({ surface, source: sources.cctv }),
|
||||
createApplicationRadio({ surface, source: sources.radio }),
|
||||
createApplicationBikeshare({ source: sources.bikeshare }),
|
||||
vessels,
|
||||
installations,
|
||||
@@ -113,6 +120,7 @@ export function createApplicationCatalog({
|
||||
...createInfrastructureLayers(localGeoJsonServices),
|
||||
createApplicationCables({ source: sources.cables }),
|
||||
createApplicationFirms({
|
||||
surface,
|
||||
id: 'local-firms',
|
||||
name: 'FIRMS Active Fires',
|
||||
icon: '▲',
|
||||
@@ -122,7 +130,7 @@ export function createApplicationCatalog({
|
||||
],
|
||||
metadata,
|
||||
);
|
||||
return Object.freeze({ ...catalog, militaryRegistry });
|
||||
return Object.freeze({ ...catalog, militaryRegistry, surface });
|
||||
} catch (error) {
|
||||
dispose();
|
||||
throw error;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { createSurfaceServices } from './surfaceServices.js';
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { createApplicationCatalog } from './constructCatalog.js';
|
||||
@@ -30,10 +31,12 @@ test('catalogs construct distinct layers and classification from their supplied
|
||||
const first = createApplicationCatalog({
|
||||
sources: fixtureSources(['abc123'], callsA),
|
||||
signal: a.signal,
|
||||
surface: fixtureSurface(a.signal),
|
||||
});
|
||||
const second = createApplicationCatalog({
|
||||
sources: fixtureSources(['def456'], callsB),
|
||||
signal: b.signal,
|
||||
surface: fixtureSurface(b.signal),
|
||||
});
|
||||
assert.equal(first.layers.length, 17);
|
||||
assert.deepEqual(
|
||||
@@ -62,7 +65,12 @@ test('catalogs construct distinct layers and classification from their supplied
|
||||
test('invalid or already cancelled construction fails before classification can acquire', () => {
|
||||
const lifetime = new AbortController();
|
||||
assert.throws(
|
||||
() => createApplicationCatalog({ sources: {}, signal: lifetime.signal }),
|
||||
() =>
|
||||
createApplicationCatalog({
|
||||
sources: {},
|
||||
signal: lifetime.signal,
|
||||
surface: fixtureSurface(lifetime.signal),
|
||||
}),
|
||||
/catalog source/,
|
||||
);
|
||||
lifetime.abort();
|
||||
@@ -75,3 +83,11 @@ test('invalid or already cancelled construction fails before classification can
|
||||
{ name: 'AbortError' },
|
||||
);
|
||||
});
|
||||
|
||||
function fixtureSurface(signal) {
|
||||
return createSurfaceServices({
|
||||
terrainSource: { getHeights: async () => [] },
|
||||
signal,
|
||||
eventTarget: null,
|
||||
});
|
||||
}
|
||||
Vendored
+13
-3
@@ -5,7 +5,7 @@ import { initCockpitCloudEffects } from '../cockpitCloudEffects.js';
|
||||
|
||||
/** Construct the existing controls and camera presentation. */
|
||||
export function createApplicationControls({
|
||||
scene: { viewer, mapStackController },
|
||||
scene: { viewer, mapStackController, operations },
|
||||
loaderStatus,
|
||||
Controls = StyleManager,
|
||||
services,
|
||||
@@ -15,7 +15,15 @@ export function createApplicationControls({
|
||||
}) {
|
||||
// Initialize the style manager (post-processing, HUD, locations, share links)
|
||||
const styleManager = new Controls(viewer, {
|
||||
services: { ...services, ...catalogControlServices(catalog) },
|
||||
services: {
|
||||
...services,
|
||||
...operations.surface.controlServices,
|
||||
searchAndFlyTo: operations.searchAndFlyTo,
|
||||
fetchRegionalBrief: (...args) =>
|
||||
operations.requests.regional.getBrief(...args),
|
||||
...catalogControlServices(catalog),
|
||||
},
|
||||
requestServices: operations.requests,
|
||||
mapStackController,
|
||||
placeSearch,
|
||||
});
|
||||
@@ -26,7 +34,9 @@ export function createApplicationControls({
|
||||
// clouds use a separate, capped low-resolution GPU pass that never attaches
|
||||
// Cesium fog or post-process stages and is fully stopped in map mode.
|
||||
const weatherEffects = null;
|
||||
const cockpitCloudEffects = initCockpitCloudEffects(viewer);
|
||||
const cockpitCloudEffects = initCockpitCloudEffects(viewer, {
|
||||
weatherService: operations.requests.weather,
|
||||
});
|
||||
defer(() => cockpitCloudEffects?.destroy());
|
||||
|
||||
// If no share link state, do default fly-to Austin
|
||||
|
||||
@@ -2,10 +2,10 @@ import { createAlprCamerasLayer } from '../../layers/alpr/index.js';
|
||||
import * as render from '../../renderGovernor.js';
|
||||
import * as context from '../../data/contextStore.js';
|
||||
import * as picking from '../../data/pickRegistry.js';
|
||||
import * as groundFloor from '../../data/groundFloor.js';
|
||||
|
||||
/** Construct one layer using the application scene owners and a supplied source. */
|
||||
export function createApplicationAlpr({ source }) {
|
||||
export function createApplicationAlpr({ surface, source }) {
|
||||
const { groundFloor } = surface;
|
||||
return createAlprCamerasLayer({
|
||||
source,
|
||||
services: { render, context, picking, groundFloor },
|
||||
|
||||
@@ -4,14 +4,12 @@ import * as activation from '../../cctvFocusRequest.js';
|
||||
import * as overlays from '../../overlays/worldOverlay.js';
|
||||
import * as locations from '../../locations.js';
|
||||
import * as picking from '../../data/pickRegistry.js';
|
||||
import * as terrain from '../../data/terrainHeights.js';
|
||||
import * as ground from '../../data/groundFloor.js';
|
||||
import * as mesh from '../../data/meshFloorSampler.js';
|
||||
import * as focus from '../../data/focusDeemphasis.js';
|
||||
import * as render from '../../renderGovernor.js';
|
||||
|
||||
/** Construct one layer using the application scene owners and a supplied source. */
|
||||
export function createApplicationCctv({ source }) {
|
||||
export function createApplicationCctv({ surface, source }) {
|
||||
const { terrain, groundFloor: ground, meshFloor: mesh } = surface;
|
||||
return createCctvLayer({
|
||||
source,
|
||||
services: {
|
||||
|
||||
@@ -4,7 +4,6 @@ import * as render from '../../renderGovernor.js';
|
||||
import * as sprites from '../../data/spriteOrder.js';
|
||||
import * as context from '../../data/contextStore.js';
|
||||
import * as picking from '../../data/pickRegistry.js';
|
||||
import * as anchors from '../../data/fireAnchors.js';
|
||||
import * as overlays from '../../overlays/worldOverlay.js';
|
||||
import * as focus from '../../worldFocus.js';
|
||||
export const firmsServices = {
|
||||
@@ -12,19 +11,18 @@ export const firmsServices = {
|
||||
sprites,
|
||||
context,
|
||||
picking,
|
||||
anchors,
|
||||
overlays,
|
||||
focus,
|
||||
};
|
||||
|
||||
/** Bind a supplied fire feed to the application scene service owners. */
|
||||
export function createApplicationFirms(options) {
|
||||
export function createApplicationFirms({ surface, ...options }) {
|
||||
return createLayer({
|
||||
...options,
|
||||
icon: options.icon ?? '▲',
|
||||
source: options.source ?? 'NASA FIRMS',
|
||||
feed: options.feed,
|
||||
services: firmsServices,
|
||||
services: { ...firmsServices, anchors: surface.anchors },
|
||||
overlayHost: options.overlayHost ?? {
|
||||
setEntries: overlays.setOverlayEntries,
|
||||
setVisible: overlays.setOverlaySourceVisible,
|
||||
|
||||
@@ -5,23 +5,22 @@ import * as trails from '../../data/trailRenderer.js';
|
||||
import * as aircraftPresentation from '../../data/tr3bRegistry.js';
|
||||
import * as camera from '../../data/trackedCamera.js';
|
||||
import * as labels from '../../data/detectionDraw.js';
|
||||
import * as groundFloor from '../../data/groundFloor.js';
|
||||
import * as meshFloor from '../../data/meshFloorSampler.js';
|
||||
import * as geoid from '../../data/geoid.js';
|
||||
import * as focus from '../../data/focusDeemphasis.js';
|
||||
import * as readout from '../../data/trackedReadout.js';
|
||||
import * as context from '../../data/contextStore.js';
|
||||
import * as render from '../../renderGovernor.js';
|
||||
import * as groundSnap from '../../data/groundSnap.js';
|
||||
import * as recession from '../../data/aircraftRecession.js';
|
||||
|
||||
/** Construct one layer using the application scene owners and a supplied source. */
|
||||
export function createApplicationFlights({
|
||||
surface,
|
||||
source,
|
||||
militaryRegistry,
|
||||
resolveAsset = (url) =>
|
||||
`${import.meta.env?.BASE_URL || '/'}${url.replace(/^\//, '')}`,
|
||||
}) {
|
||||
const { groundFloor, meshFloor, groundSnap } = surface;
|
||||
return createCivilFlightLayer({
|
||||
source,
|
||||
resolveAsset,
|
||||
|
||||
@@ -5,23 +5,22 @@ import * as trails from '../../data/trailRenderer.js';
|
||||
import * as aircraftPresentation from '../../data/tr3bRegistry.js';
|
||||
import * as camera from '../../data/trackedCamera.js';
|
||||
import * as labels from '../../data/detectionDraw.js';
|
||||
import * as groundFloor from '../../data/groundFloor.js';
|
||||
import * as meshFloor from '../../data/meshFloorSampler.js';
|
||||
import * as geoid from '../../data/geoid.js';
|
||||
import * as focus from '../../data/focusDeemphasis.js';
|
||||
import * as readout from '../../data/trackedReadout.js';
|
||||
import * as context from '../../data/contextStore.js';
|
||||
import * as render from '../../renderGovernor.js';
|
||||
import * as groundSnap from '../../data/groundSnap.js';
|
||||
import * as recession from '../../data/aircraftRecession.js';
|
||||
|
||||
/** Construct one layer using the application scene owners and a supplied source. */
|
||||
export function createApplicationMilitary({
|
||||
surface,
|
||||
source,
|
||||
militaryRegistry,
|
||||
resolveAsset = (url) =>
|
||||
`${import.meta.env?.BASE_URL || '/'}${url.replace(/^\//, '')}`,
|
||||
}) {
|
||||
const { groundFloor, meshFloor, groundSnap } = surface;
|
||||
return createMilitaryFlightLayer({
|
||||
source,
|
||||
resolveAsset,
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { createInstallationsLayer } from '../../layers/installations/index.js';
|
||||
import * as render from '../../renderGovernor.js';
|
||||
import * as context from '../../data/contextStore.js';
|
||||
import * as ground from '../../data/groundFloor.js';
|
||||
import * as anchors from '../../data/fireAnchors.js';
|
||||
import * as picking from '../../data/pickRegistry.js';
|
||||
|
||||
/** Construct one layer using the application scene owners and a supplied source. */
|
||||
export function createApplicationInstallations({ source }) {
|
||||
export function createApplicationInstallations({ surface, source }) {
|
||||
const { groundFloor: ground, anchors } = surface;
|
||||
return createInstallationsLayer({
|
||||
source,
|
||||
services: { render, context, ground, anchors, picking },
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { createRadioLayer } from '../../layers/radio/index.js';
|
||||
import * as ground from '../../data/groundFloor.js';
|
||||
import * as picking from '../../data/pickRegistry.js';
|
||||
import * as overlays from '../../overlays/worldOverlay.js';
|
||||
import * as globe from '../../celestialRing.js';
|
||||
import * as render from '../../renderGovernor.js';
|
||||
|
||||
/** Construct one layer using the application scene owners and a supplied source. */
|
||||
export function createApplicationRadio({ source }) {
|
||||
export function createApplicationRadio({ surface, source }) {
|
||||
const { groundFloor: ground } = surface;
|
||||
return createRadioLayer({
|
||||
source,
|
||||
services: { ground, picking, overlays, globe, render },
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
import { createSurfaceServices } from './surfaceServices.js';
|
||||
import { createAnnotationResolver } from '../annotations/resolver.js';
|
||||
import { searchAndFlyTo } from '../locations.js';
|
||||
|
||||
/** Assemble application operations from the caller's request services. */
|
||||
export function createApplicationOperations({ requests, signal, eventTarget }) {
|
||||
for (const [name, method] of Object.entries({
|
||||
boundaries: 'query',
|
||||
terrain: 'getHeights',
|
||||
regional: 'getBrief',
|
||||
weather: 'getConditions',
|
||||
summary: 'summarize',
|
||||
})) {
|
||||
if (typeof requests?.[name]?.[method] !== 'function')
|
||||
throw new TypeError(`Missing application request service: ${name}`);
|
||||
}
|
||||
const surface = createSurfaceServices({
|
||||
terrainSource: requests.terrain,
|
||||
signal,
|
||||
eventTarget,
|
||||
});
|
||||
const annotationResolver = createAnnotationResolver({
|
||||
boundarySource: requests.boundaries,
|
||||
signal,
|
||||
});
|
||||
return Object.freeze({
|
||||
requests,
|
||||
surface,
|
||||
annotationResolver,
|
||||
searchAndFlyTo: (viewer, query, options = {}) =>
|
||||
searchAndFlyTo(viewer, query, {
|
||||
...options,
|
||||
boundaries: requests.boundaries,
|
||||
recoverNearView: annotationResolver.placesNearViewRecovery,
|
||||
}),
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { createApplicationOperations } from './operations.js';
|
||||
|
||||
function requests(terrain, boundaries = { query: async () => [] }) {
|
||||
return {
|
||||
terrain,
|
||||
boundaries,
|
||||
regional: { getBrief: async () => ({}) },
|
||||
weather: { getConditions: async () => ({}) },
|
||||
summary: { summarize: async () => ({}) },
|
||||
};
|
||||
}
|
||||
|
||||
test('surface cache and stack listeners belong to the supplied application lifetime', async (t) => {
|
||||
const a = new AbortController();
|
||||
const b = new AbortController();
|
||||
t.after(() => {
|
||||
a.abort();
|
||||
b.abort();
|
||||
});
|
||||
const target = new EventTarget();
|
||||
let calls = 0;
|
||||
const first = createApplicationOperations({
|
||||
signal: a.signal,
|
||||
eventTarget: target,
|
||||
requests: requests({
|
||||
async getHeights(points) {
|
||||
calls++;
|
||||
return points.map(() => ({ ellipsoid: 123 }));
|
||||
},
|
||||
}),
|
||||
});
|
||||
const second = createApplicationOperations({
|
||||
signal: b.signal,
|
||||
eventTarget: target,
|
||||
requests: requests({
|
||||
async getHeights(points) {
|
||||
return points.map(() => ({ ellipsoid: 456 }));
|
||||
},
|
||||
}),
|
||||
});
|
||||
const point = { lat: 30, lon: -97 };
|
||||
await first.surface.terrain.resolveEllipsoidalGround([point]);
|
||||
await first.surface.terrain.resolveEllipsoidalGround([point]);
|
||||
await second.surface.terrain.resolveEllipsoidalGround([point]);
|
||||
assert.equal(calls, 1);
|
||||
assert.equal(first.surface.groundFloor.cachedGroundFloor(30, -97), 123);
|
||||
assert.equal(second.surface.groundFloor.cachedGroundFloor(30, -97), 456);
|
||||
target.dispatchEvent(
|
||||
new CustomEvent('gev:map-stack-changed', {
|
||||
detail: { activeId: 'esri-imagery' },
|
||||
}),
|
||||
);
|
||||
assert.equal(first.surface.groundFloor.meshFloorPreferred(), false);
|
||||
a.abort();
|
||||
assert.equal(first.surface.terrain.cachedEllipsoidalGround(30, -97), null);
|
||||
target.dispatchEvent(
|
||||
new CustomEvent('gev:map-stack-changed', {
|
||||
detail: { activeId: 'photoreal' },
|
||||
}),
|
||||
);
|
||||
assert.equal(
|
||||
first.surface.groundFloor.meshFloorPreferred(),
|
||||
false,
|
||||
'disposed listener cannot update the old owner',
|
||||
);
|
||||
assert.equal(second.surface.groundFloor.meshFloorPreferred(), true);
|
||||
});
|
||||
|
||||
test('a terrain reply after application abort cannot refill the cache or become a fallback', async () => {
|
||||
const lifetime = new AbortController();
|
||||
let respond;
|
||||
let receivedSignal;
|
||||
const operations = createApplicationOperations({
|
||||
signal: lifetime.signal,
|
||||
eventTarget: null,
|
||||
requests: requests({
|
||||
getHeights(_points, { signal }) {
|
||||
receivedSignal = signal;
|
||||
return new Promise((resolve) => {
|
||||
respond = resolve;
|
||||
});
|
||||
},
|
||||
}),
|
||||
});
|
||||
const pending = operations.surface.terrain.resolveEllipsoidalGround([
|
||||
{ lat: 30, lon: -97 },
|
||||
]);
|
||||
lifetime.abort();
|
||||
respond([{ ellipsoid: 123 }]);
|
||||
await assert.rejects(pending, { name: 'AbortError' });
|
||||
assert.equal(receivedSignal.aborted, true);
|
||||
assert.equal(
|
||||
operations.surface.terrain.cachedEllipsoidalGround(30, -97),
|
||||
null,
|
||||
);
|
||||
});
|
||||
|
||||
test('annotation lookup and cached outlines use the supplied source independently', async (t) => {
|
||||
const priorWindow = globalThis.window;
|
||||
globalThis.window = { setTimeout, clearTimeout };
|
||||
const a = new AbortController();
|
||||
const b = new AbortController();
|
||||
t.after(() => {
|
||||
a.abort();
|
||||
b.abort();
|
||||
if (priorWindow === undefined) delete globalThis.window;
|
||||
else globalThis.window = priorWindow;
|
||||
});
|
||||
const calls = [0, 0];
|
||||
const make = (signal, index) =>
|
||||
createApplicationOperations({
|
||||
signal,
|
||||
eventTarget: null,
|
||||
requests: requests(
|
||||
{ getHeights: async () => [] },
|
||||
{
|
||||
query: async () => {
|
||||
calls[index]++;
|
||||
const delta = index * 0.0001;
|
||||
return [
|
||||
{
|
||||
type: 'way',
|
||||
id: index + 1,
|
||||
tags: { building: 'yes', name: 'Source fixture hall' },
|
||||
geometry: [
|
||||
{ lat: 30 - 0.0001, lon: -97 - 0.0001 + delta },
|
||||
{ lat: 30 - 0.0001, lon: -97 + 0.0001 + delta },
|
||||
{ lat: 30 + 0.0001, lon: -97 + 0.0001 + delta },
|
||||
{ lat: 30 + 0.0001, lon: -97 - 0.0001 + delta },
|
||||
{ lat: 30 - 0.0001, lon: -97 - 0.0001 + delta },
|
||||
],
|
||||
},
|
||||
];
|
||||
},
|
||||
},
|
||||
),
|
||||
});
|
||||
const first = make(a.signal, 0);
|
||||
const second = make(b.signal, 1);
|
||||
const query = {
|
||||
viewer: {},
|
||||
target: 'Source fixture hall',
|
||||
latitude: 30,
|
||||
longitude: -97,
|
||||
footprint: true,
|
||||
entityKind: 'building',
|
||||
};
|
||||
const resultA = await first.annotationResolver.resolveAnnotationTarget(query);
|
||||
const resultB =
|
||||
await second.annotationResolver.resolveAnnotationTarget(query);
|
||||
assert.ok(resultA.ring?.length >= 4);
|
||||
assert.ok(resultB.ring?.length >= 4);
|
||||
assert.notDeepEqual(resultA.ring, resultB.ring);
|
||||
const before = calls[0];
|
||||
const cached = await first.annotationResolver.resolveAnnotationTarget(query);
|
||||
assert.deepEqual(cached.ring, resultA.ring);
|
||||
assert.equal(calls[0], before);
|
||||
a.abort();
|
||||
await assert.rejects(
|
||||
first.annotationResolver.resolveAnnotationTarget(query),
|
||||
{ name: 'AbortError' },
|
||||
);
|
||||
});
|
||||
+7
-1
@@ -1,3 +1,4 @@
|
||||
import { createApplicationOperations } from './operations.js';
|
||||
import * as Cesium from 'cesium';
|
||||
import { createApplicationViewer } from '../app/viewer.js';
|
||||
import { registerDataCredits } from '../data/dataCredits.js';
|
||||
@@ -13,6 +14,7 @@ import { describeError } from './errors.js';
|
||||
|
||||
/** Construct the application globe using the caller's local configuration. */
|
||||
export async function createApplicationScene({
|
||||
requestServices,
|
||||
googleApiKey,
|
||||
cesiumToken,
|
||||
credits,
|
||||
@@ -22,6 +24,10 @@ export async function createApplicationScene({
|
||||
signal,
|
||||
defer,
|
||||
}) {
|
||||
const operations = createApplicationOperations({
|
||||
requests: requestServices,
|
||||
signal,
|
||||
});
|
||||
defer(initLogoGaze());
|
||||
const previousKey = window.__GOOGLE_MAPS_API_KEY__;
|
||||
if (googleApiKey) {
|
||||
@@ -109,5 +115,5 @@ export async function createApplicationScene({
|
||||
});
|
||||
|
||||
signal.throwIfAborted();
|
||||
return { viewer, tileset, mapStackController };
|
||||
return { viewer, tileset, mapStackController, operations };
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import { createTerrainHeights } from '../services/terrainHeights.js';
|
||||
import { createGroundFloor } from '../services/groundFloor.js';
|
||||
import { createMeshFloorSampler } from '../services/meshFloorSampler.js';
|
||||
import { createGroundSnap } from '../services/groundSnap.js';
|
||||
import { createFireAnchors } from '../layers/firms/anchors.js';
|
||||
|
||||
/** Own the DEM, coarse floors and mesh samples used by one application. */
|
||||
export function createSurfaceServices({
|
||||
terrainSource,
|
||||
signal,
|
||||
eventTarget = globalThis.window,
|
||||
}) {
|
||||
const terrain = createTerrainHeights({ source: terrainSource, signal });
|
||||
const groundFloor = createGroundFloor({ terrain, signal });
|
||||
const meshFloor = createMeshFloorSampler({
|
||||
groundFloor,
|
||||
signal,
|
||||
eventTarget,
|
||||
});
|
||||
return Object.freeze({
|
||||
terrain,
|
||||
groundFloor,
|
||||
meshFloor,
|
||||
groundSnap: Object.freeze({
|
||||
createGroundSnap: () => createGroundSnap({ groundFloor }),
|
||||
}),
|
||||
anchors: createFireAnchors(groundFloor),
|
||||
controlServices: Object.freeze({
|
||||
cachedGroundFloor: groundFloor.cachedGroundFloor,
|
||||
cachedMeshFloor: groundFloor.cachedMeshFloor,
|
||||
GROUND_FLOOR_LIFT_M: groundFloor.GROUND_FLOOR_LIFT_M,
|
||||
meshFloorPreferred: groundFloor.meshFloorPreferred,
|
||||
warmGroundFloor: groundFloor.warmGroundFloor,
|
||||
sampleMeshFloorCells: meshFloor.sampleMeshFloorCells,
|
||||
}),
|
||||
});
|
||||
}
|
||||
+11
-2
@@ -23,13 +23,18 @@ export function createApplicationTools({
|
||||
signal,
|
||||
defer,
|
||||
}) {
|
||||
const { viewer, tileset, mapStackController } = scene;
|
||||
const { viewer, tileset, mapStackController, operations } = scene;
|
||||
const { styleManager, weatherEffects, cockpitCloudEffects } = controls;
|
||||
const { dataManager } = data;
|
||||
const sceneDirector = new SceneDirector(viewer, styleManager, dataManager);
|
||||
defer(() => sceneDirector.destroy());
|
||||
onSceneDirector?.(sceneDirector);
|
||||
const annotations = initAnnotations({ viewer, tileset, placeSearch });
|
||||
const annotations = initAnnotations({
|
||||
viewer,
|
||||
tileset,
|
||||
placeSearch,
|
||||
resolver: operations.annotationResolver,
|
||||
});
|
||||
defer(() => {
|
||||
if (window.__gevAnnotations === annotations) delete window.__gevAnnotations;
|
||||
annotations.destroy();
|
||||
@@ -95,6 +100,7 @@ export function createApplicationTools({
|
||||
weatherEffects,
|
||||
cockpitCloudEffects,
|
||||
getRenderGovernorDiagnostics,
|
||||
surfaceServices: operations.surface,
|
||||
requestRender: governorRequestRender,
|
||||
};
|
||||
const debug = window.__godsEyeView;
|
||||
@@ -103,6 +109,9 @@ export function createApplicationTools({
|
||||
});
|
||||
const voiceCommands = initGevVoiceCommands({
|
||||
...voice,
|
||||
floorServices: operations.surface.groundFloor,
|
||||
annotationResolver: operations.annotationResolver,
|
||||
searchNavigation: operations.searchAndFlyTo,
|
||||
signal,
|
||||
placeSearch,
|
||||
viewer,
|
||||
|
||||
Reference in new issue
Block a user