集成剖面盒到预计算过程

This commit is contained in:
tian 2026-02-12 13:29:41 +08:00
parent 949c7ed6b5
commit 73c26601fd
5 changed files with 185 additions and 33 deletions

View File

@ -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<ModelItem> _sectionClipObjects = null; // 剖面盒模式下的局部对象缓存
private List<Point3D> _pathPoints;
private List<ModelItem> _manualCollisionTargets = new List<ModelItem>();
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 ? "" : "")}");
}
/// <summary>
/// 设置是否使用剖面盒纯模式(独立控制)
/// </summary>
/// <param name="useOnlyMode">true=只用剖面盒false=剖面盒+空间索引</param>
public void SetUseSectionClipOnlyMode(bool useOnlyMode)
{
_useSectionClipOnlyMode = useOnlyMode;
LogManager.Info($"[PathAnimationManager] 剖面盒纯模式{(useOnlyMode ? "" : "")}");
}
/// <summary>
@ -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
/// <summary>
/// 构建剖面盒内的局部对象缓存
/// 遍历模型树,只收集与剖面盒相交的对象,并排除可通行对象
/// </summary>
/// <returns>剖面盒内的对象列表(已排除可通行对象)</returns>
private List<ModelItem> BuildObjectsInClipBox()
{
var objectsInClipBox = new List<ModelItem>();
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<ModelItem>(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
}
}

View File

@ -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(() =>

View File

@ -1640,8 +1640,9 @@ namespace NavisworksTransport
/// <param name="animatedObject">运动物体</param>
/// <param name="isManualMode">是否为手工指定检测对象模式</param>
/// <param name="manualTargets">手工指定的检测目标(仅在手工模式下使用)</param>
/// <param name="useSectionClipOnlyMode">是否使用剖面盒纯模式(跳过全局缓存)</param>
/// <returns>是否成功准备</returns>
public static bool PrepareCollisionDetection(ModelItem animatedObject, bool isManualMode, List<ModelItem> manualTargets = null)
public static bool PrepareCollisionDetection(ModelItem animatedObject, bool isManualMode, List<ModelItem> 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;
}

View File

@ -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
/// <summary>
/// 是否使用选择的模型物体
/// </summary>
/// <summary>
/// 是否使用剖面盒优化(用于性能对比测试)
/// </summary>
public bool UseSectionClip
{
get => _useSectionClip;
set
{
if (SetProperty(ref _useSectionClip, value))
{
LogManager.Info($"[剖面盒] 优化开关已{(value ? "" : "")}");
}
}
}
/// <summary>
/// 是否使用虚拟车辆
@ -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);

View File

@ -429,10 +429,7 @@ NavisworksTransport 检测动画页签视图 - 采用与类别设置和分层管
IsEnabled="{Binding CanGenerateAnimation}"
Style="{StaticResource ActionButtonStyle}"
Margin="0,0,10,0"/>
<CheckBox Content="使用剖面盒优化"
IsChecked="{Binding UseSectionClip}"
VerticalAlignment="Center"
ToolTip="启用剖面盒可大幅提升大型模型的碰撞检测性能(用于性能对比测试)"/>
</StackPanel>
<!-- 生成状态提示 -->