# 自由路径(Free Path)设计方案 > 分支:`feature/free-path` > 创建日期:2026-06-30 > 状态:实施中(详见下方"实施进度跟踪") > > **已确认决策**: > - 决策点1(旋转姿态):**最终改为 —— 自由路径保持物体原始姿态**,不自动对齐路径方向 > (真实物体/YUp 的自动姿态解析易出错;用户通过"调整物体"控制朝向) > - 决策点2(旧数据迁移):方案A —— 自动转换 IsTwoPointVertical → Free > > **架构原则(2026-08)**:"调整物体"只是调整物体的**姿态修正 + 上下偏移**, > 与路径对齐无关。物体在起点的姿态/位置由两个分离步骤决定: > - **第一步(统一,路径无关,无分支)**:调整物体的结果(姿态修正 X/Y/Z + 上下偏移 lift) > - **第二步(各路径自己的处理逻辑)**:路径起点对齐(路径点→物体位置 + 基座姿态对齐) > 所有路径都遵循此架构;只有第二步允许分支。 --- ## 一、背景与问题 ### 1.1 现状 当前路径类型 `PathType`: | 值 | 类型 | 说明 | |----|------|------| | 0 | Ground | 地面路径 | | 1 | Rail | 空轨路径 | | 2 | Hoisting | 吊装路径 | **2点路径**:是 Hoisting 上的 `IsTwoPointVertical` 特殊标志,非独立类型。语义混乱: | | 起点 | 终点 | |----|------|------| | 动画帧循环 | 底面中心对齐(`ResolveGroundTrackedCenter`) | 几何中心(`p2` 原始点) | | 终点诊断 | — | 底面中心对齐(又一种) | **问题**:起点用底面中心对齐、终点用几何中心对齐,**对齐语义不一致**; 且 2 点路径被绑死在吊装逻辑中,无法作为通用路径使用。 ### 1.2 需求 1. 2 点路径改为**自由路径(Free)**,从吊装路径中剥离 2. 与地面、空轨、吊装等路径**并列**为一级路径类型 3. **统一包围盒中心对齐**:每个路径点 = 物体几何中心 4. 支持**任意多个自由路径点** --- ## 二、目标 1. 新增一级 `PathType.Free` 2. 统一包围盒中心对齐(轨迹即物体中心) 3. 支持任意多点自由路径 4. 从吊装剥离,废弃 `IsTwoPointVertical` 特殊逻辑 5. 温和迁移旧 2 点吊装路径数据 --- ## 三、核心设计 ### 3.1 PathType 枚举 ```csharp public enum PathType { Ground = 0, Rail = 1, Hoisting = 2, Free = 3 // 新增 } ``` - `GetDisplayName()` 增加 `case PathType.Free: return "自由";` - DB 存储为整数,**追加枚举值向后安全**,无需 schema 迁移 ### 3.2 动画语义(关键) 自由路径的每个路径点**就是物体包围盒中心**: ```csharp framePosition = 路径点直接插值; // 不加任何半高偏移 ``` - 起点/终点/中间点**统一**用几何中心对齐(无起点/终点不对称) - 天然满足"矢量任意方向"——不依赖哪个面是底 ### 3.3 旋转姿态策略(决策点1 → 方案1) **方案1(已确认)**:forward = 路径切线方向,up = 世界 up 投影正交化。 - 复用 `RailPathPoseHelper` 的三维姿态计算 - 物体保持"上"朝世界,像车沿坡道走 - 通用且符合物流车语义 ### 3.4 创建流程(UI) - 新增"自由路径"创建模式,与地面/空轨/吊装并列 - 用户连续点击任意 3D 点(即物体中心轨迹) - 无地面约束、无提升/下降段逻辑 - 支持任意点数,最后设终点完成 ### 3.5 渲染 - 自由路径按普通多点线渲染(去掉吊装特殊逻辑) - 通行空间以路径点为中心扩展 ### 3.6 碰撞检测 framePosition 即物体中心,现有碰撞盒计算直接正确(无需改动)。 --- ## 四、兼容与迁移 ### 4.1 旧数据迁移(决策点2 → 方案A) **方案A(已确认):自动转换** 加载旧库时,`IsTwoPointVertical=true` 的吊装路径: - 转换为 `PathType.Free` - 路径点坐标直接作为物体几何中心 - 注意:旧 2 点路径终点是"提升点"(lift 高度),转换时作为物体中心需确认合理性 --- ## 五、实施步骤与进度跟踪 | # | 步骤 | 状态 | 备注 | |----|------|------|------| | 1 | `PathType` 加 `Free` + `GetDisplayName` | ✅ | 枚举值3,显示"自由" | | 2 | 动画管理器:新增 Free 分支(统一中心对齐 + 方案1姿态) | ✅ | `TryCreateFreePathRotationForFrame/AtStart`,复用 CanonicalRailPoseBuilder | | 3 | 渲染插件:Free 普通渲染 | ✅ | 通行空间垂直偏移0(路径=中心) | | 4 | 路径管理器:`StartCreatingNewRoute`/`FinishEditing` 支持 Free | ✅ | 状态消息 + 设终点逻辑 | | 5 | UI:新增自由路径创建入口 | ✅ | PathEditingView 按钮 + `NewFreePathCommand` + `ExecuteNewFreePathAsync` | | 6 | 数据库:枚举扩展(无 schema 变更) | ✅ | 存 int,Free=3 自动映射 | | 7 | 旧数据迁移(方案A) | ✅ | 加载时 IsTwoPointVertical→Free | | 8 | 补单测(中心对齐 + 姿态 + 多点) | ✅ | 新增 FreePathTests(6个) | | 9 | 编译 + 单测 + 部署 + 手动验证 | 🔄 | 需部署后手动验证 | > ✅ 附带修复:`CornerTurnCheckHelperTests` 6个 pre-existing 失败 > - 根因:代码正确,测试期望值与公式不符(`7e71387` 改算法时测试未同步) > - 已修正测试期望值 + 补 maxLength 断言 > - 另将 `FreePathTests.cs` 显式加入 UnitTests.csproj(此前未编译) > ✅ 自由路径起点姿态已正确(保持原始姿态,纯平移,排除平面旋转分支) ## 六、待办事项(明日处理) ### 6.1 "调整物体"窗口功能问题 **状态**:起点姿态、动画已正确;"调整物体"窗口功能在逐步修复。 **已修复**: - ✅ **X/Y/Z 角度调整**:根因是 `MoveObjectToPathStart` 的 Free 分支只做纯平移, 忽略了 `_objectRotationCorrection`。已改为先应用角度修正(围绕物体中心旋转) 再平移到起点;动画帧保留修正后姿态。 - ✅ **上下偏移(lift)**:泛化 `ApplyGroundPathObjectLiftOffset` 支持 Free; 窗口对 Free 启用 lift 输入;起点和动画帧均应用偏移。 **待验证**: - ☐ 自动调整(ObjectPassageProjectionOptimizer) - ☐ 贴合地面(FaceInfer 流程) - ☐ 平移到起点 > 进度图例:☐ 未开始 / 🔄 进行中 / ✅ 完成