feat(qgis): add editable traffic signal assemblies

This commit is contained in:
2026-08-07 12:48:38 +08:00
parent 72fa04ddeb
commit e153a1c57d
24 changed files with 766 additions and 243 deletions

View File

@@ -0,0 +1,100 @@
# Design: QGIS Traffic Signal Overrides
## Architecture
Introduce a separate auxiliary-edit-layer registry rather than adding traffic signals to `SCENE_LAYERS`. The initial registry contains one layer:
```text
traffic_signal_assemblies.geojson
geometry: Point (pole ground position, EPSG:4326)
properties: stable identity, source identity, heading, phase, reach, stop point, enabled, z offset
```
The existing runtime file remains:
```text
traffic_signals.json
version/layout/signals[] with full pose.* data
```
The editable GeoJSON is the placement source; the runtime JSON is a derived consumer artifact.
## Data Flow
```text
OSM controls + topology + stop lines + intersections
|
intermediates only
v
traffic_signal_assemblies.geojson
|
import into GeoPackage
|
edit in QGIS
|
reimport
v
traffic_signal_assemblies.geojson
|
validate + derive pose
v
traffic_signals.json
/ \
Blender preview/Cesium
```
`blender` reruns the final validation/derivation arrow from the editable GeoJSON so derived JSON cannot be stale, but it never reruns the OSM initialization arrow.
## Editable Feature Contract
Recommended properties:
| Property | Type | Ownership |
|---|---|---|
| `signal_uid` | string | generated, immutable technical identity |
| `display_id` | string | user-editable unique label/number |
| `control_id` | string | generated OSM control id |
| `approach_id` | string | generated physical approach identity |
| `source_way_id` | string | generated matching/diagnostic field |
| `heading_deg` | number | user-editable assembly facing direction |
| `phase_group` | integer 0/1 | user-editable current two-phase group |
| `mast_reach_m` | positive number | user-editable arm reach |
| `stop_lon`, `stop_lat` | finite numbers | generated vehicle stop point, preserved when pole moves |
| `enabled` | boolean/integer | user-editable suppression flag |
| `z_offset_m` | finite number | user-editable vertical adjustment |
Point geometry is the pole longitude/latitude. The runtime `id` should be derived from `signal_uid`, not display numbering, so changing `display_id` does not rename GLB nodes or break preview control.
## Stable Identity
Extend parsed OSM arm data to retain enough deterministic source identity (control node, way, adjacent arm direction/node). Generate a technical key from those source values. Do not use sorted array index or rounded heading as the primary key.
If topology changes on a future `intermediates` run, the rebuilt GeoPackage may produce new identities. This is consistent with current road-edit lifecycle and is explicitly out of scope for MVP migration. Validation still reports duplicate identities and malformed source fields.
## QGIS Integration
- Add an auxiliary layer definition separate from the nine render layers.
- Import it into the same GeoPackage after render layers.
- Include it in the generated project but exclude it from the merged scene and 2D raster preview unless deliberately enabled for editing visibility.
- Use a point marker plus rotated direction indicator driven by `heading_deg` and label by `display_id`, falling back to `signal_uid`.
- Configure read-only/editor widgets where practical: technical/source ids read-only; phase group constrained to 0/1; numeric fields constrained to valid ranges; enabled as checkbox.
## Reimport and Atomicity
Extend the reimport layer manifest to include auxiliary editable layers while keeping render-scene merge derived only from `SCENE_LAYERS`. Export every layer into staging, parse and validate all editable features, then replace output files. Runtime JSON is written only after the staged auxiliary layer passes validation.
## Compatibility
- The next `intermediates` run bootstraps existing areas; no old JSON migration is required.
- Main `.blend`/GLB geometry changes intentionally when a QGIS edit changes a signal.
- Dynamic and countdown GLBs continue using runtime signal ids, now stable across ordinary reimport edits.
- Current two-phase simulation remains unchanged.
## Risks and Controls
- **OSM way splitting changes source ids:** accepted across a full intermediates rebuild; ordinary reimport is stable.
- **QGIS boolean/string coercion:** normalize known GDAL representations before strict validation and test the round-trip output.
- **Accidental source-field editing:** mark technical fields read-only in QGIS and validate identity format during reimport.
- **Partial overwrite on invalid auxiliary data:** retain the existing staging-before-replace discipline.
- **Old spec conflict:** update pipeline specs that currently forbid traffic-signal anchors in GeoPackage, clarifying the distinction between editable assembly points and derived runtime anchors.