mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 19:04:02 +00:00
feat(cctv): seven camera packs, semantic labels, terrain-clear monitor planes (#433)
Seven contributed CCTV camera packs (Ontario 511, Fintraffic Finland, DriveBC, TxDOT Texas, Estonia Tallinn + Tarktee, Warendorf, Live Traffic NSW) on a fair per-pack catalog cap; semantic camera labels; monitor planes lifted clear of the terrain from a precomputed, bundled ground-height dataset. Default catalog 800 → 3,446 cameras. Full context in PR #433. Co-authored-by: sendmebits <[email protected]> Co-authored-by: avocadoAgent <[email protected]> Co-authored-by: Alex Harvey <[email protected]> Co-authored-by: Jason Meredith <[email protected]> Co-authored-by: Daniel Smith <[email protected]> Co-authored-by: Vladimir Sobolev <[email protected]> Co-authored-by: Matthias Schneider <[email protected]> Co-authored-by: Cyber Knight <[email protected]> Co-authored-by: NovaSoft Australia <[email protected]>
This commit is contained in:
51 files changed
+78682
-939
No files matched your search
@@ -1,3 +1,12 @@
|
||||
import {
|
||||
SUPPORT_KEYS,
|
||||
planeSupportPoints,
|
||||
poseHash,
|
||||
} from '../../data/cctvFootprint.js';
|
||||
|
||||
/** Cooldown before a provisional (geoid-fallback / partial) footprint is retried. */
|
||||
const FOOTPRINT_RETRY_MS = 60_000;
|
||||
|
||||
export function createGround({ state: layerState, services, parts, source }) {
|
||||
const { resolveGroundFloorCells } = services.ground;
|
||||
const { resolveEllipsoidalGround } = services.terrain;
|
||||
@@ -248,8 +257,13 @@ export function createGround({ state: layerState, services, parts, source }) {
|
||||
}
|
||||
const ground = groundAltFor(record, regime);
|
||||
// Skip the entity rewrite when the applied ground already matches (e.g.
|
||||
// entering google-3d before any sample: prior → prior is a no-op).
|
||||
// entering google-3d before any sample: prior → prior is a no-op) —
|
||||
// unless the record has a footprint source, whose eligibility depends
|
||||
// on the regime (shipped mesh samples apply in google-3d only).
|
||||
const hasFootprintSource =
|
||||
!!record.camera?.groundHeights || !!record.footprintGround;
|
||||
if (
|
||||
!hasFootprintSource &&
|
||||
record.frustumGeometry &&
|
||||
Math.abs(record.frustumGeometry.groundAltM - ground) < 0.001
|
||||
) {
|
||||
@@ -266,11 +280,77 @@ export function createGround({ state: layerState, services, parts, source }) {
|
||||
// under the ≤1-per-(camera, session) ceiling.
|
||||
layerState._tilesReadyReenqueued = false;
|
||||
}
|
||||
// The active camera may have just lost its shipped footprint (globe
|
||||
// regime) — resolve its DEM footprint for the new surface.
|
||||
const active = layerState._recordById.get(layerState._activeCameraId);
|
||||
if (active) void resolveFootprintGround(active);
|
||||
parts.presentation.notifyListeners();
|
||||
}
|
||||
/**
|
||||
* Resolves the ground under the monitor plane's nine support points for the
|
||||
* record's CURRENT pose from the Re:Earth DEM (network-cached proxy, never a
|
||||
* scene query), then re-applies the geometry so the rigid lift accounts for
|
||||
* terrain rising under the plane's far edge. This is the fallback for
|
||||
* cameras without a shipped precompute for this pose (a new pack, or a
|
||||
* camera the user has edited), and it runs only on demand: activation and
|
||||
* calibration commit. A late result for a stale pose or a torn-down record
|
||||
* is dropped. Never rejects.
|
||||
* @param {Object} record - Camera record.
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async function resolveFootprintGround(record) {
|
||||
if (!record?.camera) return;
|
||||
const pose = parts.geometry.footprintPose(record);
|
||||
const hash = poseHash(pose);
|
||||
const existing = record.footprintGround;
|
||||
if (existing?.poseHash === hash) {
|
||||
// Complete real-DEM results are final; a geoid-fallback (proxy outage)
|
||||
// or partial result is retried after a cooldown.
|
||||
if (!existing.provisional || Date.now() < existing.retryAt) return;
|
||||
}
|
||||
if (parts.geometry.hasShippedFootprint(record)) return;
|
||||
const revision = (record.footprintRevision || 0) + 1;
|
||||
record.footprintRevision = revision;
|
||||
const { supports } = planeSupportPoints(pose);
|
||||
const coords = SUPPORT_KEYS.map((key) => ({
|
||||
lat: supports[key].lat,
|
||||
lon: supports[key].lon,
|
||||
}));
|
||||
let results = null;
|
||||
try {
|
||||
results = await resolveEllipsoidalGround(coords);
|
||||
} catch {
|
||||
results = null;
|
||||
}
|
||||
if (!Array.isArray(results)) return;
|
||||
if (record.footprintRevision !== revision) return;
|
||||
if (layerState._recordById.get(record.camera.id) !== record) return;
|
||||
if (poseHash(parts.geometry.footprintPose(record)) !== hash) return;
|
||||
const under = {};
|
||||
let real = 0;
|
||||
results.forEach((result, index) => {
|
||||
if (Number.isFinite(result?.ellipsoid)) {
|
||||
under[SUPPORT_KEYS[index]] = result.ellipsoid;
|
||||
if (result.source === 'reearth') real += 1;
|
||||
}
|
||||
});
|
||||
const provisional = real < SUPPORT_KEYS.length;
|
||||
record.footprintGround = {
|
||||
poseHash: hash,
|
||||
supports: under,
|
||||
source: provisional ? 'dem-provisional' : 'dem',
|
||||
provisional,
|
||||
retryAt: provisional ? Date.now() + FOOTPRINT_RETRY_MS : 0,
|
||||
};
|
||||
parts.geometry.applyFrustumGeometry(record, groundAltFor(record));
|
||||
parts.rendering.refreshCoverageStyles();
|
||||
parts.presentation.notifyListeners();
|
||||
}
|
||||
|
||||
return {
|
||||
surfaceRegimeKey,
|
||||
currentSurfaceRegime,
|
||||
resolveFootprintGround,
|
||||
groundPriorAltFor,
|
||||
isGroundResolved,
|
||||
groundAltFor,
|
||||
|
||||
Reference in new issue
Block a user