NavisworksTransport/doc/design/2026/real-object-pose-source-migration-draft.md

424 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 真实物体位姿来源迁移草案
## 1. 背景
当前真实物体位姿链路中,`fragment` 承担了两种不同语义:
- 读取真实物体的**参考姿态**
- 间接参与判断真实物体的**当前显示姿态**
这两个语义不应混在一起。
当前工程已确认:
- `ModelItem.Transform` 不能默认视为真实物体当前姿态或原始姿态
- `fragment` 代表姿态适合做“参考姿态解释”
- `ModelGeometry.ActiveTransform` 更适合做“当前实际显示姿态”读取
因此,本次迁移目标不是“简单移除 fragment”而是
1. 先把**参考姿态来源**与**当前显示变换来源**拆开
2. 优先把“当前显示姿态读取”切到准确变换 API
3. 保留 fragment 参考姿态链作为稳定基线
4. 在测试和 shadow 验证足够充分后,再评估参考姿态主来源是否切换
---
## 2. 当前问题
### 2.1 语义混用
当前真实物体链路同时关心:
- 物体原始业务姿态是什么
- 物体此刻在 Navisworks 里实际显示成什么姿态
- 增量变换叠加后,应以哪一层为“当前状态”
如果这三者没有统一入口,就容易出现:
- 起点姿态正确,但播放过程漂移
- `ResetPermanentTransform` 后内部状态与宿主状态不同步
- 通行空间、碰撞恢复、动画终点使用了不同的姿态基线
### 2.2 fragment 并不是“当前姿态 API”
fragment 的 `GetLocalToWorldMatrix()` 更接近几何层矩阵。
它适合:
- 统计代表姿态
- 解释真实物体的原始参考框架
- 参与 COM 几何分析
它不应优先承担:
- 当前 override 后显示姿态读取
- 动画增量变换后的宿主状态读回
### 2.3 直接回退 `ModelItem.Transform` 风险很高
对于很多 Revit/复合件导入模型:
- `ModelItem.Transform` 可能是单位旋转
- 不反映当前 override 后姿态
- 不足以表达真实物体的业务参考姿态
所以迁移不能走“fragment -> ModelItem.Transform”的单步替换。
---
## 3. 迁移目标
### 3.1 核心目标
建立两条明确分离的来源链:
- **当前显示变换链**
- 用于读取当前实际显示姿态
- 优先使用 `ModelGeometry.ActiveTransform`
- **参考姿态链**
- 用于表达真实物体的原始业务姿态
- 当前仍以 fragment 解释链为稳定主来源
### 3.2 非目标
本阶段不做以下事情:
- 不重写 `Ground / Hoisting / Rail` 的姿态求解器
- 不直接移除现有 fragment 参考姿态链
- 不修改 Canonical / Host / Asset 三层坐标语义
- 不在没有验证前,把 `ModelItem.Transform` 升级为真实姿态主来源
---
## 4. 目标架构
### 4.1 新的职责划分
建议新增两类 provider
#### A. `ICurrentDisplayTransformProvider`
职责:
- 读取当前几何实际显示姿态
- 读取当前几何实际旋转
- 读取当前几何原始姿态与 override 后姿态
建议首个实现:
- `GeometryActiveTransformProvider`
优先数据源:
1. `ModelGeometry.ActiveTransform`
2. `ModelGeometry.PermanentOverrideTransform`
3. `ModelGeometry.OriginalTransform`
4. 明确失败,不偷偷 fallback 到不可靠语义
#### B. `IReferencePoseProvider`
职责:
- 提供真实物体参考姿态
- 输出解释后的 `Rotation + AxisX/Y/Z`
- 对上层屏蔽具体来源是 fragment 还是 geometry
建议实现顺序:
1. `FragmentReferencePoseProvider`
- 复用当前 `RealObjectReferencePoseResolver`
2. `GeometryReferencePoseProvider`
- 后续用于 shadow 验证
- 初期不接主链
### 4.2 上层调用关系
建议上层只依赖语义接口:
- `PathAnimationManager`
- 读取参考姿态时,只依赖 `IReferencePoseProvider`
- 读取当前宿主实际姿态时,只依赖 `ICurrentDisplayTransformProvider`
- `ModelItemTransformHelper`
- 统一封装 `ActiveTransform / OriginalTransform / delta transform`
- 成为“当前显示变换链”的基础工具层
- `RealObjectPlanarPoseSolver`
- `CanonicalRailPoseBuilder`
- 保持纯数学求解,不感知来源替换
---
## 5. 分阶段迁移方案
### 阶段 0冻结语义与测试基线
目标:
- 不改正式行为
- 先把关键业务场景和期望值固定下来
产出:
- 参考姿态语义测试
- 当前显示姿态读取测试
- 增量变换恢复测试
- `YUp / ZUp` 双宿主测试矩阵
通过条件:
- 现有 fragment 主链全部通过基线测试
### 阶段 1抽象来源接口但不改行为
目标:
- 只做代码结构调整
- 不改变当前正式结果
建议动作:
- 新增 `ICurrentDisplayTransformProvider`
- 新增 `IReferencePoseProvider`
-`PathAnimationManager` 从直接依赖 helper/fragment改为依赖 provider
- 默认配置仍然使用 `FragmentReferencePoseProvider`
通过条件:
- 行为无变化
- 回归测试全绿
### 阶段 2迁移“当前显示姿态读取”
目标:
- 把“当前姿态读取”切到准确变换 API
建议动作:
- 将以下读当前姿态的场景统一迁到 `ModelGeometry.ActiveTransform`
- 当前旋转读回
- 当前显示姿态调试日志
- override 后的实际姿态验证
- 动画恢复/碰撞恢复前的状态同步
注意:
- 这一阶段不改“参考姿态”来源
- 只改“当前实际显示变换”的读取
通过条件:
- 起点/播放/暂停/终点/恢复行为与当前主链一致
- `ResetPermanentTransform` 后内部跟踪状态不再依赖 `ModelItem.Transform`
### 阶段 3引入 `GeometryReferencePoseProvider` shadow 验证
目标:
- 并行验证 geometry 是否能稳定替代 fragment 参考姿态
建议动作:
- 新增几何级参考姿态读取实现
- 不接正式主链
- 只在日志/调试模式下输出与 fragment 基线的差异
建议记录差异:
- quaternion 夹角差
- `AxisX / AxisY / AxisZ` 与基线的夹角差
- 多 geometry 是否一致
- `YUp / ZUp` 下解释后是否仍满足宿主语义
判定规则建议:
- 若 geometry 内部姿态不一致,则自动判定“不适合作为语义参考姿态主来源”
- 若与 fragment 基线夹角超阈值,则继续保留 fragment 主来源
### 阶段 4按路径类型逐步接入
目标:
- 在证据足够充分后,才让新的参考姿态来源参与正式链路
建议接入顺序:
1. `Rail`
2. `Ground`
3. `Hoisting`
原因:
- `Rail` 当前姿态框架最明确,收益最大
- `Ground / Hoisting` 对“对象前进轴语义”更敏感
通过条件:
- `Rail 0°` 基线不变
- Ground 逐帧姿态不退化
- 通行空间与真实物体仍共用同一尺寸语义
---
## 6. 建议新增/调整的代码结构
### 6.1 建议新增文件
- `src/Utils/CoordinateSystem/ICurrentDisplayTransformProvider.cs`
- `src/Utils/CoordinateSystem/IReferencePoseProvider.cs`
- `src/Utils/CoordinateSystem/GeometryActiveTransformProvider.cs`
- `src/Utils/CoordinateSystem/FragmentReferencePoseProvider.cs`
- `src/Utils/CoordinateSystem/GeometryReferencePoseProvider.cs`
### 6.2 建议优先调整的现有文件
- `src/Core/Animation/PathAnimationManager.cs`
- 只依赖 provider
- 去掉对 fragment/helper 的直接耦合
- `src/Utils/ModelItemTransformHelper.cs`
- 成为统一的当前显示变换读取入口
- `src/Utils/CoordinateSystem/RealObjectReferencePoseResolver.cs`
- 收敛为 fragment provider 的内部实现
- 不再直接被业务层广泛调用
### 6.3 不建议本阶段改动的文件
- `CanonicalPlanarPoseBuilder`
- `CanonicalRailPoseBuilder`
- `CanonicalTrackedPositionResolver`
- `RailPathPoseHelper`
原因:
- 这些文件主要负责姿态求解与偏移语义
- 不是本次来源迁移的根因层
---
## 7. 测试先行策略
### 7.1 测试原则
本次迁移必须遵循:
1. 先补测试
2. 再抽象接口
3. 再切换读取来源
4. 最后才考虑正式接入
### 7.2 第一批必须补的测试
#### A. 参考姿态基线测试
建议位置:
- `UnitTests/CoordinateSystem/RealObjectReferencePoseResolverTests.cs`
锁定内容:
- fragment 多片段平均后的代表姿态
- `Fragment默认Up``Y/Z` 时的解释结果
- `YUp / ZUp` 宿主下输出轴语义一致
#### B. 当前显示姿态读取测试
建议新增:
- `UnitTests/CoordinateSystem/CurrentDisplayTransformProviderTests.cs`
锁定内容:
- `ActiveTransform` 优先级
- `OriginalTransform / PermanentOverrideTransform / ActiveTransform` 的语义区分
- override 后读取结果与预期一致
#### C. 动画增量恢复测试
建议新增:
- `UnitTests/CoordinateSystem/IncrementalTransformRestoreTests.cs`
锁定内容:
- reset 后状态同步
- 当前跟踪姿态与宿主状态一致
- 不再错误依赖 `ModelItem.Transform`
#### D. 业务回归测试
建议补到现有测试中:
- `Ground + 真实物体`
- `Rail + 真实物体`
- `YUp / ZUp`
- 起点 / 逐帧 / 终点 / restore
### 7.3 第二批 shadow 验证测试
建议新增:
- `UnitTests/CoordinateSystem/GeometryReferencePoseProviderTests.cs`
锁定内容:
- 单 geometry 对象能否稳定导出参考姿态
- 多 geometry 姿态不一致时是否正确拒绝
- geometry 基线与 fragment 基线差异是否在阈值内
---
## 8. 验收标准
### 8.1 阶段 1-2 验收
- 正式行为无肉眼可见退化
- 所有已有姿态回归测试通过
- `PathAnimationManager` 不再把“当前姿态读取”和“参考姿态来源”混用
### 8.2 阶段 3 验收
- 能输出 geometry vs fragment 的稳定差异报告
- 能区分“可替代对象”和“不可替代对象”
### 8.3 阶段 4 验收
- `Rail 0°` 基线不变
- `Ground / Hoisting` 逐帧行为不退化
- 通行空间、碰撞恢复、终点诊断不出现新的语义分叉
---
## 9. 当前推荐执行顺序
建议下一步按下面顺序推进:
1. 先补测试,不接正式代码
2. 抽 provider 接口,不改默认实现
3. 先切“当前显示姿态读取”
4. 做 geometry 参考姿态 shadow 验证
5. 证据足够后,再讨论 fragment 主来源是否退出
---
## 10. 当前结论
本次迁移的关键不是“删掉 fragment”而是
- 先把语义拆开
- 先把准确 API 用在该用的地方
- 先用测试固定业务场景
- 再用 shadow 验证去证明新的参考姿态来源是否真的可靠
在当前阶段,**最稳的路线**是:
- fragment 继续作为真实物体参考姿态主来源
- `ModelGeometry.ActiveTransform` 接管当前显示姿态读取
- 测试先行
- 分阶段接入