diff --git a/doc/requirement/todo_features.md b/doc/requirement/todo_features.md
index 7465a91..a3b7627 100644
--- a/doc/requirement/todo_features.md
+++ b/doc/requirement/todo_features.md
@@ -4,7 +4,7 @@
### [2026/1/6]
-1. [ ] (BUG)虚拟车辆模型每次点击都重建
+1. [x] (BUG)虚拟车辆模型每次点击都重建
2. [x] (BUG)碰撞结果高亮,应该显示clashdetective检测的结果
3. [x] (优化)对clashdetective的检测结果,进行向上合并,找到集合对象。
4. [x] (功能)碰撞检测结果保存数据库,列表展示
diff --git a/src/Core/Collision/ClashDetectiveIntegration.cs b/src/Core/Collision/ClashDetectiveIntegration.cs
index 1f9d515..d0f9d44 100644
--- a/src/Core/Collision/ClashDetectiveIntegration.cs
+++ b/src/Core/Collision/ClashDetectiveIntegration.cs
@@ -297,19 +297,15 @@ namespace NavisworksTransport
ModelItem vehicleObject = null;
if (testInfo.IsVirtualVehicle)
{
- // 创建虚拟车辆
- vehicleObject = VirtualVehicleManager.Instance.CreateVirtualVehicle(
+ // 显示虚拟车辆
+ VirtualVehicleManager.Instance.ShowVirtualVehicle(
testInfo.VirtualVehicleLength,
testInfo.VirtualVehicleWidth,
testInfo.VirtualVehicleHeight
- ) ?? throw new InvalidOperationException($"[LoadClashDetectiveResultsFromDatabase] 创建虚拟车辆失败");
- LogManager.Info($"[LoadClashDetectiveResultsFromDatabase] 已创建虚拟车辆: {testInfo.VirtualVehicleLength}×{testInfo.VirtualVehicleWidth}×{testInfo.VirtualVehicleHeight}m");
-
- // 将虚拟车辆显示出来(确保不被隐藏)
- var doc = Application.ActiveDocument;
- var vehicleItems = new ModelItemCollection { vehicleObject };
- doc.Models.SetHidden(vehicleItems, false);
- LogManager.Info($"[LoadClashDetectiveResultsFromDatabase] 虚拟车辆已显示");
+ );
+ vehicleObject = VirtualVehicleManager.Instance.CurrentVirtualVehicle
+ ?? throw new InvalidOperationException($"[LoadClashDetectiveResultsFromDatabase] 显示虚拟车辆失败");
+ LogManager.Info($"[LoadClashDetectiveResultsFromDatabase] 已显示虚拟车辆: {testInfo.VirtualVehicleLength}×{testInfo.VirtualVehicleWidth}×{testInfo.VirtualVehicleHeight}m");
}
else if (testInfo.VehicleModelIndex.HasValue && !string.IsNullOrEmpty(testInfo.VehiclePathId))
{
diff --git a/src/Core/MainPlugin.cs b/src/Core/MainPlugin.cs
index ef8820a..3eda1d7 100644
--- a/src/Core/MainPlugin.cs
+++ b/src/Core/MainPlugin.cs
@@ -626,6 +626,17 @@ namespace NavisworksTransport
LogManager.Warning($"[文档管理] 清理Idle事件管理器时出现警告: {ex.Message}");
}
+ // 清理虚拟车辆
+ try
+ {
+ VirtualVehicleManager.Instance.Cleanup();
+ LogManager.Info("[文档管理] 已清理虚拟车辆");
+ }
+ catch (Exception ex)
+ {
+ LogManager.Warning($"[文档管理] 清理虚拟车辆时出现警告: {ex.Message}");
+ }
+
// 清除临时材质
try
{
diff --git a/src/Core/VirtualVehicleManager.cs b/src/Core/VirtualVehicleManager.cs
index 36fcbc2..ee9dccf 100644
--- a/src/Core/VirtualVehicleManager.cs
+++ b/src/Core/VirtualVehicleManager.cs
@@ -56,81 +56,177 @@ namespace NavisworksTransport.Core
}
///
- /// 创建虚拟车辆立方体
+ /// 显示虚拟车辆
///
- /// 长度(米)- X方向
- /// 宽度(米)- Y方向
- /// 高度(米)- Z方向
- /// 创建的ModelItem
- public ModelItem CreateVirtualVehicle(double lengthMeters, double widthMeters, double heightMeters)
+ /// 长度(米)
+ /// 宽度(米)
+ /// 高度(米)
+ public void ShowVirtualVehicle(double lengthMeters, double widthMeters, double heightMeters)
{
try
{
- LogManager.Info($"=== 创建虚拟车辆 ===");
- LogManager.Info($"目标尺寸: {lengthMeters:F2}m × {widthMeters:F2}m × {heightMeters:F2}m");
-
- // 1. 清理之前的虚拟车辆
- RemoveVirtualVehicle();
-
- // 2. 获取单位立方体文件路径
- var unitCubePath = GetUnitCubeFilePath();
- if (string.IsNullOrEmpty(unitCubePath) || !File.Exists(unitCubePath))
- {
- throw new FileNotFoundException($"找不到单位立方体文件: {unitCubePath}");
- }
-
- LogManager.Info($"单位立方体文件: {unitCubePath}");
-
- // 3. 记录追加前的模型数量
var doc = Application.ActiveDocument;
- int modelCountBefore = doc.Models.Count;
- LogManager.Info($"追加前模型数量: {modelCountBefore}");
- // 4. 追加单位立方体文件
- if (!doc.TryAppendFile(unitCubePath))
+ // 检查虚拟车辆模型是否已存在
+ if (_virtualVehicleModel != null)
{
- throw new InvalidOperationException($"无法追加文件: {unitCubePath}");
+ int currentIndex = doc.Models.IndexOf(_virtualVehicleModel);
+ if (currentIndex >= 0)
+ {
+ // 模型存在,显示它并更新尺寸
+ LogManager.Info($"虚拟车辆模型已存在(索引: {currentIndex}),显示并更新尺寸");
+
+ var modelItems = new ModelItemCollection { _virtualVehicleModelItem };
+ doc.Models.SetHidden(modelItems, false);
+
+ // 获取实际的几何体项
+ _virtualVehicleModelItem = _virtualVehicleModel.RootItem;
+ var geometryItem = FindFirstGeometryItem(_virtualVehicleModelItem);
+ if (geometryItem != null && !geometryItem.Equals(_virtualVehicleModelItem))
+ {
+ _virtualVehicleModelItem = geometryItem;
+ }
+
+ // 重置变换并缩放到目标尺寸
+ ResetVirtualVehicleTransform();
+ ScaleVirtualVehicle(lengthMeters, widthMeters, heightMeters);
+
+ _isVirtualVehicleActive = true;
+ LogManager.Info($"虚拟车辆更新成功");
+ return;
+ }
+ else
+ {
+ LogManager.Warning($"已保存的虚拟车辆模型不在文档中,需要重新创建");
+ }
}
- // 5. 获取新追加的模型
- int modelCountAfter = doc.Models.Count;
- LogManager.Info($"追加后模型数量: {modelCountAfter}");
-
- if (modelCountAfter <= modelCountBefore)
- {
- throw new InvalidOperationException("追加文件后模型数量未增加");
- }
-
- _virtualVehicleModel = doc.Models.Last();
- _virtualVehicleModelItem = _virtualVehicleModel.RootItem;
-
- LogManager.Info($"虚拟车辆模型: {_virtualVehicleModel.FileName}");
- LogManager.Info($"虚拟车辆根项: {_virtualVehicleModelItem.DisplayName}");
-
- // 6. 获取实际的几何体项(可能在子节点中)
- var geometryItem = FindFirstGeometryItem(_virtualVehicleModelItem);
- if (geometryItem != null && !geometryItem.Equals(_virtualVehicleModelItem))
- {
- LogManager.Info($"找到几何体项: {geometryItem.DisplayName}");
- _virtualVehicleModelItem = geometryItem;
- }
-
- // 7. 缩放到目标尺寸
- ScaleVirtualVehicle(lengthMeters, widthMeters, heightMeters);
-
- _isVirtualVehicleActive = true;
-
- LogManager.Info($"虚拟车辆创建成功");
- return _virtualVehicleModelItem;
+ // 模型不存在,创建新的
+ CreateVirtualVehicleInternal(doc, lengthMeters, widthMeters, heightMeters);
}
catch (Exception ex)
{
- LogManager.Error($"创建虚拟车辆失败: {ex.Message}", ex);
- RemoveVirtualVehicle();
- throw;
+ LogManager.Error($"显示虚拟车辆失败: {ex.Message}");
}
}
+ ///
+ /// 隐藏虚拟车辆
+ ///
+ public void HideVirtualVehicle()
+ {
+ try
+ {
+ if (_virtualVehicleModelItem != null)
+ {
+ var doc = Application.ActiveDocument;
+ var modelItems = new ModelItemCollection { _virtualVehicleModelItem };
+ doc.Models.SetHidden(modelItems, true);
+
+ LogManager.Info($"已隐藏虚拟车辆模型");
+ }
+
+ // 隐藏时设置为非激活状态,但保留模型引用
+ _isVirtualVehicleActive = false;
+ }
+ catch (Exception ex)
+ {
+ LogManager.Error($"隐藏虚拟车辆失败: {ex.Message}");
+ _isVirtualVehicleActive = false;
+ }
+ }
+
+ ///
+ /// 创建虚拟车辆(内部方法)
+ ///
+ private void CreateVirtualVehicleInternal(Document doc, double lengthMeters, double widthMeters, double heightMeters)
+ {
+ LogManager.Info($"=== 创建虚拟车辆 ===");
+ LogManager.Info($"目标尺寸: {lengthMeters:F2}m × {widthMeters:F2}m × {heightMeters:F2}m");
+
+ // 加载新的虚拟车辆模型
+ LoadNewVirtualVehicleModel(doc);
+
+ // 获取实际的几何体项
+ _virtualVehicleModelItem = _virtualVehicleModel.RootItem;
+ var geometryItem = FindFirstGeometryItem(_virtualVehicleModelItem);
+ if (geometryItem != null && !geometryItem.Equals(_virtualVehicleModelItem))
+ {
+ _virtualVehicleModelItem = geometryItem;
+ }
+
+ // 重置变换并缩放到目标尺寸
+ ResetVirtualVehicleTransform();
+ ScaleVirtualVehicle(lengthMeters, widthMeters, heightMeters);
+
+ // 设置状态
+ _isVirtualVehicleActive = true;
+
+ LogManager.Info($"虚拟车辆创建成功");
+ }
+
+ ///
+ /// 加载新的虚拟车辆模型
+ ///
+ private void LoadNewVirtualVehicleModel(Document doc)
+ {
+ LogManager.Info($"需要加载新的虚拟车辆模型");
+
+ // 1. 获取单位立方体文件路径
+ var unitCubePath = GetUnitCubeFilePath();
+ if (string.IsNullOrEmpty(unitCubePath) || !File.Exists(unitCubePath))
+ {
+ throw new FileNotFoundException($"找不到单位立方体文件: {unitCubePath}");
+ }
+
+ LogManager.Info($"单位立方体文件: {unitCubePath}");
+
+ // 2. 记录追加前的模型数量
+ int modelCountBefore = doc.Models.Count;
+ LogManager.Info($"追加前模型数量: {modelCountBefore}");
+
+ // 3. 追加单位立方体文件
+ if (!doc.TryAppendFile(unitCubePath))
+ {
+ throw new InvalidOperationException($"无法追加文件: {unitCubePath}");
+ }
+
+ // 4. 验证并获取新追加的模型
+ int modelCountAfter = doc.Models.Count;
+ LogManager.Info($"追加后模型数量: {modelCountAfter}");
+
+ if (modelCountAfter <= modelCountBefore)
+ {
+ throw new InvalidOperationException("追加文件后模型数量未增加");
+ }
+
+ // 保存模型引用(最后一个模型就是刚追加的)
+ _virtualVehicleModel = doc.Models.Last();
+
+ LogManager.Info($"虚拟车辆模型: {_virtualVehicleModel.FileName}");
+ LogManager.Info($"虚拟车辆根项: {_virtualVehicleModel.RootItem.DisplayName}");
+ }
+
+ ///
+ /// 重置虚拟车辆变换为单位矩阵
+ ///
+ private void ResetVirtualVehicleTransform()
+ {
+ if (_virtualVehicleModel == null) return;
+
+ var doc = Application.ActiveDocument;
+
+ // 创建单位变换矩阵
+ Transform3D identityTransform = new Transform3D();
+ Transform3DComponents identityComponents = identityTransform.Factor();
+
+ // 应用单位变换
+ Units currentUnits = _virtualVehicleModel.Units;
+ doc.Models.SetModelUnitsAndTransform(_virtualVehicleModel, currentUnits, identityTransform, false);
+
+ LogManager.Info("已重置虚拟车辆变换");
+ }
+
///
/// 缩放虚拟车辆到目标尺寸
/// 使用DocumentModels.SetModelUnitsAndTransform方法进行模型级缩放
@@ -208,31 +304,47 @@ namespace NavisworksTransport.Core
}
///
- /// 移除虚拟车辆(隐藏模型,因为Navisworks API不支持直接删除追加的模型)
+ /// 移除虚拟车辆(使用 TryRemoveFile 真正删除模型)
///
public void RemoveVirtualVehicle()
{
try
{
- if (_virtualVehicleModelItem != null)
+ var doc = Application.ActiveDocument;
+
+ if (_virtualVehicleModel != null)
{
- // Navisworks API不支持直接删除追加的模型
- // 使用隐藏方式处理
- var doc = Application.ActiveDocument;
- var modelItems = new ModelItemCollection { _virtualVehicleModelItem };
- doc.Models.SetHidden(modelItems, true);
-
- LogManager.Info($"已隐藏虚拟车辆模型");
+ // 动态查找模型索引
+ int currentIndex = doc.Models.IndexOf(_virtualVehicleModel);
+
+ if (currentIndex >= 0)
+ {
+ // 使用 TryRemoveFile 真正删除模型
+ bool removed = doc.TryRemoveFile(currentIndex);
+
+ if (removed)
+ {
+ LogManager.Info($"已删除虚拟车辆模型(索引: {currentIndex})");
+ }
+ else
+ {
+ LogManager.Warning($"删除虚拟车辆模型失败(索引: {currentIndex})");
+ }
+ }
+ else
+ {
+ LogManager.Warning($"虚拟车辆模型不在文档中,无法删除");
+ }
}
- // 清理引用但不尝试删除模型
+ // 清理引用
_virtualVehicleModel = null;
_virtualVehicleModelItem = null;
_isVirtualVehicleActive = false;
}
catch (Exception ex)
{
- LogManager.Error($"隐藏虚拟车辆失败: {ex.Message}");
+ LogManager.Error($"删除虚拟车辆失败: {ex.Message}");
_virtualVehicleModel = null;
_virtualVehicleModelItem = null;
_isVirtualVehicleActive = false;
diff --git a/src/UI/WPF/ViewModels/AnimationControlViewModel.cs b/src/UI/WPF/ViewModels/AnimationControlViewModel.cs
index 3abfde3..5981a6b 100644
--- a/src/UI/WPF/ViewModels/AnimationControlViewModel.cs
+++ b/src/UI/WPF/ViewModels/AnimationControlViewModel.cs
@@ -481,18 +481,16 @@ namespace NavisworksTransport.UI.WPF.ViewModels
LogManager.Info("已切换到虚拟车辆模式,将之前的手动选择物体归位并清理动画数据");
}
- // ✨ 统一逻辑:启用虚拟车辆时立即创建并对齐到起点
- if (VirtualVehicleManager.Instance.IsVirtualVehicleActive == false)
- {
- LogManager.Info("正在创建并初始化虚拟车辆到起点...");
- var vModel = VirtualVehicleManager.Instance.CreateVirtualVehicle(
- VirtualVehicleLength, VirtualVehicleWidth, VirtualVehicleHeight);
+ // 显示虚拟车辆,并同步到起点
+ LogManager.Info("正在显示虚拟车辆到起点...");
+ VirtualVehicleManager.Instance.ShowVirtualVehicle(
+ VirtualVehicleLength, VirtualVehicleWidth, VirtualVehicleHeight);
- if (vModel != null && CurrentPathRoute != null && CurrentPathRoute.Points != null)
- {
- var points = CurrentPathRoute.Points.Select(p => new Point3D(p.X, p.Y, p.Z)).ToList();
- _pathAnimationManager?.SyncToPathStart(vModel, points);
- }
+ var vModel = VirtualVehicleManager.Instance.CurrentVirtualVehicle;
+ if (vModel != null && CurrentPathRoute != null && CurrentPathRoute.Points != null)
+ {
+ var points = CurrentPathRoute.Points.Select(p => new Point3D(p.X, p.Y, p.Z)).ToList();
+ _pathAnimationManager?.SyncToPathStart(vModel, points);
}
}
catch (Exception ex)
@@ -502,10 +500,11 @@ namespace NavisworksTransport.UI.WPF.ViewModels
}
else
{
- // ✨ 模式切换清理:切换到手动选择模式时,移除存在的虚拟车辆并清理数据
+ // ✨ 模式切换清理:切换到手动选择模式时,隐藏虚拟车辆并清理数据
try
{
- VirtualVehicleManager.Instance.RemoveVirtualVehicle();
+ // 不删除虚拟车辆,只隐藏它
+ VirtualVehicleManager.Instance.HideVirtualVehicle();
_pathAnimationManager?.ClearAnimationResults(); // 清理虚拟车辆留下的动画数据
LogManager.Info("已切换到手动选择模式,自动隐藏虚拟车辆并清理动画数据");
}
@@ -2133,20 +2132,21 @@ namespace NavisworksTransport.UI.WPF.ViewModels
if (animatedObject == null)
{
- LogManager.Info("[ExecuteGenerateAnimation] 虚拟车辆不存在,正在创建...");
- UpdateMainStatus("正在创建虚拟车辆...", -1, true);
+ LogManager.Info("[ExecuteGenerateAnimation] 虚拟车辆不存在,正在显示...");
+ UpdateMainStatus("正在显示虚拟车辆...", -1, true);
- animatedObject = Core.VirtualVehicleManager.Instance.CreateVirtualVehicle(
+ VirtualVehicleManager.Instance.ShowVirtualVehicle(
VirtualVehicleLength,
VirtualVehicleWidth,
VirtualVehicleHeight
);
+ animatedObject = VirtualVehicleManager.Instance.CurrentVirtualVehicle;
}
if (animatedObject == null)
{
- LogManager.Error("[动画生成] 虚拟车辆创建失败");
- UpdateMainStatus("生成失败:无法创建虚拟车辆");
+ LogManager.Error("[动画生成] 虚拟车辆显示失败");
+ UpdateMainStatus("生成失败:无法显示虚拟车辆");
return;
}