为分层导出和碰撞检测添加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:
parent
a0a667d45d
commit
543479ee65
@ -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>
|
||||
|
||||
@ -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 辅助方法
|
||||
|
||||
@ -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
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user