集成剖面盒到预计算过程
This commit is contained in:
parent
949c7ed6b5
commit
73c26601fd
@ -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
|
||||
}
|
||||
}
|
||||
@ -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(() =>
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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>
|
||||
|
||||
<!-- 生成状态提示 -->
|
||||
|
||||
Loading…
Reference in New Issue
Block a user