mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-06 03:14:00 +00:00
fix(transit): keep the real silhouettes under sensor presets, make the selected trail visible, put Transit in Movement (#596)
## Changes Follow-up to #587 after the owner's first look at the merged transit layer on Google 3D tiles. - **Sensor presets keep the real silhouettes.** Under NVG, thermal (white-hot, black-hot, Ironbow) and noir, vehicles are the same silhouettes as in normal view, filled opaque white with a 2 px dark halo, at the CRT display sizes (26 px fleet, 39 px selected). The solid rounded "signature" bodies are gone. - **The selected vehicle's trail is visible.** The retained history is now draped onto 3D tiles and terrain (`GroundPolylinePrimitive`, `ClassificationType.BOTH`, the way the traffic heat-lines are drawn), 3 px core over a 5 px dark backing, per-segment age colour, a short draped head clipped to the sprite. Two defects kept it off screen before: Cesium's per-instance attribute getters return copies, so the renderer's show/colour edits were discarded, and a marker did not recover after the camera jumped to it, which hid the trail with it. Trail geometry is now prepared on selection independent of floor resolution and marker visibility; sparse long intervals (rail) keep a bounded marker corridor instead of dropping the interval; classification survives map-source changes. - **Transit sits in the Movement panel group** between Street Traffic and Bike Share (the panel orders by `PANEL_GROUPS`, not by catalog order; the catalog is moved too). ## How it was verified - `npm run format:check` (854 files), `npm run check:boundaries`, `npm test` (4,062 passing), `npm run build` clean; tracking regression 109/109 in a real browser on Google 3D tiles. - Browser harness (`scripts/qa-transit.mjs`), keyed on Google 3D tiles and keyless: keyed 194 pass, with the trail pixel check passing at 300, 600 and 900 m; the remaining keyed failures are the per-frame allocation gate already recorded as a follow-up from #587 (CPU and frame time within budget), four readability lines at threshold edges, and the card-anchor check now counting frames where the selected marker is legitimately off screen; keyless 193 pass with the remaining misses being threshold edges on the thin tram silhouette (centre 0.83–0.88 against 0.85) and one bus ring 0.28 against 0.25 on a pure-white roof. - New harness checks: `Google 3D selected trail visible at 6 of 8 projected samples` (repeated off/on framebuffer captures at 300/600/900 m, samples outside the sprite footprint, a background-change negative control; fails on main, passes here), a camera-arrival check (select a moving vehicle, `setView` onto it, marker shown and trail body drawn within 2 s), `PANEL_ORDER` pinned, raster tests comparing every sensor raster's mask and aspect ratio to the normal silhouette. - Direct look on a keyed build: a live CapMetro bus at 30 m/s selected through the layer API draws its draped trail along the highway lane (harness capture `keyed-600m-trail-visible.jpg`). - Adversarial review by Codex Astra before the last two fix passes (stack-switch classification, marker corridor under the vertex cap, pixel-gate loophole), all three fixed with regressions. Docs: `docs/CURRENT-STATE.md` and `CHANGELOG.md` updated in this PR. No data-source changes.
This commit is contained in:
1 parent
cd22ca3559
commit
0bb61f53c6
24 files changed
+1945
-205
No files matched your search
@@ -328,6 +328,7 @@ test('sensor sampler waits for postRender and reads framebuffer pixels; stopped
|
||||
globalThis.Image = previousImage;
|
||||
});
|
||||
const identity = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
|
||||
const readRows = [];
|
||||
let listener,
|
||||
reads = 0,
|
||||
render = true;
|
||||
@@ -336,6 +337,7 @@ test('sensor sampler waits for postRender and reads framebuffer pixels; stopped
|
||||
UNSIGNED_BYTE: 2,
|
||||
readPixels(x, y, w, h, format, type, buffer) {
|
||||
reads++;
|
||||
readRows.push(y);
|
||||
buffer.set([255, 255, 255, 255]);
|
||||
},
|
||||
};
|
||||
@@ -408,13 +410,70 @@ test('sensor sampler waits for postRender and reads framebuffer pixels; stopped
|
||||
},
|
||||
};
|
||||
const page = { evaluate: async (fn, ...args) => fn(...args) };
|
||||
const sampledLayer =
|
||||
window.__godsEyeView.dataManager.layers.get('transit').module;
|
||||
const originalState = sampledLayer._transitStateForTest;
|
||||
sampledLayer._transitStateForTest = () => {
|
||||
const state = originalState();
|
||||
state._vehicles.get('bus').marker.position.y = 0.0025; // Screen y = 199.5.
|
||||
return state;
|
||||
};
|
||||
const pixels = await sampleTransitPixels(page, {});
|
||||
sampledLayer._transitStateForTest = originalState;
|
||||
assert.deepEqual(
|
||||
readRows.slice(0, 9),
|
||||
[201, 200, 199, 201, 200, 199, 201, 200, 199],
|
||||
'fractional CSS coordinates must invert the floored framebuffer row',
|
||||
);
|
||||
assert.ok(
|
||||
reads >= 13,
|
||||
'centre, rings and background come from WebGL readPixels',
|
||||
);
|
||||
assert.ok(Math.abs(pixels[0].centre - 1) < 1e-6);
|
||||
assert.equal(listener, null);
|
||||
// An opaque window/panel is not a sensor core. Choose another solid patch,
|
||||
// and reject a raster with no white interior even though alpha/picking pass.
|
||||
for (let i = 0; i < raster.length; i += 4) raster.fill(0, i, i + 3);
|
||||
assert.equal((await sampleTransitPixels(page, {})).length, 0);
|
||||
raster.fill(255);
|
||||
for (let y = 6; y <= 9; y++)
|
||||
for (let x = 0; x < 16; x++) {
|
||||
const i = (y * 16 + x) * 4;
|
||||
raster.fill(0, i, i + 3);
|
||||
}
|
||||
assert.equal(
|
||||
(await sampleTransitPixels(page, {})).length,
|
||||
1,
|
||||
'a body patch away from the central panel remains eligible',
|
||||
);
|
||||
// A narrow centre can be opaque yet put the framebuffer sample on its
|
||||
// antialiased side. Prefer the wider solid band above it, before reading luma.
|
||||
raster.fill(0);
|
||||
for (let y = 0; y < 16; y++)
|
||||
for (let x = 0; x < 16; x++) {
|
||||
const wide = y >= 3 && y <= 5;
|
||||
if ((wide && x >= 3 && x <= 12) || (x >= 7 && x <= 9))
|
||||
raster.fill(255, (y * 16 + x) * 4, (y * 16 + x + 1) * 4);
|
||||
}
|
||||
const readStart = readRows.length;
|
||||
assert.equal((await sampleTransitPixels(page, {})).length, 1);
|
||||
assert.ok(
|
||||
readRows[readStart] > 204,
|
||||
'centre samples use the widest solid band',
|
||||
);
|
||||
raster.fill(255);
|
||||
sampledLayer._transitStateForTest = () => {
|
||||
const state = originalState();
|
||||
state._vehicles.get('bus').mode = 'tram';
|
||||
return state;
|
||||
};
|
||||
const tramStart = readRows.length;
|
||||
assert.equal((await sampleTransitPixels(page, {})).length, 1);
|
||||
assert.ok(
|
||||
readRows[tramStart] > 204,
|
||||
'equal-width tram bands prefer the upper solid body',
|
||||
);
|
||||
sampledLayer._transitStateForTest = originalState;
|
||||
scene.pick = () => ({ id: 'overlapping-label' });
|
||||
assert.equal(
|
||||
(await sampleTransitPixels(page, {})).length,
|
||||
|
||||
Reference in new issue
Block a user