From c117e0d0c3a64ae13e1d0fa088f836acb0d680e2 Mon Sep 17 00:00:00 2001 From: tian <11429339@qq.com> Date: Mon, 26 Jan 2026 00:25:05 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84=E7=A2=B0=E6=92=9E=E6=A3=80?= =?UTF-8?q?=E6=B5=8B=E5=8F=82=E6=95=B0=EF=BC=8C=E6=9B=BF=E6=8D=A2=E4=B8=BA?= =?UTF-8?q?=E6=A3=80=E6=B5=8B=E5=AE=B9=E5=B7=AE=EF=BC=9B=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E9=85=8D=E7=BD=AE=E5=92=8CUI=E6=98=BE?= =?UTF-8?q?=E7=A4=BA=EF=BC=8C=E7=A1=AE=E4=BF=9D=E4=B8=80=E8=87=B4=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- default_config.toml | 4 +- doc/working/2017/步进式动画方案.md | 2 +- .../GenerateCollisionReportCommand.cs | 4 +- src/Core/Animation/PathAnimationManager.cs | 161 ++++++++++++------ src/Core/BatchQueueManager.cs | 91 ++++++---- src/Core/BatchTaskManager.cs | 2 +- src/Core/Collision/BatchCollisionExecutor.cs | 19 ++- src/Core/Collision/BatchCollisionProcessor.cs | 6 +- .../Collision/ClashDetectiveIntegration.cs | 66 +++---- .../Collision/IBatchCollisionProcessor.cs | 4 +- src/Core/Config/ConfigManager.cs | 16 +- src/Core/Config/SystemConfig.cs | 81 ++++++++- src/Core/Models/BatchQueueItem.cs | 2 +- src/Core/Models/CollisionDetectionConfig.cs | 32 ++-- src/Core/PathDatabase.cs | 16 +- src/Core/VirtualVehicleManager.cs | 5 +- .../Converters/BatchQueueStatusConverter.cs | 2 +- .../ViewModels/AnimationControlViewModel.cs | 120 +++++-------- .../BatchTaskManagementViewModel.cs | 30 +++- .../ViewModels/CollisionReportViewModel.cs | 18 +- src/UI/WPF/ViewModels/PathEditingViewModel.cs | 17 +- src/UI/WPF/Views/AnimationControlView.xaml | 4 +- src/UI/WPF/Views/PathConfigDialog.xaml.cs | 4 +- src/Utils/CoordinateConverter.cs | 6 +- 24 files changed, 434 insertions(+), 278 deletions(-) diff --git a/default_config.toml b/default_config.toml index 37cd13a..1bbb85d 100644 --- a/default_config.toml +++ b/default_config.toml @@ -37,8 +37,8 @@ frame_rate = 30 # 动画持续时间(秒) duration_seconds = 10.0 -# 检测间隙(米) -detection_gap_meters = 0.05 +# 检测容差(米)- 用于ClashDetective精确检测 +detection_tolerance_meters = 0.05 # 空间索引格子大小(米) spatial_index_cell_size = 1.0 diff --git a/doc/working/2017/步进式动画方案.md b/doc/working/2017/步进式动画方案.md index b277b1d..e0508c4 100644 --- a/doc/working/2017/步进式动画方案.md +++ b/doc/working/2017/步进式动画方案.md @@ -76,7 +76,7 @@ │ │ │ // 执行碰撞检测 │ │ var collisions = ClashDetectiveIntegration.Instance.DetectCollisions( │ - │ _animatedObject, null, _detectionGap); │ + │ _animatedObject, null, _detectionTolerance:F4); │ │ │ │ // 创建帧数据 │ │ var frame = new AnimationFrame │ diff --git a/src/Commands/GenerateCollisionReportCommand.cs b/src/Commands/GenerateCollisionReportCommand.cs index 29b5f29..0035ab3 100644 --- a/src/Commands/GenerateCollisionReportCommand.cs +++ b/src/Commands/GenerateCollisionReportCommand.cs @@ -85,7 +85,7 @@ namespace NavisworksTransport.Commands public string PathName { get; set; } public int FrameRate { get; set; } public double Duration { get; set; } - public double DetectionGap { get; set; } + public double DetectionTolerance { get; set; } // 新增:截图信息 public string ScreenshotPath { get; set; } @@ -163,7 +163,7 @@ namespace NavisworksTransport.Commands { result.FrameRate = animationManager.AnimationFrameRate; result.Duration = animationManager.AnimationDuration; - result.DetectionGap = animationManager.DetectionGap; + result.DetectionTolerance = animationManager.DetectionTolerance; // PathName需要从动画管理器获取 result.PathName = animationManager.PathName ?? "未知路径"; } diff --git a/src/Core/Animation/PathAnimationManager.cs b/src/Core/Animation/PathAnimationManager.cs index d9799cb..308d1cd 100644 --- a/src/Core/Animation/PathAnimationManager.cs +++ b/src/Core/Animation/PathAnimationManager.cs @@ -131,8 +131,8 @@ namespace NavisworksTransport.Core.Animation private int _animationFrameRate; // 动画帧率(默认30FPS) private double _collisionDetectionAccuracy; // 检测精度(内部存储:模型单位/帧) private double _movementSpeed; // 运动速度(仅用于显示,单位:米/秒) - private double _detectionGap; // 检测间隙(内部存储:模型单位) - private double _precomputedDetectionGap; // 预计算时使用的扩大检测间隙(内部存储:模型单位) + private double _detectionTolerance; // 检测容差(米,从UI设置) + private double _safetyMargin; // 安全间隙(模型单位,从CreateAnimation传入) private string _pathName; // 路径名称 private string _currentRouteId; // 当前路由ID @@ -185,11 +185,7 @@ namespace NavisworksTransport.Core.Animation var config = ConfigManager.Instance.Current; _animationFrameRate = config.Animation.FrameRate; _animationDuration = config.Animation.DurationSeconds; - - var detectionGapMeters = config.Animation.DetectionGapMeters; - _detectionGap = UnitsConverter.ConvertFromMeters(detectionGapMeters); - _precomputedDetectionGap = _detectionGap; - + // 初始化动画模式 _frameInterval = 1000.0 / _animationFrameRate; // 计算帧间隔 _lastFrameTime = DateTime.MinValue; @@ -260,29 +256,53 @@ namespace NavisworksTransport.Core.Animation try { var doc = NavisApplication.ActiveDocument; - if (doc == null || _animatedObject == null) return; + if (doc == null) return; - var modelItems = new ModelItemCollection { _animatedObject }; + // 🔥 支持虚拟车辆的恢复 + ModelItem objectToRestore = null; + bool isVirtual = _isVirtualVehicle; + + if (isVirtual) + { + objectToRestore = VirtualVehicleManager.Instance.CurrentVirtualVehicle; + if (objectToRestore == null) + { + LogManager.Warning("[归位] 虚拟车辆未激活,跳过恢复"); + return; + } + } + else + { + objectToRestore = _animatedObject; + if (objectToRestore == null) + { + LogManager.Warning("[归位] 没有动画对象,跳过恢复"); + return; + } + } + + var modelItems = new ModelItemCollection { objectToRestore }; // 1. 彻底清除 Navisworks 中的所有覆盖变换,强制恢复到设计文件定义的原始状态 doc.Models.ResetPermanentTransform(modelItems); - // 2. 重置内部跟踪变量(同步到 CAD 原始状态) - // 注意:ResetPermanentTransform 后物体的 Transform 属性会自动变回 CAD 原始值 - _currentYaw = ModelItemTransformHelper.GetYawFromTransform(_animatedObject.Transform); + // 2. 重置内部跟踪变量(同步到原始状态) + // 注意:ResetPermanentTransform 后物体的 Transform 属性会自动变回原始值 + _currentYaw = ModelItemTransformHelper.GetYawFromTransform(objectToRestore.Transform); - var originalBoundingBox = _animatedObject.BoundingBox(); + var originalBoundingBox = objectToRestore.BoundingBox(); _currentPosition = new Point3D( originalBoundingBox.Center.X, originalBoundingBox.Center.Y, originalBoundingBox.Min.Z ); - LogManager.Info($"[归位] 物体 {_animatedObject.DisplayName} 已彻底恢复到 CAD 原始位置, yaw={_currentYaw:F3}"); + string objectName = isVirtual ? "虚拟车辆" : objectToRestore.DisplayName; + LogManager.Info($"[归位] {objectName} 已彻底恢复到原始位置, yaw={_currentYaw:F3}"); } catch (Exception ex) { - LogManager.Error($"[归位] 恢复物体到 CAD 位置失败: {ex.Message}"); + LogManager.Error($"[归位] 恢复物体到原始位置失败: {ex.Message}"); } } @@ -320,11 +340,23 @@ namespace NavisworksTransport.Core.Animation /// /// 设置动画参数(批处理专用) /// - public void SetAnimationParameters(int frameRate, double duration, double detectionGap) + public void SetAnimationParameters(int frameRate, double duration, double detectionTolerance) { _animationFrameRate = frameRate; _animationDuration = duration; - _precomputedDetectionGap = detectionGap; + // 注意:预计算使用安全间隙,不使用检测容差 + } + + /// + /// 检测容差(米)- 用于ClashDetective精确检测 + /// + public double DetectionTolerance + { + get + { + var config = ConfigManager.Instance.Current; + return config.Animation.DetectionToleranceMeters; + } } /// @@ -431,6 +463,14 @@ namespace NavisworksTransport.Core.Animation { try { + // 🔥 重要:先恢复物体到原始状态(CAD位置和原始朝向),确保每次计算都从相同的状态开始 + // 这样可以避免之前旋转导致的包围盒尺寸计算不准确的问题 + if (_animatedObject != null) + { + RestoreObjectToCADPosition(); + LogManager.Info($"[移动到起点] 已恢复物体到原始状态"); + } + // 如果提供了参数,更新内部状态 if (animatedObject != null) { @@ -523,6 +563,28 @@ namespace NavisworksTransport.Core.Animation } LogManager.Info($"物体已初始化到路径起点并对齐朝向: pos=({startPosition.X:F2},{startPosition.Y:F2},{startPosition.Z:F2}), yaw={yaw:F3}rad, 路径类型={pathTypeName}"); + + // 打印实际物体的位置和方向 + if (_animatedObject != null) + { + var bbox = _animatedObject.BoundingBox(); + var actualCenter = bbox.Center; + var actualYaw = ModelItemTransformHelper.GetYawFromTransform(_animatedObject.Transform); + LogManager.Info($"实际物体位置: X={actualCenter.X:F2}, Y={actualCenter.Y:F2}, Z={actualCenter.Z:F2}"); + LogManager.Info($"实际物体朝向: {actualYaw * 180 / Math.PI:F2}度"); + } + else if (_isVirtualVehicle) + { + var virtualVehicle = VirtualVehicleManager.Instance.CurrentVirtualVehicle; + if (virtualVehicle != null) + { + var bbox = virtualVehicle.BoundingBox(); + var actualCenter = bbox.Center; + var actualYaw = ModelItemTransformHelper.GetYawFromTransform(virtualVehicle.Transform); + LogManager.Info($"虚拟车辆位置: X={actualCenter.X:F2}, Y={actualCenter.Y:F2}, Z={actualCenter.Z:F2}"); + LogManager.Info($"虚拟车辆朝向: {actualYaw * 180 / Math.PI:F2}度"); + } + } } catch (Exception ex) { @@ -539,6 +601,14 @@ namespace NavisworksTransport.Core.Animation { LogManager.Info("=== 使用路径预计算动画帧 ==="); + // 🔥 重要:预计算前先将物体移动到起点位置 + if (_animatedObject != null && _route != null && _route.Points != null && _route.Points.Count > 0) + { + var pathPoints = _route.Points.Select(p => p.Position).ToList(); + MoveVehicleToPathStart(_animatedObject, pathPoints); + LogManager.Info("[预计算] 物体已移动到路径起点"); + } + int totalFrames = (int)(_animationDuration * _animationFrameRate); // 🔥 判断路径类型:空中路径使用Points,地面路径使用Edges @@ -620,6 +690,9 @@ namespace NavisworksTransport.Core.Animation var manualTargetsSnapshot = new List(); bool manualOverrideActive = _manualCollisionOverrideEnabled && _manualCollisionTargets != null && _manualCollisionTargets.Count > 0; + // 获取配置 + var config = ConfigManager.Instance.Current; + if (manualOverrideActive) { manualTargetsSnapshot = _manualCollisionTargets @@ -647,8 +720,8 @@ namespace NavisworksTransport.Core.Animation spatialIndexManager = SpatialIndexManager.Instance; - // 使用动画专用的空间索引格子大小配置 - double cellSizeInModelUnits = UnitsConverter.ConvertFromMeters(ConfigManager.Instance.Current.Animation.SpatialIndexCellSize); + // 使用动画专用的空间索引格子大小配置 - 使用模型单位接口 + double cellSizeInModelUnits = config.Animation.SpatialIndexCellSize; LogManager.Info($"[空间索引] 格子大小: {cellSizeInModelUnits:F2}模型单位 (动画配置)"); @@ -672,8 +745,9 @@ namespace NavisworksTransport.Core.Animation // 原因:车辆在通道上水平移动,主要检测侧面碰撞 double maxHorizontalDimension = Math.Max(boundingBoxSize.X, boundingBoxSize.Y); - searchRadiusInModelUnits = maxHorizontalDimension + _precomputedDetectionGap; - LogManager.Info($"空间查询半径: {searchRadiusInModelUnits:F2} 模型单位 (基于最大水平尺寸: {maxHorizontalDimension:F2})"); + // 🔥 使用安全间隙计算空间查询半径 - _safetyMargin 已是模型单位 + searchRadiusInModelUnits = maxHorizontalDimension + _safetyMargin; + LogManager.Info($"空间查询半径: {searchRadiusInModelUnits:F2} 模型单位 (基于最大水平尺寸: {maxHorizontalDimension:F2}, 安全间隙: {_safetyMargin:F4}模型单位)"); } // 3. 生成每一帧 @@ -857,11 +931,12 @@ namespace NavisworksTransport.Core.Animation // 使用包围盒距离检测方法 double distance = BoundingBoxGeometryUtils.CalculateDistance(virtualBoundingBox, colliderBox); - bool intersects = distance <= _precomputedDetectionGap; + var safetyMarginInModelUnits = UnitsConverter.ConvertFromMeters(_safetyMargin); + bool intersects = distance <= safetyMarginInModelUnits; if (intersects) { - LogManager.Debug($"帧 {i} 检测到碰撞: {_animatedObject.DisplayName} <-> {collider.DisplayName}, 距离: {distance:F4},阈值: {_precomputedDetectionGap:F4}"); + LogManager.Debug($"帧 {i} 检测到碰撞: {_animatedObject.DisplayName} <-> {collider.DisplayName}, 距离: {distance:F4},阈值: {safetyMarginInModelUnits:F4}"); LogManager.Debug($"移动物体位置: {framePosition.X:F2},{framePosition.Y:F2},{framePosition.Z:F2}"); LogManager.Debug($"被撞物体位置:{GetObjectPosition(collider).X:F2},{GetObjectPosition(collider).Y:F2},{GetObjectPosition(collider).Z:F2}"); @@ -1454,9 +1529,10 @@ namespace NavisworksTransport.Core.Animation try { + // 🔥 使用用户设置的检测容差(米) ClashDetectiveIntegration.Instance.CreateAllAnimationCollisionTests( _allCollisionResults, - _detectionGap, + _detectionTolerance, _pathName, _currentRouteId, _animatedObject, @@ -1465,7 +1541,8 @@ namespace NavisworksTransport.Core.Animation _animationDuration, _virtualVehicleLength, _virtualVehicleWidth, - _virtualVehicleHeight + _virtualVehicleHeight, + _pathPoints ); } finally @@ -2390,23 +2467,12 @@ namespace NavisworksTransport.Core.Animation } /// - /// 设置检测间隙(参数单位:米) + /// 设置检测容差(参数单位:米) /// - public void SetDetectionGap(double gapInMeters) + public void SetDetectionTolerance(double toleranceInMeters) { - // 转换为模型单位存储 - var gapInModelUnits = UnitsConverter.ConvertFromMeters(Math.Max(0.0, gapInMeters)); - var roundedGapInModelUnits = Math.Round(gapInModelUnits, 4); // 模型单位保留更多精度 - - // 只在值真正改变时才更新和记录日志 - if (Math.Abs(_detectionGap - roundedGapInModelUnits) > 0.0001) - { - _detectionGap = roundedGapInModelUnits; - LogManager.Info($"检测间隙设置为: {gapInMeters:F2}米"); - - // 预计算检测间隙与检测间隙相同 - _precomputedDetectionGap = _detectionGap; - } + _detectionTolerance = Math.Max(0.0, toleranceInMeters); + LogManager.Info($"检测容差设置为: {_detectionTolerance:F2}米(仅用于ClashDetective)"); } /// @@ -2476,9 +2542,7 @@ namespace NavisworksTransport.Core.Animation { get { - // 将内部模型单位转换为米制单位 - var modelUnitsToMeters = UnitsConverter.GetUnitsToMetersConversionFactor(); - return _detectionGap * modelUnitsToMeters; + return _detectionTolerance; } } @@ -2514,14 +2578,15 @@ namespace NavisworksTransport.Core.Animation /// 路径名称 /// 路由ID public void CreateAnimation(ModelItem animatedObject, List pathPoints, double durationSeconds = 10.0, string pathName = "未知路径", string routeId = null, bool isVirtualVehicle = false, - double virtualVehicleLength = 0, double virtualVehicleWidth = 0, double virtualVehicleHeight = 0) + double virtualVehicleLength = 0, double virtualVehicleWidth = 0, double virtualVehicleHeight = 0, double safetyMargin = 0) { _pathName = pathName; _currentRouteId = routeId; _isVirtualVehicle = isVirtualVehicle; // 设置是否使用虚拟车辆 - _virtualVehicleLength = virtualVehicleLength; - _virtualVehicleWidth = virtualVehicleWidth; - _virtualVehicleHeight = virtualVehicleHeight; + _virtualVehicleLength = virtualVehicleLength; // 模型单位 + _virtualVehicleWidth = virtualVehicleWidth; // 模型单位 + _virtualVehicleHeight = virtualVehicleHeight; // 模型单位 + _safetyMargin = safetyMargin; // 模型单位 _pathPoints = pathPoints; _animatedObject = animatedObject; @@ -2824,7 +2889,7 @@ namespace NavisworksTransport.Core.Animation // 包含动画参数(确保参数改变时重新检测) sb.Append($"Duration:{_animationDuration:F2}s"); sb.Append($"|FrameRate:{_animationFrameRate}"); - sb.Append($"|DetectionGap:{_detectionGap:F4}"); + sb.Append($"|DetectionTolerance:{_detectionTolerance:F4}"); sb.Append("|"); // 包含虚拟车辆尺寸(确保车辆尺寸改变时重新检测) diff --git a/src/Core/BatchQueueManager.cs b/src/Core/BatchQueueManager.cs index a9a837e..a0b8279 100644 --- a/src/Core/BatchQueueManager.cs +++ b/src/Core/BatchQueueManager.cs @@ -202,6 +202,13 @@ namespace NavisworksTransport.Core { animatedObject = FindModelItemById(item.VehicleObjectId); isVirtualVehicle = false; + + if (animatedObject == null) + { + throw new InvalidOperationException("未找到指定的运动物体"); + } + + LogManager.Info($"[批处理] 使用真实物体: {animatedObject.DisplayName}"); } else if (isVirtualVehicle) { @@ -230,23 +237,19 @@ namespace NavisworksTransport.Core // 在主线程执行Navisworks API调用 var frames = await UIStateManager.Instance.ExecuteUIUpdateAsync(() => { - // 🔥 重要:预计算前必须将车辆移动到起点位置,确保变换状态与实际动画播放时一致 - var animationManager = PathAnimationManager.GetInstance(); - animationManager.MoveVehicleToPathStart(animatedObject, pathRoute.Points.Select(p => p.Position).ToList()); - // 预计算动画帧和碰撞 var config = new CollisionDetectionConfig { FrameRate = item.FrameRate, DurationSeconds = item.DurationSeconds, - DetectionGapMeters = item.DetectionGapMeters, + DetectionToleranceMeters = item.DetectionToleranceMeters, VirtualVehicleLength = item.VirtualVehicleLength, VirtualVehicleWidth = item.VirtualVehicleWidth, VirtualVehicleHeight = item.VirtualVehicleHeight, CollisionDetectionEnabled = true, ReportGenerationEnabled = true }; - + return _executor._processor.PrecomputeFrames( pathRoute, animatedObject, @@ -256,7 +259,7 @@ namespace NavisworksTransport.Core config.VirtualVehicleHeight, config.FrameRate, config.DurationSeconds, - config.DetectionGapMeters, + config.DetectionToleranceMeters, null ); }); @@ -268,34 +271,62 @@ namespace NavisworksTransport.Core } // 提取碰撞结果 - var collisions = frames.SelectMany(f => f.Collisions).ToList(); - - // 创建并运行ClashDetective测试(直接在主线程执行,避免异步切换导致的Navisworks Native对象生命周期问题) - var testName = _executor._processor.CreateAndRunClashDetectiveTest( - collisions, - item.DetectionGapMeters, - pathRoute.Name, - pathRoute.Id, - animatedObject, - isVirtualVehicle, - item.FrameRate, - item.DurationSeconds, - item.VirtualVehicleLength, - item.VirtualVehicleWidth, - item.VirtualVehicleHeight - ); - - // 🔥 使用 ClashDetective 确认的碰撞数,而不是预计算的碰撞数 - item.CollisionCount = ClashDetectiveIntegration.Instance.ClashDetectiveCollisionCount; - - // 保存测试名称 - item.ClashDetectiveTestName = testName; + var collisions = frames.SelectMany(f => f.Collisions).ToList(); + + + + // 创建并运行ClashDetective测试(直接在主线程执行,避免异步切换导致的Navisworks Native对象生命周期问题) + + // 传入 pathPoints 参数,让 ClashDetective 测试完成后自动恢复到路径起点 + + var pathPoints = pathRoute.Points.Select(p => p.Position).ToList(); + + var testName = _executor._processor.CreateAndRunClashDetectiveTest( + + collisions, + + item.DetectionToleranceMeters, + + pathRoute.Name, + + pathRoute.Id, + + animatedObject, + + isVirtualVehicle, + + item.FrameRate, + + item.DurationSeconds, + + item.VirtualVehicleLength, + + item.VirtualVehicleWidth, + + item.VirtualVehicleHeight, + + pathPoints + + ); + + + + // 🔥 使用 ClashDetective 确认的碰撞数,而不是预计算的碰撞数 + + item.CollisionCount = ClashDetectiveIntegration.Instance.ClashDetectiveCollisionCount; + + + + // 保存测试名称 + + item.ClashDetectiveTestName = testName; + // 标记为完成 item.Status = BatchQueueStatus.Completed; item.EndTime = DateTime.Now; await _database.UpdateBatchQueueItemAsync(item); - + LogManager.Info($"[批处理队列] 队列项执行完成: {item.PathRouteName}, 碰撞数: {item.CollisionCount}"); } catch (Exception ex) diff --git a/src/Core/BatchTaskManager.cs b/src/Core/BatchTaskManager.cs index 4fa631c..2da2805 100644 --- a/src/Core/BatchTaskManager.cs +++ b/src/Core/BatchTaskManager.cs @@ -232,7 +232,7 @@ namespace NavisworksTransport.Core var systemConfig = ConfigManager.Instance.Current; return new CollisionDetectionConfig { - DetectionGapMeters = systemConfig.Animation.DetectionGapMeters, + DetectionToleranceMeters = systemConfig.Animation.DetectionToleranceMeters, FrameRate = systemConfig.Animation.FrameRate, DurationSeconds = systemConfig.Animation.DurationSeconds }; diff --git a/src/Core/Collision/BatchCollisionExecutor.cs b/src/Core/Collision/BatchCollisionExecutor.cs index 70511ad..56dc3e7 100644 --- a/src/Core/Collision/BatchCollisionExecutor.cs +++ b/src/Core/Collision/BatchCollisionExecutor.cs @@ -7,6 +7,8 @@ using Autodesk.Navisworks.Api; using NavisworksTransport.Core.Models; using NavisworksTransport.Utils; using NavisworksTransport.Core.Config; +using NavisworksTransport.Core.Animation; +using NavisworksTransport.Core; namespace NavisworksTransport.Core.Collision { @@ -148,12 +150,12 @@ namespace NavisworksTransport.Core.Collision pathRoute, animatedObject, isVirtualVehicle, - config.DetectionGapMeters, // 虚拟车辆尺寸从配置获取 - config.DetectionGapMeters, - config.DetectionGapMeters, + config.VirtualVehicleLength, + config.VirtualVehicleWidth, + config.VirtualVehicleHeight, config.FrameRate, config.DurationSeconds, - config.DetectionGapMeters, + config.DetectionToleranceMeters, null // 暂不支持手动检测项 ); @@ -165,9 +167,11 @@ namespace NavisworksTransport.Core.Collision } // 创建并运行ClashDetective测试(纯计算,无UI操作) + // 传入 pathPoints 参数,让 ClashDetective 测试完成后自动恢复到路径起点 + var pathPoints = pathRoute.Points.Select(p => p.Position).ToList(); var testName = _processor.CreateAndRunClashDetectiveTest( allCollisions, - config.DetectionGapMeters, + config.DetectionToleranceMeters, pathRoute.Name, pathRoute.Id, animatedObject, @@ -176,7 +180,8 @@ namespace NavisworksTransport.Core.Collision config.DurationSeconds, config.VirtualVehicleLength, config.VirtualVehicleWidth, - config.VirtualVehicleHeight + config.VirtualVehicleHeight, + pathPoints ); // 保存测试名称到任务项 @@ -262,7 +267,7 @@ namespace NavisworksTransport.Core.Collision var systemConfig = ConfigManager.Instance.Current; return new CollisionDetectionConfig { - DetectionGapMeters = systemConfig.Animation.DetectionGapMeters, + DetectionToleranceMeters = systemConfig.Animation.DetectionToleranceMeters, FrameRate = systemConfig.Animation.FrameRate, DurationSeconds = systemConfig.Animation.DurationSeconds, VirtualVehicleLength = systemConfig.PathEditing.VehicleLengthMeters, diff --git a/src/Core/Collision/BatchCollisionProcessor.cs b/src/Core/Collision/BatchCollisionProcessor.cs index c1af851..caa5ee9 100644 --- a/src/Core/Collision/BatchCollisionProcessor.cs +++ b/src/Core/Collision/BatchCollisionProcessor.cs @@ -80,7 +80,8 @@ namespace NavisworksTransport.Core.Collision double duration, double virtualVehicleLength, double virtualVehicleWidth, - double virtualVehicleHeight) + double virtualVehicleHeight, + List pathPoints = null) { try { @@ -98,7 +99,8 @@ namespace NavisworksTransport.Core.Collision duration, virtualVehicleLength, virtualVehicleWidth, - virtualVehicleHeight + virtualVehicleHeight, + pathPoints ); LogManager.Info($"[批处理] ClashDetective测试创建完成 - 测试名称: {testName}"); diff --git a/src/Core/Collision/ClashDetectiveIntegration.cs b/src/Core/Collision/ClashDetectiveIntegration.cs index cd6fa3a..c018fa5 100644 --- a/src/Core/Collision/ClashDetectiveIntegration.cs +++ b/src/Core/Collision/ClashDetectiveIntegration.cs @@ -4,6 +4,7 @@ using System.Linq; using Autodesk.Navisworks.Api; using Autodesk.Navisworks.Api.Clash; using NavisworksTransport.Core; +using NavisworksTransport.Core.Animation; using NavisworksTransport.Utils; namespace NavisworksTransport @@ -755,6 +756,7 @@ namespace NavisworksTransport /// 虚拟车辆长度(米) /// 虚拟车辆宽度(米) /// 虚拟车辆高度(米) + /// 路径点列表(用于测试完成后恢复物体位置) public void CreateAllAnimationCollisionTests( List precomputedCollisions, double detectionGap, @@ -766,7 +768,8 @@ namespace NavisworksTransport double duration, double virtualVehicleLength, double virtualVehicleWidth, - double virtualVehicleHeight) + double virtualVehicleHeight, + List pathPoints = null) { try { @@ -795,24 +798,10 @@ namespace NavisworksTransport _animationCollisionCount = collisionResults.Count; LogManager.Info($"[预计算处理] 原始记录: {precomputedCollisions.Count},有效碰撞: {_animationCollisionCount}"); - // 获取动画对象和当前动画终点位置(用于后续恢复) - Point3D animationEndPosition = new Point3D(0, 0, 0); - + // 获取动画对象 if (collisionResults.Count > 0) { animatedObject = collisionResults[0].Item1; - - // 记录当前位置(应该是动画终点) - if (animatedObject != null && IsModelItemValid(animatedObject)) - { - var bounds = animatedObject.BoundingBox(); - animationEndPosition = new Point3D( - (bounds.Min.X + bounds.Max.X) / 2, - (bounds.Min.Y + bounds.Max.Y) / 2, - (bounds.Min.Z + bounds.Max.Z) / 2 - ); - LogManager.Info($"记录动画终点位置: ({animationEndPosition.X:F2},{animationEndPosition.Y:F2},{animationEndPosition.Z:F2})"); - } } var doc = Application.ActiveDocument; @@ -858,35 +847,17 @@ namespace NavisworksTransport LogManager.Warning("[分组测试] 分组为空(未检测到真实几何碰撞),未添加到主测试"); } - // 碰撞测试完成后,将物体恢复到动画终点位置 - if (animatedObject != null && IsModelItemValid(animatedObject)) + // 碰撞测试完成后,将物体恢复到路径起点位置(如果提供了路径点) + if (animatedObject != null && IsModelItemValid(animatedObject) && pathPoints != null && pathPoints.Count > 0) { try { - var modelItems = new ModelItemCollection { animatedObject }; - - // 计算当前位置到动画终点的偏移 - var currentBounds = animatedObject.BoundingBox(); - var currentPos = new Point3D( - (currentBounds.Min.X + currentBounds.Max.X) / 2, - (currentBounds.Min.Y + currentBounds.Max.Y) / 2, - (currentBounds.Min.Z + currentBounds.Max.Z) / 2 - ); - - var restoreOffset = new Vector3D( - animationEndPosition.X - currentPos.X, - animationEndPosition.Y - currentPos.Y, - animationEndPosition.Z - currentPos.Z - ); - - var restoreTransform = Transform3D.CreateTranslation(restoreOffset); - doc.Models.OverridePermanentTransform(modelItems, restoreTransform, false); - - LogManager.Info($"已将 {animatedObject.DisplayName} 恢复到动画终点位置: ({animationEndPosition.X:F2},{animationEndPosition.Y:F2},{animationEndPosition.Z:F2})"); + PathAnimationManager.GetInstance().MoveVehicleToPathStart(animatedObject, pathPoints); + LogManager.Info($"已将 {animatedObject.DisplayName} 恢复到路径起点位置"); } catch (Exception restoreEx) { - LogManager.Error($"恢复物体到动画终点失败: {restoreEx.Message}"); + LogManager.Error($"恢复物体到路径起点失败: {restoreEx.Message}"); } } @@ -1555,7 +1526,8 @@ namespace NavisworksTransport double duration, double virtualVehicleLength, double virtualVehicleWidth, - double virtualVehicleHeight) + double virtualVehicleHeight, + List pathPoints = null) { try { @@ -1615,6 +1587,20 @@ namespace NavisworksTransport LogManager.Warning("[批处理] 分组为空(未检测到真实几何碰撞),未添加到主测试"); } + // 碰撞测试完成后,将物体恢复到路径起点位置(如果提供了路径点) + if (animatedObject != null && IsModelItemValid(animatedObject) && pathPoints != null && pathPoints.Count > 0) + { + try + { + PathAnimationManager.GetInstance().MoveVehicleToPathStart(animatedObject, pathPoints); + LogManager.Info($"[批处理] 已将 {animatedObject.DisplayName} 恢复到路径起点位置"); + } + catch (Exception restoreEx) + { + LogManager.Error($"[批处理] 恢复物体到路径起点失败: {restoreEx.Message}"); + } + } + return addedMainTest?.DisplayName; } catch (Exception ex) diff --git a/src/Core/Collision/IBatchCollisionProcessor.cs b/src/Core/Collision/IBatchCollisionProcessor.cs index 9142561..5eab884 100644 --- a/src/Core/Collision/IBatchCollisionProcessor.cs +++ b/src/Core/Collision/IBatchCollisionProcessor.cs @@ -53,6 +53,7 @@ namespace NavisworksTransport.Core.Collision /// 虚拟车辆长度(米) /// 虚拟车辆宽度(米) /// 虚拟车辆高度(米) + /// 路径点列表(用于测试完成后恢复物体位置) /// ClashDetective测试名称 string CreateAndRunClashDetectiveTest( List precomputedCollisions, @@ -65,6 +66,7 @@ namespace NavisworksTransport.Core.Collision double duration, double virtualVehicleLength, double virtualVehicleWidth, - double virtualVehicleHeight); + double virtualVehicleHeight, + List pathPoints = null); } } \ No newline at end of file diff --git a/src/Core/Config/ConfigManager.cs b/src/Core/Config/ConfigManager.cs index 4e9ffd5..1f5aab0 100644 --- a/src/Core/Config/ConfigManager.cs +++ b/src/Core/Config/ConfigManager.cs @@ -166,8 +166,8 @@ namespace NavisworksTransport.Core.Config config.PathEditing.VehicleWidthMeters = GetRequiredDoubleValue(pathEdit, "vehicle_width_meters"); config.PathEditing.VehicleHeightMeters = GetRequiredDoubleValue(pathEdit, "vehicle_height_meters"); config.PathEditing.SafetyMarginMeters = GetRequiredDoubleValue(pathEdit, "safety_margin_meters"); - config.PathEditing.DefaultPathTurnRadius = GetRequiredDoubleValue(pathEdit, "default_path_turn_radius"); - config.PathEditing.ArcSamplingStep = GetRequiredDoubleValue(pathEdit, "arc_sampling_step"); + config.PathEditing.DefaultPathTurnRadiusMeters = GetRequiredDoubleValue(pathEdit, "default_path_turn_radius"); + config.PathEditing.ArcSamplingStepMeters = GetRequiredDoubleValue(pathEdit, "arc_sampling_step"); // 加载可视化配置 if (!model.ContainsKey("visualization")) @@ -197,8 +197,8 @@ namespace NavisworksTransport.Core.Config config.Animation.FrameRate = GetRequiredIntValue(anim, "frame_rate"); config.Animation.DurationSeconds = GetRequiredDoubleValue(anim, "duration_seconds"); - config.Animation.DetectionGapMeters = GetRequiredDoubleValue(anim, "detection_gap_meters"); - config.Animation.SpatialIndexCellSize = GetRequiredDoubleValue(anim, "spatial_index_cell_size"); + config.Animation.DetectionToleranceMeters = GetRequiredDoubleValue(anim, "detection_tolerance_meters"); + config.Animation.SpatialIndexCellSizeMeters = GetRequiredDoubleValue(anim, "spatial_index_cell_size"); // 加载物流属性配置 if (!model.ContainsKey("logistics")) @@ -321,8 +321,8 @@ namespace NavisworksTransport.Core.Config pathEdit["vehicle_width_meters"] = config.PathEditing.VehicleWidthMeters; pathEdit["vehicle_height_meters"] = config.PathEditing.VehicleHeightMeters; pathEdit["safety_margin_meters"] = config.PathEditing.SafetyMarginMeters; - pathEdit["default_path_turn_radius"] = config.PathEditing.DefaultPathTurnRadius; - pathEdit["arc_sampling_step"] = config.PathEditing.ArcSamplingStep; + pathEdit["default_path_turn_radius"] = config.PathEditing.DefaultPathTurnRadiusMeters; + pathEdit["arc_sampling_step"] = config.PathEditing.ArcSamplingStepMeters; } } @@ -344,8 +344,8 @@ namespace NavisworksTransport.Core.Config { anim["frame_rate"] = config.Animation.FrameRate; anim["duration_seconds"] = config.Animation.DurationSeconds; - anim["detection_gap_meters"] = config.Animation.DetectionGapMeters; - anim["spatial_index_cell_size"] = config.Animation.SpatialIndexCellSize; + anim["detection_tolerance_meters"] = config.Animation.DetectionToleranceMeters; + anim["spatial_index_cell_size"] = config.Animation.SpatialIndexCellSizeMeters; } } diff --git a/src/Core/Config/SystemConfig.cs b/src/Core/Config/SystemConfig.cs index 3ca1803..259e324 100644 --- a/src/Core/Config/SystemConfig.cs +++ b/src/Core/Config/SystemConfig.cs @@ -89,12 +89,54 @@ namespace NavisworksTransport.Core.Config /// /// 路径默认转弯半径(米) /// - public double DefaultPathTurnRadius { get; set; } + public double DefaultPathTurnRadiusMeters { get; set; } /// /// 圆弧采样步长(米) /// - public double ArcSamplingStep { get; set; } + public double ArcSamplingStepMeters { get; set; } + + // === 模型单位接口(用于内部计算) === + + /// + /// 网格单元大小(模型单位) + /// + public double CellSize => CellSizeMeters * Utils.UnitsConverter.GetMetersToUnitsConversionFactor(); + + /// + /// 最大高度差(模型单位) + /// + public double MaxHeightDiff => MaxHeightDiffMeters * Utils.UnitsConverter.GetMetersToUnitsConversionFactor(); + + /// + /// 车辆长度(模型单位) + /// + public double VehicleLength => VehicleLengthMeters * Utils.UnitsConverter.GetMetersToUnitsConversionFactor(); + + /// + /// 车辆宽度(模型单位) + /// + public double VehicleWidth => VehicleWidthMeters * Utils.UnitsConverter.GetMetersToUnitsConversionFactor(); + + /// + /// 车辆高度(模型单位) + /// + public double VehicleHeight => VehicleHeightMeters * Utils.UnitsConverter.GetMetersToUnitsConversionFactor(); + + /// + /// 安全间隙(模型单位) + /// + public double SafetyMargin => SafetyMarginMeters * Utils.UnitsConverter.GetMetersToUnitsConversionFactor(); + + /// + /// 路径默认转弯半径(模型单位) + /// + public double DefaultPathTurnRadius => DefaultPathTurnRadiusMeters * Utils.UnitsConverter.GetMetersToUnitsConversionFactor(); + + /// + /// 圆弧采样步长(模型单位) + /// + public double ArcSamplingStep => ArcSamplingStepMeters * Utils.UnitsConverter.GetMetersToUnitsConversionFactor(); } /// @@ -124,14 +166,26 @@ namespace NavisworksTransport.Core.Config public double DurationSeconds { get; set; } /// - /// 检测间隙(米) + /// 检测容差(米)- 用于ClashDetective精确检测 /// - public double DetectionGapMeters { get; set; } + public double DetectionToleranceMeters { get; set; } /// /// 空间索引格子大小(米)- 用于动画碰撞检测的空间索引 /// - public double SpatialIndexCellSize { get; set; } + public double SpatialIndexCellSizeMeters { get; set; } + + // === 模型单位接口(用于内部计算) === + + /// + /// 检测容差(模型单位)- 用于ClashDetective精确检测 + /// + public double DetectionTolerance => DetectionToleranceMeters * Utils.UnitsConverter.GetMetersToUnitsConversionFactor(); + + /// + /// 空间索引格子大小(模型单位)- 用于动画碰撞检测的空间索引 + /// + public double SpatialIndexCellSize => SpatialIndexCellSizeMeters * Utils.UnitsConverter.GetMetersToUnitsConversionFactor(); } /// @@ -163,5 +217,22 @@ namespace NavisworksTransport.Core.Config /// 宽度限制(米) /// public double WidthLimitMeters { get; set; } + + // === 模型单位接口(用于内部计算) === + + /// + /// 高度限制(模型单位) + /// + public double HeightLimit => HeightLimitMeters * Utils.UnitsConverter.GetMetersToUnitsConversionFactor(); + + /// + /// 速度限制(模型单位/秒) + /// + public double SpeedLimit => SpeedLimitMetersPerSecond * Utils.UnitsConverter.GetMetersToUnitsConversionFactor(); + + /// + /// 宽度限制(模型单位) + /// + public double WidthLimit => WidthLimitMeters * Utils.UnitsConverter.GetMetersToUnitsConversionFactor(); } } diff --git a/src/Core/Models/BatchQueueItem.cs b/src/Core/Models/BatchQueueItem.cs index b1506f2..4cffe99 100644 --- a/src/Core/Models/BatchQueueItem.cs +++ b/src/Core/Models/BatchQueueItem.cs @@ -22,7 +22,7 @@ namespace NavisworksTransport.Core.Models public double DurationSeconds { get; set; } // 碰撞检测配置 - public double DetectionGapMeters { get; set; } + public double DetectionToleranceMeters { get; set; } // 运动物体配置 public bool IsVirtualVehicle { get; set; } diff --git a/src/Core/Models/CollisionDetectionConfig.cs b/src/Core/Models/CollisionDetectionConfig.cs index 6e35263..2d52e31 100644 --- a/src/Core/Models/CollisionDetectionConfig.cs +++ b/src/Core/Models/CollisionDetectionConfig.cs @@ -5,23 +5,23 @@ namespace NavisworksTransport.Core.Models /// public class CollisionDetectionConfig { - public double DetectionGapMeters { get; set; } = 0.05; - public int FrameRate { get; set; } = 30; - public double DurationSeconds { get; set; } = 10.0; - public bool CollisionDetectionEnabled { get; set; } = true; - public bool ReportGenerationEnabled { get; set; } = true; + public double DetectionToleranceMeters { get; set; } + public int FrameRate { get; set; } + public double DurationSeconds { get; set; } + public bool CollisionDetectionEnabled { get; set; } + public bool ReportGenerationEnabled { get; set; } // 虚拟车辆参数 - public double VirtualVehicleLength { get; set; } = 1.0; - public double VirtualVehicleWidth { get; set; } = 1.0; - public double VirtualVehicleHeight { get; set; } = 2.0; + public double VirtualVehicleLength { get; set; } + public double VirtualVehicleWidth { get; set; } + public double VirtualVehicleHeight { get; set; } /// /// 序列化为JSON字符串(简化版) /// public string ToJson() { - return $"{{\"DetectionGapMeters\":{DetectionGapMeters},\"FrameRate\":{FrameRate},\"DurationSeconds\":{DurationSeconds},\"CollisionDetectionEnabled\":{CollisionDetectionEnabled.ToString().ToLower()},\"ReportGenerationEnabled\":{ReportGenerationEnabled.ToString().ToLower()}}}"; + return $"{{\"DetectionToleranceMeters\":{DetectionToleranceMeters},\"FrameRate\":{FrameRate},\"DurationSeconds\":{DurationSeconds},\"CollisionDetectionEnabled\":{CollisionDetectionEnabled.ToString().ToLower()},\"ReportGenerationEnabled\":{ReportGenerationEnabled.ToString().ToLower()}}}"; } /// @@ -48,9 +48,9 @@ namespace NavisworksTransport.Core.Models switch (key) { - case "DetectionGapMeters": - if (double.TryParse(value, out var detectionGap)) - config.DetectionGapMeters = detectionGap; + case "DetectionToleranceMeters": + if (double.TryParse(value, out var detectionTolerance)) + config.DetectionToleranceMeters = detectionTolerance; break; case "FrameRate": if (int.TryParse(value, out var frameRate)) @@ -88,11 +88,11 @@ namespace NavisworksTransport.Core.Models if (overrideConfig == null) return this; return new CollisionDetectionConfig { - DetectionGapMeters = overrideConfig.DetectionGapMeters > 0 - ? overrideConfig.DetectionGapMeters : DetectionGapMeters, - FrameRate = overrideConfig.FrameRate > 0 + DetectionToleranceMeters = overrideConfig.DetectionToleranceMeters > 0 + ? overrideConfig.DetectionToleranceMeters : DetectionToleranceMeters, + FrameRate = overrideConfig.FrameRate > 0 ? overrideConfig.FrameRate : FrameRate, - DurationSeconds = overrideConfig.DurationSeconds > 0 + DurationSeconds = overrideConfig.DurationSeconds > 0 ? overrideConfig.DurationSeconds : DurationSeconds, CollisionDetectionEnabled = overrideConfig.CollisionDetectionEnabled, ReportGenerationEnabled = overrideConfig.ReportGenerationEnabled diff --git a/src/Core/PathDatabase.cs b/src/Core/PathDatabase.cs index 23d15b4..cdcfdc3 100644 --- a/src/Core/PathDatabase.cs +++ b/src/Core/PathDatabase.cs @@ -225,7 +225,7 @@ namespace NavisworksTransport ErrorMessage TEXT, FrameRate INTEGER NOT NULL, DurationSeconds REAL NOT NULL, - DetectionGapMeters REAL NOT NULL, + DetectionToleranceMeters REAL NOT NULL, IsVirtualVehicle INTEGER NOT NULL, VirtualVehicleLength REAL, VirtualVehicleWidth REAL, @@ -1598,14 +1598,14 @@ namespace NavisworksTransport cmd.CommandText = @" INSERT INTO BatchQueueItems ( PathRouteId, PathRouteName, Status, CreatedTime, StartTime, EndTime, ErrorMessage, - FrameRate, DurationSeconds, DetectionGapMeters, + FrameRate, DurationSeconds, DetectionToleranceMeters, IsVirtualVehicle, VirtualVehicleLength, VirtualVehicleWidth, VirtualVehicleHeight, VehicleObjectId, VehicleObjectName, DetectionItems, DetectAllObjects, ClashDetectiveTestName, CollisionCount ) VALUES ( @PathRouteId, @PathRouteName, @Status, @CreatedTime, @StartTime, @EndTime, @ErrorMessage, - @FrameRate, @DurationSeconds, @DetectionGapMeters, + @FrameRate, @DurationSeconds, @DetectionToleranceMeters, @IsVirtualVehicle, @VirtualVehicleLength, @VirtualVehicleWidth, @VirtualVehicleHeight, @VehicleObjectId, @VehicleObjectName, @DetectionItems, @DetectAllObjects, @ClashDetectiveTestName, @CollisionCount @@ -1621,7 +1621,7 @@ namespace NavisworksTransport cmd.Parameters.AddWithValue("@ErrorMessage", item.ErrorMessage ?? ""); cmd.Parameters.AddWithValue("@FrameRate", item.FrameRate); cmd.Parameters.AddWithValue("@DurationSeconds", item.DurationSeconds); - cmd.Parameters.AddWithValue("@DetectionGapMeters", item.DetectionGapMeters); + cmd.Parameters.AddWithValue("@DetectionToleranceMeters", item.DetectionToleranceMeters); cmd.Parameters.AddWithValue("@IsVirtualVehicle", item.IsVirtualVehicle ? 1 : 0); cmd.Parameters.AddWithValue("@VirtualVehicleLength", item.VirtualVehicleLength); cmd.Parameters.AddWithValue("@VirtualVehicleWidth", item.VirtualVehicleWidth); @@ -1649,7 +1649,7 @@ namespace NavisworksTransport { cmd.CommandText = @" SELECT Id, PathRouteId, PathRouteName, Status, CreatedTime, StartTime, EndTime, ErrorMessage, - FrameRate, DurationSeconds, DetectionGapMeters, + FrameRate, DurationSeconds, DetectionToleranceMeters, IsVirtualVehicle, VirtualVehicleLength, VirtualVehicleWidth, VirtualVehicleHeight, VehicleObjectId, VehicleObjectName, DetectionItems, DetectAllObjects, ClashDetectiveTestName, CollisionCount @@ -1674,7 +1674,7 @@ namespace NavisworksTransport ErrorMessage = reader["ErrorMessage"].ToString(), FrameRate = Convert.ToInt32(reader["FrameRate"]), DurationSeconds = Convert.ToDouble(reader["DurationSeconds"]), - DetectionGapMeters = Convert.ToDouble(reader["DetectionGapMeters"]), + DetectionToleranceMeters = Convert.ToDouble(reader["DetectionToleranceMeters"]), IsVirtualVehicle = Convert.ToBoolean(reader["IsVirtualVehicle"]), VirtualVehicleLength = Convert.ToDouble(reader["VirtualVehicleLength"]), VirtualVehicleWidth = Convert.ToDouble(reader["VirtualVehicleWidth"]), @@ -1705,7 +1705,7 @@ namespace NavisworksTransport { var sql = @" SELECT Id, PathRouteId, PathRouteName, Status, CreatedTime, StartTime, EndTime, ErrorMessage, - FrameRate, DurationSeconds, DetectionGapMeters, + FrameRate, DurationSeconds, DetectionToleranceMeters, IsVirtualVehicle, VirtualVehicleLength, VirtualVehicleWidth, VirtualVehicleHeight, VehicleObjectId, VehicleObjectName, DetectionItems, DetectAllObjects, ClashDetectiveTestName, CollisionCount @@ -1755,7 +1755,7 @@ namespace NavisworksTransport ErrorMessage = reader["ErrorMessage"].ToString(), FrameRate = Convert.ToInt32(reader["FrameRate"]), DurationSeconds = Convert.ToDouble(reader["DurationSeconds"]), - DetectionGapMeters = Convert.ToDouble(reader["DetectionGapMeters"]), + DetectionToleranceMeters = Convert.ToDouble(reader["DetectionToleranceMeters"]), IsVirtualVehicle = Convert.ToBoolean(reader["IsVirtualVehicle"]), VirtualVehicleLength = Convert.ToDouble(reader["VirtualVehicleLength"]), VirtualVehicleWidth = Convert.ToDouble(reader["VirtualVehicleWidth"]), diff --git a/src/Core/VirtualVehicleManager.cs b/src/Core/VirtualVehicleManager.cs index d770780..665aebd 100644 --- a/src/Core/VirtualVehicleManager.cs +++ b/src/Core/VirtualVehicleManager.cs @@ -218,9 +218,10 @@ namespace NavisworksTransport.Core } /// - /// 重置虚拟车辆变换为单位矩阵 + /// + /// 重置虚拟车辆变换为单位矩阵(公开方法,供批处理使用) /// - private void ResetVirtualVehicleTransform() + public void ResetVirtualVehicleTransform() { if (_virtualVehicleModel == null) return; diff --git a/src/UI/WPF/Converters/BatchQueueStatusConverter.cs b/src/UI/WPF/Converters/BatchQueueStatusConverter.cs index 53a129a..7b84b46 100644 --- a/src/UI/WPF/Converters/BatchQueueStatusConverter.cs +++ b/src/UI/WPF/Converters/BatchQueueStatusConverter.cs @@ -30,7 +30,7 @@ namespace NavisworksTransport.UI.WPF.Converters return "未知"; } } - return "待处理"; + return "全部"; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) diff --git a/src/UI/WPF/ViewModels/AnimationControlViewModel.cs b/src/UI/WPF/ViewModels/AnimationControlViewModel.cs index f5abd91..6a352fa 100644 --- a/src/UI/WPF/ViewModels/AnimationControlViewModel.cs +++ b/src/UI/WPF/ViewModels/AnimationControlViewModel.cs @@ -215,7 +215,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels private CollisionReportResult _lastGeneratedReport; // 缓存最后生成的报告 // 碰撞检测参数字段(从配置初始化) - private double _detectionGap; // 检测间隙(米) + private double _detectionTolerance; // 检测容差(米) private int _animationFrameRate; // 动画帧率(FPS) @@ -236,12 +236,12 @@ namespace NavisworksTransport.UI.WPF.ViewModels private double _safetyMargin; // 检测间隙(米),从路径编辑同步 // 角度修正相关字段 - private double _objectRotationCorrection = 0.0; // 物体角度修正值(度,顺时针) + private double _objectRotationCorrection; // 物体角度修正值(度,顺时针) // 移动物体原始尺寸(米,在选择物体时保存) - private double _objectOriginalLength = 0.0; // 物体原始长度(X方向) - private double _objectOriginalWidth = 0.0; // 物体原始宽度(Y方向) - private double _objectOriginalHeight = 0.0; // 物体原始高度(Z方向) + private double _objectOriginalLength; // 物体原始长度(X方向) + private double _objectOriginalWidth; // 物体原始宽度(Y方向) + private double _objectOriginalHeight; // 物体原始高度(Z方向) // 手工碰撞对象相关字段 private bool _isManualCollisionTargetEnabled = false; @@ -411,20 +411,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels } } - /// - /// 检测间隙(米) - /// - public double DetectionGap - { - get => _detectionGap; - set - { - // 限制精度到2位小数 - var roundedValue = Math.Round(value, 2); - SetProperty(ref _detectionGap, roundedValue); - } - } - /// /// 动画帧率(FPS) /// @@ -546,18 +532,11 @@ namespace NavisworksTransport.UI.WPF.ViewModels LogManager.Info("已切换到虚拟车辆模式,将之前的手动选择物体归位并清理动画数据"); } - // 显示虚拟车辆,并同步到起点 - LogManager.Info("正在显示虚拟车辆到起点..."); + // 显示虚拟车辆 + LogManager.Info("正在显示虚拟车辆..."); VirtualVehicleManager.Instance.ShowVirtualVehicle( VirtualVehicleLength, VirtualVehicleWidth, VirtualVehicleHeight); - 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?.MoveVehicleToPathStart(vModel, points); - } - // 重置角度修正值(虚拟车辆重新选择时重置) ObjectRotationCorrection = 0.0; LogManager.Debug($"[切换虚拟车辆] 已重置角度修正值为0度"); @@ -620,15 +599,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels private set => SetProperty(ref _virtualVehicleHeight, value); } - /// - /// 检测间隙(米)- 只读,从路径编辑同步 - /// - public double SafetyMargin - { - get => _safetyMargin; - private set => SetProperty(ref _safetyMargin, value); - } - /// /// 物体角度修正值(度,顺时针) /// @@ -647,16 +617,17 @@ namespace NavisworksTransport.UI.WPF.ViewModels /// /// 设置虚拟车辆参数(由主ViewModel调用) - /// 参数单位:模型单位 + /// 参数单位:米 /// public void SetVirtualVehicleParameters(double length, double width, double height, double safetyMargin) { + LogManager.Info($"[AnimationControlViewModel] SetVirtualVehicleParameters被调用: length={length:F4}, width={width:F4}, height={height:F4}, safetyMargin={safetyMargin:F4}"); VirtualVehicleLength = length; VirtualVehicleWidth = width; VirtualVehicleHeight = height; - SafetyMargin = safetyMargin; + _safetyMargin = safetyMargin; - LogManager.Info($"[AnimationControlViewModel] 虚拟车辆参数已更新: {length:F1}模型单位 × {width:F1}模型单位 × {height:F1}模型单位, 检测间隙: {safetyMargin:F2}模型单位"); + LogManager.Info($"[AnimationControlViewModel] 虚拟车辆参数已更新: {length:F1}米 × {width:F1}米 × {height:F1}米, 检测间隙: {safetyMargin:F2}米, _safetyMargin={_safetyMargin:F4}"); // 如果当前使用虚拟车辆模式,更新生成动画的可用状态 if (UseVirtualVehicle) @@ -935,22 +906,22 @@ namespace NavisworksTransport.UI.WPF.ViewModels HasClashDetectiveResults = false; UpdateMainStatus("碰撞检测就绪"); - // 获取单位转换系数 - double metersToModelUnits = UnitsConverter.GetMetersToUnitsConversionFactor(); - - // 从配置读取碰撞检测参数(转换为模型单位) - DetectionGap = config.Animation.DetectionGapMeters * metersToModelUnits; - AnimationFrameRate = config.Animation.FrameRate; - - // 🔥 从配置加载虚拟车辆尺寸(与路径编辑保持一致,转换为模型单位) - VirtualVehicleLength = config.PathEditing.VehicleLengthMeters * metersToModelUnits; - VirtualVehicleWidth = config.PathEditing.VehicleWidthMeters * metersToModelUnits; - VirtualVehicleHeight = config.PathEditing.VehicleHeightMeters * metersToModelUnits; - - // 设置动画按钮的初始状态 - UpdateAnimationButtonStates(); - - LogManager.Info($"动画设置初始化完成 - 帧率:{SelectedFrameRate}fps, 持续时间:{AnimationDuration}秒, 检测间隙:{DetectionGap}模型单位"); } + // 从配置读取安全间隙(用于预计算)- 使用米单位接口 + _safetyMargin = config.PathEditing.SafetyMarginMeters; + AnimationFrameRate = config.Animation.FrameRate; + + // 从配置读取检测容差(用于ClashDetective)- 使用米单位接口用于显示 + _detectionTolerance = config.Animation.DetectionToleranceMeters; + + // 🔥 从配置加载虚拟车辆尺寸(与路径编辑保持一致,使用米单位接口) + VirtualVehicleLength = config.PathEditing.VehicleLengthMeters; + VirtualVehicleWidth = config.PathEditing.VehicleWidthMeters; + VirtualVehicleHeight = config.PathEditing.VehicleHeightMeters; + + // 设置动画按钮的初始状态 + UpdateAnimationButtonStates(); + + LogManager.Info($"动画设置初始化完成 - 帧率:{SelectedFrameRate}fps, 持续时间:{AnimationDuration}秒, 安全间隙:{_safetyMargin}米"); } /// /// 初始化命令 @@ -1378,13 +1349,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels { LogManager.Debug($"[选择物体] 保持当前角度修正值(同一物体)"); } - - // 3. 立即移动到起点(如果路径存在) - if (CurrentPathRoute != null && CurrentPathRoute.Points != null && _pathAnimationManager != null) - { - var points = CurrentPathRoute.Points.Select(p => new Point3D(p.X, p.Y, p.Z)).ToList(); - _pathAnimationManager.MoveVehicleToPathStart(newObject, points); - } } catch (Exception ex) { @@ -1747,7 +1711,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels reportResult.UniqueCollidedObjectsCount, reportResult.FrameRate, reportResult.Duration, - reportResult.DetectionGap, + reportResult.DetectionTolerance, reportResult.AnimationCollisions, reportResult.TotalCollisions ); @@ -2453,6 +2417,10 @@ namespace NavisworksTransport.UI.WPF.ViewModels if (!UseVirtualVehicle) { UpdateMainStatus("正在分析动画对象...", -1, true); + + // 🔥 设置检测容差(安全间隙通过CreateAnimation传入) + _pathAnimationManager.SetDetectionTolerance(_detectionTolerance); + var success = _pathAnimationManager.PrecomputeCollisionExclusions(SelectedAnimatedObject); if (!success) @@ -2483,7 +2451,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels _pathAnimationManager.SetAnimationFrameRate(_animationFrameRate); _pathAnimationManager.SetCollisionDetectionAccuracy(CollisionDetectionAccuracy); _pathAnimationManager.SetMovementSpeed(MovementSpeed); - _pathAnimationManager.SetDetectionGap(_detectionGap); + _pathAnimationManager.SetDetectionTolerance(_detectionTolerance); // 将PathRouteViewModel的点转换为Point3D列表 var pathPoints = CurrentPathRoute.Points.Select(p => new Point3D(p.X, p.Y, p.Z)).ToList(); @@ -2558,15 +2526,17 @@ namespace NavisworksTransport.UI.WPF.ViewModels // 先设置路径到动画管理器 _pathAnimationManager.SetRoute(pathRoute); - // 准备车辆尺寸参数 - double vLength = UseVirtualVehicle ? VirtualVehicleLength : 0; - double vWidth = UseVirtualVehicle ? VirtualVehicleWidth : 0; - double vHeight = UseVirtualVehicle ? VirtualVehicleHeight : 0; + // 准备车辆尺寸参数(从米转换为模型单位) + var metersToModelUnits = Utils.UnitsConverter.GetMetersToUnitsConversionFactor(); + double vLength = UseVirtualVehicle ? VirtualVehicleLength * metersToModelUnits : 0; + double vWidth = UseVirtualVehicle ? VirtualVehicleWidth * metersToModelUnits : 0; + double vHeight = UseVirtualVehicle ? VirtualVehicleHeight * metersToModelUnits : 0; + double safetyMargin = _safetyMargin * metersToModelUnits; - LogManager.Info($"[ExecuteGenerateAnimation] 准备调用CreateAnimation: UseVirtualVehicle={UseVirtualVehicle}, 车辆尺寸: {vLength:F2}×{vWidth:F2}×{vHeight:F2}m"); + LogManager.Info($"[ExecuteGenerateAnimation] 准备调用CreateAnimation: UseVirtualVehicle={UseVirtualVehicle}, 车辆尺寸: {vLength:F2}×{vWidth:F2}×{vHeight:F2}模型单位, 安全间隙: {safetyMargin:F4}模型单位 (_safetyMargin={_safetyMargin:F4}米)"); _pathAnimationManager.CreateAnimation(animatedObject, pathPoints, AnimationDuration, CurrentPathRoute.Name, CurrentPathRoute.Id, UseVirtualVehicle, - vLength, vWidth, vHeight); + vLength, vWidth, vHeight, safetyMargin); var totalElapsed = (DateTime.Now - cacheStartTime).TotalMilliseconds; LogManager.Info($"[动画生成] 动画生成完成,总耗时: {totalElapsed:F1}ms"); @@ -2692,7 +2662,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels double passageNormalToPathVertical, passageNormalToPathHorizontal; // 使用从路径编辑同步过来的检测间隙 - double safetyMargin = SafetyMargin; + double safetyMargin = _safetyMargin; if (UseVirtualVehicle) { @@ -3505,10 +3475,10 @@ namespace NavisworksTransport.UI.WPF.ViewModels // 动画配置 FrameRate = _animationFrameRate, DurationSeconds = AnimationDuration, - + // 碰撞检测配置 - DetectionGapMeters = _detectionGap, - + DetectionToleranceMeters = _detectionTolerance, + // 运动物体配置 IsVirtualVehicle = UseVirtualVehicle, VirtualVehicleLength = VirtualVehicleLength, diff --git a/src/UI/WPF/ViewModels/BatchTaskManagementViewModel.cs b/src/UI/WPF/ViewModels/BatchTaskManagementViewModel.cs index 902d938..50dc6bb 100644 --- a/src/UI/WPF/ViewModels/BatchTaskManagementViewModel.cs +++ b/src/UI/WPF/ViewModels/BatchTaskManagementViewModel.cs @@ -169,12 +169,19 @@ namespace NavisworksTransport.UI.WPF.ViewModels // 订阅队列管理器事件 if (_queueManager != null) { + _queueManager.ItemAdded += OnItemAdded; _queueManager.ItemStarted += OnItemStarted; _queueManager.ItemCompleted += OnItemCompleted; _queueManager.ItemProgress += OnItemProgress; } - // 加载队列列表 + // 订阅路径规划管理器事件(用于在数据库初始化后重新加载队列列表) + if (_pathPlanningManager != null) + { + _pathPlanningManager.RoutesLoaded += OnRoutesLoaded; + } + + // 尝试加载队列列表(如果数据库已初始化) _ = LoadQueueItemsAsync(); LogManager.Info("[BatchQueueManagement] PathPlanningManager已设置"); @@ -203,7 +210,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels var database = GetDatabase(); if (database == null) { - LogManager.Warning("[BatchQueueManagement] Database未初始化"); return; } @@ -218,6 +224,8 @@ namespace NavisworksTransport.UI.WPF.ViewModels // 按创建时间倒序 items = items.OrderByDescending(item => item.CreatedTime).ToList(); + LogManager.Info($"[BatchQueueManagement] 加载队列列表完成,共 {items.Count} 项"); + await _uiStateManager.ExecuteUIUpdateAsync(() => { QueueItems.Clear(); @@ -343,6 +351,24 @@ namespace NavisworksTransport.UI.WPF.ViewModels #region 事件处理 + private async void OnRoutesLoaded(object sender, RoutesLoadedEventArgs e) + { + // 数据库初始化完成,重新加载队列列表 + await _uiStateManager.ExecuteUIUpdateAsync(async () => + { + await LoadQueueItemsAsync(); + }); + } + + private async void OnItemAdded(object sender, BatchQueueItemEventArgs e) + { + // 自动刷新列表 + await _uiStateManager.ExecuteUIUpdateAsync(async () => + { + await LoadQueueItemsAsync(); + }); + } + private async void OnItemStarted(object sender, BatchQueueItemEventArgs e) { await _uiStateManager.ExecuteUIUpdateAsync(() => diff --git a/src/UI/WPF/ViewModels/CollisionReportViewModel.cs b/src/UI/WPF/ViewModels/CollisionReportViewModel.cs index 962a597..d6f0136 100644 --- a/src/UI/WPF/ViewModels/CollisionReportViewModel.cs +++ b/src/UI/WPF/ViewModels/CollisionReportViewModel.cs @@ -81,7 +81,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels private string _pathName; private int _frameRate; private double _duration; - private double _detectionGap; + private double _detectionTolerance; private CollisionReportResult _currentReport; #endregion @@ -234,12 +234,12 @@ namespace NavisworksTransport.UI.WPF.ViewModels } /// - /// 检测间隙 + /// 检测容差 /// - public double DetectionGap + public double DetectionTolerance { - get => _detectionGap; - set => SetProperty(ref _detectionGap, value); + get => _detectionTolerance; + set => SetProperty(ref _detectionTolerance, value); } /// @@ -378,7 +378,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels PathName = reportResult.PathName; FrameRate = reportResult.FrameRate; Duration = reportResult.Duration; - DetectionGap = reportResult.DetectionGap; + DetectionTolerance = reportResult.DetectionTolerance; // 更新统计信息 UpdateStatistics(reportResult); @@ -680,7 +680,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels report.AppendLine("=== 动画参数 ==="); report.AppendLine($"帧率: {FrameRate} FPS"); report.AppendLine($"时长: {Duration:F1} 秒"); - report.AppendLine($"检测间隙: {DetectionGap:F2} 米"); + report.AppendLine($"检测容差: {DetectionTolerance:F2} 米"); report.AppendLine(); // 运动构件信息 @@ -826,8 +826,8 @@ namespace NavisworksTransport.UI.WPF.ViewModels html.AppendLine($"
{Duration:F1} 秒
"); html.AppendLine(""); html.AppendLine("
"); - html.AppendLine("
检测间隙
"); - html.AppendLine($"
{DetectionGap:F2} 米
"); + html.AppendLine("
检测容差
"); + html.AppendLine($"
{DetectionTolerance:F2} 米
"); html.AppendLine("
"); html.AppendLine(""); diff --git a/src/UI/WPF/ViewModels/PathEditingViewModel.cs b/src/UI/WPF/ViewModels/PathEditingViewModel.cs index 6b4d984..8d52b76 100644 --- a/src/UI/WPF/ViewModels/PathEditingViewModel.cs +++ b/src/UI/WPF/ViewModels/PathEditingViewModel.cs @@ -788,17 +788,14 @@ namespace NavisworksTransport.UI.WPF.ViewModels { var config = ConfigManager.Instance.Current; - // 获取单位转换系数 - double metersToModelUnits = UnitsConverter.GetMetersToUnitsConversionFactor(); + // 从 PathEditing 配置加载所有参数(使用米单位接口) + _gridSize = config.PathEditing.CellSizeMeters; + _vehicleLength = config.PathEditing.VehicleLengthMeters; + _vehicleWidth = config.PathEditing.VehicleWidthMeters; + _vehicleHeight = config.PathEditing.VehicleHeightMeters; + _safetyMargin = config.PathEditing.SafetyMarginMeters; - // 从 PathEditing 配置加载所有参数(转换为模型单位) - _gridSize = config.PathEditing.CellSizeMeters * metersToModelUnits; - _vehicleLength = config.PathEditing.VehicleLengthMeters * metersToModelUnits; - _vehicleWidth = config.PathEditing.VehicleWidthMeters * metersToModelUnits; - _vehicleHeight = config.PathEditing.VehicleHeightMeters * metersToModelUnits; - _safetyMargin = config.PathEditing.SafetyMarginMeters * metersToModelUnits; - - LogManager.Info($"从配置加载参数 - 车辆: {_vehicleLength:F1}x{_vehicleWidth:F1}x{_vehicleHeight:F1}模型单位, 安全间隙: {_safetyMargin:F2}模型单位, 网格: {_gridSize:F1}模型单位"); + LogManager.Info($"从配置加载参数 - 车辆: {_vehicleLength:F1}x{_vehicleWidth:F1}x{_vehicleHeight:F1}米, 安全间隙: {_safetyMargin:F2}米, 网格: {_gridSize:F1}米"); } catch (Exception ex) { diff --git a/src/UI/WPF/Views/AnimationControlView.xaml b/src/UI/WPF/Views/AnimationControlView.xaml index af107b1..ac35e68 100644 --- a/src/UI/WPF/Views/AnimationControlView.xaml +++ b/src/UI/WPF/Views/AnimationControlView.xaml @@ -91,9 +91,9 @@ NavisworksTransport 检测动画页签视图 - 采用与类别设置和分层管 - + -