diff --git a/scripts/qa-floor-verify.mjs b/scripts/qa-floor-verify.mjs index 97b1483dd..756f4cfe3 100644 --- a/scripts/qa-floor-verify.mjs +++ b/scripts/qa-floor-verify.mjs @@ -10,7 +10,12 @@ import fs from 'node:fs'; // QA_BASE_URL matches the sibling harnesses (qa-height-datum / qa-cctv-v2) so a // secondary checkout can verify against its own dev server instead of the default :4173. -const APP_URL = process.env.QA_BASE_URL || 'http://localhost:4173'; +const BASE_URL = process.env.QA_BASE_URL || 'http://localhost:4173'; +// --engine=cesium|navara (phase 3): on Navara the camera, the mesh probes and +// the sprite census go through the engine and the QA probe. +const ENGINE = (process.argv.find((arg) => arg.startsWith('--engine=')) ?? '--engine=cesium').slice(9); +const APP_URL = + ENGINE === 'cesium' ? BASE_URL : `${BASE_URL.replace(/\/$/, '')}/?engine=${ENGINE}`; // CLI: --lat --lon --floor-min --floor-max (defaults: Austin airport) const argv = Object.fromEntries(process.argv.slice(2).map((a) => a.split('=')).filter((x) => x.length === 2).map(([k, v]) => [k.replace(/^--/, ''), Number(v)])); const SITE = { @@ -38,7 +43,7 @@ const page = await browser.newPage(); await page.setViewport({ width: 1400, height: 900 }); page.on('pageerror', (e) => console.log('[pageerror]', e.message)); await page.goto(APP_URL, { waitUntil: 'domcontentloaded', timeout: 120000 }); -await page.waitForFunction(() => window.__godsEyeView?.dataManager && window.__godsEyeView?.viewer, { timeout: 150000 }); +await page.waitForFunction(() => window.__godsEyeView?.dataManager && window.__godsEyeView?.engine, { timeout: 150000 }); await sleep(2000); // Let the app's boot fly-to fully settle FIRST (it was overriding an early @@ -46,8 +51,16 @@ await sleep(2000); // coarse global tiles at ~25 m and the oracle was garbage). await sleep(12000); await page.evaluate((site) => { window.__QA_SITE = site; }, SITE); -const camPin = async () => page.evaluate(() => { +const camPin = async () => page.evaluate(async () => { const v = window.__godsEyeView.viewer; + if (!v) { + const geo = await import('/src/geo/index.js'); + const { camera } = window.__godsEyeView.engine; + camera.cancelFlight(); + camera.setView({ destination: geo.cartesian3.fromDegrees(window.__QA_SITE.lon, window.__QA_SITE.lat, 3000) }); + const c = camera.pose().cartographic; + return { lat: +(c.latitude * 180 / Math.PI).toFixed(3), lon: +(c.longitude * 180 / Math.PI).toFixed(3), h: Math.round(c.height) }; + } const C = v.camera.positionCartographic.constructor; v.camera.cancelFlight(); v.camera.setView({ destination: v.scene.globe.ellipsoid.cartographicToCartesian(C.fromDegrees(window.__QA_SITE.lon, window.__QA_SITE.lat, 3000)) }); @@ -63,6 +76,7 @@ await sleep(100000); console.log('camera at probe time:', JSON.stringify(await camPin())); const ready = await page.evaluate(() => { const v = window.__godsEyeView.viewer; + if (!v) return { tilesLoaded: window.__godsEyeView.engine.surface.tilesLoaded() }; const prims = v.scene.primitives; for (let i = 0; i < prims.length; i++) { const p = prims.get(i); @@ -73,11 +87,44 @@ const ready = await page.evaluate(() => { console.log('tileset ready:', JSON.stringify(ready)); await sleep(8000); -const report = await page.evaluate(() => { +const report = await page.evaluate(async () => { const gev = window.__godsEyeView; const v = gev.viewer; const layer = gev.dataManager.layers.get('flights')?.module; if (!layer) return { err: 'no flights module' }; + if (!v) { + // The engine path: mesh probes through engine.surface, excluding the + // layer's own mover sets; the census from the probe's drawn(). + const geo = await import('/src/geo/index.js'); + const { engine } = gev; + 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 out = []; + for (const p of nearby) { + const c = geo.cartographic.fromCartesian(p.position); + const answer = engine.surface.sampleHeightDetailed( + geo.cartographic.fromRadians(c.longitude, c.latitude, 0), + { exclude }, + ); + const meshH = answer?.source === 'tiles' && Number.isFinite(answer.height) ? answer.height : null; + out.push({ + id: p.id, + renderAltM: +c.height.toFixed(1), + meshM: meshH != null ? +meshH.toFixed(1) : null, + aboveMeshM: meshH != null ? +(c.height - meshH).toFixed(1) : null, + }); + } + let shown = 0, hidden = 0; + for (const row of gev.layers.drawn('flights') ?? []) { + if (!row.position) continue; + const cc = geo.cartographic.fromCartesian(row.position); + const la = cc.latitude * 180 / Math.PI, lo = cc.longitude * 180 / Math.PI; + if (Math.abs(la - window.__QA_SITE.lat) > 0.08 || Math.abs(lo - window.__QA_SITE.lon) > 0.10) continue; + if (row.show) shown++; else hidden++; + } + return { ausContacts: out.length, contacts: out.slice(0, 16), spritesShown: shown, spritesHidden: hidden }; + } const ell = v.scene.globe.ellipsoid; const C = v.camera.positionCartographic.constructor; const center = ell.cartographicToCartesian(C.fromDegrees(window.__QA_SITE.lon, window.__QA_SITE.lat, 200));