mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-12 06:12:18 +00:00
Fly the director, annotations, voice framing and local GeoJSON through the camera port
The scene director's shot flights, start pose and stops, the annotation framings and fly-to, the voice overhead framing and the local GeoJSON click flight now drive the renderer's camera port. The director's stops look the camera up with findCamera: teardown can run after the viewer is gone, and then there is no flight to stop. The local GeoJSON flight, part of the public infrastructure export, works on a plain Cesium viewer through the unbound camera, and looks it up before taking its input hold. Voice zoom stays for the move slice.
This commit is contained in:
1 parent
0b1c5d0f23
commit
bc69e8a4ee
8 files changed
+125
-73
No files matched your search
@@ -8,12 +8,23 @@
|
|||||||
"modules": [
|
"modules": [
|
||||||
"src/data/infrastructure.js",
|
"src/data/infrastructure.js",
|
||||||
"src/data/localGeojsonCore.js",
|
"src/data/localGeojsonCore.js",
|
||||||
|
"src/render/cesium/camera.js",
|
||||||
"src/data/localGeojsonLod.js",
|
"src/data/localGeojsonLod.js",
|
||||||
"src/data/inputOwnership.js",
|
"src/data/inputOwnership.js",
|
||||||
"src/data/pickRegistry.js",
|
"src/data/pickRegistry.js",
|
||||||
"src/data/scenePick.js",
|
"src/data/scenePick.js",
|
||||||
"src/input/dispatcher.js",
|
"src/input/dispatcher.js",
|
||||||
"src/render/cesium/cameraInput.js",
|
"src/render/cesium/cameraInput.js",
|
||||||
|
"src/render/camera/events.js",
|
||||||
|
"src/geo/index.js",
|
||||||
|
"src/geo/celestial.js",
|
||||||
|
"src/geo/quaternion.js",
|
||||||
|
"src/geo/frames.js",
|
||||||
|
"src/geo/ellipsoid.js",
|
||||||
|
"src/geo/vector.js",
|
||||||
|
"src/render/rendererOf.js",
|
||||||
|
"src/render/cesium/common.js",
|
||||||
|
"src/render/cesium/internals.js",
|
||||||
"src/render/cesium/input.js",
|
"src/render/cesium/input.js",
|
||||||
"src/render/cesium/ctrlWheelZoom.js",
|
"src/render/cesium/ctrlWheelZoom.js",
|
||||||
"src/render/input/router.js",
|
"src/render/input/router.js",
|
||||||
@@ -1242,6 +1253,17 @@
|
|||||||
"src/data/bhoteKoshiFloodPath.js",
|
"src/data/bhoteKoshiFloodPath.js",
|
||||||
"src/maps/catalog.js",
|
"src/maps/catalog.js",
|
||||||
"src/scenes/director.js",
|
"src/scenes/director.js",
|
||||||
|
"src/render/cesium/camera.js",
|
||||||
|
"src/geo/index.js",
|
||||||
|
"src/render/rendererOf.js",
|
||||||
|
"src/render/camera/events.js",
|
||||||
|
"src/geo/celestial.js",
|
||||||
|
"src/geo/quaternion.js",
|
||||||
|
"src/geo/frames.js",
|
||||||
|
"src/geo/ellipsoid.js",
|
||||||
|
"src/geo/vector.js",
|
||||||
|
"src/render/cesium/internals.js",
|
||||||
|
"src/render/cesium/common.js",
|
||||||
"src/scenes/sceneSaveError.js",
|
"src/scenes/sceneSaveError.js",
|
||||||
"src/scenes/playbackAdapter.js",
|
"src/scenes/playbackAdapter.js",
|
||||||
"src/director/playback.js",
|
"src/director/playback.js",
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { isUnavailableCapability } from '../sources/capability.js';
|
import { isUnavailableCapability } from '../sources/capability.js';
|
||||||
import { defaultGeospatial } from '../search/defaults.js';
|
import { defaultGeospatial } from '../search/defaults.js';
|
||||||
import * as Cesium from 'cesium';
|
import * as Cesium from 'cesium';
|
||||||
|
import { cameraOf } from '../render/cesium/camera.js';
|
||||||
import { greatCircleMeters } from '../geoDistance.js';
|
import { greatCircleMeters } from '../geoDistance.js';
|
||||||
import {
|
import {
|
||||||
holdContinuousRender,
|
holdContinuousRender,
|
||||||
@@ -1700,14 +1701,18 @@ export function createAnnotationEngine({
|
|||||||
Cesium.Cartesian3.fromDegrees(p.lon, p.lat, p.height || 0),
|
Cesium.Cartesian3.fromDegrees(p.lon, p.lat, p.height || 0),
|
||||||
);
|
);
|
||||||
const sphere = Cesium.BoundingSphere.fromPoints(cart);
|
const sphere = Cesium.BoundingSphere.fromPoints(cart);
|
||||||
viewer.camera.flyToBoundingSphere(sphere, {
|
const camera = cameraOf(viewer);
|
||||||
offset: new Cesium.HeadingPitchRange(
|
camera.flyToBounds(
|
||||||
viewer.camera.heading,
|
{ center: sphere.center, radius: sphere.radius },
|
||||||
Cesium.Math.toRadians(-35),
|
{
|
||||||
Math.max(900, sphere.radius * 2.6),
|
offset: {
|
||||||
),
|
heading: camera.pose().heading,
|
||||||
duration: 1.6,
|
pitch: Cesium.Math.toRadians(-35),
|
||||||
});
|
range: Math.max(900, sphere.radius * 2.6),
|
||||||
|
},
|
||||||
|
durationS: 1.6,
|
||||||
|
},
|
||||||
|
);
|
||||||
} catch {
|
} catch {
|
||||||
/* camera assist is best-effort */
|
/* camera assist is best-effort */
|
||||||
}
|
}
|
||||||
@@ -1757,22 +1762,23 @@ export function createAnnotationEngine({
|
|||||||
: anno.ring,
|
: anno.ring,
|
||||||
)
|
)
|
||||||
: viewportRange(anno.viewport) || 600;
|
: viewportRange(anno.viewport) || 600;
|
||||||
viewer.camera.flyToBoundingSphere(
|
const camera = cameraOf(viewer);
|
||||||
new Cesium.BoundingSphere(
|
camera.flyToBounds(
|
||||||
Cesium.Cartesian3.fromDegrees(
|
|
||||||
target.lon,
|
|
||||||
target.lat,
|
|
||||||
anno.anchor.height || 0,
|
|
||||||
),
|
|
||||||
range,
|
|
||||||
),
|
|
||||||
{
|
{
|
||||||
offset: new Cesium.HeadingPitchRange(
|
center: {
|
||||||
viewer.camera.heading,
|
lon: target.lon,
|
||||||
Cesium.Math.toRadians(-35),
|
lat: target.lat,
|
||||||
range * 2.4,
|
height: anno.anchor.height || 0,
|
||||||
),
|
},
|
||||||
duration: 1.8,
|
radius: range,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
offset: {
|
||||||
|
heading: camera.pose().heading,
|
||||||
|
pitch: Cesium.Math.toRadians(-35),
|
||||||
|
range: range * 2.4,
|
||||||
|
},
|
||||||
|
durationS: 1.8,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
} catch {
|
} catch {
|
||||||
@@ -1978,15 +1984,17 @@ export function createAnnotationEngine({
|
|||||||
}) {
|
}) {
|
||||||
if (destroyed) return;
|
if (destroyed) return;
|
||||||
try {
|
try {
|
||||||
viewer.camera.flyTo({
|
cameraOf(viewer).flyTo(
|
||||||
destination: Cesium.Cartesian3.fromDegrees(lon, lat, height),
|
{ lon, lat, height },
|
||||||
orientation: {
|
{
|
||||||
heading: Cesium.Math.toRadians(heading),
|
orientation: {
|
||||||
pitch: Cesium.Math.toRadians(pitch),
|
heading: Cesium.Math.toRadians(heading),
|
||||||
roll: 0,
|
pitch: Cesium.Math.toRadians(pitch),
|
||||||
|
roll: 0,
|
||||||
|
},
|
||||||
|
durationS: duration,
|
||||||
},
|
},
|
||||||
duration,
|
);
|
||||||
});
|
|
||||||
} catch {
|
} catch {
|
||||||
/* camera flight best-effort */
|
/* camera flight best-effort */
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { bindFakeCesiumCamera } from '../testSupport/fakeCameraPort.mjs';
|
||||||
import { createStandalonePlaceSearch } from '../standalone/placeSearch.js';
|
import { createStandalonePlaceSearch } from '../standalone/placeSearch.js';
|
||||||
// Voice-annotation resilience contract tests — pure logic, no network, no browser.
|
// Voice-annotation resilience contract tests — pure logic, no network, no browser.
|
||||||
//
|
//
|
||||||
@@ -1262,7 +1263,7 @@ test('hand-drawn marks: one mark can be hidden, renamed, recoloured, framed and
|
|||||||
const { renderer, calls } = fakeRenderer();
|
const { renderer, calls } = fakeRenderer();
|
||||||
const flights = [];
|
const flights = [];
|
||||||
const engine = createAnnotationEngine({
|
const engine = createAnnotationEngine({
|
||||||
viewer: { camera: { heading: 0, flyToBoundingSphere: (sphere) => flights.push(sphere) } },
|
viewer: bindFakeCesiumCamera({ camera: { heading: 0, flyToBoundingSphere: (sphere) => flights.push(sphere) } }),
|
||||||
renderer,
|
renderer,
|
||||||
});
|
});
|
||||||
let changes = 0;
|
let changes = 0;
|
||||||
@@ -1331,12 +1332,12 @@ test('hand-drawn marks: remove, hide, clear, expiry and framing have their effec
|
|||||||
const { renderer, calls } = fakeRenderer();
|
const { renderer, calls } = fakeRenderer();
|
||||||
const flights = [];
|
const flights = [];
|
||||||
const engine = createAnnotationEngine({
|
const engine = createAnnotationEngine({
|
||||||
viewer: {
|
viewer: bindFakeCesiumCamera({
|
||||||
camera: {
|
camera: {
|
||||||
heading: 0,
|
heading: 0,
|
||||||
flyToBoundingSphere: (sphere) => flights.push(sphere),
|
flyToBoundingSphere: (sphere) => flights.push(sphere),
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
renderer,
|
renderer,
|
||||||
});
|
});
|
||||||
let changes = 0;
|
let changes = 0;
|
||||||
|
|||||||
@@ -186,21 +186,28 @@ test('consumer build includes only infrastructure code and resolves assets under
|
|||||||
const entry = output.find((item) => item.type === 'chunk' && item.isEntry);
|
const entry = output.find((item) => item.type === 'chunk' && item.isEntry);
|
||||||
const sources = Object.keys(entry.modules).filter((id) => id.endsWith('.js'));
|
const sources = Object.keys(entry.modules).filter((id) => id.endsWith('.js'));
|
||||||
assert.deepEqual(sources.map((id) => id.split('/').at(-1)).sort(), [
|
assert.deepEqual(sources.map((id) => id.split('/').at(-1)).sort(), [
|
||||||
|
'camera.js',
|
||||||
'cameraInput.js',
|
'cameraInput.js',
|
||||||
|
'celestial.js',
|
||||||
|
'common.js',
|
||||||
'ctrlWheelZoom.js',
|
'ctrlWheelZoom.js',
|
||||||
'dispatcher.js',
|
'dispatcher.js',
|
||||||
|
'events.js',
|
||||||
'heights.js',
|
'heights.js',
|
||||||
'infrastructure.js',
|
'infrastructure.js',
|
||||||
'infrastructureData.js',
|
'infrastructureData.js',
|
||||||
'infrastructureOverlayEntry.js',
|
'infrastructureOverlayEntry.js',
|
||||||
'input.js',
|
'input.js',
|
||||||
'inputOwnership.js',
|
'inputOwnership.js',
|
||||||
|
'internals.js',
|
||||||
'localGeojsonCore.js',
|
'localGeojsonCore.js',
|
||||||
'localGeojsonLod.js',
|
'localGeojsonLod.js',
|
||||||
'pickRegistry.js',
|
'pickRegistry.js',
|
||||||
|
'rendererOf.js',
|
||||||
'router.js',
|
'router.js',
|
||||||
'scenePick.js',
|
'scenePick.js',
|
||||||
'sensorPick.js',
|
'sensorPick.js',
|
||||||
|
'vector.js',
|
||||||
]);
|
]);
|
||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
entry.imports,
|
entry.imports,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import * as Cesium from 'cesium';
|
import * as Cesium from 'cesium';
|
||||||
|
import { cameraOf } from '../render/cesium/camera.js';
|
||||||
import {
|
import {
|
||||||
layerTitle,
|
layerTitle,
|
||||||
mapAnalystRecord,
|
mapAnalystRecord,
|
||||||
@@ -820,6 +821,8 @@ export function createLocalGeoJsonLayer(
|
|||||||
|
|
||||||
if (targetPos) {
|
if (targetPos) {
|
||||||
const carto = Cesium.Cartographic.fromCartesian(targetPos);
|
const carto = Cesium.Cartographic.fromCartesian(targetPos);
|
||||||
|
// Before the hold: with no camera, nothing would end it.
|
||||||
|
const camera = cameraOf(viewer);
|
||||||
|
|
||||||
// Hold camera input so Cesium doesn't cancel the flight.
|
// Hold camera input so Cesium doesn't cancel the flight.
|
||||||
// A hold, not a flag: the flight ending must not hand input
|
// A hold, not a flag: the flight ending must not hand input
|
||||||
@@ -828,16 +831,18 @@ export function createLocalGeoJsonLayer(
|
|||||||
'local-geojson-flight',
|
'local-geojson-flight',
|
||||||
);
|
);
|
||||||
|
|
||||||
viewer.camera.flyTo({
|
camera.flyTo(
|
||||||
destination: Cesium.Cartesian3.fromRadians(
|
Cesium.Cartesian3.fromRadians(
|
||||||
carto.longitude,
|
carto.longitude,
|
||||||
carto.latitude,
|
carto.latitude,
|
||||||
5000,
|
5000,
|
||||||
),
|
),
|
||||||
duration: 1.5,
|
{
|
||||||
complete: releaseCamera,
|
durationS: 1.5,
|
||||||
cancel: releaseCamera,
|
onComplete: releaseCamera,
|
||||||
});
|
onCancel: releaseCamera,
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
+25
-22
@@ -21,6 +21,8 @@ import { createToast } from '../ui/toast.js';
|
|||||||
import { buildPlaybackQueue, playSceneQueue } from '../director/playback.js';
|
import { buildPlaybackQueue, playSceneQueue } from '../director/playback.js';
|
||||||
import { createScenePlaybackAdapter } from './playbackAdapter.js';
|
import { createScenePlaybackAdapter } from './playbackAdapter.js';
|
||||||
import * as Cesium from 'cesium';
|
import * as Cesium from 'cesium';
|
||||||
|
import { cameraOf } from '../render/cesium/camera.js';
|
||||||
|
import { findCamera } from '../render/rendererOf.js';
|
||||||
import {
|
import {
|
||||||
SCENE_APPEND_RECIPES,
|
SCENE_APPEND_RECIPES,
|
||||||
SCENE_RECIPES,
|
SCENE_RECIPES,
|
||||||
@@ -263,7 +265,8 @@ export class SceneDirector {
|
|||||||
this.stopScene(msg('Stopped'));
|
this.stopScene(msg('Stopped'));
|
||||||
this._loadAbort?.abort();
|
this._loadAbort?.abort();
|
||||||
this._loadGeneration++;
|
this._loadGeneration++;
|
||||||
this.viewer.camera.cancelFlight();
|
// The viewer may be gone by now: then there is no flight to stop.
|
||||||
|
findCamera(this.viewer)?.cancelFlight();
|
||||||
this._storageToast?.cancel();
|
this._storageToast?.cancel();
|
||||||
await Promise.allSettled(this._pendingWork || []);
|
await Promise.allSettled(this._pendingWork || []);
|
||||||
this._clock.destroy();
|
this._clock.destroy();
|
||||||
@@ -1746,16 +1749,16 @@ export class SceneDirector {
|
|||||||
|
|
||||||
/** Place the camera at an authored replay start pose without an intermediate flight. */
|
/** Place the camera at an authored replay start pose without an intermediate flight. */
|
||||||
_setCameraView(cameraState) {
|
_setCameraView(cameraState) {
|
||||||
if (!cameraState || typeof this.viewer?.camera?.setView !== 'function')
|
const camera = findCamera(this.viewer);
|
||||||
return false;
|
if (!cameraState || !camera) return false;
|
||||||
this.styleManager?.clearSearchedLocation?.();
|
this.styleManager?.clearSearchedLocation?.();
|
||||||
this.viewer.camera.cancelFlight?.();
|
camera.cancelFlight();
|
||||||
this.viewer.camera.setView({
|
camera.setView({
|
||||||
destination: Cesium.Cartesian3.fromDegrees(
|
destination: {
|
||||||
cameraState.lon,
|
lon: cameraState.lon,
|
||||||
cameraState.lat,
|
lat: cameraState.lat,
|
||||||
cameraState.alt,
|
height: cameraState.alt,
|
||||||
),
|
},
|
||||||
orientation: {
|
orientation: {
|
||||||
heading: Cesium.Math.toRadians(cameraState.heading || 0),
|
heading: Cesium.Math.toRadians(cameraState.heading || 0),
|
||||||
pitch: Cesium.Math.toRadians(cameraState.pitch ?? -35),
|
pitch: Cesium.Math.toRadians(cameraState.pitch ?? -35),
|
||||||
@@ -2022,7 +2025,8 @@ export class SceneDirector {
|
|||||||
this._loadGeneration++;
|
this._loadGeneration++;
|
||||||
this._clock.stopShot();
|
this._clock.stopShot();
|
||||||
this._cancelActiveSceneTravel();
|
this._cancelActiveSceneTravel();
|
||||||
this.viewer.camera.cancelFlight();
|
// Stop runs in teardown too, after the viewer may be gone.
|
||||||
|
findCamera(this.viewer)?.cancelFlight();
|
||||||
this._clock.stop();
|
this._clock.stop();
|
||||||
if (!this._running || !this._runToken) return;
|
if (!this._running || !this._runToken) return;
|
||||||
this._runToken.cancelled = true;
|
this._runToken.cancelled = true;
|
||||||
@@ -2464,11 +2468,11 @@ export class SceneDirector {
|
|||||||
0.2,
|
0.2,
|
||||||
Number(durationSec) || DEFAULT_SHOT_DURATION_SEC,
|
Number(durationSec) || DEFAULT_SHOT_DURATION_SEC,
|
||||||
);
|
);
|
||||||
const destination = Cesium.Cartesian3.fromDegrees(
|
const destination = {
|
||||||
cameraState.lon,
|
lon: cameraState.lon,
|
||||||
cameraState.lat,
|
lat: cameraState.lat,
|
||||||
cameraState.alt,
|
height: cameraState.alt,
|
||||||
);
|
};
|
||||||
|
|
||||||
await new Promise((resolve) => {
|
await new Promise((resolve) => {
|
||||||
// Guard against double-resolve from both callback and timeout
|
// Guard against double-resolve from both callback and timeout
|
||||||
@@ -2481,17 +2485,16 @@ export class SceneDirector {
|
|||||||
resolve();
|
resolve();
|
||||||
};
|
};
|
||||||
|
|
||||||
this.viewer.camera.flyTo({
|
cameraOf(this.viewer).flyTo(destination, {
|
||||||
destination,
|
|
||||||
orientation: {
|
orientation: {
|
||||||
heading: Cesium.Math.toRadians(cameraState.heading || 0),
|
heading: Cesium.Math.toRadians(cameraState.heading || 0),
|
||||||
pitch: Cesium.Math.toRadians(cameraState.pitch ?? -35),
|
pitch: Cesium.Math.toRadians(cameraState.pitch ?? -35),
|
||||||
roll: Cesium.Math.toRadians(cameraState.roll || 0),
|
roll: Cesium.Math.toRadians(cameraState.roll || 0),
|
||||||
},
|
},
|
||||||
duration,
|
durationS: duration,
|
||||||
easingFunction: Cesium.EasingFunction.CUBIC_IN_OUT,
|
easing: 'cubicInOut',
|
||||||
complete: finish,
|
onComplete: finish,
|
||||||
cancel: finish,
|
onCancel: finish,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Safety timeout in case Cesium callbacks fail to fire
|
// Safety timeout in case Cesium callbacks fail to fire
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { bindFakeCesiumCamera } from '../testSupport/fakeCameraPort.mjs';
|
||||||
import { readShellSource } from '../testSupport/readShellSource.mjs';
|
import { readShellSource } from '../testSupport/readShellSource.mjs';
|
||||||
import { useStatusStore } from '../ui/stores/status.js';
|
import { useStatusStore } from '../ui/stores/status.js';
|
||||||
import { applicationPinia } from '../ui/vueRuntime.js';
|
import { applicationPinia } from '../ui/vueRuntime.js';
|
||||||
@@ -1072,7 +1073,7 @@ function fakeViewer() {
|
|||||||
const flights = [];
|
const flights = [];
|
||||||
const views = [];
|
const views = [];
|
||||||
let cancelled = 0;
|
let cancelled = 0;
|
||||||
return {
|
return bindFakeCesiumCamera({
|
||||||
flights,
|
flights,
|
||||||
views,
|
views,
|
||||||
get cancelledFlights() { return cancelled; },
|
get cancelledFlights() { return cancelled; },
|
||||||
@@ -1086,7 +1087,7 @@ function fakeViewer() {
|
|||||||
},
|
},
|
||||||
cancelFlight() { cancelled++; },
|
cancelFlight() { cancelled++; },
|
||||||
},
|
},
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Yield enough turns for the director's pending awaits to advance. */
|
/** Yield enough turns for the director's pending awaits to advance. */
|
||||||
@@ -1776,7 +1777,7 @@ test('destroy drains cancelled LOAD work before its viewer can be discarded', as
|
|||||||
t.after(restore);
|
t.after(restore);
|
||||||
let finishVisual;
|
let finishVisual;
|
||||||
const dataManager = fakeDataManager();
|
const dataManager = fakeDataManager();
|
||||||
const viewer = { camera: { cancelFlight() {} } };
|
const viewer = bindFakeCesiumCamera({ camera: { cancelFlight() {} } });
|
||||||
const director = new SceneDirector(viewer, {
|
const director = new SceneDirector(viewer, {
|
||||||
applyVisualState: () => new Promise((resolve) => { finishVisual = resolve; }),
|
applyVisualState: () => new Promise((resolve) => { finishVisual = resolve; }),
|
||||||
}, dataManager);
|
}, dataManager);
|
||||||
|
|||||||
+13
-8
@@ -12,6 +12,7 @@ import { msg } from '../i18n/index.js';
|
|||||||
import { useProviderSettingsStore } from '../ui/stores/providerSettings.js';
|
import { useProviderSettingsStore } from '../ui/stores/providerSettings.js';
|
||||||
import { applicationPinia } from '../ui/vueRuntime.js';
|
import { applicationPinia } from '../ui/vueRuntime.js';
|
||||||
import * as Cesium from 'cesium';
|
import * as Cesium from 'cesium';
|
||||||
|
import { cameraOf } from '../render/cesium/camera.js';
|
||||||
import { distance as chordM, toLonLatH } from '../geo/index.js';
|
import { distance as chordM, toLonLatH } from '../geo/index.js';
|
||||||
import { CITY_POIS } from '../cityPois.js';
|
import { CITY_POIS } from '../cityPois.js';
|
||||||
import { greatCircleKm } from '../geoDistance.js';
|
import { greatCircleKm } from '../geoDistance.js';
|
||||||
@@ -2654,14 +2655,18 @@ async function frameOverhead(viewer, dataManager, styleManager, args = {}) {
|
|||||||
'frame',
|
'frame',
|
||||||
'frame_overhead',
|
'frame_overhead',
|
||||||
() => {
|
() => {
|
||||||
viewer.camera.flyToBoundingSphere(sphere, {
|
const camera = cameraOf(viewer);
|
||||||
duration: 2.0,
|
camera.flyToBounds(
|
||||||
offset: new Cesium.HeadingPitchRange(
|
{ center: sphere.center, radius: sphere.radius },
|
||||||
viewer.camera.heading,
|
{
|
||||||
pitch,
|
durationS: 2.0,
|
||||||
sphere.radius * 2.4,
|
offset: {
|
||||||
),
|
heading: camera.pose().heading,
|
||||||
});
|
pitch,
|
||||||
|
range: sphere.radius * 2.4,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
let detectionEnabled = false;
|
let detectionEnabled = false;
|
||||||
try {
|
try {
|
||||||
|
|||||||
Reference in new issue
Block a user