为几何体提取添加进度条支持,优化用户体验
主要改进: - 添加 Navisworks Progress API 支持到 ExtractTriangles 方法 - 实时显示片段处理进度(百分比) - 支持用户取消操作(IsCanceled 检查) - 移除批量日志输出,改用进度条展示 - 统一 ExtractTriangles 方法,移除单个项目的重复实现 - 在 finally 块中确保进度条正确关闭 文档更新: - 扩展 NavisworksAPI使用方法.md 中的进度条章节 - 添加详细的 Progress API 使用指南 - 包含实际应用案例、最佳实践和常见陷阱 - 提供完整的代码示例和性能优化建议 性能改进: - 每个片段更新一次进度(3516次调用,可接受) - 移除频繁的日志写入(每100个片段),减少 I/O 开销 - 保留关键日志(开始、结束、取消、错误) 用户体验提升: - 可视化进度反馈,避免假死感 - 支持随时取消长时间操作 - 优雅的错误处理和资源清理 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
51be24161d
commit
e12e1125d2
@ -1846,6 +1846,8 @@ using Autodesk.Navisworks.Api.Controls;
|
||||
|
||||
When instantiated a progress bar in the Navisworks style is displayed to the user inside the Navisworks main application. This can then be updated by the program or plugin with textual information as well as the percentage completed of the process.
|
||||
|
||||
#### 基础示例
|
||||
|
||||
```csharp
|
||||
/// <summary>
|
||||
/// Shows the basic concept of using the Progress class
|
||||
@ -1874,6 +1876,531 @@ private static void SimpleProgressExample()
|
||||
}
|
||||
```
|
||||
|
||||
#### 14.1 Progress API 核心方法详解
|
||||
|
||||
**Navisworks Progress API** 提供了原生的进度条显示功能,可以在耗时操作中向用户展示进度和允许取消操作。
|
||||
|
||||
**核心方法**:
|
||||
|
||||
```csharp
|
||||
// 1. BeginProgress() - 开始进度跟踪(无参数版本)
|
||||
Progress progress = Application.BeginProgress();
|
||||
|
||||
// 2. BeginProgress(string title) - 带标题版本(推荐)
|
||||
Progress progress = Application.BeginProgress("提取几何体");
|
||||
|
||||
// 3. progress.Update(double) - 更新进度(0.0 到 1.0)
|
||||
progress.Update(0.5); // 50% 进度
|
||||
|
||||
// 4. progress.IsCanceled - 检查用户是否取消
|
||||
if (progress.IsCanceled)
|
||||
{
|
||||
Application.EndProgress();
|
||||
return null;
|
||||
}
|
||||
|
||||
// 5. Application.EndProgress() - 结束进度跟踪
|
||||
Application.EndProgress();
|
||||
```
|
||||
|
||||
**Progress 类的重要成员**:
|
||||
|
||||
| 方法/属性 | 说明 |
|
||||
|---------|------|
|
||||
| `Update(double progress)` | 更新进度(0.0-1.0),显示百分比 |
|
||||
| `IsCanceled` | 只读属性,用户是否点击取消按钮 |
|
||||
| `BeginSubOperation(double, string)` | 开始子操作,分配总进度的一部分 |
|
||||
| `EndSubOperation()` | 结束当前子操作 |
|
||||
| `Hide()` | 隐藏进度对话框(如需打开其他窗口) |
|
||||
| `Show()` | 显示之前隐藏的进度对话框 |
|
||||
| `ReportError(int, string)` | 向用户报告错误 |
|
||||
|
||||
#### 14.2 带标题的进度条(推荐用法)
|
||||
|
||||
```csharp
|
||||
/// <summary>
|
||||
/// 带标题的进度条示例 - 提供更好的用户体验
|
||||
/// </summary>
|
||||
public void ProcessWithTitle()
|
||||
{
|
||||
Progress progress = null;
|
||||
try
|
||||
{
|
||||
// 创建带标题的进度条
|
||||
progress = Application.BeginProgress("处理模型数据",
|
||||
"正在分析 3516 个几何片段...");
|
||||
|
||||
int totalItems = 100;
|
||||
for (int i = 0; i < totalItems; i++)
|
||||
{
|
||||
// 执行处理逻辑
|
||||
ProcessItem(i);
|
||||
|
||||
// 更新进度
|
||||
progress.Update((double)i / totalItems);
|
||||
}
|
||||
|
||||
// 完成
|
||||
progress.Update(1.0);
|
||||
}
|
||||
finally
|
||||
{
|
||||
// 确保进度条被关闭
|
||||
if (progress != null)
|
||||
{
|
||||
Application.EndProgress();
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 14.3 支持用户取消操作
|
||||
|
||||
```csharp
|
||||
/// <summary>
|
||||
/// 支持取消的进度条示例
|
||||
/// </summary>
|
||||
public List<Triangle3D> ExtractWithCancellation(IEnumerable<ModelItem> items)
|
||||
{
|
||||
var results = new List<Triangle3D>();
|
||||
Progress progress = null;
|
||||
|
||||
try
|
||||
{
|
||||
progress = Application.BeginProgress("提取三角形",
|
||||
"正在提取几何数据,可随时取消...");
|
||||
|
||||
var itemList = items.ToList();
|
||||
int totalCount = itemList.Count;
|
||||
|
||||
for (int i = 0; i < totalCount; i++)
|
||||
{
|
||||
// ✅ 关键:检查用户是否取消
|
||||
if (progress.IsCanceled)
|
||||
{
|
||||
LogManager.Info($"[提取] 用户取消操作,已处理 {i}/{totalCount}");
|
||||
break; // 退出循环
|
||||
}
|
||||
|
||||
// 执行处理
|
||||
var triangles = ExtractTrianglesFromItem(itemList[i]);
|
||||
results.AddRange(triangles);
|
||||
|
||||
// 更新进度
|
||||
progress.Update((double)(i + 1) / totalCount);
|
||||
}
|
||||
|
||||
LogManager.Info($"[提取] 完成,共提取 {results.Count} 个三角形");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"[提取] 发生错误: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
// ✅ 关键:无论成功、失败还是取消,都要关闭进度条
|
||||
if (progress != null)
|
||||
{
|
||||
Application.EndProgress();
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
```
|
||||
|
||||
#### 14.4 子操作(SubOperation)用法
|
||||
|
||||
当任务有多个阶段时,可以使用子操作来细化进度显示:
|
||||
|
||||
```csharp
|
||||
/// <summary>
|
||||
/// 使用子操作的多阶段进度示例
|
||||
/// </summary>
|
||||
public void MultiStageProcess()
|
||||
{
|
||||
Progress progress = null;
|
||||
|
||||
try
|
||||
{
|
||||
progress = Application.BeginProgress("处理模型");
|
||||
|
||||
// 阶段1:分析模型结构(占总进度的20%)
|
||||
progress.BeginSubOperation(0.2, "正在分析模型结构...");
|
||||
var allFragments = AnalyzeModelStructure();
|
||||
progress.Update(1.0); // 子操作完成100%
|
||||
progress.EndSubOperation();
|
||||
|
||||
// 阶段2:提取几何数据(占总进度的70%)
|
||||
progress.BeginSubOperation(0.7, "正在提取几何数据...");
|
||||
for (int i = 0; i < allFragments.Count; i++)
|
||||
{
|
||||
if (progress.IsCanceled) break;
|
||||
|
||||
ProcessFragment(allFragments[i]);
|
||||
progress.Update((double)i / allFragments.Count);
|
||||
}
|
||||
progress.EndSubOperation();
|
||||
|
||||
// 阶段3:保存结果(占总进度的10%)
|
||||
progress.BeginSubOperation(0.1, "正在保存结果...");
|
||||
SaveResults();
|
||||
progress.Update(1.0);
|
||||
progress.EndSubOperation();
|
||||
|
||||
LogManager.Info("所有阶段完成");
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (progress != null)
|
||||
{
|
||||
Application.EndProgress();
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 14.5 实际应用:几何体提取中使用进度条
|
||||
|
||||
基于实际的 `ExtractTriangles` 方法,展示如何集成 Progress API:
|
||||
|
||||
```csharp
|
||||
/// <summary>
|
||||
/// 批量提取三角形(带进度条和取消支持)
|
||||
/// </summary>
|
||||
/// <param name="modelItems">模型项集合</param>
|
||||
/// <returns>三角形集合</returns>
|
||||
public static List<Triangle3D> ExtractTriangles(IEnumerable<ModelItem> modelItems)
|
||||
{
|
||||
var triangles = new List<Triangle3D>();
|
||||
ComApi.InwOpSelection comSelection = null;
|
||||
Progress progress = null;
|
||||
|
||||
try
|
||||
{
|
||||
// 第1步:批量转换为 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);
|
||||
|
||||
// 第2步:获取所有片段
|
||||
var allFragments = GetAllFragments(comSelection);
|
||||
LogManager.Info($"[批量提取] 获取到 {allFragments.Count} 个片段");
|
||||
|
||||
// 🎯 第3步:开始进度条
|
||||
progress = Application.BeginProgress("提取几何体",
|
||||
$"正在提取 {allFragments.Count} 个片段的三角形数据...");
|
||||
|
||||
try
|
||||
{
|
||||
int processedFragments = 0;
|
||||
foreach (var fragmentInfo in allFragments)
|
||||
{
|
||||
// 🎯 检查用户是否取消
|
||||
if (progress.IsCanceled)
|
||||
{
|
||||
LogManager.Info($"[批量提取] 用户取消操作,已处理 {processedFragments}/{allFragments.Count}");
|
||||
break;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var callback = new OptimizedGeometryCallback(fragmentInfo.TransformMatrix);
|
||||
fragmentInfo.Fragment.GenerateSimplePrimitives(
|
||||
ComApi.nwEVertexProperty.eNORMAL,
|
||||
callback);
|
||||
|
||||
var fragmentTriangles = callback.GetTriangles();
|
||||
triangles.AddRange(fragmentTriangles);
|
||||
processedFragments++;
|
||||
|
||||
// 🎯 更新进度(每处理完一个片段更新一次)
|
||||
progress.Update((double)processedFragments / allFragments.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
|
||||
{
|
||||
// 🎯 确保进度条被关闭
|
||||
if (progress != null)
|
||||
{
|
||||
Application.EndProgress();
|
||||
}
|
||||
|
||||
// 释放COM对象,避免内存泄漏
|
||||
if (comSelection != null)
|
||||
{
|
||||
Marshal.ReleaseComObject(comSelection);
|
||||
}
|
||||
}
|
||||
|
||||
return triangles;
|
||||
}
|
||||
```
|
||||
|
||||
#### 14.6 Progress API 最佳实践
|
||||
|
||||
**1. 合理的更新频率**
|
||||
|
||||
```csharp
|
||||
// ✅ 推荐:每个片段更新一次(3516次调用,可接受)
|
||||
progress.Update((double)processedFragments / allFragments.Count);
|
||||
|
||||
// ❌ 避免:每个三角形更新(可能数十万次,太频繁)
|
||||
// progress.Update((double)triangleCount / totalTriangles); // 性能问题
|
||||
|
||||
// ✅ 推荐:如果更新太频繁,可以批量更新
|
||||
if (processedFragments % 10 == 0) // 每10个更新一次
|
||||
{
|
||||
progress.Update((double)processedFragments / allFragments.Count);
|
||||
}
|
||||
```
|
||||
|
||||
**2. 异常处理中确保关闭**
|
||||
|
||||
```csharp
|
||||
// ✅ 正确模式:使用 finally 确保关闭
|
||||
Progress progress = null;
|
||||
try
|
||||
{
|
||||
progress = Application.BeginProgress("处理中...");
|
||||
// ... 处理逻辑
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"处理失败: {ex.Message}");
|
||||
// 即使发生异常,进度条也会在 finally 中关闭
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (progress != null)
|
||||
{
|
||||
Application.EndProgress();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**3. 取消操作的资源清理**
|
||||
|
||||
```csharp
|
||||
// ✅ 正确:取消时也要清理资源
|
||||
foreach (var item in items)
|
||||
{
|
||||
if (progress.IsCanceled)
|
||||
{
|
||||
LogManager.Info("用户取消操作");
|
||||
CleanupPartialResults(); // 清理部分结果
|
||||
break;
|
||||
}
|
||||
// ... 处理
|
||||
}
|
||||
```
|
||||
|
||||
**4. 线程安全考虑**
|
||||
|
||||
```csharp
|
||||
// ✅ Progress API 调用必须在主UI线程中
|
||||
System.Windows.Application.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
Progress progress = null;
|
||||
try
|
||||
{
|
||||
progress = Application.BeginProgress("处理中...");
|
||||
// 所有 Navisworks API 调用都在主线程中
|
||||
ProcessInMainThread();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (progress != null)
|
||||
{
|
||||
Application.EndProgress();
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
#### 14.7 进度条 vs 日志输出对比
|
||||
|
||||
| 特性 | Progress API | 日志输出 |
|
||||
|------|-------------|----------|
|
||||
| **用户体验** | ✅ 实时可视化进度,直观 | ❌ 需要打开日志文件查看 |
|
||||
| **取消操作** | ✅ 支持用户取消 | ❌ 无法中断 |
|
||||
| **性能开销** | ✅ 极小(内存操作) | ❌ 磁盘I/O开销 |
|
||||
| **调试信息** | ❌ 不保留历史 | ✅ 可追溯问题 |
|
||||
| **适用场景** | 耗时操作的用户交互 | 问题诊断和审计 |
|
||||
|
||||
**推荐方案:同时使用两者**
|
||||
|
||||
```csharp
|
||||
// 进度条:给用户看,提供交互
|
||||
progress.Update((double)i / total);
|
||||
|
||||
// 日志:只记录关键节点(开始、结束、错误)
|
||||
LogManager.Info($"[批量提取] 开始提取 {total} 个片段");
|
||||
// ... 处理过程中不频繁写日志
|
||||
LogManager.Info($"[批量提取] 完成,共提取 {count} 个三角形");
|
||||
```
|
||||
|
||||
#### 14.8 完整使用模式总结
|
||||
|
||||
**推荐的标准模板**:
|
||||
|
||||
```csharp
|
||||
public ReturnType MethodWithProgress(InputType input)
|
||||
{
|
||||
Progress progress = null;
|
||||
try
|
||||
{
|
||||
// 1. 开始进度条(带描述性标题)
|
||||
progress = Application.BeginProgress("操作标题", "详细描述...");
|
||||
|
||||
// 2. 计算总工作量
|
||||
int totalWork = CalculateTotalWork(input);
|
||||
int completedWork = 0;
|
||||
|
||||
// 3. 执行主要工作循环
|
||||
foreach (var item in workItems)
|
||||
{
|
||||
// 3.1 检查取消
|
||||
if (progress.IsCanceled)
|
||||
{
|
||||
LogManager.Info("用户取消操作");
|
||||
CleanupResources();
|
||||
break;
|
||||
}
|
||||
|
||||
// 3.2 执行工作
|
||||
try
|
||||
{
|
||||
ProcessItem(item);
|
||||
completedWork++;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"处理项目失败: {ex.Message}");
|
||||
// 决定是继续还是中断
|
||||
}
|
||||
|
||||
// 3.3 更新进度
|
||||
progress.Update((double)completedWork / totalWork);
|
||||
}
|
||||
|
||||
// 4. 完成
|
||||
LogManager.Info($"操作完成,处理了 {completedWork}/{totalWork} 项");
|
||||
return result;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"操作失败: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
// 5. 确保清理
|
||||
if (progress != null)
|
||||
{
|
||||
Application.EndProgress();
|
||||
}
|
||||
CleanupResources();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**常见陷阱和避免方法**:
|
||||
|
||||
```csharp
|
||||
// ❌ 陷阱1:忘记关闭进度条
|
||||
Progress progress = Application.BeginProgress("处理中...");
|
||||
// ... 处理逻辑
|
||||
// 忘记调用 Application.EndProgress(); // 进度条会一直显示
|
||||
|
||||
// ✅ 正确:使用 try-finally
|
||||
Progress progress = null;
|
||||
try
|
||||
{
|
||||
progress = Application.BeginProgress("处理中...");
|
||||
// ... 处理逻辑
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (progress != null) Application.EndProgress();
|
||||
}
|
||||
|
||||
// ❌ 陷阱2:进度值超出范围
|
||||
progress.Update(1.5); // 错误!应该是 0.0-1.0
|
||||
|
||||
// ✅ 正确:确保范围
|
||||
double progressValue = Math.Min(1.0, (double)completed / total);
|
||||
progress.Update(progressValue);
|
||||
|
||||
// ❌ 陷阱3:在后台线程中调用
|
||||
await Task.Run(() =>
|
||||
{
|
||||
var progress = Application.BeginProgress("处理中..."); // 崩溃!
|
||||
});
|
||||
|
||||
// ✅ 正确:在主线程中调用
|
||||
await System.Windows.Application.Current.Dispatcher.InvokeAsync(() =>
|
||||
{
|
||||
var progress = Application.BeginProgress("处理中...");
|
||||
// ... 主线程中的处理
|
||||
});
|
||||
```
|
||||
|
||||
**性能优化建议**:
|
||||
|
||||
| 场景 | 更新策略 | 原因 |
|
||||
|------|---------|------|
|
||||
| 少量项目(<100) | 每项更新一次 | 用户体验好,开销可忽略 |
|
||||
| 中等项目(100-1000) | 每项更新一次 | 平衡体验和性能 |
|
||||
| 大量项目(1000-10000) | 每10项更新一次 | 减少UI刷新开销 |
|
||||
| 海量项目(>10000) | 每100项更新一次 | 显著减少UI开销 |
|
||||
|
||||
**官方示例参考**:
|
||||
|
||||
官方示例文件中的 Progress API 使用案例:
|
||||
- `ClashDetective/ClashGrouper/ClashGrouperUtils.cs` - 碰撞分组中的进度条使用
|
||||
- 展示了在复杂算法中如何正确使用 Progress API 和取消支持
|
||||
|
||||
### Navisworks的Models.CollectionChanged事件模式
|
||||
|
||||
事件模式总结
|
||||
|
||||
@ -100,7 +100,7 @@ namespace NavisworksTransport
|
||||
}
|
||||
|
||||
// 使用优化的几何提取方法
|
||||
var triangles = ExtractTriangles(targetItem);
|
||||
var triangles = ExtractTriangles(new[] { targetItem });
|
||||
LogManager.Debug($"提取到 {triangles.Count} 个三角形");
|
||||
|
||||
if (triangles.Count > 0)
|
||||
@ -128,11 +128,12 @@ namespace NavisworksTransport
|
||||
/// </summary>
|
||||
/// <param name="modelItems">模型项集合</param>
|
||||
/// <returns>三角形集合</returns>
|
||||
public static List<Triangle3D> ExtractTrianglesBatch(IEnumerable<ModelItem> modelItems)
|
||||
public static List<Triangle3D> ExtractTriangles(IEnumerable<ModelItem> modelItems)
|
||||
{
|
||||
var triangles = new List<Triangle3D>();
|
||||
|
||||
ComApi.InwOpSelection comSelection = null;
|
||||
Progress progress = null;
|
||||
try
|
||||
{
|
||||
// 批量转换为 COM 选择 - 性能优化关键
|
||||
@ -155,11 +156,22 @@ namespace NavisworksTransport
|
||||
var allFragments = GetAllFragments(comSelection);
|
||||
LogManager.Info($"[批量提取] 获取到 {allFragments.Count} 个片段");
|
||||
|
||||
// 🎯 开始进度条
|
||||
progress = Application.BeginProgress("提取几何体",
|
||||
$"正在提取 {allFragments.Count} 个片段的三角形数据...");
|
||||
|
||||
try
|
||||
{
|
||||
int processedFragments = 0;
|
||||
foreach (var fragmentInfo in allFragments)
|
||||
{
|
||||
// 🎯 检查用户是否取消
|
||||
if (progress.IsCanceled)
|
||||
{
|
||||
LogManager.Info($"[批量提取] 用户取消操作,已处理 {processedFragments}/{allFragments.Count}");
|
||||
break;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var callback = new OptimizedGeometryCallback(fragmentInfo.TransformMatrix);
|
||||
@ -171,11 +183,8 @@ namespace NavisworksTransport
|
||||
triangles.AddRange(fragmentTriangles);
|
||||
processedFragments++;
|
||||
|
||||
// 每处理100个片段输出一次进度
|
||||
if (processedFragments % 100 == 0)
|
||||
{
|
||||
LogManager.Debug($"[批量提取] 已处理 {processedFragments}/{allFragments.Count} 个片段,累计三角形: {triangles.Count}");
|
||||
}
|
||||
// 🎯 更新进度(每处理完一个片段更新一次)
|
||||
progress.Update((double)processedFragments / allFragments.Count);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -210,90 +219,12 @@ namespace NavisworksTransport
|
||||
}
|
||||
finally
|
||||
{
|
||||
// 释放COM对象,避免内存泄漏
|
||||
if (comSelection != null)
|
||||
// 🎯 确保进度条被关闭
|
||||
if (progress != null)
|
||||
{
|
||||
Marshal.ReleaseComObject(comSelection);
|
||||
Application.EndProgress();
|
||||
}
|
||||
}
|
||||
|
||||
return triangles;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 提取三角形(单个模型项)
|
||||
/// </summary>
|
||||
/// <param name="modelItem">模型项</param>
|
||||
/// <returns>三角形集合</returns>
|
||||
public static List<Triangle3D> ExtractTriangles(ModelItem modelItem)
|
||||
{
|
||||
var triangles = new List<Triangle3D>();
|
||||
|
||||
ComApi.InwOpSelection comSelection = null;
|
||||
try
|
||||
{
|
||||
// 转换为 COM 选择
|
||||
var modelCollection = new ModelItemCollection
|
||||
{
|
||||
modelItem
|
||||
};
|
||||
|
||||
var comState = ComStateManager.GetState();
|
||||
comSelection = ComApiBridge.ToInwOpSelection(modelCollection);
|
||||
|
||||
LogManager.Debug($"COM 选择创建成功,路径数: {comSelection.Paths().Count}");
|
||||
|
||||
// 获取所有片段
|
||||
var allFragments = GetAllFragments(comSelection);
|
||||
LogManager.Debug($"获取到 {allFragments.Count} 个片段");
|
||||
|
||||
try
|
||||
{
|
||||
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);
|
||||
|
||||
LogManager.Debug($"片段生成了 {fragmentTriangles.Count} 个三角形");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"处理片段失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
|
||||
Loading…
Reference in New Issue
Block a user