From 5ff8c5d7a64573b2f04ffd6ba7f412a76c9e9e92 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Sat, 17 Oct 2026 11:02:52 +0400 Subject: [PATCH] test(qa): floor verification reads the app's ground floor and measures models where drawn - The DEM prior column read a fresh import of src/data/groundFloor.js, a module the app does not use for its layers (they read the scene's surface services), so it was null for every contact. It now reads window.__godsEyeView.surfaceServices.groundFloor. The terrain proxy answers 200 and the AUS cells resolve within one or two polls (123-128 m); the "proxy 503" reading in the task-11 report was this misread. - A contact a 3D model draws is measured at the model's translation (the probe's drawn() reports it now): its sprite is hidden and keeps the pre-floor height by design (T7), so measuring the sprite reported a buried aircraft that is not drawn. --- scripts/qa-floor-verify.mjs | 24 +++++++++++++++++++++--- src/layers/aircraft/qaDrawn.js | 7 +++++++ 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/scripts/qa-floor-verify.mjs b/scripts/qa-floor-verify.mjs index 22f842afe..2bcfcf1c9 100644 --- a/scripts/qa-floor-verify.mjs +++ b/scripts/qa-floor-verify.mjs @@ -100,10 +100,20 @@ const report = await page.evaluate(async () => { const center = geo.cartesian3.fromDegrees(window.__QA_SITE.lon, window.__QA_SITE.lat, 200); const nearby = layer.getNearby(center, 15000, 60); const exclude = engine.movers.list().map(({ id }) => id).filter((id) => id.startsWith('flights')); - const { cachedGroundFloor } = await import('/src/data/groundFloor.js'); + // The app's own ground floor (the scene's surface services, not a fresh + // import of the module). + const { cachedGroundFloor } = gev.surfaceServices.groundFloor; const out = []; + // A contact a 3D model draws is measured where the model is (its sprite + // is hidden and keeps the pre-floor height by design, T7). + const drawnRows = new Map((gev.layers.drawn('flights') ?? []).map((row) => [row.id, row])); + const drawnAt = (p) => { + const model = drawnRows.get(p.id)?.model; + return model?.show && model.ready && model.position ? model.position : null; + }; for (const p of nearby) { - const c = geo.cartographic.fromCartesian(p.position); + const modelAt = drawnAt(p); + const c = geo.cartographic.fromCartesian(modelAt ?? p.position); const answer = engine.surface.sampleHeightDetailed( geo.cartographic.fromRadians(c.longitude, c.latitude, 0), { exclude }, @@ -112,6 +122,7 @@ const report = await page.evaluate(async () => { out.push({ id: p.id, renderAltM: +c.height.toFixed(1), + drawnBy: modelAt ? 'model' : 'sprite', meshM: meshH != null ? +meshH.toFixed(1) : null, aboveMeshM: meshH != null ? +(c.height - meshH).toFixed(1) : null, // Why a contact sits where it does (10b review 6): the probe's own @@ -153,9 +164,15 @@ const report = await page.evaluate(async () => { } }; walk(v.scene.primitives); + const drawnRows = new Map((gev.layers?.drawn('flights') ?? []).map((row) => [row.id, row])); + const drawnAt = (p) => { + const model = drawnRows.get(p.id)?.model; + return model?.show && model.ready && model.position ? model.position : null; + }; const out = []; for (const p of nearby) { - const c = ell.cartesianToCartographic(p.position); + const modelAt = drawnAt(p); + const c = ell.cartesianToCartographic(modelAt ?? p.position); const latDeg = c.latitude * 180 / Math.PI, lonDeg = c.longitude * 180 / Math.PI; let meshH = null; try { @@ -165,6 +182,7 @@ const report = await page.evaluate(async () => { out.push({ id: p.id, renderAltM: +c.height.toFixed(1), + drawnBy: modelAt ? 'model' : 'sprite', meshM: meshH != null ? +meshH.toFixed(1) : null, aboveMeshM: meshH != null ? +(c.height - meshH).toFixed(1) : null, }); diff --git a/src/layers/aircraft/qaDrawn.js b/src/layers/aircraft/qaDrawn.js index 24ade0dcc..4a2fd087e 100644 --- a/src/layers/aircraft/qaDrawn.js +++ b/src/layers/aircraft/qaDrawn.js @@ -9,6 +9,11 @@ * handle), `_models` (id → model handle), `_trackedIcao`, `_trackedModel`. * @returns {Array} */ +const translationOf = (matrix) => + matrix && Number.isFinite(matrix[12]) + ? { x: matrix[12], y: matrix[13], z: matrix[14] } + : null; + export function aircraftQaDrawn(state) { const out = []; for (const [id, sprite] of state._billboards) { @@ -36,6 +41,8 @@ export function aircraftQaDrawn(state) { computedScale: model.computedScale, show: model.show, ready: model.ready, + // Where it is drawn: its transform's translation. + position: translationOf(model.modelMatrix), } : null, });