NavisworksTransport/doc/working/2025-01-08-multi-layer-gridmap-solution.md

5.7 KiB
Raw Blame History

多高度层GridMap解决方案

日期: 2025-01-08 问题: 楼梯与楼板在同一(x,y)坐标重叠时2D网格投影导致互相覆盖 目标: 支持多高度层同时保留RoyT.AStar高性能算法


问题分析

场景描述

  • 楼梯: 倾斜通道,在(x,y)位置有不同Z高度
  • 楼梯下方楼板: 水平通道,在相同(x,y)位置也可通行
  • 当前问题: 两者投影到同一2D网格坐标(x,y),后处理的覆盖前处理的

核心矛盾

  • 2D网格投影系统无法处理垂直空间层叠
  • 起点在楼面(Z=3.0m),终点在楼梯(Z=5.0m)的路径无法正确规划

解决方案

核心思路

  1. 保留RoyT.AStar: 2D A*算法不变继续产生最优2D路径
  2. 扩展数据结构: GridCell支持多个HeightLayer
  3. 投影改为追加: 通道投影不覆盖,而是添加新层
  4. 路径后处理选层: A*产生2D路径后为每个路径点智能选择高度层

关键洞察

  • 2D路径已经最优: RoyT.AStar产生的2D网格序列[(x1,y1), (x2,y2), ..., (xn,yn)]不需要改变
  • 只需选Z坐标: 为每个2D点选择正确的高度层形成3D路径
  • 基于高度趋势: 根据当前位置到终点的剩余高度变化,选择最合适的层

技术设计

1. 数据结构扩展

HeightLayer结构

public struct HeightLayer
{
    public double Z;                      // 该层的Z坐标
    public HeightInterval PassableHeight; // 可通行高度范围(用于车辆检查)
    public ModelItem SourceItem;          // 来源模型项
    public double SpeedLimit;             // 限速
    public CategoryAttributeManager.LogisticsElementType Type; // 层类型
}

GridCell扩展

public struct GridCell
{
    // ... 保留所有现有字段 ...

    // 新增:多高度层支持
    public List<HeightLayer> HeightLayers { get; set; }
}

2. 通道投影改为追加模式

文件: src/PathPlanning/ChannelBasedGridBuilder.cs 方法: RasterizeTriangleToGrid()

修改前:

var cell = GridCellBuilder.Channel(preciseWorldPosition, channel, channelSpeedLimit);
gridMap.PlaceCell(gridPos, cell); // 覆盖

修改后:

var layer = new HeightLayer
{
    Z = gridCenterHeight,
    PassableHeight = new HeightInterval(0, 0), // 初始化,后续设置
    SourceItem = channel,
    SpeedLimit = channelSpeedLimit,
    Type = CategoryAttributeManager.GetLogisticsElementType(channel)
};
gridMap.AddHeightLayer(gridPos, layer); // 追加

3. PassableHeight计算适配

保留现有逻辑: SetChannelPassableHeights() 已经很完善 修改点: 从设置单层GridCell改为设置多个HeightLayer

// 为每个高度层设置PassableHeight
if (cell.HeightLayers != null && cell.HeightLayers.Any())
{
    for (int i = 0; i < cell.HeightLayers.Count; i++)
    {
        var layer = cell.HeightLayers[i];
        layer.PassableHeight = new HeightInterval(0, scanHeightInModelUnits);
        cell.HeightLayers[i] = layer;
    }
}

4. 路径后处理智能选层

核心算法: AssignLayerBased3DCoordinates()

选层策略:

1. 起点锁定: 选择包含start.Z的层
2. 终点锁定: 选择包含end.Z的层
3. 中间点选层:
   - 计算剩余高度变化: remainingHeight = end.Z - current.Z
   - 计算期望每步变化: desiredChange = remainingHeight / remainingSteps
   - 目标Z: targetZ = prevZ + desiredChange
   - 选择最接近targetZ且净空足够的层

示例执行:

场景: 起点楼面(3.0m) → 终点楼梯(5.0m)
2D路径: [(0,0), (1,1), (2,2), (3,3)]

赋值过程:
1. (0,0): Z=3.0 (起点锁定楼面层)
2. (1,1): remainingHeight=2.0, steps=2, desiredChange=1.0
         targetZ=4.0, 选择楼梯层3.5m (更接近4.0)
3. (2,2): remainingHeight=1.5, steps=1, desiredChange=1.5
         targetZ=5.0, 选择楼梯层4.5m
4. (3,3): Z=5.0 (终点锁定楼梯层)

最终路径: [(0,0,3.0), (1,1,3.5), (2,2,4.5), (3,3,5.0)]
✅ 平滑爬升!

实施计划

步骤1: 扩展GridCell支持多层

  • 文件: src/PathPlanning/GridMap.cs
  • 内容: 新增HeightLayer结构、扩展GridCell、添加AddHeightLayer()和FindLayerContainingZ()方法

步骤2: 通道投影改为追加模式

  • 文件: src/PathPlanning/ChannelBasedGridBuilder.cs
  • 内容: 修改RasterizeTriangleToGrid()从PlaceCell改为AddHeightLayer

步骤3: 适配PassableHeight计算

  • 文件: src/PathPlanning/GridMapGenerator.cs
  • 内容: 修改SetChannelPassableHeights()支持多层

步骤4: 实现智能选层算法

  • 文件: src/PathPlanning/AutoPathFinder.cs
  • 内容: 新增AssignLayerBased3DCoordinates()和SelectBestLayer()方法,替换现有路径后处理

步骤5: 测试验证

  • 起点楼面 → 终点楼梯(验证爬升)
  • 起点楼梯 → 终点楼面(验证下降)
  • 楼梯下方通行(验证多层并存)

关键约束

  1. 保留RoyT.AStar: 不修改A*算法,保持高性能
  2. 不考虑向后兼容: 直接改为多层架构
  3. 保留现有PassableHeight逻辑: 只适配到多层结构
  4. 最小化改动: 只修改必要的数据结构和投影逻辑

预期效果

  • 解决楼梯-楼板重叠问题
  • 自动选择最优高度层
  • 平滑的高度过渡
  • 保持RoyT.AStar高性能
  • 代码改动最小化

文件修改清单

  1. src/PathPlanning/GridMap.cs - 数据结构扩展
  2. src/PathPlanning/ChannelBasedGridBuilder.cs - 投影逻辑修改
  3. src/PathPlanning/GridMapGenerator.cs - PassableHeight计算适配
  4. src/PathPlanning/AutoPathFinder.cs - 路径后处理智能选层

状态: 设计完成,待实施 预计工作量: 4个文件约200行代码修改