优自动规划几何体获取逻辑,统一使用DFS遍历和过滤,过滤隐藏项
This commit is contained in:
parent
66353f9621
commit
e2fb22efe6
@ -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>();
|
||||
|
||||
// 阶段1:Search API预筛选(一次性批量获取几何体项目)
|
||||
var geometryItems = GetGeometryItemsUsingSearchAPI();
|
||||
var geometryItems = ModelItemAnalysisHelper.GetAllVisibleGeometryItems();
|
||||
|
||||
LogManager.Info($"[高性能障碍物处理] 输入统计 - 几何体项目: {geometryItems.Count}, 通道元素: {traversableItemsSet.Count}");
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}, "自动路径规划");
|
||||
}
|
||||
|
||||
|
||||
@ -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 数据结构定义
|
||||
|
||||
Loading…
Reference in New Issue
Block a user