diff --git a/src/Core/Animation/PathAnimationManager.cs b/src/Core/Animation/PathAnimationManager.cs index 6685823..d975c71 100644 --- a/src/Core/Animation/PathAnimationManager.cs +++ b/src/Core/Animation/PathAnimationManager.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Windows.Forms; +using System.Windows.Threading; using Autodesk.Navisworks.Api; using Autodesk.Navisworks.Api.Clash; using NavisApplication = Autodesk.Navisworks.Api.Application; @@ -92,9 +93,7 @@ namespace NavisworksTransport.Core.Animation // === 动画播放机制 === private double _frameInterval; // 帧间隔(毫秒) private DateTime _lastFrameTime = DateTime.MinValue; // 上一帧时间 - private Timer _animationTimer; // 备用Timer定时器 - private bool _isUsingTimer = false; // 是否使用Timer模式 - private const double _fpsThreshold = 10.0; // FPS阈值,低于此值切换到Timer模式 + private DispatcherTimer _animationTimer; // 备用DispatcherTimer定时器 // === 动画参数 === private double _animationDuration = 10.0; // 动画总时长(秒) @@ -156,16 +155,18 @@ namespace NavisworksTransport.Core.Animation _lastFrameTime = DateTime.MinValue; _fpsCounterStart = DateTime.Now; - // 初始化备用Timer - _animationTimer = new Timer(); + // 初始化备用DispatcherTimer + _animationTimer = new DispatcherTimer(DispatcherPriority.Render) + { + Interval = TimeSpan.FromMilliseconds(_frameInterval) + }; _animationTimer.Tick += OnTimerTick; - _animationTimer.Interval = (int)_frameInterval; // 初始化 TimeLiner 集成 try { _timeLinerManager = new TimeLinerIntegrationManager(); - LogManager.Info($"PathAnimationManager 初始化完成 - Idle事件模式, 目标FPS: {_animationFrameRate}"); + LogManager.Info($"PathAnimationManager 初始化完成 - DispatcherTimer模式, 目标FPS: {_animationFrameRate}"); } catch (Exception ex) { @@ -633,6 +634,7 @@ namespace NavisworksTransport.Core.Animation // 初始化动画状态 _animationStartTime = DateTime.Now; _animationFrameCount = 0; // 重置帧计数 + _currentFrameIndex = 0; // 重置当前帧索引,确保从第一帧开始 _pausedProgress = 0.0; // 重置暂停进度 // 重置动画状态 @@ -640,14 +642,13 @@ namespace NavisworksTransport.Core.Animation _fpsFrameCount = 0; _fpsCounterStart = DateTime.Now; _frameInterval = 1000.0 / _animationFrameRate; - _isUsingTimer = false; // 优先使用Idle事件 _lastHighlightState = false; // 重置高亮状态 // 启动动画播放 StartAnimationPlayback(); SetState(AnimationState.Playing); - LogManager.Info($"动画开始播放 - {(_isUsingTimer ? "Timer" : "Idle事件")}模式"); + LogManager.Info($"动画开始播放 - DispatcherTimer模式"); } catch (Exception ex) { @@ -657,7 +658,7 @@ namespace NavisworksTransport.Core.Animation } /// - /// 启动动画播放(Idle事件或Timer) + /// 启动动画播放(DispatcherTimer) /// private void StartAnimationPlayback() { @@ -666,18 +667,10 @@ namespace NavisworksTransport.Core.Animation // 停止之前的播放 StopAnimationPlayback(); - if (_isUsingTimer) - { - // 使用Timer模式 - _animationTimer.Start(); - LogManager.Debug("[播放模式] 启动Timer模式"); - } - else - { - // 使用Idle事件模式 - NavisApplication.Idle += OnApplicationIdle; - LogManager.Debug("[播放模式] 启动Idle事件模式"); - } + // 使用DispatcherTimer模式 + _animationTimer.Interval = TimeSpan.FromMilliseconds(_frameInterval); + _animationTimer.Start(); + LogManager.Debug("[播放模式] 启动DispatcherTimer模式"); } catch (Exception ex) { @@ -686,22 +679,19 @@ namespace NavisworksTransport.Core.Animation } /// - /// 停止动画播放(清理事件和定时器) + /// 停止动画播放(停止DispatcherTimer) /// private void StopAnimationPlayback() { try { - // 停止Timer + // 停止DispatcherTimer if (_animationTimer != null) { _animationTimer.Stop(); } - // 注销Idle事件 - NavisApplication.Idle -= OnApplicationIdle; - - LogManager.Debug("[播放模式] 已停止所有播放机制"); + LogManager.Debug("[播放模式] 已停止DispatcherTimer"); } catch (Exception ex) { @@ -710,54 +700,31 @@ namespace NavisworksTransport.Core.Animation } /// - /// Timer事件处理器 - 备用动画机制 + /// DispatcherTimer事件处理器 - 主要动画机制 /// private void OnTimerTick(object sender, EventArgs e) { try { - // 调用相同的动画更新逻辑 + // 处理动画帧 ProcessAnimationFrame(); + + // 关键改进:显式请求重绘,解决卡顿 + NavisApplication.ActiveDocument.ActiveView.RequestDelayedRedraw(ViewRedrawRequests.All); } catch (Exception ex) { - LogManager.Error($"[Timer模式] 动画更新异常: {ex.Message}"); + LogManager.Error($"[DispatcherTimer模式] 动画更新异常: {ex.Message}"); // 发生异常时停止动画 ShutdownAnimation(); } } - /// - /// 切换到Timer模式 - /// - private void SwitchToTimerMode() - { - try - { - if (!_isUsingTimer && _currentState == AnimationState.Playing) - { - LogManager.Info("[播放模式] 检测到Idle事件不稳定,切换到Timer模式"); - - // 停止Idle事件 - NavisApplication.Idle -= OnApplicationIdle; - - // 启动Timer - _isUsingTimer = true; - _animationTimer.Start(); - - LogManager.Info("[播放模式] 已切换到Timer模式"); - } - } - catch (Exception ex) - { - LogManager.Error($"切换到Timer模式失败: {ex.Message}"); - } - } /// /// 停止动画 /// - public void StopAnimation() + public void CancelAnimation() { try { @@ -851,7 +818,6 @@ namespace NavisworksTransport.Core.Animation try { if (_animationTimer != null) _animationTimer.Stop(); - NavisApplication.Idle -= OnApplicationIdle; } catch (Exception stopEx) { @@ -902,6 +868,13 @@ namespace NavisworksTransport.Core.Animation LogManager.Info("动画完成,路径上无碰撞对象"); } + // 将物体移回起点位置 + if (_pathPoints != null && _pathPoints.Count > 0 && _animatedObject != null) + { + UpdateObjectPosition(_pathPoints[0]); + LogManager.Info($"动画完成,物体已移回起点位置: ({_pathPoints[0].X:F2},{_pathPoints[0].Y:F2},{_pathPoints[0].Z:F2})"); + } + // 直接设置为完成状态,避免中间状态切换 SetState(AnimationState.Finished); @@ -1001,7 +974,7 @@ namespace NavisworksTransport.Core.Animation // 只在需要时停止动画,避免重复调用 if (_currentState == AnimationState.Playing || _currentState == AnimationState.Paused) { - StopAnimation(); // 停止当前动画 + CancelAnimation(); // 停止当前动画 } // 恢复对象的原始变换(安全检查Navisworks对象可用性) @@ -1750,19 +1723,19 @@ namespace NavisworksTransport.Core.Animation } } - // 4. 清理Timer资源 + // 4. 清理DispatcherTimer资源 if (_animationTimer != null) { try { _animationTimer.Stop(); - _animationTimer.Dispose(); + // DispatcherTimer不需要Dispose _animationTimer = null; - LogManager.Info("动画Timer资源已清理"); + LogManager.Info("DispatcherTimer资源已清理"); } catch (Exception ex) { - LogManager.Warning($"清理Timer资源时出现警告: {ex.Message}"); + LogManager.Warning($"清理DispatcherTimer资源时出现警告: {ex.Message}"); } } @@ -1893,7 +1866,16 @@ namespace NavisworksTransport.Core.Animation public void SetAnimationFrameRate(int frameRate) { _animationFrameRate = Math.Max(10, Math.Min(60, frameRate)); // 限制在10-60FPS之间 - LogManager.Info($"动画帧率设置为: {_animationFrameRate}FPS"); + _frameInterval = 1000.0 / _animationFrameRate; // 重新计算帧间隔 + + // 动态更新DispatcherTimer间隔 + if (_animationTimer != null) + { + _animationTimer.Interval = TimeSpan.FromMilliseconds(_frameInterval); + LogManager.Info($"DispatcherTimer间隔已更新: {_frameInterval:F1}ms"); + } + + LogManager.Info($"动画帧率设置为: {_animationFrameRate}FPS (间隔: {_frameInterval:F1}ms)"); } /// @@ -1978,7 +1960,7 @@ namespace NavisworksTransport.Core.Animation /// - /// Idle事件处理器 - 新的动画核心 + /// DispatcherTimer动画处理核心 /// /// /// 根据当前帧索引更新碰撞高亮(状态跟踪优化版本) @@ -2031,7 +2013,7 @@ namespace NavisworksTransport.Core.Animation } /// - /// 统一的动画帧处理逻辑(Idle事件和Timer共用) + /// 统一的动画帧处理逻辑(DispatcherTimer专用) /// private void ProcessAnimationFrame() { @@ -2049,16 +2031,8 @@ namespace NavisworksTransport.Core.Animation return; } - // 帧率控制(仅对Idle事件有效,Timer有自己的间隔控制) + // DispatcherTimer已经控制了调用间隔,无需手动帧率控制 var now = DateTime.Now; - if (!_isUsingTimer) // Idle事件模式需要手动控制帧率 - { - var elapsed = (now - _lastFrameTime).TotalMilliseconds; - if (elapsed < _frameInterval) - { - return; // 还没到下一帧时间,跳过本次处理 - } - } // 计算下一帧索引(考虑播放方向和速度) int nextFrameIndex = _currentFrameIndex; @@ -2125,23 +2099,9 @@ namespace NavisworksTransport.Core.Animation UpdateFPSCounterAndCheckSwitch(); } - private void OnApplicationIdle(object sender, EventArgs e) - { - try - { - // 调用统一的帧处理逻辑 - ProcessAnimationFrame(); - } - catch (Exception ex) - { - LogManager.Error($"[Idle模式] 动画更新异常: {ex.Message}"); - // 发生异常时停止动画,避免持续错误 - ShutdownAnimation(); - } - } /// - /// 更新FPS计数器并检查是否需要切换播放模式 + /// 更新FPS计数器(DispatcherTimer模式) /// private void UpdateFPSCounterAndCheckSwitch() { @@ -2152,14 +2112,7 @@ namespace NavisworksTransport.Core.Animation if (elapsed >= 1.0) { _actualFPS = _fpsFrameCount / elapsed; - LogManager.Debug($"[性能监控] 实际FPS: {_actualFPS:F1} (目标: {_animationFrameRate}) - {(_isUsingTimer ? "Timer" : "Idle")}模式"); - - // 检查是否需要切换到Timer模式 - if (!_isUsingTimer && _actualFPS < _fpsThreshold) - { - LogManager.Warning($"[性能监控] FPS过低 ({_actualFPS:F1} < {_fpsThreshold}),切换到Timer模式"); - SwitchToTimerMode(); - } + LogManager.Debug($"[性能监控] 实际FPS: {_actualFPS:F1} (目标: {_animationFrameRate}) - DispatcherTimer模式"); // 重置计数器 _fpsFrameCount = 0; diff --git a/src/Core/Collision/ClashDetectiveIntegration.cs b/src/Core/Collision/ClashDetectiveIntegration.cs index f3974ca..ad3fe11 100644 --- a/src/Core/Collision/ClashDetectiveIntegration.cs +++ b/src/Core/Collision/ClashDetectiveIntegration.cs @@ -400,9 +400,7 @@ namespace NavisworksTransport resultCount++; try - { - LogManager.Info($"[分组测试-{resultCount:00}] 处理碰撞: {collision.Item1?.DisplayName} <-> {collision.Item2?.DisplayName}"); - + { // 临时移动动画对象到碰撞位置以执行测试 var testAnimatedObject = collision.Item1; var modelItems = new ModelItemCollection { testAnimatedObject }; @@ -456,7 +454,6 @@ namespace NavisworksTransport copyTest.SelectionA.PrimitiveTypes = PrimitiveTypes.Triangles | PrimitiveTypes.Lines | PrimitiveTypes.Points; copyTest.SelectionB.PrimitiveTypes = PrimitiveTypes.Triangles | PrimitiveTypes.Lines | PrimitiveTypes.Points; _documentClash.TestsData.TestsEditTestFromCopy(addedTempTest, copyTest); - LogManager.Debug($"[分组测试-{resultCount:00}] 几何类型设置完成"); } catch (Exception geomEx) { @@ -469,9 +466,7 @@ namespace NavisworksTransport // 获取刷新后的测试结果 var refreshedTempTest = _documentClash.TestsData.Tests.FirstOrDefault(t => t.DisplayName == tempTestName) as ClashTest; if (refreshedTempTest != null && refreshedTempTest.Children.Count > 0) - { - LogManager.Info($"[分组测试-{resultCount:00}] 临时测试检测到 {refreshedTempTest.Children.Count} 个碰撞"); - + { // 将碰撞结果复制到分组中,并设置唯一名称 int subResultIndex = 1; foreach (var child in refreshedTempTest.Children) @@ -488,22 +483,15 @@ namespace NavisworksTransport copiedResult.DisplayName = $"路径碰撞#{resultCount:00}-{subResultIndex:00}_{timeStamp}: {object1Name} ↔ {object2Name}"; collisionGroup.Children.Add(copiedResult); - LogManager.Debug($"[分组测试-{resultCount:00}] 复制碰撞结果到分组: {copiedResult.DisplayName}"); subResultIndex++; } } } - else - { - LogManager.Info($"[分组测试-{resultCount:00}] 临时测试未检测到碰撞,跳过此项"); - // 🔧 修复:如果没有检测到碰撞,直接跳过,不创建手动结果 - } // 删除临时测试 try { _documentClash.TestsData.TestsRemove(refreshedTempTest ?? addedTempTest); - LogManager.Debug($"[分组测试-{resultCount:00}] 临时测试已清理"); } catch (Exception cleanEx) { @@ -522,7 +510,6 @@ namespace NavisworksTransport if (collisionGroup.Children.Count > 0) { _documentClash.TestsData.TestsAddCopy(addedMainTest, collisionGroup); - LogManager.Info($"[分组测试] 分组已添加到主测试,包含 {collisionGroup.Children.Count} 个碰撞结果"); } else { @@ -531,7 +518,6 @@ namespace NavisworksTransport // 提交事务 transaction.Commit(); - LogManager.Info("[分组测试] 事务已提交,测试创建完成"); } } catch (Exception groupEx) diff --git a/src/UI/WPF/ViewModels/AnimationControlViewModel.cs b/src/UI/WPF/ViewModels/AnimationControlViewModel.cs index a314a26..8ba24ac 100644 --- a/src/UI/WPF/ViewModels/AnimationControlViewModel.cs +++ b/src/UI/WPF/ViewModels/AnimationControlViewModel.cs @@ -287,7 +287,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels { try { - _pathAnimationManager.StopAnimation(); // 这会将状态设置为Stopped,需要重新生成动画 + _pathAnimationManager.CancelAnimation(); // 这会将状态设置为Stopped,需要重新生成动画 LogManager.Info("移动物体更改,已清除之前生成的动画"); } catch (Exception ex) @@ -712,7 +712,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels }); // 停止当前动画 - _pathAnimationManager.StopAnimation(); + _pathAnimationManager.CancelAnimation(); } catch (Exception ex) { @@ -980,7 +980,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels { try { - _pathAnimationManager.StopAnimation(); // 这会将状态设置为Stopped,需要重新生成动画 + _pathAnimationManager.CancelAnimation(); // 这会将状态设置为Stopped,需要重新生成动画 LogManager.Info("路径更改,已清除之前生成的动画"); } catch (Exception ex) @@ -1159,7 +1159,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels { try { - _pathAnimationManager.StopAnimation(); + _pathAnimationManager.CancelAnimation(); LogManager.Info("已停止当前播放的动画"); } catch (Exception stopEx) @@ -1909,7 +1909,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels // 停止动画 if (_pathAnimationManager != null && _pathAnimationManager.IsAnimating) { - _pathAnimationManager.StopAnimation(); + _pathAnimationManager.CancelAnimation(); } // 清空选中对象