mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 02:44:02 +00:00
fix(street-level): sequence loads, playback and nearest-photo edge cases
From gekh's review of #768, each bug with a test that fails before: - P2: a failed sequence load clears the previous sequence's cones, resets the selection and can be retried; a second click while loading starts no second lookup. sequences.js had no tests: sequences.test.mjs now covers failure and retry, a superseded late answer, the cache and clearSelection. - P2: closing a photo stops MapillaryJS sequence playback, which kept the hidden viewer stepping and downloading images. - openNearest without the panel reports it instead of loading forever, and stops if the layer (or its provider) went off during the lookup; the mesh sampler's misses are bounded and forgotten with its samples; the sequence count is the union of ids across tiles; a provider withdraws only its own error, so a sequence error cannot mask KEY REJECTED; hover stays on (throttled) under an orbiting camera and re-picks when it stops; "since N days" follows the clock in a long-open tab. - A prewarm waits for one in flight and then builds if it gave up. - New coverage for the layer core (credits, KEY REJECTED vs REQUIRED, switching a provider off), the refresh wiring of the tilted-view fix and the draped-to-cast swap completion. - Cleanup: loading is derived from pending; freshStreet(); tile ranking computes distances once and shares one path for the date line; shared metresBetween / whenIdle / redrawTile; one NEAREST_RADIUS_M and one source method list; unused contract fields, exports, getImage and the decoder's image branch removed; PROVIDER_COLORS lists only Mapillary. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
48276450ec
commit
5f98b871e8
31 files changed
+1129
-470
No files matched your search
@@ -1,7 +1,11 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import * as Cesium from 'cesium';
|
||||
import { MESH_CELL_DEG, createMeshSampler } from './meshSampler.js';
|
||||
import {
|
||||
MESH_CELL_DEG,
|
||||
MESH_MISS_RETRY_MS,
|
||||
createMeshSampler,
|
||||
} from './meshSampler.js';
|
||||
|
||||
const settle = (ms = 60) => new Promise((resolve) => setTimeout(resolve, ms));
|
||||
const RAD = Math.PI / 180;
|
||||
@@ -78,3 +82,57 @@ test('far cells are skipped, misses are not latched, and nothing runs while disa
|
||||
assert.ok(Math.abs(probes[0].lon - 10.005) < MESH_CELL_DEG);
|
||||
sampler.destroy();
|
||||
});
|
||||
|
||||
/** Probes run on a 16 ms timer headless; with mocked timers, run them now. */
|
||||
function probeNow(t) {
|
||||
t.mock.timers.tick(20);
|
||||
}
|
||||
|
||||
test('a missed cell is probed again after the retry window, not before', (t) => {
|
||||
t.mock.timers.enable({ apis: ['setTimeout', 'Date'] });
|
||||
const { viewer, probes } = fakeViewer({ holes: () => true });
|
||||
const sampler = createMeshSampler({ getViewer: () => viewer });
|
||||
sampler.setEnabled(true);
|
||||
sampler.request([[10.001, 50]]);
|
||||
probeNow(t);
|
||||
assert.equal(probes.length, 1, 'probed, and missed');
|
||||
t.mock.timers.tick(MESH_MISS_RETRY_MS - 100);
|
||||
sampler.request([[10.001, 50]]);
|
||||
probeNow(t);
|
||||
assert.equal(probes.length, 1, 'within the window: not probed');
|
||||
t.mock.timers.tick(100 + 1);
|
||||
sampler.request([[10.001, 50]]);
|
||||
probeNow(t);
|
||||
assert.equal(probes.length, 2, 'after the window: probed again');
|
||||
sampler.destroy();
|
||||
});
|
||||
|
||||
test('remembered misses are bounded like the samples (review P3)', (t) => {
|
||||
t.mock.timers.enable({ apis: ['setTimeout', 'Date'] });
|
||||
const { viewer, probes } = fakeViewer({ holes: () => true });
|
||||
const sampler = createMeshSampler({ getViewer: () => viewer, cacheMax: 2 });
|
||||
sampler.setEnabled(true);
|
||||
for (const lon of [10.001, 10.002, 10.003]) {
|
||||
sampler.request([[lon, 50]]);
|
||||
probeNow(t);
|
||||
}
|
||||
assert.equal(probes.length, 3);
|
||||
// The third miss overflowed the list, which was dropped: the first cell
|
||||
// is asked about again rather than remembered forever.
|
||||
sampler.request([[10.001, 50]]);
|
||||
probeNow(t);
|
||||
assert.equal(probes.length, 4);
|
||||
sampler.destroy();
|
||||
});
|
||||
|
||||
test('destroy forgets the samples', (t) => {
|
||||
t.mock.timers.enable({ apis: ['setTimeout', 'Date'] });
|
||||
const { viewer } = fakeViewer();
|
||||
const sampler = createMeshSampler({ getViewer: () => viewer });
|
||||
sampler.setEnabled(true);
|
||||
sampler.request([[10.001, 50]]);
|
||||
probeNow(t);
|
||||
assert.equal(sampler.meshAt(10.001, 50), 100);
|
||||
sampler.destroy();
|
||||
assert.equal(sampler.meshAt(10.001, 50), undefined);
|
||||
});
|
||||
Reference in new issue
Block a user