using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Threading.Tasks; using System.Windows.Input; using System.Windows.Threading; using Autodesk.Navisworks.Api; using Autodesk.Navisworks.Api.Clash; using NavisworksTransport.Commands; using NavisworksTransport.Core.Animation; using NavisworksTransport.Core; using NavisworksTransport.UI.WPF.Commands; using NavisworksTransport.UI.WPF.Collections; using NavisworksTransport.UI.WPF.Models; using NavisworksTransport.Utils; namespace NavisworksTransport.UI.WPF.ViewModels { /// /// 碰撞报告数据 /// public class CollisionReportData { public bool IsValid { get; set; } public string ErrorMessage { get; set; } = string.Empty; public DateTime GeneratedTime { get; set; } public string AnimatedObjectName { get; set; } = string.Empty; public string PathName { get; set; } = string.Empty; public int TotalTests { get; set; } public int TotalCollisions { get; set; } public List Tests { get; set; } = new List(); } /// /// 碰撞测试信息 /// public class CollisionTestInfo { public string TestName { get; set; } = string.Empty; public string TestType { get; set; } = string.Empty; public double Tolerance { get; set; } public int CollisionCount { get; set; } public string Status { get; set; } = string.Empty; public List Collisions { get; set; } = new List(); } /// /// 碰撞详细信息 /// public class CollisionDetailInfo { public string CollisionId { get; set; } = string.Empty; public string Object1Name { get; set; } = string.Empty; public string Object1Position { get; set; } = string.Empty; public string Object2Name { get; set; } = string.Empty; public string Object2Position { get; set; } = string.Empty; public string CollisionCenter { get; set; } = string.Empty; public double Distance { get; set; } public string Status { get; set; } = string.Empty; } /// /// 动画控制视图模型 /// 专门处理路径动画播放和碰撞检测功能 /// public class AnimationControlViewModel : ViewModelBase, IDisposable { #region 私有字段 private readonly NavisworksTransport.Core.Animation.PathAnimationManager _pathAnimationManager; private readonly NavisworksTransport.Core.Animation.LogisticsAnimationManager _logisticsAnimationManager; private readonly ClashDetectiveIntegration _clashIntegration; private readonly UIStateManager _uiStateManager; // 动画参数相关字段 private ObservableCollection _availableFrameRates; private int _selectedFrameRate = 30; private double _animationDuration = 10.0; private double _currentAnimationTime = 0.0; private bool _canStartAnimation = true; private bool _canPauseAnimation = false; private bool _canStopAnimation = false; private string _animationStatus = "就绪"; private double _animationProgress = 0.0; private string _startAnimationButtonText = "开始动画"; // 碰撞检测相关字段 private bool _hasCollisionResults = false; private string _collisionStatus = "就绪"; private string _collisionSummary = "尚未运行碰撞检测"; // 碰撞检测参数字段 private double _collisionDetectionAccuracy = 0.1; // 检测精度(米) private double _movementSpeed = 1.0; // 运动速度(米/秒) private double _detectionGap = 0.05; // 检测间隙(米) private int _animationFrameRate = 30; // 动画帧率(FPS) private double _collisionDetectionFrequency = 10.0; // 检测频率(次/秒) // 防抖机制相关字段 private DispatcherTimer _parameterUpdateTimer; private readonly object _parameterUpdateLock = new object(); private volatile bool _hasParameterChanges = false; // 当前选中路径 private PathRouteViewModel _currentPathRoute; // 移动物体相关字段 private ModelItem _selectedAnimatedObject; private string _selectedAnimatedObjectName = "未选择移动物体"; private bool _hasSelectedAnimatedObject = false; private bool _canGenerateAnimation = false; private string _generationStatus = "就绪"; #endregion #region 公共属性 /// /// 可用帧率集合 /// public ObservableCollection AvailableFrameRates { get => _availableFrameRates; set => SetProperty(ref _availableFrameRates, value); } /// /// 选中的帧率 /// public int SelectedFrameRate { get => _selectedFrameRate; set => SetProperty(ref _selectedFrameRate, value); } /// /// 动画持续时间(秒) /// public double AnimationDuration { get => _animationDuration; set => SetProperty(ref _animationDuration, value); } /// /// 当前动画时间 /// public double CurrentAnimationTime { get => _currentAnimationTime; set => SetProperty(ref _currentAnimationTime, value); } /// /// 是否可以开始动画 /// public bool CanStartAnimation { get => _canStartAnimation; set => SetProperty(ref _canStartAnimation, value); } /// /// 是否可以暂停动画 /// public bool CanPauseAnimation { get => _canPauseAnimation; set => SetProperty(ref _canPauseAnimation, value); } /// /// 是否可以停止动画 /// public bool CanStopAnimation { get => _canStopAnimation; set => SetProperty(ref _canStopAnimation, value); } /// /// 动画状态 /// public string AnimationStatus { get => _animationStatus; set => SetProperty(ref _animationStatus, value); } /// /// 动画进度 /// public double AnimationProgress { get => _animationProgress; set => SetProperty(ref _animationProgress, value); } /// /// 开始动画按钮文本 /// public string StartAnimationButtonText { get => _startAnimationButtonText; set => SetProperty(ref _startAnimationButtonText, value); } /// /// 是否有碰撞检测结果 /// public bool HasCollisionResults { get => _hasCollisionResults; set => SetProperty(ref _hasCollisionResults, value); } /// /// 碰撞检测状态 /// public string CollisionStatus { get => _collisionStatus; set => SetProperty(ref _collisionStatus, value); } /// /// 碰撞检测摘要 /// public string CollisionSummary { get => _collisionSummary; set => SetProperty(ref _collisionSummary, value); } /// /// 碰撞检测精度(米) /// public double CollisionDetectionAccuracy { get => _collisionDetectionAccuracy; set { // 限制精度到2位小数 var roundedValue = Math.Round(value, 2); if (SetProperty(ref _collisionDetectionAccuracy, roundedValue)) { UpdateCollisionDetectionFrequency(); ScheduleParameterUpdate(); } } } /// /// 运动速度(米/秒) /// public double MovementSpeed { get => _movementSpeed; set { // 限制精度到1位小数 var roundedValue = Math.Round(value, 1); if (SetProperty(ref _movementSpeed, roundedValue)) { UpdateCollisionDetectionFrequency(); ScheduleParameterUpdate(); } } } /// /// 检测间隙(米) /// public double DetectionGap { get => _detectionGap; set { // 限制精度到2位小数 var roundedValue = Math.Round(value, 2); if (SetProperty(ref _detectionGap, roundedValue)) { ScheduleParameterUpdate(); } } } /// /// 动画帧率(FPS) /// public int AnimationFrameRate { get => _animationFrameRate; set { if (SetProperty(ref _animationFrameRate, value)) { UpdatePathAnimationManagerSettings(); } } } /// /// 碰撞检测频率(次/秒) - 计算得出 /// public double CollisionDetectionFrequency { get => _collisionDetectionFrequency; private set => SetProperty(ref _collisionDetectionFrequency, value); } /// /// 当前选中的路径 /// public PathRouteViewModel CurrentPathRoute { get => _currentPathRoute; set { SetProperty(ref _currentPathRoute, value); UpdateCanGenerateAnimation(); } } /// /// 选中的移动物体 /// public ModelItem SelectedAnimatedObject { get => _selectedAnimatedObject; set { SetProperty(ref _selectedAnimatedObject, value); UpdateAnimatedObjectInfo(); UpdateCanGenerateAnimation(); // ✨ 新功能:动画对象选择时预计算排除列表(线程安全版本) _ = PrecomputeCollisionExclusionsAsync(value); } } /// /// 选中的移动物体名称 /// public string SelectedAnimatedObjectName { get => _selectedAnimatedObjectName; set => SetProperty(ref _selectedAnimatedObjectName, value); } /// /// 是否已选择移动物体 /// public bool HasSelectedAnimatedObject { get => _hasSelectedAnimatedObject; set => SetProperty(ref _hasSelectedAnimatedObject, value); } /// /// 是否可以生成动画 /// public bool CanGenerateAnimation { get => _canGenerateAnimation; set => SetProperty(ref _canGenerateAnimation, value); } /// /// 生成状态 /// public string GenerationStatus { get => _generationStatus; set => SetProperty(ref _generationStatus, value); } #endregion #region 命令 public ICommand StartAnimationCommand { get; private set; } public ICommand PauseAnimationCommand { get; private set; } public ICommand StopAnimationCommand { get; private set; } public ICommand ViewCollisionReportCommand { get; private set; } public ICommand SelectAnimatedObjectCommand { get; private set; } public ICommand ClearAnimatedObjectCommand { get; private set; } public ICommand GenerateAnimationCommand { get; private set; } #endregion #region 构造函数 public AnimationControlViewModel() : base() { try { // 初始化管理器 _pathAnimationManager = new NavisworksTransport.Core.Animation.PathAnimationManager(); _logisticsAnimationManager = new NavisworksTransport.Core.Animation.LogisticsAnimationManager(); _clashIntegration = ClashDetectiveIntegration.Instance; _uiStateManager = UIStateManager.Instance; // 订阅PathAnimationManager事件 _pathAnimationManager.ProgressChanged += OnAnimationProgressChanged; _pathAnimationManager.StateChanged += OnAnimationStateChanged; // 初始化集合 AvailableFrameRates = new ThreadSafeObservableCollection(); // 初始化设置 InitializeAnimationSettings(); // 初始化命令 InitializeCommands(); // 初始化碰撞检测集成 InitializeClashIntegration(); // 初始化防抖定时器 InitializeParameterUpdateTimer(); LogManager.Info("AnimationControlViewModel初始化完成(含缓存管理)"); } catch (Exception ex) { LogManager.Error($"AnimationControlViewModel初始化失败: {ex.Message}", ex); throw; } } #endregion #region 初始化方法 /// /// 初始化动画设置 /// private void InitializeAnimationSettings() { // 初始化可用帧率 AvailableFrameRates.Clear(); var frameRates = new[] { 15, 24, 30, 60 }; foreach (var rate in frameRates) { AvailableFrameRates.Add(rate); } SelectedFrameRate = 30; // 默认30fps // 设置默认动画参数 AnimationDuration = 10.0; CurrentAnimationTime = 0.0; // 设置初始状态 CanStartAnimation = true; CanPauseAnimation = false; CanStopAnimation = false; StartAnimationButtonText = "开始动画"; AnimationStatus = "动画状态: 就绪"; AnimationProgress = 0; // 初始化碰撞检测状态 HasCollisionResults = false; CollisionStatus = "就绪"; CollisionSummary = "尚未运行碰撞检测"; // 初始化碰撞检测参数 CollisionDetectionAccuracy = 0.1; // 0.1米 MovementSpeed = 1.0; // 1米/秒 DetectionGap = 0.05; // 0.05米 AnimationFrameRate = 30; // 30FPS UpdateCollisionDetectionFrequency(); // 计算初始检测频率 // 初始化动画管理器设置 UpdatePathAnimationManagerSettings(); LogManager.Info("动画设置初始化完成"); } /// /// 初始化命令 /// private void InitializeCommands() { StartAnimationCommand = new RelayCommand(async () => await ExecuteStartAnimationAsync(), () => CanStartAnimation); PauseAnimationCommand = new RelayCommand(async () => await ExecutePauseAnimationAsync(), () => CanPauseAnimation); StopAnimationCommand = new RelayCommand(async () => await ExecuteStopAnimationAsync(), () => CanStopAnimation); ViewCollisionReportCommand = new RelayCommand(async () => await ExecuteViewCollisionReportAsync(), () => HasCollisionResults); SelectAnimatedObjectCommand = new RelayCommand(ExecuteSelectAnimatedObject); ClearAnimatedObjectCommand = new RelayCommand(ExecuteClearAnimatedObject, () => HasSelectedAnimatedObject); GenerateAnimationCommand = new RelayCommand(ExecuteGenerateAnimation, () => CanGenerateAnimation); LogManager.Info("动画控制命令初始化完成"); } /// /// 初始化碰撞检测集成 /// private void InitializeClashIntegration() { try { _clashIntegration.Initialize(); _clashIntegration.CollisionDetected += OnCollisionDetected; LogManager.Info("碰撞检测集成初始化完成"); } catch (Exception ex) { LogManager.Error($"碰撞检测集成初始化失败: {ex.Message}"); } } #endregion #region 命令实现 /// /// 开始动画命令 /// private async Task ExecuteStartAnimationAsync() { if (!CanStartAnimation || CurrentPathRoute == null || CurrentPathRoute.Points.Count < 2) { await _uiStateManager.ExecuteUIUpdateAsync(() => { AnimationStatus = "请先选择包含至少2个点的路径"; }); return; } try { // 根据PathAnimationManager的状态决定操作 if (_pathAnimationManager.CurrentState == NavisworksTransport.Core.Animation.AnimationState.Paused) { // 从暂停状态恢复 _pathAnimationManager.ResumeAnimation(); LogManager.Info("从暂停状态恢复动画播放"); return; // 恢复动画后直接返回,不再执行StartAnimation } else if (_pathAnimationManager.IsAnimating) { LogManager.Warning("动画已在播放中"); await _uiStateManager.ExecuteUIUpdateAsync(() => { AnimationStatus = "动画已在播放中"; CanStartAnimation = true; CanPauseAnimation = false; CanStopAnimation = false; }); return; } // 开始播放物体移动动画 // 首先重置进度(开始全新动画时) await _uiStateManager.ExecuteUIUpdateAsync(() => { AnimationProgress = 0; CurrentAnimationTime = 0.0; }); _pathAnimationManager.StartAnimation(); LogManager.Info($"开始物体移动动画播放: {CurrentPathRoute.Name}, 帧率: {SelectedFrameRate}fps"); } catch (Exception ex) { await _uiStateManager.ExecuteUIUpdateAsync(() => { AnimationStatus = $"开始动画出错: {ex.Message}"; LogManager.Error($"开始动画异常: {ex.Message}", ex); // 恢复按钮状态 CanStartAnimation = true; CanPauseAnimation = false; CanStopAnimation = false; }); } } /// /// 暂停动画命令 /// private async Task ExecutePauseAnimationAsync() { try { // 调用PathAnimationManager暂停动画 // UI状态会通过OnAnimationStateChanged事件自动更新 _pathAnimationManager.PauseAnimation(); LogManager.Info("暂停动画播放"); } catch (Exception ex) { LogManager.Error($"暂停动画异常: {ex.Message}", ex); // 错误时手动恢复UI状态 await _uiStateManager.ExecuteUIUpdateAsync(() => { AnimationStatus = "暂停动画失败"; }); } } /// /// 停止动画命令 /// private async Task ExecuteStopAnimationAsync() { try { await _uiStateManager.ExecuteUIUpdateAsync(() => { AnimationStatus = "动画状态: 已停止"; AnimationProgress = 0; CurrentAnimationTime = 0.0; CanStartAnimation = true; CanPauseAnimation = false; CanStopAnimation = false; LogManager.Info("停止动画播放"); }); // 停止当前动画 _pathAnimationManager.StopAnimation(); } catch (Exception ex) { LogManager.Error($"停止动画异常: {ex.Message}", ex); } } /// /// 查看碰撞报告命令 /// private async Task ExecuteViewCollisionReportAsync() { if (!HasCollisionResults) { await _uiStateManager.ExecuteUIUpdateAsync(() => { CollisionStatus = "尚无碰撞检测结果可查看"; }); return; } try { await _uiStateManager.ExecuteUIUpdateAsync(() => { CollisionStatus = "正在生成碰撞报告..."; }); LogManager.Info("开始生成碰撞检测详细报告"); // 在后台线程生成报告 var reportData = await Task.Run(() => { try { return GenerateCollisionReport(); } catch (Exception ex) { LogManager.Error($"生成碰撞报告失败: {ex.Message}"); return null; } }); if (reportData != null) { // 显示报告 - 可以通过多种方式显示 await ShowCollisionReport(reportData); await _uiStateManager.ExecuteUIUpdateAsync(() => { CollisionStatus = "碰撞报告已生成"; LogManager.Info("碰撞报告生成完成并已显示"); }); } else { await _uiStateManager.ExecuteUIUpdateAsync(() => { CollisionStatus = "生成碰撞报告失败"; }); } } catch (Exception ex) { await _uiStateManager.ExecuteUIUpdateAsync(() => { CollisionStatus = "查看碰撞报告出错"; }); LogManager.Error($"查看碰撞报告异常: {ex.Message}", ex); } } #endregion #region 辅助方法 /// /// 设置当前路径 /// public void SetCurrentPath(PathRouteViewModel pathRoute) { CurrentPathRoute = pathRoute; // 更新按钮状态 var hasValidPath = pathRoute != null && pathRoute.Points.Count >= 2; CanStartAnimation = hasValidPath; // 更新状态文本 if (pathRoute == null) { AnimationStatus = "动画状态: 请选择路径"; CollisionStatus = "请选择路径"; } else if (pathRoute.Points.Count < 2) { AnimationStatus = "动画状态: 路径点数不足(需要至少2个点)"; CollisionStatus = "路径点数不足"; } else { AnimationStatus = "动画状态: 就绪"; CollisionStatus = "就绪"; } LogManager.Info($"AnimationControlViewModel当前路径更新: {pathRoute?.Name ?? "无"}, 点数: {pathRoute?.Points.Count ?? 0}"); } /// /// 处理动画进度变化事件 /// 直接使用Dispatcher更新UI,避免UIStateManager的超时机制导致UI积压 /// private void OnAnimationProgressChanged(object sender, double progressPercent) { // 直接使用Dispatcher.BeginInvoke进行UI更新,避免UIStateManager的5秒超时导致积压 System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() => { // 直接使用传入的百分比数值 AnimationProgress = progressPercent; CurrentAnimationTime = (AnimationProgress / 100.0) * AnimationDuration; })); } /// /// 处理动画状态变化事件 /// 直接使用Dispatcher更新UI,避免UIStateManager的超时机制导致UI积压 /// private void OnAnimationStateChanged(object sender, NavisworksTransport.Core.Animation.AnimationState state) { // 直接使用Dispatcher.BeginInvoke进行UI更新,避免UIStateManager的5秒超时导致积压 System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() => { switch (state) { case NavisworksTransport.Core.Animation.AnimationState.Playing: CanStartAnimation = false; CanPauseAnimation = true; CanStopAnimation = true; StartAnimationButtonText = "开始动画"; // 播放中时按钮显示为灰色的"开始动画" AnimationStatus = "动画状态: 播放中"; break; case NavisworksTransport.Core.Animation.AnimationState.Paused: CanStartAnimation = true; // 暂停状态下可以继续 CanPauseAnimation = false; CanStopAnimation = true; StartAnimationButtonText = "继续播放"; // 暂停状态下显示"继续播放" AnimationStatus = "动画状态: 已暂停"; break; case NavisworksTransport.Core.Animation.AnimationState.Finished: CanStartAnimation = true; CanPauseAnimation = false; CanStopAnimation = false; StartAnimationButtonText = "开始动画"; // 完成后恢复"开始动画" AnimationStatus = "动画状态: 已完成"; // 动画完成后更新碰撞检测状态 UpdateCollisionStatusAfterAnimation(); break; case NavisworksTransport.Core.Animation.AnimationState.Stopped: CanStartAnimation = true; CanPauseAnimation = false; CanStopAnimation = false; StartAnimationButtonText = "开始动画"; // 停止后恢复"开始动画" AnimationStatus = "动画状态: 已停止"; break; default: StartAnimationButtonText = "开始动画"; AnimationStatus = $"动画状态: {state}"; break; } })); } /// /// 处理碰撞检测事件 /// private async void OnCollisionDetected(object sender, CollisionDetectedEventArgs e) { await _uiStateManager.ExecuteUIUpdateAsync(() => { HasCollisionResults = e.Results.Count > 0; CollisionSummary = e.Results.Count > 0 ? $"发现 {e.Results.Count} 个碰撞点" : "未发现碰撞"; }); } /// /// 执行选择移动物体命令 /// private void ExecuteSelectAnimatedObject() { try { LogManager.Info("开始选择移动物体"); // 获取当前选中的模型项 var doc = Autodesk.Navisworks.Api.Application.ActiveDocument; var selectedItems = doc.CurrentSelection.SelectedItems; if (selectedItems.Count == 0) { GenerationStatus = "请先在Navisworks中选择一个物体"; LogManager.Warning("用户未选择任何物体"); return; } if (selectedItems.Count > 1) { GenerationStatus = "请只选择一个物体作为移动对象"; LogManager.Warning($"用户选择了{selectedItems.Count}个物体,需要只选择一个"); return; } var selectedItem = selectedItems.First; // 检查选中项是否包含几何体(直接包含或子项包含) bool hasAnyGeometry = HasGeometryRecursive(selectedItem); if (!hasAnyGeometry) { GenerationStatus = "选中的项目及其子项都不包含几何体,请选择其他物体"; LogManager.Warning("选中的项目及其子项都不包含几何体"); return; } LogManager.Info($"选中物体信息: DisplayName={selectedItem.DisplayName}, HasGeometry={selectedItem.HasGeometry}, ChildCount={selectedItem.Children.Count()}"); // 设置选中的移动物体 SelectedAnimatedObject = selectedItem; GenerationStatus = "移动物体选择成功"; LogManager.Info($"移动物体选择成功: {SelectedAnimatedObject.DisplayName}"); } catch (Exception ex) { GenerationStatus = "选择移动物体失败"; LogManager.Error($"选择移动物体时发生错误: {ex.Message}"); } } /// /// 执行清除移动物体命令 /// /// /// 执行清除移动物体命令 /// private void ExecuteClearAnimatedObject() { try { LogManager.Info("开始清除移动物体选择并恢复原始位置"); // 如果有选中的物体,则恢复到原始位置 if (SelectedAnimatedObject != null) { try { LogManager.Info($"开始恢复物体 '{SelectedAnimatedObject.DisplayName}' 到原始位置"); // 使用ResetPermanentTransform清除所有增量变换,恢复到设计文件中的原始位置 var doc = Autodesk.Navisworks.Api.Application.ActiveDocument; var modelItems = new ModelItemCollection { SelectedAnimatedObject }; doc.Models.ResetPermanentTransform(modelItems); LogManager.Info($"物体 '{SelectedAnimatedObject.DisplayName}' 已成功恢复到原始位置"); GenerationStatus = "已清除移动物体选择并恢复到原始位置"; } catch (Exception restoreEx) { LogManager.Error($"恢复物体到原始位置时发生错误: {restoreEx.Message}"); GenerationStatus = $"已清除物体选择,但恢复位置失败: {restoreEx.Message}"; } } else { LogManager.Info("没有选中的物体需要清除"); GenerationStatus = "已清除移动物体选择"; } // 清理选择状态 SelectedAnimatedObject = null; LogManager.Info("移动物体选择已完全清除"); } catch (Exception ex) { LogManager.Error($"清除移动物体选择时发生错误: {ex.Message}"); GenerationStatus = $"清除失败: {ex.Message}"; } } /// /// 异步预计算碰撞排除列表 /// /// 动画对象 private async Task PrecomputeCollisionExclusionsAsync(ModelItem animationObject) { try { if (animationObject == null) { LogManager.Debug("[缓存预计算] 动画对象为空,跳过预计算"); return; } LogManager.Info($"[缓存预计算] 开始为新选择的动画对象预计算: {animationObject.DisplayName}"); // 在UI线程中更新开始状态 await System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() => { GenerationStatus = "正在分析动画对象..."; })); // 在UI线程中执行Navisworks API操作(线程安全) bool success; try { success = _logisticsAnimationManager.PrecomputeCollisionExclusions(animationObject); } catch (Exception ex) { LogManager.Error($"[缓存预计算] 预计算失败: {ex.Message}", ex); success = false; } // 异步更新UI状态 await System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() => { if (success) { var cacheStats = _logisticsAnimationManager.GetCacheStats(); GenerationStatus = $"动画对象分析完成 - {cacheStats}"; LogManager.Info($"[缓存预计算] 预计算成功 - {cacheStats}"); } else { GenerationStatus = "动画对象分析失败,将使用实时计算"; LogManager.Warning("[缓存预计算] 预计算失败,碰撞检测将使用实时计算模式"); } })); } catch (Exception ex) { LogManager.Error($"[缓存预计算] 异步预计算过程异常: {ex.Message}", ex); await System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() => { GenerationStatus = "动画对象分析异常"; })); } } /// /// 执行生成动画命令(同步执行,因为Navisworks API需要STA线程) /// private void ExecuteGenerateAnimation() { try { if (!CanGenerateAnimation) { GenerationStatus = "无法生成动画:缺少必要条件"; LogManager.Warning("尝试生成动画但条件不满足"); return; } GenerationStatus = "正在生成动画..."; LogManager.Info("开始生成动画"); // 🔥 新增:在生成动画阶段构建碰撞检测缓存 GenerationStatus = "正在构建碰撞检测缓存..."; LogManager.Info("[动画生成] 开始构建碰撞检测缓存"); var cacheStartTime = DateTime.Now; try { // 构建全局缓存(与具体移动物体无关) ClashDetectiveIntegration.ClearAllCaches(); GenerationStatus = "正在缓存几何对象列表..."; ClashDetectiveIntegration.BuildAllGeometryItemsCache(); GenerationStatus = "正在缓存通道对象..."; var clashIntegration = ClashDetectiveIntegration.Instance; clashIntegration.BuildChannelObjectsCache(); var cacheElapsed = (DateTime.Now - cacheStartTime).TotalMilliseconds; LogManager.Info($"[动画生成] 碰撞检测缓存构建完成,耗时: {cacheElapsed:F1}ms"); // 构建特定于动画对象的缓存 GenerationStatus = "正在分析动画对象..."; var success = _logisticsAnimationManager.PrecomputeCollisionExclusions(SelectedAnimatedObject); if (!success) { LogManager.Warning("[动画生成] 动画对象分析失败,将使用实时计算模式"); } } catch (Exception cacheEx) { LogManager.Warning($"[动画生成] 缓存构建失败: {cacheEx.Message},将使用实时计算模式"); } // 原有的动画生成逻辑 GenerationStatus = "正在生成路径动画..."; // 将PathRouteViewModel的点转换为Point3D列表 var pathPoints = CurrentPathRoute.Points.Select(p => new Point3D(p.X, p.Y, p.Z)).ToList(); // 使用PathAnimationManager设置物体动画(真正的物体移动动画) _pathAnimationManager.SetupAnimation(SelectedAnimatedObject, pathPoints, AnimationDuration); // 更新状态 CanStartAnimation = true; AnimationStatus = "动画已生成,可以开始播放"; GenerationStatus = "动画生成成功"; var totalElapsed = (DateTime.Now - cacheStartTime).TotalMilliseconds; LogManager.Info($"[动画生成] 动画生成完成,总耗时: {totalElapsed:F1}ms"); LogManager.Info($"动画生成成功: 物体={SelectedAnimatedObject.DisplayName}, 路径={CurrentPathRoute.Name}"); } catch (Exception ex) { GenerationStatus = "动画生成失败"; AnimationStatus = "动画生成失败"; LogManager.Error($"生成动画时发生错误: {ex.Message}"); LogManager.Error($"动画生成失败,详细错误信息:{ex}"); } } /// /// 更新移动物体信息 /// private void UpdateAnimatedObjectInfo() { if (SelectedAnimatedObject != null) { SelectedAnimatedObjectName = SelectedAnimatedObject.DisplayName ?? "未命名物体"; HasSelectedAnimatedObject = true; } else { SelectedAnimatedObjectName = "未选择移动物体"; HasSelectedAnimatedObject = false; } } /// /// 递归检查ModelItem是否包含几何体 /// private bool HasGeometryRecursive(ModelItem item) { if (item == null) return false; // 如果当前项有几何体,直接返回true if (item.HasGeometry) return true; // 递归检查子项 foreach (ModelItem child in item.Children) { if (HasGeometryRecursive(child)) return true; } return false; } /// /// 更新是否可以生成动画的状态 /// private void UpdateCanGenerateAnimation() { var hasObject = SelectedAnimatedObject != null; var hasPath = CurrentPathRoute != null && CurrentPathRoute.Points.Count >= 2; CanGenerateAnimation = hasObject && hasPath; if (!hasObject && !hasPath) { GenerationStatus = "请选择移动物体和动画路径"; } else if (!hasObject) { GenerationStatus = "请选择移动物体"; } else if (!hasPath) { GenerationStatus = "请选择有效的动画路径"; } else { GenerationStatus = "可以生成动画"; } } /// /// 更新碰撞检测频率 /// private void UpdateCollisionDetectionFrequency() { // 碰撞检测频率 = 运动速度 / 检测精度 (次/秒) if (_collisionDetectionAccuracy > 0) { CollisionDetectionFrequency = _movementSpeed / _collisionDetectionAccuracy; } else { CollisionDetectionFrequency = 10.0; // 默认值 } } /// /// 初始化参数更新防抖定时器 /// private void InitializeParameterUpdateTimer() { _parameterUpdateTimer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(150) // 150毫秒防抖延迟 }; _parameterUpdateTimer.Tick += OnParameterUpdateTimerTick; } /// /// 定时器触发时执行参数更新 /// private void OnParameterUpdateTimerTick(object sender, EventArgs e) { _parameterUpdateTimer.Stop(); lock (_parameterUpdateLock) { if (_hasParameterChanges) { _hasParameterChanges = false; UpdatePathAnimationManagerSettings(); } } } /// /// 计划参数更新(防抖机制) /// private void ScheduleParameterUpdate() { lock (_parameterUpdateLock) { _hasParameterChanges = true; _parameterUpdateTimer.Stop(); _parameterUpdateTimer.Start(); } } /// /// 更新PathAnimationManager的设置 /// private void UpdatePathAnimationManagerSettings() { try { if (_pathAnimationManager != null) { _pathAnimationManager.SetAnimationFrameRate(_animationFrameRate); _pathAnimationManager.SetCollisionDetectionAccuracy(_collisionDetectionAccuracy); _pathAnimationManager.SetMovementSpeed(_movementSpeed); _pathAnimationManager.SetDetectionGap(_detectionGap); LogManager.Debug($"碰撞检测参数已更新: 帧率={_animationFrameRate}FPS, 精度={_collisionDetectionAccuracy:F2}m, 速度={_movementSpeed:F1}m/s, 间隙={_detectionGap:F2}m"); } } catch (Exception ex) { LogManager.Error($"更新动画管理器设置失败: {ex.Message}"); } } /// /// 动画完成后更新碰撞检测状态 /// private void UpdateCollisionStatusAfterAnimation() { try { // 给一个短暂延迟,让CreateAllAnimationCollisionTests有时间完成 Task.Delay(1000).ContinueWith(_ => _uiStateManager.ExecuteUIUpdateAsync(() => { // 检查ClashDetectiveIntegration是否有缓存结果 var clashIntegration = _clashIntegration; if (clashIntegration != null) { // 通过检查是否有任何动画相关的碰撞测试来判断是否有结果 HasCollisionResults = true; // 假设动画完成后总是有结果可查看 CollisionStatus = "动画完成,碰撞检测已完成"; CollisionSummary = "请点击'查看碰撞报告'查看详细结果"; LogManager.Info("动画完成后碰撞状态已更新"); } else { CollisionStatus = "碰撞检测未就绪"; CollisionSummary = "碰撞检测功能不可用"; LogManager.Warning("ClashDetectiveIntegration实例不可用"); } })); } catch (Exception ex) { LogManager.Error($"动画完成后更新碰撞状态失败: {ex.Message}"); } } /// /// 生成碰撞检测报告数据 /// private CollisionReportData GenerateCollisionReport() { try { LogManager.Info("开始从Clash Detective获取碰撞检测结果"); var doc = Autodesk.Navisworks.Api.Application.ActiveDocument; var documentClash = doc.GetClash(); if (documentClash == null) { LogManager.Warning("无法获取Clash Detective文档"); return new CollisionReportData { IsValid = false, ErrorMessage = "Clash Detective不可用" }; } var reportData = new CollisionReportData { IsValid = true, GeneratedTime = DateTime.Now, AnimatedObjectName = SelectedAnimatedObject?.DisplayName ?? "未知对象", PathName = CurrentPathRoute?.Name ?? "未知路径" }; // 获取所有动画相关的碰撞测试 var animationTests = documentClash.TestsData.Tests.Cast() .Where(t => t.DisplayName.Contains("动画路径碰撞")) .ToList(); LogManager.Info($"找到 {animationTests.Count} 个动画碰撞测试"); foreach (var test in animationTests) { var testInfo = new CollisionTestInfo { TestName = test.DisplayName, TestType = test.TestType.ToString(), Tolerance = test.Tolerance, CollisionCount = test.Children.Count, Status = test.Status.ToString() }; // 获取每个碰撞的详细信息 foreach (var clashResult in test.Children.Cast()) { var collision = new CollisionDetailInfo { CollisionId = clashResult.Guid.ToString(), Distance = clashResult.Distance, Status = clashResult.Status.ToString() }; // 获取碰撞对象信息 if (clashResult.CompositeItem1 != null) { collision.Object1Name = clashResult.CompositeItem1.DisplayName; var point = clashResult.CompositeItem1.BoundingBox(); collision.Object1Position = $"({point.Center.X:F2}, {point.Center.Y:F2}, {point.Center.Z:F2})"; } if (clashResult.CompositeItem2 != null) { collision.Object2Name = clashResult.CompositeItem2.DisplayName; var point = clashResult.CompositeItem2.BoundingBox(); collision.Object2Position = $"({point.Center.X:F2}, {point.Center.Y:F2}, {point.Center.Z:F2})"; } // 获取碰撞中心点 if (clashResult.Center != null) { collision.CollisionCenter = $"({clashResult.Center.X:F2}, {clashResult.Center.Y:F2}, {clashResult.Center.Z:F2})"; } testInfo.Collisions.Add(collision); } reportData.Tests.Add(testInfo); } // 统计总体信息 reportData.TotalTests = reportData.Tests.Count; reportData.TotalCollisions = reportData.Tests.Sum(t => t.CollisionCount); LogManager.Info($"碰撞报告生成完成:{reportData.TotalTests}个测试,{reportData.TotalCollisions}个碰撞"); return reportData; } catch (Exception ex) { LogManager.Error($"生成碰撞报告异常: {ex.Message}"); return new CollisionReportData { IsValid = false, ErrorMessage = ex.Message }; } } /// /// 显示碰撞报告 /// private async Task ShowCollisionReport(CollisionReportData reportData) { try { // 更新UI摘要信息 await _uiStateManager.ExecuteUIUpdateAsync(() => { if (reportData.IsValid) { CollisionSummary = $"共找到 {reportData.TotalTests} 个测试,{reportData.TotalCollisions} 个碰撞点"; } else { CollisionSummary = $"报告生成失败:{reportData.ErrorMessage}"; } }); // 如果报告有效且有碰撞数据,显示详细报告窗口 if (reportData.IsValid && reportData.TotalCollisions > 0) { // 调用ViewCollisionReportCommand显示详细报告窗口 try { // 创建综合碰撞报告命令并执行 var reportCommand = NavisworksTransport.Commands.ViewCollisionReportCommand.CreateComprehensive(autoHighlight: false); // 执行命令,UI显示会在正确的线程中处理 var result = await reportCommand.ExecuteAsync(); if (result.IsSuccess) { LogManager.Info("碰撞报告窗口已成功显示"); } else { LogManager.Warning($"显示碰撞报告窗口失败: {result.ErrorMessage}"); } } catch (Exception ex) { LogManager.Error($"调用碰撞报告命令失败: {ex.Message}"); } } else if (reportData.IsValid && reportData.TotalCollisions == 0) { // 没有碰撞时显示简单提示 LogManager.Info("未发现碰撞问题,路径规划良好"); System.Windows.MessageBox.Show( "未发现碰撞问题,路径规划良好!", "碰撞检测结果", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Information); } else { // 报告无效时的错误处理 LogManager.Error($"碰撞报告数据无效: {reportData.ErrorMessage}"); System.Windows.MessageBox.Show( $"碰撞报告生成失败:{reportData.ErrorMessage}", "错误", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Error); } } catch (Exception ex) { LogManager.Error($"显示碰撞报告异常: {ex.Message}"); System.Windows.MessageBox.Show( $"显示碰撞报告时发生异常:{ex.Message}", "错误", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Error); } } /// /// 将碰撞报告详情输出到日志 /// private void LogCollisionReportDetails(CollisionReportData reportData) { if (!reportData.IsValid) { LogManager.Error($"碰撞报告无效: {reportData.ErrorMessage}"); return; } var report = new System.Text.StringBuilder(); report.AppendLine("=== 碰撞检测详细报告 ==="); report.AppendLine($"生成时间: {reportData.GeneratedTime:yyyy-MM-dd HH:mm:ss}"); report.AppendLine($"动画对象: {reportData.AnimatedObjectName}"); report.AppendLine($"动画路径: {reportData.PathName}"); report.AppendLine($"总测试数: {reportData.TotalTests}"); report.AppendLine($"总碰撞数: {reportData.TotalCollisions}"); report.AppendLine(); foreach (var test in reportData.Tests) { report.AppendLine($"【测试】 {test.TestName}"); report.AppendLine($" 类型: {test.TestType}, 容差: {test.Tolerance:F3}, 状态: {test.Status}"); report.AppendLine($" 碰撞数量: {test.CollisionCount}"); foreach (var collision in test.Collisions) { report.AppendLine($" 碰撞 {collision.CollisionId}:"); report.AppendLine($" 对象1: {collision.Object1Name} 位置: {collision.Object1Position}"); report.AppendLine($" 对象2: {collision.Object2Name} 位置: {collision.Object2Position}"); report.AppendLine($" 碰撞中心: {collision.CollisionCenter}"); report.AppendLine($" 距离: {collision.Distance:F3}, 状态: {collision.Status}"); } report.AppendLine(); } LogManager.Info(report.ToString()); } #endregion #region 资源清理 private bool _disposed = false; /// /// 清理资源 /// public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } /// /// 清理资源 /// protected virtual void Dispose(bool disposing) { if (!_disposed) { if (disposing) { try { // 取消PathAnimationManager事件订阅 if (_pathAnimationManager != null) { _pathAnimationManager.ProgressChanged -= OnAnimationProgressChanged; _pathAnimationManager.StateChanged -= OnAnimationStateChanged; } // 停止当前动画 _pathAnimationManager?.StopAnimation(); // 清理动画管理器 _pathAnimationManager?.Dispose(); // 清理LogisticsAnimationManager缓存 _logisticsAnimationManager?.ClearExclusionCache(); _logisticsAnimationManager?.Dispose(); // 取消碰撞检测事件订阅 if (_clashIntegration != null) { _clashIntegration.CollisionDetected -= OnCollisionDetected; } // 清理防抖定时器 if (_parameterUpdateTimer != null) { _parameterUpdateTimer.Stop(); _parameterUpdateTimer.Tick -= OnParameterUpdateTimerTick; _parameterUpdateTimer = null; } LogManager.Info("AnimationControlViewModel资源清理完成"); } catch (Exception ex) { LogManager.Error($"AnimationControlViewModel资源清理失败: {ex.Message}"); } } _disposed = true; } } #endregion } }