mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-11 13:52:19 +00:00
Check the photoreal paths in the browser on a synthetic 3D Tiles set
A generated tileset (a plate at ellipsoid level, 50 m and 200 m blocks and a pitched roof, 27 KB) replaces Google's tiles when a QA page passes ?qaTileset=/path; only a root-relative path on the page origin is accepted, and the Google credit is not shown for it. The strict harness serves the set from disk, so nothing reaches Google. qa-tiles-fixture checks on both engines that sampleHeight reads the block at 50 m, clampToHeight lands on the roof, tiles and terrain drapes draw where they should, tilesLoaded turns true, surface points land on the roof within their budget, and pick renders per pass stay within it.
This commit is contained in:
1 parent
a90407d547
commit
e9ba5e9859
17 files changed
+1855
-20
No files matched your search
@@ -0,0 +1,8 @@
|
||||
import { Cesium3DTileset } from 'cesium';
|
||||
import { localTilesetPath } from '../../maps/qaTileset.js';
|
||||
|
||||
/** The QA source uses the controller's normal tileset ownership path. */
|
||||
export function createQaTileset(url, { signal } = {}) {
|
||||
signal?.throwIfAborted();
|
||||
return Cesium3DTileset.fromUrl(localTilesetPath(url));
|
||||
}
|
||||
+16
-10
@@ -22,6 +22,7 @@ import {
|
||||
SENTINEL2_MAX_ZOOM,
|
||||
SENTINEL2_URL,
|
||||
} from '../../maps/sentinel2.js';
|
||||
import { localTilesetPath } from '../../maps/qaTileset.js';
|
||||
|
||||
const OSM_URL = 'https://tile.openstreetmap.org/{z}/{x}/{y}.png';
|
||||
const OSM_CREDIT = {
|
||||
@@ -280,12 +281,15 @@ export function createNavaraMaps(
|
||||
return;
|
||||
}
|
||||
const key = String(source.googleApiKey || '').trim();
|
||||
if (!key)
|
||||
const tilesetUrl = localTilesetPath(source.tilesetUrl);
|
||||
if (!tilesetUrl && !key)
|
||||
throw new Error(
|
||||
'Google 3D tiles on Navara need a browser key (googleApiKey)',
|
||||
);
|
||||
if (destroyed || generation !== generations.display) return;
|
||||
const url = `${GOOGLE_TILES_ROOT}?key=${encodeURIComponent(key)}`;
|
||||
const url = tilesetUrl
|
||||
? new URL(tilesetUrl, globalThis.location.origin).href
|
||||
: `${GOOGLE_TILES_ROOT}?key=${encodeURIComponent(key)}`;
|
||||
setImageryShown(false);
|
||||
currentBase = null;
|
||||
tilesSource = source;
|
||||
@@ -296,17 +300,19 @@ export function createNavaraMaps(
|
||||
url,
|
||||
{ type: '3d-tiles', url },
|
||||
{ type: '3d-tiles', model: { maxSse: PHOTOREAL_MAX_SSE } },
|
||||
[
|
||||
(layer) => ({
|
||||
attribution: 'Google',
|
||||
logo: GOOGLE_LOGO,
|
||||
creditLayerId: layer.id,
|
||||
}),
|
||||
],
|
||||
tilesetUrl
|
||||
? []
|
||||
: [
|
||||
(layer) => ({
|
||||
attribution: 'Google',
|
||||
logo: GOOGLE_LOGO,
|
||||
creditLayerId: layer.id,
|
||||
}),
|
||||
],
|
||||
);
|
||||
// Google's terms want its copyright lines on screen, as Cesium shows
|
||||
// them; Navara lists them in its attribution card, collapsed by default.
|
||||
view.attribution?.show();
|
||||
if (!tilesetUrl) view.attribution?.show();
|
||||
},
|
||||
releasePhotorealTiles(source) {
|
||||
if (!knownTiles.delete(source)) return;
|
||||
|
||||
@@ -408,6 +408,7 @@ export class MapSourceController {
|
||||
descriptor: source.descriptor,
|
||||
kind: source.descriptor.kind,
|
||||
credit: source.credit ?? null,
|
||||
...(source.tilesetUrl && { tilesetUrl: source.tilesetUrl }),
|
||||
...(source.googleApiKey && { googleApiKey: source.googleApiKey }),
|
||||
...(source.cesiumToken && { cesiumToken: source.cesiumToken }),
|
||||
...(tileset && { tileset }),
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
} from '../globe/cesium/mapImagery.js';
|
||||
import { terrainSourceFor } from '../globe/cesium/terrain.js';
|
||||
import { t } from '../i18n/index.js';
|
||||
import { localTilesetPath, qaTilesetUrl } from './qaTileset.js';
|
||||
|
||||
const navaraIonImageryReason = () =>
|
||||
t('Bing imagery is not available on the experimental Navara engine');
|
||||
@@ -24,10 +25,12 @@ export function createDefaultMapSources({
|
||||
cesiumToken = '',
|
||||
googleApiKey = '',
|
||||
engineKind = 'cesium',
|
||||
tilesetUrl = qaTilesetUrl(),
|
||||
} = {}) {
|
||||
if (engineKind !== 'cesium' && engineKind !== 'navara')
|
||||
throw new TypeError(`Unknown globe engine: ${engineKind}`);
|
||||
const navara = engineKind === 'navara';
|
||||
tilesetUrl = localTilesetPath(tilesetUrl);
|
||||
const ionToken = String(cesiumToken || '').trim();
|
||||
const hasIon = Boolean(ionToken);
|
||||
// Engine-neutral descriptions ride beside the Cesium factories: a terrain
|
||||
@@ -40,7 +43,8 @@ export function createDefaultMapSources({
|
||||
};
|
||||
const googleKey = String(googleApiKey || '').trim();
|
||||
const hasGoogle = Boolean(googleKey);
|
||||
const photorealAvailable = navara ? hasGoogle : Boolean(googleTileset);
|
||||
const photorealAvailable =
|
||||
Boolean(tilesetUrl) || (navara ? hasGoogle : Boolean(googleTileset));
|
||||
return {
|
||||
defaultId: photorealAvailable ? 'photoreal' : 'esri-imagery',
|
||||
unknownId: 'photoreal',
|
||||
@@ -69,7 +73,15 @@ export function createDefaultMapSources({
|
||||
photorealUnavailableReason(
|
||||
navara ? hasGoogle : hasIon || hasGoogle,
|
||||
),
|
||||
tileset: googleTileset,
|
||||
tileset: tilesetUrl ? null : googleTileset,
|
||||
...(tilesetUrl && {
|
||||
tilesetUrl,
|
||||
createTileset: async (options) => {
|
||||
const { createQaTileset } =
|
||||
await import('../globe/cesium/qaTileset.js');
|
||||
return createQaTileset(tilesetUrl, options);
|
||||
},
|
||||
}),
|
||||
...(googleKey && { googleApiKey: googleKey }),
|
||||
...(hasIon && { cesiumToken: ionToken }),
|
||||
};
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
/** Only a root-relative path on this page may replace the photoreal source. */
|
||||
export function localTilesetPath(value, location = globalThis.location) {
|
||||
if (!value) return null;
|
||||
if (
|
||||
typeof value !== 'string' ||
|
||||
!/^\/(?!\/)/.test(value) ||
|
||||
/[\\\s\u0000-\u001f\u007f]/.test(value) ||
|
||||
!location?.origin
|
||||
)
|
||||
throw new TypeError('tilesetUrl must be a path on the page origin');
|
||||
const url = new URL(value, location.origin);
|
||||
if (url.origin !== location.origin || url.search || url.hash)
|
||||
throw new TypeError('tilesetUrl must be a path on the page origin');
|
||||
return url.pathname;
|
||||
}
|
||||
|
||||
// Like parkedMs, this explicit QA parameter is inert on an ordinary page.
|
||||
export function qaTilesetUrl() {
|
||||
return localTilesetPath(
|
||||
new URLSearchParams(globalThis.location?.search).get('qaTileset'),
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user