# 自动路径规划坐标系重构实施方案

更新时间：2026-04-13  
状态：实施中  
目标：将 `Ground` 自动路径规划整条链路并入当前稳定的“宿主坐标系 -> Canonical Space -> 宿主坐标系”架构，消除旧 `XY` 平面 / `Z` 高度硬编码，不再针对单一 `YUp` 现象打补丁。

---

## 1. 背景与问题定义

当前项目的坐标系架构已经明确：

- 宿主坐标系（Host Space）
  - Navisworks 文档坐标系
  - UI 输入输出、鼠标拾取、日志、渲染交互都属于这一层
- 内部坐标系（Canonical Space）
  - 项目内部统一固定为 `ZUp`
  - 几何、姿态、法向、路径计算优先在这一层完成
- 业务语义层
  - 在 canonical 之上表达地面接触点、吊点、轨道法向、动画跟踪点等业务含义

但自动路径规划链路目前仍大量保留旧实现习惯：

- 默认 `XY` 是水平平面
- 默认 `Z` 是高度轴
- 默认世界 `Z` 可以直接代表“向上”
- 路径起终点修正仍然是“保留 `XY`，替换 `Z`”

这说明当前问题不是“某个 `YUp` 细节没处理”，而是：

- 自动路径规划整条链没有接入当前稳定的坐标系架构

因此本方案的目标不是修一个 `YUp` bug，而是把自动路径规划整体收编到现有坐标系体系中。

---

## 2. 现象与直接证据

以 `YUp` 文档中的地面自动路径为例，日志显示：

- 起点：`(-209.94, 14.83, -1.68)`
- 终点：`(-169.20, 14.83, -5.35)`

对当前文档来说，宿主 `up` 是 `Y`，所以：

- 地面高度应主要体现在 `Y`
- `Z` 应属于宿主水平面的一部分

但自动路径规划链中仍有如下旧假设：

1. `PathPlanningManager` 按 `X/Y` 计算边界与网格尺寸
- `src/Core/PathPlanningManager.cs`
- `GetModelBounds()`
- `CalculateOptimalGridSize(...)`

2. `AutoPathFinder` 把图节点还原为：
- `new Point3D(worldPos.X, worldPos.Y, nodeInfo.Z)`

3. `AutoPathFinder` 的起终点修正逻辑仍是：
- 保留原始 `X/Y`
- 只替换 `Z`

这套实现天然绑定旧 `ZUp` 语义，无法正确支持当前多坐标系架构。

---

## 3. 重构目标

本次重构要达成的不是“YUp 也能跑”，而是以下更高层目标：

1. 自动路径规划输入输出继续保持宿主坐标语义
- 用户点击点、UI 日志、路径显示、数据库路径点仍然按宿主坐标解释

2. 自动路径规划内部计算统一切到 canonical
- 网格范围
- 栅格映射
- A* 路径求解
- 高度层处理
- 曲线化前的路径点

3. Ground 自动路径与通行空间、路径渲染、动画主链共享同一套 up / 高度语义

4. 禁止继续保留旧 `XY/Z` 写死逻辑作为 fallback

---

## 4. 范围界定

### 4.1 本次重构范围

- `PathEditingViewModel`
  - 自动路径起点/终点输入边界
- `PathPlanningManager`
  - 自动路径入口、边界、网格参数、路径落库前收口
- `GridMapGenerator`
  - BIM 到网格的平面/高度语义
- `AutoPathFinder`
  - 路径搜索、节点转世界坐标、首尾点修正
- 与自动路径规划直接耦合的测试

### 4.2 暂不纳入本次范围

- 手动路径编辑主链
- 吊装路径自动生成链
- Rail 自动生成链
- 动画姿态链
- 碰撞恢复链

说明：

- 本次先聚焦 `Ground` 自动路径规划
- 但设计必须是通用的宿主/内部坐标边界，不允许做成“只为 `YUp` 单独补丁”

---

## 5. 关键设计原则

### 5.1 边界清晰

- 宿主坐标只在输入输出边界存在
- 内部计算统一使用 canonical
- 不允许在算法中间层直接假设世界 `Z` 是高度

### 5.2 不新增 fallback

不允许：

- canonical 转换失败时回退旧 `XY/Z` 逻辑
- `YUp` 失败时偷偷走旧分支
- 用“如果是 YUp 就特判”掩盖整体架构问题

### 5.3 优先复用现有坐标工具

优先复用：

- `HostCoordinateAdapter`
- `CanonicalTrackedPositionResolver`
- 坐标系统一设计文档中已经稳定的术语和边界

### 5.4 先锁测试，再动实现

本次重构必须先补针对多坐标系的自动路径测试，再改实现。

---

## 6. 目标架构

目标链路应收敛为：

```text
宿主点击点 / 宿主通道边界 / 宿主模型几何
    ↓ HostCoordinateAdapter
Canonical 起点 / 终点 / 边界 / 网格 / 高度层
    ↓ 自动路径规划算法（统一在 canonical 内）
Canonical 路径点
    ↓ HostCoordinateAdapter
宿主路径点 / 渲染 / UI / 数据库存储
```

关键语义：

- canonical 内部固定：
  - `XY` 为水平平面
  - `Z` 为高度
- 宿主坐标系的 `YUp/ZUp` 差异只由 `HostCoordinateAdapter` 负责吸收

---

## 7. 分阶段实施计划

### Phase 0：现状锁定与测试补齐

目标：

- 先把当前正确/错误行为锁定，避免重构中语义漂移

任务：

- [ ] 新增 `Ground` 自动路径在 `ZUp` 文档下的首尾点测试
- [ ] 新增 `Ground` 自动路径在 `YUp` 文档下的首尾点测试
- [ ] 新增“宿主点 -> 自动路径 -> 路径点输出”边界测试
- [ ] 新增“路径点 / 路径线 / 通行空间”首尾地面一致性测试

验收标准：

- 在没有改实现前，测试至少能明确暴露 `YUp` 下当前错误
- `ZUp` 当前稳定行为被锁住，不允许回归

### Phase 1：输入边界 canonical 化

目标：

- 自动路径规划入口不再把宿主点直接扔进旧 `XY/Z` 规划逻辑

任务：

- [ ] 梳理 `PathEditingViewModel` 起点/终点点击数据的宿主语义
- [ ] 在自动路径规划入口显式引入 `HostCoordinateAdapter`
- [ ] 将 `AutoPlanPath(...)` 的内部输入切换为 canonical 起点/终点
- [ ] 明确日志里同时打印宿主输入点与 canonical 输入点

验收标准：

- 自动路径规划入口不再直接依赖宿主 `YUp/ZUp`
- 起点终点进入算法前，坐标语义清晰可见

### Phase 2：网格与边界 canonical 化

目标：

- 网格边界、障碍物、通道数据全部按 canonical 平面/高度工作

任务：

- [ ] 重构 `GetModelBounds()` / `CalculateChannelsBounds(...)`
- [ ] 重构 `CalculateOptimalGridSize(...)`，不再把 `X/Y` 固定当平面
- [ ] 重构 `GridMapGenerator.GenerateFromBIM(...)` 的输入语义
- [ ] 明确网格二维平面坐标与 canonical 三维坐标的边界

验收标准：

- 网格生成不再依赖宿主世界 `XY`
- `YUp` / `ZUp` 两类文档进入网格阶段后语义完全一致

### Phase 3：路径求解与输出 canonical 化

目标：

- `AutoPathFinder` 内部只处理 canonical
- 路径输出统一经适配器返回宿主

任务：

- [ ] 重构图节点到三维点的转换逻辑
- [ ] 删除或重写“保留 XY、替换 Z”的旧首尾点修正
- [ ] 重构路径输出与落库前的宿主还原逻辑
- [ ] 日志里同时打印 canonical 路径首尾点与宿主路径首尾点

验收标准：

- 路径首尾点在 `YUp/ZUp` 下都能正确贴回宿主地面
- 不再出现“终点被压到地面下方”的旧 `ZUp` 语义残留

### Phase 4：联动校验与收尾

目标：

- 自动路径规划与可视化、通行空间、动画链的基础语义重新对齐

任务：

- [ ] 检查路径点显示是否仍使用宿主坐标
- [ ] 检查路径线和通行空间首尾点是否与路径点一致
- [ ] 清理旧 `XY/Z` 注释、旧日志、旧辅助方法
- [ ] 更新 `current-engineering-state.md` 中自动路径规划状态说明

验收标准：

- 自动路径规划的起点、终点、路径线、通行空间在多坐标系文档下语义一致
- 旧 `XY/Z` 硬编码实现不再残留为正式执行链

---

## 8. 关键改动点清单

高风险文件：

- `src/UI/WPF/ViewModels/PathEditingViewModel.cs`
- `src/Core/PathPlanningManager.cs`
- `src/PathPlanning/GridMapGenerator.cs`
- `src/PathPlanning/AutoPathFinder.cs`

重点清理的旧逻辑：

- [ ] “默认 `XY` 为地面平面”的边界计算
- [ ] “默认 `Z` 为高度”的路径节点组装
- [ ] “保留 `XY`，替换 `Z`”的起终点修正
- [ ] 任何直接写死世界 `Z` 为 up 的自动路径规划实现

---

## 9. 测试与验证策略

### 9.1 单元/集成测试

至少补齐：

- [ ] `ZUp Ground` 自动路径首尾点测试
- [ ] `YUp Ground` 自动路径首尾点测试
- [ ] 起点/终点保持宿主地面接触语义测试
- [ ] 路径输出后首尾点与通行空间一致性测试

### 9.2 手工验证

在真实 Navisworks 场景中验证：

- [ ] `ZUp` 模型中自动地面路径仍正常显示
- [ ] `YUp` 模型中自动地面路径终点不再掉到地面下
- [ ] 默认显示模式下能看到起点、终点和路径线
- [ ] 打开通行空间后，首尾位置与路径点一致

---

## 10. 风险与注意事项

1. 自动路径规划链路历史较老，旧实现可能分散在多个辅助方法中
- 不能只改主入口，必须顺着网格、A*、输出一路清理

2. 数据库存储仍然是宿主坐标语义
- 不能把 canonical 点直接落库

3. 路径渲染和自动路径规划不能各自维护一套“高度轴”解释
- 否则会再次出现“路径点对、通行空间错”或反过来的问题

4. 本次重构不是 `Ground` 的最后一步
- 后续 `Hoisting/Rail` 若要做自动路径，也应直接复用这次收好的边界层

---

## 11. 进度记录

### 2026-04-13

- [x] 确认当前自动路径规划主链仍大量保留旧 `XY/Z` 假设
- [x] 明确本次方向应为“并入现有坐标系架构”，而不是追加 `YUp` 特判
- [x] 建立本实施方案文档
- [x] 引入 `HostPlanarGridHelper`，明确“旧 ICoordinateSystem 水平/高程契约”与 `HostCoordinateAdapter` 的桥接边界
- [x] `YUpCoordinateSystem` / `ZUpCoordinateSystem` 改为复用统一桥接 helper，而不是各自散落实现
- [x] 为宿主平面/高程桥接补充纯数学单测，锁定：
  - `YUp` 高程走宿主 `Y`
  - `YUp` 水平面走宿主 `XZ`
  - `ZUp` 仍保持宿主 `XY + Z`
- [x] `AutoPathFinder` 第一轮收口完成：
  - 起终点映射改为通过 `gridMap.GetWorldElevation(...)`
  - 图节点 / 路径点还原改为通过 `gridMap.CreateWorldPoint(...)`
  - 高度层匹配与路径恢复改为通过 `gridMap.GetWorldElevation(...) / SetWorldElevation(...)`
- [ ] Phase 0 剩余：补“自动路径首尾点”更贴近业务的回归测试
- [ ] Phase 2 尚未开始：`GridMapGenerator` 仍存在较多旧 `XY/Z` 硬编码
