新增空间查询AABB范围查询功能,不再使用半径查询。

This commit is contained in:
tian 2026-02-08 06:55:07 +08:00
parent 71fe79a447
commit 5fdccf55c5
4 changed files with 105 additions and 11 deletions

View File

@ -7,6 +7,7 @@
1. [x] (功能)在碰撞报告中支持多张截图
2. [x] (功能)增加提取元素的包围盒信息,并一键拷贝到坐标编辑窗口
3. [x] (功能)在状态栏增加路径可视化快捷按钮
4. [x] (优化)利用通行空间过滤空间几何体,提高非手工指定模式的性能
### [2026/2/3]

View File

@ -792,7 +792,6 @@ namespace NavisworksTransport.Core.Animation
// 空间索引设置
SpatialIndexManager spatialIndexManager = null;
double searchRadiusInModelUnits = 0;
var manualTargetsSnapshot = new List<ModelItem>();
bool manualOverrideActive = _manualCollisionOverrideEnabled && _manualCollisionTargets != null && _manualCollisionTargets.Count > 0;
@ -844,13 +843,9 @@ namespace NavisworksTransport.Core.Animation
LogManager.Info(spatialIndexManager.GetStatistics());
// 🔥 修改:使用车辆的最大水平尺寸而不是对角线
// 原因:车辆在通道上水平移动,主要检测侧面碰撞
double maxHorizontalDimension = Math.Max(boundingBoxSize.X, boundingBoxSize.Y);
// 🔥 使用安全间隙计算空间查询半径 - _safetyMargin 已是模型单位
searchRadiusInModelUnits = maxHorizontalDimension + _safetyMargin;
LogManager.Info($"空间查询半径: {searchRadiusInModelUnits:F2} 模型单位 (基于最大水平尺寸: {maxHorizontalDimension:F2}, 安全间隙: {_safetyMargin:F4}模型单位)");
// 🔥 优化使用AABB查询代替球形查询查询范围更精确
// 不再预计算球形半径改为每帧计算车辆AABB + 安全间隙的搜索AABB
LogManager.Info($"空间查询使用AABB模式安全间隙: {_safetyMargin:F4}模型单位");
}
// 3. 生成每一帧
@ -1028,9 +1023,22 @@ namespace NavisworksTransport.Core.Animation
}
else
{
nearbyObjects = spatialIndexManager.FindNearbyObjects(
framePosition,
searchRadiusInModelUnits,
// 🔥 优化使用AABB查询代替球形查询避免球体扩大的无效范围
// 查询AABB = 车辆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
)
);
nearbyObjects = spatialIndexManager.FindInAABB(
searchBounds,
excludeObject: _animatedObject
);
}

View File

@ -219,6 +219,54 @@ namespace NavisworksTransport.Core.Spatial
return FindInRadius(center, radius, distanceFunc: null);
}
/// <summary>
/// AABB范围查询查找与指定AABB相交格子中的所有对象
/// 比球形查询更精确,避免球体扩大的无效范围
/// </summary>
/// <param name="boundsMin">AABB最小点</param>
/// <param name="boundsMax">AABB最大点</param>
/// <returns>范围内的对象列表(自动去重)</returns>
public List<T> FindInAABB(Vector3d boundsMin, Vector3d boundsMax)
{
var results = new HashSet<T>();
// 计算AABB覆盖的格子范围
var minGrid = _indexer.ToGrid(boundsMin);
var maxGrid = _indexer.ToGrid(boundsMax);
// 只遍历AABB覆盖的格子比球形查询更精确
for (int x = minGrid.x; x <= maxGrid.x; x++)
{
for (int y = minGrid.y; y <= maxGrid.y; y++)
{
for (int z = minGrid.z; z <= maxGrid.z; z++)
{
var gridCell = new Vector3i(x, y, z);
if (_grid.TryGetValue(gridCell, out var cellObjects))
{
foreach (var obj in cellObjects)
{
results.Add(obj);
}
}
}
}
}
return new List<T>(results);
}
/// <summary>
/// AABB范围查询使用Navisworks BoundingBox3D
/// </summary>
public List<T> FindInAABB(Autodesk.Navisworks.Api.BoundingBox3D bounds)
{
var min = new Vector3d(bounds.Min.X, bounds.Min.Y, bounds.Min.Z);
var max = new Vector3d(bounds.Max.X, bounds.Max.Y, bounds.Max.Z);
return FindInAABB(min, max);
}
/// <summary>
/// 清空所有数据
/// </summary>

View File

@ -237,6 +237,43 @@ namespace NavisworksTransport.Core.Spatial
return results;
}
/// <summary>
/// AABB范围查询查找与指定AABB相交的对象
/// 比球形查询更精确,避免球体扩大的无效范围
/// </summary>
/// <param name="bounds">查询AABBNavisworks BoundingBox3D</param>
/// <param name="excludeObject">要排除的对象</param>
/// <returns>与AABB相交格子中的对象列表</returns>
public List<ModelItem> FindInAABB(
BoundingBox3D bounds,
ModelItem excludeObject = null)
{
if (!_isInitialized)
{
throw new InvalidOperationException(
"[空间索引] 空间索引未初始化,请先调用 BuildGlobalIndex()");
}
try
{
// 直接使用AABB查询更精确
var nearbyObjects = _globalSpatialIndex.FindInAABB(bounds);
// 排除指定对象
if (excludeObject != null)
{
nearbyObjects = nearbyObjects.Where(obj => !obj.Equals(excludeObject)).ToList();
}
return nearbyObjects;
}
catch (Exception ex)
{
LogManager.Error($"[空间索引] AABB查询失败: {ex.Message}");
throw;
}
}
/// <summary>
/// 获取对象的缓存位置
/// </summary>