# 自动调整物体姿态以最小化通行截面投影面积 更新时间: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 角度仍按宿主坐标系解释。 路径起点方向使用宿主坐标系点计算: 1. 取路径起点到下一个有效路径点的方向。 2. 剔除宿主 up 分量,得到水平路径前进方向 `HostPathForward`。 3. 通过 `HostCoordinateAdapter` 获取宿主 up:`HostUp`。 4. 截面横向方向为 `HostSide = normalize(cross(HostPathForward, HostUp))`。 如果路径起始段过短或剔除 up 后方向退化,应继续查找后续有效路径段;若仍无法得到方向,则自动调整失败并提示用户。 ## 5. 目标函数 自动调整的主目标函数是门洞截面投影面积: ```text Score(rotation) = ProjectedWidthAcrossPath(rotation) * ProjectedHeightAlongHostUp(rotation) ``` 其中: - `ProjectedWidthAcrossPath`:物体在 `HostSide` 方向上的投影宽度。 - `ProjectedHeightAlongHostUp`:物体在 `HostUp` 方向上的投影高度。 - 路径前进方向上的长度不参与目标函数。 该目标符合“穿门”语义:门洞主要限制的是横向净宽和竖向净高,而不是物体沿路径方向占多长。 在工程现场中,门洞通常“宽度大于高度”,因此仅比较面积不够。两个姿态可能具有相同或非常接近的面积,但一个姿态更高、更窄,另一个姿态更低、更宽;实际通行时应优先选择更低、更平放的姿态。 因此最终排序应采用词典序或近似平局策略: 1. 先最小化 `ProjectedArea`。 2. 当面积差异小于容差时,选择 `ProjectedHeightAlongHostUp` 更小的姿态。 3. 当面积和高度都接近时,再选择 `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 三轴角度修正,并写回: - `RotationXDegrees` - `RotationYDegrees` - `RotationZDegrees` 角度顺序必须遵守项目当前约束:X -> Y -> Z,对应 `qz * qy * qx`。 ## 7. 评估方式 第一阶段建议实现为纯几何优化器: - 输入物体三轴尺寸。 - 输入宿主坐标系下的 `HostPathForward` / `HostSide` / `HostUp`。 - 输入候选旋转。 - 输出截面投影宽度、高度、面积。 这样可以用单元测试充分锁定算法,不需要启动 Navisworks。 真实物体的 fragment 代表姿态不作为优化真值。若后续发现数学预测与 Navisworks 实际 AABB 存在明显偏差,再增加“慢速精确模式”: 1. 保存当前动画物体状态。 2. 临时应用候选姿态到路径起点。 3. 读取 Navisworks 更新后的 AABB。 4. 计算截面投影面积。 5. 恢复状态。 慢速模式必须复用 `PathAnimationManager` / `ModelItemTransformHelper` 的现有姿态链路,不能绕过主链路直接写入临时补丁。 ## 8. UI 行为 “调整物体”窗口增加一个“自动调整”按钮。 建议行为: 1. 用户打开“调整物体”窗口。 2. 点击“自动调整”。 3. 系统根据当前路径起点方向、当前物体尺寸和宿主坐标系执行优化。 4. 将最优 X/Y/Z 角度写入输入框。 5. 用户可继续修改角度。 6. 点击“确认”后沿用现有 `ObjectStartPlacementRequest.CreateRotationCorrection(...)` 链路。 自动调整失败时,窗口不关闭,并显示明确错误: - 未选择路径。 - 路径点不足。 - 起点方向退化。 - 未选择动画物体。 - 物体尺寸无效。 - 优化器未找到有效姿态。 ## 9. 测试计划 新增纯几何单元测试,建议放在 `UnitTests/CoordinateSystem/`。 必须覆盖: - 长方体通过三轴旋转得到比初始姿态更小的截面面积。 - 三轴优化能找到单轴 yaw 无法达到的更小截面面积。 - `YUp` 和 `ZUp` 下 `HostUp` 高度语义正确。 - 路径横向宽度和宿主 up 高度共同参与目标函数。 - 面积接近时优先选择投影高度更小的平放姿态。 - 任意旋转允许倒置,不强制保持原 up 方向。 - 优化结果确定性:同一输入多次运行输出一致。 - 退化路径方向会失败而不是回退默认方向。 后续接入 UI 后,补充 ViewModel 或窗口级测试: - 点击自动调整后会更新 X/Y/Z 输入值。 - 自动调整后确认仍走现有角度修正请求。 - 失败时保留原输入值。 ## 10. 实现落点 候选落点: - `src/Utils/CoordinateSystem/ObjectPassageProjectionOptimizer.cs` - `UnitTests/CoordinateSystem/ObjectPassageProjectionOptimizerTests.cs` - `src/UI/WPF/Views/EditRotationWindow.xaml` - `src/UI/WPF/Views/EditRotationWindow.xaml.cs` - `src/UI/WPF/ViewModels/AnimationControlViewModel.cs` 如果需要从 ViewModel 提供路径和尺寸上下文,可新增一个小的请求对象,避免窗口直接依赖大型 ViewModel。 ## 11. 风险与注意事项 - Euler 角存在多解和万向节锁风险;优化内部应优先用四元数,Euler 只作为 UI 输出格式。 - AABB 只能近似真实几何,通过性结果应理解为基于包围盒的保守估计。 - 对真实物体,fragment 仅可作为现有动画链路的弱参考,不作为自动调整的优化真值。 - 对 Ground / Hoisting / Rail 的路径姿态链路不得引入旧 yaw fallback。 - 若候选姿态会改变落位补偿,必须同步更新通行空间尺寸和起点预览。