diff --git a/src/UI/WPF/ViewModels/AnimationControlViewModel.cs b/src/UI/WPF/ViewModels/AnimationControlViewModel.cs index 318f27e..5163420 100644 --- a/src/UI/WPF/ViewModels/AnimationControlViewModel.cs +++ b/src/UI/WPF/ViewModels/AnimationControlViewModel.cs @@ -1036,6 +1036,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels public ICommand RemoveExcludedObjectCommand { get; private set; } public ICommand HighlightAllExcludedObjectsCommand { get; private set; } public ICommand ClearExcludedHighlightCommand { get; private set; } + public ICommand AnalyzeCollisionHotspotsCommand { get; private set; } public ICommand HighlightPrecomputedCollisionResultsCommand { get; private set; } public ICommand ClearPrecomputedCollisionHighlightsCommand { get; private set; } public ICommand ToggleWireframeModeCommand { get; private set; } @@ -1313,6 +1314,9 @@ namespace NavisworksTransport.UI.WPF.ViewModels RemoveExcludedObjectCommand = new RelayCommand(ExecuteRemoveExcludedObject, obj => obj != null); HighlightAllExcludedObjectsCommand = new RelayCommand(ExecuteHighlightAllExcludedObjects, () => HasExcludedObjects); ClearExcludedHighlightCommand = new RelayCommand(ExecuteClearExcludedHighlight, () => HasExcludedObjects); + AnalyzeCollisionHotspotsCommand = new RelayCommand( + async () => await ExecuteCollisionHotspotAnalysisAsync(), + () => _pathAnimationManager?.AllCollisionResults?.Count > 0); HighlightPrecomputedCollisionResultsCommand = new RelayCommand(ExecuteHighlightPrecomputedCollisionResults, () => HasClashDetectiveResults); ClearPrecomputedCollisionHighlightsCommand = new RelayCommand(ExecuteClearPrecomputedCollisionHighlights, () => HasClashDetectiveResults); ToggleWireframeModeCommand = new RelayCommand(ExecuteToggleWireframeMode); @@ -3619,31 +3623,27 @@ namespace NavisworksTransport.UI.WPF.ViewModels /// /// 🔥 分析预计算碰撞结果,自动高亮并显示分析对话框 /// - private async Task AnalyzeAndHighlightPrecomputedCollisionsAsync() + /// + /// 【手动入口】碰撞热点分析(排除列表区域按钮触发): + /// 分析当前动画的预计算碰撞结果,显示高频碰撞物体窗口——用户判断哪些物体需要排除。 + /// 不自动保存检测记录(分析是决策辅助,不是动画流程的一部分)。 + /// 说明:动画后不再自动弹出(非手工指定模式 = 检测所有物体,避免人工遗漏; + /// 批处理用户不在场无决策机会;排除建议由用户主动触发)。 + /// + private async Task ExecuteCollisionHotspotAnalysisAsync() { try { - // 仅测试环境变量(副实例/测试进程)跳过预计算分析(历史行为); - // 批处理/测试请求自动模式下窗口会自动选择默认动作并关闭,业务流程完整执行 - if (DialogHelper.IsTestAutomationModeEnabled) - { - LogManager.Info("[碰撞分析] 自动测试模式下跳过预计算碰撞分析"); - SaveCollisionDetectionRecord(); - return; - } - // 1. 获取预计算碰撞结果(从PathAnimationManager,现在缓存帧中已包含碰撞结果) var allResults = _pathAnimationManager?.AllCollisionResults; if (allResults == null || allResults.Count == 0) { - LogManager.Info("[碰撞分析] 没有预计算碰撞结果,跳过分析"); - // 🔥 没有预计算碰撞,配置已确定,直接保存检测记录 - var recordId = SaveCollisionDetectionRecord(); - if (recordId.HasValue && IsReusedHistoryRecord(recordId.Value)) - { - LogManager.Info("[碰撞分析] 用户选择使用历史记录,跳过动画生成"); - return; - } + LogManager.Info("[碰撞热点分析] 无预计算碰撞结果(请先生成动画)"); + System.Windows.MessageBox.Show( + "没有预计算碰撞结果。请先运行\"生成动画\",再进行碰撞热点分析。", + "碰撞热点分析", + System.Windows.MessageBoxButton.OK, + System.Windows.MessageBoxImage.Information); return; } @@ -3653,21 +3653,21 @@ namespace NavisworksTransport.UI.WPF.ViewModels .Select(g => g.First()) .ToList(); - LogManager.Info($"[碰撞分析] 开始分析 {allResults.Count} 个碰撞结果(去重后 {deduplicatedResults.Count} 个)"); + LogManager.Info($"[碰撞热点分析] 开始分析 {allResults.Count} 个碰撞结果(去重后 {deduplicatedResults.Count} 个)"); - // 2. 自动高亮所有预计算碰撞结果 + // 2. 高亮所有预计算碰撞结果 ModelHighlightHelper.ManageCollisionHighlightsByCategory( ModelHighlightHelper.PrecomputeCollisionResultsCategory, deduplicatedResults, clearOtherCategories: false); - LogManager.Info($"[碰撞分析] 已高亮 {deduplicatedResults.Count} 个碰撞对象"); + LogManager.Info($"[碰撞热点分析] 已高亮 {deduplicatedResults.Count} 个碰撞对象"); // 3. 分析碰撞热点(使用原始结果 - 按频率统计) var hotspots = AnalyzeCollisionHotspots(allResults); if (hotspots.Count > 0) { - LogManager.Info($"[碰撞分析] 发现 {hotspots.Count} 个高频碰撞物体"); + LogManager.Info($"[碰撞热点分析] 发现 {hotspots.Count} 个高频碰撞物体"); foreach (var hotspot in hotspots.Take(5)) { LogManager.Info($" - {hotspot.ObjectName}: {hotspot.CollisionCount} 次 ({hotspot.Percentage:F1}%) - {hotspot.Reason}"); @@ -3681,20 +3681,17 @@ namespace NavisworksTransport.UI.WPF.ViewModels } else { - LogManager.Info("[碰撞分析] 没有发现明显的高频碰撞物体"); - // 🔥 有碰撞但无高频热点,配置已确定,保存检测记录 - var recordId = SaveCollisionDetectionRecord(); - if (recordId.HasValue && IsReusedHistoryRecord(recordId.Value)) - { - // 用户选择使用历史记录,跳过后续流程 - LogManager.Info("[碰撞分析] 用户选择使用历史记录,跳过动画生成"); - return; - } + LogManager.Info("[碰撞热点分析] 没有发现明显的高频碰撞物体"); + System.Windows.MessageBox.Show( + "没有发现明显的高频碰撞物体(碰撞次数 > 100 或占比 > 50%)。", + "碰撞热点分析", + System.Windows.MessageBoxButton.OK, + System.Windows.MessageBoxImage.Information); } } catch (Exception ex) { - LogManager.Error($"[碰撞分析] 分析预计算碰撞结果失败: {ex.Message}", ex); + LogManager.Error($"[碰撞热点分析] 分析失败: {ex.Message}", ex); } } @@ -5024,8 +5021,14 @@ namespace NavisworksTransport.UI.WPF.ViewModels Mouse.OverrideCursor = oldCursor; oldCursor = null; // 标记已恢复,避免 finally 再次恢复 - // 🔥 自动生成动画后,自动高亮预计算碰撞结果并显示分析对话框 - await AnalyzeAndHighlightPrecomputedCollisionsAsync(); + // 🔥 动画生成后直接保存检测记录——不再自动弹出预计算碰撞分析窗口: + // 非手工指定模式 = 检测所有物体(避免人工遗漏);排除建议由 + // 排除列表区域的"碰撞热点分析"手动触发(用户主动决策) + var autoRecordId = SaveCollisionDetectionRecord(); + if (autoRecordId.HasValue && IsReusedHistoryRecord(autoRecordId.Value)) + { + LogManager.Info("[动画生成] 用户选择使用历史记录,跳过动画生成"); + } // 更新状态 UpdateAnimationButtonStates(); diff --git a/src/UI/WPF/Views/AnimationControlView.xaml b/src/UI/WPF/Views/AnimationControlView.xaml index e295298..9a91dfa 100644 --- a/src/UI/WPF/Views/AnimationControlView.xaml +++ b/src/UI/WPF/Views/AnimationControlView.xaml @@ -239,6 +239,10 @@ NavisworksTransport 检测动画页签视图 - 采用与类别设置和分层管