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

10 KiB
Raw Blame History

真实物体位姿来源迁移草案

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默认UpY/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 接管当前显示姿态读取
  • 测试先行
  • 分阶段接入