19 KiB
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
- Login — pick or create a user when the app opens. The username is stamped on every audit-log entry.
- 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.
- 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 fromclasses.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
sidelabel; 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_nameisNot available/ NA.
- L↔R: requires assets to have a
- Pair max slider (2–60 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.
- Filter the map to the affected slice (e.g.,
video=X,name=Streetlight). - Click an asset → Mark as anchor (gold ring appears).
- Drag the gold-ringed asset to where it should be. Repeat for as many anchors as you like.
- 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 first–last anchor span are not touched.
- 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.1–30 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
onewaythrough 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
- Shift-click a vertex pin → turns red with
✕. Repeat to mark more. - Press Del → all marked vertices removed in one shot.
- Clear marks unselects without deleting. Shift-click a marked vertex to unmark.
- The road must keep ≥ 2 vertices.
B. Sweeping — Simplify by tolerance
- Simplify (m) slider (0.5–20 m, default 2 m). Higher = more aggressive.
- Click Simplify this road → Douglas-Peucker on the polyline.
- Status bar reports
before → aftervertex counts.
Bulk road tools (focus mode only)
A "Bulk road tools — focus:
- 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_ignoredcolumn on theroadstable — 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_pathURLs to disk (HTTPS URLs always pass through unchanged).
Export
The Export data… button writes every non-deleted asset in one of four formats:
.jsonSource JSON — round-trippable. Same shapeimport_fixed_assetsandimport_range_assetsaccept (separatefixedandrangearrays). Includesimage_path*,side,deleted, etc..geojson— FeatureCollection. Points for fixed assets, LineStrings for ranges. Properties includeimage_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:
assetsonly 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
onewaydirection. - Re-importing wipes my edits — re-import preserves rows where
modified=1(manual moves) and rows the user deleted; onlymodified=0geometry 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.dbdelete) — 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_namehas 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.