支持多层可视化,并解决楼梯下高度不足的区域网格可视化的问题

This commit is contained in:
tian 2025-10-10 11:51:05 +08:00
parent 59ecebebc4
commit a4eaf46723
2 changed files with 215 additions and 73 deletions

View File

@ -58,6 +58,7 @@ namespace NavisworksTransport
private bool _showUnknownGrid = false;
private bool _showDoorGrid = false;
private GridMap _currentGridMap = null; // 保存当前网格地图用于刷新
private double _currentVehicleHeight = 2.0; // 保存当前车辆高度(米)用于网格刷新
private bool _isPreviewMode = false;
private int _previewInsertIndex = -1; // 保存预览点应该插入的索引位置
@ -955,7 +956,7 @@ namespace NavisworksTransport
if (_showWalkableGrid || _showObstacleGrid || _showUnknownGrid || _showDoorGrid)
{
LogManager.Info("开始网格可视化,显示所有可通行网格单元");
VisualizeGridCells(gridMap);
VisualizeGridCells(gridMap, vehicleHeight);
}
// 3. 获取通道高度数据
@ -3336,7 +3337,7 @@ namespace NavisworksTransport
if (_currentGridMap != null && IsAnyGridVisualizationEnabled)
{
LogManager.Info("[网格可视化] 使用缓存的网格地图重新渲染");
VisualizeGridCells(_currentGridMap);
VisualizeGridCells(_currentGridMap, _currentVehicleHeight);
}
else if (_currentGridMap == null)
{
@ -3358,7 +3359,8 @@ namespace NavisworksTransport
/// 在每个可通行网格的中心绘制一个绿色小球
/// </summary>
/// <param name="gridMap">要可视化的网格地图</param>
public void VisualizeGridCells(GridMap gridMap)
/// <param name="vehicleHeight">车辆高度(米),用于判断层高是否足够</param>
public void VisualizeGridCells(GridMap gridMap, double vehicleHeight = 2.0)
{
if (gridMap == null)
{
@ -3368,9 +3370,10 @@ namespace NavisworksTransport
try
{
// 保存当前网格地图用于后续刷新
// 保存当前网格地图和车辆高度用于后续刷新
_currentGridMap = gridMap;
LogManager.Info($"[网格可视化] 开始可视化网格:{gridMap.Width}x{gridMap.Height}");
_currentVehicleHeight = vehicleHeight;
LogManager.Info($"[网格可视化] 开始可视化网格:{gridMap.Width}x{gridMap.Height}, 车辆高度:{vehicleHeight}m");
// 获取渲染插件
var renderPlugin = PathPointRenderPlugin.Instance;
@ -3416,6 +3419,15 @@ namespace NavisworksTransport
int openSpaceCells = 0;
int doorCells = 0;
int totalVisualized = 0;
int multiLayerCells = 0;
int totalLayersVisualized = 0;
int heightInsufficientLayers = 0;
// 获取车辆高度(模型单位)用于判断层高是否足够
double vehicleHeightInModelUnits = vehicleHeight *
UnitsConverter.GetMetersToUnitsConversionFactor(Application.ActiveDocument.Units);
LogManager.Info($"[网格可视化] 车辆高度: {vehicleHeight}m = {vehicleHeightInModelUnits:F2}模型单位");
// 遍历所有网格单元格,根据类型分别收集
for (int x = 0; x < gridMap.Width; x++)
@ -3424,79 +3436,168 @@ namespace NavisworksTransport
{
var cell = gridMap.Cells[x, y];
// 计算网格单元格的世界中心位置
// 计算网格单元格的XY中心位置Z坐标在多层逻辑中单独处理
var gridPos = new NavisworksTransport.PathPlanning.GridPoint2D(x, y);
var gridCorner = gridMap.GridToWorld3D(gridPos);
var gridCenter = new Point3D(
gridCorner.X + gridMap.CellSize / 2,
gridCorner.Y + gridMap.CellSize / 2,
gridCorner.Z
);
double centerX = gridCorner.X + gridMap.CellSize / 2;
double centerY = gridCorner.Y + gridMap.CellSize / 2;
PathRoute targetRoute = null;
string gridTypeName = "";
// 检查是否有多个高度层
if (cell.HeightLayers != null && cell.HeightLayers.Count > 0)
{
// 多层逻辑遍历每一层根据PassableHeight判断是否可通行
multiLayerCells++;
// 根据网格类型和用户设置确定目标路径和名称
if (cell.IsWalkable && cell.CellType == CategoryAttributeManager.LogisticsElementType.)
{
if (_showWalkableGrid) // 检查可通行网格开关
foreach (var layer in cell.HeightLayers)
{
targetRoute = channelRoute;
gridTypeName = "通道";
channelCells++;
}
}
else if (cell.IsWalkable && cell.CellType == CategoryAttributeManager.LogisticsElementType.)
{
if (_showDoorGrid) // 检查门网格独立开关
{
targetRoute = doorRoute;
gridTypeName = "门";
doorCells++;
}
}
else if (cell.IsWalkable && cell.CellType == CategoryAttributeManager.LogisticsElementType.)
{
if (_showWalkableGrid) // 检查可通行网格开关
{
targetRoute = channelRoute; // 开放空间也用绿色显示
gridTypeName = "开放";
openSpaceCells++;
}
}
else if (cell.CellType == CategoryAttributeManager.LogisticsElementType.Unknown)
{
if (_showUnknownGrid) // 检查未知网格开关
{
targetRoute = unknownRoute;
gridTypeName = "空洞";
unknownCells++;
}
}
else if (cell.CellType == CategoryAttributeManager.LogisticsElementType.)
{
if (_showObstacleGrid) // 检查障碍物网格开关
{
targetRoute = obstacleRoute;
gridTypeName = "障碍";
obstacleCells++;
}
}
double layerZ = layer.Z;
double passableHeight = layer.PassableHeight.GetSpan();
// 如果有对应的路径,创建并添加网格点
if (targetRoute != null)
{
var gridPoint = new PathPoint
{
Position = gridCenter,
Name = $"网格_{gridTypeName}({x},{y})",
Type = PathPointType.WayPoint,
Index = totalVisualized,
Notes = $"GridType:{cell.CellType}"
};
// 判断高度是否足够车辆通行
bool isHeightSufficient = passableHeight >= vehicleHeightInModelUnits;
targetRoute.Points.Add(gridPoint);
totalVisualized++;
// 调试:输出高度不足的层
if (!isHeightSufficient && multiLayerCells < 5) // 只输出前5个网格的详情
{
LogManager.Debug($"[高度判断] 网格({x},{y}) Layer Z={layerZ:F2}, PassableH={passableHeight:F2}, 车辆H={vehicleHeightInModelUnits:F2}, 高度足够={isHeightSufficient}");
}
PathRoute targetRoute = null;
string gridTypeName = "";
// 根据高度是否足够和网格类型决定渲染方式
if (isHeightSufficient)
{
// 高度足够 - 按原类型渲染
if (cell.CellType == CategoryAttributeManager.LogisticsElementType.)
{
if (_showWalkableGrid)
{
targetRoute = channelRoute;
gridTypeName = "通道";
channelCells++;
}
}
else if (cell.CellType == CategoryAttributeManager.LogisticsElementType.)
{
if (_showDoorGrid)
{
targetRoute = doorRoute;
gridTypeName = "门";
doorCells++;
}
}
else if (cell.CellType == CategoryAttributeManager.LogisticsElementType.)
{
if (_showWalkableGrid)
{
targetRoute = channelRoute;
gridTypeName = "开放";
openSpaceCells++;
}
}
}
else
{
// 高度不足 - 渲染为障碍物(灰色)
if (_showObstacleGrid)
{
targetRoute = obstacleRoute;
gridTypeName = "障碍_高度不足"; // 必须包含"障碍"关键词才能渲染为灰色
heightInsufficientLayers++;
}
}
// 创建该层的可视化点
if (targetRoute != null)
{
var gridCenter = new Point3D(centerX, centerY, layerZ);
var gridPoint = new PathPoint
{
Position = gridCenter,
Name = $"网格_{gridTypeName}({x},{y})_Z{layerZ:F2}",
Type = PathPointType.WayPoint,
Index = totalVisualized,
Notes = $"GridType:{cell.CellType}, LayerZ={layerZ:F2}, PassableH={passableHeight:F2}m"
};
targetRoute.Points.Add(gridPoint);
totalVisualized++;
totalLayersVisualized++;
}
}
}
else
{
// 单层逻辑:保持原有逻辑不变
var gridCenter = new Point3D(centerX, centerY, gridCorner.Z);
PathRoute targetRoute = null;
string gridTypeName = "";
// 根据网格类型和用户设置确定目标路径和名称
if (cell.IsWalkable && cell.CellType == CategoryAttributeManager.LogisticsElementType.)
{
if (_showWalkableGrid)
{
targetRoute = channelRoute;
gridTypeName = "通道";
channelCells++;
}
}
else if (cell.IsWalkable && cell.CellType == CategoryAttributeManager.LogisticsElementType.)
{
if (_showDoorGrid)
{
targetRoute = doorRoute;
gridTypeName = "门";
doorCells++;
}
}
else if (cell.IsWalkable && cell.CellType == CategoryAttributeManager.LogisticsElementType.)
{
if (_showWalkableGrid)
{
targetRoute = channelRoute;
gridTypeName = "开放";
openSpaceCells++;
}
}
else if (cell.CellType == CategoryAttributeManager.LogisticsElementType.Unknown)
{
if (_showUnknownGrid)
{
targetRoute = unknownRoute;
gridTypeName = "空洞";
unknownCells++;
}
}
else if (cell.CellType == CategoryAttributeManager.LogisticsElementType.)
{
if (_showObstacleGrid)
{
targetRoute = obstacleRoute;
gridTypeName = "障碍";
obstacleCells++;
}
}
// 如果有对应的路径,创建并添加网格点
if (targetRoute != null)
{
var gridPoint = new PathPoint
{
Position = gridCenter,
Name = $"网格_{gridTypeName}({x},{y})",
Type = PathPointType.WayPoint,
Index = totalVisualized,
Notes = $"GridType:{cell.CellType}"
};
targetRoute.Points.Add(gridPoint);
totalVisualized++;
}
}
}
}
@ -3529,14 +3630,17 @@ namespace NavisworksTransport
// 输出统计信息
LogManager.Info($"[网格可视化] 可视化完成:");
LogManager.Info($" - 总网格单元格数:{gridMap.Width * gridMap.Height}");
LogManager.Info($" - 多层网格数:{multiLayerCells}");
LogManager.Info($" - 通道单元格数:{channelCells}");
LogManager.Info($" - 门单元格数:{doorCells}");
LogManager.Info($" - 开放空间单元格数:{openSpaceCells}");
LogManager.Info($" - Unknown单元格数{unknownCells}");
LogManager.Info($" - 障碍物单元格数:{obstacleCells}");
LogManager.Info($" - 高度不足层数:{heightInsufficientLayers}");
LogManager.Info($" - 已可视化单元格数:{totalVisualized}");
LogManager.Info($" - 已可视化层数:{totalLayersVisualized}");
RaiseStatusChanged($"网格可视化完成:显示了 {totalVisualized} 个网格单元 (通道:{channelCells}, 门:{doorCells}[50%透明], Unknown:{unknownCells}, 障碍:{obstacleCells})", PathPlanningStatusType.Success);
RaiseStatusChanged($"网格可视化完成:显示了 {totalVisualized} 个网格单元 (多层网格:{multiLayerCells}, 通道:{channelCells}, 门:{doorCells}[50%透明], Unknown:{unknownCells}, 障碍:{obstacleCells}, 高度不足:{heightInsufficientLayers})", PathPlanningStatusType.Success);
}
catch (Exception ex)
{

View File

@ -346,6 +346,7 @@ namespace NavisworksTransport.PathPlanning
int processedCount = 0;
int layerCount = 0;
int stairBottomLayersProcessed = 0;
for (int x = 0; x < gridMap.Width; x++)
{
@ -354,11 +355,47 @@ namespace NavisworksTransport.PathPlanning
var cell = gridMap.Cells[x, y];
if (cell.IsWalkable && cell.HeightLayers != null && cell.HeightLayers.Count > 0)
{
// 检查是否是楼梯或电梯网格(有多层且包含楼梯/电梯层)
bool hasStairsOrElevator = cell.HeightLayers.Any(layer =>
layer.Type == CategoryAttributeManager.LogisticsElementType. ||
layer.Type == CategoryAttributeManager.LogisticsElementType.);
// 为每个高度层设置PassableHeight
for (int i = 0; i < cell.HeightLayers.Count; i++)
{
var layer = cell.HeightLayers[i];
layer.PassableHeight = new HeightInterval(0, scanHeightInModelUnits);
// 特殊处理:楼梯/电梯的第0层下方通道层
if (hasStairsOrElevator && i == 0 && cell.HeightLayers.Count >= 2)
{
// Layer 0是楼梯下方的通道层
// PassableHeight应该是从层顶到上方楼梯底面的距离
var upperLayer = cell.HeightLayers[1]; // 楼梯层
double bottomLayerTop = layer.Z; // 下层顶部
double upperLayerBottom = upperLayer.Z; // 上层底部
// 计算实际可通行高度
double actualPassableHeight = upperLayerBottom - bottomLayerTop;
if (actualPassableHeight > 0)
{
layer.PassableHeight = new HeightInterval(0, actualPassableHeight);
stairBottomLayersProcessed++;
LogManager.Debug($"【楼梯下方高度】网格({x},{y}) Layer{i} Z={layer.Z:F2}, 上层Z={upperLayer.Z:F2}, PassableHeight={actualPassableHeight:F2}模型单位");
}
else
{
// 如果计算出负值或0使用默认值
layer.PassableHeight = new HeightInterval(0, scanHeightInModelUnits);
LogManager.Warning($"【楼梯下方高度】网格({x},{y}) Layer{i} 计算高度异常: {actualPassableHeight:F2},使用默认值");
}
}
else
{
// 普通层或楼梯层本身,使用标准扫描高度
layer.PassableHeight = new HeightInterval(0, scanHeightInModelUnits);
}
cell.HeightLayers[i] = layer;
layerCount++;
}
@ -370,6 +407,7 @@ namespace NavisworksTransport.PathPlanning
}
LogManager.Info($"【高度约束设置】完成,已处理 {processedCount} 个网格,{layerCount} 个高度层");
LogManager.Info($"【高度约束设置】其中楼梯/电梯下方层: {stairBottomLayersProcessed} 个(使用实际可通行高度)");
}
/// <summary>