重构创建和显示虚拟车辆的功能

This commit is contained in:
tian 2026-01-10 16:03:46 +08:00
parent 075fd5c602
commit 0a2e29cee9
5 changed files with 219 additions and 100 deletions

View File

@ -4,7 +4,7 @@
### [2026/1/6]
1. [ ] BUG虚拟车辆模型每次点击都重建
1. [x] BUG虚拟车辆模型每次点击都重建
2. [x] BUG碰撞结果高亮应该显示clashdetective检测的结果
3. [x] 优化对clashdetective的检测结果进行向上合并找到集合对象。
4. [x] (功能)碰撞检测结果保存数据库,列表展示

View File

@ -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))
{

View File

@ -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
{

View File

@ -56,81 +56,177 @@ namespace NavisworksTransport.Core
}
/// <summary>
/// 创建虚拟车辆立方体
/// 显示虚拟车辆
/// </summary>
/// <param name="lengthMeters">长度(米)- X方向</param>
/// <param name="widthMeters">宽度(米)- Y方向</param>
/// <param name="heightMeters">高度(米)- Z方向</param>
/// <returns>创建的ModelItem</returns>
public ModelItem CreateVirtualVehicle(double lengthMeters, double widthMeters, double heightMeters)
/// <param name="lengthMeters">长度(米)</param>
/// <param name="widthMeters">宽度(米)</param>
/// <param name="heightMeters">高度(米)</param>
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}");
}
}
/// <summary>
/// 隐藏虚拟车辆
/// </summary>
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;
}
}
/// <summary>
/// 创建虚拟车辆(内部方法)
/// </summary>
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($"虚拟车辆创建成功");
}
/// <summary>
/// 加载新的虚拟车辆模型
/// </summary>
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}");
}
/// <summary>
/// 重置虚拟车辆变换为单位矩阵
/// </summary>
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("已重置虚拟车辆变换");
}
/// <summary>
/// 缩放虚拟车辆到目标尺寸
/// 使用DocumentModels.SetModelUnitsAndTransform方法进行模型级缩放
@ -208,31 +304,47 @@ namespace NavisworksTransport.Core
}
/// <summary>
/// 移除虚拟车辆(隐藏模型因为Navisworks API不支持直接删除追加的模型)
/// 移除虚拟车辆(使用 TryRemoveFile 真正删除模型)
/// </summary>
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;

View File

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