mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 19:04:02 +00:00
refactor(data): focus projects through the engine; readout follows a tracked visual's follow
Task 10b foundation. - focusDeemphasis projects through the engine registered for the scene it is given (engineFromViewer(scene).projector), as iconOrientation already does, else Cesium's SceneTransforms. On Cesium the engine projector is SceneTransforms, so nothing changes there; on Navara the aircraft renderer's scene adapter is registered with the engine. Test with a fake engine. - refreshTrackedReadout accepts a layer's tracked visual that names its follow handle (gevFollowHandle): engines without tracked entities republish the card through it. Test.
This commit is contained in:
1 parent
4dfcba8989
commit
443c581280
4 files changed
+71
-14
No files matched your search
+14
-12
@@ -1,4 +1,16 @@
|
||||
import * as Cesium from 'cesium';
|
||||
import { engineFromViewer } from '../globe/cesium/engineFromViewer.js';
|
||||
|
||||
// A window position through the engine's projector when `scene` has a
|
||||
// registered engine (a Cesium scene in the app, the Navara aircraft
|
||||
// renderer's scene adapter), else Cesium's SceneTransforms (bare scenes in
|
||||
// tests). The two agree on Cesium (the engine projector is SceneTransforms).
|
||||
function worldToWindow(scene, position, result) {
|
||||
const projector = engineFromViewer(scene)?.projector;
|
||||
return projector
|
||||
? projector.worldToWindow(position, result)
|
||||
: Cesium.SceneTransforms.worldToWindowCoordinates(scene, position, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Focus-aware sprite treatment shared by the live contact layers.
|
||||
@@ -208,11 +220,7 @@ export function publishFocusTargetFromCachedPosition({
|
||||
clearFocusTarget(ownerLayer, id);
|
||||
return null;
|
||||
}
|
||||
const screen = Cesium.SceneTransforms.worldToWindowCoordinates(
|
||||
scene,
|
||||
displayPosition,
|
||||
_scratchScreen,
|
||||
);
|
||||
const screen = worldToWindow(scene, displayPosition, _scratchScreen);
|
||||
if (!screen || !Number.isFinite(screen.x) || !Number.isFinite(screen.y)) {
|
||||
clearFocusTarget(ownerLayer, id);
|
||||
return null;
|
||||
@@ -480,13 +488,7 @@ export function advanceProjectedSpriteFocus(
|
||||
return _advanceResult;
|
||||
}
|
||||
const screen =
|
||||
position && scene
|
||||
? Cesium.SceneTransforms.worldToWindowCoordinates(
|
||||
scene,
|
||||
position,
|
||||
_scratchScreen,
|
||||
)
|
||||
: null;
|
||||
position && scene ? worldToWindow(scene, position, _scratchScreen) : null;
|
||||
const cameraDistance =
|
||||
position && camera?.positionWC
|
||||
? Cesium.Cartesian3.distance(camera.positionWC, position)
|
||||
|
||||
@@ -162,3 +162,46 @@ test('NearFarScalar rendered-size interpolation matches Cesium clamp endpoints',
|
||||
const middle = nearFarScalarValueAtDistance(scalar, 1_000_000);
|
||||
assert.ok(middle > 0.5 && middle < 3);
|
||||
});
|
||||
|
||||
test('a focus target projects through the engine registered for its scene', async () => {
|
||||
const { publishFocusTargetFromCachedPosition, clearFocusTarget } =
|
||||
await import('./focusDeemphasis.js');
|
||||
const { registerViewerEngine } = await import(
|
||||
'../globe/cesium/engineFromViewer.js'
|
||||
);
|
||||
const { createFakeEngine } = await import('../globe/testing/fakeEngine.js');
|
||||
const engine = createFakeEngine();
|
||||
const projected = [];
|
||||
engine.projector.worldToWindow = (position, result = {}) => {
|
||||
projected.push(position);
|
||||
return Object.assign(result, { x: 300, y: 200 });
|
||||
};
|
||||
// A scene with no Cesium behind it (the Navara renderer's adapter).
|
||||
const scene = { frameState: { frameNumber: 7 } };
|
||||
const unregister = registerViewerEngine(scene, engine);
|
||||
try {
|
||||
const target = publishFocusTargetFromCachedPosition({
|
||||
ownerLayer: 'flights',
|
||||
id: 'abc123',
|
||||
scene,
|
||||
camera: { positionWC: { x: 0, y: 0, z: 1000 } },
|
||||
displayPosition: { x: 0, y: 0, z: 0 },
|
||||
widthPx: 20,
|
||||
heightPx: 20,
|
||||
params: { paddingPx: 0 },
|
||||
});
|
||||
assert.equal(projected.length, 1);
|
||||
assert.deepEqual(target.screenRect, {
|
||||
left: 290,
|
||||
top: 190,
|
||||
right: 310,
|
||||
bottom: 210,
|
||||
});
|
||||
assert.equal(target.cameraDistance, 1000);
|
||||
assert.equal(target.frameNumber, 7);
|
||||
} finally {
|
||||
clearFocusTarget('flights');
|
||||
unregister();
|
||||
engine.destroy();
|
||||
}
|
||||
});
|
||||
@@ -241,8 +241,13 @@ function syncActiveEntity() {
|
||||
* @param {Object} entity Entity whose model changed.
|
||||
*/
|
||||
export function refreshTrackedReadout(entity) {
|
||||
// A follow handle stands for its label subject.
|
||||
const subject = _labelSubjects.get(entity) ?? entity;
|
||||
// A follow handle stands for its label subject; so does a layer's tracked
|
||||
// visual that names its follow handle (gevFollowHandle, an engine without
|
||||
// tracked entities: the Navara aircraft renderer).
|
||||
const subject =
|
||||
_labelSubjects.get(entity) ??
|
||||
_labelSubjects.get(entity?.gevFollowHandle) ??
|
||||
entity;
|
||||
if (subject && subject === activeEntity()) publishEntity(subject);
|
||||
}
|
||||
|
||||
|
||||
@@ -333,6 +333,13 @@ test("on a globe engine the readout follows engine.camera.follow's plain-data la
|
||||
recorder.calls.filter(({ op }) => op === 'set').at(-1).entries[0].details,
|
||||
['409 km'],
|
||||
);
|
||||
// So does a layer's tracked visual that names its follow handle.
|
||||
model = { ...model, details: ['410 km'] };
|
||||
refreshTrackedReadout({ gevFollowHandle: handle });
|
||||
assert.deepEqual(
|
||||
recorder.calls.filter(({ op }) => op === 'set').at(-1).entries[0].details,
|
||||
['410 km'],
|
||||
);
|
||||
handle.stop();
|
||||
assert.equal(getActiveTrackedReadoutId(), null);
|
||||
} finally {
|
||||
|
||||
Reference in new issue
Block a user