kml first commit

This commit is contained in:
2026-04-27 12:48:37 +05:30
commit ac72da88f2
48 changed files with 24957 additions and 0 deletions

176
README.md Normal file
View File

@@ -0,0 +1,176 @@
# 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.