From 73c26601fd8cd6066f94516e7ca18b22d909a5f2 Mon Sep 17 00:00:00 2001 From: tian <11429339@qq.com> Date: Thu, 12 Feb 2026 13:29:41 +0800 Subject: [PATCH] =?UTF-8?q?=E9=9B=86=E6=88=90=E5=89=96=E9=9D=A2=E7=9B=92?= =?UTF-8?q?=E5=88=B0=E9=A2=84=E8=AE=A1=E7=AE=97=E8=BF=87=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Core/Animation/PathAnimationManager.cs | 172 +++++++++++++++++- src/Core/BatchQueueManager.cs | 3 +- .../Collision/ClashDetectiveIntegration.cs | 10 +- .../ViewModels/AnimationControlViewModel.cs | 28 +-- src/UI/WPF/Views/AnimationControlView.xaml | 5 +- 5 files changed, 185 insertions(+), 33 deletions(-) diff --git a/src/Core/Animation/PathAnimationManager.cs b/src/Core/Animation/PathAnimationManager.cs index 90b44f0..9a35c0e 100644 --- a/src/Core/Animation/PathAnimationManager.cs +++ b/src/Core/Animation/PathAnimationManager.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Text; using System.Windows.Threading; @@ -94,6 +95,8 @@ namespace NavisworksTransport.Core.Animation private double _virtualObjectWidth = 0; // 虚拟运动物体宽度(模型单位) private double _virtualObjectHeight = 0; // 虚拟运动物体高度(模型单位) private bool _useSectionClip = true; // 是否使用剖面盒优化(默认启用) + private bool _useSectionClipOnlyMode = true; // 🔥 剖面盒纯模式:跳过空间索引,直接用剖面盒获取对象 + private List _sectionClipObjects = null; // 剖面盒模式下的局部对象缓存 private List _pathPoints; private List _manualCollisionTargets = new List(); private bool _manualCollisionOverrideEnabled = false; @@ -450,7 +453,18 @@ namespace NavisworksTransport.Core.Animation public void SetUseSectionClip(bool useSectionClip) { _useSectionClip = useSectionClip; - LogManager.Info($"[PathAnimationManager] 剖面盒优化已{(useSectionClip ? "启用" : "禁用")}"); + _useSectionClipOnlyMode = useSectionClip; // 剖面盒开关同时控制纯模式 + LogManager.Info($"[PathAnimationManager] 剖面盒优化已{(useSectionClip ? "启用" : "禁用")},剖面盒纯模式{(useSectionClip ? "启用" : "禁用")}"); + } + + /// + /// 设置是否使用剖面盒纯模式(独立控制) + /// + /// true=只用剖面盒,false=剖面盒+空间索引 + public void SetUseSectionClipOnlyMode(bool useOnlyMode) + { + _useSectionClipOnlyMode = useOnlyMode; + LogManager.Info($"[PathAnimationManager] 剖面盒纯模式{(useOnlyMode ? "启用" : "禁用")}"); } /// @@ -757,6 +771,20 @@ namespace NavisworksTransport.Core.Animation LogManager.Info("[预计算] 已禁用剖面盒优化(性能对比测试模式)"); } + // 🔥 剖面盒纯模式:直接用剖面盒获取局部对象,跳过80秒的全局空间缓存构建 + if (_useSectionClip && _useSectionClipOnlyMode && SectionClipHelper.IsClipBoxEnabled) + { + LogManager.Info("=== 剖面盒纯模式:构建局部对象缓存 ==="); + var sw = Stopwatch.StartNew(); + _sectionClipObjects = BuildObjectsInClipBox(); + sw.Stop(); + LogManager.Info($"[剖面盒模式] 局部对象缓存构建完成,耗时: {sw.ElapsedMilliseconds}ms,对象数: {_sectionClipObjects.Count}"); + } + else + { + _sectionClipObjects = null; // 清除剖面盒对象缓存 + } + // 🔥 重要:预计算前先将物体移动到起点位置 if (_animatedObject != null && _route != null && _route.Points != null && _route.Points.Count > 0) { @@ -870,7 +898,12 @@ namespace NavisworksTransport.Core.Animation } } - if (!manualOverrideActive) + // 🔥 剖面盒纯模式:跳过80秒的全局空间索引构建 + if (_sectionClipObjects != null) + { + LogManager.Info("=== 剖面盒纯模式:跳过全局空间索引构建,使用局部对象缓存 ==="); + } + else if (!manualOverrideActive) { LogManager.Info("=== 构建全局空间索引 ==="); @@ -1080,6 +1113,40 @@ namespace NavisworksTransport.Core.Animation nearbyObjects = nearbyObjects.Where(obj => !_excludedObjects.Contains(obj)); } } + else if (_sectionClipObjects != null) + { + // 🔥 剖面盒纯模式:使用局部对象缓存进行AABB筛选 + var searchBounds = new BoundingBox3D( + new Point3D( + virtualBoundingBox.Min.X - _safetyMargin, + virtualBoundingBox.Min.Y - _safetyMargin, + virtualBoundingBox.Min.Z - _safetyMargin + ), + new Point3D( + virtualBoundingBox.Max.X + _safetyMargin, + virtualBoundingBox.Max.Y + _safetyMargin, + virtualBoundingBox.Max.Z + _safetyMargin + ) + ); + + // 在剖面盒对象列表中筛选与searchBounds相交的对象 + nearbyObjects = _sectionClipObjects + .Where(item => item != _animatedObject) + .Where(item => { + try { + return item.BoundingBox().Intersects(searchBounds); + } + catch { + return false; + } + }); + + // 🔥 Human-in-the-Loop: 应用用户排除列表过滤 + if (_excludedObjects.Count > 0) + { + nearbyObjects = nearbyObjects.Where(obj => !_excludedObjects.Contains(obj)); + } + } else { // 🔥 优化:使用AABB查询代替球形查询,避免球体扩大的无效范围 @@ -3823,6 +3890,107 @@ namespace NavisworksTransport.Core.Animation #endregion + #region 剖面盒纯模式 + + /// + /// 构建剖面盒内的局部对象缓存 + /// 遍历模型树,只收集与剖面盒相交的对象,并排除可通行对象 + /// + /// 剖面盒内的对象列表(已排除可通行对象) + private List BuildObjectsInClipBox() + { + var objectsInClipBox = new List(); + + try + { + if (!SectionClipHelper.TryGetCurrentClipBox(out var clipBox)) + { + LogManager.Warning("[剖面盒模式] 无法获取当前剖面盒,返回空列表"); + return objectsInClipBox; + } + + LogManager.Debug($"[剖面盒模式] 开始遍历模型,剖面盒范围: X[{clipBox.Min.X:F2},{clipBox.Max.X:F2}], Y[{clipBox.Min.Y:F2},{clipBox.Max.Y:F2}], Z[{clipBox.Min.Z:F2},{clipBox.Max.Z:F2}]"); + + var stack = new Stack(1000); + int totalChecked = 0; + int intersectCount = 0; + int skipByClipCount = 0; + int skipByTraversableCount = 0; + + // 将所有模型的根节点压入栈 + foreach (var model in Application.ActiveDocument.Models) + { + stack.Push(model.RootItem); + } + + while (stack.Count > 0) + { + var item = stack.Pop(); + totalChecked++; + + try + { + // 关键剪枝1:如果节点显式隐藏,则跳过其整个分支 + if (item.IsHidden) + continue; + + // 🔥 关键剪枝2:如果节点是可通行的(具有物流属性且可通行性为"是"),则跳过 + string traversableValue = CategoryAttributeManager.GetLogisticsPropertyValue(item, CategoryAttributeManager.LogisticsProperties.TRAVERSABLE); + if (traversableValue == "是") + { + skipByTraversableCount++; + continue; // 跳过可通行对象及其子节点 + } + + // 测试包围盒是否与剖面盒相交 + var itemBox = item.BoundingBox(); + bool intersects = clipBox.Intersects(itemBox); + + if (!intersects) + { + skipByClipCount++; + continue; // 跳过该节点及其子节点(剪枝) + } + + // 相交:如果是复合对象或有几何数据,加入列表 + if (item.IsComposite) + { + objectsInClipBox.Add(item); + intersectCount++; + // 复合对象不遍历子节点 + } + else if (item.HasGeometry) + { + objectsInClipBox.Add(item); + intersectCount++; + } + else + { + // 空节点:继续遍历子节点 + foreach (var child in item.Children) + { + stack.Push(child); + } + } + } + catch (Exception ex) + { + LogManager.Warning($"[剖面盒模式] 处理对象失败: {ex.Message}"); + } + } + + LogManager.Debug($"[剖面盒模式] 遍历完成: 检查{totalChecked}个节点,剖面盒内{intersectCount}个对象,剖面盒过滤{skipByClipCount}个,可通行对象过滤{skipByTraversableCount}个"); + } + catch (Exception ex) + { + LogManager.Error($"[剖面盒模式] 构建局部对象缓存失败: {ex.Message}"); + } + + return objectsInClipBox; + } + + #endregion + #endregion } } \ No newline at end of file diff --git a/src/Core/BatchQueueManager.cs b/src/Core/BatchQueueManager.cs index 4dbc9e2..f26db07 100644 --- a/src/Core/BatchQueueManager.cs +++ b/src/Core/BatchQueueManager.cs @@ -505,7 +505,8 @@ namespace NavisworksTransport.Core } // 统一准备碰撞检测(根据模式自动决定是否构建全局缓存) - ClashDetectiveIntegration.PrepareCollisionDetection(animatedObject, isManualMode, manualDetectionTargets); + // 🔥 剖面盒纯模式下跳过全局缓存构建(剖面盒始终启用) + ClashDetectiveIntegration.PrepareCollisionDetection(animatedObject, isManualMode, manualDetectionTargets, true); // 在主线程执行Navisworks API调用 var result = await UIStateManager.Instance.ExecuteUIUpdateAsync(() => diff --git a/src/Core/Collision/ClashDetectiveIntegration.cs b/src/Core/Collision/ClashDetectiveIntegration.cs index 05694d4..e61d4b7 100644 --- a/src/Core/Collision/ClashDetectiveIntegration.cs +++ b/src/Core/Collision/ClashDetectiveIntegration.cs @@ -1640,8 +1640,9 @@ namespace NavisworksTransport /// 运动物体 /// 是否为手工指定检测对象模式 /// 手工指定的检测目标(仅在手工模式下使用) + /// 是否使用剖面盒纯模式(跳过全局缓存) /// 是否成功准备 - public static bool PrepareCollisionDetection(ModelItem animatedObject, bool isManualMode, List manualTargets = null) + public static bool PrepareCollisionDetection(ModelItem animatedObject, bool isManualMode, List manualTargets = null, bool useSectionClipOnlyMode = false) { try { @@ -1651,10 +1652,11 @@ namespace NavisworksTransport return false; } - if (isManualMode) + if (isManualMode || useSectionClipOnlyMode) { - // 手工模式:只设置移动物体,不构建全局缓存 - LogManager.Info("[碰撞检测] 手工模式 - 跳过全局缓存初始化"); + // 手工模式或剖面盒纯模式:只设置移动物体,不构建全局缓存 + string modeName = isManualMode ? "手工模式" : "剖面盒纯模式"; + LogManager.Info($"[碰撞检测] {modeName} - 跳过全局缓存初始化"); SetAnimatedObject(animatedObject); // 使用优化后的方法 return true; } diff --git a/src/UI/WPF/ViewModels/AnimationControlViewModel.cs b/src/UI/WPF/ViewModels/AnimationControlViewModel.cs index 22cb50f..7d23aad 100644 --- a/src/UI/WPF/ViewModels/AnimationControlViewModel.cs +++ b/src/UI/WPF/ViewModels/AnimationControlViewModel.cs @@ -319,8 +319,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels private double _virtualObjectHeight; // 虚拟车辆高度(米) private double _safetyMargin; // 检测间隙(米),从路径编辑同步 - // 剖面盒优化相关字段 - private bool _useSectionClip = true; // 使用剖面盒优化(默认启用,用于性能对比测试) + // 🔥 剖面盒优化已移除开关,始终启用(经测试验证有效) // 角度修正相关字段 private double _objectRotationCorrection; // 物体角度修正值(度,顺时针) @@ -612,23 +611,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels #region 虚拟车辆属性 - /// - /// 是否使用选择的模型物体 - /// - /// - /// 是否使用剖面盒优化(用于性能对比测试) - /// - public bool UseSectionClip - { - get => _useSectionClip; - set - { - if (SetProperty(ref _useSectionClip, value)) - { - LogManager.Info($"[剖面盒] 优化开关已{(value ? "启用" : "禁用")}"); - } - } - } + /// /// 是否使用虚拟车辆 @@ -3367,7 +3350,8 @@ namespace NavisworksTransport.UI.WPF.ViewModels } // 统一准备碰撞检测(根据模式自动决定是否构建全局缓存) - ClashDetectiveIntegration.PrepareCollisionDetection(animatedObject, manualModeEnabled, manualTargets); + // 🔥 剖面盒纯模式下跳过全局缓存构建(剖面盒始终启用) + ClashDetectiveIntegration.PrepareCollisionDetection(animatedObject, manualModeEnabled, manualTargets, true); // 设置碰撞检测目标 if (manualModeEnabled) @@ -3405,8 +3389,8 @@ namespace NavisworksTransport.UI.WPF.ViewModels LogManager.Info($"[ExecuteGenerateAnimation] 准备调用CreateAnimation: UseVirtualObject={UseVirtualObject}, 车辆尺寸: {vLength:F2}×{vWidth:F2}×{vHeight:F2}模型单位, 安全间隙: {safetyMargin:F4}模型单位 (_safetyMargin={_safetyMargin:F4}米)"); - // 设置剖面盒优化开关 - _pathAnimationManager.SetUseSectionClip(UseSectionClip); + // 🔥 剖面盒优化始终启用(经测试验证有效) + _pathAnimationManager.SetUseSectionClip(true); _pathAnimationManager.CreateAnimation(animatedObject, pathPoints, AnimationDuration, CurrentPathRoute.Name, CurrentPathRoute.Id, UseVirtualObject, vLength, vWidth, vHeight, safetyMargin); diff --git a/src/UI/WPF/Views/AnimationControlView.xaml b/src/UI/WPF/Views/AnimationControlView.xaml index a2fbe19..3692e83 100644 --- a/src/UI/WPF/Views/AnimationControlView.xaml +++ b/src/UI/WPF/Views/AnimationControlView.xaml @@ -429,10 +429,7 @@ NavisworksTransport 检测动画页签视图 - 采用与类别设置和分层管 IsEnabled="{Binding CanGenerateAnimation}" Style="{StaticResource ActionButtonStyle}" Margin="0,0,10,0"/> - +