refactor(street-level): remove the remaining duplicated code and fakes

A duplicate scan of every module the PR adds (repeated 4-line blocks,
normalised) after gekh's dedup round left these:

- glyphs.js: the cone, ring and position glyphs share cachedGlyph(), wedge(),
  ring() and dot(). Checked with a recording canvas: all 20 draw calls keep
  the same path and fill/stroke state, so the glyphs are pixel-identical.
- panelPositionControls.js: one placeAt() for the three places that pin a
  panel's top-left corner as a fixed window.
- tiles.js: one warn() for the three background-failure logs.
- Tests: src/testSupport/streetLevelFakes.mjs holds the provider snapshot
  (uiState + presentation tests), the stand-in provider (core + controls
  tests) and one real-ray pinhole camera (view + coverage tests, which had
  each written their own). The coverage line-of-sight test still fails when
  refresh() stops passing its focus.
- qa-street-level.mjs: one waitForCoverage() for the five copies of the
  "on, drawn, settled, not key-gated" wait.

No behaviour change: unit 5862 pass, fixture gate 16/16, panel gate 5/5.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
Said TurkseverandClaude Opus 5.5 committed 2026-10-06 14:27:58 +01:00
1 parent d70f468781
commit c2f1b54d00
12 files changed
+281 -345

No files matched your search

+151
View File
@@ -0,0 +1,151 @@
/**
* Shared stand-ins for the Street Level tests: a provider snapshot as the
* core reports it, the smallest provider definition the core accepts, and a
* camera whose screen rays really meet the ellipsoid they are given.
*/
import * as Cesium from 'cesium';
import { MAPILLARY_CREDIT_HTML } from '../layers/streetLevel/providers/mapillary/policy.js';
const RAD = Math.PI / 180;
/** One provider as `getUIState().providers` lists it. */
export function providerSnapshot(overrides = {}) {
return {
id: 'mapillary',
name: 'Mapillary',
label: 'MAPILLARY',
on: true,
configured: true,
keyRequired: false,
requiresKeyId: 'mapillary',
loading: false,
count: 0,
hint: '',
error: null,
color: '#05cb63',
...overrides,
};
}
/**
* The smallest provider definition the core accepts. `stats` is what
* coverageStats() answers (mutate it to change the answer), `calls` counts
* what the core asked of the provider and its viewer, `filters` lists every
* filter it was given and `context()` is the context the core created it with.
*/
export function fakeStreetLevelProvider({
id = 'mapillary',
pickPrefix = 'mly:',
html = MAPILLARY_CREDIT_HTML,
nearestImage = async () => null,
} = {}) {
const calls = { activate: 0, deactivate: 0, mount: 0, open: [], unmount: 0 };
const filters = [];
const stats = {
count: 0,
zoom: null,
kind: null,
loading: false,
hint: '',
error: null,
keyRequired: false,
};
let context = null;
return {
calls,
filters,
stats,
context: () => context,
id,
name: 'Mapillary',
label: 'MAPILLARY',
requiresKeyId: null,
pickPrefix,
colors: { coverage: '#05cb63' },
credit: { html },
create: (providerContext) => {
context = providerContext;
return {
status: async () => ({ configured: true }),
init() {},
activate: () => calls.activate++,
deactivate: () => calls.deactivate++,
destroy() {},
refreshCoverage() {},
setFilter: (filter) => filters.push(filter),
coverageStats: () => ({ ...stats }),
handlePick: () => false,
nearestImage,
viewer: {
mount: async () => calls.mount++,
open: async (imageId) => calls.open.push(imageId),
close() {},
unmount: () => calls.unmount++,
resize() {},
onPose: () => () => {},
},
};
},
};
}
/**
* A pinhole camera at `altitude` metres above the WGS84 ellipsoid, looking
* along `heading` (degrees from north) and `pitch` (degrees, negative is
* down), over a `width`×`height` canvas with the given fields of view. Its
* `pickEllipsoid` intersects whatever ellipsoid it is given, as Cesium's does.
*/
export function rayCamera({
lon,
lat,
altitude,
heading = 0,
pitch,
width = 1600,
height = 900,
fovY = 60,
fovX = null,
}) {
const position = Cesium.Cartesian3.fromDegrees(lon, lat, altitude);
const frame = Cesium.Transforms.eastNorthUpToFixedFrame(position);
const h = heading * RAD;
const p = pitch * RAD;
// East-north-up axes of the view: forward, right and up.
const forward = [
Math.sin(h) * Math.cos(p),
Math.cos(h) * Math.cos(p),
Math.sin(p),
];
const right = [Math.cos(h), -Math.sin(h), 0];
const up = [
-Math.sin(h) * Math.sin(p),
-Math.cos(h) * Math.sin(p),
Math.cos(p),
];
const halfY = Math.tan((fovY / 2) * RAD);
const halfX =
fovX == null ? halfY * (width / height) : Math.tan((fovX / 2) * RAD);
return {
positionWC: position,
positionCartographic: Cesium.Cartographic.fromDegrees(lon, lat, altitude),
pickEllipsoid(point, ellipsoid = Cesium.Ellipsoid.WGS84) {
const sx = ((2 * point.x) / width - 1) * halfX;
const sy = (1 - (2 * point.y) / height) * halfY;
const local = [0, 1, 2].map(
(i) => forward[i] + sx * right[i] + sy * up[i],
);
const direction = Cesium.Cartesian3.normalize(
Cesium.Matrix4.multiplyByPointAsVector(
frame,
new Cesium.Cartesian3(...local),
new Cesium.Cartesian3(),
),
new Cesium.Cartesian3(),
);
const ray = new Cesium.Ray(position, direction);
const hit = Cesium.IntersectionTests.rayEllipsoid(ray, ellipsoid);
return hit ? Cesium.Ray.getPoint(ray, hit.start) : undefined;
},
computeViewRectangle: () => undefined,
};
}