为分层导出和碰撞检测添加Progress API进度条支持

- 分层导出(ExportLayerToNwd):增加三阶段进度条(隔离30%/导出70%/完成100%)和用户取消支持
- 碰撞检测(CreateAllAnimationCollisionTests):增加循环进度条和用户取消支持
- 清理LayerManagementCommands中未使用的辅助函数

🤖 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 11:37:44 +08:00
parent a0a667d45d
commit 543479ee65
3 changed files with 72 additions and 339 deletions

View File

@ -249,6 +249,7 @@ namespace NavisworksTransport
string pathName = "未知路径", string routeId = null, string animatedObjectName = null,
int frameRate = 30, double duration = 10.0)
{
Progress progress = null;
try
{
LogManager.Info($"=== 使用预计算碰撞数据创建ClashDetective测试容差: {detectionGap}米) ===");
@ -355,11 +356,25 @@ namespace NavisworksTransport
};
LogManager.Info($"[分组测试] 创建碰撞分组: {collisionGroup.DisplayName}");
// 🎯 创建进度条
progress = Application.BeginProgress("碰撞检测",
$"正在处理 {validCollisions.Count} 个碰撞点...");
int resultCount = 0;
foreach (var collision in validCollisions)
{
resultCount++;
// 🎯 检查用户是否取消
if (progress.IsCanceled)
{
LogManager.Info($"[碰撞检测] 用户取消操作,已处理 {resultCount - 1}/{validCollisions.Count}");
break;
}
// 🎯 更新进度
progress.Update((double)resultCount / validCollisions.Count);
try
{
@ -610,6 +625,21 @@ namespace NavisworksTransport
{
LogManager.Error($"动画结束后创建测试失败: {ex.Message}");
}
finally
{
// 🎯 确保进度条被关闭
if (progress != null)
{
try
{
Application.EndProgress();
}
catch (Exception progressEx)
{
LogManager.Error($"[碰撞检测] 关闭进度条失败: {progressEx.Message}");
}
}
}
}
/// <summary>

View File

@ -1706,6 +1706,7 @@ namespace NavisworksTransport
return false;
}
Progress progress = null;
try
{
LogManager.Info($"[分层管理器] ========== ExportLayerToNwd开始 ==========");
@ -1726,16 +1727,20 @@ namespace NavisworksTransport
// 检查线程状态
var apartmentState = System.Threading.Thread.CurrentThread.GetApartmentState();
LogManager.Info($"[分层管理器] 当前线程状态: {apartmentState}");
// 核心修复:确保在主 UI 线程中执行 Navisworks API 调用
bool exportResult = false;
Exception exportException = null;
// 使用 Application.Current.Dispatcher.Invoke 确保在主线程中执行
System.Windows.Application.Current.Dispatcher.Invoke(() =>
{
try
{
// 🎯 创建进度条
progress = NavisApplication.BeginProgress("导出分层",
$"正在导出 {preview.LayerName}...");
LogManager.Info($"[分层管理器] 在主线程中执行导出操作");
var document = NavisApplication.ActiveDocument;
@ -1746,23 +1751,37 @@ namespace NavisworksTransport
try
{
// 🎯 阶段1隔离显示 (30%)
progress.Update(0.3);
// 直接使用预览结果中的项目,这些已经是展开的完整节点树
// 不添加任何祖先路径,让 IsolateSpecificItems 自己处理
var itemsToIsolate = preview.Items;
LogManager.Info($"[分层管理器] 准备隔离显示 {itemsToIsolate.Count} 个节点");
// 使用 VisibilityManager.IsolateSpecificItems 隔离显示
// 这个方法会使用缓存优化,效率更高
bool isolateSuccess = VisibilityHelper.IsolateSpecificItems(itemsToIsolate);
if (!isolateSuccess)
{
throw new InvalidOperationException("隔离显示失败");
}
LogManager.Info($"[分层管理器] 隔离显示成功");
// 🎯 检查用户是否取消
if (progress.IsCanceled)
{
LogManager.Info("[分层管理器] 用户取消导出操作");
exportResult = false;
return; // 跳过导出直接到finally块恢复状态
}
// 🎯 阶段2导出文件 (70%)
progress.Update(0.7);
// 创建导出选项
var exportOptions = new Autodesk.Navisworks.Api.NwdExportOptions
{
@ -1778,10 +1797,26 @@ namespace NavisworksTransport
document.ExportToNwd(outputPath, exportOptions);
LogManager.Info($"[分层管理器] ExportToNwd API调用完成主线程");
// 🎯 完成 (100%)
progress.Update(1.0);
exportResult = true;
}
finally
{
// 🎯 确保进度条被关闭
if (progress != null)
{
try
{
NavisApplication.EndProgress();
}
catch (Exception progressEx)
{
LogManager.Error($"[分层管理器] 关闭进度条失败: {progressEx.Message}");
}
}
// 恢复原始可见性状态(在主线程中)
try
{
@ -2230,152 +2265,6 @@ namespace NavisworksTransport
}
}
/// <summary>
/// 获取指定楼层的模型项
/// </summary>
private ModelItemCollection GetFloorItems(ModelItemCollection allItems, string floorName, int maxDepth)
{
var floorItems = new ModelItemCollection();
try
{
LogManager.Info($"[分层管理器] ===== GetFloorItems开始 =====");
LogManager.Info($"[分层管理器] 目标楼层名称: '{floorName}'");
LogManager.Info($"[分层管理器] 输入模型项数: {allItems.Count}");
int checkedCount = 0;
int matchedCount = 0;
// 这里需要实现根据楼层名称筛选模型项的逻辑
// 暂时使用简化实现:遍历所有项目,检查其属性是否匹配楼层名称
foreach (ModelItem item in allItems)
{
try
{
checkedCount++;
// 检查项目的楼层属性
bool hasMatch = HasFloorAttribute(item, floorName);
if (hasMatch)
{
floorItems.Add(item);
matchedCount++;
if (matchedCount <= 5) // 只记录前5个匹配的详细信息
{
LogManager.Info($"[分层管理器] 找到匹配模型项 #{matchedCount}: {item.DisplayName}");
}
}
// 每处理1000个项记录进度
if (checkedCount % 1000 == 0)
{
LogManager.Info($"[分层管理器] 已检查 {checkedCount}/{allItems.Count} 个模型项,找到 {matchedCount} 个匹配");
}
}
catch (Exception ex)
{
LogManager.Warning($"[分层管理器] 检查模型项楼层属性时出错: {ex.Message}");
}
}
LogManager.Info($"[分层管理器] ===== GetFloorItems完成 ===== 检查了 {checkedCount} 个模型项,找到 {matchedCount} 个匹配的楼层项目");
}
catch (Exception ex)
{
LogManager.Error($"[分层管理器] 获取楼层项目失败: {ex.Message}");
}
return floorItems;
}
/// <summary>
/// 检查模型项是否具有指定的楼层属性
/// </summary>
private bool HasFloorAttribute(ModelItem item, string floorName)
{
try
{
// 检查常见的楼层属性名称
string[] floorAttributeNames = { "Level", "Floor", "楼层", "层", "Story", "Storey" };
var categories = item.PropertyCategories;
if (categories != null)
{
foreach (PropertyCategory category in categories)
{
var properties = category.Properties;
if (properties != null)
{
foreach (DataProperty property in properties)
{
if (floorAttributeNames.Any(attr =>
property.DisplayName.IndexOf(attr, StringComparison.OrdinalIgnoreCase) >= 0))
{
string propValue = property.Value?.ToString() ?? "";
bool isMatch = propValue.IndexOf(floorName, StringComparison.OrdinalIgnoreCase) >= 0;
// 详细调试日志 - 当找到楼层相关属性时
if (!string.IsNullOrEmpty(propValue))
{
LogManager.Info($"[分层管理器] 楼层属性检查: 项目='{item.DisplayName}', 属性='{property.DisplayName}', 值='{propValue}', 目标='{floorName}', 匹配={isMatch}");
}
if (isMatch)
{
return true;
}
}
}
}
}
}
}
catch (Exception ex)
{
LogManager.Warning($"[分层管理器] 检查楼层属性时出错: {ex.Message}");
}
return false;
}
/// <summary>
/// 检查模型项是否具有指定的属性值
/// </summary>
private bool HasAttributeValue(ModelItem item, string attributeName, string targetValue)
{
try
{
var categories = item.PropertyCategories;
if (categories != null)
{
foreach (PropertyCategory category in categories)
{
var properties = category.Properties;
if (properties != null)
{
foreach (DataProperty property in properties)
{
if (property.DisplayName.Equals(attributeName, StringComparison.OrdinalIgnoreCase))
{
string propValue = property.Value?.ToString() ?? "";
return propValue.Equals(targetValue, StringComparison.OrdinalIgnoreCase);
}
}
}
}
}
}
catch (Exception ex)
{
LogManager.Warning($"[分层管理器] 检查属性值时出错: {ex.Message}");
}
return false;
}
/// <summary>
/// 恢复可见性状态
/// </summary>
@ -2443,110 +2332,6 @@ namespace NavisworksTransport
}
}
/// <summary>
/// 测试导出功能:导出少量模型项以验证基础功能
/// </summary>
/// <param name="outputPath">测试文件输出路径</param>
/// <param name="maxItems">最大测试项目数默认5个</param>
/// <returns>测试是否成功</returns>
public bool TestBasicExport(string outputPath, int maxItems = 5)
{
try
{
LogManager.Info($"[分层管理器] ========== 开始基础导出测试 ==========");
LogManager.Info($"[分层管理器] 测试文件路径: {outputPath}");
LogManager.Info($"[分层管理器] 最大测试项目数: {maxItems}");
var document = NavisApplication.ActiveDocument;
if (document?.Models?.Count == 0)
{
LogManager.Error("[SimplifiedModelSplitter] 当前文档无效,无法进行测试");
return false;
}
// 获取少量模型项进行测试
var allItems = GetAllModelItems(1); // 只获取第一层
if (allItems.Count == 0)
{
LogManager.Error("[SimplifiedModelSplitter] 没有可用的模型项进行测试");
return false;
}
// 限制测试项目数量
var testItems = new ModelItemCollection();
int addedCount = 0;
foreach (ModelItem item in allItems)
{
if (addedCount >= maxItems) break;
try
{
// 验证项目有效性
string displayName = item.DisplayName;
testItems.Add(item);
addedCount++;
LogManager.Info($"[分层管理器] 添加测试项目 #{addedCount}: {displayName}");
}
catch (Exception ex)
{
LogManager.Warning($"[分层管理器] 跳过无效测试项目: {ex.Message}");
}
}
if (testItems.Count == 0)
{
LogManager.Error("[SimplifiedModelSplitter] 没有有效的测试项目");
return false;
}
LogManager.Info($"[分层管理器] 准备测试导出 {testItems.Count} 个模型项");
// 确保输出目录存在
string directory = Path.GetDirectoryName(outputPath);
if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
LogManager.Info($"[分层管理器] 创建测试输出目录: {directory}");
}
// 创建测试预览结果
var testPreview = new SplitPreviewResult
{
LayerName = "测试导出",
LayerAttribute = "测试",
Items = testItems
};
// 创建测试配置
var testConfig = new SplitConfiguration
{
Strategy = SplitStrategy.BySmartFloorDetection,
OutputDirectory = directory,
ExportOptions = new NwdExportUserOptions() // 使用默认选项
};
// 执行测试导出
bool testResult = ExportLayerToNwd(testPreview, outputPath, testConfig);
LogManager.Info($"[分层管理器] ========== 基础导出测试完成 ========== 结果: {testResult}");
if (testResult && File.Exists(outputPath))
{
var fileInfo = new FileInfo(outputPath);
LogManager.Info($"[分层管理器] 测试文件生成成功,大小: {fileInfo.Length / 1024} KB");
}
return testResult;
}
catch (Exception ex)
{
LogManager.Error($"[分层管理器] 基础导出测试失败: {ex.Message}");
LogManager.Error($"[分层管理器] 测试异常堆栈: {ex.StackTrace}");
return false;
}
}
#endregion
#region

View File

@ -704,87 +704,5 @@ namespace NavisworksTransport.UI.WPF.Commands
}
}
/// <summary>
/// 测试导出命令 - 导出少量模型项验证基础功能
/// </summary>
public class TestExportCommand : ILayerManagementCommand<TestExportResult>
{
private readonly ModelSplitterManager _modelSplitterManager;
private readonly string _outputPath;
private readonly int _maxItems;
public TestExportCommand(ModelSplitterManager modelSplitterManager, string outputPath, int maxItems = 5)
{
_modelSplitterManager = modelSplitterManager ?? throw new ArgumentNullException(nameof(modelSplitterManager));
_outputPath = outputPath ?? throw new ArgumentNullException(nameof(outputPath));
_maxItems = Math.Max(1, Math.Min(20, maxItems)); // 限制在1-20个项目之间
}
public async Task<TestExportResult> ExecuteAsync()
{
return await Task.Run(() =>
{
try
{
LogManager.Info("[TestExportCommand] 开始执行测试导出");
LogManager.Info($"[TestExportCommand] 输出路径: {_outputPath}");
LogManager.Info($"[TestExportCommand] 最大测试项目数: {_maxItems}");
// 调用SimplifiedModelSplitterManager的测试方法
bool testResult = _modelSplitterManager.TestBasicExport(_outputPath, _maxItems);
if (testResult)
{
// 检查生成的文件信息
long fileSize = 0;
if (System.IO.File.Exists(_outputPath))
{
var fileInfo = new System.IO.FileInfo(_outputPath);
fileSize = fileInfo.Length;
}
string successMessage = $"测试导出成功!已导出{_maxItems}个模型项";
LogManager.Info($"[TestExportCommand] {successMessage}");
return new TestExportResult
{
IsSuccess = true,
Message = successMessage,
OutputPath = _outputPath,
FileSizeBytes = fileSize,
ItemCount = _maxItems
};
}
else
{
string errorMessage = "测试导出失败,请检查日志了解详细错误信息";
LogManager.Error($"[TestExportCommand] {errorMessage}");
return new TestExportResult
{
IsSuccess = false,
ErrorMessage = errorMessage,
OutputPath = _outputPath,
ItemCount = _maxItems
};
}
}
catch (Exception ex)
{
string errorMessage = $"测试导出异常: {ex.Message}";
LogManager.Error($"[TestExportCommand] {errorMessage}", ex);
return new TestExportResult
{
IsSuccess = false,
ErrorMessage = errorMessage,
OutputPath = _outputPath,
ItemCount = _maxItems
};
}
});
}
}
#endregion
}