mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-06 03:14:00 +00:00
refactor(pick): use the globe engine
pickGroundPosition takes the globe engine (picker.pickPosition, then camera.pickEllipsoid) and still accepts a Cesium viewer from callers that hold one (layers until phase 1c), with one shared ground-or-ellipsoid rule. isSurfacePick classifies engine pick results exactly as the Cesium picks they wrap.
This commit is contained in:
1 parent
aaa6074663
commit
c2a0d20f3d
2 files changed
+77
-15
No files matched your search
+31
-15
@@ -1,3 +1,5 @@
|
||||
import { isGlobeEngine } from '../globe/contract.js';
|
||||
|
||||
/**
|
||||
* Validation for positions that came back from a Cesium screen pick.
|
||||
*
|
||||
@@ -52,29 +54,43 @@ export function isPickedWorldPosition(position) {
|
||||
* The world position under a screen point: the rendered surface where the
|
||||
* depth buffer has it, else the ellipsoid; null over the sky.
|
||||
*
|
||||
* @param {object} viewer A Cesium viewer.
|
||||
* @param {object} target The globe engine (`engine.picker.pickPosition`, then
|
||||
* `engine.camera.pickEllipsoid`), or a Cesium viewer from callers that
|
||||
* still hold one (`scene.pickPosition`, then `camera.pickEllipsoid`).
|
||||
* @param {{x: number, y: number}} screenPosition
|
||||
* @returns {{x: number, y: number, z: number}|null} A Cartesian3.
|
||||
*/
|
||||
export function pickGroundPosition(viewer, screenPosition) {
|
||||
const scene = viewer?.scene;
|
||||
export function pickGroundPosition(target, screenPosition) {
|
||||
if (isGlobeEngine(target)) {
|
||||
const { picker, camera } = target;
|
||||
return groundUnder(
|
||||
screenPosition,
|
||||
picker.pickPositionSupported ? picker : null,
|
||||
camera,
|
||||
);
|
||||
}
|
||||
const scene = target?.scene;
|
||||
return groundUnder(
|
||||
screenPosition,
|
||||
scene?.pickPositionSupported && typeof scene.pickPosition === 'function'
|
||||
? scene
|
||||
: null,
|
||||
typeof target?.camera?.pickEllipsoid === 'function' ? target.camera : null,
|
||||
);
|
||||
}
|
||||
|
||||
function groundUnder(screenPosition, depth, ellipsoid) {
|
||||
let position = null;
|
||||
if (
|
||||
scene?.pickPositionSupported &&
|
||||
typeof scene.pickPosition === 'function'
|
||||
) {
|
||||
if (depth) {
|
||||
try {
|
||||
position = scene.pickPosition(screenPosition);
|
||||
position = depth.pickPosition(screenPosition);
|
||||
} catch {
|
||||
position = null;
|
||||
}
|
||||
}
|
||||
if (
|
||||
!isPickedWorldPosition(position) &&
|
||||
typeof viewer?.camera?.pickEllipsoid === 'function'
|
||||
) {
|
||||
if (!isPickedWorldPosition(position) && ellipsoid) {
|
||||
try {
|
||||
position = viewer.camera.pickEllipsoid(screenPosition);
|
||||
position = ellipsoid.pickEllipsoid(screenPosition);
|
||||
} catch {
|
||||
position = null;
|
||||
}
|
||||
@@ -83,8 +99,8 @@ export function pickGroundPosition(viewer, screenPosition) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether a `scene.pick()` result is the map itself: nothing, or 3D tile
|
||||
* content (which has no id).
|
||||
* Whether a pick result (`engine.picker.pick()` or `scene.pick()`) is the
|
||||
* map itself: nothing, or 3D tile content (which has no id).
|
||||
*
|
||||
* @param {object|null|undefined} picked
|
||||
* @returns {boolean}
|
||||
|
||||
@@ -184,3 +184,49 @@ test('a surface pick is nothing, or Google 3D tile content without an id', async
|
||||
assert.equal(isSurfacePick({ id: 'flight:1', content: {} }), false);
|
||||
assert.equal(isSurfacePick({ primitive: {} }), false, 'an unnamed primitive');
|
||||
});
|
||||
|
||||
test('on a globe engine the ground is the picked surface, else the ellipsoid, never the sky', async () => {
|
||||
const { pickGroundPosition } = await import('./scenePick.js');
|
||||
const { createFakeEngine } = await import('../globe/testing/fakeEngine.js');
|
||||
const ground = { x: 6378137, y: 0, z: 0 };
|
||||
const sky = { x: 500, y: 0, z: 0 };
|
||||
const screen = { x: 10, y: 20 };
|
||||
const engine = createFakeEngine();
|
||||
engine.fake.script('pickPosition', ground);
|
||||
engine.fake.script('pickEllipsoid', undefined);
|
||||
assert.equal(pickGroundPosition(engine, screen), ground);
|
||||
assert.deepEqual(engine.fake.callsOf('picker.pickPosition')[0].args, [screen]);
|
||||
engine.fake.script('pickPosition', sky);
|
||||
engine.fake.script('pickEllipsoid', ground);
|
||||
assert.equal(pickGroundPosition(engine, screen), ground);
|
||||
engine.fake.script('pickPosition', () => {
|
||||
throw new Error('depth read failed');
|
||||
});
|
||||
assert.equal(pickGroundPosition(engine, screen), ground);
|
||||
engine.fake.script('pickEllipsoid', undefined);
|
||||
assert.equal(pickGroundPosition(engine, screen), null);
|
||||
const unsupported = createFakeEngine();
|
||||
unsupported.picker.pickPositionSupported = false;
|
||||
unsupported.fake.script('pickEllipsoid', ground);
|
||||
assert.equal(pickGroundPosition(unsupported, screen), ground);
|
||||
assert.equal(unsupported.fake.callsOf('picker.pickPosition').length, 0);
|
||||
});
|
||||
|
||||
test('engine pick results classify like the Cesium picks they wrap', async () => {
|
||||
const { isSurfacePick } = await import('./scenePick.js');
|
||||
const { createCesiumPicker } = await import('../globe/cesium/picker.js');
|
||||
const { createFakeViewer } = await import('../globe/cesium/testing/fakeViewer.mjs');
|
||||
const raws = [
|
||||
undefined,
|
||||
{ content: {}, primitive: {} },
|
||||
{ primitive: { isCesium3DTileset: true } },
|
||||
{ id: 'flight:1', content: {} },
|
||||
{ primitive: {} },
|
||||
];
|
||||
for (const raw of raws) {
|
||||
const viewer = createFakeViewer();
|
||||
viewer.scene.pick = () => raw;
|
||||
const { picker } = createCesiumPicker(viewer);
|
||||
assert.equal(isSurfacePick(picker.pick({ x: 1, y: 2 })), isSurfacePick(raw), JSON.stringify(raw));
|
||||
}
|
||||
});
|
||||
Reference in new issue
Block a user