# 多高度层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结构 ```csharp public struct HeightLayer { public double Z; // 该层的Z坐标 public HeightInterval PassableHeight; // 可通行高度范围(用于物体检查) public ModelItem SourceItem; // 来源模型项 public double SpeedLimit; // 限速 public CategoryAttributeManager.LogisticsElementType Type; // 层类型 } ``` #### GridCell扩展 ```csharp public struct GridCell { // ... 保留所有现有字段 ... // 新增:多高度层支持 public List HeightLayers { get; set; } } ``` ### 2. 通道投影改为追加模式 **文件**: `src/PathPlanning/ChannelBasedGridBuilder.cs` **方法**: `RasterizeTriangleToGrid()` **修改前**: ```csharp var cell = GridCellBuilder.Channel(preciseWorldPosition, channel, channelSpeedLimit); gridMap.PlaceCell(gridPos, cell); // 覆盖 ``` **修改后**: ```csharp 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 ```csharp // 为每个高度层设置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行代码修改