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; }