优化三角形提取性能 - 实现批量COM Selection创建

问题分析:
- 当前逐个ModelItem创建COM Selection(290次)
- 从290个模型项提取776140个三角形耗时较长
- COM对象创建/销毁开销大

优化方案:
1. 新增 GeometryHelper.ExtractTrianglesBatch 方法
   - 批量创建COM Selection(290次 → 1次)
   - 一次性提取所有模型项的三角形
   - 添加进度日志(每100个片段输出一次)

2. 修改 NavisworksToDMesh3Converter.ConvertFromModelItems
   - 从逐个调用 ExtractTriangles 改为批量调用 ExtractTrianglesBatch
   - 添加详细的耗时统计(毫秒和秒)
   - 添加 System.Linq 引用支持ToList()

3. 保留原有 ExtractTriangles 方法
   - 向后兼容单个模型项提取场景
   - 用于小规模提取或特殊场景

预期效果:
- COM Selection创建:290次 → 1次
- 预计性能提升:50-70%
- 日志更详细,便于性能分析

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
tian 2025-10-13 09:34:52 +08:00
parent 2e9b9fe2b3
commit 51be24161d
2 changed files with 108 additions and 25 deletions

View File

@ -124,7 +124,104 @@ namespace NavisworksTransport
}
/// <summary>
/// 提取三角形
/// 批量提取三角形(优化版本)
/// </summary>
/// <param name="modelItems">模型项集合</param>
/// <returns>三角形集合</returns>
public static List<Triangle3D> ExtractTrianglesBatch(IEnumerable<ModelItem> modelItems)
{
var triangles = new List<Triangle3D>();
ComApi.InwOpSelection comSelection = null;
try
{
// 批量转换为 COM 选择 - 性能优化关键
var modelCollection = new ModelItemCollection();
int itemCount = 0;
foreach (var item in modelItems)
{
modelCollection.Add(item);
itemCount++;
}
LogManager.Info($"[批量提取] 开始批量提取 {itemCount} 个模型项的三角形");
var comState = ComStateManager.GetState();
comSelection = ComApiBridge.ToInwOpSelection(modelCollection);
LogManager.Debug($"[批量提取] COM 选择创建成功,路径数: {comSelection.Paths().Count}");
// 获取所有片段
var allFragments = GetAllFragments(comSelection);
LogManager.Info($"[批量提取] 获取到 {allFragments.Count} 个片段");
try
{
int processedFragments = 0;
foreach (var fragmentInfo in allFragments)
{
try
{
var callback = new OptimizedGeometryCallback(fragmentInfo.TransformMatrix);
fragmentInfo.Fragment.GenerateSimplePrimitives(
ComApi.nwEVertexProperty.eNORMAL,
callback);
var fragmentTriangles = callback.GetTriangles();
triangles.AddRange(fragmentTriangles);
processedFragments++;
// 每处理100个片段输出一次进度
if (processedFragments % 100 == 0)
{
LogManager.Debug($"[批量提取] 已处理 {processedFragments}/{allFragments.Count} 个片段,累计三角形: {triangles.Count}");
}
}
catch (Exception ex)
{
LogManager.Error($"[批量提取] 处理片段失败: {ex.Message}");
}
}
LogManager.Info($"[批量提取] 片段处理完成,共提取 {triangles.Count} 个三角形");
}
finally
{
// 释放所有片段COM对象
foreach (var fragmentInfo in allFragments)
{
try
{
if (fragmentInfo.Fragment != null)
{
Marshal.ReleaseComObject(fragmentInfo.Fragment);
}
}
catch (Exception ex)
{
LogManager.Warning($"[批量提取] 释放片段COM对象失败: {ex.Message}");
}
}
}
}
catch (Exception ex)
{
LogManager.Error($"[批量提取] 提取三角形失败: {ex.Message}");
}
finally
{
// 释放COM对象避免内存泄漏
if (comSelection != null)
{
Marshal.ReleaseComObject(comSelection);
}
}
return triangles;
}
/// <summary>
/// 提取三角形(单个模型项)
/// </summary>
/// <param name="modelItem">模型项</param>
/// <returns>三角形集合</returns>
@ -146,7 +243,7 @@ namespace NavisworksTransport
LogManager.Debug($"COM 选择创建成功,路径数: {comSelection.Paths().Count}");
// 获取所有片段(已移除错误的去重逻辑)
// 获取所有片段
var allFragments = GetAllFragments(comSelection);
LogManager.Debug($"获取到 {allFragments.Count} 个片段");
@ -208,7 +305,7 @@ namespace NavisworksTransport
}
/// <summary>
/// 获取所有片段(移除错误的去重逻辑)
/// 获取所有片段
/// </summary>
/// <param name="selection">COM 选择</param>
/// <returns>所有片段信息集合</returns>

View File

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Autodesk.Navisworks.Api;
using NavisworksTransport.Utils;
using g4;
@ -138,33 +139,18 @@ namespace NavisworksTransport
LogManager.Info("[DMesh3转换] 开始从 ModelItem 批量提取和转换");
// 收集所有三角形
var allTriangles = new List<Triangle3D>();
int itemCount = 0;
// 批量提取所有三角形 - 性能优化
var extractStopwatch = System.Diagnostics.Stopwatch.StartNew();
foreach (var item in items)
{
try
{
itemCount++;
var triangles = GeometryHelper.ExtractTriangles(item);
var itemsList = items.ToList();
int itemCount = itemsList.Count;
if (triangles != null && triangles.Count > 0)
{
allTriangles.AddRange(triangles);
LogManager.Debug($"[DMesh3转换] 从 {item.DisplayName} 提取了 {triangles.Count} 个三角形");
}
}
catch (Exception ex)
{
LogManager.Warning($"[DMesh3转换] 从 ModelItem {item.DisplayName} 提取几何体失败: {ex.Message}");
}
}
LogManager.Info($"[DMesh3转换] 共 {itemCount} 个模型项,使用批量提取方式");
var allTriangles = GeometryHelper.ExtractTrianglesBatch(itemsList);
extractStopwatch.Stop();
LogManager.Info($"[DMesh3转换] 从 {itemCount} 个模型项共提取 {allTriangles.Count} 个三角形,耗时: {extractStopwatch.ElapsedMilliseconds} ms");
LogManager.Info($"[DMesh3转换] 从 {itemCount} 个模型项共提取 {allTriangles.Count} 个三角形,耗时: {extractStopwatch.ElapsedMilliseconds} ms ({extractStopwatch.Elapsed.TotalSeconds:F2}秒)");
// 转换为 DMesh3
return Convert(allTriangles);