Files
KML-Verification/README.md
2026-05-02 16:44:03 +05:30

299 lines
19 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.
- **Per-video metadata (JSON)** — vehicle GPS track per video; takes priority over OSM for direction inference. **Persists in the SQLite database**, so you only pick the file once — every subsequent app start hydrates it automatically. Cleared only by the **Clear** button on the Per-video metadata row, or by **Reset DB**.
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).
---
## Single-video focus mode
When you want to inspect / clean one video's worth of data in isolation:
- **Tap that video's metadata polyline on the map**, or
- **Leave exactly one video checked in the Filters panel**.
Either path triggers focus mode:
- Other videos' metadata polylines are hidden — only the focused track renders.
- OSM roads are spatially filtered to those within ~75 m of the focused track (cheap spatial-hash buffer; recomputed on each switch).
- Clicking the metadata line again, or unchecking the lone video filter, restores the full view.
Focus mode also unlocks the bulk OSM road tools (multi-select / hide / merge — see **OSM road editing**). Selection and hidden state are session-scoped: they reset whenever you exit OSM edit mode or change the focused video.
---
## 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
### Modes
- **OSM tools…** modal — generate roads for the visible bbox or for a buffer around imported assets (Overpass), import existing GeoJSON, export current roads, prune small road classes.
- **Edit OSM roads** button — toggles OSM edit mode. While on, every other layer is dimmed and only OSM roads are interactive.
- **Magnifier** button — cursor-following circular lens that zooms +3 levels around the cursor; renders satellite + OSM cyan + dashed-green metadata + red asset dots. Toggle on, hover anywhere, then ESC or click again to exit.
- **Lane offset (m)** — controls the parallel offset used by snap-to-road. Range 0.130 m.
### Two click models
OSM edit mode behaves differently depending on whether a single video is focused (see **Single-video focus mode**):
- **Non-focus** — click a road to enter the legacy single-road vertex editor (the only road remains visible; vertex pins appear). One road at a time.
- **Focus mode** — click a road to **toggle multi-select** (yellow highlight). All roads stay visible. When the selection narrows to **exactly one** road, the vertex editor automatically engages on it (Flip / Simplify / Delete this road / Ignore for snap appear inline). Click the road again to drop back to multi-select.
### Modifying a road's vertices (single road active)
- **Drag a yellow `•` pin** — moves that vertex. Saved immediately.
- **Click a yellow `+` ghost pin** between two vertices — inserts a new vertex at that midpoint.
- **Flip direction** — cycles `oneway` through forward (`1`) → reverse (`-1`) → undirected (`0`).
- Vertex handles render at z ≥ 14; zoom in if you don't see them.
### Deleting vertices
**A. Surgical — Shift-click + Del**
1. **Shift-click** a vertex pin → turns red with `✕`. Repeat to mark more.
2. Press **Del** → all marked vertices removed in one shot.
3. **Clear marks** unselects without deleting. Shift-click a marked vertex to unmark.
4. The road must keep ≥ 2 vertices.
**B. Sweeping — Simplify by tolerance**
1. **Simplify (m)** slider (0.520 m, default 2 m). Higher = more aggressive.
2. Click **Simplify this road** → Douglas-Peucker on the polyline.
3. Status bar reports `before → after` vertex counts.
### Bulk road tools (focus mode only)
A "Bulk road tools — focus: <video>" panel appears when OSM edit mode is on inside single-video focus. Workflow:
- **Click** roads to build a selection (yellow + thicker stroke).
- **Right-click** any road → instantly hides it (no selection needed).
- **Del** → moves all currently-selected roads into the hidden bucket and clears the selection.
- **Hide selected / Clear selection / Restore hidden** buttons in the panel mirror those shortcuts.
- **Merge selected** (≥ 2 picked) — concatenates connected ways into one. Endpoints within ~8 m of each other are clustered first, so OSM ways with near-but-not-touching endpoints still merge — both ends are snapped to the cluster centroid so the merged geometry has no visible gap. **Disconnected clusters become independent merged roads** (no false bridging).
- **Merge all visible** — same logic over every non-hidden road in the focused area.
- Branched clusters (any node with > 2 incident ways) are skipped rather than corrupted; the toast tells you how many.
Both **hidden** and **selection** sets are session-scoped — cleared on **Exit OSM edit mode** or focused-video change, never persisted.
### Ignore-for-snap (persistent)
Per-road toggle that keeps a road on the map for visual reference but excludes it from snap candidates. Useful for service roads / driveways that the snap should never pick.
- With **one road selected** in the vertex editor, the **Ignore for snap** button appears next to **Flip direction**.
- Ignored roads render in **grey** (vs. the default cyan) and are skipped by both single-asset and bulk snap.
- Stored as a `snap_ignored` column on the `roads` table — survives app restarts. Toggle again to re-enable.
### Whole-road actions
- **Delete this road** — removes the road (with confirmation).
- **Deselect road** — exits the per-road editor (non-focus only; in focus mode, click the road again).
### Per-session OSM edit undo
A 3-deep ring buffer scoped to the current OSM edit session captures the last edits so you can revert them without affecting the global asset audit log.
- **↶ Undo last edit (N)** button right under "Exit OSM edit mode" — visible in both focused and non-focused mode. Tooltip names the action it will undo.
- Covers: **flip direction, simplify road, delete vertices, drag vertex, ignore-for-snap toggle, hide road (right-click + Del), restore hidden**.
- **Not** undoable via this stack: merge selected / merge all visible (they consume source rows; this stack doesn't recreate them), creating new roads, deleting whole roads.
- Cleared on **Exit OSM edit mode**.
---
## 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**.
---
## Quality dashboard
A `<details>` panel in the right sidebar that scans the live asset set for likely-bad rows. Click **Run scan** the first time, **Refresh** thereafter.
Three checks (cap 500 hits each; totals shown even when capped):
- **Moved far from import** — modified rows whose current position is > 50 m from the original (import-time) lat/lng. Flags accidental drags.
- **Off track (far from metadata polyline)** — perpendicular distance to the asset's video metadata polyline exceeds the configured threshold (default **30 m**, tunable in Settings). Flags assets that were assigned to a video / side they don't actually belong to. Skipped silently for videos with no metadata loaded.
- **Missing side** — `side IS NULL`. Flags assets the labeller didn't tag.
For any non-zero count, **View** in the row launches a step-through:
- Zooms the map to z=18 on the first issue.
- **Prev / Next** in the same panel walks through the rest, one at a time at z=18.
### Post-snap quality check
Every snap entrypoint (single asset, bulk visible, snap by video, snap to road) runs a quality scan immediately after and surfaces a toast:
- **Green** — "No quality issues."
- **Red** — "N quality issues found (M moved · O off track · P no side)."
The scan reuses your configured off-track threshold. Toast auto-dismisses after 8 s; click `×` to dismiss sooner.
---
## 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.
- **Quality thresholds**
- **Off-track distance (m)** — perpendicular distance from metadata polyline beyond which an asset is flagged "off track" by the Quality dashboard and post-snap scan. Default 30 m. **Reset to 30 m** button restores the default. Persisted in localStorage. Lowering below ~25 m starts producing noise on curved / sparse polylines (chord cuts a corner the asset is on).
- **Diagnostics**
- **Performance mode** — while panning / zooming, render only basemap + asset markers + range paths (hide roads / scope / metadata / links / labels). Diagnostic; leave off for normal use.
- **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 | Context | Action |
|---|---|---|
| `[` / `]` | filtered list | Step prev / next asset |
| `ESC` | various | Cancel: lasso / link-pick / draw-road / road-edit / image popup / metadata focus / magnifier |
| `Delete` / `Backspace` | link selected | Unlink the currently-selected link line |
| `Shift` + click | OSM vertex | Mark / unmark a road vertex (red ✕) |
| `Delete` / `Backspace` | OSM edit, marked vertices | Delete all marked vertices on the active road |
| `Delete` / `Backspace` | OSM edit, focus + selection | Hide all currently-selected roads (session-only) |
| Right-click | OSM edit, focus | Hide that road instantly |
---
## Undo / Redo
Two independent stacks:
**Asset audit log** — every state-changing asset action writes an audit row. The **Recent actions** panel shows the last N. **Undo** on any row reverts; **Redo** replays. Multi-asset operations (bulk delete, distribute, auto-link, snap) revert atomically as a single step.
**OSM edit ring buffer** — separate 3-deep, in-session undo for road edits, with its own **↶ Undo last edit** button in the OSM edit panel. Covers flip / simplify / delete vertices / drag vertex / ignore-for-snap toggle / hide / restore-hidden. Cleared on Exit OSM edit mode. Merge and whole-road creation / deletion are **not** captured here — be deliberate with those.
Road edits do not appear in the asset audit log; the asset Undo and the OSM Undo never collide.
---
## 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.
- **Per-video metadata didn't auto-load on startup** — confirm the **Per-video metadata** row in the Loaded data section shows a non-zero count. If it does and the polylines aren't drawing, toggle **Metadata** in the Layers picker. If the count is zero after a previous import, the DB was wiped (Reset DB or manual `markers.db` delete) — re-pick the JSON.
- **Quality "Off track" flags too many / too few rows** — adjust **Settings → Quality thresholds → Off-track distance**. Default 30 m. Going below ~25 m starts producing noise on curved / sparse polylines (chord cuts a corner the asset is on).
- **Off-track flagged assets that look fine on the map** — check that the asset's `video_name` has metadata loaded. If the metadata is for a different video the chord-distance calc compares against the wrong track.
- **Bulk road tools panel doesn't show** — needs OSM edit mode AND a focused video. Tap a metadata polyline on the map (or check exactly one video in Filters) to focus, then press **Edit OSM roads**.
- **Magnifier shows a black circle** — basemap tile fetch hadn't completed when the lens map mounted; move the cursor a couple of pixels to trigger a re-render, or close and re-open the magnifier.