NavisworksTransport/doc/design/2026/geometry3Sharp空间数据结构集成方案.md
tian b05bb727c6 refactor: 完成 DataBindingPerformanceMonitor 功能的完整删除
- 删除 DataBindingPerformanceMonitor.cs 文件
- 从 NavisworksTransportPlugin.csproj 移除编译引用
- 清理 ViewModelBase.cs 中的所有性能监控代码
- 清理 ThreadSafeObservableCollection.cs 中的性能监控集成
- 清理 SmartDataBindingOptimizer.cs 中的性能监控使用
- 清理 BindingExpressionOptimizer.cs 中的性能监控调用

该功能不再需要,移除后简化了代码结构
2025-10-14 15:01:26 +08:00

34 KiB
Raw Blame History

geometry3Sharp 空间数据结构集成方案

1. 背景与动机

1.1 当前碰撞检测的性能瓶颈

NavisworksTransport 项目在物流路径动画中实现了碰撞检测功能,但存在以下性能问题:

当前实现的问题

// 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 基本信息

项目信息

代码来源

  • 核心算法移植自 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

可用查询

// 1. 最近三角形查找
int FindNearestTriangle(Point3d point, double maxDistance);

// 2. 射线-网格最近命中
int FindNearestHitTriangle(Ray3d ray, double maxDistance);

// 3. 射线-网格所有命中
List<int> FindAllHitTriangles(Ray3d ray, double maxDistance);

// 4. 三角形相交测试
bool TestIntersection(Triangle3d triangle);

// 5. 树-树相交测试
bool TestIntersection(DMeshAABBTree3 otherTree);

// 6. 树-树所有相交
List<Tuple<int,int>> FindAllIntersections(DMeshAABBTree3 otherTree);

// 7. 树-树范围内最近三角形
List<Tuple<int,int>> FindNearestTriangles(DMeshAABBTree3 otherTree, double maxDist);

// 8. 点包含测试
bool IsInside(Point3d point);

// 9. 缠绕数Winding Number
double WindingNumber(Point3d point);

应用场景

场景 1优化 GetPotentialColliders()**

当前实现(线性遍历):

// PathAnimationManager.cs - GetPotentialColliders()
foreach (var item in allGeometryItems)
{
    double distance = CalculateDistance(pathCenter, item);
    if (distance <= detectionGap)
    {
        potentialColliders.Add(item);
    }
}

使用 AABB 树优化(对数查询):

// 1. 预构建场景的 AABB 树(一次性)
var sceneTree = BuildSceneAABBTree(allGeometryItems);

// 2. 快速范围查询
var potentialColliders = sceneTree.FindNearestTriangles(
    animatedObjectTree,
    detectionGap
);

性能提升预估

  • 当前O(n) = 290 次包围盒测试
  • 优化后O(log n) ≈ log₂(290) ≈ 8 次树节点遍历
  • 加速比:约 36 倍

场景 2精确碰撞检测**

替代简单包围盒检测,使用三角形级别的精确相交:

// 检查动画对象是否与场景相交
bool hasCollision = animatedObjectTree.TestIntersection(sceneTree);

// 获取所有相交的三角形对
var intersections = animatedObjectTree.FindAllIntersections(sceneTree);

构建策略选择

public enum BuildStrategy
{
    TopDownMidpoint,        // 最快(默认)
    BottomUpFromOneRings,   // 平衡但慢 2.5 倍
    TopDownMedian           // 更平衡但慢 2-4 倍
}

// 推荐:快速构建 + 大量查询场景
var tree = new DMeshAABBTree3(mesh, autoBuild: false);
tree.Build(BuildStrategy.TopDownMidpoint);

技术挑战

挑战 1Navisworks Geometry → DMesh3 转换

Navisworks 的 ModelItem 不直接暴露三角网格,需要通过几何提取:

// 方案 A使用 GeometryExtractor项目已有
// 需要扩展为输出 geometry3Sharp 的 DMesh3 格式

// 方案 B使用包围盒代替精确网格简化版
// 优点:实现简单,性能好
// 缺点:精度降低(但对预过滤足够)

推荐方案:渐进式实现

  1. Phase 1:使用包围盒近似(快速验证)
  2. Phase 2:实现精确几何提取(提升精度)

3.2 PointHashGrid3d - 空间哈希网格

功能描述

PointHashGrid3d<T> 是泛型的 3D 空间哈希表,提供 O(1) 平均时间复杂度的范围查询。

核心特性

  • 基于网格单元的哈希索引
  • 支持动态插入/删除/更新
  • 线程安全SpinLock
  • 泛型设计,可存储任意类型

关键方法

// 初始化cellSize = 查询半径的 1-2 倍)
var grid = new PointHashGrid3d<ModelItem>(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<T> FindPointsInBox(AxisAlignedBox3d box);

应用场景

场景 1加速动画碰撞检测

当前问题:

  • 动画每帧都要遍历 108 个潜在碰撞对象
  • 300 帧 × 108 对象 = 32,400 次检测

使用空间哈希优化:

// === 初始化阶段(动画开始前)===
var spatialGrid = new PointHashGrid3d<ModelItem>(
    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动态场景更新

支持障碍物动态添加/移动:

// 添加新障碍物
spatialGrid.InsertPoint(newObstacle, newObstacle.Position);

// 移动障碍物
spatialGrid.UpdatePoint(movingObstacle, oldPosition, newPosition);

// 删除障碍物
spatialGrid.RemovePoint(removedObstacle, removedObstacle.Position);

格子大小选择

原则cellSize 应该接近查询半径

// 推荐设置
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<ModelItem>(cellSize, null);

权衡

  • cellSize 过小 → 格子太多,内存和查询开销大
  • cellSize 过大 → 每个格子对象太多,退化为线性查询

3.3 DistPoint3Triangle3 - 精确距离查询

功能描述

计算点到三角形的最短距离及最近点位置。

核心方法

var query = new DistPoint3Triangle3(point, triangle);
double distance = query.Get();             // 最短距离
Vector3d closestPoint = query.TriangleClosest;  // 三角形上最近点
int closestType = query.TriangleClosestType;    // 最近点类型(顶点/边/面)

相关类

DistPoint3Circle3      // 点到圆的距离
DistPoint3Cylinder3    // 点到圆柱的距离(带符号)
DistLine3Triangle3     // 线段到三角形的距离
DistSegment3Triangle3  // 线段到三角形的距离
DistTriangle3Triangle3 // 三角形到三角形的距离

应用场景

场景 1精确碰撞容差

当前问题:

// BoundingBoxGeometryUtils.cs - CalculateDistance()
// 只计算包围盒中心的距离,不精确
double distance = Vector3.Distance(bbox1.Center, bbox2.Center);

使用精确距离:

// 计算物体表面到障碍物表面的真实距离
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 - 射线相交查询

功能描述

计算射线/线段与三角形的相交。

核心方法

// 射线-三角形相交
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();

相关类

IntrLine2Line2          // 2D 直线相交
IntrSegment2Segment2    // 2D 线段相交
IntrTriangle3Triangle3  // 3D 三角形相交
IntrRay3Box3            // 射线-AABB 相交
IntrRay3AxisAlignedBox3 // 射线-轴对齐盒相交

应用场景

场景 1路径可达性验证

检查两点间的直线路径是否被障碍物阻挡:

/// <summary>
/// 检查直线路径是否可达(无障碍物阻挡)
/// </summary>
public bool IsPathClear(Point3D start, Point3D end, IEnumerable<DMesh3> 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视线检测

判断两个物体之间是否有遮挡:

// 检查从起重机到目标物体的视线是否被遮挡
bool hasLineOfSight = IsPathClear(crane.Position, targetObject.Position, obstacles);

场景 3改进 A 路径规划*

在 A* 算法中增加射线检测,避免规划出会穿模的路径:

// 生成路径后,后处理优化
var optimizedPath = new List<Point3D>();
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 整体架构

┌─────────────────────────────────────────────────────────────┐
│                     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 - 适配层

/// <summary>
/// Navisworks API 与 geometry3Sharp 之间的转换适配器
/// </summary>
public static class NavisworksGeometryAdapter
{
    #region 坐标转换

    /// <summary>
    /// Navisworks Point3D → geometry3Sharp Vector3d
    /// </summary>
    public static Vector3d ToVector3d(this Point3D point)
    {
        return new Vector3d(point.X, point.Y, point.Z);
    }

    /// <summary>
    /// geometry3Sharp Vector3d → Navisworks Point3D
    /// </summary>
    public static Point3D ToPoint3D(this Vector3d vector)
    {
        return new Point3D(vector.x, vector.y, vector.z);
    }

    /// <summary>
    /// Navisworks BoundingBox3D → geometry3Sharp AxisAlignedBox3d
    /// </summary>
    public static AxisAlignedBox3d ToAxisAlignedBox3d(this BoundingBox3D bbox)
    {
        return new AxisAlignedBox3d(
            bbox.Min.ToVector3d(),
            bbox.Max.ToVector3d()
        );
    }

    #endregion

    #region 几何提取

    /// <summary>
    /// 从 ModelItem 提取三角网格(简化版:使用包围盒)
    /// </summary>
    public static DMesh3 ExtractMeshSimple(ModelItem item)
    {
        var bbox = item.BoundingBox();
        var mesh = new DMesh3();

        // 将包围盒转为 8 个顶点 + 12 个三角形
        // (简化实现,适用于快速验证)
        AddBoxToMesh(mesh, bbox.ToAxisAlignedBox3d());

        return mesh;
    }

    /// <summary>
    /// 从 ModelItem 提取精确三角网格完整版Phase 2 实现)
    /// </summary>
    public static DMesh3 ExtractMeshAccurate(ModelItem item)
    {
        // TODO: 使用 GeometryExtractor 获取实际三角形
        // 需要遍历 Navisworks Geometry API
        throw new NotImplementedException("Phase 2");
    }

    #endregion
}

5.2.2 SpatialIndexCache - 空间索引缓存

/// <summary>
/// 场景空间索引缓存管理器
/// 在动画开始前预构建空间索引,动画过程中复用
/// </summary>
public class SpatialIndexCache
{
    private static SpatialIndexCache _instance;
    public static SpatialIndexCache Instance => _instance ??= new SpatialIndexCache();

    // 场景 AABB 树(用于精确查询)
    private DMeshAABBTree3 _sceneAABBTree;

    // 障碍物空间哈希网格(用于快速范围查询)
    private PointHashGrid3d<ModelItem> _obstacleHashGrid;

    // 缓存版本(检测场景变化)
    private int _cacheVersion = 0;

    #region 构建方法

    /// <summary>
    /// 构建场景的空间索引
    /// </summary>
    public void BuildSpatialIndex(
        IEnumerable<ModelItem> 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<ModelItem>(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 查询方法

    /// <summary>
    /// 快速范围查询(使用哈希网格)
    /// </summary>
    public List<ModelItem> FindNearbyObstacles(Point3D center, double radius)
    {
        if (_obstacleHashGrid == null)
            throw new InvalidOperationException("空间索引未初始化");

        var centerVec = center.ToVector3d();
        var nearby = new List<ModelItem>();

        // 哈希网格范围查询
        // 注意PointHashGrid3d 没有直接的 FindNearestInRadius 方法
        // 需要手动实现或使用 FindPointsInBox
        var searchBox = new AxisAlignedBox3d(centerVec, radius);

        // 遍历搜索框内的所有格子(简化实现)
        // 实际应该调用哈希网格的范围查询方法
        // 这里需要根据 geometry3Sharp 的实际 API 调整

        return nearby;
    }

    /// <summary>
    /// 精确相交查询(使用 AABB 树)
    /// </summary>
    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<ModelItem> 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 - 碰撞查询助手

/// <summary>
/// 精确碰撞查询辅助类
/// </summary>
public static class CollisionQueryHelper
{
    /// <summary>
    /// 计算物体到障碍物的最短距离
    /// </summary>
    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;
    }

    /// <summary>
    /// 检查射线路径是否畅通
    /// </summary>
    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

// 在 GetPotentialColliders() 中使用空间索引
private List<ModelItem> 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 集成策略

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 资源

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 1PointHashGrid3d
  3. 测试性能提升

后续行动

  • Phase 1 验证后,评估是否继续 Phase 2
  • 与体素网格方案协同推进

13.3 成功标准

  • 动画碰撞检测速度提升 10 倍以上
  • 构建开销可接受(< 5 秒)
  • 内存占用增加 < 100 MB
  • 功能正确性保持不变
  • 代码可维护性良好

文档版本: v1.0 创建日期: 2025-10-14 最后更新: 2025-10-14 作者: NavisworksTransport 开发团队 相关文档: 《体素网格路径规划方案.md》