feat: add native road direction arrows
This commit is contained in:
@@ -367,6 +367,53 @@ if (!networkSaysIntersection && (roadCounts.get(endpoint.id) || 0) < 3) return n
|
||||
fs.writeFileSync(diagnosticsPath, `${JSON.stringify(diagnostics, null, 2)}\n`);
|
||||
```
|
||||
|
||||
## Native 道路标线
|
||||
|
||||
### 1. 范围与触发条件
|
||||
|
||||
`node scripts/compile-native-roads.js --config <area>` 将原生道路标线写入
|
||||
`outputs/<area>/native-road/layers/`。它不读取 osm2streets 渲染几何;只复用
|
||||
`turn-lane-arrows.js` 中已测试的箭头模板。工作台 `GET /api/state` 原样服务这些
|
||||
GeoJSON,native Blender 构建通过 `catalog.NATIVE_ROAD_LAYERS` 消费它们。
|
||||
|
||||
### 2. 图层契约
|
||||
|
||||
| 文件 | 语义 | 必需 provenance | Blender material layer |
|
||||
|---|---|---|---|
|
||||
| `lane_separators.geojson` | 同向相邻车道的分隔线 | `native-road-lane-separator/v1` | `lane_separators` |
|
||||
| `direction_arrows.geojson` | 沿定向车道重复的直行方向箭头 | `native-road-direction-arrow/v1` | `lane_arrows_webscale` |
|
||||
| `turn_arrows.geojson` | 明确 `turn:lanes` 的路口动作箭头 | `native-road-turn-arrow/v1` | `lane_arrows_webscale` |
|
||||
|
||||
方向箭头必须带 `road_id`、`lane_id`、`osm_way_ids`、`direction`、`lane_index`、
|
||||
`sequence`、`distance_along_lane_meters` 和 `placement_interval_meters`。转向箭头
|
||||
必须带 `maneuver` 与 `placement_distance_meters`。两者不能共用 provenance 或假装为
|
||||
彼此:前者表达沿路行驶方向,后者表达路口处允许动作。
|
||||
|
||||
### 3. 放置与错误矩阵
|
||||
|
||||
| 条件 | 结果 |
|
||||
|---|---|
|
||||
| 车道长度不足以容纳两端 14m 缓冲 | 不生成道路方向箭头 |
|
||||
| 可用车道长度 | 从 14m 起按 32m 间距生成 `through` 箭头 |
|
||||
| OSM 未提供 `turn:lanes` | 不生成路口转向箭头 |
|
||||
| `turn:lanes` 存在但动作不受已测试模板支持 | 记录诊断,不猜测动作 |
|
||||
| native Blender 构建缺任一图层文件 | 在 `ensureNativeRoadLayers()` 失败,不能静默漏画 |
|
||||
|
||||
### 4. 必需测试
|
||||
|
||||
- `npm run test:native-road`:方向箭头的 Polygon、provenance、间距,以及无标签道路
|
||||
不生成路口转向箭头。
|
||||
- `npm run test:road-workbench`:方向箭头开关、选择溯源和概览标签。
|
||||
- `npm run build:area -- --config config/areas/nantaizi-lake-innovation-valley.json --stages blender,cesium,preview --road-provider native`:日志必须列出
|
||||
`direction_arrows` 与 `turn_arrows`,且不运行 `package`。
|
||||
|
||||
### 5. 错误与正确写法
|
||||
|
||||
错误:把默认 `through` 当作路口 `turn:lanes` 动作,统一写入 `turn_arrows.geojson`。
|
||||
|
||||
正确:道路方向箭头进入 `direction_arrows.geojson`;只有 OSM 明确标注的动作进入
|
||||
`turn_arrows.geojson`。工作台用两个开关呈现,Blender 复用同一现有箭头材质。
|
||||
|
||||
## 斑马线与停止线来源
|
||||
|
||||
### 1. 范围与触发条件
|
||||
|
||||
@@ -18,7 +18,9 @@
|
||||
"commit": null,
|
||||
"pr_url": null,
|
||||
"subtasks": [],
|
||||
"children": [],
|
||||
"children": [
|
||||
"08-14-native-road-lane-markings"
|
||||
],
|
||||
"parent": null,
|
||||
"relatedFiles": [],
|
||||
"notes": "",
|
||||
|
||||
@@ -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."}
|
||||
77
.trellis/tasks/08-14-native-road-lane-markings/design.md
Normal file
77
.trellis/tasks/08-14-native-road-lane-markings/design.md
Normal file
@@ -0,0 +1,77 @@
|
||||
# Native Lane Markings Design
|
||||
|
||||
## Architecture
|
||||
|
||||
The native compiler remains the source of truth. It derives two new polygon
|
||||
layers alongside its existing surface, sidewalk, lane-centerline, and
|
||||
connector outputs:
|
||||
|
||||
```text
|
||||
canonical directed roads + lane centerlines + junction cutbacks
|
||||
|
|
||||
+-- lane separators: paint polygons between adjacent same-direction lanes
|
||||
|
|
||||
+-- direction arrows: repeated through-arrow template on directed lanes,
|
||||
| outside the reserved junction marking zone
|
||||
|
|
||||
+-- turn arrows: tested existing template, anchored to an incoming lane
|
||||
only when that lane has an explicit supported turn:lanes value
|
||||
```
|
||||
|
||||
No OSM2streets rendered geometry is consumed by this path. The existing arrow
|
||||
template library is reused only as a geometry/style asset, so the native lane
|
||||
ID and OSM tags remain the evidence for placement.
|
||||
|
||||
## Contracts
|
||||
|
||||
- `layers/lane_separators.geojson`: polygon FeatureCollection. Each feature
|
||||
records `native_id`, directed `road_id`, adjacent lane indices, source OSM
|
||||
ways, and `native-road-lane-separator/v1` provenance.
|
||||
- `layers/turn_arrows.geojson`: polygon FeatureCollection. Each feature records
|
||||
its `native_id`, `road_id`, `lane_id`, OSM way IDs, direction, lane index,
|
||||
maneuver, template asset, placement distance, and placement provenance.
|
||||
- Unsupported turn values, a missing usable incoming-lane segment, or an
|
||||
insufficient pre-junction placement distance create a diagnostic and no
|
||||
arrow geometry.
|
||||
- `layers/direction_arrows.geojson`: polygon FeatureCollection. Each feature
|
||||
records the native lane and directed road, OSM way IDs, a stable sequence
|
||||
index, its distance along the lane, and `native-road-direction-arrow/v1`
|
||||
provenance. It uses the tested `through` template but is not a turn claim.
|
||||
- The workbench serves both layers, draws them separately from its current
|
||||
centerline/connector debug layer, and selects them by `native_id`.
|
||||
- `catalog.NATIVE_ROAD_LAYERS` maps the two native sources to the existing
|
||||
`lane_separators` and `lane_arrows_webscale` Blender materials. The native
|
||||
adapter does not extend the osm2streets scene-layer registry.
|
||||
|
||||
## Placement
|
||||
|
||||
An incoming lane is oriented in driving direction. A turn arrow is sampled
|
||||
from that lane's endpoint backwards by the configured safe distance, staying
|
||||
outside the junction cutback. Its template basis uses the sampled lane tangent;
|
||||
therefore it is on and aligned with the lane rather than the OSM centerline or
|
||||
a screen-space direction. Multiple template rings remain separate polygons.
|
||||
|
||||
Lane separators are narrow polygons centered between adjacent lane centerlines
|
||||
on a single directional carriageway. They stop at the same junction cutbacks as
|
||||
the lane centerlines. A one-lane direction produces none.
|
||||
|
||||
Direction arrows are sampled at a fixed road-scale interval along the same
|
||||
directed lane centerline. Their candidates exclude both endpoint buffers and
|
||||
the turn-arrow reserve at the incoming end. This preserves a readable repeated
|
||||
direction cue without overlapping a turn instruction at a junction.
|
||||
|
||||
## Compatibility And Rollback
|
||||
|
||||
All new files are additive under `native-road/layers/`. The existing
|
||||
osm2streets/QGIS layer contract and `package/` are unchanged. Selecting
|
||||
`--road-provider osm2streets` remains rollback. Missing native marking files
|
||||
are a native Blender build error rather than a silent omission.
|
||||
|
||||
## Risks
|
||||
|
||||
- OSM turn tags can be incomplete or incompatible with the inferred lane
|
||||
count. These are diagnostics, not guessed arrows.
|
||||
- Very short approaches can have no safe position before the cutback. They are
|
||||
skipped with a source-traceable diagnostic.
|
||||
- Blender and Cesium need a real native build to verify the mesh/material
|
||||
contract, not only GeoJSON unit tests.
|
||||
@@ -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."}
|
||||
31
.trellis/tasks/08-14-native-road-lane-markings/implement.md
Normal file
31
.trellis/tasks/08-14-native-road-lane-markings/implement.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# Implementation Plan
|
||||
|
||||
1. Add reusable template-placement helper to the existing turn-arrow module,
|
||||
preserving its supported-asset gate and output ring shape.
|
||||
2. Extend the native compiler with lane-separator, repeated road-direction
|
||||
arrow, and explicit-turn-arrow polygon generation plus source diagnostics
|
||||
and layer persistence.
|
||||
3. Extend native output records/counts and Blender adapter mappings. Reuse
|
||||
existing `lane_separators` and `lane_arrows_webscale` materials only.
|
||||
4. Add Workbench layers, toggles, selection/provenance inspector entries, and
|
||||
preserve the existing Workbench-only direction triangle behavior.
|
||||
5. Add focused fixtures for supported turn placement, unsupported maneuver,
|
||||
short approach skip, and separator geometry; run native/workbench/build
|
||||
stage tests.
|
||||
6. Build Nantaizi with `blender,cesium,preview --road-provider native`, inspect
|
||||
the final preview, and confirm no `package/` publication occurred.
|
||||
|
||||
## Validation
|
||||
|
||||
```bash
|
||||
npm run test:native-road
|
||||
npm run test:road-workbench
|
||||
npm run test:turn-lane-arrows
|
||||
npm run test:build-stages
|
||||
npm run road:compile -- --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 existing output path
|
||||
is replaced.
|
||||
74
.trellis/tasks/08-14-native-road-lane-markings/prd.md
Normal file
74
.trellis/tasks/08-14-native-road-lane-markings/prd.md
Normal file
@@ -0,0 +1,74 @@
|
||||
# Native road lane markings and turn arrows
|
||||
|
||||
## Goal
|
||||
|
||||
Complete the native-road visual language for Nantaizi before any cross-area
|
||||
migration: lane separators, travel-direction markers, and OSM-backed turn
|
||||
arrows must be inspectable in the Road Workbench and visible in Blender and
|
||||
Cesium output.
|
||||
|
||||
## Confirmed Facts
|
||||
|
||||
- Native output currently contains directed lane centerlines and connector
|
||||
curves, but it does not emit paintable lane-separator or turn-arrow polygons.
|
||||
- The existing osm2streets path has tested arrow templates in
|
||||
`scripts/lib/turn-lane-arrows.js`, the `lane_arrows_webscale` material layer,
|
||||
and a matching Blender material. Reuse these instead of introducing a second
|
||||
arrow style.
|
||||
- Earlier reviews established that direction markers must sit on the OSM / lane
|
||||
centerline, use a clearly directional sharp triangle, and never be treated as
|
||||
a road-surface decoration that drifts sideways.
|
||||
- Turn arrows must follow the actual incoming lane and be placed before its
|
||||
junction, with OSM source way, direction, lane index, and maneuver retained
|
||||
as provenance.
|
||||
- Scope remains Nantaizi only. Existing osm2streets output remains untouched.
|
||||
|
||||
## Requirements
|
||||
|
||||
- R1: Native compilation emits polygonal lane-separator markings derived from
|
||||
its own directed lane geometry.
|
||||
- R2: Native compilation emits turn-arrow polygons for supported OSM
|
||||
`turn:lanes` maneuvers, using the existing tested arrow templates and the
|
||||
exact native incoming-lane centerline for placement.
|
||||
- R2a: Native compilation emits repeated straight-ahead direction-arrow
|
||||
polygons along directed lanes, matching the visual role of osm2streets'
|
||||
ordinary road arrows. These are a separate layer from turn arrows, retain
|
||||
their own provenance, and leave a clear buffer around junction turn arrows.
|
||||
- R3: Native output preserves provenance for every marking: native road/lane
|
||||
ID, OSM way IDs, direction, lane number, maneuver, and placement method.
|
||||
- R4: The Workbench renders markings in a separately controllable layer and
|
||||
exposes those provenance fields on selection.
|
||||
- R5: The native Blender adapter consumes native marking layers through the
|
||||
existing lane-separator and lane-arrow material layers; Cesium must receive
|
||||
the same geometry through the exported GLB.
|
||||
- R6: Unsupported, unplaceable, or ambiguous arrow inputs become diagnostics;
|
||||
the compiler must not invent a maneuver.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] Nantaizi native output contains valid polygon GeoJSON for generated lane
|
||||
separators, repeated road direction arrows, and every supported, explicitly
|
||||
tagged turn arrow.
|
||||
- [ ] A Workbench user can toggle, select, and inspect a generated marker and
|
||||
see its lane, OSM, maneuver, and placement provenance.
|
||||
- [ ] A selected direction marker is geometrically aligned to its directed lane
|
||||
centerline; a selected turn arrow is on its incoming lane before the junction.
|
||||
- [ ] Blender scene output and Cesium GLB contain native lane markings and
|
||||
arrows with the existing visual material language.
|
||||
- [ ] Unit tests cover a normal supported arrow, an unsupported maneuver, and
|
||||
an unsafe/too-short placement; native compile and final Nantaizi visual build
|
||||
pass without publishing `package/`.
|
||||
|
||||
## Out Of Scope
|
||||
|
||||
- Inventing turn arrows for untagged lanes, traffic-control semantics, changing
|
||||
QGIS/osm2streets layers, or processing another area.
|
||||
|
||||
## Key Decision
|
||||
|
||||
- Sharp travel-direction triangles remain a Workbench-only inspection aid.
|
||||
They explain raw OSM node order after a road is selected.
|
||||
- Repeated `through` direction arrows are final road markings, distinct from
|
||||
both those debug triangles and OSM-backed junction turn arrows. They are
|
||||
placed on native lane centerlines at a fixed interval and enter the same
|
||||
Blender/Cesium material layer as turn arrows.
|
||||
26
.trellis/tasks/08-14-native-road-lane-markings/task.json
Normal file
26
.trellis/tasks/08-14-native-road-lane-markings/task.json
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"id": "native-road-lane-markings",
|
||||
"name": "native-road-lane-markings",
|
||||
"title": "Native road lane markings and turn arrows",
|
||||
"description": "Complete Nantaizi native lane separators, travel direction and turn-arrow geometry through Road Workbench, Blender and Cesium before cross-area migration.",
|
||||
"status": "in_progress",
|
||||
"dev_type": null,
|
||||
"scope": null,
|
||||
"package": null,
|
||||
"priority": "P1",
|
||||
"creator": "dingkang",
|
||||
"assignee": "dingkang",
|
||||
"createdAt": "2026-08-14",
|
||||
"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": {}
|
||||
}
|
||||
Reference in New Issue
Block a user