- 新增 ObjectPassageProjectionOptimizer(SO(3)粗搜索+Nelder-Mead) - EditRotationWindow 加入"自动调整"按钮 - AnimationControlViewModel 实现黑盒实测评估(临时摆位→读BoundingBox→恢复) - 设计文档和实现计划
196 lines
7.9 KiB
Markdown
196 lines
7.9 KiB
Markdown
# 自动调整物体姿态以最小化通行截面投影面积
|
||
|
||
更新时间: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。
|
||
- 若候选姿态会改变落位补偿,必须同步更新通行空间尺寸和起点预览。
|