Files
osmWorkflow/.trellis/spec/preview/vehicle-routes.md

121 lines
6.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 车辆连续路线
## 1. Scope / Trigger
适用于 `scripts/lib/vehicle-route.js` 生成的路线 JSON以及
`scripts/lib/cesium-preview.js` 对车辆巡航路线的读取与展示。
触发修改路线生成、OSM 转向标签解析、车辆选择菜单或路线 JSON 字段时。
路线仅用于 Cesium 验证预览,不构成交通仿真或法规级导航。
## 2. Signatures
```js
buildVehicleRoute(osmPath, lanePolygonsPath, networkPath, intersectionSurfacePath) => {
source, laneSource, networkSource, intersectionSource, bounds, generatedAt, speedMetersPerSecond, loop,
routes, segments, diagnostics
}
allowedTurns(tags, direction) => Set<"left" | "through" | "right">
classifyConnection(incomingEdge, outgoingEdge) =>
"left" | "through" | "right" | "u_turn"
```
浏览器运行时调用 `addVehicleCruises(viewer, routeData, vehicleModelName)`;它首先读取
`routeData.routes`,仅在其不存在时回退到 `routeData.segments`
## 3. Contracts
- `routes` 是当前主字段;`segments` 必须是同一数组的兼容别名,供旧预览使用。
- 每个路线至少包含 `id``coordinates``centerlineCoordinates``lengthMeters`
`maneuvers``edgeIds``laneSegments``connectors`。道路区间来自匹配的 Driving lane polygon 中轴。
- 路线拓扑以 `network.json` 的 internal road 和 intersection 为准;禁止把整个 OSM way 直接当作一条不可分割 edge。
- connector 必须绑定同一个 internal intersection并位于对应 `intersection_surface.geojson` 内或允许的边界容差内;越界时拒绝候选路线。
- preview 必须将 `lane_polygons.geojson``network.json``intersection_surface.geojson` 作为强制输入;缺失或无效时在写产物前失败。
- route 经纬度由 Cesium 按 WGS84 直接放置;最终道路 GLB 必须由 WGS84 ECEF→ENU
`Projector` 生成。禁止以固定米/度近似投影道路,否则即使 route 与 lane polygon
完全一致,最终画面仍会随离锚点距离产生横向偏移。
- 单条路线无法可靠匹配时跳过并写结构化 `diagnostics`,不得回退固定或默认车道宽度。
-`oneway=yes`(及等价真值)的 way 只能按 OSM 原始方向生成 edge绝不能生成反向
`:backward` edge`oneway=-1` 仅允许反向 edge。
- 去程在路口按入边方向读取 `turn:lanes:forward``turn:lanes:backward`,只有标签中的
`left``through``right` 才是候选出口;无标签时允许这三类非 U-turn 动作。
- 返程是展示路线的原路回返,不以反向 `turn:lanes` 再次否决,但依旧不可逆行单行道。
- 路网没有闭环时,在去程和返程端点插入平滑调头曲线;不得在 way 端点或路口瞬移。
- 选择菜单使用 `#编号 · 长度 m · 左 N / 右 N / 直 N`,因为一条路线可跨越多个道路名称。
- 预览只显示当前下拉框选中车辆的 route polyline避免多条闭环轨迹在路口重叠造成错误的偏移判断。
## 4. Validation & Error Matrix
| 条件 | 结果 |
|---|---|
| 缺少或无法读取 route JSON | 预览继续加载,只取消巡航控件 |
| `routes` 存在但为空 | 不回退到旧 `segments`;没有可播放车辆 |
| 可行驶 way 少于两个节点或不在区域范围 | 不生成 edge |
| 只存在反向单行可达路径 | 不生成违反单行限制的路线 |
| 路口夹角接近掉头 | 分类为 `u_turn`,不作为去程出口 |
| 候选路线不足五条 | 输出实际可用数量,预览按已有路线加载 |
## 5. Good/Base/Bad Cases
- 正常:树状道路网产生多条跨 way 往返路线,车辆经过左、右、直三种连接并在端点平滑掉头。
- 基础:旧 JSON 只有 `segments` 时,预览仍能创建车辆与 Follow 控制。
- 错误:对返程再次套用反向 `turn:lanes`,使原路返回在树状网络中被错误过滤。
## 6. Tests Required
- `node scripts/test-preview-assets.js`:断言路线闭合、端点调头、`turn:lanes` 拆分、左/右/直
分类、单行道不逆行,以及 `segments === routes`
- `node --check scripts/lib/vehicle-route.js`
`node --check scripts/lib/cesium-preview.js`:保证 Node 与浏览器直载脚本语法可用。
- 对目标区域运行 `npm run build:area -- --config config/areas/<area>.json --stages preview`,确认
`routes` 中存在左、右、直动作,且 Cesium 下拉标签显示编号、长度与动作统计。
- 修改地理投影时必须运行 `blender,cesium,preview`,不能只重跑 preview最终检查青色路线
到黄色中心线及道路边缘的横截面距离,确认两侧路线分别位于各自车道中心。
## 7. Wrong vs Correct
错误:优先使用旧字段,导致新路线元数据无法被消费。
```js
const segments = routeData.segments || routeData.routes || [];
```
正确:新字段优先,旧字段仅作兼容回退。
```js
const routes = routeData.routes || routeData.segments || [];
```
错误:为使路线闭合而生成单行道路的反向 edge。
```js
edges.push(makeEdge(way, refs.reverse(), coords.reverse(), "backward"));
```
正确:单行仅保留其允许的方向,树状网络用端点调头闭合预览路线。
```js
if (oneway !== "-1") edges.push(makeEdge(way, refs, coords, "forward"));
if (!isOneWay(oneway)) edges.push(makeEdge(way, [...refs].reverse(), [...coords].reverse(), "backward"));
```
## 信号动态 GLB 契约
`traffic_signals.json``pose.*` 是 Blender 静态设施、动态灯珠和倒计时共享的锚点。Blender
把发光灯珠导出为独立的 `*-traffic-signals-dynamic.glb`preview 必须使用与主 GLB 相同的
`scenePlacement(metadata).modelMatrix` 加载它Cesium 仅按命名灯珠节点切换 `show`。倒计时
例外:它由 Cesium Entity 从 `pose.countdown` 的 ENU 坐标与面向直接绘制,避免 glTF 轴变换
反转七段字形。
动态表面不能与静态镜片或倒计时外壳共面:镜片和数码管必须沿本地 `face` 轴前移
`(static_depth + dynamic_depth) / 2 + epsilon`。这是模型局部几何关系,不是经纬度修正;
否则静态网格会通过深度测试遮住发光状态,表现为灯不切换或数字不可见。
错误:在 Cesium 用 `fromDegrees`/Entity 重新计算动态设施,或将动态网格中心与静态表面中心
重合。
正确Blender 生成命名节点 `TrafficSignalDynamic_<signal-id>_<state>`;浏览器在同一 model
matrix 下加载该 GLB并只切换这些灯珠节点。倒计时 Entity 使用 `pose.countdown` 的经纬度、
高度、`faceHeadingDegrees` 生成与牌面相同的 ENU 坐标轴。