FloodTruth — Tap-to-mark closed-loop validation

Tap-to-mark closed-loop validation

Tap-to-Mark Phase I prototype

Inspector closed-loop validation tool. Walk the downstream reach with the AR overlay running, and tap the screen wherever the predicted inundation shoreline disagrees with the real terrain you're observing. Each tap records a discrepancy: lat/lon (back-projected from the tap through the camera model and DSM intersection), elevation, predicted depth at that world point, an observed-terrain class (wet / dry / uncertain), and an optional note. Marks export as a GeoJSON FeatureCollection that feeds back into the Bayesian breach posterior for envelope refinement (Phase I scope).

Inherits the rendering pipeline of ar-prototype.html: same WGS84 → ENU → camera projection, same DSM occluder, same 3D water column. Adds a tap-capture canvas above the overlay and a marks drawer.

Two recording modes (toggle is in the AR overlay, top-center): Discrepancy — original closed-loop validation against the predicted envelope. High-Water Mark — geotag observed peak-flood evidence (debris line, mud staining, bent vegetation, water/silt stain) for FEMA HMGP/BRIC, insurance damage assessment, and academic post-event reconstruction. HWM marks accept a per-mark evidence photo (stored in IndexedDB) and export as a FEMA-style survey package (GeoJSON + CSV + photos + README, bundled as a ZIP). Both modes coexist in the same session and on the same overlay.

1 · Inundation polygon (GeoJSON)

no GeoJSON loaded

Same parser as the inundation viewer — accepts FeatureCollection, Feature, or bare Polygon/MultiPolygon. WGS84 (lon, lat). Optional depth_ft / depth_m / wsel_ft per feature.

2 · Observer position

no fix

Mark elevations are read from the active DSM if loaded; otherwise the observer ground plane is used as a planar approximation (degrades with range and varied terrain).

3 · DSM (optional, but improves mark elevation accuracy)

Loading a DSM (drone survey, project lidar, or USGS 3DEP) lets the inverse projection intersect the actual terrain rather than the observer's ground plane. Without it, marks >~100 m from the observer drift in elevation.

no DEM — falling back to planar ground at observer

4 · Camera intrinsics

5 · Start AR + tap-to-mark

ready · 0 mark(s) saved

Marks persist in browser localStorage (records) and IndexedDB (HWM evidence photos) — survives reload, cleared by the explicit button or by clearing site data.

How tap-to-mark works (inverse projection & mark schema)

1 · Forward pipeline (inherited)

The renderer projects each polygon vertex through three transforms identical to ar-prototype.html: (a) WGS84 → ENU (planar small-area approximation), (b) ENU → camera frame via the heading/pitch/roll rotation built in buildCamRotFromHPR, (c) camera frame → screen pixels via the standard pinhole projection.

2 · Inverse projection (this tool)

A tap at screen pixel $(u, v)$ is mapped to a camera-space ray

$\;\vec{r}_{\rm cam} = \big( (u - W/2) \tan(\text{HFOV}/2) / (W/2),\; (v - H/2) \tan(\text{VFOV}/2) / (H/2),\; 1 \big)$

This is the analytic inverse of the pinhole forward map at $z = 1$. The ray is rotated into ENU via $\vec{r}_{\rm ENU} = R^{T} \vec{r}_{\rm cam}$ — note that $R$ is orthonormal so $R^{-1} = R^{T}$. The world-space ray origin is the camera at $(0, 0, 0)$ in ENU (i.e., the observer GPS at eye-height).

3 · Ray–surface intersection

With a DSM loaded, the ray is marched outward in steps of $\sim 1$ m up to a 1.5 km cap. At each step the bilinearly-interpolated DSM elevation is compared against the ray's instantaneous elevation; the first sample where the ray drops below terrain is the intersection (refined by one bisection pass). Without a DSM, the ray is intersected with the planar ground at the observer's elevation — accurate near the observer, drifts with range over varied terrain. The intersection point $(\Delta E, \Delta N, z_{\rm ground})$ is converted back to lat/lon via the inverse of the planar-ENU equations.

4 · What gets recorded per mark

  • lat, lon — back-projected WGS84 coordinate of the tap target. Not a real GPS reading at that point; it is computed from the camera model. Accuracy depends on compass calibration, FOV calibration, and DSM availability.
  • elevation_navd88 — DSM elevation at (lat, lon) if available; else observer ground elevation as a planar fallback.
  • screen_xy — original screen pixel of the tap (for traceability + replay).
  • timestamp — ISO 8601 UTC.
  • predicted_depth_at_mark — depth from the active feature whose ring contains the back-projected (lat, lon), resolved by the same property fallback chain as the reticle HUD (depth_ft → depth_m → wsel_ft − ground). 0 if the back-projected point is outside every active feature.
  • observed_terrain_class — inspector judgment from the on-screen picker: wet / dry / uncertain.
  • discrepancy_kind — derived: if predicted depth > 0 and observed = "dry" → ar_wet_observed_dry; if predicted depth = 0 and observed = "wet" → ar_dry_observed_wet; if observed = "uncertain" → uncertain; otherwise agree (mark still saved — useful for confirming hits).
  • note — free-text annotation, optional.
  • observer — copy of observer lat/lon/elev/heading at tap time, for traceability.
  • scenario — copy of active storm/offset selection, since marks are scenario-specific.

5 · High-Water Mark (HWM) recording mode

A second tap mode geotags observed peak-flood evidence rather than predicted-vs-observed discrepancies. The inverse projection, DSM intersection, and lat/lon/elevation back-projection are identical to Discrepancy mode — only the schema and visual style differ.

  • Tap flow: tap → bottom sheet prompts for evidence_type (debris_line / mud_staining / bent_vegetation / water_stain / silt_line / other) and confidence (high / medium / low) → save.
  • Per-mark photo: "Capture evidence" button on each HWM opens a still-photo capture overlay; the photo is stored as a JPEG blob in IndexedDB (object store hwm_photos, key = mark id) — keeps localStorage well below its 5-10 MB quota.
  • Visual style: HWM marks render as inverted teardrops (point-down) to distinguish from discrepancy marks (point-up); both can coexist on the same overlay.
  • Color palette: orange (debris), brown (mud), green (vegetation), grey (water stain), tan (silt), purple (other).
  • Schema fields specific to HWM: mark_type:'high_water_mark', evidence_type, confidence, observation_date_iso, photo_capture_filename, free_text_note, observer_pose (heading/pitch/roll snapshot at tap time).
  • Export — FEMA HWM survey package (ZIP): mirrors USGS STN / FEMA HWM survey conventions — hwm_points.geojson (all HWM features), hwm_summary.csv (one row per HWM with lat/lon/elev/evidence/confidence/date/note), photos/hwm_<idx>_<evidence_type>.jpg, and README.txt with provenance + survey methodology. This is a defensible derivative format, not a verbatim FEMA template — see README in the ZIP.

6 · What this prototype does NOT do (Phase I scope)

  • The actual Bayesian importance reweighting against breach-parameter posterior draws. That sits in the backend per closed_loop_workflow_spec.md §2.3; this prototype only produces the GeoJSON observation set that feeds it.
  • The QA loop UI showing pre/post envelope side-by-side. Phase I §2.4.
  • Camera-frame snapshot per tap. Phase I §2.2 step 5 — the existing snapshot button in ar-prototype.html covers the equivalent at higher level.
  • Server sync. Marks are local-only in this prototype.
lat—, lon—
elev— m
hdg—°
pitch—°
roll—°
offset δ0.0°  marks0
mode
tap will record
Marks
No marks yet — tap the AR view to record one.