NavisworksTransport/doc/working/virtual_vehicle_collision_detection.md

9.1 KiB
Raw Permalink Blame History

虚拟车辆立方体碰撞检测功能设计方案

需求背景

当前项目中,检测动画用的移动物体是手工选择的。需要增加一种方式,按照路径编辑中车辆的长宽高,动态生成一个立方体,用它来进行碰撞检测。

需求来源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 创建 VirtualVehicleManager 类

/// <summary>
/// 虚拟车辆管理器 - 负责创建和管理虚拟车辆几何体
/// </summary>
public class VirtualVehicleManager
{
    private static VirtualVehicleManager _instance;
    public static VirtualVehicleManager Instance => _instance ?? (_instance = new VirtualVehicleManager());
    
    private ModelItem _virtualVehicleModelItem;
    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 CreateVirtualVehicle(double lengthMeters, double widthMeters, double heightMeters, Point3D position)
    {
        try
        {
            // 1. 清理之前的虚拟车辆
            RemoveVirtualVehicle();
            
            // 2. 创建临时NWD文件包含立方体
            _tempFilePath = CreateCubeNwdFile(lengthMeters, widthMeters, heightMeters);
            
            // 3. 追加到当前文档
            var doc = Application.ActiveDocument;
            doc.AppendFile(_tempFilePath);
            
            // 4. 获取追加后的ModelItem最后一个模型的根节点
            _virtualVehicleModelItem = GetLastAppendedModel();
            
            // 5. 移动到指定位置
            MoveToPosition(_virtualVehicleModelItem, position);
            
            LogManager.Info($"虚拟车辆创建成功: {lengthMeters:F1}m × {widthMeters:F1}m × {heightMeters:F1}m");
            return _virtualVehicleModelItem;
        }
        catch (Exception ex)
        {
            LogManager.Error($"创建虚拟车辆失败: {ex.Message}");
            throw;
        }
    }
    
    /// <summary>
    /// 移除虚拟车辆
    /// </summary>
    public void RemoveVirtualVehicle()
    {
        if (_virtualVehicleModelItem != null)
        {
            // 从文档中移除模型
            // ...
            _virtualVehicleModelItem = null;
        }
        
        // 清理临时文件
        if (!string.IsNullOrEmpty(_tempFilePath) && File.Exists(_tempFilePath))
        {
            File.Delete(_tempFilePath);
            _tempFilePath = null;
        }
    }
    
    /// <summary>
    /// 获取当前虚拟车辆
    /// </summary>
    public ModelItem CurrentVirtualVehicle => _virtualVehicleModelItem;
}

2.2 修改 AnimationControlViewModel

private void ExecuteGenerateAnimation()
{
    try
    {
        ModelItem animatedObject;
        
        if (UseVirtualVehicle)
        {
            // 创建虚拟车辆几何体
            var startPosition = CurrentPathRoute.Points.First();
            animatedObject = VirtualVehicleManager.Instance.CreateVirtualVehicle(
                VirtualVehicleLength,
                VirtualVehicleWidth,
                VirtualVehicleHeight,
                new Point3D(startPosition.X, startPosition.Y, startPosition.Z)
            );
            
            LogManager.Info($"使用虚拟车辆: {VirtualVehicleLength:F1}m × {VirtualVehicleWidth:F1}m × {VirtualVehicleHeight: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 (UseVirtualVehicle && VirtualVehicleManager.Instance.CurrentVirtualVehicle != null)
    {
        // 可选:提示用户是否保留虚拟车辆
        // 或者自动移除
        // VirtualVehicleManager.Instance.RemoveVirtualVehicle();
    }
}

3. 创建立方体NWD文件的技术细节

由于Navisworks API不直接支持创建几何体可以采用以下方案

方案A预制单位立方体 + 缩放

  1. 预先准备一个1m×1m×1m的立方体NWC文件放在插件资源目录
  2. 运行时追加这个文件
  3. 使用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中间格式

  1. 运行时生成OBJ格式的立方体文件
  2. 使用Navisworks的文件转换功能导入

4. 关于预制立方体文件

需要准备一个unit_cube.nwc文件:

  • 尺寸1m × 1m × 1m
  • 原点:底面中心在原点
  • 材质:半透明(便于观察碰撞)

可以使用以下工具创建:

  1. AutoCAD/Revit 导出
  2. 3ds Max 导出
  3. 简单的OBJ文件手动编写后转换

修改文件清单

文件 修改类型 主要改动
VirtualVehicleManager.cs 新增 虚拟车辆几何体创建和管理
AnimationControlView.xaml 修改 添加RadioButton选择组和虚拟车辆尺寸显示
AnimationControlViewModel.cs 修改 调用VirtualVehicleManager创建虚拟车辆
LogisticsControlPanel.xaml.cs 修改 添加车辆参数同步逻辑
resources/unit_cube.nwc 新增 预制的单位立方体模型文件

关键优势

  1. 完全复用现有代码创建真实ModelItem后所有现有逻辑动画、碰撞检测、Clash Detective测试、报告生成无需任何修改
  2. 真实的碰撞检测结果Clash Detective可以进行精确几何体验证
  3. 最小改动原则:只需添加创建几何体的逻辑,其他代码不变

测试要点

  1. 几何体创建

    • 虚拟车辆立方体正确创建
    • 尺寸和位置正确
  2. 碰撞检测

    • 与手动选择物体的检测结果一致
    • Clash Detective测试正常生成
  3. 清理

    • 动画结束后正确清理临时文件
    • 用户可选择是否保留虚拟车辆

实现步骤

  1. 准备预制的单位立方体NWC文件
  2. 创建VirtualVehicleManager类
  3. 修改AnimationControlViewModel调用VirtualVehicleManager
  4. 测试完整流程