优自动规划几何体获取逻辑,统一使用DFS遍历和过滤,过滤隐藏项

This commit is contained in:
tian 2026-01-21 21:05:35 +08:00
parent 66353f9621
commit e2fb22efe6
3 changed files with 165 additions and 133 deletions

View File

@ -1180,131 +1180,7 @@ namespace NavisworksTransport.PathPlanning
}
/// <summary>
/// 使用Search API一次性获取所有有几何体的模型项
/// 这比逐项调用HasGeometry快得多
/// </summary>
private List<ModelItem> GetGeometryItemsUsingSearchAPI()
{
try
{
LogManager.Info("[Search API优化] 开始批量获取几何体项目");
var startTime = DateTime.Now;
// 统计模型总数
var totalModelItems = Application.ActiveDocument.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(Application.ActiveDocument, 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}");
// 🔥 关键优化使用PrimitiveTypes精确过滤线性几何体
// 基于多模型测试验证LINQ筛选条件(IsCollection, IsComposite, Children.Any)都返回0项
LogManager.Info("[Search API优化] 开始使用PrimitiveTypes过滤线性几何体");
var primitiveFilterStart = DateTime.Now;
int triangleCount = 0;
int lineOnlyCount = 0;
int pointOnlyCount = 0;
int snapPointOnlyCount = 0;
int textOnlyCount = 0;
int mixedCount = 0;
int noGeometryCount = 0;
var filteredItems = geometryItems.Where(item =>
{
try
{
var geometry = item.Geometry;
if (geometry == null)
{
noGeometryCount++;
return false;
}
var primitiveTypes = geometry.PrimitiveTypes;
// 统计各种图元类型
if (primitiveTypes.HasFlag(PrimitiveTypes.Triangles))
{
if (primitiveTypes == PrimitiveTypes.Triangles)
triangleCount++;
else
mixedCount++;
return true; // 包含三角形的几何体都保留
}
else if (primitiveTypes == PrimitiveTypes.Lines)
{
lineOnlyCount++;
return false; // 纯线条几何体过滤掉
}
else if (primitiveTypes == PrimitiveTypes.Points)
{
pointOnlyCount++;
return false; // 纯点几何体过滤掉
}
else if (primitiveTypes == PrimitiveTypes.SnapPoints)
{
snapPointOnlyCount++;
return false; // 纯捕捉点几何体过滤掉
}
else if (primitiveTypes == PrimitiveTypes.Text)
{
textOnlyCount++;
return false; // 纯文本几何体过滤掉
}
else
{
mixedCount++;
return true; // 其他混合类型保留
}
}
catch
{
return false; // 出错时跳过该项目
}
}).ToList();
var primitiveFilterElapsed = (DateTime.Now - primitiveFilterStart).TotalMilliseconds;
var filteredByPrimitives = geometryItems.Count() - filteredItems.Count;
LogManager.Info($"[Search API优化] PrimitiveTypes过滤完成: 过滤掉 {filteredByPrimitives} 个线性几何体,耗时: {primitiveFilterElapsed:F1}ms");
LogManager.Info($"[Search API优化] 图元类型统计 - 纯三角形: {triangleCount}, 纯线条: {lineOnlyCount}, 纯点: {pointOnlyCount}, 纯捕捉点: {snapPointOnlyCount}, 纯文本: {textOnlyCount}, 混合类型: {mixedCount}, 无几何体: {noGeometryCount}");
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>
private Dictionary<ModelItem, ItemProperties> PostProcessGeometryItems(
@ -1406,7 +1282,7 @@ namespace NavisworksTransport.PathPlanning
var traversableItemsSet = channelItems ?? new HashSet<ModelItem>();
// 阶段1Search API预筛选一次性批量获取几何体项目
var geometryItems = GetGeometryItemsUsingSearchAPI();
var geometryItems = ModelItemAnalysisHelper.GetAllVisibleGeometryItems();
LogManager.Info($"[高性能障碍物处理] 输入统计 - 几何体项目: {geometryItems.Count}, 通道元素: {traversableItemsSet.Count}");

View File

@ -1595,14 +1595,22 @@ namespace NavisworksTransport.UI.WPF.ViewModels
{
await SafeExecuteAsync(async () =>
{
if (!_hasStartPoint || !_hasEndPoint)
{
UpdateMainStatus("请先选择起点和终点");
return;
}
// 保存当前光标
var oldCursor = Mouse.OverrideCursor;
UpdateMainStatus("正在计算最优路径...", -1, true);
LogManager.Info("=== 开始执行自动路径规划 ===");
try
{
if (!_hasStartPoint || !_hasEndPoint)
{
UpdateMainStatus("请先选择起点和终点");
return;
}
// 设置等待光标
Mouse.OverrideCursor = Cursors.Wait;
UpdateMainStatus("正在计算最优路径...", -1, true);
LogManager.Info("=== 开始执行自动路径规划 ===");
// 确保在开始自动路径规划前清理任何残留的事件订阅
CleanupAutoPathEventSubscriptions();
@ -1709,6 +1717,12 @@ namespace NavisworksTransport.UI.WPF.ViewModels
}
}
}
}
finally
{
// 恢复光标
Mouse.OverrideCursor = oldCursor;
}
}, "自动路径规划");
}

View File

@ -344,6 +344,148 @@ namespace NavisworksTransport.Utils
}
#endregion
#region
/// <summary>
/// 获取所有可见的几何体项目DFS遍历 + 隐藏项过滤 + 几何体类型过滤)
/// 统一的几何体获取接口,供自动路径规划和动画检测预计算共同使用
/// </summary>
/// <returns>可见的几何体项目列表(只保留包含 Triangles 的几何体)</returns>
public static List<ModelItem> GetAllVisibleGeometryItems()
{
try
{
LogManager.Info("[几何体获取] 开始获取所有可见几何体项目");
var startTime = DateTime.Now;
// 统计模型总数
var totalModelItems = Application.ActiveDocument.Models.RootItemDescendantsAndSelf.Count();
LogManager.Info($"[几何体获取] 模型总数统计: {totalModelItems} 个模型项");
// 使用 Stack 模拟递归避免栈溢出
// Stack 初始容量设为 1000 以减少扩容
var stack = new Stack<ModelItem>(1000);
var visibleItems = new List<ModelItem>();
// 将所有模型的根节点压入栈
foreach (var model in Application.ActiveDocument.Models)
{
stack.Push(model.RootItem);
}
// 统计信息
int hiddenSkipped = 0; // 跳过的隐藏节点(包括其子节点)
int visibleCount = 0; // 可见节点总数
int triangleCount = 0; // 纯三角形几何体
int lineOnlyCount = 0; // 纯线条几何体(过滤)
int pointOnlyCount = 0; // 纯点几何体(过滤)
int snapPointOnlyCount = 0; // 纯捕捉点几何体(过滤)
int textOnlyCount = 0; // 纯文本几何体(过滤)
int mixedCount = 0; // 混合类型几何体
int noGeometryCount = 0; // 无几何体节点
while (stack.Count > 0)
{
var item = stack.Pop();
// 关键剪枝:如果节点显式隐藏,则跳过其整个分支(它的所有子节点都不可见)
if (item.IsHidden)
{
hiddenSkipped++;
continue;
}
visibleCount++;
// 🔥 优化只提取复合对象IsComposite = true或独立实体节点HasGeometry
// 原因:复合对象(如窗户)包含多个实体节点(玻璃、框架、把手)
// 我们只需要检测复合对象,不需要检测其子节点
bool isComposite = item.IsComposite;
bool hasGeometry = item.HasGeometry;
if (isComposite || hasGeometry)
{
// 复合对象或独立实体节点:检查几何体类型
var geometry = item.Geometry;
if (geometry != null)
{
var primitiveTypes = geometry.PrimitiveTypes;
// 统计各种图元类型
if (primitiveTypes.HasFlag(PrimitiveTypes.Triangles))
{
if (primitiveTypes == PrimitiveTypes.Triangles)
triangleCount++;
else
mixedCount++;
visibleItems.Add(item); // 只保留包含三角形的几何体
}
else if (primitiveTypes == PrimitiveTypes.Lines)
{
lineOnlyCount++;
// 不添加:纯线条几何体过滤掉
}
else if (primitiveTypes == PrimitiveTypes.Points)
{
pointOnlyCount++;
// 不添加:纯点几何体过滤掉
}
else if (primitiveTypes == PrimitiveTypes.SnapPoints)
{
snapPointOnlyCount++;
// 不添加:纯捕捉点几何体过滤掉
}
else if (primitiveTypes == PrimitiveTypes.Text)
{
textOnlyCount++;
// 不添加:纯文本几何体过滤掉
}
else
{
mixedCount++;
visibleItems.Add(item); // 其他混合类型保留
}
}
else
{
noGeometryCount++;
// 不添加:无几何体数据
}
// 复合对象不继续遍历子节点Clash Detective API 会自动处理)
// 独立实体节点:也没有子节点
}
else
{
// 空节点:继续遍历子节点
foreach (var child in item.Children)
{
stack.Push(child);
}
}
}
var elapsed = (DateTime.Now - startTime).TotalMilliseconds;
// 输出详细统计信息
LogManager.Info($"[几何体获取] DFS遍历完成总耗时: {elapsed:F1}ms");
LogManager.Info($"[几何体获取] 隐藏项过滤效果: 跳过 {hiddenSkipped} 个隐藏节点(包括其子节点)");
LogManager.Info($"[几何体获取] 可见节点统计: {visibleCount} 个可见节点");
LogManager.Info($"[几何体获取] 图元类型统计 - 纯三角形: {triangleCount}, 纯线条: {lineOnlyCount}, 纯点: {pointOnlyCount}, 纯捕捉点: {snapPointOnlyCount}, 纯文本: {textOnlyCount}, 混合类型: {mixedCount}, 无几何体: {noGeometryCount}");
LogManager.Info($"[几何体获取] 最终结果: {visibleItems.Count} 个几何体项目(只保留包含 Triangles 的几何体)");
return visibleItems;
}
catch (Exception ex)
{
LogManager.Error($"[几何体获取] 获取失败: {ex.Message}");
throw;
}
}
#endregion
}
#region