mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-06 11:24:00 +00:00
feat(globe): bring the Navara engine up to the shell contract
- camera.livePosition: one engine-owned Cartesian3, refreshed on read (the model replaces its state on every move); camera.height() - render.request(reason) takes the diagnostic reason and ignores it - maps.current() returns the sources as passed: the base imagery on the globe (none while tiles replace it) and the tiles shown - maps.releasePhotorealTiles forgets a source and takes its tiles away if they show - base imagery and photoreal share one switch order; tiles off brings back the last base imagery with its credit; imagery chosen while tiles show waits hidden, credit included - Navara QA runs the contract's maps checks with a Google 3D tiles source on the dev server's browser key: 58/58
This commit is contained in:
1 parent
a4ac0b9b0d
commit
840e34a881
5 files changed
+130
-10
No files matched your search
@@ -266,7 +266,15 @@ export function createCameraModel({
|
||||
}
|
||||
}
|
||||
|
||||
// camera.livePosition: one owned object, refreshed on read (place() and
|
||||
// sync() replace `state`, so it is copied rather than aliased).
|
||||
const livePosition = cartesian3.create();
|
||||
|
||||
const camera = {
|
||||
get livePosition() {
|
||||
return cartesian3.clone(state.position, livePosition);
|
||||
},
|
||||
height: () => cartographic.fromCartesian(state.position, WGS84).height,
|
||||
pose() {
|
||||
const current = view();
|
||||
const angles = headingPitchRoll(
|
||||
|
||||
@@ -439,3 +439,21 @@ test('rounding noise in the drawn camera is no movement, so moveEnd still fires'
|
||||
assert.equal(clock.time >= 960, true);
|
||||
assert.equal(ends, 1, 'moveEnd did not fire while Navara redrew the pose');
|
||||
});
|
||||
|
||||
test('livePosition is one engine-owned object holding the current position; height() reads it', () => {
|
||||
const { camera, port, frame } = setup();
|
||||
const live = camera.livePosition;
|
||||
const destination = cartesian3.fromDegrees(20, 10, 12345);
|
||||
camera.setView({ destination });
|
||||
assert.equal(camera.livePosition, live, 'not the same object');
|
||||
near(cartesian3.distance(live, destination), 0, 1e-9, 'follows setView');
|
||||
near(camera.height(), 12345, 1e-6, 'height');
|
||||
frame();
|
||||
const moved = cartesian3.fromDegrees(21, 11, 9e5);
|
||||
port.drawn = { position: moved, ...orientationVectors(moved, 0.3, -1, 0) };
|
||||
frame();
|
||||
near(cartesian3.distance(camera.livePosition, moved), 0, 1e-9, 'follows Navara');
|
||||
near(camera.height(), 9e5, 1e-6, 'height after a user move');
|
||||
const pose = camera.pose();
|
||||
assert.notEqual(pose.position, live, 'pose shares the live object');
|
||||
});
|
||||
@@ -115,6 +115,8 @@ test('render requests are forceUpdate and continuous mode is Navara animation',
|
||||
const { engine, view } = setup();
|
||||
engine.render.request();
|
||||
assert.deepEqual(view.calls.at(-1), ['forceUpdate']);
|
||||
engine.render.request('world-overlay');
|
||||
assert.deepEqual(view.calls.at(-1), ['forceUpdate'], 'the reason is ignored');
|
||||
engine.render.setContinuous(true);
|
||||
assert.equal(view.animation, true);
|
||||
assert.equal(engine.render.isContinuous(), true);
|
||||
|
||||
+47
-10
@@ -67,7 +67,9 @@ export function createNavaraMaps(
|
||||
{ fetch: fetchJson = globalThis.fetch } = {},
|
||||
) {
|
||||
const slots = { imagery: null, terrain: null, photoreal: null };
|
||||
const generations = { imagery: 0, terrain: 0, photoreal: 0 };
|
||||
// Base imagery and photoreal tiles share one switch order (display): the
|
||||
// call made last decides what shows.
|
||||
const generations = { display: 0, terrain: 0 };
|
||||
let destroyed = false;
|
||||
|
||||
function retire(slot) {
|
||||
@@ -95,7 +97,14 @@ export function createNavaraMaps(
|
||||
);
|
||||
retire(previous);
|
||||
if (shown.length) view.attribution?.add(shown);
|
||||
slots[name] = { key, source, layer, layerDesc, credits: shown };
|
||||
slots[name] = {
|
||||
key,
|
||||
source,
|
||||
layer,
|
||||
layerDesc,
|
||||
credits: shown,
|
||||
hidden: false,
|
||||
};
|
||||
view.forceUpdate();
|
||||
}
|
||||
|
||||
@@ -146,15 +155,26 @@ export function createNavaraMaps(
|
||||
}
|
||||
}
|
||||
|
||||
// What current() reports: the base imagery on the globe (none while tiles
|
||||
// replace it) and the tiles shown, as the objects passed in.
|
||||
let baseSource = null;
|
||||
let currentBase = null;
|
||||
let tilesSource = null;
|
||||
const knownTiles = new Set();
|
||||
|
||||
const maps = {
|
||||
async setBaseImagery(source) {
|
||||
const generation = ++generations.imagery;
|
||||
const generation = ++generations.display;
|
||||
const { url, credit } = imageryFor(source);
|
||||
if (destroyed || generation !== generations.imagery) return;
|
||||
if (slots.imagery?.key === url) return setImageryShown(true);
|
||||
show('imagery', url, { type: 'raster-tile', url }, { type: 'raster' }, [
|
||||
credit,
|
||||
]);
|
||||
if (destroyed || generation !== generations.display) return;
|
||||
baseSource = source;
|
||||
currentBase = source;
|
||||
if (slots.imagery?.key !== url)
|
||||
show('imagery', url, { type: 'raster-tile', url }, { type: 'raster' }, [
|
||||
credit,
|
||||
]);
|
||||
// Under tiles the base imagery waits hidden, credit included.
|
||||
setImageryShown(slots.photoreal == null);
|
||||
},
|
||||
async setTerrain(source) {
|
||||
const generation = ++generations.terrain;
|
||||
@@ -169,9 +189,15 @@ export function createNavaraMaps(
|
||||
show('terrain', description.url, description, { type: 'terrain' });
|
||||
},
|
||||
async setPhotorealTiles(source) {
|
||||
const generation = ++generations.photoreal;
|
||||
const generation = ++generations.display;
|
||||
if (source == null) {
|
||||
clear('photoreal');
|
||||
tilesSource = null;
|
||||
// The globe comes back with the last base imagery and its credit.
|
||||
if (slots.imagery) {
|
||||
setImageryShown(true);
|
||||
currentBase = baseSource;
|
||||
}
|
||||
view.forceUpdate();
|
||||
return;
|
||||
}
|
||||
@@ -180,9 +206,12 @@ export function createNavaraMaps(
|
||||
throw new Error(
|
||||
'Google 3D tiles on Navara need a browser key (googleApiKey)',
|
||||
);
|
||||
if (destroyed || generation !== generations.photoreal) return;
|
||||
if (destroyed || generation !== generations.display) return;
|
||||
const url = `${GOOGLE_TILES_ROOT}?key=${encodeURIComponent(key)}`;
|
||||
setImageryShown(false);
|
||||
currentBase = null;
|
||||
tilesSource = source;
|
||||
knownTiles.add(source);
|
||||
if (slots.photoreal?.key === url) return;
|
||||
show(
|
||||
'photoreal',
|
||||
@@ -201,7 +230,15 @@ export function createNavaraMaps(
|
||||
// them; Navara lists them in its attribution card, collapsed by default.
|
||||
view.attribution?.show();
|
||||
},
|
||||
releasePhotorealTiles(source) {
|
||||
if (!knownTiles.delete(source)) return;
|
||||
if (tilesSource !== source) return;
|
||||
tilesSource = null;
|
||||
clear('photoreal');
|
||||
view.forceUpdate();
|
||||
},
|
||||
photorealActive: () => slots.photoreal != null,
|
||||
current: () => ({ baseImagery: currentBase, photoreal: tilesSource }),
|
||||
};
|
||||
|
||||
return {
|
||||
|
||||
@@ -223,3 +223,58 @@ test('destroy removes every layer, source and credit it added', async () => {
|
||||
assert.deepEqual(view.sources, []);
|
||||
assert.deepEqual(view.shown, []);
|
||||
});
|
||||
|
||||
test('current() returns the passed sources: base while the globe shows, tiles while they show', async () => {
|
||||
const view = fakeView();
|
||||
const { maps } = createNavaraMaps(view);
|
||||
const osm = { kind: 'osm' };
|
||||
const esri = { kind: 'esri-imagery' };
|
||||
const tiles = { kind: 'photoreal', googleApiKey: 'k' };
|
||||
assert.deepEqual(maps.current(), { baseImagery: null, photoreal: null });
|
||||
await maps.setBaseImagery(osm);
|
||||
assert.deepEqual(maps.current(), { baseImagery: osm, photoreal: null });
|
||||
await maps.setPhotorealTiles(tiles);
|
||||
assert.equal(maps.current().baseImagery, null, 'tiles replace the base');
|
||||
assert.equal(maps.current().photoreal, tiles);
|
||||
// Imagery chosen while the tiles show goes on the hidden globe.
|
||||
await maps.setBaseImagery(esri);
|
||||
const [raster] = layersOf(view, 'raster');
|
||||
assert.match(raster.desc.source.desc.url, /World_Imagery/);
|
||||
assert.equal(raster.desc.raster?.show, false, 'the new layer shows over tiles');
|
||||
assert.ok(
|
||||
!view.shown.some((item) => /esri/i.test(JSON.stringify(item))),
|
||||
'its credit shows over tiles',
|
||||
);
|
||||
assert.equal(maps.current().baseImagery, esri);
|
||||
assert.equal(maps.current().photoreal, tiles);
|
||||
await maps.setPhotorealTiles(null);
|
||||
assert.deepEqual(maps.current(), { baseImagery: esri, photoreal: null });
|
||||
assert.notEqual(raster.desc.raster?.show, false, 'base not back');
|
||||
assert.ok(view.shown.some((item) => /esri/i.test(JSON.stringify(item))), 'credit not back');
|
||||
});
|
||||
|
||||
test('the same tiles under a new source object count as that source', async () => {
|
||||
const view = fakeView();
|
||||
const { maps } = createNavaraMaps(view);
|
||||
const first = { kind: 'photoreal', googleApiKey: 'k' };
|
||||
const second = { kind: 'photoreal', googleApiKey: 'k' };
|
||||
await maps.setPhotorealTiles(first);
|
||||
await maps.setPhotorealTiles(second);
|
||||
assert.equal(maps.current().photoreal, second);
|
||||
assert.equal(layersOf(view, '3d-tiles').length, 1);
|
||||
});
|
||||
|
||||
test('releasePhotorealTiles forgets the source and takes its tiles away if shown', async () => {
|
||||
const view = fakeView();
|
||||
const { maps } = createNavaraMaps(view);
|
||||
const tiles = { kind: 'photoreal', googleApiKey: 'k' };
|
||||
await maps.setPhotorealTiles(tiles);
|
||||
maps.releasePhotorealTiles({ kind: 'photoreal', googleApiKey: 'k' });
|
||||
assert.equal(maps.photorealActive(), true, 'another object released it');
|
||||
maps.releasePhotorealTiles(tiles);
|
||||
maps.releasePhotorealTiles(tiles);
|
||||
assert.equal(maps.photorealActive(), false);
|
||||
assert.equal(maps.current().photoreal, null);
|
||||
assert.equal(layersOf(view, '3d-tiles').length, 0);
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user