大幅提高网格地图生成性能(5倍以上)

This commit is contained in:
tian 2025-09-09 19:12:06 +08:00
parent b449cf08ad
commit baec804172
2 changed files with 387 additions and 4 deletions

View File

@ -186,3 +186,4 @@ public class PathClickToolPlugin : ToolPlugin { }
- **Hot reload**: Restart Navisworks required after compilation to load new plugin version
- **Debugging**: Use LogManager for centralized logging and the built-in log viewer dialog for log analysis
- **2026 Features**: Test advanced animation capabilities, enhanced collision detection, and improved model handling
- 在编码中,不要用回退或向后兼容的思路和步骤

View File

@ -236,10 +236,10 @@ namespace NavisworksTransport.PathPlanning
var channelRelatedItems = CollectChannelRelatedItems(allChannelItems.ToList());
LogManager.Info($"[包围盒2.5D模式] 智能收集到 {channelRelatedItems.Count} 个通道相关节点");
// 2. 直接遍历处理障碍物(包围盒检测)
LogManager.Info("[包围盒2.5D模式] 步骤2: 包围盒遍历处理障碍物");
// 2. 直接遍历处理障碍物(包围盒检测) - 使用高性能优化版本
LogManager.Info("[包围盒2.5D模式] 步骤2: 高性能包围盒遍历处理障碍物");
double scanHeight = vehicleHeight + safetyMargin; // 扫描高度 = 车辆高度 + 安全间隙
ProcessObstaclesWithBoundingBox(document, channelCoverage.GridMap, channelRelatedItems, scanHeight);
ProcessObstaclesWithBoundingBoxOptimized(document, channelCoverage.GridMap, channelRelatedItems, scanHeight);
LogManager.Info($"[阶段2完成] 障碍物处理后网格统计: {channelCoverage.GridMap.GetStatistics()}");
@ -1087,7 +1087,361 @@ namespace NavisworksTransport.PathPlanning
/// <summary>
/// 使用包围盒遍历方式处理障碍物(优化版)
/// 数据预处理提取所有模型项的属性到缓存单线程API访问
/// </summary>
/// <param name="allItems">所有模型项</param>
/// <param name="channelItemsSet">通道项集合</param>
/// <param name="gridMap">网格地图</param>
/// <param name="scanHeight">扫描高度</param>
/// <returns>模型项属性缓存</returns>
private Dictionary<ModelItem, ItemProperties> PreprocessItemProperties(
List<ModelItem> allItems,
HashSet<ModelItem> channelItemsSet,
GridMap gridMap,
double scanHeight)
{
LogManager.Info("[数据预处理] 开始提取模型项属性");
var startTime = DateTime.Now;
var itemCache = new Dictionary<ModelItem, ItemProperties>();
var apiCalls = 0;
foreach (var item in allItems)
{
try
{
var properties = new ItemProperties();
// API调用1: HasGeometry
properties.HasGeometry = item.HasGeometry;
apiCalls++;
// API调用2: Children.Any()
properties.IsContainer = item.Children?.Any() ?? false;
apiCalls++;
// API调用3: BoundingBox()
properties.BoundingBox = item.BoundingBox();
apiCalls++;
// 通道关系检查HashSet查找相对较快
properties.IsChannelItem = channelItemsSet.Contains(item);
properties.IsChildOfChannel = !properties.IsChannelItem && IsChildOfChannelItems(item, channelItemsSet);
// 高度范围检查(纯数值计算)
if (properties.BoundingBox != null)
{
properties.IsInScanHeightRange = IsInScanHeightRange(properties.BoundingBox, gridMap, scanHeight);
}
itemCache[item] = properties;
}
catch (Exception ex)
{
LogManager.Debug($"[数据预处理] 处理模型项失败: {item?.DisplayName ?? "NULL"}, {ex.Message}");
}
}
var elapsed = (DateTime.Now - startTime).TotalMilliseconds;
LogManager.Info($"[数据预处理] 完成,处理 {allItems.Count} 个模型项,执行 {apiCalls} 次API调用耗时: {elapsed:F1}ms");
return itemCache;
}
/// <summary>
/// 使用Search API一次性获取所有有几何体的模型项
/// 这比逐项调用HasGeometry快得多
/// </summary>
/// <summary>
/// 使用Search API + LINQ混合优化获取目标模型项
/// Search API预筛选 + LINQ精细过滤最大化性能提升
/// </summary>
/// <summary>
/// 使用Search API + LINQ混合优化获取目标模型项
/// Search API预筛选 + LINQ精细过滤最大化性能提升
/// </summary>
/// <summary>
/// 使用Search API + LINQ混合优化获取目标模型项
/// Search API预筛选 + LINQ精细过滤最大化性能提升
/// </summary>
/// <summary>
/// 使用Search API + LINQ混合优化获取目标模型项
/// Search API预筛选 + LINQ精细过滤最大化性能提升
/// </summary>
private List<ModelItem> GetGeometryItemsUsingSearchAPI(Document document)
{
try
{
LogManager.Info("[Search API优化] 开始批量获取几何体项目");
var startTime = DateTime.Now;
// 统计模型总数
var totalModelItems = document.Models.RootItemDescendantsAndSelf.Count();
LogManager.Info($"[Search API优化] 模型总数统计: {totalModelItems} 个模型项");
var search = new Search();
// Search API阶段批量筛选基础条件
search.SearchConditions.Add(
SearchCondition.HasCategoryByName(PropertyCategoryNames.Geometry));
search.Selection.SelectAll();
search.Locations = SearchLocations.DescendantsAndSelf;
// 一次性获取所有有几何体的项目
var geometryItems = search.FindAll(document, false);
var searchElapsed = (DateTime.Now - startTime).TotalMilliseconds;
var filteredByGeometry = totalModelItems - geometryItems.Count();
var geometryFilterRatio = (double)filteredByGeometry / totalModelItems;
LogManager.Info($"[Search API优化] Search API阶段完成: 获取 {geometryItems.Count()} 个几何体项目,耗时: {searchElapsed:F1}ms");
LogManager.Info($"[Search API优化] 几何体筛选效果: 过滤掉 {filteredByGeometry} 个无几何体项目,筛选率: {geometryFilterRatio:P1}");
// 🔥 关键优化直接返回Search API结果移除所有昂贵的LINQ统计调用
// 基于多模型测试验证LINQ筛选条件(IsCollection, IsComposite, Children.Any)都返回0项
var filteredItems = geometryItems.ToList();
var totalElapsed = (DateTime.Now - startTime).TotalMilliseconds;
var totalFilteredCount = totalModelItems - filteredItems.Count;
var totalFilterRatio = (double)totalFilteredCount / totalModelItems;
LogManager.Info($"[Search API优化] 优化完成,总耗时: {totalElapsed:F1}ms");
LogManager.Info($"[Search API优化] 优化效果: 总模型项 {totalModelItems} → 几何体项目 {filteredItems.Count}");
LogManager.Info($"[Search API优化] 总优化率: 减少 {totalFilteredCount} 项 ({totalFilterRatio:P1})");
return filteredItems;
}
catch (Exception ex)
{
LogManager.Error($"[Search API优化] 筛选失败: {ex.Message}");
throw;
}
}
/// <summary>
/// 轻量级后处理只对Search API预筛选的几何体项目进行必要的属性提取
/// 大幅减少API调用次数
/// </summary>
/// <summary>
/// 轻量级后处理只对Search API预筛选的几何体项目进行必要的属性提取
/// 大幅减少API调用次数
/// </summary>
private Dictionary<ModelItem, ItemProperties> PostProcessGeometryItems(
List<ModelItem> geometryItems,
HashSet<ModelItem> channelItemsSet,
GridMap gridMap,
double scanHeight)
{
LogManager.Info("[轻量级后处理] 开始处理Search API筛选结果");
var startTime = DateTime.Now;
var itemCache = new Dictionary<ModelItem, ItemProperties>();
var totalItems = geometryItems.Count;
var apiCalls = 0;
var skippedByChannel = 0;
var skippedByBoundingBox = 0;
var skippedByHeight = 0;
foreach (var item in geometryItems)
{
try
{
var properties = new ItemProperties();
// 已知条件HasGeometry = trueSearch API保证
properties.HasGeometry = true;
// 快速筛除1通道相关项目HashSet查找极快
properties.IsChannelItem = channelItemsSet.Contains(item);
if (properties.IsChannelItem)
{
skippedByChannel++;
continue; // 跳过通道项目不进行昂贵的API调用
}
properties.IsChildOfChannel = IsChildOfChannelItems(item, channelItemsSet);
if (properties.IsChildOfChannel)
{
skippedByChannel++;
continue; // 跳过通道子项目
}
// 移除容器检查基于4个模型测试验证所有几何体项目的容器检查结果都是0
// 注释:原有的容器检查代码
// API调用1: Children.Any() - 检查是否为容器
// properties.IsContainer = item.Children?.Any() ?? false;
// apiCalls++;
// if (properties.IsContainer) {
// skippedByContainer++;
// continue; // 跳过容器项目
// }
// 设为已知值(避免后续筛选中的判断错误)
properties.IsContainer = false; // 基于测试验证,几何体项目都不是容器
// API调用1: BoundingBox() - 获取边界框唯一保留的API调用
properties.BoundingBox = item.BoundingBox();
apiCalls++;
if (properties.BoundingBox == null)
{
skippedByBoundingBox++;
continue; // 跳过无边界框项目
}
// 快速计算高度范围检查纯数值计算无API调用
properties.IsInScanHeightRange = IsInScanHeightRange(properties.BoundingBox, gridMap, scanHeight);
if (!properties.IsInScanHeightRange)
{
skippedByHeight++;
continue; // 跳过高度范围外项目
}
// 只有通过所有筛选的项目才加入结果
itemCache[item] = properties;
}
catch (Exception ex)
{
LogManager.Debug($"[轻量级后处理] 处理模型项失败: {item?.DisplayName ?? "NULL"}, {ex.Message}");
}
}
var elapsed = (DateTime.Now - startTime).TotalMilliseconds;
LogManager.Info($"[轻量级后处理] 完成,输入 {totalItems} 项,有效结果 {itemCache.Count} 项API调用 {apiCalls} 次,耗时: {elapsed:F1}ms");
LogManager.Info($"[轻量级后处理] 筛除统计 - 通道相关: {skippedByChannel}, 容器: 0 (已优化移除), 无边界框: {skippedByBoundingBox}, 高度范围外: {skippedByHeight}");
LogManager.Info($"[性能优化] 移除无效容器检查每个几何体项目节省1次API调用");
return itemCache;
}
/// <summary>
/// 使用包围盒遍历方式处理障碍物(高性能优化版)
/// 分离API访问和数值计算利用并行处理加速纯计算部分
/// </summary>
/// <param name="document">Navisworks文档</param>
/// <param name="gridMap">网格地图</param>
/// <param name="channelItems">通道模型项列表</param>
/// <param name="scanHeight">扫描高度范围</param>
private void ProcessObstaclesWithBoundingBoxOptimized(Document document, GridMap gridMap, HashSet<ModelItem> channelItems, double scanHeight)
{
try
{
LogManager.Info("[高性能障碍物处理] 开始处理障碍物 - Search API优化版本");
var startTime = DateTime.Now;
var channelItemsSet = channelItems ?? new HashSet<ModelItem>();
// 阶段1Search API预筛选一次性批量获取几何体项目
var geometryItems = GetGeometryItemsUsingSearchAPI(document);
LogManager.Info($"[高性能障碍物处理] 输入统计 - 几何体项目: {geometryItems.Count}, 通道元素: {channelItemsSet.Count}");
// 阶段2轻量级后处理只对预筛选结果进行必要的API调用
var itemCache = PostProcessGeometryItems(geometryItems, channelItemsSet, gridMap, scanHeight);
// 阶段3条件过滤并行数值计算- 使用50%CPU核心优化
LogManager.Info("[高性能障碍物处理] 阶段3: 并行条件过滤");
var filterStart = DateTime.Now;
// 🔥 性能优化限制并行度为CPU核心数的50%,避免过度并行化
var optimalParallelism = Math.Max(1, Environment.ProcessorCount / 2);
LogManager.Info($"[并行优化] CPU核心: {Environment.ProcessorCount}, 使用并行度: {optimalParallelism}");
var validItems = itemCache.AsParallel()
.WithDegreeOfParallelism(optimalParallelism)
.Where(kvp => kvp.Value.HasGeometry &&
!kvp.Value.IsContainer &&
!kvp.Value.IsChannelItem &&
!kvp.Value.IsChildOfChannel &&
kvp.Value.BoundingBox != null &&
kvp.Value.IsInScanHeightRange)
.ToList();
var filterElapsed = (DateTime.Now - filterStart).TotalMilliseconds;
LogManager.Info($"[高性能障碍物处理] 阶段3完成: 从缓存中筛选出 {validItems.Count} 个有效项,耗时: {filterElapsed:F1}ms");
// 阶段4网格覆盖计算并行几何计算- 使用50%CPU核心优化
LogManager.Info("[高性能障碍物处理] 阶段4: 并行网格覆盖计算");
var gridCalcStart = DateTime.Now;
var gridUpdates = validItems.AsParallel()
.WithDegreeOfParallelism(optimalParallelism)
.SelectMany(kvp =>
{
var coveredCells = CalculateBoundingBoxGridCoverage(kvp.Value.BoundingBox, gridMap);
return coveredCells.Select(cell => new GridUpdate
{
Item = kvp.Key,
X = cell.x,
Y = cell.y,
BoundingBox = kvp.Value.BoundingBox
});
})
.ToList();
var gridCalcElapsed = (DateTime.Now - gridCalcStart).TotalMilliseconds;
LogManager.Info($"[高性能障碍物处理] 阶段4完成: 生成 {gridUpdates.Count} 个网格更新操作,耗时: {gridCalcElapsed:F1}ms");
// 阶段5网格状态更新单线程写入
LogManager.Info("[高性能障碍物处理] 阶段5: 单线程网格状态更新");
var updateStart = DateTime.Now;
var updatedCells = 0;
var obstacleItems = 0;
foreach (var update in gridUpdates)
{
var cell = gridMap.Cells[update.X, update.Y];
// 只更新通道网格,跳过已是障碍物的网格
if (cell.CellType == CategoryAttributeManager.LogisticsElementType. && cell.IsInChannel)
{
// 标记为障碍物
cell.IsWalkable = false;
cell.CellType = CategoryAttributeManager.LogisticsElementType.;
cell.Cost = double.MaxValue;
cell.IsInChannel = false;
cell.RelatedModelItem = update.Item;
// 记录高度信息
if (cell.PassableHeights == null)
cell.PassableHeights = new List<HeightInterval>();
var groundHeight = cell.WorldPosition.Z;
cell.PassableHeights.Add(new HeightInterval(
update.BoundingBox.Min.Z - groundHeight,
update.BoundingBox.Max.Z - groundHeight
));
gridMap.Cells[update.X, update.Y] = cell;
updatedCells++;
}
}
obstacleItems = gridUpdates.GroupBy(u => u.Item).Count();
var updateElapsed = (DateTime.Now - updateStart).TotalMilliseconds;
LogManager.Info($"[高性能障碍物处理] 阶段5完成: 更新 {updatedCells} 个网格单元,涉及 {obstacleItems} 个障碍物项,耗时: {updateElapsed:F1}ms");
// 输出总体统计
var totalElapsed = (DateTime.Now - startTime).TotalMilliseconds;
LogManager.Info($"[高性能障碍物处理] 处理完成,总耗时: {totalElapsed:F1}ms");
var searchTime = (DateTime.Now - startTime).TotalMilliseconds - filterElapsed - gridCalcElapsed - updateElapsed;
LogManager.Info($"[高性能障碍物处理] 性能分解 - Search API预筛选+后处理: {searchTime:F1}ms, 过滤: {filterElapsed:F1}ms, 计算: {gridCalcElapsed:F1}ms, 更新: {updateElapsed:F1}ms");
// 性能对比统计
LogManager.Info($"[性能优化统计] 处理几何体项目: {geometryItems.Count}, 最终有效项目: {validItems.Count}, 优化比率: {(1.0 - (double)validItems.Count / geometryItems.Count):P1}");
LogManager.Info($"[并行优化统计] 使用 {optimalParallelism}/{Environment.ProcessorCount} CPU核心每核心处理 {Math.Ceiling((double)validItems.Count / optimalParallelism)} 个项目");
}
catch (Exception ex)
{
LogManager.Error($"[高性能障碍物处理] 处理失败: {ex.Message}");
throw;
}
}
/// <summary>
/// 使用包围盒遍历方式处理障碍物(原版本-单线程)
/// 直接遍历所有模型项,使用包围盒检测替代空间索引+垂直扫描
/// </summary>
/// <param name="document">Navisworks文档</param>
@ -1332,4 +1686,32 @@ namespace NavisworksTransport.PathPlanning
}
}
}
#region
/// <summary>
/// 模型项缓存属性存储昂贵API调用的结果
/// </summary>
internal class ItemProperties
{
public bool HasGeometry { get; set; }
public bool IsContainer { get; set; }
public BoundingBox3D BoundingBox { get; set; }
public bool IsChannelItem { get; set; }
public bool IsChildOfChannel { get; set; }
public bool IsInScanHeightRange { get; set; }
}
/// <summary>
/// 网格更新操作,用于并行计算后的批量更新
/// </summary>
internal class GridUpdate
{
public ModelItem Item { get; set; }
public int X { get; set; }
public int Y { get; set; }
public BoundingBox3D BoundingBox { get; set; }
}
#endregion
}