feat: add OSM turn lane arrows

This commit is contained in:
2026-08-05 10:17:34 +08:00
parent 9970e3eeef
commit 9a23f74f0f
34 changed files with 1540 additions and 33 deletions

View File

@@ -0,0 +1,4 @@
{"file":".trellis/spec/pipeline/index.md","reason":"Defines the expected intermediates artifacts and dependency boundaries."}
{"file":".trellis/spec/pipeline/layer-registry.md","reason":"Requires preserving existing lane-arrow layer collection and order across QGIS and Blender."}
{"file":".trellis/spec/pipeline/cli-and-stages.md","reason":"Defines quality-gate and target-area validation expectations."}
{"file":".trellis/tasks/08-04-add-osm-turn-lane-arrows/research/lane-icons.md","reason":"Defines the source provenance and assertion that untested assets cannot be mapped."}

View File

@@ -0,0 +1,74 @@
# Design: OSM turn-lane arrows
## Boundaries
- `scripts/build-osm2streets-qgis.js` remains the intermediates owner. It will
append generated custom features to the existing in-memory `laneArrows`
collection before it is written as `lane_arrows_webscale.geojson`.
- No render layer, QGIS symbol, Blender material, or Cesium export contract
changes. Existing `lane_arrows_webscale` styling and catalog ownership apply
to generated features automatically.
- Vendored upstream artwork lives under a dedicated repository-local asset
directory with its CC0 license and a machine-readable manifest. The manifest
is the source of truth for upstream path, source revision, local path,
support status, and test status.
## Asset Contract
- Import every arrow SVG from `openstreetmap/lane-icons/docs/` that represents
an arrow. Preserve the source bytes and retain `LICENSE.md` with the assets.
- Mark only `through`, `left`, `right`, `through;left`, and `through;right` as
`supported` and `tested` in the manifest. All remaining imported arrows are
`unsupported` and `untested`; no production parser may select them.
- The upstream repository has left-side examples only. Derive `right` and
`through;right` through a deterministic horizontal mirror of the matching
left-side geometry, recording `derived_from` in the manifest.
## Data Flow
1. Parse OSM ways once using the existing OSM parser.
2. Read `turn:lanes:forward` / `turn:lanes:backward`, split lane declarations
by `|`, and map only the five supported normalized maneuvers to manifest
entries.
3. For each valid lane near a determinable intersection endpoint, calculate a
stable lane center and road-local axis; transform the selected local arrow
polygon into WGS84 coordinates.
4. Add a GeoJSON feature with existing render-layer behavior and explicit
provenance: custom source, OSM way id, direction, lane index, maneuver,
source asset, and deterministic feature id/order.
5. Record a structured skipped item when tags, lane geometry, or endpoint
classification are insufficient. Do not invent a fallback location.
6. Existing normalization, scene merge, GeoPackage import, Blender assembly,
and Cesium export consume the expanded collection unchanged.
## Geometry and Compatibility
- Parse only the vendored SVG subset used by supported assets at build time:
`line` elements and `path` commands are converted into local meter-scale
polygons, with cubic curves sampled and SVG strokes expanded into outlines.
The source SVG is the sole geometry authority; no hand-drawn replacement
template is permitted. This stays dependency-free because the supported
upstream syntax is intentionally small and covered by Node tests.
- Use the upstream Standard Arrow shape as the geometry basis, but let the
existing QGIS fill and outline preserve the project's visual language.
- Preserve the existing osm2streets-generated arrow features. Custom features
are additive and have provenance that distinguishes them from upstream
osm2streets output.
- Deterministic ordering is by way id, travel direction, and lane index.
- Each asset manifest entry defines the source SVG's shaft-axis `anchor_x`.
Placement aligns that axis, rather than the SVG viewBox center, with the
lane centerline. Mirrored right-side variants mirror around the same axis.
- Upstream SVG units are converted at `0.10 m` per unit. This calibrates their
local extent against the existing approximately 1.4 m osm2streets arrows;
do not use SVG display-pixel scale as road-marking scale.
## Risks and Rollback
- OSM lane counts, one-way semantics, or endpoint topology can be incomplete.
These cases remain skipped with diagnostics rather than creating misleading
markings.
- Asset import is self-contained and CC0. Rollback removes the custom feature
generation and local asset directory; the existing arrow layer remains
unchanged.
- User approval of the two initial visual samples is required before the
feature is enabled in production output.

View File

@@ -0,0 +1,4 @@
{"file":".trellis/spec/pipeline/index.md","reason":"Defines the intermediates data flow, CommonJS conventions, and existing layer ownership."}
{"file":".trellis/spec/pipeline/layer-registry.md","reason":"The feature adds a source to an existing layer and must preserve the cross-language layer contract."}
{"file":".trellis/spec/pipeline/cli-and-stages.md","reason":"Defines stage ownership and target-area validation commands."}
{"file":".trellis/tasks/08-04-add-osm-turn-lane-arrows/research/lane-icons.md","reason":"Records the selected upstream SVG source, CC0 provenance, and supported-versus-untested asset policy."}

View File

@@ -0,0 +1,39 @@
# Implementation Plan: OSM turn-lane arrows
## Steps
1. Add the complete lane-icons arrow asset set, upstream revision metadata,
CC0 license text, and a manifest with the five supported/tested entries and
explicit untested status for all other entries.
2. Add a small CommonJS helper for asset-manifest loading, source-SVG path and
stroke conversion, maneuver parsing, road-local placement, and diagnostic
skip records. Keep it dependency-free and separately testable.
3. Wire the helper into the intermediates build so custom features are merged
into `laneArrows` before the existing GeoJSON write and normalization path.
4. Add Node tests for the five supported maneuvers, forward/backward endpoint
choice, lane index placement, deterministic order/id, and every required
skip reason. Assert that untested manifest entries cannot be selected.
5. Generate `right` and `through;right` inspection samples from the exact
local templates and request user confirmation. Do not enable custom output
until this gate is met.
6. Run the focused tests, syntax checks, the Nantaizi intermediates build, the
full Nantaizi chain, and `check:area`. Compare against a turn-tag-removed
control to prove an observable GeoJSON difference.
## Validation
- `node --check` for changed CommonJS scripts.
- New pure Node test script(s), invoked directly or through a package script.
- `npm run build:area -- --config config/areas/nantaizi-lake-innovation-valley.json --stages intermediates`
- Full target-area pipeline after visual approval.
- `npm run check:area -- --config config/areas/nantaizi-lake-innovation-valley.json`
## Review Gates
- No generated custom feature may use an asset whose manifest status is not
both supported and tested.
- Samples must show the same fill/outline treatment as the existing lane-arrow
layer.
- Keep the existing layer registry unchanged; this is a new source for an
existing layer, not a new layer.
- Do not commit without the user's explicit confirmation.

View File

@@ -0,0 +1,63 @@
# Add OSM turn lane arrows
## Goal
让 OSM `turn:lanes:forward` / `turn:lanes:backward` 在现有 QGIS -> Blender -> Cesium
道路链中生成可辨识的 lane arrow同时保持与 osm2streets 既有道路标线相同的视觉语言。
## Confirmed Facts
- 当前 `osm2streets-js-node@0.1.4` 生成 lane arrow但纯内存移除 way `98607123`
`98607128``98607147``turn:lanes:*`593 个原始箭头的 JSON 内容逐字一致;
因此该依赖不消费这些 OSM 标签。
- 当前南台子完整链已经通过:中间层落盘 580 个归一化箭头Blender 装配 397 个,
Cesium / preview / compress manifest 均 fresh`check:area` PASS。
- 现有 `lane_arrows_webscale` 已是 QGIS、Blender、Cesium 共用图层,样式为浅色填充
`#fffff6`、深色描边 `#2b2b28`,正常外轮廓为七顶点箭头。
- `turn:lanes:forward=right``turn:lanes:backward=through;right` 等标准标签已存在于
南台子 OSM。
- `openstreetmap/lane-icons` 是 OSM 官方组织发布的 CC0 SVG 图标集;其 `DESIGN.md`
以 MUTCD Standard Arrow 为基准,并规定组合转向共享箭杆、箭头数量增加时缩小箭头。
仓库只提供左侧转向示例,右转及 `through;right` 需在几何层对其镜像,不能直接作为
当前 GeoJSON polygon 图层输入。
- 用户已决定将该库中首版需要的转向图标作为本仓库维护的源素材,而不是只作为视觉参考。
## Requirements
1. 在写入 `lane_arrows_webscale.geojson` 前,从 OSM 标准 `turn:lanes:*` 生成自定义箭头
polygon并沿用既有图层、材质、QGIS/Blender/Cesium 路径。
2. 支持首版实际需要的 `through``left``right``through;left``through;right`
同一 OSM 输入必须产生确定性结果。
3. 自定义箭头必须使用现有道路标线的视觉语言,不新建一套颜色、描边或图标风格。
4. 在 OSM way 进入路口的一端、按 forward/backward 和 lane index 放置;车道配置不完整或
端点不是可判定路口时给出可诊断的跳过原因。
5. 首先完成并获得用户对 `right``through;right` 轮廓样张的确认,之后才能将其接入
GeoJSON / Blender 导出。
6. 未经用户确认,不提交 Git。
7.`openstreetmap/lane-icons` 的全部箭头 SVG 和 CC0 许可证说明纳入本仓库维护;
右转变体由左转源图镜像生成。生成的 polygon 仍由本仓库维护,并继续使用
`lane_arrows_webscale` 的既有填充与描边样式。
8. 素材清单必须逐项标记验证状态:仅 `through``left``right``through;left`
`through;right` 在首版具备 OSM 映射与自动化测试;其他已收录箭头明确标为未测试,
且不得自动参与生产 GeoJSON 输出。
## Acceptance Criteria
- [ ] 用户确认箭头样张的轮廓与视觉语言。
- [ ] 目标 OSM 标签导致 lane-arrow GeoJSON 与移除这些标签的对照产生可观察差异。
- [ ] 自定义 arrow properties 标识来源和 OSM way / direction / lane便于诊断。
- [ ] 纯 Node 测试覆盖标签解析、forward/backward、lane placement、组合转向和幂等排序。
- [ ] 本地素材清单包含所有上游箭头,逐项标记 CC0 来源、支持状态和测试状态;未测试条目
不会参与生产映射。
- [ ] 仅南台子完整链和质量门验证通过。
- [ ] 无 Git 提交,直到用户明确确认。
## Out Of Scope
- 修改 osm2streets 依赖、道路改为 Cesium 直渲染、增加新的道路渲染图层。
- 支持首版范围之外的 OSM maneuver 词汇、匝道标线、文字或自行车专用箭头。
## Delivery Gate
在自定义箭头接入生产 GeoJSON / Blender 导出前,用户必须确认 `right`
`through;right` 样张的轮廓和视觉语言。

View File

@@ -0,0 +1,40 @@
# lane-icons research
Source: <https://github.com/openstreetmap/lane-icons>, inspected 2026-08-04.
## Provenance
- Owner: `openstreetmap` GitHub organization.
- Repository tree revision: `db3cab321da93a757c2cf3cdb4f1f1db6b1a091c` (`master`).
- License: `LICENSE.md` is CC0 1.0 Universal. Keep that text adjacent to any
vendored source assets.
## Relevant Contents
- `docs/through.svg`
- `docs/left.svg`
- `docs/left-through.svg`
- `docs/slight_left.svg`
- `docs/slight_left-through.svg`
- `docs/sharp_left.svg`
- `docs/sharp_left-through.svg`
- `docs/reverse_left.svg`
- `docs/reverse_left-through.svg`
- `docs/reverse_left-left-slight_left-through.svg`
- `docs/left-slight_left-through.svg`
## Design Rules
`DESIGN.md` bases arrows on the MUTCD Standard Arrow. It specifies a shared
shaft for compound arrows, smooth curves, aligned arrow bottoms, and reduced
arrowhead scale as the number of directions grows. The upstream SVGs are
single-color and stroke-free; our existing render layer supplies the project
fill and outline treatment.
## Adoption Decision
Vendor all listed arrow SVGs with provenance and CC0 license text. The
production mapping is initially restricted to `through`, `left`, `right`,
`through;left`, and `through;right`. Right-side variants are deterministic
mirrors of upstream left-side assets. Every other vendored arrow remains
explicitly untested and unavailable to the production mapper.

View File

@@ -0,0 +1,26 @@
{
"id": "add-osm-turn-lane-arrows",
"name": "add-osm-turn-lane-arrows",
"title": "Add OSM turn lane arrows",
"description": "",
"status": "in_progress",
"dev_type": null,
"scope": null,
"package": null,
"priority": "P2",
"creator": "dingkang",
"assignee": "dingkang",
"createdAt": "2026-08-04",
"completedAt": null,
"branch": null,
"base_branch": "main",
"worktree_path": null,
"commit": null,
"pr_url": null,
"subtasks": [],
"children": [],
"parent": null,
"relatedFiles": [],
"notes": "",
"meta": {}
}