Skip to content

fix(chatt): register the aerial drape N-S so buildings stop floating over the river#223

Merged
TortoiseWolfe merged 1 commit into
mainfrom
fix/chatt-hero-registration
Jul 7, 2026
Merged

fix(chatt): register the aerial drape N-S so buildings stop floating over the river#223
TortoiseWolfe merged 1 commit into
mainfrom
fix/chatt-hero-registration

Conversation

@TortoiseWolfe

Copy link
Copy Markdown
Owner

Closes #222 (drape N-S registration). Follow-up to #221.

The real bug (found by TDD, not by eye)

#221 clipped OSM geometry to the box and I mistook "streets contained in the drape extent" for "layers registered." They weren't. Buildings still floated over the river.

Ground-truth investigation (overlaying streets/buildings/heroes on the actual drape.jpg, then looking) showed:

  • Projection is exact — streets register pixel-perfect E-W on the aerial. The cos-lat factor cancels in the ENU↔drape mapping. No scale bug.
  • The NAIP drape was N-S mis-registered. ArcGIS exportImage returns the requested bbox exactly only when the requested pixel aspect equals the bbox aspect in the request SR. We requested SR 4326 (degrees) with a metre-proportional 729×2886 size. Degree aspect (0.307) ≠ metre aspect (0.253 = cos35·0.307), so ArcGIS expanded the latitude extent to keep pixels square — it returned lat 35.00223..35.06557 instead of the requested 35.0078..35.06: ~616 m over-scan on each end. The runtime maps row→lat linearly over the assumed box, so every N-S feature shifted and the south-bank (Ross's Landing) buildings landed on pixels that read as open water.
  • Longitude was untouched (dLon=0) — which is exactly why it looked like a pure vertical float.

Fix

Size the drape at the degree aspect: fix E-W resolution at groundWm/mpp, derive height = width·degLat/degLon729×2378. Verified live: ArcGIS now returns ymin=35.0078, ymax=35.06, 0.0 m over-scan. Re-fetched the drape, re-baked, and confirmed by building-footprint overlay that riverfront buildings now sit on land.

Registration uses groundWm/groundHm (true metres), not pixel count, so the taller-in-pixels image still maps correctly; manifest.drape now reports the real 729×2378.

Tests (fail-first, run offline in CI)

  • fetch-drape: pixel aspect must equal the bbox aspect in the request SR — the no-extent-expansion invariant that was being violated (this test failed on the old size, passes on the fix).
  • build-scene: each way-based hero registers on its true OSM footprint centroid (≤5 m) — pins hero placement to ground truth so a stale anchor can't drift silently.

Before / after

Building-footprint overlay on the aerial: before — a cluster of footprints floating in the open river; after — footprints stop at the south bank, every one on a real building. (Verified by looking, per the project's screenshots-are-truth discipline.)

All 16 bake/world/stage test files (46 tests) green; type-check clean.

🤖 Generated with Claude Code

…ArcGIS returns the exact bbox

The buildings floated over the river because the NAIP drape was N-S mis-
registered against the OSM/terrain layers. Root cause found by TDD, not by eye:

ArcGIS exportImage returns the requested bbox EXACTLY only when the requested
pixel aspect equals the bbox aspect IN THE REQUEST SR. We requested SR 4326
(degrees) with a metre-proportional (cos-lat corrected) 729x2886 size. Because
the degree aspect (0.307) != the metre aspect (0.253 = cos35 * 0.307), ArcGIS
expanded the LATITUDE extent to keep pixels square: it returned lat
35.00223..35.06557 instead of the requested 35.0078..35.06 — ~616 m of over-scan
on EACH end. The runtime maps row->lat linearly across the assumed box range, so
every N-S feature was shifted/scaled and the south-bank (Ross's Landing)
buildings landed on aerial pixels that read as open water.

Longitude was unaffected (dLon=0), which is why streets registered E-W perfectly
and the bug looked purely like a vertical float.

Fix: size the drape at the DEGREE aspect (fix E-W resolution at groundWm/mpp,
derive height = width * degLat/degLon -> 729x2378). Verified live: ArcGIS now
returns ymin=35.0078, ymax=35.06 with 0.0 m over-scan. Re-fetched the drape and
re-baked. Building-footprint overlay on the corrected aerial confirms the
riverfront buildings now sit on land, not in the river.

Registration uses groundWm/groundHm (true metres), not the drape pixel count, so
the taller-in-pixels image still maps correctly; manifest.drape now reports the
real 729x2378 dims.

Tests (fail-first, offline in CI):
- fetch-drape: pixel aspect must equal the bbox aspect in the request SR (the
  no-extent-expansion invariant that was violated).
- build-scene: each way-based hero registers on its true OSM footprint centroid
  (<=5 m) — guards hero placement against the aerial ground truth.

Refs #222

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Chatt diorama: layers not georegistered in sync — need landmark-anchored registration tests (TDD)

2 participants