给网格增加了高度层概念,试图支持楼面上的楼梯,还不完善
This commit is contained in:
parent
a8e8760e2b
commit
9ccf925964
194
doc/working/2025-01-08-multi-layer-gridmap-solution.md
Normal file
194
doc/working/2025-01-08-multi-layer-gridmap-solution.md
Normal file
@ -0,0 +1,194 @@
|
||||
# 多高度层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<HeightLayer> 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行代码修改
|
||||
@ -105,8 +105,8 @@ namespace NavisworksTransport.PathPlanning
|
||||
.Select(point => (point, gridMap.WorldToGrid(point)))
|
||||
.ToList();
|
||||
|
||||
// 6. 根据网格点通行高度区间对路径点Z坐标调整
|
||||
var enhancedPath = ApplyGridHeightConstraints(pathWithGridCoords, gridMap, vehicleHeight);
|
||||
// 6. 根据网格点通行高度区间对路径点Z坐标调整(传递原始坐标以保留用户指定的Z值)
|
||||
var enhancedPath = ApplyGridHeightConstraints(pathWithGridCoords, gridMap, vehicleHeight, originalStart, originalEnd);
|
||||
|
||||
// 7. 验证路径中所有点的高度约束(直接使用原始网格坐标,因为网格位置未变)
|
||||
ValidatePathHeightConstraints(pathWithGridCoords, gridMap, vehicleHeight);
|
||||
@ -214,34 +214,24 @@ namespace NavisworksTransport.PathPlanning
|
||||
}
|
||||
|
||||
// 检查基本可通行性和高度约束
|
||||
bool isPassable = cell.IsWalkable;
|
||||
bool isPassable = IsPassableWithHeight(cell, vehicleHeight);
|
||||
|
||||
if (isPassable)
|
||||
if (cell.IsWalkable && !isPassable)
|
||||
{
|
||||
if (cell.PassableHeight.MaxZ > cell.PassableHeight.MinZ)
|
||||
{
|
||||
// vehicleHeight已经是模型单位,直接比较即可
|
||||
bool heightOk = cell.PassableHeight.GetSpan() >= vehicleHeight;
|
||||
if (!heightOk)
|
||||
{
|
||||
heightConstrainedCells++;
|
||||
// 本来可通行但被高度约束排除
|
||||
heightConstrainedCells++;
|
||||
|
||||
// 详细日志:记录被高度约束排除的单元格(仅记录前10个避免日志过多)
|
||||
if (heightConstrainedCells <= 10)
|
||||
{
|
||||
LogManager.Info($"[A*高度约束] 单元格({x},{y})被高度约束排除:车辆高度{vehicleHeight:F2}模型单位,可用区间:{cell.PassableHeight.MinZ:F2}-{cell.PassableHeight.MaxZ:F2}(跨度{cell.PassableHeight.GetSpan():F2})");
|
||||
}
|
||||
else if (heightConstrainedCells == 11)
|
||||
{
|
||||
LogManager.Info($"[A*高度约束] 还有更多单元格被高度约束排除,不再详细记录...");
|
||||
}
|
||||
}
|
||||
isPassable = heightOk;
|
||||
}
|
||||
else
|
||||
// 详细日志:记录被高度约束排除的单元格(仅记录前10个避免日志过多)
|
||||
if (heightConstrainedCells <= 10)
|
||||
{
|
||||
// 没有高度信息的网格直接标记为不可通行
|
||||
isPassable = false;
|
||||
var layerInfo = cell.HeightLayers != null && cell.HeightLayers.Count > 0
|
||||
? $"有{cell.HeightLayers.Count}个高度层"
|
||||
: "无高度层";
|
||||
LogManager.Info($"[A*高度约束] 单元格({x},{y})被高度约束排除:车辆高度{vehicleHeight:F2}模型单位,{layerInfo}");
|
||||
}
|
||||
else if (heightConstrainedCells == 11)
|
||||
{
|
||||
LogManager.Info($"[A*高度约束] 还有更多单元格被高度约束排除,不再详细记录...");
|
||||
}
|
||||
}
|
||||
|
||||
@ -255,11 +245,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
if (x + 1 < gridMap.Width)
|
||||
{
|
||||
var rightCell = gridMap.Cells[x + 1, y];
|
||||
bool rightPassable = rightCell.IsWalkable;
|
||||
if (rightPassable && rightCell.PassableHeight.MaxZ > rightCell.PassableHeight.MinZ)
|
||||
{
|
||||
rightPassable = rightCell.PassableHeight.GetSpan() >= vehicleHeight;
|
||||
}
|
||||
bool rightPassable = IsPassableWithHeight(rightCell, vehicleHeight);
|
||||
if (rightPassable)
|
||||
{
|
||||
var rightPos = new GridPosition(x + 1, y);
|
||||
@ -273,11 +259,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
if (y + 1 < gridMap.Height)
|
||||
{
|
||||
var bottomCell = gridMap.Cells[x, y + 1];
|
||||
bool bottomPassable = bottomCell.IsWalkable;
|
||||
if (bottomPassable && bottomCell.PassableHeight.MaxZ > bottomCell.PassableHeight.MinZ)
|
||||
{
|
||||
bottomPassable = bottomCell.PassableHeight.GetSpan() >= vehicleHeight;
|
||||
}
|
||||
bool bottomPassable = IsPassableWithHeight(bottomCell, vehicleHeight);
|
||||
if (bottomPassable)
|
||||
{
|
||||
var bottomPos = new GridPosition(x, y + 1);
|
||||
@ -291,11 +273,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
if (x - 1 >= 0)
|
||||
{
|
||||
var leftCell = gridMap.Cells[x - 1, y];
|
||||
bool leftPassable = leftCell.IsWalkable;
|
||||
if (leftPassable && leftCell.PassableHeight.MaxZ > leftCell.PassableHeight.MinZ)
|
||||
{
|
||||
leftPassable = leftCell.PassableHeight.GetSpan() >= vehicleHeight;
|
||||
}
|
||||
bool leftPassable = IsPassableWithHeight(leftCell, vehicleHeight);
|
||||
if (leftPassable)
|
||||
{
|
||||
var leftPos = new GridPosition(x - 1, y);
|
||||
@ -309,11 +287,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
if (y - 1 >= 0)
|
||||
{
|
||||
var topCell = gridMap.Cells[x, y - 1];
|
||||
bool topPassable = topCell.IsWalkable;
|
||||
if (topPassable && topCell.PassableHeight.MaxZ > topCell.PassableHeight.MinZ)
|
||||
{
|
||||
topPassable = topCell.PassableHeight.GetSpan() >= vehicleHeight;
|
||||
}
|
||||
bool topPassable = IsPassableWithHeight(topCell, vehicleHeight);
|
||||
if (topPassable)
|
||||
{
|
||||
var topPos = new GridPosition(x, y - 1);
|
||||
@ -430,16 +404,10 @@ namespace NavisworksTransport.PathPlanning
|
||||
var cell = gridMap.Cells[x, y];
|
||||
|
||||
// 检查基本可通行性和高度约束
|
||||
bool isPassable = cell.IsWalkable;
|
||||
if (isPassable && cell.PassableHeight.MaxZ > cell.PassableHeight.MinZ)
|
||||
bool isPassable = IsPassableWithHeight(cell, vehicleHeight);
|
||||
if (cell.IsWalkable && !isPassable)
|
||||
{
|
||||
// vehicleHeight已经是模型单位,直接比较即可
|
||||
bool heightOk = cell.PassableHeight.GetSpan() >= vehicleHeight;
|
||||
if (!heightOk)
|
||||
{
|
||||
heightConstrainedCells++;
|
||||
isPassable = false;
|
||||
}
|
||||
heightConstrainedCells++;
|
||||
}
|
||||
|
||||
if (isPassable)
|
||||
@ -581,10 +549,15 @@ namespace NavisworksTransport.PathPlanning
|
||||
if (!cell.IsWalkable)
|
||||
return false;
|
||||
|
||||
if (cell.PassableHeight.MaxZ > cell.PassableHeight.MinZ)
|
||||
// 检查是否有任何高度层满足车辆高度要求
|
||||
if (cell.HeightLayers != null && cell.HeightLayers.Count > 0)
|
||||
{
|
||||
// vehicleHeight已经是模型单位,直接比较即可
|
||||
return cell.PassableHeight.GetSpan() >= vehicleHeight;
|
||||
foreach (var layer in cell.HeightLayers)
|
||||
{
|
||||
if (layer.PassableHeight.GetSpan() >= vehicleHeight)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -1210,23 +1183,32 @@ namespace NavisworksTransport.PathPlanning
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查高度约束
|
||||
if (cell.PassableHeight.MaxZ > cell.PassableHeight.MinZ)
|
||||
// 检查高度层约束
|
||||
if (cell.HeightLayers != null && cell.HeightLayers.Count > 0)
|
||||
{
|
||||
bool spanOk = cell.PassableHeight.GetSpan() >= vehicleHeight;
|
||||
// 将绝对坐标转换为相对于网格底面的坐标
|
||||
double relativeZ = point.Z - cell.WorldPosition.Z;
|
||||
bool containsHeight = cell.PassableHeight.Contains(relativeZ);
|
||||
// 查找包含指定Z坐标且满足车辆高度的层
|
||||
var matchingLayer = gridMap.FindLayerContainingZ(gridPos, point.Z, tolerance: 0.5);
|
||||
|
||||
if (spanOk && containsHeight)
|
||||
if (matchingLayer.HasValue)
|
||||
{
|
||||
return true;
|
||||
bool heightOk = matchingLayer.Value.PassableHeight.GetSpan() >= vehicleHeight;
|
||||
if (heightOk)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogManager.Warning($"[高度检查] ❌ 找到匹配Z={point.Z:F2}的层Z={matchingLayer.Value.Z:F2},但高度不足:车辆高度{vehicleHeight:F2},层高度跨度{matchingLayer.Value.PassableHeight.GetSpan():F2}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogManager.Warning($"[高度检查] ❌ 单元格({gridX}, {gridY})有{cell.HeightLayers.Count}个高度层,但无法找到包含Z={point.Z:F2}的层");
|
||||
}
|
||||
|
||||
LogManager.Warning($"[高度检查] ❌ 高度区间不满足要求:({gridX}, {gridY}) - PassableHeight=[{cell.PassableHeight.MinZ:F2}, {cell.PassableHeight.MaxZ:F2}], VehicleHeight={vehicleHeight:F2}, RelativeZ={relativeZ:F2}, SpanOK={spanOk}, ContainsHeight={containsHeight}, 原因:高度约束不满足");
|
||||
return false;
|
||||
}
|
||||
|
||||
LogManager.Warning($"[高度检查] ❌ 单元格({gridX}, {gridY})没有高度层信息");
|
||||
return false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -1242,16 +1224,35 @@ namespace NavisworksTransport.PathPlanning
|
||||
/// <param name="pathWithGridCoords">路径点和对应的网格坐标</param>
|
||||
/// <param name="gridMap">网格地图</param>
|
||||
/// <param name="vehicleHeight">车辆高度(模型单位)</param>
|
||||
/// <param name="originalStart">用户指定的原始起点(保留原始Z坐标)</param>
|
||||
/// <param name="originalEnd">用户指定的原始终点(保留原始Z坐标)</param>
|
||||
/// <returns>调整后的路径</returns>
|
||||
private List<Point3D> ApplyGridHeightConstraints(List<(Point3D point, GridPoint2D gridPos)> pathWithGridCoords, GridMap gridMap, double vehicleHeight)
|
||||
private List<Point3D> ApplyGridHeightConstraints(List<(Point3D point, GridPoint2D gridPos)> pathWithGridCoords, GridMap gridMap, double vehicleHeight, Point3D originalStart, Point3D originalEnd)
|
||||
{
|
||||
LogManager.Info($"[应用高度区间] 开始调整,路径点数: {pathWithGridCoords.Count}");
|
||||
LogManager.Info($"[智能选层] 开始为路径点选择最优高度层,路径点数: {pathWithGridCoords.Count}");
|
||||
|
||||
if (pathWithGridCoords.Count == 0)
|
||||
return new List<Point3D>();
|
||||
|
||||
var adjustedPath = new List<Point3D>();
|
||||
int adjustedCount = 0;
|
||||
|
||||
foreach (var (point, gridPos) in pathWithGridCoords)
|
||||
// 1. 使用用户指定的原始起点和终点Z坐标(而不是从转换后的路径中提取)
|
||||
double startZ = originalStart.Z;
|
||||
double endZ = originalEnd.Z;
|
||||
|
||||
// 对比日志:显示原始坐标与路径坐标的差异
|
||||
var pathStartZ = pathWithGridCoords[0].point.Z;
|
||||
var pathEndZ = pathWithGridCoords[pathWithGridCoords.Count - 1].point.Z;
|
||||
|
||||
LogManager.Info($"[智能选层] 原始起点Z={startZ:F3}, 原始终点Z={endZ:F3}");
|
||||
LogManager.Info($"[智能选层] 路径起点Z={pathStartZ:F3}, 路径终点Z={pathEndZ:F3}");
|
||||
LogManager.Info($"[智能选层] 使用原始Z坐标进行智能选层,高度变化={endZ - startZ:F3}");
|
||||
|
||||
// 2. 为每个路径点选择高度层
|
||||
for (int i = 0; i < pathWithGridCoords.Count; i++)
|
||||
{
|
||||
var (point, gridPos) = pathWithGridCoords[i];
|
||||
|
||||
// 检查网格位置有效性
|
||||
if (!gridMap.IsValidGridPosition(gridPos))
|
||||
{
|
||||
@ -1261,25 +1262,133 @@ namespace NavisworksTransport.PathPlanning
|
||||
|
||||
var cell = gridMap.Cells[gridPos.X, gridPos.Y];
|
||||
|
||||
// 检查单个高度区间是否满足车辆高度要求
|
||||
if (cell.PassableHeight.GetSpan() >= vehicleHeight)
|
||||
// 如果没有高度层,使用原始点
|
||||
if (cell.HeightLayers == null || cell.HeightLayers.Count == 0)
|
||||
{
|
||||
// 使用高度区间的底部作为最优Z坐标
|
||||
var optimalZ = cell.WorldPosition.Z + cell.PassableHeight.MinZ;
|
||||
adjustedPath.Add(new Point3D(point.X, point.Y, optimalZ));
|
||||
adjustedPath.Add(point);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 起点和终点:锁定到包含其Z坐标的层
|
||||
if (i == 0)
|
||||
{
|
||||
var selectedLayer = SelectBestLayer(cell.HeightLayers, startZ, vehicleHeight, startZ, endZ, i, pathWithGridCoords.Count, true);
|
||||
if (selectedLayer.HasValue)
|
||||
{
|
||||
adjustedPath.Add(new Point3D(point.X, point.Y, selectedLayer.Value.Z));
|
||||
LogManager.Debug($"[智能选层] 起点({gridPos.X},{gridPos.Y}) Z={selectedLayer.Value.Z:F3}");
|
||||
}
|
||||
else
|
||||
{
|
||||
adjustedPath.Add(point);
|
||||
}
|
||||
}
|
||||
else if (i == pathWithGridCoords.Count - 1)
|
||||
{
|
||||
var selectedLayer = SelectBestLayer(cell.HeightLayers, endZ, vehicleHeight, startZ, endZ, i, pathWithGridCoords.Count, true);
|
||||
if (selectedLayer.HasValue)
|
||||
{
|
||||
adjustedPath.Add(new Point3D(point.X, point.Y, selectedLayer.Value.Z));
|
||||
LogManager.Debug($"[智能选层] 终点({gridPos.X},{gridPos.Y}) Z={selectedLayer.Value.Z:F3}");
|
||||
}
|
||||
else
|
||||
{
|
||||
adjustedPath.Add(point);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 高度不足,保持原始点
|
||||
adjustedPath.Add(point);
|
||||
// 中间点:根据高度趋势选择最佳层
|
||||
var prevZ = adjustedPath[i - 1].Z;
|
||||
var selectedLayer = SelectBestLayer(cell.HeightLayers, prevZ, vehicleHeight, startZ, endZ, i, pathWithGridCoords.Count, false);
|
||||
|
||||
if (selectedLayer.HasValue)
|
||||
{
|
||||
adjustedPath.Add(new Point3D(point.X, point.Y, selectedLayer.Value.Z));
|
||||
}
|
||||
else
|
||||
{
|
||||
adjustedPath.Add(point);
|
||||
}
|
||||
}
|
||||
adjustedCount++;
|
||||
}
|
||||
|
||||
LogManager.Info($"[应用高度区间] 完成,调整了 {adjustedCount}/{pathWithGridCoords.Count} 个点");
|
||||
LogManager.Info($"[智能选层] 完成,调整了 {adjustedPath.Count}/{pathWithGridCoords.Count} 个点");
|
||||
return adjustedPath;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 为路径点选择最佳高度层
|
||||
/// </summary>
|
||||
/// <param name="layers">可用的高度层列表</param>
|
||||
/// <param name="referenceZ">参考Z坐标(起点/终点为目标Z,中间点为前一点Z)</param>
|
||||
/// <param name="vehicleHeight">车辆高度</param>
|
||||
/// <param name="startZ">路径起点Z</param>
|
||||
/// <param name="endZ">路径终点Z</param>
|
||||
/// <param name="currentIndex">当前点索引</param>
|
||||
/// <param name="totalPoints">总点数</param>
|
||||
/// <param name="exactMatch">是否精确匹配(起点/终点使用)</param>
|
||||
/// <returns>选中的高度层,如果没有合适的返回null</returns>
|
||||
private HeightLayer? SelectBestLayer(List<HeightLayer> layers, double referenceZ, double vehicleHeight,
|
||||
double startZ, double endZ, int currentIndex, int totalPoints, bool exactMatch)
|
||||
{
|
||||
if (layers == null || layers.Count == 0)
|
||||
return null;
|
||||
|
||||
// 只有一层,直接返回
|
||||
if (layers.Count == 1)
|
||||
{
|
||||
var layer = layers[0];
|
||||
if (layer.PassableHeight.GetSpan() >= vehicleHeight)
|
||||
return layer;
|
||||
return null;
|
||||
}
|
||||
|
||||
// 确定目标Z坐标
|
||||
double targetZ;
|
||||
if (exactMatch)
|
||||
{
|
||||
// 精确匹配:直接使用参考Z
|
||||
targetZ = referenceZ;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 中间点:根据高度趋势计算目标Z
|
||||
int remainingSteps = totalPoints - currentIndex - 1;
|
||||
if (remainingSteps <= 0)
|
||||
{
|
||||
// 没有剩余步骤,使用参考Z
|
||||
targetZ = referenceZ;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 计算期望的高度变化率
|
||||
double remainingHeight = endZ - referenceZ;
|
||||
double desiredChange = remainingHeight / remainingSteps;
|
||||
targetZ = referenceZ + desiredChange;
|
||||
}
|
||||
}
|
||||
|
||||
// 选择最接近目标Z且满足车辆高度要求的层
|
||||
HeightLayer? bestLayer = null;
|
||||
double minDistance = double.MaxValue;
|
||||
|
||||
foreach (var layer in layers)
|
||||
{
|
||||
if (layer.PassableHeight.GetSpan() < vehicleHeight)
|
||||
continue;
|
||||
|
||||
double distance = Math.Abs(layer.Z - targetZ);
|
||||
if (distance < minDistance)
|
||||
{
|
||||
minDistance = distance;
|
||||
bestLayer = layer;
|
||||
}
|
||||
}
|
||||
|
||||
return bestLayer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将A*返回的米坐标转换为网格坐标(统一方法)
|
||||
/// </summary>
|
||||
@ -1605,16 +1714,10 @@ namespace NavisworksTransport.PathPlanning
|
||||
var cell = gridMap.Cells[x, y];
|
||||
|
||||
// 检查基本可通行性和高度约束
|
||||
bool isPassable = cell.IsWalkable;
|
||||
if (isPassable && cell.PassableHeight.MaxZ > cell.PassableHeight.MinZ)
|
||||
bool isPassable = IsPassableWithHeight(cell, vehicleHeight);
|
||||
if (cell.IsWalkable && !isPassable)
|
||||
{
|
||||
// vehicleHeight已经是模型单位,直接比较即可
|
||||
bool heightOk = cell.PassableHeight.GetSpan() >= vehicleHeight;
|
||||
if (!heightOk)
|
||||
{
|
||||
heightConstrainedCells++;
|
||||
isPassable = false;
|
||||
}
|
||||
heightConstrainedCells++;
|
||||
}
|
||||
|
||||
if (isPassable)
|
||||
|
||||
@ -274,12 +274,18 @@ namespace NavisworksTransport.PathPlanning
|
||||
// 计算网格中心点在三角形平面上的精确高度
|
||||
double gridCenterHeight = GetHeightAtPoint(triangle, worldPos.X, worldPos.Y);
|
||||
|
||||
// 使用精确的世界坐标位置创建通道GridCell
|
||||
var preciseWorldPosition = new Point3D(worldPos.X, worldPos.Y, gridCenterHeight);
|
||||
var cell = GridCellBuilder.Channel(preciseWorldPosition, channel, channelSpeedLimit);
|
||||
// 创建高度层(追加模式,不覆盖)
|
||||
var channelType = CategoryAttributeManager.GetLogisticsElementType(channel);
|
||||
var layer = new HeightLayer(
|
||||
z: gridCenterHeight,
|
||||
passableHeight: new HeightInterval(0, 0), // 初始化,后续由SetChannelPassableHeights设置
|
||||
sourceItem: channel,
|
||||
speedLimit: channelSpeedLimit,
|
||||
type: channelType
|
||||
);
|
||||
|
||||
// 一次性放置完整配置的GridCell
|
||||
gridMap.PlaceCell(gridPos, cell);
|
||||
// 追加高度层(支持同一网格多个高度)
|
||||
gridMap.AddHeightLayer(gridPos, layer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,7 +28,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
WorldPosition = worldPosition,
|
||||
RelatedModelItem = channel,
|
||||
SpeedLimit = speedLimit,
|
||||
PassableHeight = new HeightInterval(),
|
||||
HeightLayers = new System.Collections.Generic.List<HeightLayer>(),
|
||||
Cost = cost // 会在PlaceCell时由ApplyCellValidationRules处理
|
||||
};
|
||||
}
|
||||
@ -52,7 +52,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
WorldPosition = worldPosition,
|
||||
RelatedModelItem = door,
|
||||
SpeedLimit = speedLimit,
|
||||
PassableHeight = new HeightInterval(),
|
||||
HeightLayers = new System.Collections.Generic.List<HeightLayer>(),
|
||||
Cost = cost
|
||||
};
|
||||
}
|
||||
@ -74,7 +74,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
WorldPosition = worldPosition,
|
||||
RelatedModelItem = obstacle,
|
||||
SpeedLimit = 0,
|
||||
PassableHeight = new HeightInterval(),
|
||||
HeightLayers = new System.Collections.Generic.List<HeightLayer>(),
|
||||
Cost = double.MaxValue // 障碍物成本最大
|
||||
};
|
||||
}
|
||||
@ -98,7 +98,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
WorldPosition = worldPosition,
|
||||
RelatedModelItem = elevator,
|
||||
SpeedLimit = speedLimit,
|
||||
PassableHeight = new HeightInterval(),
|
||||
HeightLayers = new System.Collections.Generic.List<HeightLayer>(),
|
||||
Cost = cost
|
||||
};
|
||||
}
|
||||
@ -122,7 +122,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
WorldPosition = worldPosition,
|
||||
RelatedModelItem = stairs,
|
||||
SpeedLimit = speedLimit,
|
||||
PassableHeight = new HeightInterval(),
|
||||
HeightLayers = new System.Collections.Generic.List<HeightLayer>(),
|
||||
Cost = cost
|
||||
};
|
||||
}
|
||||
@ -143,7 +143,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
WorldPosition = worldPosition,
|
||||
RelatedModelItem = null,
|
||||
SpeedLimit = 0,
|
||||
PassableHeight = new HeightInterval(),
|
||||
HeightLayers = new System.Collections.Generic.List<HeightLayer>(),
|
||||
Cost = double.MaxValue
|
||||
};
|
||||
}
|
||||
|
||||
@ -163,7 +163,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
IsWalkable = false,
|
||||
CellType = CategoryAttributeManager.LogisticsElementType.Unknown, // 修改:默认为未知/空洞类型
|
||||
IsInChannel = false,
|
||||
PassableHeight = new HeightInterval(),
|
||||
HeightLayers = new List<HeightLayer>(),
|
||||
ChannelType = ChannelType.Other,
|
||||
WorldPosition = worldPos
|
||||
};
|
||||
@ -257,7 +257,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
IsWalkable = isWalkable,
|
||||
CellType = cellType,
|
||||
IsInChannel = cellType == CategoryAttributeManager.LogisticsElementType.通道,
|
||||
PassableHeight = new HeightInterval(),
|
||||
HeightLayers = new List<HeightLayer>(),
|
||||
ChannelType = cellType == CategoryAttributeManager.LogisticsElementType.通道 ? ChannelType.Corridor : ChannelType.Other,
|
||||
WorldPosition = worldPos,
|
||||
SpeedLimit = speedLimit
|
||||
@ -286,6 +286,88 @@ namespace NavisworksTransport.PathPlanning
|
||||
Cells[gridPosition.X, gridPosition.Y] = cell;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 为指定网格坐标添加高度层(追加模式,不覆盖)
|
||||
/// </summary>
|
||||
/// <param name="gridPosition">网格坐标</param>
|
||||
/// <param name="layer">要添加的高度层</param>
|
||||
public void AddHeightLayer(GridPoint2D gridPosition, HeightLayer layer)
|
||||
{
|
||||
if (!IsValidGridPosition(gridPosition))
|
||||
return;
|
||||
|
||||
var cell = Cells[gridPosition.X, gridPosition.Y];
|
||||
|
||||
// 确保HeightLayers列表已初始化
|
||||
if (cell.HeightLayers == null)
|
||||
{
|
||||
cell.HeightLayers = new List<HeightLayer>();
|
||||
}
|
||||
|
||||
// 添加新的高度层
|
||||
cell.HeightLayers.Add(layer);
|
||||
|
||||
// 更新单元格的基本属性(使用第一个层的属性)
|
||||
if (cell.HeightLayers.Count == 1)
|
||||
{
|
||||
cell.IsWalkable = true;
|
||||
cell.CellType = layer.Type;
|
||||
cell.IsInChannel = true;
|
||||
cell.RelatedModelItem = layer.SourceItem;
|
||||
cell.SpeedLimit = layer.SpeedLimit;
|
||||
cell.Cost = cell.GetCost();
|
||||
}
|
||||
|
||||
Cells[gridPosition.X, gridPosition.Y] = cell;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找包含指定Z坐标的高度层
|
||||
/// </summary>
|
||||
/// <param name="gridPosition">网格坐标</param>
|
||||
/// <param name="z">Z坐标(米)</param>
|
||||
/// <param name="tolerance">容差(米),默认0.1m</param>
|
||||
/// <returns>符合条件的高度层,如果没有则返回null</returns>
|
||||
public HeightLayer? FindLayerContainingZ(GridPoint2D gridPosition, double z, double tolerance = 0.1)
|
||||
{
|
||||
if (!IsValidGridPosition(gridPosition))
|
||||
return null;
|
||||
|
||||
var cell = Cells[gridPosition.X, gridPosition.Y];
|
||||
if (cell.HeightLayers == null || cell.HeightLayers.Count == 0)
|
||||
return null;
|
||||
|
||||
// 查找Z坐标最接近的层
|
||||
HeightLayer? bestLayer = null;
|
||||
double minDistance = double.MaxValue;
|
||||
|
||||
foreach (var layer in cell.HeightLayers)
|
||||
{
|
||||
double distance = Math.Abs(layer.Z - z);
|
||||
if (distance < minDistance && distance <= tolerance)
|
||||
{
|
||||
minDistance = distance;
|
||||
bestLayer = layer;
|
||||
}
|
||||
}
|
||||
|
||||
return bestLayer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定网格位置的所有高度层
|
||||
/// </summary>
|
||||
/// <param name="gridPosition">网格坐标</param>
|
||||
/// <returns>高度层列表,如果没有则返回空列表</returns>
|
||||
public List<HeightLayer> GetHeightLayers(GridPoint2D gridPosition)
|
||||
{
|
||||
if (!IsValidGridPosition(gridPosition))
|
||||
return new List<HeightLayer>();
|
||||
|
||||
var cell = Cells[gridPosition.X, gridPosition.Y];
|
||||
return cell.HeightLayers ?? new List<HeightLayer>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 应用GridCell验证规则
|
||||
/// 确保Unknown和障碍物类型永远不可通行,并设置合适的成本
|
||||
@ -323,8 +405,16 @@ namespace NavisworksTransport.PathPlanning
|
||||
if (!cell.IsWalkable)
|
||||
return false;
|
||||
|
||||
// 检查是否有任何高度区间包含指定高度
|
||||
return (cell.PassableHeight.MaxZ - cell.PassableHeight.MinZ) >= height;
|
||||
// 检查是否有任何高度层满足高度要求
|
||||
if (cell.HeightLayers != null && cell.HeightLayers.Count > 0)
|
||||
{
|
||||
foreach (var layer in cell.HeightLayers)
|
||||
{
|
||||
if (layer.PassableHeight.GetSpan() >= height)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -594,9 +684,9 @@ namespace NavisworksTransport.PathPlanning
|
||||
public bool IsInChannel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 可通行高度区间列表 - 支持2.5D路径规划
|
||||
/// 多高度层列表 - 支持同一网格坐标多个高度层(如楼梯下方通道)
|
||||
/// </summary>
|
||||
public HeightInterval PassableHeight { get; set; }
|
||||
public List<HeightLayer> HeightLayers { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 通道类型 - 用于区分不同类型的通道
|
||||
@ -661,7 +751,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
IsWalkable = false,
|
||||
CellType = CategoryAttributeManager.LogisticsElementType.障碍物,
|
||||
IsInChannel = false,
|
||||
PassableHeight = new HeightInterval(),
|
||||
HeightLayers = new List<HeightLayer>(),
|
||||
ChannelType = ChannelType.Other,
|
||||
SpeedLimit = 0
|
||||
};
|
||||
@ -680,7 +770,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
IsWalkable = true,
|
||||
CellType = CategoryAttributeManager.LogisticsElementType.楼板,
|
||||
IsInChannel = false,
|
||||
PassableHeight = new HeightInterval(),
|
||||
HeightLayers = new List<HeightLayer>(),
|
||||
ChannelType = ChannelType.Other,
|
||||
SpeedLimit = 0
|
||||
};
|
||||
@ -700,7 +790,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
IsWalkable = isOpen,
|
||||
CellType = CategoryAttributeManager.LogisticsElementType.门,
|
||||
IsInChannel = isOpen,
|
||||
PassableHeight = new HeightInterval(),
|
||||
HeightLayers = new List<HeightLayer>(),
|
||||
ChannelType = ChannelType.Other,
|
||||
SpeedLimit = 0
|
||||
};
|
||||
@ -720,7 +810,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
IsWalkable = true,
|
||||
CellType = CategoryAttributeManager.LogisticsElementType.通道,
|
||||
IsInChannel = true,
|
||||
PassableHeight = new HeightInterval(),
|
||||
HeightLayers = new List<HeightLayer>(),
|
||||
ChannelType = channelType,
|
||||
SpeedLimit = 0
|
||||
};
|
||||
@ -729,6 +819,49 @@ namespace NavisworksTransport.PathPlanning
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 高度层结构体
|
||||
/// 用于支持多高度层的网格单元格
|
||||
/// </summary>
|
||||
public struct HeightLayer
|
||||
{
|
||||
/// <summary>
|
||||
/// 该层的Z坐标(米)
|
||||
/// </summary>
|
||||
public double Z { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 可通行高度范围(用于车辆检查)
|
||||
/// </summary>
|
||||
public HeightInterval PassableHeight { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 来源模型项
|
||||
/// </summary>
|
||||
public ModelItem SourceItem { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 限速(米/秒),0表示未设置限速
|
||||
/// </summary>
|
||||
public double SpeedLimit { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 层类型
|
||||
/// </summary>
|
||||
public CategoryAttributeManager.LogisticsElementType Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public HeightLayer(double z, HeightInterval passableHeight, ModelItem sourceItem, double speedLimit, CategoryAttributeManager.LogisticsElementType type)
|
||||
{
|
||||
Z = z;
|
||||
PassableHeight = passableHeight;
|
||||
SourceItem = sourceItem;
|
||||
SpeedLimit = speedLimit;
|
||||
Type = type;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 高度区间结构体 - 用于2.5D路径规划
|
||||
|
||||
@ -309,11 +309,8 @@ namespace NavisworksTransport.PathPlanning
|
||||
var cell = GridCellBuilder.Door(preciseWorldPosition, doorItem, doorSpeedLimit);
|
||||
LogManager.Info($"[门网格创建] 位置({preciseWorldPosition.X:F2},{preciseWorldPosition.Y:F2},{preciseWorldPosition.Z:F2}) 限速: {cell.SpeedLimit:F2}m/s");
|
||||
|
||||
// 设置门的高度范围
|
||||
if (doorHeight > 0)
|
||||
{
|
||||
cell.PassableHeight = new HeightInterval(0, doorHeight);
|
||||
}
|
||||
// 多层架构:PassableHeight现在在HeightLayer中设置
|
||||
// 门的高度范围由AddHeightLayer时设置
|
||||
|
||||
// 一次性放置完整配置的GridCell
|
||||
gridMap.PlaceCell(gridPos, cell);
|
||||
@ -348,21 +345,31 @@ namespace NavisworksTransport.PathPlanning
|
||||
LogManager.Info($"【高度约束设置】开始为所有可通行网格设置高度约束,扫描高度: {scanHeightInModelUnits:F2}模型单位");
|
||||
|
||||
int processedCount = 0;
|
||||
int layerCount = 0;
|
||||
|
||||
for (int x = 0; x < gridMap.Width; x++)
|
||||
{
|
||||
for (int y = 0; y < gridMap.Height; y++)
|
||||
{
|
||||
var cell = gridMap.Cells[x, y];
|
||||
if (cell.IsWalkable)
|
||||
if (cell.IsWalkable && cell.HeightLayers != null && cell.HeightLayers.Count > 0)
|
||||
{
|
||||
cell.PassableHeight = new HeightInterval(0, scanHeightInModelUnits);
|
||||
// 为每个高度层设置PassableHeight
|
||||
for (int i = 0; i < cell.HeightLayers.Count; i++)
|
||||
{
|
||||
var layer = cell.HeightLayers[i];
|
||||
layer.PassableHeight = new HeightInterval(0, scanHeightInModelUnits);
|
||||
cell.HeightLayers[i] = layer;
|
||||
layerCount++;
|
||||
}
|
||||
|
||||
gridMap.Cells[x, y] = cell;
|
||||
processedCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LogManager.Info($"【高度约束设置】完成,已处理 {processedCount} 个可通行网格");
|
||||
LogManager.Info($"【高度约束设置】完成,已处理 {processedCount} 个网格,{layerCount} 个高度层");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -492,8 +499,8 @@ namespace NavisworksTransport.PathPlanning
|
||||
// 更新网格单元格的高度区间信息
|
||||
var cell = gridMap.Cells[gridX, gridY];
|
||||
|
||||
// 直接设置高度区间
|
||||
cell.PassableHeight = interval;
|
||||
// 多层架构:高度区间在HeightLayer中设置,这里不再需要
|
||||
// cell.PassableHeight = interval;
|
||||
|
||||
// 关键修复:只处理通道单元格的高度信息集成
|
||||
// 非通道单元格不应该通过高度扫描而改变其类型或可通行性
|
||||
@ -516,7 +523,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
WorldPosition = point,
|
||||
RelatedModelItem = cell.RelatedModelItem, // 保持原有关联
|
||||
SpeedLimit = cell.SpeedLimit, // 保持原有限速
|
||||
PassableHeight = interval,
|
||||
HeightLayers = cell.HeightLayers, // 保持高度层
|
||||
Cost = 1.0
|
||||
};
|
||||
|
||||
@ -538,7 +545,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
WorldPosition = point,
|
||||
RelatedModelItem = cell.RelatedModelItem, // 保持原有关联
|
||||
SpeedLimit = cell.SpeedLimit, // 保持原有限速
|
||||
PassableHeight = interval,
|
||||
HeightLayers = cell.HeightLayers, // 保持高度层
|
||||
Cost = double.MaxValue
|
||||
};
|
||||
|
||||
@ -554,9 +561,10 @@ namespace NavisworksTransport.PathPlanning
|
||||
// 这种情况理论上不应该发生,因为只对通道单元格进行扫描
|
||||
LogManager.Warning($"[通道2.5D模式] 警告:非通道单元格 ({gridX},{gridY}) 收到高度数据,类型:{cell.CellType}, IsInChannel:{cell.IsInChannel}");
|
||||
|
||||
// 仍然更新高度信息,但保持原有状态
|
||||
// 仍然更新世界位置,但保持原有状态
|
||||
cell.WorldPosition = point;
|
||||
cell.PassableHeight = interval;
|
||||
// 多层架构:高度区间在HeightLayer中设置
|
||||
// cell.PassableHeight = interval;
|
||||
gridMap.Cells[gridX, gridY] = cell;
|
||||
}
|
||||
updatedCells++;
|
||||
@ -1311,12 +1319,9 @@ namespace NavisworksTransport.PathPlanning
|
||||
cell.IsInChannel = false;
|
||||
cell.RelatedModelItem = update.Item;
|
||||
|
||||
// 记录高度信息
|
||||
var groundHeight = cell.WorldPosition.Z;
|
||||
cell.PassableHeight = new HeightInterval(
|
||||
update.BoundingBox.Min.Z - groundHeight,
|
||||
update.BoundingBox.Max.Z - groundHeight
|
||||
);
|
||||
// 多层架构:障碍物不需要PassableHeight
|
||||
// var groundHeight = cell.WorldPosition.Z;
|
||||
// cell.PassableHeight = new HeightInterval(...)
|
||||
|
||||
gridMap.Cells[update.X, update.Y] = cell;
|
||||
updatedCells++;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user