Files
osmWorkflow/scripts/test-gaode-junction-reference.js
que01 12aeda9a63 feat: parameterize complex junction geometry with Gaode reference
- 高德 GeoJSON 参考流程: `scripts/lib/gaode-junction-reference.js`
  与 `scripts/inspect-junction-reference.js` 将 GCJ-02 参考转换为 WGS84,
  按 node id/最近距离关联 OSM, 支持普通路口面和 `complex-cluster` 两种匹配。
- 复合路口模板 `complex-junction-v1`: `scripts/lib/complex-junction.js` 用参考
  几何校准 core 半径, 生成路口面、进口路面、斑马线、停止线、角部圆角与安全岛;
  拓扑/信号/连接全部沿用 OSM/native。
- 车道中心线控制要素避让: `compileLaneCenterlines` 现接收模板已产出的斑马线/停止线,
  新增 `trimLaneOutsideControls` 按到路口中心的半径定向裁剪; 标线源几何同步裁剪, 不再
  越过斑马线继续画到核心区。拓扑几何不变, connector 集合前后一致。
- 复合路口人行道转角: `buildComplexJunctionGeometry` 沿已定义的路缘生成 2m 宽转角带,
  复用圆角曲线, 通过 `islands` 通道并入 `sidewalk_surface`; 自交或坐标非有限时报
  `complex-junction-sidewalk-corner-fallback` 并跳过。
- 新增诊断: `complex-junction-configured-radius-ignored`、
  `lane-centerline-fully-inside-control`、`complex-junction-sidewalk-corner-fallback`。
- 死码清理: 移除未被调用的 `clusterApproachRing`。
- spec 更新: `.trellis/spec/pipeline/cli-and-stages.md` 复合路口小节补充控制要素
  避让顺序、人行道转角契约、Validation 矩阵三行; 索引新增导航。
- 任务产物 `08-19-gaode-junction-reference`: 8 条验收标准全部实测记录,
  Scope Drift / Verification Log / Known Gaps 三节沉淀本次工作。

Regression: test:native-road / test:road-workbench / test:preflight /
test:native-preview-traffic / test:package-contract / test:traffic-signals /
test:gaode-junction-reference 全绿; road:check ok=true, errors=[]。
2026-08-21 11:59:03 +08:00

37 lines
2.5 KiB
JavaScript

#!/usr/bin/env node
"use strict";
const assert = require("assert");
const fs = require("fs");
const os = require("os");
const path = require("path");
const { gcj02ToWgs84, convertGeoJson, inspectReference } = require("./lib/gaode-junction-reference");
const converted = gcj02ToWgs84([114.12864875054062, 30.460485279762146]);
assert.ok(Math.abs(converted[0] - 114.1229659) < 0.00001);
assert.ok(Math.abs(converted[1] - 30.4628266) < 0.00001);
assert.throws(() => gcj02ToWgs84([Infinity, 30]), /finite/);
assert.deepEqual(convertGeoJson({ type: "FeatureCollection", features: [{ type: "Feature", properties: {}, geometry: { type: "Point", coordinates: [114.12864875054062, 30.460485279762146] } }] }).features[0].geometry.coordinates.map((value) => Number(value.toFixed(6))), [114.122966, 30.462827]);
const temp = fs.mkdtempSync(path.join(os.tmpdir(), "gaode-junction-reference-"));
try {
const reference = path.join(temp, "reference.geojson");
const osm = path.join(temp, "input.osm");
const native = path.join(temp, "intersections.geojson");
fs.writeFileSync(reference, JSON.stringify({ type: "FeatureCollection", features: [{ type: "Feature", properties: { type: 1 }, geometry: { type: "Polygon", coordinates: [[[114.12860, 30.46040], [114.12870, 30.46040], [114.12870, 30.46050], [114.12860, 30.46040]]] } }] }));
fs.writeFileSync(osm, "<osm><node id='8005332807' lon='114.1229249' lat='30.462899'><tag k='highway' v='traffic_signals'/></node></osm>");
fs.writeFileSync(native, JSON.stringify({ type: "FeatureCollection", features: [{ type: "Feature", properties: { osm_node_id: "8005332807" }, geometry: { type: "Polygon", coordinates: [[[114.1228, 30.4627], [114.1231, 30.4627], [114.1231, 30.4630], [114.1228, 30.4627]]] } }] }));
const result = inspectReference({ referenceFile: reference, osmFile: osm, nativeIntersectionFile: native, nodeId: "8005332807" });
assert.equal(result.matchedOsmNode.id, "8005332807");
assert.equal(result.matchedOsmNode.match, "node-id");
assert.ok(result.matchedOsmNode.centerDistanceMeters < 20);
assert.ok(result.nativeIntersection.bboxIoU > 0);
assert.deepEqual(result.diagnostics, []);
fs.writeFileSync(native, JSON.stringify({ type: "FeatureCollection", features: [] }));
assert.match(inspectReference({ referenceFile: reference, osmFile: osm, nativeIntersectionFile: native, nodeId: "8005332807" }).diagnostics[0], /No native intersection/);
} finally {
fs.rmSync(temp, { recursive: true, force: true });
}
console.log("Gaode junction reference tests passed.");