9.0 KiB
9.0 KiB
虚拟物体立方体碰撞检测功能设计方案
需求背景
当前项目中,检测动画用的移动物体是手工选择的。需要增加一种方式,按照路径编辑中物体的长宽高,动态生成一个立方体,用它来进行碰撞检测。
需求来源:doc/requirement/todo_features.md - 2025/12/08 功能点3
(功能)动画检测,增加使用模拟物流构件立方体选项
方案选择
方案A(已弃用):虚拟包围盒
- 仅使用虚拟包围盒进行碰撞检测
- 问题:Clash Detective需要两个真实的ModelItem进行精确几何体验证,虚拟包围盒无法满足
方案B(采用):创建真实几何体
- 在Navisworks中动态创建一个真实的立方体几何体
- 将其作为动画对象,复用现有的全部碰撞检测逻辑
- 优势:完全复用现有代码,支持Clash Detective精确验证
核心思路
关键洞察:虚拟物体本质上就是一个动态创建的立方体ModelItem,一旦创建完成,后续流程与手动选择物体完全一致。
用户选择"虚拟物体模式"
↓
根据物体尺寸创建立方体几何体(NWD/NWC文件或内存几何体)
↓
将创建的立方体作为 _animatedObject
↓
【完全复用现有流程】
- SetupAnimation()
- PrecomputeAnimationFrames()
- StartAnimation()
- CreateClashTestAfterAnimation()
技术实现
1. 创建立方体几何体的方法
Navisworks API有以下几种方式创建几何体:
方法1:使用临时NWD文件(推荐)
// 1. 创建临时NWD文件包含立方体
// 2. 追加到当前文档
// 3. 获取追加后的ModelItem引用
// 4. 动画结束后移除临时模型
方法2:使用Presenter API(如果可用)
// 使用 Autodesk.Navisworks.Api.Presenter 命名空间
// 创建临时几何体用于可视化
方法3:使用外部工具生成
// 预先创建一个单位立方体NWC文件
// 运行时追加并缩放到目标尺寸
2. 实现方案详细设计
2.1 创建 VirtualObjectManager 类
/// <summary>
/// 虚拟物体管理器 - 负责创建和管理虚拟物体几何体
/// </summary>
public class VirtualObjectManager
{
private static VirtualObjectManager _instance;
public static VirtualObjectManager Instance => _instance ?? (_instance = new VirtualObjectManager());
private ModelItem _virtualObjectModelItem;
private string _tempFilePath;
/// <summary>
/// 创建虚拟物体立方体
/// </summary>
/// <param name="lengthMeters">长度(米)</param>
/// <param name="widthMeters">宽度(米)</param>
/// <param name="heightMeters">高度(米)</param>
/// <param name="position">初始位置</param>
/// <returns>创建的ModelItem</returns>
public ModelItem CreateVirtualObject(double lengthMeters, double widthMeters, double heightMeters, Point3D position)
{
try
{
// 1. 清理之前的虚拟物体
RemoveVirtualObject();
// 2. 创建临时NWD文件包含立方体
_tempFilePath = CreateCubeNwdFile(lengthMeters, widthMeters, heightMeters);
// 3. 追加到当前文档
var doc = Application.ActiveDocument;
doc.AppendFile(_tempFilePath);
// 4. 获取追加后的ModelItem(最后一个模型的根节点)
_virtualObjectModelItem = GetLastAppendedModel();
// 5. 移动到指定位置
MoveToPosition(_virtualObjectModelItem, position);
LogManager.Info($"虚拟物体创建成功: {lengthMeters:F1}m × {widthMeters:F1}m × {heightMeters:F1}m");
return _virtualObjectModelItem;
}
catch (Exception ex)
{
LogManager.Error($"创建虚拟物体失败: {ex.Message}");
throw;
}
}
/// <summary>
/// 移除虚拟物体
/// </summary>
public void RemoveVirtualObject()
{
if (_virtualObjectModelItem != null)
{
// 从文档中移除模型
// ...
_virtualObjectModelItem = null;
}
// 清理临时文件
if (!string.IsNullOrEmpty(_tempFilePath) && File.Exists(_tempFilePath))
{
File.Delete(_tempFilePath);
_tempFilePath = null;
}
}
/// <summary>
/// 获取当前虚拟物体
/// </summary>
public ModelItem CurrentVirtualObject => _virtualObjectModelItem;
}
2.2 修改 AnimationControlViewModel
private void ExecuteGenerateAnimation()
{
try
{
ModelItem animatedObject;
if (UseVirtualObject)
{
// 创建虚拟物体几何体
var startPosition = CurrentPathRoute.Points.First();
animatedObject = VirtualObjectManager.Instance.CreateVirtualObject(
VirtualObjectLength,
VirtualObjectWidth,
VirtualObjectHeight,
new Point3D(startPosition.X, startPosition.Y, startPosition.Z)
);
LogManager.Info($"使用虚拟物体: {VirtualObjectLength:F1}m × {VirtualObjectWidth:F1}m × {VirtualObjectHeight:F1}m");
}
else
{
animatedObject = SelectedAnimatedObject;
}
// 【以下完全复用现有逻辑】
var pathPoints = CurrentPathRoute.Points.Select(p => new Point3D(p.X, p.Y, p.Z)).ToList();
_pathAnimationManager.CreateAnimation(
animatedObject, // 无论是手动选择的还是虚拟物体,都是真实的ModelItem
pathPoints,
AnimationDuration,
CurrentPathRoute.Name,
CurrentPathRoute.Id
);
// ... 其余现有逻辑不变 ...
}
catch (Exception ex)
{
// ...
}
}
2.3 动画结束后清理
// 在动画完成后的处理中
private void OnAnimationCompleted()
{
// ... 现有的报告生成和Clash测试创建 ...
// 如果使用了虚拟物体,询问用户是否保留
if (UseVirtualObject && VirtualObjectManager.Instance.CurrentVirtualObject != null)
{
// 可选:提示用户是否保留虚拟物体
// 或者自动移除
// VirtualObjectManager.Instance.RemoveVirtualObject();
}
}
3. 创建立方体NWD文件的技术细节
由于Navisworks API不直接支持创建几何体,可以采用以下方案:
方案A:预制单位立方体 + 缩放
- 预先准备一个1m×1m×1m的立方体NWC文件(放在插件资源目录)
- 运行时追加这个文件
- 使用
Transform3D.CreateScale缩放到目标尺寸
private ModelItem CreateScaledCube(double length, double width, double height)
{
// 追加预制的单位立方体
var unitCubePath = Path.Combine(PluginResourcesPath, "unit_cube.nwc");
doc.AppendFile(unitCubePath);
var cubeItem = GetLastAppendedModel();
// 缩放到目标尺寸
var scaleTransform = Transform3D.CreateScale(length, width, height);
doc.Models.OverridePermanentTransform(new ModelItemCollection { cubeItem }, scaleTransform, true);
return cubeItem;
}
方案B:使用FBX/OBJ中间格式
- 运行时生成OBJ格式的立方体文件
- 使用Navisworks的文件转换功能导入
4. 关于预制立方体文件
需要准备一个unit_cube.nwc文件:
- 尺寸:1m × 1m × 1m
- 原点:底面中心在原点
- 材质:半透明(便于观察碰撞)
可以使用以下工具创建:
- AutoCAD/Revit 导出
- 3ds Max 导出
- 简单的OBJ文件手动编写后转换
修改文件清单
| 文件 | 修改类型 | 主要改动 |
|---|---|---|
VirtualObjectManager.cs |
新增 | 虚拟物体几何体创建和管理 |
AnimationControlView.xaml |
修改 | 添加RadioButton选择组和虚拟物体尺寸显示 |
AnimationControlViewModel.cs |
修改 | 调用VirtualObjectManager创建虚拟物体 |
LogisticsControlPanel.xaml.cs |
修改 | 添加物体参数同步逻辑 |
resources/unit_cube.nwc |
新增 | 预制的单位立方体模型文件 |
关键优势
- 完全复用现有代码:创建真实ModelItem后,所有现有逻辑(动画、碰撞检测、Clash Detective测试、报告生成)无需任何修改
- 真实的碰撞检测结果:Clash Detective可以进行精确几何体验证
- 最小改动原则:只需添加创建几何体的逻辑,其他代码不变
测试要点
-
几何体创建
- 虚拟物体立方体正确创建
- 尺寸和位置正确
-
碰撞检测
- 与手动选择物体的检测结果一致
- Clash Detective测试正常生成
-
清理
- 动画结束后正确清理临时文件
- 用户可选择是否保留虚拟物体
实现步骤
- 准备预制的单位立方体NWC文件
- 创建VirtualObjectManager类
- 修改AnimationControlViewModel调用VirtualObjectManager
- 测试完整流程