geo: one tool directory, one unit boundary, per-asset provenance

Geo/tools/ is now every geographic script, with Geo/README.md documenting each
one; the Blender-side builders moved beside their outputs in Art/blender/*/ and
import their helpers from Geo/tools/osm_common.py.

That module gains to_unreal_local() and to_blender_local(): the only place in the
repository that multiplies metres by 100, so a second silent scale cannot be
introduced. block_height_report.py adds height provenance for the block — 3 of
15 buildings have no height data and render at a placeholder 6.4 m.
asset_metadata.py writes and audits <asset>.geo.json sidecars; four now exist
(hero-facade, terrain, street, blockout) and the audit recomputes each centre from
the origin, failing anything that disagrees.
This commit is contained in:
zwitschi committed 2026-11-07 12:28:26 +01:00
1 parent 5e5e5ae9b4
commit 386d4bee78
26 files changed
+471 -57

No files matched your search

+26 -29
View File
@@ -1,48 +1,45 @@
# Geo
Geographic sources, manifests, and the scripts that turn them into Blender imports.
Geographic sources, manifests, and the tools that turn them into Blender and Unreal content.
OSM is layout data only. It is not authoritative for façade detail, height, or pavement, and it is never sampled as a texture or panorama source.
The OSM source files are © OpenStreetMap contributors, available under the [Open Database License 1.0](https://opendatacommons.org/licenses/odbl/1-0/); see [OpenStreetMap attribution](https://www.openstreetmap.org/copyright). Public use of a derivative database can require sharing that database or the changes needed to recreate it under ODbL. Review the applicable obligations for each distributed product.
## Layout
| Path | Contents |
| --- | --- |
| `Geo/raw/` | Verbatim source responses, checksummed. Never edited by hand. |
| `Geo/verification/` | Per-pass verification notes: address, footprint, bounds, and what remains unresolved |
| `Geo/manifests/` | One manifest per saved extract (see below) |
| `Geo/scripts/` | Repeatable fetch and conversion helpers |
| `Geo/raw/` | Verbatim source responses and downloads, checksummed. Never edited by hand. |
| `Geo/manifests/` | One manifest per source: extract, DEM, and the local origin |
| `Geo/verification/` | Per-pass notes: address, footprints, bounds, street profile, cross-sections, elevation |
| `Geo/tools/` | Every geographic tool (Python, standard library only unless noted) |
Current state: the extract, both El Capitan footprints, the demo bounds, the building sets, the street profile, and the designated crossing are recorded in [`verification/`](verification/). The local CRS and origin are fixed in [`manifests/local-origin.md`](manifests/local-origin.md), with the projected easting/northing still to be computed. Elevation is measured and the 3DEP 1 m DEM window is committed (EPSG:26911, NAVD88, 984 KB). The street cross-sections (crown ~2 %, gutters at ±10–11 m) are in `verification/`. The hero façade width is resolved at 25.75 m. The geo pipeline is ready for the Blender blockout.
Tools that build 3D content from these sources live next to their output in `Art/blender/*/` (`terrain_from_dem.py`, `street_mesh.py`, `site_assembly.py`, `blosm_blockout.py`) because they need Blender; their shared geo helpers and the unit conversion come from `Geo/tools/osm_common.py`.
## Required manifest
## Tools
Every extract gets a manifest file `Geo/manifests/<source>-<date>.md` recording:
| Field | Example |
| Tool | Purpose |
| --- | --- |
| Source | Overpass API / Geofabrik / OSM extract provider |
| Extract date | date the query ran or the file was downloaded |
| Query or file URL | the exact query text or download URL |
| Data timestamp | OSM data date reported by the source (may differ from the extract date) |
| Bounds | west, south, east, north in WGS84 decimal degrees |
| Licence | ODbL 1.0, attribution string |
| Checksum | SHA-256 of the committed file |
| CRS and local origin | projected CRS plus the chosen origin, with its WGS84 coordinates |
| Files | every file produced from this extract |
| `osm_common.py` | Shared helpers: parse `.osm`, stitch and clip a street, project to UTM through PROJ, **and the single metres→centimetres conversion** (`to_unreal_local`) |
| `block_report.py` | Streets, boundary intersections, and the building set for a block, split by side |
| `block_height_report.py` | Every block building with its height **source** — tag, levels × 3.2 m, or a placeholder guess |
| `street_profile.py` | Carriageway width from crossings, sidewalk offsets, per-building setbacks |
| `street_section.py` | Cross-sections from the DEM: crown, gutters, kerb detection |
| `elevation_probe.py` | Samples 3DEP for relief and records the baseline for the release checks |
| `dem_stats.py` | Stdlib reader for the tiled GeoTIFF the 3DEP service returns; GDAL does not run on this host |
| `asset_metadata.py` | Writes and audits `<asset>.geo.json` sidecars: position, provenance, conversion |
## Demo bounds
## Unit boundary
`0.1.0` covers 6840 Hollywood Blvd / El Capitan Entertainment Centre, buildings on the south side of Hollywood Boulevard between Highland Avenue and Orange Drive, and north-side buildings whose footprint lies within 50 m of the north frontage. Verify address, footprints, and boundaries against source data before modeling; anything unverifiable is recorded here as unresolved and is not modeled.
There is exactly one conversion in the repository:
## Coordinate convention
```
WGS84 (lat, lon) → EPSG:26911 (E, N metres) → project-local metres → Unreal centimetres
```
- Work in a local projected CRS (EPSG:26911, NAD83 / UTM zone 11N, is the default candidate) and record the local origin explicitly.
- Blender and Unreal both take metres → Unreal units at 1 m = 100 uu. The conversion is applied once, in one place, and recorded in the manifest. Never apply a second silent scale on import.
- Preserve the original geographic coordinates in metadata so any asset can be traced back to its position.
`Geo/tools/osm_common.py::to_unreal_local` is the only place that multiplies by 100. Per-asset sidecars record the result, and `asset_metadata.py audit` checks each saved sidecar against that function, so a file that drifts is caught rather than trusted.
## Unresolved items
## Current state
Record here any structure whose address, footprint, or boundary could not be verified from permitted sources, with the sources checked. It does not get modeled.
The extract, both El Capitan footprints, the demo bounds, the building sets, the street profile, cross-sections, and the 3DEP DEM window are recorded in `Geo/verification/` and `Geo/manifests/`. The local CRS and origin are fixed in `manifests/local-origin.md`.
Open items live in `ROADMAP.md` under **Geographic data**.