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

@@ -144,20 +144,22 @@ OSM way 的端点不一定在原始 XML 中有三个以上相连 wayosm2stree
**教训****跨阶段契约必须随产物保存;兼容旧产物的字符串回退也要被审查**。
### 坑 6部分构建复用了过期的交通信号锚点
### 坑 6部分构建复用了过期的交通信号运行时数据
`scripts/lib/traffic-signals.js` 根据当前 OSM 的 `highway=traffic_signals` 控制节点、
`vehicle_stop_lines.geojson``intersection_surface.geojson` 派生
`osm2streets_web_out/traffic_signals.json`。Blender 将这份文件中的每个 signal id 导出为
三个动态灯节点和一组倒计时节点,`scripts/lib/cesium-preview.js` 再按相同 id 控制它们。
`intermediates` 才能根据当前 OSM 的 `highway=traffic_signals` 控制节点、
`vehicle_stop_lines.geojson``intersection_surface.geojson` 初始化可编辑的
`traffic_signal_assemblies.geojson`。此后该 GeoJSON 是 QGIS 编辑生命周期内的事实源;
`traffic_signals.json` 只是严格校验后派生的运行时数据。Blender 将其中每个稳定的
`signal_uid` 导出为静态设施、三个动态灯节点和一组倒计时节点,
`scripts/lib/cesium-preview.js` 再按相同 id 控制它们。
因此执行 `blender,cesium,preview` 这类部分构建时,必须在 Blender stage 入口重新写入
交通信号文件。若沿用旧文件GLB 可能已经包含新增 T/十字路口,但预览仍只控制旧的
signal id表现为灯不切换、数字叠加或路口整体异常。该刷新由
因此执行 `blender,cesium,preview` 这类部分构建时,必须在 Blender stage 入口从当前
`traffic_signal_assemblies.geojson` 重建运行时 JSON但绝不能重新从 OSM 初始化位置,
否则会覆盖 QGIS 中移动、旋转或禁用设施的编辑。该刷新由
`scripts/build-area.js:buildBlenderScene()` 负责。
**教训****任何由输入 OSM 或归一化图层派生、又被多个后续 stage 共享的中间 JSON
都必须在最早消费它的 stage 重新生成,不能只在完整 `intermediates` 构建时生成。**
**教训****跨阶段运行时 JSON 必须在最早消费它的 stage 从当前权威产物重建;同时要
区分“初始化来源”和“编辑后的事实源”,不能用早期输入覆盖人工编辑。**
---

View File

@@ -343,13 +343,14 @@ out.vehicleStopLines = crosswalkData.stopLines;
// 原生 lane_markings 停止线不得复制到输出。
```
## 信号锚点的跨阶段消费
## 可编辑信号设施与运行时锚点的跨阶段消费
### 1. Scope / Trigger
路口信号设施需要同时被 Blender 主 GLB 和 Cesium 预览消费时,使用
`<geojsonDir>/traffic_signals.json`。它是附属 intermediates 产物,而不是第十个
osm2streets/QGIS 图层。
`<geojsonDir>/traffic_signal_assemblies.geojson` 是 GeoPackage/QGIS 中的附属可编辑点图层;
`<geojsonDir>/traffic_signals.json` 是从它严格校验并派生的运行时产物。前者不属于九个
`SCENE_LAYERS`,后者不进入 GeoPackage。
### 2. Signatures
@@ -366,15 +367,19 @@ area.outputs.trafficSignals
### 3. Contracts
- `build-area.js:writeTrafficSignals()` 是锚点 JSON 的生产者,调用
`traffic-signals.js:readTrafficSignals()`,输入为 `vehicle_stop_lines.geojson`
`intersection_surface.geojson`
- `intermediates``reimport` 都必须在其 GeoJSON 产物稳定后重写锚点,确保 QGIS
人工修补反导入后Blender 和 preview 仍使用同一事实
- `intermediates` 从 OSM control、停止线和路口面初始化 `traffic_signal_assemblies.geojson`
并将其作为附属点层导入 GeoPackage完整重跑 intermediates 会像道路图层一样覆盖人工编辑。
- `reimport` 必须与九个场景层一起暂存导出附属层,先校验全部信号要素,再替换任何输出
- `build-area.js:writeTrafficSignals()` 只从当前 `traffic_signal_assemblies.geojson` 重建运行时
`traffic_signals.json`。Blender 入口也执行这一步,但不得重新从 OSM 初始化位置
- `blender``preview` 在启动前必须检查该文件存在;前者把静态设施写进 `05_Props`
后者只叠加动态灯珠、倒计时和车辆相位。
- `traffic_signals.json` 不得加入 `SCENE_LAYERS`GeoPackageQGIS 工程;这些层只能
继续包含九个道路场景图层
- `traffic_signal_assemblies.geojson` 必须加入 GeoPackage/QGIS 工程,但不得加入
`SCENE_LAYERS`、合并道路场景或栅格预览;`traffic_signals.json` 仍不得加入 GeoPackage
- `signal_uid` 必须由 control id、source way id 和相邻 arm node id 确定性生成;运行时 `id`
使用该技术 id。`display_id` 可编辑且非空时唯一,修改它不得重命名 GLB 节点。
- Point 几何是灯杆地面点;`stop_lon`/`stop_lat` 独立保存,移动杆件不得移动车辆停止点。
- `enabled=false` 的要素保留在编辑层但不进入运行时 signals。
- `layout.countdownLateralMeters` 等几何字段是 Blender/preview 的共同事实源;横向正值统一
表示相对来车方向的右侧。不得在任一消费方用独立的负号约定替代它。
- `layout.mastHeightMeters``layout.headCenterHeightMeters` 必须相等,表示横杆与灯壳的
@@ -385,9 +390,9 @@ area.outputs.trafficSignals
| 条件 | 结果 |
|---|---|
| `intermediates``reimport` 有合法停止线和路口面 | 写出 `version``signals` 数组,即使数组为空 |
| `intermediates``reimport` 有合法编辑层 | 写出 `version``signals` 数组,即使数组为空 |
| 直接运行 `blender` / `preview` 但锚点不存在 | 在启动外部工具前报 `Traffic signal anchors not found` |
| 单个停止线无法可靠关联路口 | 锚点生成器跳过该项,其他进口照常输出 |
| `signal_uid` 缺失/重复、非空 `display_id` 重复、字段或 Point 无效 | 重导入在替换任何输出前失败 |
| 用户仅修改 QGIS 后运行 `reimport` | 重新生成锚点,不沿用旧坐标 |
### 5. Good/Base/Bad Cases