Files
osmWorkflow/.trellis/tasks/archive/2026-08/08-07-qgis-traffic-signal-overrides/design.md

5.0 KiB

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:

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:

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

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.