From 3905db56bc75fbce289ac365161a1fde6c9abb1d Mon Sep 17 00:00:00 2001 From: tian <11429339@qq.com> Date: Fri, 23 Jan 2026 18:40:54 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84=E7=A2=B0=E6=92=9E=E6=8A=A5?= =?UTF-8?q?=E5=91=8A=E7=94=9F=E6=88=90=E9=80=BB=E8=BE=91=EF=BC=8C=E6=97=A0?= =?UTF-8?q?=E7=A2=B0=E6=92=9E=E4=B9=9F=E7=94=9F=E6=88=90=E6=8A=A5=E5=91=8A?= =?UTF-8?q?=EF=BC=9B=E4=BF=AE=E6=94=B9=E9=80=9A=E8=A1=8C=E7=A9=BA=E9=97=B4?= =?UTF-8?q?=E4=B8=BA=E6=B5=85=E7=BB=BF=E8=89=B2=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../GenerateCollisionReportCommand.cs | 106 ++-------------- src/Core/Animation/PathAnimationManager.cs | 5 + .../Collision/ClashDetectiveIntegration.cs | 65 ++++++++-- src/Core/PathPointRenderPlugin.cs | 3 +- .../ViewModels/AnimationControlViewModel.cs | 118 +++++++++++------- 5 files changed, 145 insertions(+), 152 deletions(-) diff --git a/src/Commands/GenerateCollisionReportCommand.cs b/src/Commands/GenerateCollisionReportCommand.cs index 8b42bf1..29b5f29 100644 --- a/src/Commands/GenerateCollisionReportCommand.cs +++ b/src/Commands/GenerateCollisionReportCommand.cs @@ -99,20 +99,6 @@ namespace NavisworksTransport.Commands /// public class GenerateCollisionReportCommand : CommandBase { - #region 静态缓存机制 - - /// - /// 碰撞报告结果缓存 - 使用测试名称作为键 - /// - private static readonly Dictionary _reportCache = new Dictionary(); - - /// - /// 缓存操作锁对象 - /// - private static readonly object _cacheLock = new object(); - - #endregion - private readonly CollisionReportParameters _parameters; private string _specificTestName = null; // 指定的测试名称(用于历史报告) @@ -152,31 +138,6 @@ namespace NavisworksTransport.Commands return PathPlanningResult.Failure("无法确定测试名称,请先运行碰撞检测或选择历史记录"); } - // 检查缓存 - lock (_cacheLock) - { - if (_reportCache.ContainsKey(targetTestName)) - { - var cachedResult = _reportCache[targetTestName]; - LogManager.Info($"使用缓存的碰撞报告: {targetTestName}"); - - UpdateProgress(100, "使用缓存报告"); - - // 显示缓存的报告 - ShowReport(cachedResult); - - var cachedMessage = cachedResult.TotalCollisions > 0 ? - $"碰撞报告显示完成(缓存):发现 {cachedResult.TotalCollisions} 个碰撞" : - "碰撞报告显示完成(缓存):未发现碰撞"; - - return PathPlanningResult.Success(cachedResult, cachedMessage); - } - else - { - LogManager.Debug($"缓存中未找到测试: {targetTestName}"); - } - } - var result = new CollisionReportResult(); try @@ -266,13 +227,6 @@ namespace NavisworksTransport.Commands // 显示报告(UI线程) ShowReport(result); - - // 将报告结果缓存起来 - lock (_cacheLock) - { - _reportCache[targetTestName] = result; - LogManager.Info($"碰撞报告已缓存: {targetTestName}, 缓存总数: {_reportCache.Count}"); - } } catch (OperationCanceledException) { @@ -293,56 +247,7 @@ namespace NavisworksTransport.Commands return PathPlanningResult.Success(result, message); } - #region 缓存相关方法 - - /// - /// 从缓存获取报告 - /// - public static CollisionReportResult GetReportFromCache(string testName) - { - if (string.IsNullOrEmpty(testName)) - return null; - - lock (_cacheLock) - { - if (_reportCache.ContainsKey(testName)) - { - LogManager.Info($"从缓存获取报告: {testName}"); - return _reportCache[testName]; - } - } - return null; - } - - /// - /// 缓存报告 - /// - public static void CacheReport(string testName, CollisionReportResult reportResult) - { - if (string.IsNullOrEmpty(testName) || reportResult == null) - return; - - lock (_cacheLock) - { - _reportCache[testName] = reportResult; - LogManager.Info($"报告已缓存: {testName}, 缓存总数: {_reportCache.Count}"); - } - } - - /// - /// 清理过期缓存(可选功能) - /// - public static void ClearReportCache() - { - lock (_cacheLock) - { - var count = _reportCache.Count; - _reportCache.Clear(); - LogManager.Info($"已清理碰撞报告缓存,共清理 {count} 个缓存项"); - } - } - - #endregion + /// /// 收集所有碰撞数据及统计信息 @@ -379,7 +284,14 @@ namespace NavisworksTransport.Commands if (testCollisionsRaw == null || testCollisionsRaw.Count == 0) { - throw new InvalidOperationException($"未找到测试 '{targetTestName}' 的ClashDetective碰撞结果"); + LogManager.Info($"测试 '{targetTestName}' 没有碰撞结果,返回空数据"); + result.AllCollisions = allCollisions; + result.ClashDetectiveCollisionCount = 0; + result.AnimationCollisions = 0; + result.UniqueCollidedObjects = new HashSet(); + result.BoundingBoxTestCount = 0; + result.MovingObjectInfo = "无碰撞"; + return result; } LogManager.Info($"从缓存获取ClashDetective结果: {testCollisionsRaw.Count}个碰撞,测试名称:{targetTestName}"); diff --git a/src/Core/Animation/PathAnimationManager.cs b/src/Core/Animation/PathAnimationManager.cs index 590aea9..f854b47 100644 --- a/src/Core/Animation/PathAnimationManager.cs +++ b/src/Core/Animation/PathAnimationManager.cs @@ -2398,6 +2398,11 @@ namespace NavisworksTransport.Core.Animation /// public int AnimationFrameRate => _animationFrameRate; + /// + /// 获取所有碰撞结果(不去重) + /// + public List AllCollisionResults => _allCollisionResults; + /// /// 获取当前碰撞检测精度 /// diff --git a/src/Core/Collision/ClashDetectiveIntegration.cs b/src/Core/Collision/ClashDetectiveIntegration.cs index c688ff3..b1ad333 100644 --- a/src/Core/Collision/ClashDetectiveIntegration.cs +++ b/src/Core/Collision/ClashDetectiveIntegration.cs @@ -905,15 +905,15 @@ namespace NavisworksTransport LogManager.Info($"=== 碰撞统计最终结果 ==="); LogManager.Info($"动画过程包围盒检测: {_animationCollisionCount}个碰撞 (参考值)"); LogManager.Info($"Clash Detective权威结果: {_clashDetectiveCollisionCount}个碰撞 (权威数据)"); - - // 触发碰撞检测完成事件,通知生成报告 - // 使用ClashDetective权威结果,而不是预计算结果 - // 如果权威结果为0个碰撞,传入空列表以触发祝贺对话框 - var finalCollisions = _clashDetectiveCollisionCount > 0 ? validCollisions : new List(); - LogManager.Info($"触发CollisionDetected事件,通知生成报告({_clashDetectiveCollisionCount}个碰撞,权威数据)"); - var eventArgs = new CollisionDetectedEventArgs(finalCollisions); - OnCollisionDetected(eventArgs); } + + // 🔥 无论是否有主测试,都触发碰撞检测完成事件,通知生成报告 + // 使用ClashDetective权威结果,而不是预计算结果 + // 如果权威结果为0个碰撞,传入空列表以触发祝贺对话框 + var finalCollisions = _clashDetectiveCollisionCount > 0 ? validCollisions : new List(); + LogManager.Info($"触发CollisionDetected事件,通知生成报告({_clashDetectiveCollisionCount}个碰撞,权威数据)"); + var eventArgs = new CollisionDetectedEventArgs(finalCollisions); + OnCollisionDetected(eventArgs); } catch (Exception ex) { @@ -1013,7 +1013,7 @@ namespace NavisworksTransport /// 获取当前路径的Clash结果 /// /// 路径名称 - /// 当前路径的碰撞结果列表 + /// 当前路径的碰撞结果列表(如果没有结果返回空列表) public List GetCurrentPathClashResults(string testName) { lock (_clashResultsCacheLock) @@ -1036,9 +1036,11 @@ namespace NavisworksTransport LogManager.Info($"[ClashDetective结果] 已从数据库加载 '{testName}' 的结果并缓存:{loadedResults.Count}个碰撞"); return loadedResults; } + + // 没有找到结果,返回空列表 + LogManager.Info($"[ClashDetective结果] 未找到测试 '{testName}' 的碰撞结果,返回空列表"); + return new List(); } - - throw new InvalidOperationException($"未找到测试 '{testName}' 的ClashDetective结果(缓存和数据库中都没有)"); } /// @@ -1050,6 +1052,47 @@ namespace NavisworksTransport return GetCurrentPathClashResults(_currentTestName); } + /// + /// 清理当前测试的缓存 + /// + public void ClearCurrentTestCache() + { + if (string.IsNullOrEmpty(_currentTestName)) + { + return; + } + + lock (_clashResultsCacheLock) + { + if (_clashDetectiveResultsCache.ContainsKey(_currentTestName)) + { + _clashDetectiveResultsCache.Remove(_currentTestName); + LogManager.Info($"[ClashDetective缓存] 已清理当前测试 '{_currentTestName}' 的缓存"); + } + } + } + + /// + /// 清空当前测试名称 + /// + public void ClearCurrentTestName() + { + if (!string.IsNullOrEmpty(_currentTestName)) + { + LogManager.Info($"[ClashDetective] 清空当前测试名称: {_currentTestName}"); + _currentTestName = null; + } + } + + /// + /// 设置当前测试名称 + /// + public void SetCurrentTestName(string testName) + { + _currentTestName = testName; + LogManager.Info($"[ClashDetective] 设置当前测试名称: {_currentTestName}"); + } + /// /// 从测试中提取碰撞结果 /// diff --git a/src/Core/PathPointRenderPlugin.cs b/src/Core/PathPointRenderPlugin.cs index 959393a..273171b 100644 --- a/src/Core/PathPointRenderPlugin.cs +++ b/src/Core/PathPointRenderPlugin.cs @@ -2094,8 +2094,7 @@ namespace NavisworksTransport return new RenderStyle(Color.FromByteRGB(255, 152, 0), 0.8); // Material Orange连线,20%透明 case RenderStyleName.VehicleSpace: - return new RenderStyle(Color.FromByteRGB(158, 158, 158), 0.4); // Material Grey车辆空间,60%透明 - + return new RenderStyle(Color.FromByteRGB(129, 199, 132), 0.4); // Material Light Green通行空间,60%透明 case RenderStyleName.PreviewPoint: return new RenderStyle(Color.White, 0.7); // 白色预览点,30%透明 diff --git a/src/UI/WPF/ViewModels/AnimationControlViewModel.cs b/src/UI/WPF/ViewModels/AnimationControlViewModel.cs index f937b70..b29d499 100644 --- a/src/UI/WPF/ViewModels/AnimationControlViewModel.cs +++ b/src/UI/WPF/ViewModels/AnimationControlViewModel.cs @@ -1520,8 +1520,10 @@ namespace NavisworksTransport.UI.WPF.ViewModels UpdateMediaControlProperties(); // 更新媒体控制属性 // 先清除所有碰撞高亮(包括预计算和ClashDetective) ModelHighlightHelper.ClearCollisionHighlights(); - // 检查并高亮ClashDetective结果(只在动画自然完成时进行) - CheckAndHighlightClashDetectiveResults(); + // 生成碰撞报告(无论有无碰撞) + GenerateAndSaveCollisionReport(); + // 高亮ClashDetective结果(只在动画自然完成时进行) + HighlightClashDetectiveResults(); break; case NavisworksTransport.Core.Animation.AnimationState.Stopped: CanStartAnimation = true; @@ -1542,9 +1544,73 @@ namespace NavisworksTransport.UI.WPF.ViewModels } /// - /// 检查并高亮ClashDetective结果 + /// 生成并保存碰撞报告(无论有无碰撞都生成) /// - private void CheckAndHighlightClashDetectiveResults() + private async void GenerateAndSaveCollisionReport() + { + try + { + var animationManager = Core.Animation.PathAnimationManager.GetInstance(); + var hasAnimationCollisions = animationManager?.AllCollisionResults?.Count > 0; + + // 如果当前动画没有碰撞数据,但CurrentTestName存在,说明是旧数据 + // 需要清空CurrentTestName,避免使用上一次的测试数据 + if (!hasAnimationCollisions && !string.IsNullOrEmpty(_clashIntegration?.CurrentTestName)) + { + LogManager.Info("当前动画无碰撞数据,清空ClashDetectiveIntegration的CurrentTestName"); + _clashIntegration.ClearCurrentTestName(); + } + + // 如果没有测试名称,创建一个临时的测试名称(用于无碰撞情况) + if (string.IsNullOrEmpty(_clashIntegration?.CurrentTestName)) + { + var tempTestName = $"无碰撞_{DateTime.Now:yyyyMMdd_HHmmss}"; + LogManager.Info($"创建临时测试名称用于无碰撞报告: {tempTestName}"); + _clashIntegration.SetCurrentTestName(tempTestName); + } + + // 统一使用GenerateCollisionReportCommand生成报告(无论有无碰撞) + UpdateMainStatus($"正在生成碰撞报告...", -1, true); + + var generateReportCommand = NavisworksTransport.Commands.GenerateCollisionReportCommand.CreateComprehensive(); + var result = await generateReportCommand.ExecuteAsync(); + + if (result.IsSuccess && result is PathPlanningResult reportResult) + { + // 缓存报告结果,供后续查看使用 + _lastGeneratedReport = reportResult.Data; + + // 保存到数据库 + await SaveCollisionReportToDatabase(reportResult.Data); + + var collisionCount = reportResult.Data.TotalCollisions; + if (collisionCount > 0) + { + UpdateMainStatus($"✅ 碰撞报告已生成并保存:{collisionCount} 个碰撞"); + LogManager.Info("碰撞报告已自动生成并保存到数据库"); + } + else + { + UpdateMainStatus($"✅ 碰撞报告已生成并保存:0 个碰撞"); + LogManager.Info("碰撞报告已自动生成并保存到数据库(无碰撞)"); + } + } + else + { + UpdateMainStatus($"碰撞报告生成失败: {result.ErrorMessage}"); + LogManager.Error($"自动生成碰撞报告失败: {result.ErrorMessage}"); + } + } + catch (Exception ex) + { + LogManager.Error($"生成碰撞报告失败: {ex.Message}"); + } + } + + /// + /// 高亮ClashDetective结果 + /// + private void HighlightClashDetectiveResults() { try { @@ -1576,58 +1642,26 @@ namespace NavisworksTransport.UI.WPF.ViewModels } catch (Exception ex) { - LogManager.Error($"检查并高亮ClashDetective结果失败: {ex.Message}"); + LogManager.Error($"高亮ClashDetective结果失败: {ex.Message}"); } } /// - /// 处理ClashDetective的碰撞检测事件 - 自动生成报告并保存数据库 + /// 处理ClashDetective的碰撞检测事件 - 已废弃,报告生成统一在CheckAndHighlightClashDetectiveResults中处理 /// - private async void OnCollisionDetected(object sender, CollisionDetectedEventArgs e) + private void OnCollisionDetected(object sender, CollisionDetectedEventArgs e) { + // 报告生成已统一在CheckAndHighlightClashDetectiveResults中处理 + // 此事件保留用于日志记录和未来扩展 try { - // 获取ClashDetective结果 var clashResults = _clashIntegration?.GetCurrentTestResults(); var collisionCount = clashResults?.Count ?? 0; - - if (collisionCount > 0) - { - UpdateMainStatus($"发现 {collisionCount} 个碰撞点,正在生成报告...", -1, true); - LogManager.Info($"碰撞检测完成,发现 {collisionCount} 个碰撞,开始自动生成报告"); - - // 自动生成碰撞报告 - var generateReportCommand = NavisworksTransport.Commands.GenerateCollisionReportCommand.CreateComprehensive(); - var result = await generateReportCommand.ExecuteAsync(); - - if (result.IsSuccess && result is PathPlanningResult reportResult) - { - // 缓存报告结果,供后续查看使用 - _lastGeneratedReport = reportResult.Data; - - // 保存到数据库 - await SaveCollisionReportToDatabase(reportResult.Data); - - UpdateMainStatus($"✅ 碰撞报告已生成并保存:{collisionCount} 个碰撞"); - LogManager.Info("碰撞报告已自动生成并保存到数据库"); - - // 高亮ClashDetective结果 - ModelHighlightHelper.HighlightClashDetectiveResults(_clashIntegration.CurrentTestName, _clashIntegration.GetCurrentPathClashResults); - HasClashDetectiveResults = true; - LogManager.Info("已自动高亮ClashDetective检测结果"); - } - else - { - UpdateMainStatus($"发现 {collisionCount} 个碰撞点(报告生成失败)"); - LogManager.Error($"自动生成碰撞报告失败: {result.ErrorMessage}"); - } - } - // 无碰撞的情况由OnAnimationCollisionDetected方法处理,这里不做任何操作 + LogManager.Info($"[OnCollisionDetected] 碰撞检测事件触发,碰撞数量: {collisionCount}"); } catch (Exception ex) { LogManager.Error($"处理碰撞检测事件失败: {ex.Message}", ex); - UpdateMainStatus("处理碰撞检测事件失败"); } }