feat: add native preview traffic simulation

This commit is contained in:
2026-08-18 16:57:27 +08:00
parent 0bc949bc24
commit 5403936ae4
21 changed files with 777 additions and 45 deletions

View File

@@ -0,0 +1 @@
{"_example": "Fill with {\"file\": \"<path>\", \"reason\": \"<why>\"}. Put spec/research files only — no code paths. Run `python3 .trellis/scripts/get_context.py --mode packages` to list available specs. Delete this line once real entries are added."}

View File

@@ -0,0 +1,70 @@
# Design
## Authority And Boundaries
The native compiler remains the only road authority. The existing traffic-signal runtime remains the
only signal authority. The new feature adds a route/simulation layer beside those artifacts; it does
not alter signal geometry, phase grouping, or Blender static assets.
```text
native-road/compiled.json + native-road/layers/*
-> native route compiler
-> _preview/<area>-traffic-simulation.json
-> Cesium preview runtime
package/runtime/traffic-signals.json
-> signal phase clock + stop events
```
The descriptor is intentionally package-adjacent, not embedded in the GLB. A consumer can copy the
package and descriptor to another platform and reproduce the simulation without running Node.
## Descriptor Contract
Schema: `native-preview-traffic-simulation/v1`.
Required top-level fields:
- `areaId`, `coordinateSystem` (`WGS84` route coordinates, `ENU` model placement), `generatedAt`
- `source` with relative artifact references and SHA-256 records
- `settings` with speed, acceleration, deceleration, reaction time, vehicle length, and minimum gap
- `routes[]` with ordered WGS84 coordinates, cumulative distances, connector/maneuver IDs, and
`stops[]`
- `signals[]` copied by stable `signal_uid` from the runtime contract, including phase group and
stop-line association; no regenerated pose fields
- `migration` describing schema version, coordinate conversion, update-loop expectations, and
compatibility notes
The descriptor is deterministic for the same OSM, overrides, native compiler version, and settings.
## Route Construction
Use native directional roads and published connector geometry. Build a small number of deterministic
closed demonstration routes that cross real connectors and retain lane/road IDs. Route generation
must reject routes with missing geometry or disabled connectors and write structured diagnostics.
Native stop lines are matched by `road_id`/`lane_id` where available, with a bounded geometric
fallback recorded in the stop record. No fixed-width or legacy polygon fallback is allowed.
## Browser Simulation
Keep the existing signal phase functions and `signalData` payload. Replace the current per-vehicle
independent distance advance with a shared simulation state:
- each vehicle has route distance, speed, desired speed, status, and active stop reason;
- signal stop constraints are evaluated before the native stop line for red/yellow phases;
- leader constraints are evaluated on the same route and wrap around the loop;
- acceleration/deceleration clamps advance toward the minimum of desired speed, signal limit, and
leader-safe speed;
- vehicle position and orientation remain Cesium callback properties, with no per-frame allocation
of heavyweight Cesium objects;
- incident-card behavior remains local to each vehicle and must not mutate the descriptor or package.
Diagnostics expose route count, signal count, stopped vehicles, and queue length in the existing
preview diagnostics panel.
## Migration And Rollback
Document the descriptor, runtime signal schema, coordinate conversion, and a reference update loop in
`docs/native-preview-traffic-simulation.md`. Include a JSON example and a consumer checklist. Legacy
preview route files remain readable only through the existing legacy provider path; native generation
must not depend on them. Removing the new descriptor restores the existing no-cruise native preview.

View File

@@ -0,0 +1 @@
{"_example": "Fill with {\"file\": \"<path>\", \"reason\": \"<why>\"}. Put spec/research files only — no code paths. Run `python3 .trellis/scripts/get_context.py --mode packages` to list available specs. Delete this line once real entries are added."}

View File

@@ -0,0 +1,37 @@
# Implementation Plan
1. Add a native route compiler module that consumes `native-road/compiled.json` and native layers,
emits `native-preview-traffic-simulation/v1`, and records source hashes and migration metadata.
2. Wire native preview generation to write the descriptor and keep legacy osm2streets route
generation unchanged.
3. Extend the browser preview with shared deterministic vehicle state, signal stop constraints,
leader following, queue diagnostics, and graceful empty-route behavior.
4. Preserve the existing signal phase, `signal_uid`, pose, dynamic lens, countdown, disabled-signal,
and incident-card contracts; add focused regression tests for each boundary.
5. Add `docs/native-preview-traffic-simulation.md` with schema, example, coordinate rules, update
loop, migration checklist, and rollback notes.
6. Run focused Node tests, native compile/check, a native build with no legacy directory, and browser
preview validation in the available Blender/Cesium environment.
## Validation Commands
```bash
node --check scripts/lib/native-preview-traffic-simulation.js
node --check scripts/build-area.js
npm run test:native-road
npm run test:traffic-signals
npm run test:preview-assets
npm run test:native-preview-traffic
npm run road:compile -- --config config/areas/nantaizi-lake-innovation-valley.json
npm run road:check -- --config config/areas/nantaizi-lake-innovation-valley.json
npm run build:area -- --config config/areas/nantaizi-lake-innovation-valley.json --stages blender,cesium,compress,package,preview
```
## Risk Controls
- Do not change `scripts/lib/traffic-signals.js` geometry or phase semantics unless a test proves a
migration bug; prefer adapter code.
- Do not add route data to the static package manifest; it belongs beside `_preview/` and is optional.
- If native route generation produces no valid route, emit a valid descriptor with diagnostics and
keep preview usable.
- Keep all route and simulation math unit-testable without Cesium.

View File

@@ -0,0 +1,38 @@
# Native preview traffic simulation and migration contract
## Goal
Extend the native road compiler preview with a deterministic, portable vehicle traffic demonstration that consumes native road topology and the already-validated traffic-signal runtime. The result must be useful as a visual validation tool and as a migration reference for Cesium, Blender, or another platform consuming the generated area package.
## Confirmed Baseline
- Native road compilation is the production authority; QGIS/osm2streets is not a runtime input.
- The previous traffic-signal work is the source of truth and must remain compatible: deterministic `signal_uid`, `phase_group`, `mast_heading_deg`, `face_heading_deg`, stop-line anchors, shared `pose.*`, dynamic lens/countdown assets, and disabled-signal filtering.
- Existing browser preview already has signal phase timing, signal visualization, route stop matching, vehicle incident cards, and a missing-route fallback. Native preview currently omits the route.
- Native road output contains compiled roads/connectors and `vehicle_stop_lines.geojson`; the native package contains `runtime/traffic-signals.json`.
- The feature is preview-level deterministic behavior, not a legal navigation or microscopic traffic simulator.
## Requirements
- R1: Generate a native route artifact from `native-road/compiled.json` and native layer geometry; it must not read `osm2streets_web_out`, QGIS files, or legacy route files.
- R2: Preserve and consume the existing traffic-signal contract without deriving a second signal layout in the browser.
- R3: Vehicles must stop before a red/yellow signal at the native stop line, resume on green, and expose the active stop reason in preview diagnostics.
- R4: Multiple vehicles on the same route must maintain a configurable minimum gap; a stopped front vehicle must cause following vehicles to decelerate and queue rather than overlap it.
- R5: Route, signal, vehicle, stop-event, and following-distance data must be written as versioned, package-adjacent JSON with stable ENU/WGS84 and migration metadata. Another platform must be able to consume the artifact without executing the Node compiler.
- R6: The browser preview must degrade gracefully when there are no valid routes or signals; the primary scene remains usable and diagnostics explain the missing optional capability.
- R7: Documentation must describe the data flow, schemas, coordinate conventions, signal identity, stop-line association, update loop, and migration/rollback guidance.
## Acceptance Criteria
- [ ] Native build emits a versioned route/traffic-simulation descriptor under the area output and preview loads it without any legacy directory present.
- [ ] At least one route crosses a native connector and contains a native stop-line association.
- [ ] A red/yellow phase visibly stops a vehicle before the stop line; green releases it.
- [ ] Two or more vehicles never overlap and maintain the configured minimum gap while cruising and while queued at a signal.
- [ ] Disabled native signals are absent from runtime control and do not create vehicle stops.
- [ ] Preview diagnostics report route count, signal count, stopped vehicles, queue length, and the active simulation descriptor version.
- [ ] Migration documentation and focused tests allow another consumer to reproduce route, signal, stopping, and gap behavior from generated assets alone.
- [ ] Existing traffic-signal tests and native road tests remain green; legacy provider behavior is unchanged.
## Decided Scope
- Simulation fidelity: MVP is a deterministic preview simulation with configurable speed, acceleration/deceleration, reaction time, and minimum gap. A full lane-changing, collision, priority, and multi-intersection traffic engine is deferred.

View File

@@ -0,0 +1,26 @@
{
"id": "native-preview-traffic-simulation",
"name": "native-preview-traffic-simulation",
"title": "Native preview traffic simulation and migration contract",
"description": "",
"status": "in_progress",
"dev_type": null,
"scope": null,
"package": null,
"priority": "P2",
"creator": "dingkang",
"assignee": "dingkang",
"createdAt": "2026-08-18",
"completedAt": null,
"branch": null,
"base_branch": "feature/native-road-compiler",
"worktree_path": null,
"commit": null,
"pr_url": null,
"subtasks": [],
"children": [],
"parent": null,
"relatedFiles": [],
"notes": "",
"meta": {}
}