# 道路与路口的联合求解边界 ## 当前依赖已经存在 `compileGeometry()` 目前以同一 `model` 和 `junctionPlans` 依次生成道路面、车道中心线、边缘线、控制设施、中心线/车道标线、步行带、connector 与路口面。它们不是孤立图层: ```text 道路横断面 / 进口尺寸 -> 道路面、步行带、车道偏移 -> 车道线与 connector -> 路口边界、cutback、转弯圆角 -> 停止线、斑马线、箭头与诊断 ``` 普通路口目前由 `compileJunctionPlans()` 的 approach、`cutbackMeters` 和 boundary 驱动;复合路口则由 `junctionTemplates.clusters` 和 `complex-junction.js` 的 core radius、进口包络和角部岛生成。直接操纵不能在最终 `roadSurface` / `intersectionSurface` 上独立移动顶点,否则会破坏这条依赖链。 ## 提议的新增阶段 ```text OSM -> compileRoadModel -> 现有 v1 参数覆盖 -> resolveDirectEditConstraints -> editableRoadModel + editableJunctionPlans -> 既有图层编译器(逐步接收扩展参数) -> GeoJSON ``` `resolveDirectEditConstraints` 的职责是: 1. 将 `road-station` / `road-interval` 约束整理为道路横断面 profile; 2. 将道路末端 profile 与 `junction-approach` 约束合并,构建一致的进口截面; 3. 以 `junction-corner` / `junction-cutback` 约束生成可验证的 junction plan; 4. 在违反最小车道宽、相邻道路相交、交叉口连接线包络等不变量时,返回明确冲突而非偷偷修复; 5. 输出一个 handle manifest,使地图手柄能从同一语义模型读取位置、可拖动方向、受影响对象和可见的值。 道路 interval 的默认范围由求解器决定,而不是 UI 预设像素:避开两端的 junction cutback,优先取拖拽站点两侧可用长度的有限比例;若道路过短或与另一个约束重叠,预览返回可调整范围或冲突信息。 ## 交互预览 拖动不触发文件写入或完整工作台重建。地图维护 `EditSession`: ```text pointer down: 读取 handle 的 semantic anchor,创建 draft command pointer move: 投影鼠标位置 -> 立即更新 ghost 与 draft constraint -> 防抖服务端预览求解 pointer up: 验证成功则压入本地命令栈;失败保留提示并回退到上一个有效预览 save: 批量持久化 constraints + operations compile: 用已保存文档运行权威全量编译 ``` 浏览器 ghost 仅包含控制柄、辅助线与半透明预估轮廓,不承担权威道路几何。服务端复用正式编译的约束求解逻辑,返回受影响的少数 OpenLayers source(道路面、步行带、路口、标线、connector 和 handles);客户端替换它们,而非卸载 `MapCanvas` 或重新创建 `Map`。这与现有图层可见性和选择修复一致。 ## 约束不变量 - 单车道最小宽度,例如 2.4m;道路横断面总宽度等于车道、边缘和步行带之和。 - 一个站点的左右外缘不得交叉;相邻 profile 之间必须有可计算的过渡。 - 进口截面必须在路口 cutback 处与路口边界连续。 - connector、停止线和人行横道必须保持在所属道路/路口可用面内,否则产生阻塞性诊断。 - 普通路口与复杂 cluster 不共用相同低层约束:前者锚定 node,后者锚定 cluster 和 arm,避免将 cluster 缩减为多个互相冲突的普通路口编辑。