修改了寻路算法穿洞的bug

This commit is contained in:
tian 2025-09-06 20:47:12 +08:00
parent 289eff5554
commit fb8d52398b
6 changed files with 321 additions and 116 deletions

View File

@ -7,9 +7,11 @@
## 问题背景
### 当前问题
在当前的自动寻路系统中发现了路径会穿越空洞没有几何覆盖的区域的问题。从3D可视化中可以看到黄色的寻路路径直接穿过了黑色的空洞区域而不是沿着绿色的通行网格前进。
### 根本原因分析
通过代码分析发现问题出现在网格初始化和A*算法转换的逻辑中:
1. **网格初始化问题** (`GridMap.InitializeCells`)
@ -29,6 +31,7 @@
### 双属性设计理念
每个网格单元包含两个独立的属性:
1. **可通行性** (`IsWalkable`) - 布尔值,决定是否能够通行
2. **物流类型** (`LogisticsType`) - 枚举值,决定通行成本和特殊处理
@ -200,13 +203,15 @@ private Grid ConvertToAStarGrid(GridMap gridMap)
## 使用场景示例
### 场景1最简单 - 只有楼板
- **输入**: 只标记楼板几何,无物流属性
- **结果**:
- **结果**:
- 楼板区域 → `Floor` + `IsWalkable=true` (权重1.0)
- 其他区域 → `Unknown` + `IsWalkable=false` (不可通行)
- **路径**: 在楼板范围内找几何最短路径
### 场景2楼板 + 通道
- **输入**: 标记楼板几何 + 部分区域标记为通道
- **结果**:
- 通道区域 → `Channel` + `IsWalkable=true` (权重0.5)
@ -215,6 +220,7 @@ private Grid ConvertToAStarGrid(GridMap gridMap)
- **路径**: 优先走通道,必要时走普通楼板,绝不穿越空洞
### 场景3复杂场景
- **输入**: 楼板 + 通道 + 门 + 楼梯 + 障碍物等混合
- **结果**: 各种类型有不同的权重
- **路径**: A*算法综合考虑距离和成本找最优路径
@ -222,38 +228,45 @@ private Grid ConvertToAStarGrid(GridMap gridMap)
## 关键改进点
### 1. 解决空洞穿越问题
- **根本解决**: `Unknown` 类型 + `IsWalkable=false` 确保空洞区域不可通行
- **可视化一致**: 黑色空洞区域在算法中也确实不可通行
### 2. 逻辑清晰
- **职责分离**: 通行性和类型分开处理,逻辑更清晰
- **易于调试**: 可以分别检查通行性和类型,快速定位问题
### 3. 灵活扩展
- **新类型**: 轻松添加新的物流类型和权重
- **特殊场景**: 支持"不可通行的通道"(施工中)等特殊组合
### 4. 向后兼容
- **现有工作流**: 继续支持只设置通道的工作方式
- **渐进迁移**: 可以逐步引入更复杂的几何和属性设置
## 实施优先级
### 第一阶段:修复空洞问题
1. 修改 `GridMap.InitializeCells()` - 默认类型改为 `Unknown`
2. 修改 `AutoPathFinder.ConvertToAStarGridWith2_5D()` - 基于 `IsWalkable` 判断
3. 测试验证空洞不再可穿越
### 第二阶段:完善类型系统
1. 实现完整的 `LogisticsType` 枚举
2. 实现权重计算系统
3. 支持楼板几何投影
### 第三阶段:扩展功能
1. 支持更多物流属性类型
2. 实现复杂场景的自动分类
3. 优化性能和内存使用
## 总结
这个双属性设计方案既解决了当前的空洞穿越问题,又为未来的功能扩展奠定了坚实基础。通过清晰的职责分离和灵活的类型系统,系统能够支持从简单楼板到复杂物流场景的各种需求。
这个双属性设计方案既解决了当前的空洞穿越问题,又为未来的功能扩展奠定了坚实基础。通过清晰的职责分离和灵活的类型系统,系统能够支持从简单楼板到复杂物流场景的各种需求。

View File

@ -3141,25 +3141,25 @@ namespace NavisworksTransport
string gridTypeName = "";
// 根据网格类型确定目标路径和名称
if (cell.IsWalkable && cell.CellType == ElementType.Channel)
if (cell.IsWalkable && cell.CellType == CategoryAttributeManager.LogisticsElementType.)
{
targetRoute = channelRoute;
gridTypeName = "通道";
channelCells++;
}
else if (cell.IsWalkable && cell.CellType == ElementType.OpenSpace)
else if (cell.IsWalkable && cell.CellType == CategoryAttributeManager.LogisticsElementType.)
{
targetRoute = channelRoute; // 开放空间也用绿色显示
gridTypeName = "开放";
openSpaceCells++;
}
else if (cell.CellType == ElementType.Unknown)
else if (cell.CellType == CategoryAttributeManager.LogisticsElementType.Unknown)
{
targetRoute = unknownRoute;
gridTypeName = "空洞";
unknownCells++;
}
else if (cell.CellType == ElementType.Obstacle)
else if (cell.CellType == CategoryAttributeManager.LogisticsElementType.)
{
targetRoute = obstacleRoute;
gridTypeName = "障碍";

View File

@ -41,15 +41,55 @@ namespace NavisworksTransport
/// </summary>
public enum LogisticsElementType
{
,
,
,
,
,
,
,
,
/// <summary>
/// 未知/空洞 - 没有任何几何覆盖,不可通行(默认值)
/// </summary>
Unknown = 0,
/// <summary>
/// 障碍物 - 墙体、柱子、设备等,不可通行
/// </summary>
= 1,
/// <summary>
/// 楼板 - 基础可通行区域权重1.0
/// </summary>
= 2,
/// <summary>
/// 门 - 可通行权重1.2
/// </summary>
= 3,
/// <summary>
/// 电梯 - 可通行权重2.0
/// </summary>
= 4,
/// <summary>
/// 楼梯 - 可通行权重3.0
/// </summary>
= 5,
/// <summary>
/// 通道 - 可通行优先路径权重0.5
/// </summary>
= 6,
/// <summary>
/// 走廊 - 可通行权重0.6
/// </summary>
= 7,
/// <summary>
/// 装卸区 - 可通行权重0.8
/// </summary>
= 8,
/// <summary>
/// 停车位 - 可通行权重0.9
/// </summary>
= 9
}
/// <summary>

View File

@ -106,12 +106,10 @@ namespace NavisworksTransport.PathPlanning
// 6. 精确高度修正
var heightCorrectedPath = ApplyPreciseHeightCorrection(enhancedPath, gridMap);
// 7. 替换起点和终点为原始用户指定的坐标与FindPathCore保持一致
var finalPath = CorrectStartEndPoints(heightCorrectedPath, originalStart, originalEnd);
// 7. 直接返回高度校正后的路径不再修改XY坐标
var finalPath = heightCorrectedPath;
LogManager.Info($"[2.5D路径规划] 路径生成完成,最终包含 {finalPath.Count} 个路径点");
LogManager.Info($"[2.5D路径规划] 起点坐标修正: 网格转换({heightCorrectedPath[0].X:F2}, {heightCorrectedPath[0].Y:F2}) -> 原始坐标({originalStart.X:F2}, {originalStart.Y:F2})");
LogManager.Info($"[2.5D路径规划] 终点坐标修正: 网格转换({heightCorrectedPath[heightCorrectedPath.Count-1].X:F2}, {heightCorrectedPath[heightCorrectedPath.Count-1].Y:F2}) -> 原始坐标({originalEnd.X:F2}, {originalEnd.Y:F2})");
return finalPath;
}
@ -134,6 +132,9 @@ namespace NavisworksTransport.PathPlanning
try
{
LogManager.Info($"[A*转换-2.5D] 开始转换网格格式: {gridMap.Width}x{gridMap.Height},车辆高度: {vehicleHeight}m");
// 输出详细的网格统计信息
LogManager.Info($"[A*转换-2.5D] 输入网格统计信息:\n{gridMap.GetStatistics()}");
// 单位转换
double cellSizeInMeters = UnitsConverter.ConvertToMeters(gridMap.CellSize);
@ -158,21 +159,54 @@ namespace NavisworksTransport.PathPlanning
// 只连接可通行的节点
int connectedCells = 0;
int totalWalkableCells = 0;
int totalNonWalkableCells = 0;
int heightConstrainedCells = 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)
{
totalWalkableCells++;
}
else
{
totalNonWalkableCells++;
}
// 检查基本可通行性和高度约束
bool isPassable = cell.IsWalkable;
bool heightRestricted = false;
if (isPassable && cell.PassableHeights != null && cell.PassableHeights.Any())
{
isPassable = cell.PassableHeights.Any(interval => interval.GetSpan() >= vehicleHeight);
bool heightOk = cell.PassableHeights.Any(interval => interval.GetSpan() >= vehicleHeight);
if (!heightOk)
{
heightConstrainedCells++;
heightRestricted = true;
// 详细日志记录被高度约束排除的单元格仅记录前10个避免日志过多
if (heightConstrainedCells <= 10)
{
LogManager.Info($"[A*高度约束] 单元格({x},{y})被高度约束排除:车辆高度{vehicleHeight}m可用区间{string.Join(", ", cell.PassableHeights.Select(i => $"{i.MinZ:F2}-{i.MaxZ:F2}({i.GetSpan():F2})"))}");
}
else if (heightConstrainedCells == 11)
{
LogManager.Info($"[A*高度约束] 还有更多单元格被高度约束排除,不再详细记录...");
}
}
isPassable = heightOk;
}
if (isPassable)
{
// 直接使用网格索引RoyT.AStar内部处理米坐标转换
var pos = new GridPosition(x, y);
connectedCells++;
@ -213,7 +247,13 @@ namespace NavisworksTransport.PathPlanning
}
}
LogManager.Info($"[A*转换-2.5D] 网格转换完成,已连接 {connectedCells} 个可通行节点");
LogManager.Info($"[A*转换-2.5D] 网格转换完成A*节点连接统计:");
LogManager.Info($"[A*转换-2.5D] - 总网格单元格: {gridMap.Width * gridMap.Height}");
LogManager.Info($"[A*转换-2.5D] - 基本可通行单元格: {totalWalkableCells}");
LogManager.Info($"[A*转换-2.5D] - 基本不可通行单元格: {totalNonWalkableCells}");
LogManager.Info($"[A*转换-2.5D] - 被高度约束排除: {heightConstrainedCells}");
LogManager.Info($"[A*转换-2.5D] - 最终连接到A*网格的节点: {connectedCells}");
LogManager.Info($"[A*转换-2.5D] - A*可用率: {(double)connectedCells / (gridMap.Width * gridMap.Height) * 100:F1}%");
return grid;
}
catch (Exception ex)
@ -588,29 +628,49 @@ namespace NavisworksTransport.PathPlanning
int gridX = (int)Math.Floor((point.X - gridMap.Bounds.Min.X) / gridMap.CellSize);
int gridY = (int)Math.Floor((point.Y - gridMap.Bounds.Min.Y) / gridMap.CellSize);
LogManager.Info($"[高度检查] 检查点 ({point.X:F2}, {point.Y:F2}, {point.Z:F2}) -> 网格坐标 ({gridX}, {gridY})");
// 确保坐标在有效范围内
if (gridX < 0 || gridX >= gridMap.Width || gridY < 0 || gridY >= gridMap.Height)
{
LogManager.Warning($"[高度检查] 网格坐标超出范围:({gridX}, {gridY}),网格大小:{gridMap.Width}x{gridMap.Height}");
return false;
}
var cell = gridMap.Cells[gridX, gridY];
LogManager.Info($"[高度检查] 单元格状态IsWalkable={cell.IsWalkable}, CellType={cell.CellType}, PassableHeights计数={cell.PassableHeights?.Count ?? 0}");
// 检查基本可行走性
if (!cell.IsWalkable)
{
LogManager.Info($"[高度检查] 单元格不可通行:({gridX}, {gridY}),类型:{cell.CellType}");
return false;
}
// 检查高度约束
if (cell.PassableHeights != null && cell.PassableHeights.Any())
{
return cell.PassableHeights.Any(interval =>
interval.GetSpan() >= vehicleHeight &&
interval.Contains(point.Z));
LogManager.Info($"[高度检查] 检查 {cell.PassableHeights.Count} 个高度区间,车辆高度:{vehicleHeight}m");
foreach (var interval in cell.PassableHeights)
{
bool spanOk = interval.GetSpan() >= vehicleHeight;
bool containsHeight = interval.Contains(point.Z);
LogManager.Info($"[高度检查] 区间 {interval}: 跨度={interval.GetSpan():F2}m (需要≥{vehicleHeight}m): {spanOk}, 包含Z={point.Z:F2}: {containsHeight}");
if (spanOk && containsHeight)
{
LogManager.Info($"[高度检查] ✅ 找到合适的高度区间,通过检查");
return true;
}
}
LogManager.Warning($"[高度检查] ❌ 所有高度区间都不满足要求");
return false;
}
// 如果没有高度信息,认为可通行(向后兼容)
LogManager.Info($"[高度检查] 无高度信息,默认可通行(向后兼容模式)");
return true;
}
catch (Exception ex)
@ -739,6 +799,10 @@ namespace NavisworksTransport.PathPlanning
LogManager.Info($"[A*执行] 网格坐标转换 - 起点: ({startGrid.X}, {startGrid.Y}), 终点: ({endGrid.X}, {endGrid.Y})");
// 获取单位转换因子
double cellSizeInMeters = UnitsConverter.ConvertToMeters(gridMap.CellSize);
// 正确直接使用网格索引RoyT.AStar内部处理米坐标转换
var startPos = new GridPosition(startGrid.X, startGrid.Y);
var endPos = new GridPosition(endGrid.X, endGrid.Y);

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using Autodesk.Navisworks.Api;
using NavisworksTransport.Utils;
using NavisworksTransport;
namespace NavisworksTransport.PathPlanning
{
@ -155,16 +156,17 @@ namespace NavisworksTransport.PathPlanning
// 计算世界坐标位置
var worldPos = GridToWorld(new Point2D(x, y));
Cells[x, y] = new GridCell
var cell = new GridCell
{
IsWalkable = false,
Cost = double.MaxValue,
CellType = ElementType.Unknown, // 修改:默认为未知/空洞类型
CellType = CategoryAttributeManager.LogisticsElementType.Unknown, // 修改:默认为未知/空洞类型
IsInChannel = false,
PassableHeights = new List<HeightInterval>(),
ChannelType = ChannelType.Other,
WorldPosition = worldPos
};
cell.Cost = cell.GetCost(); // 使用GetCost方法计算成本
Cells[x, y] = cell;
}
}
}
@ -275,22 +277,36 @@ namespace NavisworksTransport.PathPlanning
/// <param name="isWalkable">是否可通行</param>
/// <param name="cost">遍历成本</param>
/// <param name="cellType">单元格类型</param>
public void SetCell(Point2D gridPosition, bool isWalkable, double cost, ElementType cellType)
public void SetCell(Point2D gridPosition, bool isWalkable, double cost, CategoryAttributeManager.LogisticsElementType cellType)
{
if (!IsValidGridPosition(gridPosition))
return;
var worldPos = GridToWorld(gridPosition);
Cells[gridPosition.X, gridPosition.Y] = new GridCell
var cell = new GridCell
{
IsWalkable = isWalkable,
Cost = cost,
CellType = cellType,
IsInChannel = cellType == ElementType.Channel,
IsInChannel = cellType == CategoryAttributeManager.LogisticsElementType.,
PassableHeights = new List<HeightInterval>(),
ChannelType = cellType == ElementType.Channel ? ChannelType.Corridor : ChannelType.Other,
ChannelType = cellType == CategoryAttributeManager.LogisticsElementType. ? ChannelType.Corridor : ChannelType.Other,
WorldPosition = worldPos
};
// 🔥 关键验证确保Unknown和障碍物类型永远不可通行
if (cellType == CategoryAttributeManager.LogisticsElementType.Unknown ||
cellType == CategoryAttributeManager.LogisticsElementType.)
{
cell.IsWalkable = false;
cell.Cost = double.MaxValue;
}
else
{
// 优先使用传入的cost参数如果为默认值则用GetCost
cell.Cost = (cost == double.MaxValue || cost == 0) ? cell.GetCost() : cost;
}
Cells[gridPosition.X, gridPosition.Y] = cell;
}
/// <summary>
@ -305,17 +321,18 @@ namespace NavisworksTransport.PathPlanning
return;
var worldPos = GridToWorld(gridPosition);
Cells[gridPosition.X, gridPosition.Y] = new GridCell
var cell = new GridCell
{
IsWalkable = true,
Cost = 0.5, // 通道成本较低
CellType = ElementType.Channel,
CellType = CategoryAttributeManager.LogisticsElementType.,
IsInChannel = true,
PassableHeights = new List<HeightInterval>(),
ChannelType = channelType,
WorldPosition = worldPos,
RelatedModelItem = relatedItem
};
cell.Cost = cell.GetCost(); // 用GetCost方法计算通道成本
Cells[gridPosition.X, gridPosition.Y] = cell;
}
/// <summary>
@ -373,7 +390,7 @@ namespace NavisworksTransport.PathPlanning
for (int y = 0; y < Height; y++)
{
var cell = Cells[x, y];
if (cell.IsInChannel || cell.CellType == ElementType.Channel)
if (cell.IsInChannel || cell.CellType == CategoryAttributeManager.LogisticsElementType.)
{
channelCells.Add((new Point2D(x, y), cell));
}
@ -484,54 +501,114 @@ namespace NavisworksTransport.PathPlanning
/// <returns>统计信息字符串</returns>
public string GetStatistics()
{
int walkableCount = 0;
int obstacleCount = 0;
int doorCount = 0;
int channelCount = 0;
int unknownCount = 0;
// 总计数
int totalWalkable = 0;
int totalNonWalkable = 0;
// 按类型统计 - 可通行的
int walkable_楼板 = 0;
int walkable_门 = 0;
int walkable_通道 = 0;
int walkable_装卸区 = 0;
int walkable_停车位 = 0;
int walkable_楼梯 = 0;
int walkable_电梯 = 0;
int walkable_走廊 = 0;
int walkable_Other = 0;
// 按类型统计 - 不可通行的
int nonWalkable_Unknown = 0;
int nonWalkable_障碍物 = 0;
int nonWalkable_楼板 = 0;
int nonWalkable_门 = 0;
int nonWalkable_通道 = 0;
int nonWalkable_Other = 0;
for (int x = 0; x < Width; x++)
{
for (int y = 0; y < Height; y++)
{
var cell = Cells[x, y];
if (cell.IsWalkable)
{
totalWalkable++;
switch (cell.CellType)
{
case ElementType.OpenSpace:
walkableCount++;
case CategoryAttributeManager.LogisticsElementType.:
walkable_楼板++;
break;
case ElementType.Door:
doorCount++;
case CategoryAttributeManager.LogisticsElementType.:
walkable_门++;
break;
case ElementType.Channel:
channelCount++;
case CategoryAttributeManager.LogisticsElementType.:
walkable_通道++;
break;
case CategoryAttributeManager.LogisticsElementType.:
walkable_装卸区++;
break;
case CategoryAttributeManager.LogisticsElementType.:
walkable_停车位++;
break;
case CategoryAttributeManager.LogisticsElementType.:
walkable_楼梯++;
break;
case CategoryAttributeManager.LogisticsElementType.:
walkable_电梯++;
break;
case CategoryAttributeManager.LogisticsElementType.:
walkable_走廊++;
break;
default:
walkable_Other++;
break;
}
}
else
{
totalNonWalkable++;
switch (cell.CellType)
{
case ElementType.Unknown:
unknownCount++;
case CategoryAttributeManager.LogisticsElementType.Unknown:
nonWalkable_Unknown++;
break;
case ElementType.Obstacle:
obstacleCount++;
case CategoryAttributeManager.LogisticsElementType.:
nonWalkable_障碍物++;
break;
case CategoryAttributeManager.LogisticsElementType.:
nonWalkable_楼板++;
break;
case CategoryAttributeManager.LogisticsElementType.:
nonWalkable_门++;
break;
case CategoryAttributeManager.LogisticsElementType.:
nonWalkable_通道++;
break;
default:
obstacleCount++;
nonWalkable_Other++;
break;
}
}
}
}
return $"网格统计: {Width}x{Height} ({Width * Height}个单元格), " +
$"可通行: {walkableCount}, 障碍物: {obstacleCount}, 未知: {unknownCount}, " +
$"门: {doorCount}, 通道: {channelCount}, " +
$"内存使用: {GetMemoryUsage() / 1024.0:F1} KB";
var stats = $"=== 网格统计详细信息 ===\n";
stats += $"网格尺寸: {Width}x{Height} (总计 {Width * Height} 个单元格)\n";
stats += $"总体分布: 可通行 {totalWalkable} 个, 不可通行 {totalNonWalkable} 个\n\n";
stats += $"【可通行单元格详细统计】\n";
stats += $" 楼板: {walkable_楼板}, 通道: {walkable_通道}, 走廊: {walkable_走廊}\n";
stats += $" 门: {walkable_门}, 装卸区: {walkable_装卸区}, 停车位: {walkable_停车位}\n";
stats += $" 楼梯: {walkable_楼梯}, 电梯: {walkable_电梯}, 其他: {walkable_Other}\n\n";
stats += $"【不可通行单元格详细统计】\n";
stats += $" Unknown/空洞: {nonWalkable_Unknown}, 障碍物: {nonWalkable_障碍物}\n";
stats += $" 不可通行楼板: {nonWalkable_楼板}, 不可通行门: {nonWalkable_门}\n";
stats += $" 不可通行通道: {nonWalkable_通道}, 其他不可通行: {nonWalkable_Other}\n\n";
stats += $"内存使用: {GetMemoryUsage() / 1024.0:F1} KB";
return stats;
}
}
@ -554,7 +631,7 @@ namespace NavisworksTransport.PathPlanning
/// <summary>
/// 单元格类型
/// </summary>
public ElementType CellType { get; set; }
public CategoryAttributeManager.LogisticsElementType CellType { get; set; }
/// <summary>
/// 相关的模型项引用(可选)
@ -581,21 +658,60 @@ namespace NavisworksTransport.PathPlanning
/// </summary>
public Point3D WorldPosition { get; set; }
/// <summary>
/// 根据物流类型获取通行成本
/// </summary>
/// <returns>通行成本</returns>
public double GetCost()
{
if (!IsWalkable)
return double.MaxValue;
switch (CellType)
{
case CategoryAttributeManager.LogisticsElementType.:
return 0.5;
case CategoryAttributeManager.LogisticsElementType.:
return 0.8;
case CategoryAttributeManager.LogisticsElementType.:
return 0.9;
case CategoryAttributeManager.LogisticsElementType.:
return 1.0;
case CategoryAttributeManager.LogisticsElementType.:
return 1.2;
case CategoryAttributeManager.LogisticsElementType.:
return 3.0;
case CategoryAttributeManager.LogisticsElementType.:
return 2.0;
case CategoryAttributeManager.LogisticsElementType.:
return 0.6;
case CategoryAttributeManager.LogisticsElementType.Unknown:
// Unknown类型空洞永远不可通行
return double.MaxValue;
case CategoryAttributeManager.LogisticsElementType.:
// 障碍物永远不可通行
return double.MaxValue;
default:
return 1.0;
}
}
/// <summary>
/// 创建障碍物单元格
/// </summary>
/// <returns>障碍物单元格</returns>
public static GridCell CreateObstacle()
{
return new GridCell
var cell = new GridCell
{
IsWalkable = false,
Cost = double.MaxValue,
CellType = ElementType.Obstacle,
CellType = CategoryAttributeManager.LogisticsElementType.,
IsInChannel = false,
PassableHeights = new List<HeightInterval>(),
ChannelType = ChannelType.Other
};
cell.Cost = cell.GetCost();
return cell;
}
/// <summary>
@ -604,15 +720,16 @@ namespace NavisworksTransport.PathPlanning
/// <returns>开放空间单元格</returns>
public static GridCell CreateOpenSpace()
{
return new GridCell
var cell = new GridCell
{
IsWalkable = true,
Cost = 1.0,
CellType = ElementType.OpenSpace,
CellType = CategoryAttributeManager.LogisticsElementType.,
IsInChannel = false,
PassableHeights = new List<HeightInterval>(),
ChannelType = ChannelType.Other
};
cell.Cost = cell.GetCost();
return cell;
}
/// <summary>
@ -622,15 +739,16 @@ namespace NavisworksTransport.PathPlanning
/// <returns>门单元格</returns>
public static GridCell CreateDoor(bool isOpen = true)
{
return new GridCell
var cell = new GridCell
{
IsWalkable = isOpen,
Cost = isOpen ? 5.0 : double.MaxValue, // 门的通过成本较高
CellType = ElementType.Door,
CellType = CategoryAttributeManager.LogisticsElementType.,
IsInChannel = isOpen,
PassableHeights = new List<HeightInterval>(),
ChannelType = ChannelType.Other
};
cell.Cost = cell.GetCost();
return cell;
}
/// <summary>
@ -640,49 +758,19 @@ namespace NavisworksTransport.PathPlanning
/// <returns>通道单元格</returns>
public static GridCell CreateChannel(ChannelType channelType = ChannelType.Corridor)
{
return new GridCell
var cell = new GridCell
{
IsWalkable = true,
Cost = 0.5, // 通道成本较低,优先选择
CellType = ElementType.Channel,
CellType = CategoryAttributeManager.LogisticsElementType.,
IsInChannel = true,
PassableHeights = new List<HeightInterval>(),
ChannelType = channelType
};
cell.Cost = cell.GetCost();
return cell;
}
}
/// <summary>
/// 元素类型枚举
/// 定义网格单元格可能的类型
/// </summary>
public enum ElementType
{
/// <summary>
/// 未知/空洞 - 没有任何几何覆盖,不可通行
/// </summary>
Unknown = 0,
/// <summary>
/// 开放空间 - 默认可通行区域
/// </summary>
OpenSpace = 1,
/// <summary>
/// 障碍物 - 不可通行
/// </summary>
Obstacle = 2,
/// <summary>
/// 门 - 条件性可通行
/// </summary>
Door = 3,
/// <summary>
/// 通道 - 优先通行路线
/// </summary>
Channel = 4
}
/// <summary>
/// 高度区间结构体 - 用于2.5D路径规划
@ -794,7 +882,7 @@ namespace NavisworksTransport.PathPlanning
{
for (int y = 0; y < GridMap.Height; y++)
{
if (GridMap.Cells[x, y].CellType == ElementType.Channel)
if (GridMap.Cells[x, y].CellType == CategoryAttributeManager.LogisticsElementType.)
{
channelCellCount++;
}

View File

@ -300,7 +300,7 @@ namespace NavisworksTransport.PathPlanning
var cell = gridMap.Cells[x, y];
// 只为通道类型的网格生成扫描点
if (cell.CellType == ElementType.Channel && cell.IsInChannel)
if (cell.CellType == CategoryAttributeManager.LogisticsElementType. && cell.IsInChannel)
{
// 使用标准GridToWorld方法确保坐标系统一致
var worldPos = gridMap.GridToWorld(new Point2D(x, y));
@ -388,7 +388,7 @@ namespace NavisworksTransport.PathPlanning
// 关键修复:只处理通道单元格的高度信息集成
// 非通道单元格不应该通过高度扫描而改变其类型或可通行性
if (cell.CellType == ElementType.Channel && cell.IsInChannel)
if (cell.CellType == CategoryAttributeManager.LogisticsElementType. && cell.IsInChannel)
{
channelCellsWithHeightData++;
@ -397,7 +397,7 @@ namespace NavisworksTransport.PathPlanning
// 通道区域有足够净空高度,设置为可通行
// 🔥 关键修复使用SetCell方法正确更新网格统计
var gridPos = new Point2D(gridX, gridY);
gridMap.SetCell(gridPos, true, 1.0, ElementType.Channel);
gridMap.SetCell(gridPos, true, 1.0, CategoryAttributeManager.LogisticsElementType.);
// 设置世界坐标和高度信息
var updatedCell = gridMap.Cells[gridX, gridY];
@ -410,7 +410,7 @@ namespace NavisworksTransport.PathPlanning
{
// 通道区域但净空高度不足,标记为不可通行但保持通道类型
var gridPos = new Point2D(gridX, gridY);
gridMap.SetCell(gridPos, false, double.MaxValue, ElementType.Channel);
gridMap.SetCell(gridPos, false, double.MaxValue, CategoryAttributeManager.LogisticsElementType.);
// 设置世界坐标和高度信息
var updatedCell = gridMap.Cells[gridX, gridY];
@ -466,20 +466,20 @@ namespace NavisworksTransport.PathPlanning
walkableCount++;
switch (cell.CellType)
{
case ElementType.Channel:
case CategoryAttributeManager.LogisticsElementType.:
channelCount++;
break;
case ElementType.OpenSpace:
case CategoryAttributeManager.LogisticsElementType.:
openSpaceCount++;
break;
case ElementType.Door:
case CategoryAttributeManager.LogisticsElementType.:
doorCount++;
break;
}
}
else
{
if (cell.CellType == ElementType.Obstacle)
if (cell.CellType == CategoryAttributeManager.LogisticsElementType.)
{
obstacleCount++;
}
@ -769,7 +769,7 @@ namespace NavisworksTransport.PathPlanning
var gridPos = new Point2D(x, y);
if (gridMap.IsWalkable(gridPos))
{
gridMap.SetCell(gridPos, false, double.MaxValue, ElementType.Obstacle);
gridMap.SetCell(gridPos, false, double.MaxValue, CategoryAttributeManager.LogisticsElementType.);
newlyMarkedCells++;
}
totalMarkedCells++;
@ -781,7 +781,7 @@ namespace NavisworksTransport.PathPlanning
var gridPos = new Point2D(x, y);
if (gridMap.IsWalkable(gridPos))
{
gridMap.SetCell(gridPos, false, double.MaxValue, ElementType.Obstacle);
gridMap.SetCell(gridPos, false, double.MaxValue, CategoryAttributeManager.LogisticsElementType.);
newlyMarkedCells++;
}
totalMarkedCells++;
@ -797,7 +797,7 @@ namespace NavisworksTransport.PathPlanning
var gridPos = new Point2D(x, y);
if (gridMap.IsWalkable(gridPos))
{
gridMap.SetCell(gridPos, false, double.MaxValue, ElementType.Obstacle);
gridMap.SetCell(gridPos, false, double.MaxValue, CategoryAttributeManager.LogisticsElementType.);
newlyMarkedCells++;
}
totalMarkedCells++;
@ -809,7 +809,7 @@ namespace NavisworksTransport.PathPlanning
var gridPos = new Point2D(x, y);
if (gridMap.IsWalkable(gridPos))
{
gridMap.SetCell(gridPos, false, double.MaxValue, ElementType.Obstacle);
gridMap.SetCell(gridPos, false, double.MaxValue, CategoryAttributeManager.LogisticsElementType.);
newlyMarkedCells++;
}
totalMarkedCells++;
@ -1019,7 +1019,7 @@ namespace NavisworksTransport.PathPlanning
distanceMap[x, y] > 0 &&
distanceMap[x, y] <= inflationRadius)
{
gridMap.SetCell(gridPos, false, double.MaxValue, ElementType.Obstacle);
gridMap.SetCell(gridPos, false, double.MaxValue, CategoryAttributeManager.LogisticsElementType.);
inflatedCells++;
}
else if (distanceMap[x, y] == int.MaxValue || distanceMap[x, y] > inflationRadius)
@ -1175,11 +1175,11 @@ namespace NavisworksTransport.PathPlanning
var cell = gridMap.Cells[x, y];
// 只更新通道网格,跳过已是障碍物的网格
if (cell.CellType == ElementType.Channel && cell.IsInChannel)
if (cell.CellType == CategoryAttributeManager.LogisticsElementType. && cell.IsInChannel)
{
// 标记为障碍物
cell.IsWalkable = false;
cell.CellType = ElementType.Obstacle;
cell.CellType = CategoryAttributeManager.LogisticsElementType.;
cell.Cost = double.MaxValue;
cell.IsInChannel = false;
cell.RelatedModelItem = item;