docs(cctv): describe the ground-height data plainly (#443)

Follow-up to #433.
This commit is contained in:
Bilawal Sidhu authored and GitHub committed 2026-09-13 21:54:29 -05:00
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": {