- 新增 ObjectPassageProjectionOptimizer(SO(3)粗搜索+Nelder-Mead) - EditRotationWindow 加入"自动调整"按钮 - AnimationControlViewModel 实现黑盒实测评估(临时摆位→读BoundingBox→恢复) - 设计文档和实现计划
7.9 KiB
自动调整物体姿态以最小化通行截面投影面积
更新时间:2026-05-27
1. 背景
动画检测中的“调整物体”窗口目前支持手工输入 X/Y/Z 三轴角度修正。用户希望增加一个“自动调整”按钮:对任意动画物体,在路径起点处自动寻找一个合适姿态,让物体经过路径上的门洞、狭窄通道时具有最大通过性。
Navisworks 当前主要提供 AABB 包围盒,真实物体的 fragment 代表姿态只能大概判断方向,不足以作为自动调整的精确依据。因此本功能不能依赖 fragment 推断“物体真实方向”,也不能只做绕宿主 up 轴的单轴旋转。单轴 yaw 调整手工即可完成,不满足目标。
2. 目标
在“调整物体”窗口增加自动调整能力:
- 支持三轴联动搜索,允许任意三维旋转。
- 允许物体横放、倒放、斜放,不施加运输姿态限制。
- 以路径起点方向为基准,最小化物体在门洞截面上的投影面积。
- 在投影面积相同或接近时,优先选择投影高度更小的姿态,让物体尽量平放。
- 结果写回现有 X/Y/Z 三个角度输入框,用户可继续手工微调。
- 不依赖 fragment 方向作为优化真值。
- 遵守宿主坐标系 / 内部坐标系 / 资产坐标系语义,不硬编码世界 Z 为 up。
3. 非目标
- 不在本阶段判断真实门洞尺寸,也不保证某条路径一定可通过。
- 不修改路径规划算法。
- 不重建物体 mesh 或 OBB。
- 不引入姿态限制,例如“保持底面朝下”或“禁止倒置”。
- 不用静默 fallback 掩盖优化失败;失败应明确提示。
4. 坐标系语义
UI 输入、日志、用户看到的 X/Y/Z 角度仍按宿主坐标系解释。
路径起点方向使用宿主坐标系点计算:
- 取路径起点到下一个有效路径点的方向。
- 剔除宿主 up 分量,得到水平路径前进方向
HostPathForward。 - 通过
HostCoordinateAdapter获取宿主 up:HostUp。 - 截面横向方向为
HostSide = normalize(cross(HostPathForward, HostUp))。
如果路径起始段过短或剔除 up 后方向退化,应继续查找后续有效路径段;若仍无法得到方向,则自动调整失败并提示用户。
5. 目标函数
自动调整的主目标函数是门洞截面投影面积:
Score(rotation) = ProjectedWidthAcrossPath(rotation) * ProjectedHeightAlongHostUp(rotation)
其中:
ProjectedWidthAcrossPath:物体在HostSide方向上的投影宽度。ProjectedHeightAlongHostUp:物体在HostUp方向上的投影高度。- 路径前进方向上的长度不参与目标函数。
该目标符合“穿门”语义:门洞主要限制的是横向净宽和竖向净高,而不是物体沿路径方向占多长。
在工程现场中,门洞通常“宽度大于高度”,因此仅比较面积不够。两个姿态可能具有相同或非常接近的面积,但一个姿态更高、更窄,另一个姿态更低、更宽;实际通行时应优先选择更低、更平放的姿态。
因此最终排序应采用词典序或近似平局策略:
- 先最小化
ProjectedArea。 - 当面积差异小于容差时,选择
ProjectedHeightAlongHostUp更小的姿态。 - 当面积和高度都接近时,再选择
ProjectedWidthAcrossPath更小的姿态。
面积容差建议使用相对容差,例如 1%,避免因为 AABB 或浮点误差导致高度明显更优的姿态被面积微小差异淘汰。
6. 推荐算法
采用业界常见的黑盒无导数优化路线:
6.1 全局粗搜索
在完整三维旋转空间中生成候选姿态,避免只绕某一轴或只优化 yaw。
候选生成应满足:
- 覆盖三维姿态空间。
- 结果确定性,不依赖随机数。
- 粗搜索粒度可配置,默认优先保证交互速度。
可选实现:
- 均匀方向采样加 roll 角采样。
- Fibonacci sphere / icosphere 风格方向采样。
- 固定欧拉角网格作为初始版本,但需要避免只覆盖少量手工角度。
6.2 局部精修
对粗搜索评分最好的若干候选执行无导数局部优化,例如:
- Powell method。
- Nelder-Mead simplex。
Navisworks AABB 目标函数不平滑,也不可求导,因此不使用梯度法。局部优化的终止条件应包含:
- 最大迭代次数。
- 角度步长阈值。
- 评分改善阈值。
6.3 输出角度
优化器内部可用四元数表示候选姿态,最终需要转换为当前窗口使用的宿主 X/Y/Z 三轴角度修正,并写回:
RotationXDegreesRotationYDegreesRotationZDegrees
角度顺序必须遵守项目当前约束:X -> Y -> Z,对应 qz * qy * qx。
7. 评估方式
第一阶段建议实现为纯几何优化器:
- 输入物体三轴尺寸。
- 输入宿主坐标系下的
HostPathForward/HostSide/HostUp。 - 输入候选旋转。
- 输出截面投影宽度、高度、面积。
这样可以用单元测试充分锁定算法,不需要启动 Navisworks。
真实物体的 fragment 代表姿态不作为优化真值。若后续发现数学预测与 Navisworks 实际 AABB 存在明显偏差,再增加“慢速精确模式”:
- 保存当前动画物体状态。
- 临时应用候选姿态到路径起点。
- 读取 Navisworks 更新后的 AABB。
- 计算截面投影面积。
- 恢复状态。
慢速模式必须复用 PathAnimationManager / ModelItemTransformHelper 的现有姿态链路,不能绕过主链路直接写入临时补丁。
8. UI 行为
“调整物体”窗口增加一个“自动调整”按钮。
建议行为:
- 用户打开“调整物体”窗口。
- 点击“自动调整”。
- 系统根据当前路径起点方向、当前物体尺寸和宿主坐标系执行优化。
- 将最优 X/Y/Z 角度写入输入框。
- 用户可继续修改角度。
- 点击“确认”后沿用现有
ObjectStartPlacementRequest.CreateRotationCorrection(...)链路。
自动调整失败时,窗口不关闭,并显示明确错误:
- 未选择路径。
- 路径点不足。
- 起点方向退化。
- 未选择动画物体。
- 物体尺寸无效。
- 优化器未找到有效姿态。
9. 测试计划
新增纯几何单元测试,建议放在 UnitTests/CoordinateSystem/。
必须覆盖:
- 长方体通过三轴旋转得到比初始姿态更小的截面面积。
- 三轴优化能找到单轴 yaw 无法达到的更小截面面积。
YUp和ZUp下HostUp高度语义正确。- 路径横向宽度和宿主 up 高度共同参与目标函数。
- 面积接近时优先选择投影高度更小的平放姿态。
- 任意旋转允许倒置,不强制保持原 up 方向。
- 优化结果确定性:同一输入多次运行输出一致。
- 退化路径方向会失败而不是回退默认方向。
后续接入 UI 后,补充 ViewModel 或窗口级测试:
- 点击自动调整后会更新 X/Y/Z 输入值。
- 自动调整后确认仍走现有角度修正请求。
- 失败时保留原输入值。
10. 实现落点
候选落点:
src/Utils/CoordinateSystem/ObjectPassageProjectionOptimizer.csUnitTests/CoordinateSystem/ObjectPassageProjectionOptimizerTests.cssrc/UI/WPF/Views/EditRotationWindow.xamlsrc/UI/WPF/Views/EditRotationWindow.xaml.cssrc/UI/WPF/ViewModels/AnimationControlViewModel.cs
如果需要从 ViewModel 提供路径和尺寸上下文,可新增一个小的请求对象,避免窗口直接依赖大型 ViewModel。
11. 风险与注意事项
- Euler 角存在多解和万向节锁风险;优化内部应优先用四元数,Euler 只作为 UI 输出格式。
- AABB 只能近似真实几何,通过性结果应理解为基于包围盒的保守估计。
- 对真实物体,fragment 仅可作为现有动画链路的弱参考,不作为自动调整的优化真值。
- 对 Ground / Hoisting / Rail 的路径姿态链路不得引入旧 yaw fallback。
- 若候选姿态会改变落位补偿,必须同步更新通行空间尺寸和起点预览。