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