mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 10:53:59 +00:00
docs(cctv): describe the ground-height data plainly (#443)
Follow-up to #433.
This commit is contained in:
1 parent
12790b36c6
commit
41c416e329
8 files changed
+73
-87
No files matched your search
@@ -1,37 +1,29 @@
|
||||
# CCTV ground heights
|
||||
|
||||
Precomputed ground height under every camera in the served CCTV catalog and
|
||||
under the nine support points of its monitor plane, so the client can place a
|
||||
camera and its plane with no runtime sampling. Shared placement data: any
|
||||
consumer that renders these cameras on the same photorealistic surface can
|
||||
reuse it.
|
||||
|
||||
Source surface: Google Photorealistic 3D Tiles, sampled at maximum detail with
|
||||
CesiumJS `scene.sampleHeightMostDetailed` from a running God's Eye View
|
||||
(scripts/precompute-cctv-heights.mjs). Heights are WGS84 **ellipsoidal**
|
||||
metres; no geoid conversion is needed or applied. This is placement data
|
||||
derived from the rendered surface, not imagery.
|
||||
under the nine support points of its monitor plane, aligned to work with
|
||||
Google Photorealistic 3D Tiles. Heights are WGS84 ellipsoidal metres. The
|
||||
client places a camera and its plane from this file with no runtime sampling.
|
||||
|
||||
Runtime output: `cctv_ground_heights.json`
|
||||
|
||||
```
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"provider": "google-photorealistic-3d",
|
||||
"provider": "google-3d-tiles",
|
||||
"heightReference": "WGS84-ellipsoid",
|
||||
"generatedAt": "<ISO>",
|
||||
"cameras": {
|
||||
"<camera id>": {
|
||||
"poseHash": "p1-…", // hash of the served pose the samples describe
|
||||
"poseHash": "p1-…", // hash of the served pose the entry describes
|
||||
"status": "ok" | "miss",
|
||||
"mountGroundM": <number>, // ground under the camera position (absent on a miss)
|
||||
"supports": { // ground under the plane's 3×3 support grid; a value is
|
||||
// null where that point had no sample (absent on a miss)
|
||||
"bl","bm","br", // bottom row (left, middle, right)
|
||||
"ml","mc","mr", // middle row
|
||||
"tl","tm","tr" // top row
|
||||
"supports": { // ground under the plane's 3×3 support grid; null where
|
||||
"bl","bm","br", // a point has no value (absent on a miss)
|
||||
"ml","mc","mr",
|
||||
"tl","tm","tr"
|
||||
},
|
||||
"misses": [<keys with no sample: "mount" and/or support keys>],
|
||||
"misses": [<keys with no value>],
|
||||
"sampledAt": "<ISO>",
|
||||
"attempts": <n>
|
||||
}
|
||||
@@ -40,19 +32,15 @@ Runtime output: `cctv_ground_heights.json`
|
||||
```
|
||||
|
||||
Support point positions are defined by `src/data/cctvFootprint.js`
|
||||
(`planeSupportPoints`), which the client, the server join
|
||||
(`server/providers/cctv/groundHeights.js`) and the precompute all share. An
|
||||
entry is used only while the camera's served pose still hashes to
|
||||
`poseHash`; a camera whose feed moved it, or whose pose a user edited, falls
|
||||
back to runtime placement from the Re:Earth DEM.
|
||||
(`planeSupportPoints`), shared with the server join
|
||||
(`server/providers/cctv/groundHeights.js`). An entry is used only while the
|
||||
camera's served pose still hashes to `poseHash`; a camera whose feed moved it,
|
||||
or whose pose a user edited, falls back to runtime placement from the terrain
|
||||
proxy.
|
||||
|
||||
Regenerate (resumable; only cameras whose pose changed or whose entry is
|
||||
incomplete are re-sampled):
|
||||
Regenerate against a running app (resumable; only cameras whose pose changed
|
||||
or whose entry is incomplete are redone):
|
||||
|
||||
```
|
||||
GEV_BASE=http://localhost:4173 node scripts/precompute-cctv-heights.mjs
|
||||
```
|
||||
|
||||
Coverage at generation (2026-09-14): 3,445 of 3,446 cameras `ok` (six of them
|
||||
with one or more null supports), 34,444 sampled heights, 43 minutes on a real
|
||||
GPU. Regenerate whenever a pack changes its poses or a new pack lands.
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"provider": "google-photorealistic-3d",
|
||||
"provider": "google-3d-tiles",
|
||||
"heightReference": "WGS84-ellipsoid",
|
||||
"generatedAt": "2026-09-14T01:42:02.486Z",
|
||||
"cameras": {
|
||||
|
||||
@@ -26,8 +26,9 @@ export function createGeometry({ state: layerState, services, parts, source }) {
|
||||
* CURRENT pose, or null. Shipped precompute samples (`camera.groundHeights`)
|
||||
* were taken for the nominal pose; they apply only while the pose hash still
|
||||
* matches, so a calibrated (edited) camera falls back to the mount ground
|
||||
* until its own footprint is resolved. Photoreal regime only: the samples
|
||||
* are Google mesh heights and would be wrong against a globe DEM.
|
||||
* until its own footprint is resolved. Photoreal regime only: the values
|
||||
* are aligned to the Google 3D Tiles surface and would be wrong against a
|
||||
* globe DEM.
|
||||
* @param {Object} record
|
||||
* @returns {Record<string, number>|null}
|
||||
*/
|
||||
@@ -72,7 +73,8 @@ export function createGeometry({ state: layerState, services, parts, source }) {
|
||||
|
||||
/**
|
||||
* True when the record carries shipped precompute samples for its CURRENT
|
||||
* pose and the scene is rendering the photoreal mesh they were taken from.
|
||||
* pose and the scene is rendering the Google 3D Tiles surface they are
|
||||
* aligned to.
|
||||
* @param {Object} record
|
||||
* @returns {boolean}
|
||||
*/
|
||||
|
||||
@@ -206,7 +206,7 @@ test('sidecar merging sorts ids, preserves unselected entries and replaces stale
|
||||
assert.deepEqual(result.cameras.a, { status: 'miss' });
|
||||
assert.equal(old.cameras.a.mountGroundM, 20);
|
||||
assert.equal(result.schemaVersion, 1);
|
||||
assert.equal(result.provider, 'google-photorealistic-3d');
|
||||
assert.equal(result.provider, 'google-3d-tiles');
|
||||
assert.equal(result.heightReference, 'WGS84-ellipsoid');
|
||||
assert.equal(result.generatedAt, sampledAt);
|
||||
assert.deepEqual(mergeSidecar(null, {}, sampledAt).cameras, {});
|
||||
|
||||
Reference in new issue
Block a user