完成了分层导出的功能,还是线程安全的问题

This commit is contained in:
tian 2025-08-19 00:26:46 +08:00
parent 3bdffc2b37
commit cddb7de71e
5 changed files with 224 additions and 1282 deletions

View File

@ -218,7 +218,6 @@
<Compile Include="src\Utils\FloorDetector.cs" />
<Compile Include="src\Utils\GeometryExtractor.cs" />
<Compile Include="src\Utils\LogManager.cs" />
<Compile Include="src\Utils\NavisworksFileExporter.cs" />
<Compile Include="src\Utils\UnitsConverter.cs" />
<!-- Legacy (2017 compatibility - can be removed in 2026-only branch) -->

View File

@ -139,7 +139,6 @@ namespace NavisworksTransport
private readonly FloorDetector _floorDetector;
private readonly AttributeGrouper _attributeGrouper;
private readonly NavisworksFileExporter _fileExporter;
private bool _isSplitting = false;
#endregion
@ -150,7 +149,6 @@ namespace NavisworksTransport
{
_floorDetector = new FloorDetector();
_attributeGrouper = new AttributeGrouper();
_fileExporter = new NavisworksFileExporter();
LogManager.Info("[ModelSplitter] 模型分层管理器已初始化");
}
@ -597,7 +595,60 @@ namespace NavisworksTransport
LogManager.Info("[ModelSplitter] 开始导出文件...");
LogManager.Info($"[ModelSplitter] 目标文件: {result.OutputFilePath}");
bool exportSuccess = await _fileExporter.ExportModelItemsAsync(preview.Items, result.OutputFilePath);
// 直接使用 Navisworks API 导出
bool exportSuccess = false;
try
{
var document = NavisApplication.ActiveDocument;
// 保存当前可见性状态并重置
document.Models.ResetAllHidden();
// 隐藏不需要的项目
var allItems = new ModelItemCollection();
allItems.AddRange(document.Models.RootItemDescendantsAndSelf);
var itemsToHide = new ModelItemCollection();
foreach (ModelItem item in allItems)
{
bool shouldKeep = false;
foreach (ModelItem exportItem in preview.Items)
{
if (item.Equals(exportItem))
{
shouldKeep = true;
break;
}
}
if (!shouldKeep)
{
itemsToHide.Add(item);
}
}
if (itemsToHide.Count > 0)
{
document.Models.SetHidden(itemsToHide, true);
}
// 创建导出选项并导出
var exportOptions = new Autodesk.Navisworks.Api.NwdExportOptions();
exportOptions.ExcludeHiddenItems = true;
exportOptions.EmbedXrefs = false;
exportOptions.PreventObjectPropertyExport = false;
document.ExportToNwd(result.OutputFilePath, exportOptions);
exportSuccess = true;
// 恢复可见性
document.Models.ResetAllHidden();
}
catch (Exception ex)
{
LogManager.Error($"[ModelSplitter] 导出异常: {ex.Message}");
exportSuccess = false;
}
LogManager.Info($"[ModelSplitter] 文件导出结果: {exportSuccess}");

View File

@ -110,7 +110,6 @@ namespace NavisworksTransport
private readonly FloorDetector _floorDetector;
private readonly AttributeGrouper _attributeGrouper;
private readonly NavisworksFileExporter _fileExporter;
// 楼层检测结果缓存
private readonly Dictionary<string, List<SplitPreviewResult>> _floorCache;
@ -125,7 +124,6 @@ namespace NavisworksTransport
{
_floorDetector = new FloorDetector();
_attributeGrouper = new AttributeGrouper();
_fileExporter = new NavisworksFileExporter();
// 初始化缓存
_floorCache = new Dictionary<string, List<SplitPreviewResult>>();
@ -974,20 +972,158 @@ namespace NavisworksTransport
var itemsToExport = preview.Items;
LogManager.Info($"[SimplifiedModelSplitter] 将导出 {itemsToExport.Count} 个模型项");
// 使用异步方法导出
var exportTask = _fileExporter.ExportModelItemsAsync(itemsToExport, outputPath);
bool exportSuccess = exportTask.Result;
// 检查线程状态
var apartmentState = System.Threading.Thread.CurrentThread.GetApartmentState();
LogManager.Info($"[SimplifiedModelSplitter] 当前线程状态: {apartmentState}");
if (exportSuccess)
// 核心修复:确保在主 UI 线程中执行 Navisworks API 调用
bool exportResult = false;
Exception exportException = null;
// 使用 Application.Current.Dispatcher.Invoke 确保在主线程中执行
System.Windows.Application.Current.Dispatcher.Invoke(() =>
{
LogManager.Info($"[SimplifiedModelSplitter] ========== ExportLayerToNwd完成 ========== 成功导出到: {outputPath}");
return true;
}
else
try
{
LogManager.Info($"[SimplifiedModelSplitter] 在主线程中执行导出操作");
var document = NavisApplication.ActiveDocument;
// 保存当前可见性状态(在主线程中)
LogManager.Info($"[SimplifiedModelSplitter] 开始保存当前可见性状态");
var originalVisibilityState = SaveCurrentVisibilityState(document);
LogManager.Info($"[SimplifiedModelSplitter] 已保存 {originalVisibilityState.Count} 个项目的可见性状态");
try
{
// 采用智能隐藏策略:只操作顶级节点,避免遍历所有项目
var allTopLevelItems = new List<ModelItem>();
// 只获取顶级节点,不遍历全部项目
foreach (Model model in document.Models)
{
foreach (ModelItem topLevelItem in model.RootItem.Children)
{
allTopLevelItems.Add(topLevelItem);
}
}
LogManager.Info($"[SimplifiedModelSplitter] 收集到 {allTopLevelItems.Count} 个顶级节点");
// 智能隐藏策略:如果顶级节点包含要导出的项目,则保持可见;否则隐藏整个顶级分支
var itemsToHide = new ModelItemCollection();
int hiddenCount = 0;
foreach (ModelItem topLevelItem in allTopLevelItems)
{
bool shouldKeepTopLevel = false;
// 检查这个顶级节点本身是否在导出列表中
foreach (ModelItem exportItem in itemsToExport)
{
if (topLevelItem.Equals(exportItem))
{
shouldKeepTopLevel = true;
LogManager.Info($"[SimplifiedModelSplitter] 顶级节点 {topLevelItem.DisplayName} 本身被选中,保持可见");
break;
}
}
// 如果顶级节点本身不在导出列表中,检查是否有任何导出项是它的后代
if (!shouldKeepTopLevel)
{
foreach (var exportItem in itemsToExport)
{
var current = exportItem;
while (current != null)
{
if (current == topLevelItem)
{
shouldKeepTopLevel = true;
LogManager.Info($"[SimplifiedModelSplitter] 顶级节点 {topLevelItem.DisplayName} 包含导出项目,保持可见");
break;
}
current = current.Parent;
}
if (shouldKeepTopLevel) break;
}
}
// 如果这个顶级节点不需要保持可见,则隐藏它
if (!shouldKeepTopLevel)
{
try
{
itemsToHide.Add(topLevelItem);
hiddenCount++;
LogManager.Info($"[SimplifiedModelSplitter] 隐藏顶级节点: {topLevelItem.DisplayName}");
}
catch (Exception ex)
{
LogManager.Warning($"[SimplifiedModelSplitter] 添加隐藏项目失败: {topLevelItem.DisplayName} - {ex.Message}");
}
}
}
// 执行隐藏操作
if (itemsToHide.Count > 0)
{
try
{
document.Models.SetHidden(itemsToHide, true);
LogManager.Info($"[SimplifiedModelSplitter] 成功隐藏 {hiddenCount} 个顶级节点,保留导出项目可见");
}
catch (Exception ex)
{
LogManager.Warning($"[SimplifiedModelSplitter] 隐藏操作失败: {ex.Message}");
}
}
// 创建导出选项
var exportOptions = new Autodesk.Navisworks.Api.NwdExportOptions
{
ExcludeHiddenItems = true, // 只导出可见项目
EmbedXrefs = false,
PreventObjectPropertyExport = false
};
LogManager.Info($"[SimplifiedModelSplitter] 开始调用ExportToNwd API主线程");
// 在主线程中执行导出
document.ExportToNwd(outputPath, exportOptions);
LogManager.Info($"[SimplifiedModelSplitter] ExportToNwd API调用完成主线程");
exportResult = true;
}
finally
{
// 恢复原始可见性状态(在主线程中)
try
{
RestoreVisibilityState(document, originalVisibilityState);
LogManager.Info($"[SimplifiedModelSplitter] 已恢复原始可见性状态");
}
catch (Exception restoreEx)
{
LogManager.Error($"[SimplifiedModelSplitter] 恢复可见性失败: {restoreEx.Message}");
}
}
}
catch (Exception ex)
{
exportException = ex;
}
});
// 检查导出结果
if (exportException != null)
{
LogManager.Error($"[SimplifiedModelSplitter] 导出失败: {outputPath}");
LogManager.Error($"[SimplifiedModelSplitter] 主线程导出异常: {exportException.Message}");
LogManager.Error($"[SimplifiedModelSplitter] 异常堆栈: {exportException.StackTrace}");
return false;
}
LogManager.Info($"[SimplifiedModelSplitter] ========== ExportLayerToNwd完成 ========== 成功导出到: {outputPath}");
return exportResult;
}
catch (Exception ex)
{
@ -997,157 +1133,41 @@ namespace NavisworksTransport
}
}
/// <summary>
/// 根据分层结果获取该层包含的模型项
/// 保存当前可见性状态(参考"保存当前选择项"的方法)
/// </summary>
private ModelItemCollection GetLayerModelItems(SplitPreviewResult preview, SplitConfiguration config)
private Dictionary<ModelItem, bool> SaveCurrentVisibilityState(Document document)
{
var visibilityState = new Dictionary<ModelItem, bool>();
try
{
LogManager.Info($"[SimplifiedModelSplitter] ========== GetLayerModelItems开始 ==========");
LogManager.Info($"[SimplifiedModelSplitter] 目标分层: {preview.LayerName}, 策略: {config.Strategy}");
// 优先使用预览结果中已缓存的模型项
if (preview.Items != null && preview.Items.Count > 0)
// 获取所有顶级项目并记录它们的可见性状态
foreach (Model model in document.Models)
{
LogManager.Info($"[SimplifiedModelSplitter] 使用预览结果中的缓存模型项,数量: {preview.Items.Count}");
// 关键修复:展开楼层顶层节点,收集所有子节点
LogManager.Info($"[SimplifiedModelSplitter] 开始展开楼层节点,收集完整的子节点内容...");
var expandedItems = ExpandFloorItems(preview.Items);
LogManager.Info($"[SimplifiedModelSplitter] 楼层节点展开完成: 原始{preview.Items.Count}个 -> 展开后{expandedItems.Count}个");
return expandedItems;
foreach (ModelItem topLevelItem in model.RootItem.Children)
{
try
{
// 记录是否隐藏IsHidden为true表示隐藏我们存储可见性所以取反
visibilityState[topLevelItem] = !topLevelItem.IsHidden;
}
catch
{
// 如果无法获取状态,默认为可见
visibilityState[topLevelItem] = true;
}
}
}
LogManager.Info($"[SimplifiedModelSplitter] 预览结果中没有模型项,开始重新检测");
var document = NavisApplication.ActiveDocument;
if (document?.Models?.Count == 0)
{
LogManager.Warning($"[SimplifiedModelSplitter] 文档无效或没有模型");
return new ModelItemCollection();
}
var allItems = GetAllModelItems(config.MaxDepth);
LogManager.Info($"[SimplifiedModelSplitter] 获取到总模型项数: {allItems.Count},深度: {config.MaxDepth}");
var layerItems = new ModelItemCollection();
switch (config.Strategy)
{
case SplitStrategy.ByFloor:
LogManager.Info($"[SimplifiedModelSplitter] 使用楼层策略,开始重新检测楼层");
// 按楼层分层使用FloorDetector重新检测并匹配层名
var floors = _floorDetector.DetectFloors(allItems, null, config.MaxDepth);
LogManager.Info($"[SimplifiedModelSplitter] 检测到楼层数: {floors?.Count ?? 0}");
if (floors != null)
{
foreach (var floor in floors)
{
string sanitizedFloorName = SanitizeLayerName(floor.FloorName);
LogManager.Info($"[SimplifiedModelSplitter] 楼层匹配检查: 原始名称='{floor.FloorName}' -> 清理后='{sanitizedFloorName}', 目标='{preview.LayerName}', 匹配={sanitizedFloorName == preview.LayerName}");
}
}
var matchingFloor = floors?.FirstOrDefault(f => SanitizeLayerName(f.FloorName) == preview.LayerName);
if (matchingFloor != null)
{
LogManager.Info($"[SimplifiedModelSplitter] 找到匹配楼层: 原始名称='{matchingFloor.FloorName}', 清理后名称='{preview.LayerName}', 包含模型项: {matchingFloor.ItemCount}");
// 关键修复直接使用FloorDetector检测结果并展开所有子节点
if (matchingFloor.Items != null && matchingFloor.Items.Count > 0)
{
LogManager.Info($"[SimplifiedModelSplitter] 直接使用FloorDetector的模型项结果数量: {matchingFloor.Items.Count}");
LogManager.Info($"[SimplifiedModelSplitter] 开始展开楼层节点,收集完整的子节点内容...");
// 展开楼层顶层节点,收集所有子节点
var expandedItems = ExpandFloorItems(matchingFloor.Items);
LogManager.Info($"[SimplifiedModelSplitter] 楼层节点展开完成: 原始{matchingFloor.Items.Count}个 -> 展开后{expandedItems.Count}个");
layerItems = expandedItems;
}
else
{
LogManager.Info($"[SimplifiedModelSplitter] FloorDetector结果中没有模型项使用原始名称重新查找: '{matchingFloor.FloorName}'");
var foundItems = GetFloorItems(allItems, matchingFloor.FloorName, config.MaxDepth);
LogManager.Info($"[SimplifiedModelSplitter] 重新查找结果: {foundItems.Count}个模型项");
// 同样展开找到的楼层项目
if (foundItems.Count > 0)
{
var expandedItems = ExpandFloorItems(foundItems);
LogManager.Info($"[SimplifiedModelSplitter] 重新查找的楼层项目展开完成: 原始{foundItems.Count}个 -> 展开后{expandedItems.Count}个");
layerItems = expandedItems;
}
else
{
layerItems = foundItems;
}
}
}
else
{
LogManager.Warning($"[SimplifiedModelSplitter] 未找到匹配的楼层: {preview.LayerName}");
}
break;
case SplitStrategy.ByAttribute:
LogManager.Info($"[SimplifiedModelSplitter] 使用属性策略: {config.AttributeName}");
// 按属性分层使用AttributeGrouper重新分组并匹配层名
var groups = _attributeGrouper.GroupByAttribute(allItems, config.AttributeName);
LogManager.Info($"[SimplifiedModelSplitter] 检测到属性组数: {groups?.Count ?? 0}");
if (groups != null)
{
foreach (var group in groups)
{
string sanitizedGroupName = SanitizeLayerName(group.GroupName);
LogManager.Info($"[SimplifiedModelSplitter] 属性组匹配检查: 原始名称='{group.GroupName}' -> 清理后='{sanitizedGroupName}', 目标='{preview.LayerName}', 匹配={sanitizedGroupName == preview.LayerName}");
}
}
var matchingGroup = groups?.FirstOrDefault(g => SanitizeLayerName(g.GroupName) == preview.LayerName);
if (matchingGroup != null)
{
LogManager.Info($"[SimplifiedModelSplitter] 找到匹配属性组: 原始名称='{matchingGroup.GroupName}', 清理后名称='{preview.LayerName}', 包含模型项: {matchingGroup.ItemCount}");
// 直接使用AttributeGrouper检测结果中的模型项避免重新检测
if (matchingGroup.Items != null && matchingGroup.Items.Count > 0)
{
LogManager.Info($"[SimplifiedModelSplitter] 直接使用AttributeGrouper的模型项结果数量: {matchingGroup.Items.Count}");
// 属性分组通常已经是完整的构件,不需要展开,但为了保持一致性,仍然检查
var expandedItems = ExpandFloorItems(matchingGroup.Items);
LogManager.Info($"[SimplifiedModelSplitter] 属性组项目展开完成: 原始{matchingGroup.Items.Count}个 -> 展开后{expandedItems.Count}个");
layerItems = expandedItems;
}
else
{
LogManager.Info($"[SimplifiedModelSplitter] AttributeGrouper结果中没有模型项使用原始名称重新查找: '{matchingGroup.GroupName}'");
layerItems = GetAttributeGroupItems(allItems, config.AttributeName, matchingGroup.GroupName);
}
}
else
{
LogManager.Warning($"[SimplifiedModelSplitter] 未找到匹配的属性组: {preview.LayerName}");
}
break;
default:
LogManager.Warning($"[SimplifiedModelSplitter] 不支持的分层策略: {config.Strategy}");
break;
}
LogManager.Info($"[SimplifiedModelSplitter] ========== GetLayerModelItems完成 ========== 获取到 {layerItems.Count} 个分层模型项");
return layerItems;
LogManager.Info($"[SimplifiedModelSplitter] 保存可见性状态完成,记录了 {visibilityState.Count} 个顶级项目");
}
catch (Exception ex)
{
LogManager.Error($"[SimplifiedModelSplitter] 获取分层模型项失败: {ex.Message}");
LogManager.Error($"[SimplifiedModelSplitter] 异常堆栈: {ex.StackTrace}");
return new ModelItemCollection();
LogManager.Error($"[SimplifiedModelSplitter] 保存可见性状态失败: {ex.Message}");
}
return visibilityState;
}
/// <summary>
@ -1598,42 +1618,6 @@ namespace NavisworksTransport
return false;
}
/// <summary>
/// 保存当前可见性状态
/// </summary>
private Dictionary<ModelItem, bool> SaveVisibilityState(Document document)
{
var visibilityState = new Dictionary<ModelItem, bool>();
try
{
// 这里需要保存所有模型项的可见性状态
// 简化实现:记录隐藏的项目
var allItems = new ModelItemCollection();
allItems.AddRange(document.Models.RootItemDescendantsAndSelf);
foreach (ModelItem item in allItems)
{
try
{
// Navisworks中检查项目是否隐藏的方法
visibilityState[item] = !item.IsHidden;
}
catch
{
// 如果无法获取状态,默认为可见
visibilityState[item] = true;
}
}
}
catch (Exception ex)
{
LogManager.Error($"[SimplifiedModelSplitter] 保存可见性状态失败: {ex.Message}");
}
return visibilityState;
}
/// <summary>
/// 恢复可见性状态
/// </summary>
@ -1701,84 +1685,6 @@ namespace NavisworksTransport
}
}
/// <summary>
/// 隐藏除指定项目外的其他所有项目 - 使用成熟的可见性控制模式
/// </summary>
private void HideOtherItems(Document document, ModelItemCollection keepVisible)
{
try
{
LogManager.Info($"[SimplifiedModelSplitter] 开始隐藏其他项目,保持可见: {keepVisible.Count} 个项目");
// 获取所有项目 - 使用安全的AddRange方法
var allItems = new ModelItemCollection();
allItems.AddRange(document.Models.RootItemDescendantsAndSelf);
LogManager.Info($"[SimplifiedModelSplitter] 总共 {allItems.Count} 个模型项目");
// 先重置所有项目为可见状态,确保从干净状态开始
document.Models.ResetAllHidden();
LogManager.Info("[SimplifiedModelSplitter] 已重置所有项目为可见状态");
// 收集需要隐藏的项目 - 不在keepVisible集合中的项目
var itemsToHide = new ModelItemCollection();
foreach (ModelItem item in allItems)
{
try
{
// 检查该项目是否在keepVisible集合中
bool shouldKeepVisible = false;
foreach (ModelItem visibleItem in keepVisible)
{
if (item.Equals(visibleItem))
{
shouldKeepVisible = true;
break;
}
}
// 如果不在保持可见的集合中,则需要隐藏
if (!shouldKeepVisible)
{
itemsToHide.Add(item);
}
}
catch (Exception ex)
{
LogManager.Warning($"[SimplifiedModelSplitter] 检查项目可见性时出错: {ex.Message}");
}
}
LogManager.Info($"[SimplifiedModelSplitter] 需要隐藏 {itemsToHide.Count} 个项目");
// 执行隐藏操作 - 使用成熟的SetHidden方法
if (itemsToHide.Count > 0)
{
document.Models.SetHidden(itemsToHide, true);
LogManager.Info($"[SimplifiedModelSplitter] 成功隐藏 {itemsToHide.Count} 个项目");
}
else
{
LogManager.Info("[SimplifiedModelSplitter] 没有项目需要隐藏");
}
}
catch (Exception ex)
{
LogManager.Error($"[SimplifiedModelSplitter] 隐藏其他项目失败: {ex.Message}");
// 异常处理:确保至少显示所有项目
try
{
document.Models.ResetAllHidden();
LogManager.Info("[SimplifiedModelSplitter] 异常恢复:重置为全部可见");
}
catch (Exception resetEx)
{
LogManager.Error($"[SimplifiedModelSplitter] 异常恢复也失败: {resetEx.Message}");
}
}
}
/// <summary>
/// 简化的环境诊断方法 - 快速检查API是否可用
/// </summary>

File diff suppressed because it is too large Load Diff