Files
KML-Verification/README.md
2026-04-27 12:48:37 +05:30

177 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# KML Map Tool — User Guide
Tauri 2 desktop app for reviewing, correcting and exporting fixed-asset / range-asset annotations produced by the dashcam labelling pipeline. Replaces the legacy FastAPI + Leaflet tools.
---
## Quick start
1. **Login** — pick or create a user when the app opens. The username is stamped on every audit-log entry.
2. **Import data** — top-left **Import…** button:
- **Fixed assets (JSON)** — point assets like streetlights, signs.
- **Range assets (JSON)** — linear assets with start / mid / end (e.g., crash barriers).
- **KML scope polygon** — defines which assets are "in scope". Points outside the polygon are hidden by default.
- **OSM roads (GeoJSON)** — imported road network for snapping / direction lookups.
- **Metadata polyline (KML)** — vehicle GPS track from the source video; takes priority over OSM for direction inference.
3. The map auto-centers on the first imported asset. Pan / zoom triggers viewport-bounded fetches (debounced) to keep the deck.gl rendering snappy.
---
## Map basics
- **Basemaps** — Basemap selector at the top. Default: **Google Satellite (deep zoom)** which uses Google Earth tiles and goes deeper than the regular Google Satellite layer (helpful at z≥22 to see streetlights / road surface).
- **Compare mode** — secondary basemap layered side-by-side via the Compare toggle.
- **Layer toggles** — Fixed / Range / OSM / Scope / Metadata visibility.
- **Filters panel** (left side) — narrow the visible set by Asset type, Side, Video, Asset name. Counts update live with the current viewport.
- **Show out-of-scope / Show deleted** — toggles to expose hidden assets for inspection or restore.
---
## Selecting and editing one asset
- **Click an asset** to select. The right-side **Selected** panel shows type, name, row_id, video, side. By default an image popup opens (toggle in Settings).
- **Drag the pin** on the map to move the asset. Range assets show **S / M / E** (start / mid / end) draggable pins.
- **`[` / `]`** keyboard shortcuts step through the visible filtered list.
- **Reset to original** — restores the lat/lng captured at first import. Useful if a snap or drag went wrong.
- **Snap to nearest road** — shifts the asset to the OSM road centerline or its lane-offset side. Direction priority: **metadata polyline → OSM `oneway` → position-based fallback**. Idempotent above 0.5 m drift.
- **Side: Left / Right** — toggle without moving the geometry.
- **Rename class…** — change `asset_name` (e.g. fix a mis-classified label). Pulls suggestions from `classes.txt`.
- **Delete** — soft-delete (recoverable via Restore or Undo).
- **Mark as anchor** — flag for the bulk **Distribute correction** flow (see below).
---
## Lasso selection (for bulk operations)
- **Start lasso** then pick a shape: **circle**, **rect**, or **polygon**.
- Polygon mode: click to add vertices, click near the first vertex (gold ring) or double-click to close. Pan / zoom while drawing — vertices stay anchored to the map.
- **ESC** cancels at any time and clears the lingering polygon panel.
- Once selected, you get bulk actions: **In-scope / Out-of-scope / Auto / Delete / Restore / Rename / Set Left / Set Right / Reset to original / Clear links**.
- Polygon-only extras: **Auto-link L↔R**, **Auto-link by video**, **Auto-link nearest** (see Pair linking).
---
## Cross-side / cross-video pair linking
Common situation: one physical asset (e.g., a median streetlight) is captured in two videos (LHS and RHS) and shows up as two near-duplicate points. Pair linking marks them as the same physical thing without deleting either.
- **Auto-link** — draw a polygon lasso over the area, then pick the matching strategy in the polygon panel:
- **L↔R**: requires assets to have a `side` label; pairs Left with Right.
- **By video**: pairs across the two largest video buckets (use when both videos see the same poles from opposite sides).
- **Nearest**: pairs by proximity regardless of side or video. Use when `video_name` is `Not available` / NA.
- **Pair max** slider (260 m, default 30 m) — the maximum allowed pair distance. Independent from the duplicate epsilon.
- Manual links override auto-links:
- **Right-click an asset → right-click another** — locks them as a pair (pink line). The "anchor" asset gets a status-bar prompt.
- **Right-click two already-linked assets** — unlinks them.
- **Click a link line** to select it; press **Delete** to clear that link.
- Link colors: **pink = locked manual link** (survives Auto-link re-runs); **blue = auto link** (replaceable on the next re-run).
- Unlink an asset directly via **Unlink** button on the selected panel.
- After fixing a few wrong pairs manually, click **Auto-link** again — locked links stay; orphaned partners get re-matched among the remaining unlocked candidates.
---
## Duplicates
- **Find duplicates** — scans the *currently visible viewport* for clusters of points within the chosen ε (metres). Zoom out to widen the search; zoom out fully to scan everywhere.
- **Cross-video only** — restrict matches to pairs from different videos.
- For each cluster you can **Delete losers** (keep one, delete the rest) or **Move losers out-of-scope**.
---
## Distribute correction (GPS bias fix)
When the GPS is uniformly off for a whole video / stretch, you don't want to drag every streetlight by hand.
1. **Filter** the map to the affected slice (e.g., `video=X`, `name=Streetlight`).
2. Click an asset → **Mark as anchor** (gold ring appears).
3. **Drag** the gold-ringed asset to where it should be. Repeat for as many anchors as you like.
4. Click **Distribute correction** in the yellow panel that appears at the top of the actions sidebar.
- **1 anchor** → all visible assets shift by the same Δlat/Δlng (uniform).
- **2+ anchors** → row_id-sorted piecewise linear interpolation between consecutive anchors. Assets *outside* the firstlast anchor span are not touched.
5. **Undo** in Recent actions reverts the entire distribution in one step.
Range assets (start / mid / end) translate as a rigid body — all three vertices shift by the same Δ.
---
## OSM road editing
- **OSM tools…** modal — generate roads for the visible bbox (Overpass), import existing GeoJSON, export current roads, prune small road classes.
- **OSM edit mode** — drag any road's vertex to refine the centerline. Markers are gated by zoom ≥ 14 and capped at 80 vertices / 40 ghost dots per viewport so the map stays responsive.
- **Flip road direction** — cycle a road's `oneway` between 0 / 1 / -1 when it's wrong.
- **Lane offset (m)** — controls the parallel offset used by snap-to-road. Range 0.130 m.
---
## Snap-to-road
- **Per-asset** — Snap to nearest road on the selected panel.
- **Bulk visible** — snap every visible fixed asset to the nearest road (50 m max).
- **Snap by video** — snap every asset (fixed + range) for a given video.
- Range assets snap all three vertices independently (not just mid).
- Direction priority: **metadata polyline > OSM `oneway` > position-based**.
---
## Centerline override
Some asset classes (expansion joint, vms gantry) belong on the road centerline, not the LHS/RHS offset. Settings → **Snap to centerline (instead of offset lane)** lets you tick those class names.
---
## Settings ⚙ modal
- **Image popup**
- On / off (when off, marker pins still appear but no image opens on click).
- Width: S / M / L / XL.
- Aspect ratio: 16:9 / 4:3 / 3:2 / 1:1.
- **Snap to centerline names** — list of asset_names that should snap to centerline.
- **Image folder (offline)** — a local folder used to resolve `image_path` URLs to disk (HTTPS URLs always pass through unchanged).
---
## Export
The **Export data…** button writes every non-deleted asset in one of four formats:
- **`.json` Source JSON** — round-trippable. Same shape `import_fixed_assets` and `import_range_assets` accept (separate `fixed` and `range` arrays). Includes `image_path*`, `side`, `deleted`, etc.
- **`.geojson`** — FeatureCollection. Points for fixed assets, LineStrings for ranges. Properties include `image_path*`, `link_pair_id`, `link_locked`, `in_scope`, `modified`.
- **`.kml`** — Placemarks for GIS tools. Includes name, description, geometry.
- **`.csv`** — full row dump for spreadsheets / external pipelines.
OSM roads can be exported separately via **OSM tools… → Export current roads** (writes GeoJSON with `name`, `highway`, `oneway` preserved).
---
## Keyboard shortcuts
| Key | Action |
|---|---|
| `[` / `]` | Step prev / next asset in the filtered list |
| `ESC` | Cancel: lasso / link-pick / draw-road / road-edit / image popup |
| `Delete` / `Backspace` | Unlink the currently-selected link line |
---
## Undo / Redo
Every state-changing action writes an audit row. The **Recent actions** panel shows the last N. Click **Undo** on any row to revert; **Redo** on a previously undone row replays it. Multi-asset operations (bulk delete, distribute, auto-link) revert as a single atomic step. Road edits (OSM vertex drag, create / delete / flip) are not audited.
---
## Performance notes
- Viewport-bounded fetch: `assets` only contains rows inside the current map bbox, debounced ~400 ms after pan / zoom.
- Bulk operations use 500-id chunks to stay safely under SQLite's 999-bind-param ceiling.
- Auto-link / Distribute over very large viewports may take several seconds at 50k+ rows; prefer narrowing with filters or zoom first.
- Image prefetching warms the previous / next two thumbnails so `[` / `]` navigation feels instant.
---
## Troubleshooting
- **No assets visible after import** — check Filters panel (especially Videos), Show out-of-scope toggle, and whether a stale KML scope from a previous import is filtering everything out.
- **Streetlights not visible on satellite** — switch to **Google Satellite (deep zoom)** basemap and zoom to z≥22.
- **Snap moves assets to the wrong side** — load the metadata polyline (gives true vehicle heading), or fix the OSM road's `oneway` direction.
- **Re-importing wipes my edits** — re-import preserves rows where `modified=1` (manual moves) and rows the user deleted; only `modified=0` geometry is re-stamped from source. If you need a fresh start, use **Reset DB** in the Data section first.