diff --git a/CLAUDE.md b/CLAUDE.md index e5d3810..80d2b3b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -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 -- 不要搞向后兼容 \ No newline at end of file +- 不要搞向后兼容 diff --git a/src/Core/PathPlanningManager.cs b/src/Core/PathPlanningManager.cs index 7b95aee..023c55a 100644 --- a/src/Core/PathPlanningManager.cs +++ b/src/Core/PathPlanningManager.cs @@ -829,7 +829,6 @@ namespace NavisworksTransport try { - LogManager.Info($"开始调用GridMapGenerator.GenerateFromBIM(2.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) diff --git a/src/PathPlanning/AutoPathFinder.cs b/src/PathPlanning/AutoPathFinder.cs index 56503e7..07ca37b 100644 --- a/src/PathPlanning/AutoPathFinder.cs +++ b/src/PathPlanning/AutoPathFinder.cs @@ -48,45 +48,6 @@ namespace NavisworksTransport.PathPlanning /// public class AutoPathFinder { - /// - /// 查找路径(支持通道数据和高度约束) - /// - /// 起点(世界坐标) - /// 终点(世界坐标) - /// 网格地图 - /// 通道覆盖数据(可选,用于2.5D路径规划) - /// 车辆高度(模型单位,用于高度约束检查) - /// 路径查找结果 - public PathFindingResult FindPath(Point3D start, Point3D end, GridMap gridMap, ChannelCoverage channelCoverage, double vehicleHeight) - { - // 调用支持策略的重载方法,默认使用最短路径策略 - return FindPath(start, end, gridMap, channelCoverage, vehicleHeight, PathStrategy.Shortest); - } - - /// - /// 查找路径(支持通道数据、高度约束和路径策略) - /// - /// 起点(世界坐标) - /// 终点(世界坐标) - /// 网格地图 - /// 通道覆盖数据(可选,用于2.5D路径规划) - /// 车辆高度(模型单位,用于高度约束检查) - /// 路径规划策略 - /// 路径查找结果 - 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() }; - } - /// /// 2.5D路径规划(使用通道覆盖数据、高度约束和路径策略) /// @@ -97,7 +58,7 @@ namespace NavisworksTransport.PathPlanning /// 车辆高度(模型单位) /// 路径规划策略 /// 路径查找结果 - 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 { diff --git a/src/PathPlanning/GridMapGenerator.cs b/src/PathPlanning/GridMapGenerator.cs index a15bc7e..01d87df 100644 --- a/src/PathPlanning/GridMapGenerator.cs +++ b/src/PathPlanning/GridMapGenerator.cs @@ -46,152 +46,8 @@ namespace NavisworksTransport.PathPlanning _verticalScanner = null; } - /// - /// 从BIM模型生成网格地图 - /// - /// Navisworks文档 - /// 规划区域边界 - /// 网格单元格大小(米) - /// 车辆半径(用于障碍物膨胀) - /// 安全间隙(额外的膨胀间距,米) - /// 规划起点(用于确定楼层) - /// 规划终点(用于确定楼层) - /// 网格生成模式,默认为2.5D模式 - /// 车辆高度(用于垂直通行检查) - /// 生成的网格地图 - 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); - } - } - - /// - /// 通道基础2.5D模式的网格生成 - /// 使用通道优先策略和垂直扫描处理器 - /// - /// 术语说明: - /// - "通道"在此指所有可通行结构(楼板、走廊、过道等) - /// - 对于楼板类通道,车辆在其顶面行驶 - /// - 生成的网格地图用于车辆路径规划 - /// - 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(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; - } - } - /// /// 基于包围盒遍历的网格地图生成方法(优化版) - /// 使用简化的包围盒检测替代空间索引+垂直扫描,提升性能 /// /// Navisworks文档 /// 扫描边界 @@ -202,61 +58,61 @@ namespace NavisworksTransport.PathPlanning /// 规划终点 /// 车辆高度(米) /// 生成的网格地图 - 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(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; } }