10 KiB
真实物体位姿来源迁移草案
1. 背景
当前真实物体位姿链路中,fragment 承担了两种不同语义:
- 读取真实物体的参考姿态
- 间接参与判断真实物体的当前显示姿态
这两个语义不应混在一起。
当前工程已确认:
ModelItem.Transform不能默认视为真实物体当前姿态或原始姿态fragment代表姿态适合做“参考姿态解释”ModelGeometry.ActiveTransform更适合做“当前实际显示姿态”读取
因此,本次迁移目标不是“简单移除 fragment”,而是:
- 先把参考姿态来源与当前显示变换来源拆开
- 优先把“当前显示姿态读取”切到准确变换 API
- 保留 fragment 参考姿态链作为稳定基线
- 在测试和 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
优先数据源:
ModelGeometry.ActiveTransformModelGeometry.PermanentOverrideTransformModelGeometry.OriginalTransform- 明确失败,不偷偷 fallback 到不可靠语义
B. IReferencePoseProvider
职责:
- 提供真实物体参考姿态
- 输出解释后的
Rotation + AxisX/Y/Z - 对上层屏蔽具体来源是 fragment 还是 geometry
建议实现顺序:
FragmentReferencePoseProvider- 复用当前
RealObjectReferencePoseResolver
- 复用当前
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:按路径类型逐步接入
目标:
- 在证据足够充分后,才让新的参考姿态来源参与正式链路
建议接入顺序:
RailGroundHoisting
原因:
Rail当前姿态框架最明确,收益最大Ground / Hoisting对“对象前进轴语义”更敏感
通过条件:
Rail 0°基线不变- Ground 逐帧姿态不退化
- 通行空间与真实物体仍共用同一尺寸语义
6. 建议新增/调整的代码结构
6.1 建议新增文件
src/Utils/CoordinateSystem/ICurrentDisplayTransformProvider.cssrc/Utils/CoordinateSystem/IReferencePoseProvider.cssrc/Utils/CoordinateSystem/GeometryActiveTransformProvider.cssrc/Utils/CoordinateSystem/FragmentReferencePoseProvider.cssrc/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 不建议本阶段改动的文件
CanonicalPlanarPoseBuilderCanonicalRailPoseBuilderCanonicalTrackedPositionResolverRailPathPoseHelper
原因:
- 这些文件主要负责姿态求解与偏移语义
- 不是本次来源迁移的根因层
7. 测试先行策略
7.1 测试原则
本次迁移必须遵循:
- 先补测试
- 再抽象接口
- 再切换读取来源
- 最后才考虑正式接入
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. 当前推荐执行顺序
建议下一步按下面顺序推进:
- 先补测试,不接正式代码
- 抽 provider 接口,不改默认实现
- 先切“当前显示姿态读取”
- 做 geometry 参考姿态 shadow 验证
- 证据足够后,再讨论 fragment 主来源是否退出
10. 当前结论
本次迁移的关键不是“删掉 fragment”,而是:
- 先把语义拆开
- 先把准确 API 用在该用的地方
- 先用测试固定业务场景
- 再用 shadow 验证去证明新的参考姿态来源是否真的可靠
在当前阶段,最稳的路线是:
- fragment 继续作为真实物体参考姿态主来源
ModelGeometry.ActiveTransform接管当前显示姿态读取- 测试先行
- 分阶段接入