feat: add native road control markings

This commit is contained in:
2026-08-17 10:01:44 +08:00
parent ea8a3622b9
commit 4c4f4534c0
16 changed files with 418 additions and 20 deletions

View File

@@ -19,7 +19,8 @@
"pr_url": null,
"subtasks": [],
"children": [
"08-14-native-road-lane-markings"
"08-14-native-road-lane-markings",
"08-17-native-road-control-markings"
],
"parent": null,
"relatedFiles": [],

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,66 @@
# Native Road Control Markings Design
## Architecture
The native compiler remains the source of truth. It extends its canonical OSM
parse with marked crossing nodes, then derives two additive polygon layers from
the crossing evidence, native directed lanes, and native junction plans:
```text
OSM crossing node + native directed lane centerlines + junction plans
|
+-- crosswalks.geojson: six zebra stripe polygons per safe crossing
|
+-- vehicle_stop_lines.geojson: one safe approach stop-line polygon
```
No osm2streets GeoJSON is read. Existing crossing geometry helpers may be
extracted or adapted only when they operate on native lane data and retain
native provenance.
## Source And Placement
- A source node is eligible only when `highway=crossing` and
`crossing:markings` is not `no`, `none`, or `unmarked`.
- The compiler finds native roads containing the crossing's OSM node and uses
the nearest compatible directed lane centerline to obtain the road tangent.
- Crosswalk stripes are perpendicular to that tangent and constrained to the
native road width. Existing fixed zebra dimensions are retained initially:
six 0.45m stripes with 0.45m gaps, 0.45m stripe width, and a highway-based
stripe length.
- A stop line is generated only when the crossing can be associated with a
supported junction approach and a safe outside-of-junction side. Otherwise
the crosswalk may remain valid but the missing stop line is diagnostic.
- Duplicate nearby crossing nodes use a stable cluster representative so one
physical crosswalk does not produce duplicate stripes.
## Contracts
`layers/crosswalks.geojson` and `layers/vehicle_stop_lines.geojson` are Polygon
FeatureCollections. Each feature records its crossing OSM node, source OSM way,
native directed road/lane when available, direction, placement method, and
`native-road-crosswalk/v1` or `native-road-stop-line/v1` provenance.
The Workbench API returns both layers as `state.layers.crosswalks` and
`state.layers.vehicleStopLines`. Its browser map uses separate toggleable
layers and selection evidence; the scene-preview toggle leaves real control
markings visible.
`catalog.NATIVE_ROAD_LAYERS` maps the sources to existing `crosswalks` and
`vehicle_stop_lines` material layers. This native adapter must not add them to
the osm2streets `ROAD_LAYERS` / `SCENE_LAYERS` registry.
## Compatibility And Rollback
The new files are additive under `native-road/layers/`. Existing osm2streets
output and QGIS input are unchanged. Selecting `--road-provider osm2streets`
remains rollback. A native Blender build treats a missing new layer as an error
rather than silently omitting a visible marking.
## Risks
- Crossing nodes can be detached from a routable road or lie on an ambiguous
multi-road segment. These become diagnostics rather than guessed geometry.
- A physical crossing split into several OSM nodes must deduplicate stably.
- A crosswalk near a non-supported junction may get stripes but no valid stop
line; this difference must be exposed in workbench provenance.

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,31 @@
# Implementation Plan
1. Extend the native OSM parse/model with marked crossing-node evidence while
preserving existing road IDs and parser behavior.
2. Add native crossing clustering, tangent resolution from directed lane
centerlines, stripe geometry, safe stop-line placement, and source
diagnostics.
3. Persist the two new layers in `compile-native-roads.js`, comparison counts,
native build records, required native layer checks, and existing Blender
material mappings.
4. Add Workbench API/state fields, Chinese layer toggles, selection evidence,
and summary counts while retaining scene-preview behavior.
5. Add focused fixtures for marked and unmarked crossings, duplicate cluster
handling, a missing native-lane diagnostic, and output layer contracts.
6. Run native/unit/workbench/build-stage tests, compile/check Nantaizi, then
build `blender,cesium,preview --road-provider native` without `package/`.
## Validation
```bash
npm run test:native-road
npm run test:road-workbench
npm run test:build-stages
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,preview --road-provider native
```
Rollback is selecting `--road-provider osm2streets`; no legacy output path is
changed.

View File

@@ -0,0 +1,61 @@
# Native road control markings
## Goal
Give Nantaizi's native-road provider inspectable, source-traceable crosswalk
and vehicle stop-line geometry, so intersection control markings do not depend
on the osm2streets render output.
## Confirmed Facts
- Native road output already owns road surfaces, sidewalks, lane separators,
repeated direction arrows, and explicit junction-turn arrows.
- Nantaizi's OSM input contains explicit marked crossings, including zebra and
traffic-signal crossings. The existing osm2streets output currently has 48
crosswalk-stripe polygons and 8 stop-line polygons.
- `build-osm2streets-qgis.js:1067` derives these markings from crossing nodes
plus osm2streets driving lanes. Native must not read that rendered geometry;
it can reuse only the tested geometry rules after adapting them to native
directed lanes and junction plans.
- Existing Blender materials already provide `crosswalks` and
`vehicle_stop_lines`; native may map into them without changing the legacy
osm2streets layer registry.
## Requirements
- R1: Native compilation uses explicit marked OSM crossing nodes only, and
emits crosswalk-stripe polygons plus approach stop lines only where safe
native directed-road placement exists.
- R2: Each generated feature preserves crossing node, OSM road, native road or
lane, direction, placement method, and relevant junction provenance.
- R3: The Road Workbench independently toggles, selects, and describes native
crosswalks and stop lines in Chinese.
- R4: Native Blender and Cesium builds consume both layers with the existing
control-marking materials; no `package/` publication is part of validation.
- R5: Missing compatible road context, ambiguous geometry, and unsupported
crossing inputs are diagnostics; the compiler must not invent a crossing.
## Acceptance Criteria
- [ ] Nantaizi native output contains valid `crosswalks.geojson` and
`vehicle_stop_lines.geojson` features with source-traceable properties,
without reading osm2streets rendered layers.
- [ ] A Workbench user can toggle and select either marking type and see the
crossing node, associated road/direction, and placement evidence.
- [ ] Native Blender/Cesium output contains both marking types using existing
materials, after `blender,cesium,preview --road-provider native` and without
publishing `package/`.
- [ ] Tests cover a marked crossing, an unmarked crossing skip, a missing or
ambiguous native-road placement skip, and output-layer contract checks.
## Out Of Scope
- Hand-placed control-marking overrides, traffic-signal state-machine changes,
freehand polygon editing, processing another region, and importing
osm2streets-rendered crosswalk geometry.
## Key Decision
The first version is explicit-OSM-only. This is feasible for Nantaizi and
keeps control markings evidence-backed; missing data remains a diagnostic for
OSM improvement rather than a silent geometric guess.

View File

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