修改一个网格生成时的单位转换bug

This commit is contained in:
tian 2025-09-20 11:06:13 +08:00
parent 328263e846
commit 8c8ce89978

View File

@ -62,11 +62,23 @@ namespace NavisworksTransport.PathPlanning
{ {
LogManager.Info("【生成网格地图】开始生成网格地图"); LogManager.Info("【生成网格地图】开始生成网格地图");
var startTime = DateTime.Now; var startTime = DateTime.Now;
// 重要:将米制网格大小转换为模型单位 // 第一步:统一转换所有米制参数为模型单位
double metersToModelUnitsConversionFactor = UnitsConverter.GetMetersToUnitsConversionFactor(Application.ActiveDocument.Units); double metersToModelUnitsConversionFactor = UnitsConverter.GetMetersToUnitsConversionFactor(Application.ActiveDocument.Units);
double cellSizeInModelUnits = cellSize * metersToModelUnitsConversionFactor; double cellSizeInModelUnits = cellSize * metersToModelUnitsConversionFactor;
LogManager.Info($"【生成网格地图】网格大小单位转换: {cellSize}米 → {cellSizeInModelUnits:F2}模型单位 (转换系数: {metersToModelUnitsConversionFactor:F2})"); double vehicleRadiusInModelUnits = vehicleRadius * metersToModelUnitsConversionFactor;
double safetyMarginInModelUnits = safetyMargin * metersToModelUnitsConversionFactor;
double vehicleHeightInModelUnits = vehicleHeight * metersToModelUnitsConversionFactor;
double scanHeightInModelUnits = vehicleHeightInModelUnits + safetyMarginInModelUnits; // 扫描高度 = 车辆高度 + 安全间隙
double totalInflationRadiusInModelUnits = vehicleRadiusInModelUnits + safetyMarginInModelUnits; // 膨胀半径 = 车辆半径 + 安全间隙
LogManager.Info($"【生成网格地图】参数单位转换完成 (转换系数: {metersToModelUnitsConversionFactor:F2}):");
LogManager.Info($" 网格大小: {cellSize}米 → {cellSizeInModelUnits:F2}模型单位");
LogManager.Info($" 车辆半径: {vehicleRadius}米 → {vehicleRadiusInModelUnits:F2}模型单位");
LogManager.Info($" 安全间隙: {safetyMargin}米 → {safetyMarginInModelUnits:F2}模型单位");
LogManager.Info($" 车辆高度: {vehicleHeight}米 → {vehicleHeightInModelUnits:F2}模型单位");
LogManager.Info($" 扫描高度: {scanHeightInModelUnits:F2}模型单位");
LogManager.Info($" 膨胀半径: {totalInflationRadiusInModelUnits:F2}模型单位");
// 1. 使用通道构建器构建基础通道覆盖网格 // 1. 使用通道构建器构建基础通道覆盖网格
LogManager.Info("【生成网格地图】步骤1: 构建通道覆盖网格"); LogManager.Info("【生成网格地图】步骤1: 构建通道覆盖网格");
@ -88,15 +100,14 @@ namespace NavisworksTransport.PathPlanning
// 2. 直接遍历处理障碍物(包围盒检测) - 使用高性能优化版本 // 2. 直接遍历处理障碍物(包围盒检测) - 使用高性能优化版本
LogManager.Info("【生成网格地图】步骤2: 高性能包围盒遍历处理障碍物"); LogManager.Info("【生成网格地图】步骤2: 高性能包围盒遍历处理障碍物");
double scanHeight = vehicleHeight + safetyMargin; // 扫描高度 = 车辆高度 + 安全间隙 double minChannelTopZ = channelCoverage.MinChannelTopZ; // 提取最小通道顶面高度(模型单位)
double minChannelTopZ = channelCoverage.MinChannelTopZ; // 提取最小通道顶面高度 ProcessObstaclesWithBoundingBoxOptimized(document, channelCoverage.GridMap, channelRelatedItems, scanHeightInModelUnits, minChannelTopZ);
ProcessObstaclesWithBoundingBoxOptimized(document, channelCoverage.GridMap, channelRelatedItems, scanHeight, minChannelTopZ);
LogManager.Info($"【阶段2完成】障碍物处理后网格统计: {channelCoverage.GridMap.GetStatistics()}"); LogManager.Info($"【阶段2完成】障碍物处理后网格统计: {channelCoverage.GridMap.GetStatistics()}");
// 2.5. 为所有可通行网格设置PassableHeights确保高度约束检查 // 2.5. 为所有可通行网格设置PassableHeights确保高度约束检查
LogManager.Info("【生成网格地图】步骤2.5: 为可通行网格设置高度约束"); LogManager.Info("【生成网格地图】步骤2.5: 为可通行网格设置高度约束");
SetChannelPassableHeights(channelCoverage.GridMap, scanHeight); SetChannelPassableHeights(channelCoverage.GridMap, scanHeightInModelUnits);
LogManager.Info($"【阶段2.5完成】高度约束设置后网格统计: {channelCoverage.GridMap.GetStatistics()}"); LogManager.Info($"【阶段2.5完成】高度约束设置后网格统计: {channelCoverage.GridMap.GetStatistics()}");
// 2.6. 单独处理门元素,设置为可通行,并设置通行高度 // 2.6. 单独处理门元素,设置为可通行,并设置通行高度
@ -108,10 +119,8 @@ namespace NavisworksTransport.PathPlanning
if (vehicleRadius > 0 || safetyMargin > 0) if (vehicleRadius > 0 || safetyMargin > 0)
{ {
LogManager.Info("【生成网格地图】步骤3: 应用车辆膨胀"); LogManager.Info("【生成网格地图】步骤3: 应用车辆膨胀");
double metersToModelUnits = UnitsConverter.GetMetersToUnitsConversionFactor(Application.ActiveDocument.Units); ApplyVehicleInflation(channelCoverage.GridMap, totalInflationRadiusInModelUnits);
double totalInflationRadius = (vehicleRadius + safetyMargin) * metersToModelUnits; LogManager.Info($"【生成网格地图】车辆膨胀完成,膨胀半径: {totalInflationRadiusInModelUnits:F2}模型单位");
ApplyVehicleInflation(channelCoverage.GridMap, totalInflationRadius);
LogManager.Info($"【生成网格地图】车辆膨胀完成,膨胀半径: {totalInflationRadius:F2}模型单位");
LogManager.Info($"【阶段3完成】车辆膨胀后网格统计: {channelCoverage.GridMap.GetStatistics()}"); LogManager.Info($"【阶段3完成】车辆膨胀后网格统计: {channelCoverage.GridMap.GetStatistics()}");
} }
@ -195,7 +204,7 @@ namespace NavisworksTransport.PathPlanning
// 获取门的限高属性 // 获取门的限高属性
string heightLimitStr = CategoryAttributeManager.GetLogisticsPropertyValue(doorItem, CategoryAttributeManager.LogisticsProperties.HEIGHT_LIMIT); string heightLimitStr = CategoryAttributeManager.GetLogisticsPropertyValue(doorItem, CategoryAttributeManager.LogisticsProperties.HEIGHT_LIMIT);
double configuredHeight = CategoryAttributeManager.ParseLogisticsLimitValue(heightLimitStr, "限高"); double configuredHeight = CategoryAttributeManager.ParseLogisticsLimitValue(heightLimitStr, "限高");
// 计算门的实际物理高度 // 计算门的实际物理高度
double actualDoorHeight = bbox.Max.Z - bbox.Min.Z; double actualDoorHeight = bbox.Max.Z - bbox.Min.Z;
@ -270,14 +279,10 @@ namespace NavisworksTransport.PathPlanning
/// 为所有可通行网格设置PassableHeights确保高度约束检查 /// 为所有可通行网格设置PassableHeights确保高度约束检查
/// </summary> /// </summary>
/// <param name="gridMap">网格地图</param> /// <param name="gridMap">网格地图</param>
/// <param name="scanHeight">扫描高度(车辆高度+安全间隙</param> /// <param name="scanHeightInModelUnits">扫描高度(模型单位</param>
private void SetChannelPassableHeights(GridMap gridMap, double scanHeight) private void SetChannelPassableHeights(GridMap gridMap, double scanHeightInModelUnits)
{ {
// scanHeight是米需要转换为模型单位 LogManager.Info($"【高度约束设置】开始为所有可通行网格设置高度约束,扫描高度: {scanHeightInModelUnits:F2}模型单位");
double metersToModelUnits = UnitsConverter.GetMetersToUnitsConversionFactor(Application.ActiveDocument.Units);
double scanHeightInModelUnits = scanHeight * metersToModelUnits;
LogManager.Info($"【高度约束设置】开始为所有可通行网格设置高度约束,扫描高度: {scanHeight:F2}米 ({scanHeightInModelUnits:F2}模型单位)");
int processedCount = 0; int processedCount = 0;
for (int x = 0; x < gridMap.Width; x++) for (int x = 0; x < gridMap.Width; x++)
@ -563,17 +568,17 @@ namespace NavisworksTransport.PathPlanning
/// 在障碍物周围扩展不可通行区域,考虑车辆尺寸 /// 在障碍物周围扩展不可通行区域,考虑车辆尺寸
/// </summary> /// </summary>
/// <param name="gridMap">网格地图</param> /// <param name="gridMap">网格地图</param>
/// <param name="vehicleRadius">车辆半径</param> /// <param name="vehicleRadiusInModelUnits">车辆半径(模型单位)</param>
public void ApplyVehicleInflation(GridMap gridMap, double vehicleRadius) private void ApplyVehicleInflation(GridMap gridMap, double vehicleRadiusInModelUnits)
{ {
if (vehicleRadius <= 0) return; if (vehicleRadiusInModelUnits <= 0) return;
try try
{ {
// 计算膨胀半径(网格单元格数) // 计算膨胀半径(网格单元格数)
int inflationRadius = (int)Math.Ceiling(vehicleRadius / gridMap.CellSize); int inflationRadius = (int)Math.Ceiling(vehicleRadiusInModelUnits / gridMap.CellSize);
LogManager.Info($"[高效膨胀] 膨胀半径: {inflationRadius}个网格单元"); LogManager.Info($"[高效膨胀] 膨胀半径: {inflationRadius}个网格单元");
// 使用高效的距离变换算法 // 使用高效的距离变换算法
ApplyVehicleInflationOptimized(gridMap, inflationRadius); ApplyVehicleInflationOptimized(gridMap, inflationRadius);
} }
@ -977,7 +982,7 @@ namespace NavisworksTransport.PathPlanning
List<ModelItem> geometryItems, List<ModelItem> geometryItems,
HashSet<ModelItem> channelItemsSet, HashSet<ModelItem> channelItemsSet,
GridMap gridMap, GridMap gridMap,
double scanHeight, double scanHeightInModelUnits,
double minChannelTopZ) double minChannelTopZ)
{ {
LogManager.Info("[轻量级后处理] 开始处理Search API筛选结果"); LogManager.Info("[轻量级后处理] 开始处理Search API筛选结果");
@ -1038,7 +1043,7 @@ namespace NavisworksTransport.PathPlanning
} }
// 快速计算高度范围检查纯数值计算无API调用 // 快速计算高度范围检查纯数值计算无API调用
properties.IsInScanHeightRange = IsInScanHeightRange(properties.BoundingBox, minChannelTopZ, scanHeight); properties.IsInScanHeightRange = IsInScanHeightRange(properties.BoundingBox, minChannelTopZ, scanHeightInModelUnits);
if (!properties.IsInScanHeightRange) if (!properties.IsInScanHeightRange)
{ {
skippedByHeight++; skippedByHeight++;
@ -1068,9 +1073,9 @@ namespace NavisworksTransport.PathPlanning
/// <param name="document">Navisworks文档</param> /// <param name="document">Navisworks文档</param>
/// <param name="gridMap">网格地图</param> /// <param name="gridMap">网格地图</param>
/// <param name="channelItems">通道模型项列表</param> /// <param name="channelItems">通道模型项列表</param>
/// <param name="scanHeight">扫描高度范围</param> /// <param name="scanHeightInModelUnits">扫描高度范围(模型单位)</param>
/// <param name="minChannelTopZ">最小通道顶面高度,用作扫描基准</param> /// <param name="minChannelTopZ">最小通道顶面高度,用作扫描基准</param>
private void ProcessObstaclesWithBoundingBoxOptimized(Document document, GridMap gridMap, HashSet<ModelItem> channelItems, double scanHeight, double minChannelTopZ) private void ProcessObstaclesWithBoundingBoxOptimized(Document document, GridMap gridMap, HashSet<ModelItem> channelItems, double scanHeightInModelUnits, double minChannelTopZ)
{ {
try try
{ {
@ -1085,7 +1090,7 @@ namespace NavisworksTransport.PathPlanning
LogManager.Info($"[高性能障碍物处理] 输入统计 - 几何体项目: {geometryItems.Count}, 通道元素: {channelItemsSet.Count}"); LogManager.Info($"[高性能障碍物处理] 输入统计 - 几何体项目: {geometryItems.Count}, 通道元素: {channelItemsSet.Count}");
// 阶段2轻量级后处理只对预筛选结果进行必要的API调用 // 阶段2轻量级后处理只对预筛选结果进行必要的API调用
var itemCache = PostProcessGeometryItems(geometryItems, channelItemsSet, gridMap, scanHeight, minChannelTopZ); var itemCache = PostProcessGeometryItems(geometryItems, channelItemsSet, gridMap, scanHeightInModelUnits, minChannelTopZ);
// 阶段3条件过滤并行数值计算- 使用50%CPU核心优化 // 阶段3条件过滤并行数值计算- 使用50%CPU核心优化
LogManager.Info("[高性能障碍物处理] 阶段3: 并行条件过滤"); LogManager.Info("[高性能障碍物处理] 阶段3: 并行条件过滤");
@ -1354,16 +1359,16 @@ namespace NavisworksTransport.PathPlanning
/// 检查包围盒是否在扫描高度范围内 /// 检查包围盒是否在扫描高度范围内
/// </summary> /// </summary>
/// <param name="bbox">包围盒</param> /// <param name="bbox">包围盒</param>
/// <param name="minChannelTopZ">最小通道顶面高度,用作扫描基准</param> /// <param name="minChannelTopZ">最小通道顶面高度,用作扫描基准(模型单位)</param>
/// <param name="scanHeight">扫描高度范围</param> /// <param name="scanHeightInModelUnits">扫描高度范围(模型单位)</param>
/// <returns>是否在高度范围内</returns> /// <returns>是否在高度范围内</returns>
private bool IsInScanHeightRange(BoundingBox3D bbox, double minChannelTopZ, double scanHeight) private bool IsInScanHeightRange(BoundingBox3D bbox, double minChannelTopZ, double scanHeightInModelUnits)
{ {
try try
{ {
// 使用最低通道顶面高度作为扫描基准,避免门高度干扰 // 使用最低通道顶面高度作为扫描基准,避免门高度干扰
var scanMinZ = minChannelTopZ; // 最低通道顶面 var scanMinZ = minChannelTopZ; // 最低通道顶面(模型单位)
var scanMaxZ = minChannelTopZ + scanHeight; // 从最低通道顶面向上扫描 var scanMaxZ = minChannelTopZ + scanHeightInModelUnits; // 从最低通道顶面向上扫描(模型单位)
// 检查包围盒的Z范围是否与扫描范围有重叠 // 检查包围盒的Z范围是否与扫描范围有重叠
return !(bbox.Max.Z < scanMinZ || bbox.Min.Z > scanMaxZ); return !(bbox.Max.Z < scanMinZ || bbox.Min.Z > scanMaxZ);