From e2fb22efe644622381c18b31b53ff52368fe2261 Mon Sep 17 00:00:00 2001
From: tian <11429339@qq.com>
Date: Wed, 21 Jan 2026 21:05:35 +0800
Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E8=87=AA=E5=8A=A8=E8=A7=84=E5=88=92?=
=?UTF-8?q?=E5=87=A0=E4=BD=95=E4=BD=93=E8=8E=B7=E5=8F=96=E9=80=BB=E8=BE=91?=
=?UTF-8?q?=EF=BC=8C=E7=BB=9F=E4=B8=80=E4=BD=BF=E7=94=A8DFS=E9=81=8D?=
=?UTF-8?q?=E5=8E=86=E5=92=8C=E8=BF=87=E6=BB=A4=EF=BC=8C=E8=BF=87=E6=BB=A4?=
=?UTF-8?q?=E9=9A=90=E8=97=8F=E9=A1=B9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/PathPlanning/GridMapGenerator.cs | 128 +---------------
src/UI/WPF/ViewModels/PathEditingViewModel.cs | 28 +++-
src/Utils/ModelItemAnalysisHelper.cs | 142 ++++++++++++++++++
3 files changed, 165 insertions(+), 133 deletions(-)
diff --git a/src/PathPlanning/GridMapGenerator.cs b/src/PathPlanning/GridMapGenerator.cs
index 8ed1f87..f7a7681 100644
--- a/src/PathPlanning/GridMapGenerator.cs
+++ b/src/PathPlanning/GridMapGenerator.cs
@@ -1180,131 +1180,7 @@ namespace NavisworksTransport.PathPlanning
}
///
- /// 使用Search API一次性获取所有有几何体的模型项
- /// 这比逐项调用HasGeometry快得多
- ///
- private List 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;
- }
- }
-
- ///
- /// 轻量级后处理:只对Search API预筛选的几何体项目进行必要的属性提取
+ /// 轻量级后处理:只对预筛选的几何体项目进行必要的属性提取
/// 大幅减少API调用次数
///
private Dictionary PostProcessGeometryItems(
@@ -1406,7 +1282,7 @@ namespace NavisworksTransport.PathPlanning
var traversableItemsSet = channelItems ?? new HashSet();
// 阶段1:Search API预筛选(一次性批量获取几何体项目)
- var geometryItems = GetGeometryItemsUsingSearchAPI();
+ var geometryItems = ModelItemAnalysisHelper.GetAllVisibleGeometryItems();
LogManager.Info($"[高性能障碍物处理] 输入统计 - 几何体项目: {geometryItems.Count}, 通道元素: {traversableItemsSet.Count}");
diff --git a/src/UI/WPF/ViewModels/PathEditingViewModel.cs b/src/UI/WPF/ViewModels/PathEditingViewModel.cs
index 5040a6c..0b2e2d1 100644
--- a/src/UI/WPF/ViewModels/PathEditingViewModel.cs
+++ b/src/UI/WPF/ViewModels/PathEditingViewModel.cs
@@ -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;
+ }
}, "自动路径规划");
}
diff --git a/src/Utils/ModelItemAnalysisHelper.cs b/src/Utils/ModelItemAnalysisHelper.cs
index ad698eb..39ba9ec 100644
--- a/src/Utils/ModelItemAnalysisHelper.cs
+++ b/src/Utils/ModelItemAnalysisHelper.cs
@@ -344,6 +344,148 @@ namespace NavisworksTransport.Utils
}
#endregion
+
+ #region 几何体获取方法
+
+ ///
+ /// 获取所有可见的几何体项目(DFS遍历 + 隐藏项过滤 + 几何体类型过滤)
+ /// 统一的几何体获取接口,供自动路径规划和动画检测预计算共同使用
+ ///
+ /// 可见的几何体项目列表(只保留包含 Triangles 的几何体)
+ public static List 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(1000);
+ var visibleItems = new List();
+
+ // 将所有模型的根节点压入栈
+ 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 数据结构定义