# 自由路径（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 流程）
- ☐ 平移到起点

> 进度图例：☐ 未开始 / 🔄 进行中 / ✅ 完成
