diff --git a/src/Core/Animation/PathAnimationManager.cs b/src/Core/Animation/PathAnimationManager.cs index a19f614..b18849e 100644 --- a/src/Core/Animation/PathAnimationManager.cs +++ b/src/Core/Animation/PathAnimationManager.cs @@ -377,17 +377,36 @@ namespace NavisworksTransport.Core.Animation originalBoundingBox.Max.Y - originalBoundingBox.Min.Y, originalBoundingBox.Max.Z - originalBoundingBox.Min.Z ); - - // 获取场景中所有可能碰撞的对象 - var potentialColliders = GetPotentialColliders(); - LogManager.Info($"潜在碰撞对象数: {potentialColliders.Count}"); - + + // 【新架构】构建全局空间索引(单层架构) + LogManager.Info("=== 构建全局空间索引 ==="); + var spatialIndexManager = SpatialIndexManager.Instance; + + // 使用包围盒对角线作为网格大小的参考(确保合理的网格粒度) + double cellSizeInModelUnits = Math.Max( + boundingBoxSize.X, + Math.Max(boundingBoxSize.Y, boundingBoxSize.Z) + ); + + spatialIndexManager.BuildGlobalIndex(cellSizeInModelUnits); + LogManager.Info(spatialIndexManager.GetStatistics()); + + // 计算搜索半径:动画对象包围盒的对角线 + 检测间隙 + double objectDiagonal = Math.Sqrt( + boundingBoxSize.X * boundingBoxSize.X + + boundingBoxSize.Y * boundingBoxSize.Y + + boundingBoxSize.Z * boundingBoxSize.Z + ); + double searchRadiusInModelUnits = objectDiagonal / 2 + _detectionGap; + + LogManager.Info($"空间查询半径: {searchRadiusInModelUnits:F2} 模型单位"); + // 预计算每一帧 for (int i = 0; i < totalFrames; i++) { double progress = (double)i / totalFrames; var framePosition = InterpolatePosition(progress); - + // 创建帧数据 var frame = new AnimationFrame { @@ -396,12 +415,19 @@ namespace NavisworksTransport.Core.Animation Position = framePosition, Collisions = new List() }; - + // 虚拟碰撞检测(不移动实际物体) var virtualBoundingBox = CreateVirtualBoundingBox(framePosition, boundingBoxSize); - - // 检测与所有潜在对象的碰撞 - foreach (var collider in potentialColliders) + + // 【新架构】使用空间索引查询附近对象 + var nearbyObjects = spatialIndexManager.FindNearbyObjects( + framePosition, + searchRadiusInModelUnits, + excludeObject: _animatedObject + ); + + // 检测与附近对象的碰撞 + foreach (var collider in nearbyObjects) { var colliderBox = collider.BoundingBox(); @@ -455,122 +481,6 @@ namespace NavisworksTransport.Core.Animation } } - /// - /// 获取潜在碰撞对象列表 - /// - private List GetPotentialColliders() - { - try - { - LogManager.Info("开始获取潜在碰撞对象"); - - // 构建通道缓存 - ClashDetectiveIntegration.Instance.BuildChannelObjectsCache(); - ClashDetectiveIntegration.BuildAllGeometryItemsCache(); - - // 获取所有有几何体的对象 - var allItems = NavisApplication.ActiveDocument.Models.RootItemDescendantsAndSelf - .Where(item => item.HasGeometry) - .ToList(); - - // 构建排除列表:动画对象本身及其子对象 - var excludeList = new ModelItemCollection(); - excludeList.AddRange(_animatedObject.DescendantsAndSelf); - - // 计算路径包围盒 - var pathBounds = CalculatePathBounds(); - - // 计算路径包围盒中心点(模型单位) - var pathCenter = new Point3D( - (pathBounds.Min.X + pathBounds.Max.X) / 2, - (pathBounds.Min.Y + pathBounds.Max.Y) / 2, - (pathBounds.Min.Z + pathBounds.Max.Z) / 2 - ); - - // 计算包围盒对角线长度 - var diagonal = Math.Sqrt( - Math.Pow(pathBounds.Max.X - pathBounds.Min.X, 2) + - Math.Pow(pathBounds.Max.Y - pathBounds.Min.Y, 2) + - Math.Pow(pathBounds.Max.Z - pathBounds.Min.Z, 2) - ); - - // 检测半径 = 包围盒对角线的一半(精确覆盖整条路径) - var detectionGap = diagonal / 2; - - LogManager.Info($"路径包围盒: Min=({pathBounds.Min.X:F2}, {pathBounds.Min.Y:F2}, {pathBounds.Min.Z:F2}), " + - $"Max=({pathBounds.Max.X:F2}, {pathBounds.Max.Y:F2}, {pathBounds.Max.Z:F2})"); - LogManager.Info($"路径中心: ({pathCenter.X:F2}, {pathCenter.Y:F2}, {pathCenter.Z:F2})"); - LogManager.Info($"包围盒对角线: {diagonal:F2} 模型单位"); - - // 临时移动物体到路径中心,以便在路径范围内检测潜在碰撞对象 - var offset = ModelItemTransformHelper.MoveItemToPosition(_animatedObject, pathCenter); - - try - { - LogManager.Info($"检测半径: {detectionGap:F2} 模型单位(对角线的一半)"); - - // 调用ClashDetectiveIntegration的DetectCollisions方法 - // 现在物体在路径中心,检测路径长度半径内的对象 - // 该方法内部会自动排除通道对象(通过IsChannelObject方法) - var collisionResults = ClashDetectiveIntegration.Instance.DetectCollisions( - _animatedObject, - excludeList, - detectionGap - ); - - // 从碰撞结果中提取唯一的碰撞对象 - var potentialColliders = new HashSet(); - foreach (var result in collisionResults) - { - if (result.Item2 != null && !potentialColliders.Contains(result.Item2)) - { - potentialColliders.Add(result.Item2); - } - } - - var finalList = potentialColliders.ToList(); - - LogManager.Info($"获取潜在碰撞对象完成: 总对象={allItems.Count}, " + - $"排除自身及子对象={excludeList.Count}, " + - $"路径沿途潜在碰撞对象={finalList.Count}(已自动排除通道)"); - - return finalList; - } - finally - { - // 恢复物体到原位置 - ModelItemTransformHelper.RestoreItemPosition(_animatedObject, offset); - LogManager.Info("物体已恢复到原始位置"); - } - } - catch (Exception ex) - { - LogManager.Error($"获取潜在碰撞对象失败: {ex.Message}"); - return new List(); - } - } - - /// - /// 计算路径的包围盒 - /// - private BoundingBox3D CalculatePathBounds() - { - if (_pathPoints == null || _pathPoints.Count == 0) - return new BoundingBox3D(); - - var minX = _pathPoints.Min(p => p.X); - var minY = _pathPoints.Min(p => p.Y); - var minZ = _pathPoints.Min(p => p.Z); - var maxX = _pathPoints.Max(p => p.X); - var maxY = _pathPoints.Max(p => p.Y); - var maxZ = _pathPoints.Max(p => p.Z); - - return new BoundingBox3D( - new Point3D(minX, minY, minZ), - new Point3D(maxX, maxY, maxZ) - ); - } - /// /// 创建虚拟包围盒(用于碰撞检测) ///