mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 02:44:02 +00:00
feat(outlines): voice outlines without Overpass — bundled US places and neighborhoods, guarded Nominatim, OpenFreeMap streets and buildings
This commit is contained in:
1 parent
e7707d9a0f
commit
9559e7a282
333 files changed
+13203
-271
No files matched your search
@@ -0,0 +1,162 @@
|
||||
// Outline names are drawn by the DOM annotation overlay, never as Cesium
|
||||
// text labels: the boundary data modules, the outline resolver and the
|
||||
// annotation renderers must not import or construct Cesium label primitives,
|
||||
// and drawing a bundled outline must create none at runtime.
|
||||
import { test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import * as Cesium from 'cesium';
|
||||
import { FEATURE_SOURCE_METHODS } from '../sources/featureSource.js';
|
||||
import { createAnnotationResolver } from '../annotations/resolver.js';
|
||||
import { createWorldAnnotationRenderer } from '../annotations/worldAnnotationRenderer.js';
|
||||
|
||||
const read = (path) => readFileSync(new URL(path, import.meta.url), 'utf8');
|
||||
|
||||
/** Pure data modules: no Cesium at all. */
|
||||
const DATA_MODULES = [
|
||||
'./adminBoundaries.js',
|
||||
'./placeBoundaries.js',
|
||||
'./neighborhoodPolygons.js',
|
||||
'./local_data/us_census_places/files.js',
|
||||
'./local_data/wof_neighborhoods/files.js',
|
||||
];
|
||||
|
||||
/** Modules that use Cesium for outlines but must not draw text with it. */
|
||||
const CESIUM_MODULES = [
|
||||
'../annotations/resolver.js',
|
||||
'../annotations/worldAnnotationRenderer.js',
|
||||
'../annotations/hybridAnnotationRenderer.js',
|
||||
];
|
||||
|
||||
/** The DOM overlay: callout elements, never Cesium label primitives. */
|
||||
const OVERLAY_MODULES = ['../annotations/screenAnnotationRenderer.js'];
|
||||
|
||||
const LABEL_PRIMITIVES = [
|
||||
/\bLabelCollection\b/,
|
||||
/\bLabelGraphics\b/,
|
||||
/\bLabelStyle\b/,
|
||||
/\bLabelVisualizer\b/,
|
||||
];
|
||||
|
||||
/** Entity label options, inline or assigned later. */
|
||||
const ENTITY_LABELS = [
|
||||
// `label: { text: … }` or `label: new …`
|
||||
/\blabel\s*:\s*\{[^{}]*\btext\s*:/s,
|
||||
/\blabel\s*:\s*new\b/,
|
||||
// `label: labelOptions` (anything but `null`)
|
||||
/\blabel\s*:\s*(?!null\b)[A-Za-z_$][\w$]*\s*[,}\n]/,
|
||||
// `entity.label = …`
|
||||
/\.label\s*=(?!=)/,
|
||||
];
|
||||
|
||||
test('boundary data modules never import Cesium', () => {
|
||||
for (const path of DATA_MODULES) {
|
||||
const source = read(path);
|
||||
assert.doesNotMatch(source, /from\s+['"]cesium['"]/, path);
|
||||
assert.doesNotMatch(source, /import\(\s*['"]cesium['"]/, path);
|
||||
}
|
||||
});
|
||||
|
||||
test('outline modules and renderers construct no Cesium labels', () => {
|
||||
for (const path of [...DATA_MODULES, ...CESIUM_MODULES, ...OVERLAY_MODULES])
|
||||
for (const pattern of LABEL_PRIMITIVES)
|
||||
assert.doesNotMatch(read(path), pattern, `${path}: ${pattern}`);
|
||||
for (const path of [...DATA_MODULES, ...CESIUM_MODULES])
|
||||
for (const pattern of ENTITY_LABELS)
|
||||
assert.doesNotMatch(read(path), pattern, `${path}: ${pattern}`);
|
||||
});
|
||||
|
||||
test('the static check catches a Cesium label however it is written', () => {
|
||||
const offending = [
|
||||
'viewer.scene.primitives.add(new Cesium.LabelCollection());',
|
||||
"viewer.entities.add({ position, label: { text: 'Austin' } });",
|
||||
'const graphics = new LabelGraphics({ text });',
|
||||
'viewer.entities.add({ position, label: labelOptions });',
|
||||
'entity.label = new Cesium.LabelGraphics(options);',
|
||||
'entity.label = options;',
|
||||
];
|
||||
const all = [...LABEL_PRIMITIVES, ...ENTITY_LABELS];
|
||||
for (const source of offending)
|
||||
assert.ok(
|
||||
all.some((pattern) => pattern.test(source)),
|
||||
source,
|
||||
);
|
||||
// Data, not Cesium labels: a result's label point, a stripped proxy label.
|
||||
for (const source of [
|
||||
'label: geometry.label,',
|
||||
'liveProxy(anno, { label: null });',
|
||||
'if (entity.label === x) {}',
|
||||
])
|
||||
assert.ok(!ENTITY_LABELS.some((p) => p.test(source)), source);
|
||||
});
|
||||
|
||||
test('drawing bundled place and neighborhood outlines creates no Cesium label', async (t) => {
|
||||
// Cesium's material setup checks for these browser image types.
|
||||
for (const name of [
|
||||
'HTMLCanvasElement',
|
||||
'HTMLImageElement',
|
||||
'ImageBitmap',
|
||||
'OffscreenCanvas',
|
||||
]) {
|
||||
if (name in globalThis) continue;
|
||||
globalThis[name] = class {};
|
||||
t.after(() => delete globalThis[name]);
|
||||
}
|
||||
const featureSource = {};
|
||||
for (const method of FEATURE_SOURCE_METHODS)
|
||||
featureSource[method] = async () => null;
|
||||
const { resolveAnnotationTarget } = createAnnotationResolver({
|
||||
featureSource,
|
||||
});
|
||||
const primitives = [];
|
||||
const dataSources = [];
|
||||
const viewer = {
|
||||
camera: {
|
||||
positionCartographic: Cesium.Cartographic.fromDegrees(
|
||||
-97.7431,
|
||||
30.2672,
|
||||
3000,
|
||||
),
|
||||
},
|
||||
scene: { primitives: { add: (p) => primitives.push(p) } },
|
||||
dataSources: {
|
||||
add: (ds) => dataSources.push(ds),
|
||||
remove() {},
|
||||
},
|
||||
};
|
||||
const renderer = createWorldAnnotationRenderer(viewer);
|
||||
for (const [target, lon, lat] of [
|
||||
['Austin', -97.7431, 30.2672],
|
||||
['Notting Hill', -0.2, 51.511],
|
||||
]) {
|
||||
viewer.camera.positionCartographic = Cesium.Cartographic.fromDegrees(
|
||||
lon,
|
||||
lat,
|
||||
3000,
|
||||
);
|
||||
const resolved = await resolveAnnotationTarget({
|
||||
// The resolver reads only the camera (no scene to pick from).
|
||||
viewer: { camera: viewer.camera },
|
||||
target,
|
||||
footprint: true,
|
||||
deferFootprint: true,
|
||||
});
|
||||
assert.equal(resolved.source, 'bundled', target);
|
||||
renderer.add({
|
||||
id: target,
|
||||
type: 'area',
|
||||
label: resolved.label,
|
||||
ring: resolved.ring,
|
||||
polygons: resolved.polygons,
|
||||
footprintKind: resolved.footprintKind,
|
||||
synthesized: resolved.synthesized,
|
||||
anchor: { lon: resolved.lon, lat: resolved.lat, height: 0 },
|
||||
color: 'primary',
|
||||
});
|
||||
}
|
||||
assert.equal(primitives.length, 0, 'no primitive collections');
|
||||
const entities = dataSources.flatMap((ds) => ds.entities.values);
|
||||
assert.ok(entities.length >= 2, 'the outlines were drawn');
|
||||
for (const entity of entities) assert.equal(entity.label, undefined);
|
||||
renderer.destroy();
|
||||
});
|
||||
Reference in new issue
Block a user