mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-13 14:52:19 +00:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b65a7aaed8 |
No files matched your search
@@ -0,0 +1,129 @@
|
|||||||
|
// An explicit pick of the camera that a settled move just re-opened must end
|
||||||
|
// the opening pick. That pick goes through setActiveCamera's UNCHANGED path
|
||||||
|
// (same camera, already activated); if that path keeps the provisional flag,
|
||||||
|
// the next settled move (a pan, or the landing of NEAREST's own flight)
|
||||||
|
// switches the camera away from the one the user chose.
|
||||||
|
import assert from 'node:assert/strict';
|
||||||
|
import test from 'node:test';
|
||||||
|
import * as Cesium from 'cesium';
|
||||||
|
import cctvLayer, {
|
||||||
|
_setCctvCoverageStateForTest,
|
||||||
|
_setCctvOverlayHostForTest,
|
||||||
|
reopenNearestCamera,
|
||||||
|
} from './cctv.js';
|
||||||
|
|
||||||
|
const BASE = {
|
||||||
|
headingDeg: 41,
|
||||||
|
pitchDeg: -5,
|
||||||
|
fovDeg: 56,
|
||||||
|
rangeM: 210,
|
||||||
|
mountHeightM: 100,
|
||||||
|
groundElevationM: 0,
|
||||||
|
city: 'London',
|
||||||
|
};
|
||||||
|
|
||||||
|
function record(id, lat, lon) {
|
||||||
|
return {
|
||||||
|
camera: { ...BASE, id, name: `Camera ${id}`, lat, lon },
|
||||||
|
coverageEntities: [],
|
||||||
|
projection: null,
|
||||||
|
activationDone: true,
|
||||||
|
groundResolved: {},
|
||||||
|
groundSamples: {},
|
||||||
|
groundPrior: 0,
|
||||||
|
frustumGeometry: null,
|
||||||
|
frustumPositions: null,
|
||||||
|
probeClampRangeM: null,
|
||||||
|
position: Cesium.Cartesian3.fromDegrees(lon, lat, 100),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function viewerAt(lat, lon) {
|
||||||
|
return {
|
||||||
|
entities: new Cesium.EntityCollection(),
|
||||||
|
isDestroyed: () => false,
|
||||||
|
trackedEntity: null,
|
||||||
|
camera: {
|
||||||
|
positionWC: Cesium.Cartesian3.fromDegrees(lon, lat, 300),
|
||||||
|
positionCartographic: Cesium.Cartographic.fromDegrees(lon, lat, 300),
|
||||||
|
heading: 0.4,
|
||||||
|
pitch: -0.7,
|
||||||
|
roll: 0,
|
||||||
|
transform: Cesium.Matrix4.clone(Cesium.Matrix4.IDENTITY),
|
||||||
|
flyToBoundingSphere() {},
|
||||||
|
},
|
||||||
|
scene: {
|
||||||
|
canvas: { clientWidth: 1200, clientHeight: 800 },
|
||||||
|
cartesianToCanvasCoordinates: () => undefined,
|
||||||
|
primitives: { add: (p) => p, remove: () => true },
|
||||||
|
requestRender() {},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function moveViewer(viewer, lat, lon) {
|
||||||
|
viewer.camera.positionCartographic = Cesium.Cartographic.fromDegrees(
|
||||||
|
lon,
|
||||||
|
lat,
|
||||||
|
300,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function withReopenedLayer(fn) {
|
||||||
|
_setCctvOverlayHostForTest({
|
||||||
|
setEntries() {},
|
||||||
|
setVisible() {},
|
||||||
|
clearSource() {},
|
||||||
|
});
|
||||||
|
// Activation builds the projection canvas and frame image.
|
||||||
|
const originalDocument = globalThis.document;
|
||||||
|
const originalImage = globalThis.Image;
|
||||||
|
globalThis.document = { createElement: () => ({ getContext: () => null }) };
|
||||||
|
globalThis.Image = class {};
|
||||||
|
try {
|
||||||
|
const trafalgar = record('a-trafalgar', 51.508, -0.128);
|
||||||
|
const cambridge = record('b-cambridge', 51.513, -0.129);
|
||||||
|
// enable() assigned the opening camera without activating it.
|
||||||
|
trafalgar.activationDone = false;
|
||||||
|
const viewer = viewerAt(51.5081, -0.1281);
|
||||||
|
_setCctvCoverageStateForTest({
|
||||||
|
viewer,
|
||||||
|
records: [trafalgar, cambridge],
|
||||||
|
activeCameraId: 'a-trafalgar',
|
||||||
|
enabled: true,
|
||||||
|
openingCameraProvisional: true,
|
||||||
|
});
|
||||||
|
// A settled move next to Cambridge Circus re-opens there, still as the
|
||||||
|
// opening pick.
|
||||||
|
moveViewer(viewer, 51.5131, -0.1291);
|
||||||
|
assert.equal(reopenNearestCamera(), true);
|
||||||
|
assert.equal(cctvLayer.getUIState().activeCameraId, 'b-cambridge');
|
||||||
|
fn(viewer);
|
||||||
|
} finally {
|
||||||
|
globalThis.document = originalDocument;
|
||||||
|
globalThis.Image = originalImage;
|
||||||
|
_setCctvOverlayHostForTest();
|
||||||
|
_setCctvCoverageStateForTest({ enabled: false });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const [name, pick] of [
|
||||||
|
['NEAREST (focusNearest)', () => cctvLayer.focusNearest({ focus: false })],
|
||||||
|
['selectCamera', () => cctvLayer.selectCamera('b-cambridge')],
|
||||||
|
[
|
||||||
|
'setParams({ selectedCameraId })',
|
||||||
|
() => cctvLayer.setParams({ selectedCameraId: 'b-cambridge' }),
|
||||||
|
],
|
||||||
|
]) {
|
||||||
|
test(`an explicit ${name} pick of the re-opened camera ends the opening pick`, () => {
|
||||||
|
withReopenedLayer((viewer) => {
|
||||||
|
pick();
|
||||||
|
assert.equal(cctvLayer.getUIState().activeCameraId, 'b-cambridge');
|
||||||
|
// A later settled move (a pan, or the landing of the pick's own flight)
|
||||||
|
// leaves the explicit choice alone.
|
||||||
|
moveViewer(viewer, 51.5081, -0.1281);
|
||||||
|
assert.equal(reopenNearestCamera(), false);
|
||||||
|
assert.equal(cctvLayer.getUIState().activeCameraId, 'b-cambridge');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -79,6 +79,9 @@ export function createSelection({
|
|||||||
record,
|
record,
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
|
// Picking the camera a settled move re-opened is still a choice: later
|
||||||
|
// settled moves must leave it alone.
|
||||||
|
layerState._openingCameraProvisional = false;
|
||||||
// Browser-only feeds have a separate player; a reselect retries it
|
// Browser-only feeds have a separate player; a reselect retries it
|
||||||
// without re-running activation or touching the projection geometry.
|
// without re-running activation or touching the projection geometry.
|
||||||
if (parts.model.isBrowserOverlayCamera(record.camera)) {
|
if (parts.model.isBrowserOverlayCamera(record.camera)) {
|
||||||
|
|||||||
Reference in new issue
Block a user