diff --git a/doc/requirement/todo_features.md b/doc/requirement/todo_features.md index 5725724..9083e99 100644 --- a/doc/requirement/todo_features.md +++ b/doc/requirement/todo_features.md @@ -7,6 +7,7 @@ 1. [x] (功能)在碰撞报告中支持多张截图 2. [x] (功能)增加提取元素的包围盒信息,并一键拷贝到坐标编辑窗口 3. [x] (功能)在状态栏增加路径可视化快捷按钮 +4. [x] (优化)利用通行空间过滤空间几何体,提高非手工指定模式的性能 ### [2026/2/3] diff --git a/src/Core/Animation/PathAnimationManager.cs b/src/Core/Animation/PathAnimationManager.cs index 8ab4606..8e14e79 100644 --- a/src/Core/Animation/PathAnimationManager.cs +++ b/src/Core/Animation/PathAnimationManager.cs @@ -792,7 +792,6 @@ namespace NavisworksTransport.Core.Animation // 空间索引设置 SpatialIndexManager spatialIndexManager = null; - double searchRadiusInModelUnits = 0; var manualTargetsSnapshot = new List(); 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 ); } diff --git a/src/Core/Spatial/SpatialHashGrid.cs b/src/Core/Spatial/SpatialHashGrid.cs index 40c83ba..67c2ce2 100644 --- a/src/Core/Spatial/SpatialHashGrid.cs +++ b/src/Core/Spatial/SpatialHashGrid.cs @@ -219,6 +219,54 @@ namespace NavisworksTransport.Core.Spatial return FindInRadius(center, radius, distanceFunc: null); } + /// + /// AABB范围查询:查找与指定AABB相交格子中的所有对象 + /// 比球形查询更精确,避免球体扩大的无效范围 + /// + /// AABB最小点 + /// AABB最大点 + /// 范围内的对象列表(自动去重) + public List FindInAABB(Vector3d boundsMin, Vector3d boundsMax) + { + var results = new HashSet(); + + // 计算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(results); + } + + /// + /// AABB范围查询(使用Navisworks BoundingBox3D) + /// + public List 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); + } + /// /// 清空所有数据 /// diff --git a/src/Core/Spatial/SpatialIndexManager.cs b/src/Core/Spatial/SpatialIndexManager.cs index d4549d0..9af43ed 100644 --- a/src/Core/Spatial/SpatialIndexManager.cs +++ b/src/Core/Spatial/SpatialIndexManager.cs @@ -237,6 +237,43 @@ namespace NavisworksTransport.Core.Spatial return results; } + /// + /// AABB范围查询:查找与指定AABB相交的对象 + /// 比球形查询更精确,避免球体扩大的无效范围 + /// + /// 查询AABB(Navisworks BoundingBox3D) + /// 要排除的对象 + /// 与AABB相交格子中的对象列表 + public List 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; + } + } + /// /// 获取对象的缓存位置 ///