# geometry3Sharp 空间数据结构集成方案 ## 1. 背景与动机 ### 1.1 当前碰撞检测的性能瓶颈 NavisworksTransport 项目在物流路径动画中实现了碰撞检测功能,但存在以下性能问题: **当前实现的问题**: ```csharp // ClashDetectiveIntegration.cs - DetectCollisions() // 线性遍历所有几何对象,O(n) 复杂度 foreach (var item in allGeometryItems) { if (IsColliding(animatedObject, item)) { collisions.Add(item); } } ``` **性能数据**(来自实际日志): - 场景对象总数:290 个 - 潜在碰撞对象:108 个(经过路径包围盒预过滤) - 每帧碰撞检测:遍历 108 个对象 - 动画总帧数:300 帧 - **总计算量**:300 × 108 = 32,400 次包围盒检测 **优化空间**: 1. 空间查询仍然是线性遍历(即使经过预过滤) 2. 包围盒距离计算不精确(AABB vs 实际几何距离) 3. 没有层次化空间索引加速 4. 动态查询效率低(物体移动时重新遍历) ### 1.2 空间数据结构的必要性 **需求场景**: 1. **动画碰撞检测**:物体每帧移动,需要快速查询"当前位置附近有哪些障碍物" 2. **潜在碰撞对象过滤**:在路径规划前,快速找到路径沿途的所有可能碰撞物体 3. **精确距离计算**:计算物体到障碍物的真实距离(不是包围盒距离) 4. **路径可达性验证**:检查两点间的直线是否被障碍物阻挡 **理想的解决方案特征**: - ✅ O(log n) 或 O(1) 平均查询复杂度 - ✅ 支持动态位置的范围查询 - ✅ 精确的几何距离计算 - ✅ 商业友好的许可证 - ✅ 与 .NET Framework 4.8 兼容 --- ## 2. geometry3Sharp 库概述 ### 2.1 基本信息 **项目信息**: - **官方名称**:geometry3Sharp (本项目使用的是 fork: geometry4Sharp) - **GitHub**: (原版) - **GitHub**: (fork) - **许可证**:Boost Software License 1.0(商业友好,无需开源衍生代码) - **维护状态**:原版活跃度降低(2019后),fork 有维护 - **平台兼容**:.NET Standard 2.0, .NET Framework 4.8, .NET 6.0 - **语言**:纯 C#,无 C++ 互操作 **代码来源**: - 核心算法移植自 David Eberly 的 WildMagic5 和 GTEngine(几何计算领域的经典库) - MeshSignedDistanceGrid 基于 Christopher Batty 的 SDFGen C++ 代码 - 经过多年实战验证,代码质量高 ### 2.2 与体素网格方案的关系 **重要说明**:geometry3Sharp 不是替代体素网格方案,而是**互补关系**。 | 模块 | 用途 | 应用场景 | |------|------|---------| | **体素网格 (MeshSignedDistanceGrid, Bitmap3, DSparseGrid3)** | 3D 空间离散化,路径规划 | 生成可通行网格,3D A* 路径规划 | | **空间索引 (DMeshAABBTree3, PointHashGrid3d)** | 快速空间查询,碰撞检测 | 动画碰撞检测,范围查询优化 | | **距离查询 (DistPoint3Triangle3)** | 精确几何距离 | 碰撞容差计算,最近点查询 | | **相交查询 (IntrRay3Triangle3)** | 射线-几何相交 | 路径可达性验证,视线检测 | **集成策略**: - 体素网格用于**路径规划**(已在 `体素网格路径规划方案.md` 中详细设计) - 空间索引用于**碰撞检测加速**(本文档重点) - 两者共用 geometry3Sharp 的基础数学类型(Vector3d, AxisAlignedBox3d 等) --- ## 3. 高价值模块详细分析 ### 3.1 DMeshAABBTree3 - 层次化 AABB 树 #### 功能描述 `DMeshAABBTree3` 是三角网格的层次化轴对齐包围盒树,提供 O(log n) 复杂度的空间查询。 **核心特性**: - 自底向上或自顶向下构建策略(可选) - 支持三角形级别的精确相交测试 - 多种空间查询接口 - 泛型遍历接口(DoTraversal) **可用查询**: ```csharp // 1. 最近三角形查找 int FindNearestTriangle(Point3d point, double maxDistance); // 2. 射线-网格最近命中 int FindNearestHitTriangle(Ray3d ray, double maxDistance); // 3. 射线-网格所有命中 List FindAllHitTriangles(Ray3d ray, double maxDistance); // 4. 三角形相交测试 bool TestIntersection(Triangle3d triangle); // 5. 树-树相交测试 bool TestIntersection(DMeshAABBTree3 otherTree); // 6. 树-树所有相交 List> FindAllIntersections(DMeshAABBTree3 otherTree); // 7. 树-树范围内最近三角形 List> FindNearestTriangles(DMeshAABBTree3 otherTree, double maxDist); // 8. 点包含测试 bool IsInside(Point3d point); // 9. 缠绕数(Winding Number) double WindingNumber(Point3d point); ``` #### 应用场景 场景 1:优化 GetPotentialColliders()** 当前实现(线性遍历): ```csharp // PathAnimationManager.cs - GetPotentialColliders() foreach (var item in allGeometryItems) { double distance = CalculateDistance(pathCenter, item); if (distance <= detectionGap) { potentialColliders.Add(item); } } ``` 使用 AABB 树优化(对数查询): ```csharp // 1. 预构建场景的 AABB 树(一次性) var sceneTree = BuildSceneAABBTree(allGeometryItems); // 2. 快速范围查询 var potentialColliders = sceneTree.FindNearestTriangles( animatedObjectTree, detectionGap ); ``` **性能提升预估**: - 当前:O(n) = 290 次包围盒测试 - 优化后:O(log n) ≈ log₂(290) ≈ 8 次树节点遍历 - **加速比**:约 36 倍 场景 2:精确碰撞检测** 替代简单包围盒检测,使用三角形级别的精确相交: ```csharp // 检查动画对象是否与场景相交 bool hasCollision = animatedObjectTree.TestIntersection(sceneTree); // 获取所有相交的三角形对 var intersections = animatedObjectTree.FindAllIntersections(sceneTree); ``` #### 构建策略选择 ```csharp public enum BuildStrategy { TopDownMidpoint, // 最快(默认) BottomUpFromOneRings, // 平衡但慢 2.5 倍 TopDownMedian // 更平衡但慢 2-4 倍 } // 推荐:快速构建 + 大量查询场景 var tree = new DMeshAABBTree3(mesh, autoBuild: false); tree.Build(BuildStrategy.TopDownMidpoint); ``` #### 技术挑战 挑战 1:Navisworks Geometry → DMesh3 转换 Navisworks 的 `ModelItem` 不直接暴露三角网格,需要通过几何提取: ```csharp // 方案 A:使用 GeometryExtractor(项目已有) // 需要扩展为输出 geometry3Sharp 的 DMesh3 格式 // 方案 B:使用包围盒代替精确网格(简化版) // 优点:实现简单,性能好 // 缺点:精度降低(但对预过滤足够) ``` **推荐方案**:渐进式实现 1. **Phase 1**:使用包围盒近似(快速验证) 2. **Phase 2**:实现精确几何提取(提升精度) --- ### 3.2 PointHashGrid3d - 空间哈希网格 #### 功能描述 `PointHashGrid3d` 是泛型的 3D 空间哈希表,提供 O(1) 平均时间复杂度的范围查询。 **核心特性**: - 基于网格单元的哈希索引 - 支持动态插入/删除/更新 - 线程安全(SpinLock) - 泛型设计,可存储任意类型 **关键方法**: ```csharp // 初始化(cellSize = 查询半径的 1-2 倍) var grid = new PointHashGrid3d(cellSize: 2.0, invalidValue: null); // 插入点(线程安全) grid.InsertPoint(modelItem, position); // 删除点 grid.RemovePoint(modelItem, position); // 更新点(移动) grid.UpdatePoint(modelItem, oldPosition, newPosition); // 范围查询(核心功能) var nearby = grid.FindNearestInRadius( queryPosition, radius, distanceFunc: (item) => Distance(queryPosition, item.Position) ); // 批量查询 List FindPointsInBox(AxisAlignedBox3d box); ``` #### 应用场景 场景 1:加速动画碰撞检测 当前问题: - 动画每帧都要遍历 108 个潜在碰撞对象 - 300 帧 × 108 对象 = 32,400 次检测 使用空间哈希优化: ```csharp // === 初始化阶段(动画开始前)=== var spatialGrid = new PointHashGrid3d( cellSize: vehicleRadius * 2, // 格子大小 = 车辆直径 invalidValue: null ); // 索引所有障碍物(一次性) foreach (var obstacle in potentialColliders) { spatialGrid.InsertPoint(obstacle, obstacle.BoundingBox().Center); } // === 动画每帧 === // 快速查询当前位置附近的障碍物 var nearbyObstacles = spatialGrid.FindNearestInRadius( currentPosition, vehicleRadius + safetyMargin, (item) => Vector3d.Distance(item.Position, currentPosition) ); // 只检测附近的对象(通常 < 10 个) foreach (var obstacle in nearbyObstacles) { if (IsColliding(animatedObject, obstacle)) { collisions.Add(obstacle); } } ``` **性能提升预估**: - 当前:每帧检测 108 个对象 - 优化后:每帧检测 5-15 个对象(仅邻近格子) - **加速比**:约 7-20 倍 场景 2:动态场景更新 支持障碍物动态添加/移动: ```csharp // 添加新障碍物 spatialGrid.InsertPoint(newObstacle, newObstacle.Position); // 移动障碍物 spatialGrid.UpdatePoint(movingObstacle, oldPosition, newPosition); // 删除障碍物 spatialGrid.RemovePoint(removedObstacle, removedObstacle.Position); ``` #### 格子大小选择 **原则**:cellSize 应该接近查询半径 ```csharp // 推荐设置 double vehicleRadius = 0.3; // 米 double safetyMargin = 0.1; // 米 double detectionRadius = vehicleRadius + safetyMargin; // cellSize = 查询半径 * 1.5 double cellSize = detectionRadius * 1.5; // 约 0.6 米 var spatialGrid = new PointHashGrid3d(cellSize, null); ``` **权衡**: - cellSize 过小 → 格子太多,内存和查询开销大 - cellSize 过大 → 每个格子对象太多,退化为线性查询 --- ### 3.3 DistPoint3Triangle3 - 精确距离查询 #### 功能描述 计算点到三角形的最短距离及最近点位置。 **核心方法**: ```csharp var query = new DistPoint3Triangle3(point, triangle); double distance = query.Get(); // 最短距离 Vector3d closestPoint = query.TriangleClosest; // 三角形上最近点 int closestType = query.TriangleClosestType; // 最近点类型(顶点/边/面) ``` **相关类**: ```csharp DistPoint3Circle3 // 点到圆的距离 DistPoint3Cylinder3 // 点到圆柱的距离(带符号) DistLine3Triangle3 // 线段到三角形的距离 DistSegment3Triangle3 // 线段到三角形的距离 DistTriangle3Triangle3 // 三角形到三角形的距离 ``` #### 应用场景 场景 1:精确碰撞容差 当前问题: ```csharp // BoundingBoxGeometryUtils.cs - CalculateDistance() // 只计算包围盒中心的距离,不精确 double distance = Vector3.Distance(bbox1.Center, bbox2.Center); ``` 使用精确距离: ```csharp // 计算物体表面到障碍物表面的真实距离 foreach (var triangle1 in animatedObjectMesh.Triangles) { foreach (var triangle2 in obstacleMesh.Triangles) { var query = new DistTriangle3Triangle3(triangle1, triangle2); double distance = query.Get(); if (distance < collisionThreshold) { // 记录碰撞,包含精确距离和接触点 collisions.Add(new CollisionInfo { Distance = distance, ContactPoint1 = query.Triangle1Closest, ContactPoint2 = query.Triangle2Closest }); } } } ``` 场景 2:碰撞报告增强 在碰撞报告中显示: - 精确的间隙距离(而非包围盒距离) - 最近接触点的 3D 坐标 - 可视化最短距离向量 --- ### 3.4 IntrRay3Triangle3 - 射线相交查询 #### 功能描述 计算射线/线段与三角形的相交。 **核心方法**: ```csharp // 射线-三角形相交 var query = new IntrRay3Triangle3(ray, triangle); bool intersects = query.Find(); // 是否相交 double rayParameter = query.RayParameter; // 射线参数 t (交点 = ray.Origin + t * ray.Direction) Vector3d intersectionPoint = ray.PointAt(rayParameter); // 线段-三角形相交 var segmentQuery = new IntrSegment3Triangle3(segment, triangle); bool intersects = segmentQuery.Find(); ``` **相关类**: ```csharp IntrLine2Line2 // 2D 直线相交 IntrSegment2Segment2 // 2D 线段相交 IntrTriangle3Triangle3 // 3D 三角形相交 IntrRay3Box3 // 射线-AABB 相交 IntrRay3AxisAlignedBox3 // 射线-轴对齐盒相交 ``` #### 应用场景 场景 1:路径可达性验证 检查两点间的直线路径是否被障碍物阻挡: ```csharp /// /// 检查直线路径是否可达(无障碍物阻挡) /// public bool IsPathClear(Point3D start, Point3D end, IEnumerable obstacles) { Vector3d direction = (end - start).Normalized; double distance = Vector3d.Distance(start, end); var ray = new Ray3d(start, direction); foreach (var obstacleMesh in obstacles) { foreach (var triangleId in obstacleMesh.TriangleIndices()) { var triangle = GetTriangle(obstacleMesh, triangleId); var query = new IntrRay3Triangle3(ray, triangle); if (query.Find() && query.RayParameter < distance) { // 射线在到达终点前与障碍物相交 return false; } } } return true; // 路径畅通 } ``` 场景 2:视线检测 判断两个物体之间是否有遮挡: ```csharp // 检查从起重机到目标物体的视线是否被遮挡 bool hasLineOfSight = IsPathClear(crane.Position, targetObject.Position, obstacles); ``` **场景 3:改进 A* 路径规划** 在 A* 算法中增加射线检测,避免规划出会穿模的路径: ```csharp // 生成路径后,后处理优化 var optimizedPath = new List(); optimizedPath.Add(path[0]); for (int i = 0; i < path.Count - 1; i++) { // 尝试直接连接当前点和后续点 for (int j = path.Count - 1; j > i + 1; j--) { if (IsPathClear(path[i], path[j], obstacles)) { optimizedPath.Add(path[j]); i = j - 1; break; } } } ``` --- ## 4. 中等价值模块(可选) ### 4.1 Polygon2d - 2D 多边形操作 **功能**: - 点在多边形内测试(Contains) - 多边形简化(Simplify) - 多边形裁剪 - 多边形布尔运算 **应用场景**: - 楼层区域判断(路径点是否在楼层边界内) - 2D 路径规划(作为 3D 规划的补充) ### 4.2 ConvexHull2 - 2D 凸包 **功能**: - 计算点集的 2D 凸包 **应用场景**: - 楼层边界自动识别 - 路径覆盖区域计算 ### 4.3 MeshPlaneCut - 网格平面切割 **功能**: - 用平面切割三角网格 - 返回切割边界(EdgeLoop) **应用场景**: - 楼层切片(按高度切分建筑模型) - 断面分析(生成路径断面视图) --- ## 5. 集成架构设计 ### 5.1 整体架构 ```graph ┌─────────────────────────────────────────────────────────────┐ │ Navisworks API │ │ (ModelItem, BoundingBox3D, Geometry) │ └────────────────────────┬────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ NavisworksGeometryAdapter (新) │ │ - ModelItem → DMesh3 │ │ - Point3D ↔ Vector3d │ │ - BoundingBox3D ↔ AxisAlignedBox3d │ └────────────────────────┬────────────────────────────────────┘ │ ┌────────────┴────────────┐ ▼ ▼ ┌─────────────────────┐ ┌─────────────────────┐ │ SpatialIndexCache │ │ CollisionQueryHelper│ │ (新) │ │ (新) │ │ │ │ │ │ - SceneAABBTree │ │ - DistanceQuery │ │ - ObstacleHashGrid │ │ - IntersectionQuery │ │ - 缓存管理 │ │ - 精确碰撞检测 │ └──────────┬──────────┘ └──────────┬──────────┘ │ │ │ ┌─────────────────────┘ │ │ ▼ ▼ ┌─────────────────────────────────────────────────────────────┐ │ ClashDetectiveIntegration (改进) │ │ - GetPotentialColliders() → 使用 SpatialIndexCache │ │ - DetectCollisions() → 使用 CollisionQueryHelper │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ PathAnimationManager (无需修改) │ └─────────────────────────────────────────────────────────────┘ ``` ### 5.2 核心类设计 #### 5.2.1 NavisworksGeometryAdapter - 适配层 ```csharp /// /// Navisworks API 与 geometry3Sharp 之间的转换适配器 /// public static class NavisworksGeometryAdapter { #region 坐标转换 /// /// Navisworks Point3D → geometry3Sharp Vector3d /// public static Vector3d ToVector3d(this Point3D point) { return new Vector3d(point.X, point.Y, point.Z); } /// /// geometry3Sharp Vector3d → Navisworks Point3D /// public static Point3D ToPoint3D(this Vector3d vector) { return new Point3D(vector.x, vector.y, vector.z); } /// /// Navisworks BoundingBox3D → geometry3Sharp AxisAlignedBox3d /// public static AxisAlignedBox3d ToAxisAlignedBox3d(this BoundingBox3D bbox) { return new AxisAlignedBox3d( bbox.Min.ToVector3d(), bbox.Max.ToVector3d() ); } #endregion #region 几何提取 /// /// 从 ModelItem 提取三角网格(简化版:使用包围盒) /// public static DMesh3 ExtractMeshSimple(ModelItem item) { var bbox = item.BoundingBox(); var mesh = new DMesh3(); // 将包围盒转为 8 个顶点 + 12 个三角形 // (简化实现,适用于快速验证) AddBoxToMesh(mesh, bbox.ToAxisAlignedBox3d()); return mesh; } /// /// 从 ModelItem 提取精确三角网格(完整版,Phase 2 实现) /// public static DMesh3 ExtractMeshAccurate(ModelItem item) { // TODO: 使用 GeometryExtractor 获取实际三角形 // 需要遍历 Navisworks Geometry API throw new NotImplementedException("Phase 2"); } #endregion } ``` #### 5.2.2 SpatialIndexCache - 空间索引缓存 ```csharp /// /// 场景空间索引缓存管理器 /// 在动画开始前预构建空间索引,动画过程中复用 /// public class SpatialIndexCache { private static SpatialIndexCache _instance; public static SpatialIndexCache Instance => _instance ??= new SpatialIndexCache(); // 场景 AABB 树(用于精确查询) private DMeshAABBTree3 _sceneAABBTree; // 障碍物空间哈希网格(用于快速范围查询) private PointHashGrid3d _obstacleHashGrid; // 缓存版本(检测场景变化) private int _cacheVersion = 0; #region 构建方法 /// /// 构建场景的空间索引 /// public void BuildSpatialIndex( IEnumerable obstacles, double hashGridCellSize) { LogManager.Info("[空间索引] 开始构建..."); var sw = Stopwatch.StartNew(); // 1. 构建 AABB 树 var sceneMesh = CombineMeshes(obstacles); _sceneAABBTree = new DMeshAABBTree3(sceneMesh, autoBuild: true); LogManager.Info($"[空间索引] AABB 树构建完成,节点数: {_sceneAABBTree.MaxLeafSize}"); // 2. 构建空间哈希网格 _obstacleHashGrid = new PointHashGrid3d(hashGridCellSize, null); foreach (var obstacle in obstacles) { var center = obstacle.BoundingBox().Center.ToVector3d(); _obstacleHashGrid.InsertPoint(obstacle, center); } LogManager.Info($"[空间索引] 哈希网格构建完成,格子大小: {hashGridCellSize}m"); _cacheVersion++; sw.Stop(); LogManager.Info($"[空间索引] 构建完成,耗时: {sw.ElapsedMilliseconds}ms"); } #endregion #region 查询方法 /// /// 快速范围查询(使用哈希网格) /// public List FindNearbyObstacles(Point3D center, double radius) { if (_obstacleHashGrid == null) throw new InvalidOperationException("空间索引未初始化"); var centerVec = center.ToVector3d(); var nearby = new List(); // 哈希网格范围查询 // 注意:PointHashGrid3d 没有直接的 FindNearestInRadius 方法 // 需要手动实现或使用 FindPointsInBox var searchBox = new AxisAlignedBox3d(centerVec, radius); // 遍历搜索框内的所有格子(简化实现) // 实际应该调用哈希网格的范围查询方法 // 这里需要根据 geometry3Sharp 的实际 API 调整 return nearby; } /// /// 精确相交查询(使用 AABB 树) /// public bool TestIntersection(DMesh3 objectMesh) { if (_sceneAABBTree == null) throw new InvalidOperationException("空间索引未初始化"); var objectTree = new DMeshAABBTree3(objectMesh, autoBuild: true); return _sceneAABBTree.TestIntersection(objectTree); } #endregion #region 辅助方法 private DMesh3 CombineMeshes(IEnumerable items) { var combinedMesh = new DMesh3(); foreach (var item in items) { var itemMesh = NavisworksGeometryAdapter.ExtractMeshSimple(item); var editor = new MeshEditor(combinedMesh); editor.AppendMesh(itemMesh); } return combinedMesh; } #endregion } ``` #### 5.2.3 CollisionQueryHelper - 碰撞查询助手 ```csharp /// /// 精确碰撞查询辅助类 /// public static class CollisionQueryHelper { /// /// 计算物体到障碍物的最短距离 /// public static double CalculateMinDistance( ModelItem movingObject, ModelItem obstacle) { var mesh1 = NavisworksGeometryAdapter.ExtractMeshSimple(movingObject); var mesh2 = NavisworksGeometryAdapter.ExtractMeshSimple(obstacle); double minDistance = double.MaxValue; // 遍历所有三角形对,找到最短距离 foreach (var tri1Id in mesh1.TriangleIndices()) { var tri1 = GetTriangle(mesh1, tri1Id); foreach (var tri2Id in mesh2.TriangleIndices()) { var tri2 = GetTriangle(mesh2, tri2Id); var query = new DistTriangle3Triangle3(tri1, tri2); double distance = query.Get(); if (distance < minDistance) { minDistance = distance; } } } return minDistance; } /// /// 检查射线路径是否畅通 /// public static bool IsPathClear( Point3D start, Point3D end, DMeshAABBTree3 sceneTree) { var direction = (end.ToVector3d() - start.ToVector3d()).Normalized; var distance = Vector3d.Distance(start.ToVector3d(), end.ToVector3d()); var ray = new Ray3d(start.ToVector3d(), direction); // 使用 AABB 树快速查询射线相交 int hitTriangle = sceneTree.FindNearestHitTriangle(ray); if (hitTriangle == DMesh3.InvalidID) return true; // 无相交 // 检查相交点是否在起终点之间 // TODO: 需要获取相交点位置并比较距离 return false; } private static Triangle3d GetTriangle(DMesh3 mesh, int triangleId) { var tri = mesh.GetTriangle(triangleId); var v0 = mesh.GetVertex(tri.a); var v1 = mesh.GetVertex(tri.b); var v2 = mesh.GetVertex(tri.c); return new Triangle3d(v0, v1, v2); } } ``` ### 5.3 集成到现有系统 #### 修改 ClashDetectiveIntegration.cs ```csharp // 在 GetPotentialColliders() 中使用空间索引 private List GetPotentialColliders() { // 1. 计算路径包围盒 var pathBounds = CalculatePathBounds(); var pathCenter = GetBoundingBoxCenter(pathBounds); var detectionRadius = GetBoundingBoxDiagonal(pathBounds) / 2; // 2. 使用空间哈希网格快速查询 var potentialColliders = SpatialIndexCache.Instance.FindNearbyObstacles( pathCenter, detectionRadius ); LogManager.Info($"空间索引查询结果: {potentialColliders.Count} 个潜在碰撞对象"); return potentialColliders; } ``` --- ## 6. 实施方案 ### 6.1 分阶段实施 #### Phase 1: PointHashGrid3d 集成(2-3 天,立即可用) **目标**:使用空间哈希网格优化动画碰撞检测。 **任务**: 1. 创建 `NavisworksGeometryAdapter` 类(坐标转换) 2. 创建 `SpatialIndexCache` 类(仅哈希网格部分) 3. 修改 `ClashDetectiveIntegration.GetPotentialColliders()` 使用哈希网格 4. 修改动画碰撞检测使用哈希网格查询 5. 性能测试和日志记录 **验收标准**: - ✅ 动画碰撞检测速度提升 5-10 倍 - ✅ 日志显示每帧实际检测的对象数量减少 - ✅ 功能正确性不变(碰撞结果与原方案一致) --- #### Phase 2: DMeshAABBTree3 优化(1 周) **目标**:构建场景 AABB 树,优化范围查询和相交检测。 **任务**: 1. 实现 `NavisworksGeometryAdapter.ExtractMeshSimple()`(使用包围盒) 2. 在 `SpatialIndexCache` 中添加 AABB 树构建 3. 使用 AABB 树优化 `FindNearestTriangles()` 查询 4. 实现精确相交检测(替代简单包围盒测试) 5. 性能对比测试 **验收标准**: - ✅ AABB 树构建时间 < 5 秒(中等场景) - ✅ 范围查询速度提升 10-30 倍 - ✅ 支持精确三角形级别的碰撞检测 --- #### Phase 3: 精确距离和相交查询(可选,3-5 天) **目标**:使用精确几何查询提升碰撞报告质量。 **任务**: 1. 创建 `CollisionQueryHelper` 类 2. 实现精确距离计算(DistTriangle3Triangle3) 3. 实现路径可达性验证(IntrRay3Triangle3) 4. 在碰撞报告中显示精确距离和接触点 5. (可选)实现 `ExtractMeshAccurate()` 精确几何提取 **验收标准**: - ✅ 碰撞报告显示精确距离(非包围盒距离) - ✅ 支持路径可达性验证功能 - ✅ 性能可接受(精确查询耗时 < 2x 简化查询) --- ### 6.2 时间与资源估算 | 阶段 | 任务 | 工作量 | 依赖 | |------|------|--------|------| | Phase 1 | PointHashGrid3d 集成 | 2-3 天 | geometry3Sharp | | Phase 2 | DMeshAABBTree3 优化 | 5-7 天 | Phase 1 | | Phase 3 | 精确查询(可选)| 3-5 天 | Phase 2 | | **总计** | | **10-15 天** | | --- ## 7. 技术挑战与缓解 ### 7.1 Navisworks API 限制 **挑战**:Navisworks 的 `ModelItem` 不直接暴露三角网格数据。 **缓解措施**: - ✅ **Phase 1**:使用包围盒代替精确网格(快速验证) - ✅ **Phase 2**:研究 `GeometryExtractor` 提取实际几何 - ✅ **Phase 3**:实现 Navisworks Geometry API → DMesh3 转换器 ### 7.2 坐标系转换 **挑战**:Navisworks API 和 geometry3Sharp 使用不同的类型系统。 **缓解措施**: - ✅ 创建 `NavisworksGeometryAdapter` 适配层 - ✅ 统一使用模型单位(避免米制/英制混淆) - ✅ 单元测试验证转换正确性 ### 7.3 性能权衡 **挑战**:空间索引构建有初始开销。 **缓解措施**: - ✅ 在动画开始前预构建(用户点击"生成动画"时) - ✅ 缓存索引(场景不变时复用) - ✅ 显示进度条(让用户知道正在构建) --- ## 8. 性能预期 ### 8.1 性能对比(预估) 基于类似规模的空间索引系统经验: | 操作 | 当前实现 | Phase 1 (哈希) | Phase 2 (AABB树) | |------|---------|---------------|-----------------| | **范围查询** | O(n) = 290次 | O(1) ≈ 10次 | O(log n) ≈ 8次 | | **碰撞检测** | 32,400次/动画 | 3,000次/动画 | 2,400次/动画 | | **构建开销** | 0 秒 | 0.1 秒 | 2-5 秒 | | **内存占用** | 0 MB | +10 MB | +50 MB | **场景假设**: - 对象总数:290 个 - 动画帧数:300 帧 - 潜在碰撞对象:108 个(经过预过滤) ### 8.2 预期加速比 **Phase 1 完成后**: - 每帧碰撞检测:108 对象 → 10 对象 - **加速比**:约 10 倍 **Phase 2 完成后**: - 范围查询:O(n) → O(log n) - **加速比**:约 30-50 倍(组合效果) --- ## 9. 与体素网格方案的关系 ### 9.1 互补关系说明 | 方案 | 主要用途 | 数据结构 | 查询类型 | |------|---------|---------|---------| | **体素网格** | 路径规划 | 3D 网格 + SDF | 可通行性、路径搜索 | | **空间索引** | 碰撞检测 | AABB树、哈希网格 | 范围查询、相交测试 | ### 9.2 共用基础设施 两个方案共享 geometry3Sharp 的基础组件: - 数学类型(Vector3d, AxisAlignedBox3d) - 坐标转换适配器(NavisworksGeometryAdapter) - 几何提取工具 ### 9.3 集成策略 ```graph geometry3Sharp 基础库 ├── 体素网格模块 (用于路径规划) │ ├── MeshSignedDistanceGrid │ ├── Bitmap3 / DSparseGrid3 │ └── VoxelGrid (自定义) │ └── 空间索引模块 (用于碰撞检测) ├── DMeshAABBTree3 ├── PointHashGrid3d └── Distance/Intersection 查询 ``` --- ## 10. 不适用的模块 以下 geometry3Sharp 模块**不适用于本项目**: ### 10.1 网格编辑类 - **Remesher**, **Reducer**, **MeshEditor** - **原因**:Navisworks 是只读查看器,不支持修改网格几何 ### 10.2 曲线生成类 - **NURBSCurve2**, **BezierCurve** - **原因**:项目使用折线路径,不需要复杂曲线拟合 ### 10.3 网格修复类 - **MeshAutoRepair**, **RemoveDuplicateTriangles** - **原因**:Navisworks 模型已优化,无法运行时修改 ### 10.4 布尔运算类 - **MeshBoolean** - **原因**:文档明确说"不是健壮的布尔运算",且 Navisworks API 不支持 --- ## 11. 实施建议 ### 11.1 推荐的实施优先级 **立即实施(高优先级)**: 1. ✅ **PointHashGrid3d** → 快速见效,大幅提升动画碰撞检测性能 **短期实施(中优先级)**: 2. ✅ **DMeshAABBTree3** → 进一步优化,支持精确相交检测 **长期考虑(低优先级)**: 3. ⚠️ **精确距离查询** → 功能增强,非关键路径 4. ⚠️ **射线相交查询** → 路径验证功能,可选 ### 11.2 风险提示 **不要全盘集成 geometry3Sharp**,应该: - ✅ 只提取需要的类(避免依赖膨胀) - ✅ 创建适配层(隔离外部依赖) - ✅ 渐进式验证(每个 Phase 独立验收) --- ## 12. 参考资料 ### 12.1 geometry3Sharp 资源 - **GitHub(原版)**: - **GitHub(fork)**: - **NuGet**:geometry4Sharp 1.0.0 - **原作者**:Ryan Schmidt (@rms80) - **算法来源**:WildMagic5/GTEngine (David Eberly) ### 12.2 理论基础 - **空间哈希网格**: - "Spatial Hashing for 3D Grids" - Teschner et al., 2003 - "Optimized Spatial Hashing for Collision Detection of Deformable Objects" - **AABB 树**: - "OBBTree: A Hierarchical Structure for Rapid Interference Detection" (Gottschalk et al., 1996) - "Fast Collision Detection Using AABB Trees" - Real-Time Rendering - **距离查询**: - "Distance Between Point and Triangle in 3D" - David Eberly, Geometric Tools - "Fast Distance Queries for Triangles, Lines and Points using SSE" ### 12.3 相关文档 - 《体素网格路径规划方案.md》- 路径规划部分 - 《PATHFINDING_DESIGN.md》- A* 算法设计 - 《寻路算法的对比.md》- 算法选型依据 --- ## 13. 总结 ### 13.1 核心价值 1. ✅ **显著的性能提升**:碰撞检测加速 10-50 倍 2. ✅ **商业友好许可证**:Boost License,无需开源 3. ✅ **成熟稳定的代码**:源自经典几何库 WildMagic5 4. ✅ **渐进式集成**:分阶段实施,风险可控 5. ✅ **互补体素方案**:两者协同,各司其职 ### 13.2 建议行动 **立即行动**: 1. 安装 geometry4Sharp NuGet 包 2. 实施 Phase 1(PointHashGrid3d) 3. 测试性能提升 **后续行动**: - Phase 1 验证后,评估是否继续 Phase 2 - 与体素网格方案协同推进 ### 13.3 成功标准 - ✅ 动画碰撞检测速度提升 10 倍以上 - ✅ 构建开销可接受(< 5 秒) - ✅ 内存占用增加 < 100 MB - ✅ 功能正确性保持不变 - ✅ 代码可维护性良好 --- **文档版本**: v1.0 **创建日期**: 2025-10-14 **最后更新**: 2025-10-14 **作者**: NavisworksTransport 开发团队 **相关文档**: 《体素网格路径规划方案.md》