删掉了以前的基于空间索引和垂直扫描的2.5D网格生成方法

This commit is contained in:
tian 2025-09-16 17:00:11 +08:00
parent 5ef1fdc747
commit 8fbad77e65
4 changed files with 41 additions and 222 deletions

View File

@ -115,8 +115,23 @@ public class PathClickToolPlugin : ToolPlugin { }
### Development Principles
- **不考虑向后兼容性**: 直接修改现有代码逻辑,无需保持向后兼容性,专注于解决当前问题和改进现有功能
- **最小化修改原则**: 进行任何代码修改时,必须遵循最小化原则,只修改必要的部分,不添加额外的功能或逻辑,以确保问题能够清晰暴露和定位
- 防御性编程的正确态度:
- ✅ 应该做:检测异常情况并报错,让问题暴露出来
- ❌ 不应该做用默认值掩盖问题让bug隐藏在系统中
- 对于"备份方案"和"容错处理":
- ✅ 正确做法:发现问题时记录错误日志,中断处理流程
- ❌ 错误做法:遇到异常数据时自动"修复"或使用替代值继续执行
- 对于"向后兼容性"
- 明确拒绝考虑向后兼容性
- 专注解决当前问题,不为旧版本或边缘情况妥协
- 核心原则:
- "让问题快速暴露" > "让程序看起来正常运行"
- "报错比静默失败好" > "容忍错误数据继续处理"
- "数据一致性检查" > "宽松的数据验证"
- "最小化修改" > "复杂全面的逻辑"
### Critical API Usage Patterns
@ -188,4 +203,4 @@ public class PathClickToolPlugin : ToolPlugin { }
- **2026 Features**: Test advanced animation capabilities, enhanced collision detection, and improved model handling
- 在编码中,不要用回退或向后兼容的思路和步骤
- 程序的日志在C:\ProgramData\Autodesk\Navisworks Manage 2026\NavisworksTransport\logs\debug.log
- 不要搞向后兼容
- 不要搞向后兼容

View File

@ -829,7 +829,6 @@ namespace NavisworksTransport
try
{
LogManager.Info($"开始调用GridMapGenerator.GenerateFromBIM2.5D模式)");
var performanceStart = System.Diagnostics.Stopwatch.StartNew();
// 获取当前文档
@ -841,8 +840,6 @@ namespace NavisworksTransport
try
{
// 使用2.5D通道检测模式
LogManager.Info("使用BoundingBoxBased2_5D模式生成网格");
gridMap = gridMapGenerator.GenerateFromBIM(
document,
bounds,
@ -851,14 +848,13 @@ namespace NavisworksTransport
safetyMargin,
startPoint.Position,
endPoint.Position,
GridGenerationMode.BoundingBoxBased2_5D, // 新增:使用优化的边界框算法
vehicleHeight // 传递车辆高度参数
vehicleHeight
);
LogManager.Info("✅ BoundingBoxBased2_5D模式网格生成成功");
LogManager.Info("✅ 网格地图生成成功");
}
catch (Exception modeEx)
{
LogManager.Warning($"BoundingBoxBased2_5D模式失败,{modeEx.Message}");
LogManager.Warning($"网格地图生成失败,{modeEx.Message}");
}
performanceStart.Stop();
@ -871,21 +867,14 @@ namespace NavisworksTransport
throw new Exception($"网格地图生成失败: {ex.Message}", ex);
}
LogManager.Info($"网格地图生成完成: {gridMap.GetStatistics()}");
// 根据用户设置决定是否进行网格可视化
if (_showWalkableGrid || _showObstacleGrid || _showUnknownGrid || _showDoorGrid)
{
LogManager.Info("开始网格可视化,显示所有可通行网格单元");
VisualizeGridCells(gridMap);
}
else
{
LogManager.Info("网格可视化已关闭,跳过可视化步骤");
}
// 3. 获取通道数据用于精确高度计算
LogManager.Info("开始获取通道数据用于精确高度计算...");
// 3. 获取通道高度数据
var channelItems = GetChannelItemsForHeightCalculation(gridMap);
LogManager.Info($"获取通道数据完成: {channelItems?.Count() ?? 0} 个通道项");
@ -918,11 +907,9 @@ namespace NavisworksTransport
try
{
pathFinder = new AutoPathFinder();
double vehicleHeightInModelUnits = vehicleHeight * UnitsConverter.GetMetersToUnitsConversionFactor(Application.ActiveDocument.Units);
LogManager.Info($"使用2.5D模式进行路径查找,车辆高度: {vehicleHeight}m ({vehicleHeightInModelUnits:F2}模型单位),策略: {strategy}");
pathResult = pathFinder.FindPath(startPoint.Position, endPoint.Position, gridMap, channelCoverage, vehicleHeightInModelUnits, strategy);
LogManager.Info("FindPath方法调用完成");
}
catch (Exception ex)

View File

@ -48,45 +48,6 @@ namespace NavisworksTransport.PathPlanning
/// </summary>
public class AutoPathFinder
{
/// <summary>
/// 查找路径(支持通道数据和高度约束)
/// </summary>
/// <param name="start">起点(世界坐标)</param>
/// <param name="end">终点(世界坐标)</param>
/// <param name="gridMap">网格地图</param>
/// <param name="channelCoverage">通道覆盖数据可选用于2.5D路径规划)</param>
/// <param name="vehicleHeight">车辆高度(模型单位,用于高度约束检查)</param>
/// <returns>路径查找结果</returns>
public PathFindingResult FindPath(Point3D start, Point3D end, GridMap gridMap, ChannelCoverage channelCoverage, double vehicleHeight)
{
// 调用支持策略的重载方法,默认使用最短路径策略
return FindPath(start, end, gridMap, channelCoverage, vehicleHeight, PathStrategy.Shortest);
}
/// <summary>
/// 查找路径(支持通道数据、高度约束和路径策略)
/// </summary>
/// <param name="start">起点(世界坐标)</param>
/// <param name="end">终点(世界坐标)</param>
/// <param name="gridMap">网格地图</param>
/// <param name="channelCoverage">通道覆盖数据可选用于2.5D路径规划)</param>
/// <param name="vehicleHeight">车辆高度(模型单位,用于高度约束检查)</param>
/// <param name="strategy">路径规划策略</param>
/// <returns>路径查找结果</returns>
public PathFindingResult FindPath(Point3D start, Point3D end, GridMap gridMap, ChannelCoverage channelCoverage, double vehicleHeight, PathStrategy strategy)
{
LogManager.Info($"开始A*路径查找: 起点({start?.X:F2}, {start?.Y:F2}, {start?.Z:F2}), 终点({end?.X:F2}, {end?.Y:F2}, {end?.Z:F2}), 策略: {strategy}");
// 如果提供了通道覆盖数据使用2.5D模式进行路径规划
if (channelCoverage != null && channelCoverage.ChannelItems.Any())
{
LogManager.Info($"[2.5D路径规划] 使用通道覆盖数据,通道数量: {channelCoverage.ChannelItems.Count}, 车辆高度: {vehicleHeight}m, 策略: {strategy}");
return FindPath2_5D(start, end, gridMap, channelCoverage, vehicleHeight, strategy);
}
return new PathFindingResult { PathPoints = new List<Point3D>() };
}
/// <summary>
/// 2.5D路径规划(使用通道覆盖数据、高度约束和路径策略)
/// </summary>
@ -97,7 +58,7 @@ namespace NavisworksTransport.PathPlanning
/// <param name="vehicleHeight">车辆高度(模型单位)</param>
/// <param name="strategy">路径规划策略</param>
/// <returns>路径查找结果</returns>
private PathFindingResult FindPath2_5D(Point3D start, Point3D end, GridMap gridMap, ChannelCoverage channelCoverage, double vehicleHeight, PathStrategy strategy = PathStrategy.Shortest)
public PathFindingResult FindPath(Point3D start, Point3D end, GridMap gridMap, ChannelCoverage channelCoverage, double vehicleHeight, PathStrategy strategy = PathStrategy.Shortest)
{
try
{

View File

@ -46,152 +46,8 @@ namespace NavisworksTransport.PathPlanning
_verticalScanner = null;
}
/// <summary>
/// 从BIM模型生成网格地图
/// </summary>
/// <param name="document">Navisworks文档</param>
/// <param name="bounds">规划区域边界</param>
/// <param name="cellSize">网格单元格大小(米)</param>
/// <param name="vehicleRadius">车辆半径(用于障碍物膨胀)</param>
/// <param name="safetyMargin">安全间隙(额外的膨胀间距,米)</param>
/// <param name="planningStartPoint">规划起点(用于确定楼层)</param>
/// <param name="planningEndPoint">规划终点(用于确定楼层)</param>
/// <param name="mode">网格生成模式默认为2.5D模式</param>
/// <param name="vehicleHeight">车辆高度(用于垂直通行检查)</param>
/// <returns>生成的网格地图</returns>
public GridMap GenerateFromBIM(Document document, BoundingBox3D bounds, double cellSize, double vehicleRadius, double safetyMargin, Point3D planningStartPoint, Point3D planningEndPoint, GridGenerationMode mode, double vehicleHeight)
{
try
{
LogManager.Info($"[网格生成器] 使用模式: {mode}");
// 根据模式选择不同的生成策略
switch (mode)
{
case GridGenerationMode.ChannelBased2_5D:
return GenerateChannelBased2_5D(document, bounds, cellSize, vehicleRadius, safetyMargin, planningStartPoint, planningEndPoint, vehicleHeight);
case GridGenerationMode.BoundingBoxBased2_5D:
return GenerateBoundingBoxBased2_5D(document, bounds, cellSize, vehicleRadius, safetyMargin, planningStartPoint, planningEndPoint, vehicleHeight);
default:
return GenerateBoundingBoxBased2_5D(document, bounds, cellSize, vehicleRadius, safetyMargin, planningStartPoint, planningEndPoint, vehicleHeight);
}
}
catch (Exception ex)
{
LogManager.Error($"生成网格地图时发生错误: {ex.Message}");
throw new AutoPathPlanningException($"网格地图生成失败: {ex.Message}", ex);
}
}
/// <summary>
/// 通道基础2.5D模式的网格生成
/// 使用通道优先策略和垂直扫描处理器
///
/// 术语说明:
/// - "通道"在此指所有可通行结构(楼板、走廊、过道等)
/// - 对于楼板类通道,车辆在其顶面行驶
/// - 生成的网格地图用于车辆路径规划
/// </summary>
private GridMap GenerateChannelBased2_5D(Document document, BoundingBox3D bounds, double cellSize, double vehicleRadius, double safetyMargin, Point3D planningStartPoint, Point3D planningEndPoint, double vehicleHeight)
{
try
{
LogManager.Info("[通道2.5D模式] 开始生成网格地图");
// 重要:将米制网格大小转换为模型单位
double metersToModelUnitsConversionFactor = UnitsConverter.GetMetersToUnitsConversionFactor(Application.ActiveDocument.Units);
double cellSizeInModelUnits = cellSize * metersToModelUnitsConversionFactor;
LogManager.Info($"[通道2.5D模式] 网格大小单位转换: {cellSize}米 → {cellSizeInModelUnits:F2}模型单位 (转换系数: {metersToModelUnitsConversionFactor:F2})");
// 1. 使用通道构建器构建基础通道覆盖网格
LogManager.Info("[通道2.5D模式] 步骤1: 构建通道覆盖网格");
var channelCoverage = _channelBuilder.BuildChannelCoverage(cellSizeInModelUnits, document);
LogManager.Info($"[通道2.5D模式] 通道覆盖构建完成: {channelCoverage.GetStatistics()}");
LogManager.Info($"[阶段1完成] 通道覆盖网格统计: {channelCoverage.GridMap.GetStatistics()}");
// 2. 构建垂直扫描处理器的空间索引
LogManager.Info("[通道2.5D模式] 步骤2: 构建空间哈希索引");
double spatialHashMultiplier = 10.0; // 可以根据模型密度调整高密设为6低密设为10
_verticalScanner = new VerticalScanProcessor(cellSize * spatialHashMultiplier);
var allItems = document.Models.RootItemDescendantsAndSelf;
_verticalScanner.BuildSpatialHashIndex(allItems, bounds, channelCoverage.ChannelItems);
// 3. 生成网格点坐标用于垂直扫描
LogManager.Info("[通道2.5D模式] 步骤3: 生成网格扫描点");
var gridPoints = GenerateGridPoints(channelCoverage.GridMap);
LogManager.Info($"[阶段3完成] 生成 {gridPoints.Count} 个扫描点");
// 4. 并行执行垂直扫描计算2.5D高度区间
LogManager.Info("[通道2.5D模式] 步骤4: 执行并行垂直扫描");
double scanHeight = vehicleHeight + safetyMargin; // 扫描高度 = 车辆高度 + 安全间隙
var heightIntervals = _verticalScanner.ParallelScanHeightIntervals(
gridPoints, scanHeight, vehicleHeight);
LogManager.Info($"[阶段4完成] 垂直扫描结果: 扫描了{gridPoints.Count}个通道点,生成了{heightIntervals.Count}个高度区间数据");
// 5. 将高度区间信息集成到网格地图中
LogManager.Info("[通道2.5D模式] 步骤5: 集成高度信息到网格");
// 添加集成前的验证日志
var preIntegrationStats = channelCoverage.GridMap.GetStatistics();
LogManager.Info($"[验证] 高度信息集成前网格统计: {preIntegrationStats}");
IntegrateHeightIntervalsToGrid(channelCoverage.GridMap, heightIntervals);
// 添加集成后的验证日志
var postIntegrationStats = channelCoverage.GridMap.GetStatistics();
LogManager.Info($"[阶段5完成] 高度信息集成后网格统计: {postIntegrationStats}");
// 验证网格统计一致性
ValidateGridStatisticsConsistency(channelCoverage.GridMap, "高度信息集成后");
// 6. 应用车辆尺寸膨胀(如果需要)
if (vehicleRadius > 0 || safetyMargin > 0)
{
LogManager.Info("[通道2.5D模式] 步骤6: 应用车辆膨胀");
double metersToModelUnits = UnitsConverter.GetMetersToUnitsConversionFactor(Application.ActiveDocument.Units);
double totalInflationRadius = (vehicleRadius + safetyMargin) * metersToModelUnits;
ApplyVehicleInflation(channelCoverage.GridMap, totalInflationRadius);
LogManager.Info($"[通道2.5D模式] 车辆膨胀完成,膨胀半径: {totalInflationRadius:F2}模型单位");
LogManager.Info($"[阶段6完成] 车辆膨胀后网格统计: {channelCoverage.GridMap.GetStatistics()}");
}
// 注意:边界膨胀已集成到车辆膨胀中,无需单独处理
// 8. 设置规划起点和终点信息
if (planningStartPoint != default(Point3D) && planningEndPoint != default(Point3D))
{
channelCoverage.GridMap.PlanningStartPoint = planningStartPoint;
channelCoverage.GridMap.PlanningEndPoint = planningEndPoint;
channelCoverage.GridMap.HasPlanningPoints = true;
// 注意网格的Z坐标已在通道生成时设置为实际通道高度无需重新计算
}
// 🔥 关键修复将通道数据设置到GridMap中供后续PathPlanningManager使用
if (channelCoverage.ChannelItems != null && channelCoverage.ChannelItems.Any())
{
channelCoverage.GridMap.ChannelItems = new List<ModelItem>(channelCoverage.ChannelItems);
LogManager.Info($"[通道2.5D模式] 已将 {channelCoverage.ChannelItems.Count} 个通道数据设置到GridMap中");
}
LogManager.Info($"[通道2.5D模式] 网格地图生成完成: {channelCoverage.GridMap.GetStatistics()}");
return channelCoverage.GridMap;
}
catch (Exception ex)
{
LogManager.Error($"[通道2.5D模式] 生成失败: {ex.Message}");
return null;
}
}
/// <summary>
/// 基于包围盒遍历的网格地图生成方法(优化版)
/// 使用简化的包围盒检测替代空间索引+垂直扫描,提升性能
/// </summary>
/// <param name="document">Navisworks文档</param>
/// <param name="bounds">扫描边界</param>
@ -202,61 +58,61 @@ namespace NavisworksTransport.PathPlanning
/// <param name="planningEndPoint">规划终点</param>
/// <param name="vehicleHeight">车辆高度(米)</param>
/// <returns>生成的网格地图</returns>
private GridMap GenerateBoundingBoxBased2_5D(Document document, BoundingBox3D bounds, double cellSize, double vehicleRadius, double safetyMargin, Point3D planningStartPoint, Point3D planningEndPoint, double vehicleHeight)
public GridMap GenerateFromBIM(Document document, BoundingBox3D bounds, double cellSize, double vehicleRadius, double safetyMargin, Point3D planningStartPoint, Point3D planningEndPoint, double vehicleHeight)
{
try
{
LogManager.Info("【包围盒2.5D模式】开始生成网格地图");
LogManager.Info("【生成网格地图】开始生成网格地图");
var startTime = DateTime.Now;
// 重要:将米制网格大小转换为模型单位
double metersToModelUnitsConversionFactor = UnitsConverter.GetMetersToUnitsConversionFactor(Application.ActiveDocument.Units);
double cellSizeInModelUnits = cellSize * metersToModelUnitsConversionFactor;
LogManager.Info($"【包围盒2.5D模式】网格大小单位转换: {cellSize}米 → {cellSizeInModelUnits:F2}模型单位 (转换系数: {metersToModelUnitsConversionFactor:F2})");
LogManager.Info($"【生成网格地图】网格大小单位转换: {cellSize}米 → {cellSizeInModelUnits:F2}模型单位 (转换系数: {metersToModelUnitsConversionFactor:F2})");
// 1. 使用通道构建器构建基础通道覆盖网格
LogManager.Info("【包围盒2.5D模式】步骤1: 构建通道覆盖网格");
LogManager.Info("【生成网格地图】步骤1: 构建通道覆盖网格");
var channelCoverage = _channelBuilder.BuildChannelCoverage(cellSizeInModelUnits, document);
LogManager.Info($"【包围盒2.5D模式】通道覆盖构建完成: {channelCoverage.GetStatistics()}");
LogManager.Info($"【生成网格地图】通道覆盖构建完成: {channelCoverage.GetStatistics()}");
LogManager.Info($"【阶段1完成】通道覆盖网格统计: {channelCoverage.GridMap.GetStatistics()}");
// 1.5. 使用智能收集策略收集所有通道相关节点
LogManager.Info("【包围盒2.5D模式】步骤1.5: 智能收集通道相关节点");
LogManager.Info("【生成网格地图】步骤1.5: 智能收集通道相关节点");
// 直接获取所有可通行的物流模型项
var allChannelItems = CategoryAttributeManager.GetAllTraversableLogisticsItems(document);
LogManager.Info($"【包围盒2.5D模式】直接获取到 {allChannelItems.Count} 个可通行物流元素");
LogManager.Info($"【生成网格地图】直接获取到 {allChannelItems.Count} 个可通行物流元素");
// 智能收集通道相关节点(包括父节点、同级节点等)
var channelRelatedItems = CollectChannelRelatedItems(allChannelItems.ToList());
LogManager.Info($"【包围盒2.5D模式】智能收集到 {channelRelatedItems.Count} 个通道相关节点");
LogManager.Info($"【生成网格地图】智能收集到 {channelRelatedItems.Count} 个通道相关节点");
// 2. 直接遍历处理障碍物(包围盒检测) - 使用高性能优化版本
LogManager.Info("【包围盒2.5D模式】步骤2: 高性能包围盒遍历处理障碍物");
LogManager.Info("【生成网格地图】步骤2: 高性能包围盒遍历处理障碍物");
double scanHeight = vehicleHeight + safetyMargin; // 扫描高度 = 车辆高度 + 安全间隙
ProcessObstaclesWithBoundingBoxOptimized(document, channelCoverage.GridMap, channelRelatedItems, scanHeight);
LogManager.Info($"【阶段2完成】障碍物处理后网格统计: {channelCoverage.GridMap.GetStatistics()}");
// 2.5. 单独处理门元素,设置为可通行
LogManager.Info("【包围盒2.5D模式】步骤2.5: 处理门元素");
LogManager.Info("【生成网格地图】步骤2.5: 处理门元素");
ProcessDoorElements(channelCoverage.GridMap, allChannelItems);
LogManager.Info($"【阶段2.5完成】门元素处理后网格统计: {channelCoverage.GridMap.GetStatistics()}");
// 2.6. 为通道网格设置PassableHeights确保高度约束检查
LogManager.Info("【包围盒2.5D模式】步骤2.6: 为通道网格设置高度约束");
LogManager.Info("【生成网格地图】步骤2.6: 为通道网格设置高度约束");
SetChannelPassableHeights(channelCoverage.GridMap, scanHeight);
LogManager.Info($"【阶段2.6完成】通道高度约束设置后网格统计: {channelCoverage.GridMap.GetStatistics()}");
// 3. 应用车辆尺寸膨胀(如果需要)
if (vehicleRadius > 0 || safetyMargin > 0)
{
LogManager.Info("【包围盒2.5D模式】步骤3: 应用车辆膨胀");
LogManager.Info("【生成网格地图】步骤3: 应用车辆膨胀");
double metersToModelUnits = UnitsConverter.GetMetersToUnitsConversionFactor(Application.ActiveDocument.Units);
double totalInflationRadius = (vehicleRadius + safetyMargin) * metersToModelUnits;
ApplyVehicleInflation(channelCoverage.GridMap, totalInflationRadius);
LogManager.Info($"【包围盒2.5D模式】车辆膨胀完成,膨胀半径: {totalInflationRadius:F2}模型单位");
LogManager.Info($"【生成网格地图】车辆膨胀完成,膨胀半径: {totalInflationRadius:F2}模型单位");
LogManager.Info($"【阶段3完成】车辆膨胀后网格统计: {channelCoverage.GridMap.GetStatistics()}");
}
@ -276,22 +132,22 @@ namespace NavisworksTransport.PathPlanning
if (channelRelatedItems != null && channelRelatedItems.Any())
{
channelCoverage.GridMap.ChannelItems = channelRelatedItems.ToList();
LogManager.Info($"【包围盒2.5D模式】已将 {channelRelatedItems.Count} 个通道数据设置到GridMap中");
LogManager.Info($"【生成网格地图】已将 {channelRelatedItems.Count} 个通道数据设置到GridMap中");
}
else if (channelCoverage.ChannelItems != null && channelCoverage.ChannelItems.Any())
{
channelCoverage.GridMap.ChannelItems = new List<ModelItem>(channelCoverage.ChannelItems);
LogManager.Info($"【包围盒2.5D模式】已将 {channelCoverage.ChannelItems.Count} 个通道数据设置到GridMap中");
LogManager.Info($"【生成网格地图】已将 {channelCoverage.ChannelItems.Count} 个通道数据设置到GridMap中");
}
var elapsed = (DateTime.Now - startTime).TotalMilliseconds;
LogManager.Info($"【包围盒2.5D模式】网格地图生成完成: {channelCoverage.GridMap.GetStatistics()}");
LogManager.Info($"【包围盒2.5D模式】总耗时: {elapsed:F1}ms");
LogManager.Info($"【生成网格地图】网格地图生成完成: {channelCoverage.GridMap.GetStatistics()}");
LogManager.Info($"【生成网格地图】总耗时: {elapsed:F1}ms");
return channelCoverage.GridMap;
}
catch (Exception ex)
{
LogManager.Error($"【包围盒2.5D模式】生成失败: {ex.Message}");
LogManager.Error($"【生成网格地图】生成失败: {ex.Message}");
return null;
}
}