fix(street-level): address gekh's review of #768

P0
- tileMath: lonToTileX(180) wrapped to column 0, so a whole-world view at
  z1 loaded only the western column; 180 is now the last column.
- coverage.loadTile: a superseded request (after a retire or clear) still
  deleted the newer request's pending entry and loading count in `finally`,
  letting a duplicate load attach lines that nothing could remove. Only the
  request that still owns the key attaches its tile or settles the key.

P1
- view/tileMath: a view across the date line read as a ~358 deg box and
  loaded tiles on the far side of the globe. visibleBbox now returns
  west > east for such views and tilesForBbox splits them at +/-180;
  viewCentre averages across the line.
- decode: the parts of a multi-line sequence were joined into one line,
  drawing straight segments over capture gaps. Each part is now its own
  line (`parts`); later parts carry `~n` in their pick id, and picking or
  recolouring any part acts on the whole sequence.
- viewerHost: a prewarmed MapillaryJS viewer was never destroyed, leaking
  its WebGL context. Prewarmed adapters are tracked and released on
  unmount, at once when the layer went off mid-load, and per provider when
  only that provider is switched off.
- nearestImage took the first record the API returned; it now takes the
  closest one that passes the filter.

P2
- groundCast: the cache was cleared after a request counted its corners,
  dropping ones it relied on; it is now cleared first.
- streetLevelControls: the viewer was resized on every render (every frame
  while a panorama is dragged); the ResizeObserver handles size changes and
  the viewer is resized once when it opens. The legend now rebuilds when its
  entries change, not only their count.
- panelPositionControls: the portable-panel paths this PR added called the
  CCTV viewport sync directly; they go through onPanelResized, which the
  shell routes to CCTV. The "Compose camera panel controls" JSDoc is back on
  _initCctvPanel.

New tests: zoom-1 columns, date-line tiles and bbox, multi-part decode and
part pick ids, nearest image, prewarmed viewer release, and the cache
ordering (fails on the old order).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
Said TurkseverandClaude Opus 5.5 committed 2026-10-02 19:00:01 +01:00
1 parent 514788303d
commit a1f8d6ca25
17 files changed
+435 -117

No files matched your search

+35 -1
View File
@@ -1,6 +1,7 @@
import assert from 'node:assert/strict';
import test from 'node:test';
import { cameraHeightAboveGround } from './view.js';
import * as Cesium from 'cesium';
import { cameraHeightAboveGround, viewCentre, visibleBbox } from './view.js';
const RAD = Math.PI / 180;
/** A viewer 300 m above a street 1,600 m up (Denver-like). */
@@ -42,3 +43,36 @@ test('with no ground sample the ellipsoidal height is used', () => {
assert.equal(cameraHeightAboveGround(hidden, { groundAt: () => null }), 1900);
assert.equal(cameraHeightAboveGround({}), null);
});
/** A camera whose screen rays land on a grid of lon/lat points. */
function gridViewer(lons, lats) {
const points = [];
for (const lat of lats)
for (const lon of lons)
points.push(Cesium.Cartesian3.fromDegrees(lon, lat));
let next = 0;
return {
scene: { canvas: { clientWidth: 100, clientHeight: 100 }, globe: {} },
camera: {
pickEllipsoid: () => points[next++ % points.length],
positionCartographic: { longitude: 0, latitude: 0, height: 1000 },
},
};
}
test('a view across the date line is a narrow box with west > east', () => {
const viewer = gridViewer([178, 179, -179, -178], [-1, 0, 1]);
const bbox = visibleBbox(viewer);
assert.ok(bbox[0] > 177 && bbox[0] < 179, `west ${bbox[0]}`);
assert.ok(bbox[2] < -177 && bbox[2] > -179, `east ${bbox[2]}`);
const centre = viewCentre(viewer);
assert.ok(Math.abs(Math.abs(centre.lon) - 180) < 0.5, `centre ${centre.lon}`);
});
test('an ordinary view keeps west < east', () => {
const bbox = visibleBbox(gridViewer([10, 11, 12], [50, 51]));
assert.ok(bbox[0] < bbox[2]);
assert.ok(
Math.abs(viewCentre(gridViewer([10, 11, 12], [50, 51])).lon - 11) < 1e-6,
);
});