using Autodesk.Navisworks.Api; using System; using System.Collections.Generic; using System.IO; using System.Threading.Tasks; using System.ComponentModel; using System.Threading; using System.Linq; using NavisApplication = Autodesk.Navisworks.Api.Application; using NavisworksTransport.Core; namespace NavisworksTransport { /// /// 简化版模型分层管理器 - 为新UI设计的轻量级分层管理 /// 功能范围:楼层分析、属性设置、分层保存、选中保存 /// public class ModelSplitterManager { #region 枚举和数据结构 /// /// 简化的分层策略 /// public enum SplitStrategy { BySmartFloorDetection, // 智能检测楼层(原ByFloor) ByFloorAttribute, // 按楼层属性(原ByCustomFloor) ByZoneAttribute, // 按区域属性 BySubSystemAttribute // 按子系统属性 } /// /// 分层分组策略接口 /// private interface IGroupingStrategy { string GroupTypeName { get; } string UnclassifiedLabel { get; } Dictionary GroupItems(ModelItemCollection items, SplitConfiguration config); /// /// 提取单个节点的属性值,用于智能遍历 /// string ExtractAttributeValue(ModelItem node); } /// /// 分组项信息 /// private class GroupItem { public string GroupName { get; set; } public string OriginalName { get; set; } public List Items { get; set; } = new List(); public Dictionary Metadata { get; set; } = new Dictionary(); } /// /// 楼层检测分组策略 - 使用统一的深度遍历结果 /// private class FloorDetectionStrategy : IGroupingStrategy { private readonly FloorDetector _floorDetector; public string GroupTypeName => "楼层"; public string UnclassifiedLabel => "未检测到楼层"; public FloorDetectionStrategy(FloorDetector floorDetector) { _floorDetector = floorDetector; } /// /// 实现IGroupingStrategy接口的ExtractAttributeValue方法 /// 使用FloorDetector进行智能楼层检测 /// public string ExtractAttributeValue(ModelItem node) { try { // 使用FloorDetector的通用属性检测逻辑 // 检查常见的楼层属性名称 string[] floorAttributes = { "Level", "Floor", "楼层", "层", "Story", "Storey", "Base Constraint" }; foreach (string attrName in floorAttributes) { string value = GetAttributeValueFromNode(node, attrName); if (!string.IsNullOrEmpty(value)) { return value; } } return null; } catch (Exception ex) { LogManager.Warning($"智能楼层检测失败: {ex.Message}"); return null; } } /// /// 从节点获取指定属性的值 /// private string GetAttributeValueFromNode(ModelItem item, string attributeName) { try { // 使用 CategoryAttributeManager 的通用属性获取方法,简化代码 return CategoryAttributeManager.GetGeneralPropertyValue(item, attributeName); } catch { return null; } } /// /// 获取检测到的属性类型信息(属性名称和值) /// public (string attributeName, string attributeValue) ExtractAttributeInfo(ModelItem node) { try { // 使用FloorDetector的通用属性检测逻辑 // 检查常见的楼层属性名称 string[] floorAttributes = { "Level", "Floor", "楼层", "层", "Story", "Storey", "Base Constraint" }; foreach (string attrName in floorAttributes) { string value = GetAttributeValueFromNode(node, attrName); if (!string.IsNullOrEmpty(value)) { return (attrName, value); } } return (null, null); } catch (Exception ex) { LogManager.Warning($"智能楼层属性检测失败: {ex.Message}"); return (null, null); } } public Dictionary GroupItems(ModelItemCollection items, SplitConfiguration config) { var result = new Dictionary(); try { LogManager.Info($"[FloorDetectionStrategy] 开始智能楼层检测,输入模型项数={items?.Count ?? 0}"); if (items == null || items.Count == 0) { LogManager.Warning("[FloorDetectionStrategy] 输入模型项集合为空"); return result; } // 关键修复:直接使用传入的items,不再让FloorDetector重新获取深度项 // 调用 FloorDetector,但传入 maxDepth = 0 来强制使用传入的items var floors = _floorDetector.DetectFloorsFromGivenItems(items, null); LogManager.Info($"[FloorDetectionStrategy] FloorDetector检测完成,发现 {floors?.Count ?? 0} 个楼层"); if (floors != null && floors.Count > 0) { foreach (var floor in floors) { result[floor.FloorName] = new GroupItem { GroupName = floor.FloorName, OriginalName = floor.FloorName, Items = floor.Items?.ToList() ?? new List(), Metadata = new Dictionary { ["OriginalFloorName"] = floor.FloorName, ["FloorName"] = floor.FloorName, ["Elevation"] = floor.Elevation, ["DetectionMethod"] = "Floor", ["ItemsFromUnifiedDepth"] = true // 标记使用了统一深度遍历 } }; LogManager.Info($"[FloorDetectionStrategy] 楼层 '{floor.FloorName}' 包含 {floor.Items?.Count ?? 0} 个模型项"); } } else { LogManager.Warning("[FloorDetectionStrategy] 未检测到任何楼层信息"); } } catch (Exception ex) { LogManager.Error($"[FloorDetectionStrategy] 楼层检测异常: {ex.Message}"); } LogManager.Info($"[FloorDetectionStrategy] 楼层检测完成,返回 {result.Count} 个楼层分组"); return result; } } /// /// 属性分组策略基类 /// private abstract class AttributeGroupingStrategy : IGroupingStrategy { protected readonly FloorAttributeManager _floorManager; public abstract string GroupTypeName { get; } public abstract string UnclassifiedLabel { get; } protected AttributeGroupingStrategy() { _floorManager = new FloorAttributeManager(); } protected abstract string GetAttributeValue(ModelItem item); /// /// 实现IGroupingStrategy接口的ExtractAttributeValue方法 /// 直接调用子类已实现的GetAttributeValue方法 /// public string ExtractAttributeValue(ModelItem node) { return GetAttributeValue(node); } public Dictionary GroupItems(ModelItemCollection items, SplitConfiguration config) { var result = new Dictionary(); try { LogManager.Info($"[{GroupTypeName}AttributeStrategy] 开始属性分组,输入模型项数={items?.Count ?? 0},深度={config?.MaxDepth ?? -1}"); if (items == null || items.Count == 0) { LogManager.Warning($"[{GroupTypeName}AttributeStrategy] 输入模型项集合为空"); return result; } int processedCount = 0; var attributeValueCounts = new Dictionary(); foreach (var item in items) { try { processedCount++; string attributeValue = GetAttributeValue(item); string groupKey = string.IsNullOrEmpty(attributeValue) ? UnclassifiedLabel : attributeValue; // 统计属性值分布 if (!attributeValueCounts.ContainsKey(groupKey)) attributeValueCounts[groupKey] = 0; attributeValueCounts[groupKey]++; if (!result.ContainsKey(groupKey)) { result[groupKey] = new GroupItem { GroupName = groupKey, OriginalName = attributeValue ?? UnclassifiedLabel, Metadata = new Dictionary { ["DetectionMethod"] = GroupTypeName + "Attribute", ["ItemsFromUnifiedDepth"] = true, // 标记使用了统一深度遍历 ["MaxDepth"] = config?.MaxDepth ?? -1 } }; } result[groupKey].Items.Add(item); } catch (Exception ex) { LogManager.Error($"[{GroupTypeName}AttributeStrategy] 处理单个模型项时出错: {ex.Message}"); } } // 记录属性值分布 LogManager.Info($"[{GroupTypeName}AttributeStrategy] 处理完成,共处理{processedCount}个模型项,发现{result.Count}个{GroupTypeName}分组"); foreach (var kvp in attributeValueCounts.OrderByDescending(x => x.Value)) { LogManager.Info($"[{GroupTypeName}AttributeStrategy] {GroupTypeName}分组 '{kvp.Key}': {kvp.Value} 个模型项"); } } catch (Exception ex) { LogManager.Error($"[{GroupTypeName}AttributeStrategy] 属性分组异常: {ex.Message}"); } return result; } } /// /// 楼层属性分组策略 /// private class FloorAttributeStrategy : AttributeGroupingStrategy { public override string GroupTypeName => "楼层"; public override string UnclassifiedLabel => "未设置楼层"; protected override string GetAttributeValue(ModelItem item) { return _floorManager.GetFloorProperty(item, "楼层"); } } /// /// 区域属性分组策略 /// private class ZoneAttributeStrategy : AttributeGroupingStrategy { public override string GroupTypeName => "区域"; public override string UnclassifiedLabel => "未设置区域"; protected override string GetAttributeValue(ModelItem item) { return _floorManager.GetFloorProperty(item, "区域"); } } /// /// 子系统属性分组策略 /// private class SubSystemAttributeStrategy : AttributeGroupingStrategy { public override string GroupTypeName => "子系统"; public override string UnclassifiedLabel => "未设置子系统"; protected override string GetAttributeValue(ModelItem item) { return _floorManager.GetFloorProperty(item, "子系统"); } } /// /// 简化的分层配置 /// public class SplitConfiguration { /// /// 分层策略 /// public SplitStrategy Strategy { get; set; } = SplitStrategy.BySmartFloorDetection; /// /// 属性名称(用于自定义分层时使用) /// public string AttributeName { get; set; } = "Level"; /// /// 输出目录 /// public string OutputDirectory { get; set; } = ""; /// /// 文件命名模式 /// public string FileNamePattern { get; set; } = "{ProjectName}_{LayerName}"; /// /// 遍历深度限制(1=仅第一级,2=到第二级,3=到第三级,0=所有级别) /// public int MaxDepth { get; set; } = 1; /// /// 导出选项配置 - 用户可配置的NWD导出选项 /// public NwdExportUserOptions ExportOptions { get; set; } = new NwdExportUserOptions(); } /// /// 用户可配置的NWD导出选项 - 对应截图中的选项 /// public class NwdExportUserOptions { /// /// 嵌入 ReCap 和纹理数据 - 对应截图中的复选框 /// public bool EmbedXrefs { get; set; } = false; /// /// 阻止导出对象特性 - 对应截图中的复选框 /// public bool PreventObjectPropertyExport { get; set; } = false; /// /// Navisworks 版本 - 对应截图中的下拉框(暂时使用默认值) /// public string FileVersion { get; set; } = "2026"; } /// /// 分层预览结果 /// public class SplitPreviewResult { public string LayerName { get; set; } public string LayerAttribute { get; set; } public ModelItemCollection Items { get; set; } = new ModelItemCollection(); public Dictionary Metadata { get; set; } = new Dictionary(); /// /// 是否选中用于保存,默认为true /// public bool IsSelectedForSave { get; set; } = true; } #endregion #region 事件定义 public event EventHandler ProgressChanged; public event EventHandler StatusChanged; #endregion #region 私有字段 /// /// 静态实例,方便其他类调用缓存清除功能 /// public static ModelSplitterManager Instance { get; private set; } private readonly FloorDetector _floorDetector; // 楼层检测结果缓存 private readonly Dictionary> _floorCache; private readonly object _cacheLock; #endregion #region 构造函数 public ModelSplitterManager() { // 设置静态实例 Instance = this; _floorDetector = new FloorDetector(); // 初始化缓存 _floorCache = new Dictionary>(); _cacheLock = new object(); // 验证Navisworks运行时环境 ValidateNavisworksRuntime(); LogManager.Info("[SimplifiedModelSplitter] 简化分层管理器已初始化,包含缓存机制和运行时验证"); } /// /// 验证Navisworks运行时环境 - 基于示例中的最佳实践 /// private void ValidateNavisworksRuntime() { try { LogManager.Info("[SimplifiedModelSplitter] 开始验证Navisworks运行时环境..."); // 1. 检查线程模型 - 必须在STA线程中 var apartmentState = System.Threading.Thread.CurrentThread.GetApartmentState(); LogManager.Info($"[分层管理器] 当前线程状态: {apartmentState}"); if (apartmentState != System.Threading.ApartmentState.STA) { LogManager.Warning("[SimplifiedModelSplitter] 警告:当前不在STA线程中,这可能导致API调用失败"); LogManager.Warning("[SimplifiedModelSplitter] 建议:确保主线程标记为[STAThread]"); } // 2. 检查Navisworks API可用性 - 适用于Navisworks 2026 try { // 尝试访问Navisworks Application来验证API是否可用 var app = NavisApplication.ActiveDocument; LogManager.Info("[SimplifiedModelSplitter] Navisworks API可用性检查通过"); } catch (Exception apiEx) { LogManager.Error($"[分层管理器] Navisworks API不可用: {apiEx.Message}"); LogManager.Error("[SimplifiedModelSplitter] 解决方案:确保在Navisworks环境中运行此插件"); } // 3. 检查文档状态 try { var document = NavisApplication.ActiveDocument; if (document != null) { LogManager.Info($"[分层管理器] 活动文档: {document.FileName ?? "未命名"}"); LogManager.Info($"[分层管理器] 文档模型数量: {document.Models?.Count ?? 0}"); } else { LogManager.Warning("[SimplifiedModelSplitter] 当前没有活动文档"); } } catch (Exception docEx) { LogManager.Warning($"[分层管理器] 检查文档状态时出错: {docEx.Message}"); } // 4. 内存状态检查 long memoryMB = GC.GetTotalMemory(false) / 1024 / 1024; LogManager.Info($"[分层管理器] 当前内存使用: {memoryMB} MB"); LogManager.Info("[SimplifiedModelSplitter] Navisworks运行时环境验证完成"); } catch (Exception ex) { LogManager.Error($"[分层管理器] 运行时环境验证失败: {ex.Message}"); } } #endregion #region 公共方法 /// /// 清除缓存 /// public void ClearCache() { lock (_cacheLock) { _floorCache.Clear(); LogManager.Info("[SimplifiedModelSplitter] 缓存已清除"); } } /// /// 预览分层结果(简化版本,带缓存和进度报告) /// public List PreviewSplit(SplitConfiguration config) { try { LogManager.Info($"[分层管理器] 开始智能遍历分层预览,策略: {config.Strategy},深度限制: {config.MaxDepth}"); // 步骤1:初始化和缓存检查 (0-10%) OnStatusChanged("正在初始化智能分层预览..."); OnProgressChanged(new ProgressChangedEventArgs(0, "准备智能遍历配置")); // 生成缓存键(注意:智能遍历的缓存键需要区别于原有方式) string cacheKey = GenerateSmartTraversalCacheKey(config); LogManager.Info($"[分层管理器] 生成智能遍历缓存键: {cacheKey}"); OnProgressChanged(new ProgressChangedEventArgs(5, "检查缓存")); // 检查缓存 List cachedResults = GetFromCache(config.Strategy, cacheKey); if (cachedResults != null && cachedResults.Count > 0) { LogManager.Info($"[分层管理器] 使用缓存结果,共 {cachedResults.Count} 个分层"); OnStatusChanged($"使用缓存结果,识别到 {cachedResults.Count} 个分层"); OnProgressChanged(new ProgressChangedEventArgs(100, $"从缓存加载 {cachedResults.Count} 个分层")); return cachedResults; } // 步骤2:验证文档状态 (10-15%) OnStatusChanged("正在验证模型文档..."); OnProgressChanged(new ProgressChangedEventArgs(10, "验证Navisworks文档状态")); var document = NavisApplication.ActiveDocument; if (document?.Models?.Count == 0) { throw new InvalidOperationException("当前文档中没有模型"); } OnProgressChanged(new ProgressChangedEventArgs(15, $"文档验证完成,包含 {document.Models.Count} 个模型")); LogManager.Info($"[分层管理器] 文档验证完成,包含 {document.Models.Count} 个模型"); // 步骤3:执行智能遍历分层分析 (15-90%) OnStatusChanged($"正在执行{GetStrategyDisplayName(config.Strategy)}..."); OnProgressChanged(new ProgressChangedEventArgs(20, "开始智能遍历分析")); var previewResults = new List(); var strategy = CreateStrategy(config.Strategy); // 关键改变:直接使用智能遍历,不再预收集所有节点 LogManager.Info($"[分层管理器] 使用智能遍历算法,策略: {strategy.GroupTypeName}"); previewResults = PreviewSplitWithSmartTraversal(config, strategy); OnProgressChanged(new ProgressChangedEventArgs(90, $"智能分析完成,识别到 {previewResults.Count} 个分层")); // 步骤4:缓存结果和完成 (90-100%) OnStatusChanged("正在保存分析结果..."); OnProgressChanged(new ProgressChangedEventArgs(95, "保存到缓存")); // 缓存结果 SaveToCache(config.Strategy, cacheKey, previewResults); // 完成 OnStatusChanged($"智能预览完成,识别到 {previewResults.Count} 个分层"); OnProgressChanged(new ProgressChangedEventArgs(100, $"预览完成,共 {previewResults.Count} 个分层")); LogManager.Info($"[分层管理器] 智能遍历预览完成,共识别 {previewResults.Count} 个分层(深度: {config.MaxDepth}级),已缓存"); return previewResults; } catch (Exception ex) { LogManager.Error($"[分层管理器] 智能遍历预览失败: {ex.Message}", ex); OnStatusChanged($"预览失败: {ex.Message}"); OnProgressChanged(new ProgressChangedEventArgs(0, $"预览失败: {ex.Message}")); throw; } } /// /// 生成缓存键 - 使用统一的深度遍历 /// private string GenerateCacheKey(SplitConfiguration config) { return $"{config.Strategy}_{config.MaxDepth}_{config.AttributeName ?? "Floor"}_" + $"{GetItemsByDepthUnified(config.MaxDepth).Count}"; } /// /// 生成智能遍历专用的缓存键 - 区别于原有的预收集模式 /// private string GenerateSmartTraversalCacheKey(SplitConfiguration config) { // 智能遍历的缓存键包含特殊标识,避免与原有缓存冲突 return $"SmartTraversal_{config.Strategy}_{config.MaxDepth}_{config.AttributeName ?? "Default"}_{DateTime.Now:yyyyMMdd}"; } /// /// 创建分层策略实例 /// private IGroupingStrategy CreateStrategy(SplitStrategy strategy) { switch (strategy) { case SplitStrategy.BySmartFloorDetection: return new FloorDetectionStrategy(_floorDetector); case SplitStrategy.ByFloorAttribute: return new FloorAttributeStrategy(); case SplitStrategy.ByZoneAttribute: return new ZoneAttributeStrategy(); case SplitStrategy.BySubSystemAttribute: return new SubSystemAttributeStrategy(); default: throw new NotSupportedException($"不支持的分层策略: {strategy}"); } } /// /// 从缓存获取结果 /// private List GetFromCache(SplitStrategy strategy, string cacheKey) { lock (_cacheLock) { // 只支持楼层缓存和自定义楼层缓存 var cache = _floorCache; return cache.ContainsKey(cacheKey) ? cache[cacheKey] : null; } } /// /// 保存结果到缓存 /// private void SaveToCache(SplitStrategy strategy, string cacheKey, List results) { lock (_cacheLock) { // 只支持楼层缓存和自定义楼层缓存 var cache = _floorCache; cache[cacheKey] = results; LogManager.Info($"[分层管理器] 结果已缓存: {strategy}, 键: {cacheKey}, 数量: {results.Count}"); } } /// /// 执行分层保存(异步,简化版本) /// public async Task ExecuteSplitAsync(SplitConfiguration config, CancellationToken cancellationToken = default) { try { LogManager.Info($"[分层管理器] 开始执行分层,策略: {config.Strategy}"); OnStatusChanged("正在准备分层..."); // 优先从缓存获取分层结果,避免重复检测 string cacheKey = GenerateSmartTraversalCacheKey(config); var previewResults = GetFromCache(config.Strategy, cacheKey); if (previewResults == null || previewResults.Count == 0) { LogManager.Info($"[分层管理器] 缓存中没有结果,重新预览分层"); previewResults = PreviewSplit(config); if (previewResults.Count == 0) { throw new InvalidOperationException("没有可分层的内容"); } } else { LogManager.Info($"[分层管理器] 使用缓存的分层结果,共 {previewResults.Count} 个分层"); } // 过滤出需要保存的分层 var layersToSave = previewResults.Where(p => p.IsSelectedForSave).ToList(); if (layersToSave.Count == 0) { LogManager.Warning("[SimplifiedModelSplitter] 没有选中任何分层进行保存"); OnStatusChanged("没有选中任何分层进行保存"); return; } LogManager.Info($"[分层管理器] 将保存 {layersToSave.Count}/{previewResults.Count} 个选中的分层"); // 确保输出目录存在 EnsureOutputDirectory(config.OutputDirectory); // 逐个处理分层,增强错误处理 int successCount = 0; var failedLayers = new List(); for (int i = 0; i < layersToSave.Count; i++) { if (cancellationToken.IsCancellationRequested) { LogManager.Info($"[分层管理器] 用户取消分层操作,已处理 {successCount}/{layersToSave.Count} 个分层"); break; } var preview = layersToSave[i]; OnStatusChanged($"正在处理分层: {preview.LayerName} ({i + 1}/{layersToSave.Count})"); OnProgressChanged(new ProgressChangedEventArgs((i + 1) * 100 / layersToSave.Count, $"处理分层 {i + 1}/{layersToSave.Count}: {preview.LayerName}")); try { // 实现具体的分层保存逻辑 await ProcessSingleLayerAsync(preview, config, cancellationToken, i + 1, layersToSave.Count); successCount++; LogManager.Info($"[分层管理器] 分层 {preview.LayerName} 处理成功 ({successCount}/{layersToSave.Count})"); } catch (Exception layerEx) { string errorMsg = $"分层 {preview.LayerName} 处理失败: {layerEx.Message}"; LogManager.Error($"[分层管理器] {errorMsg}"); failedLayers.Add(preview.LayerName); // 继续处理其他分层,不因单个失败而中断整个进程 OnStatusChanged(errorMsg); } } // 生成最终统计信息 string finalMessage = $"分层处理完成:成功 {successCount} 个,失败 {failedLayers.Count} 个"; if (layersToSave.Count < previewResults.Count) { int skippedCount = previewResults.Count - layersToSave.Count; finalMessage += $",跳过 {skippedCount} 个未选中的分层"; } if (failedLayers.Count > 0) { finalMessage += $"\n失败列表: {string.Join(", ", failedLayers)}"; LogManager.Warning($"[分层管理器] {finalMessage}"); } else { LogManager.Info($"[分层管理器] {finalMessage}"); } OnStatusChanged(finalMessage); // 如果所有分层都失败,抛出异常 if (successCount == 0 && layersToSave.Count > 0) { throw new InvalidOperationException($"所有选中的分层处理都失败了,共 {layersToSave.Count} 个分层"); } LogManager.Info($"[分层管理器] 分层执行完成:成功 {successCount}/{layersToSave.Count}"); } catch (Exception ex) { LogManager.Error($"[分层管理器] 分层执行失败: {ex.Message}"); OnStatusChanged($"分层失败: {ex.Message}"); throw; } } /// /// 执行分层保存(同步版本,用于UI线程调用) /// public void ExecuteSplit(SplitConfiguration config) { try { LogManager.Info($"[分层管理器] 开始执行分层,策略: {config.Strategy}"); OnStatusChanged("正在准备分层..."); // 优先从缓存获取分层结果,避免重复检测 string cacheKey = GenerateSmartTraversalCacheKey(config); var previewResults = GetFromCache(config.Strategy, cacheKey); if (previewResults == null || previewResults.Count == 0) { LogManager.Info($"[分层管理器] 缓存中没有结果,重新预览分层"); previewResults = PreviewSplit(config); if (previewResults.Count == 0) { throw new InvalidOperationException("没有可分层的内容"); } } else { LogManager.Info($"[分层管理器] 使用缓存的分层结果,共 {previewResults.Count} 个分层"); } // 过滤出需要保存的分层 var layersToSave = previewResults.Where(p => p.IsSelectedForSave).ToList(); if (layersToSave.Count == 0) { LogManager.Warning("[SimplifiedModelSplitter] 没有选中任何分层进行保存"); OnStatusChanged("没有选中任何分层进行保存"); return; } LogManager.Info($"[分层管理器] 将保存 {layersToSave.Count}/{previewResults.Count} 个选中的分层"); // 确保输出目录存在 EnsureOutputDirectory(config.OutputDirectory); // 逐个处理分层,增强错误处理(同步版本) int successCount = 0; var failedLayers = new List(); for (int i = 0; i < layersToSave.Count; i++) { var preview = layersToSave[i]; OnStatusChanged($"正在处理分层: {preview.LayerName} ({i + 1}/{layersToSave.Count})"); OnProgressChanged(new ProgressChangedEventArgs((i + 1) * 100 / layersToSave.Count, $"处理分层 {i + 1}/{layersToSave.Count}: {preview.LayerName}")); try { // 同步处理单个分层 ProcessSingleLayer(preview, config, i + 1, layersToSave.Count); successCount++; LogManager.Info($"[分层管理器] 分层 {preview.LayerName} 处理成功 ({successCount}/{layersToSave.Count})"); } catch (Exception layerEx) { string errorMsg = $"分层 {preview.LayerName} 处理失败: {layerEx.Message}"; LogManager.Error($"[分层管理器] {errorMsg}"); failedLayers.Add(preview.LayerName); // 继续处理其他分层,不因单个失败而中断整个进程 OnStatusChanged(errorMsg); } } // 生成最终统计信息 string finalMessage = $"分层处理完成:成功 {successCount} 个,失败 {failedLayers.Count} 个"; if (layersToSave.Count < previewResults.Count) { int skippedCount = previewResults.Count - layersToSave.Count; finalMessage += $",跳过 {skippedCount} 个未选中的分层"; } if (failedLayers.Count > 0) { finalMessage += $"\n失败列表: {string.Join(", ", failedLayers)}"; LogManager.Warning($"[分层管理器] {finalMessage}"); } else { LogManager.Info($"[分层管理器] {finalMessage}"); } OnStatusChanged(finalMessage); // 如果所有分层都失败,抛出异常 if (successCount == 0 && layersToSave.Count > 0) { throw new InvalidOperationException($"所有选中的分层处理都失败了,共 {layersToSave.Count} 个分层"); } LogManager.Info($"[分层管理器] 分层执行完成:成功 {successCount}/{layersToSave.Count}"); } catch (Exception ex) { LogManager.Error($"[分层管理器] 分层执行失败: {ex.Message}"); OnStatusChanged($"分层失败: {ex.Message}"); throw; } } #endregion #region 私有方法 /// /// 统一的深度遍历核心函数 - 精确控制深度逻辑 /// /// 最大深度,1=仅第一级,2=到第二级,3=到第三级,4=到第四级,5=到第五级,0=所有级别 /// 按深度筛选的模型项集合 private ModelItemCollection GetItemsByDepthUnified(int maxDepth) { try { LogManager.Info($"[分层管理器] ===== GetItemsByDepthUnified开始 ===== maxDepth={maxDepth}"); var document = NavisApplication.ActiveDocument; if (document?.Models?.Count == 0) { LogManager.Warning("[SimplifiedModelSplitter] 当前文档没有模型"); return new ModelItemCollection(); } var result = new ModelItemCollection(); if (maxDepth <= 0) { // 深度为0表示包含所有级别 result.AddRange(document.Models.RootItemDescendantsAndSelf); LogManager.Info($"[分层管理器] maxDepth=0,返回所有级别的项,共{result.Count}个"); return result; } // 从文档的根模型开始精确的深度遍历 foreach (Model model in document.Models) { if (model.RootItem != null) { // 添加第一级节点(模型根的直接子节点) if (maxDepth >= 1) { foreach (ModelItem firstLevelItem in model.RootItem.Children) { result.Add(firstLevelItem); // 递归添加更深层次的节点 AddChildrenToDepth(firstLevelItem, result, 2, maxDepth); } } } } LogManager.Info($"[分层管理器] ===== GetItemsByDepthUnified完成 ===== 返回{result.Count}个模型项(深度:{maxDepth}级)"); return result; } catch (Exception ex) { LogManager.Error($"[分层管理器] GetItemsByDepthUnified异常: {ex.Message}"); return new ModelItemCollection(); } } /// /// 递归添加子节点到指定深度 /// /// 父节点 /// 结果集合 /// 当前深度 /// 最大深度 private void AddChildrenToDepth(ModelItem parentItem, ModelItemCollection result, int currentDepth, int maxDepth) { if (currentDepth > maxDepth || parentItem?.Children == null) return; foreach (ModelItem child in parentItem.Children) { result.Add(child); // 如果还没有达到最大深度,继续遍历子项 if (currentDepth < maxDepth) { AddChildrenToDepth(child, result, currentDepth + 1, maxDepth); } } } /// /// 智能遍历分层预览 - 边遍历边检查边停止的新算法 /// 替代原有的预收集模式,大幅提升预览性能 /// private List PreviewSplitWithSmartTraversal(SplitConfiguration config, IGroupingStrategy strategy) { // 使用字典按楼层名分组,自动合并同名楼层 var layerGroups = new Dictionary(); try { LogManager.Info($"[分层管理器] ========== 开始智能遍历分层预览 =========="); LogManager.Info($"[分层管理器] 策略: {strategy.GroupTypeName}, 深度限制: {config.MaxDepth}"); var document = NavisApplication.ActiveDocument; if (document?.Models?.Count == 0) { LogManager.Warning("[SimplifiedModelSplitter] 当前文档没有模型"); return new List(); } // 从每个模型的一级节点开始智能遍历 int processedTopNodes = 0; foreach (Model model in document.Models) { if (model.RootItem?.Children != null) { foreach (ModelItem rootChild in model.RootItem.Children) { processedTopNodes++; // 统一使用 TraverseAndRecord 处理所有节点 // 它会自动检测节点是否有楼层属性并正确处理 TraverseAndRecord(rootChild, strategy, config, layerGroups, 1); // 每处理10个顶级节点记录一次进度 if (processedTopNodes % 10 == 0) { LogManager.Info($"[分层管理器] 已处理 {processedTopNodes} 个顶级节点,找到 {layerGroups.Count} 个分层"); } } } } LogManager.Info($"[分层管理器] ========== 智能遍历完成 =========="); LogManager.Info($"[分层管理器] 处理了 {processedTopNodes} 个顶级节点,识别到 {layerGroups.Count} 个{strategy.GroupTypeName}分层"); // 将字典转换为列表返回 var results = new List(layerGroups.Values); // 记录每个分层的详细信息 foreach (var layer in results) { var rootNodes = layer.Metadata["RootNodes"] as List; LogManager.Info($"[分层管理器] 楼层 '{layer.LayerName}': {rootNodes?.Count ?? 0} 个分支, {layer.Items.Count} 个节点"); } return results; } catch (Exception ex) { LogManager.Error($"[分层管理器] 智能遍历失败: {ex.Message}", ex); throw; } } /// /// 递归遍历节点并记录分层结果的核心方法(支持同名楼层合并) /// private void TraverseAndRecord(ModelItem node, IGroupingStrategy strategy, SplitConfiguration config, Dictionary layerGroups, int currentDepth) { try { // 检查当前节点的分层属性 string layerValue = strategy.ExtractAttributeValue(node); if (!string.IsNullOrEmpty(layerValue)) { // 找到分层属性,获取属性类型信息(仅对智能检测策略) string detectedAttributeName = null; if (strategy is FloorDetectionStrategy floorStrategy) { var (attributeName, attributeValue) = floorStrategy.ExtractAttributeInfo(node); detectedAttributeName = attributeName; LogManager.Info($"[分层管理器] 智能检测到属性类型: '{attributeName}', 值: '{attributeValue}'"); } // 清理楼层名称 string sanitizedLayerName = SanitizeLayerName(layerValue); // 检查是否已存在该楼层的结果 if (!layerGroups.ContainsKey(sanitizedLayerName)) { // 第一次遇到这个楼层名,创建新结果 layerGroups[sanitizedLayerName] = new SplitPreviewResult { LayerName = sanitizedLayerName, LayerAttribute = GetAttributeDescription(config.Strategy, layerValue, null), Items = new ModelItemCollection(), Metadata = new Dictionary { ["RootNodes"] = new List(), // 存储多个根节点 ["BranchCount"] = 0, ["GroupType"] = strategy.GroupTypeName, ["TraversalMode"] = "SmartTraversal", ["DetectedAttributeName"] = detectedAttributeName } }; LogManager.Info($"[分层管理器] 创建新楼层分组: '{sanitizedLayerName}'"); } // 获取现有楼层结果 var layerResult = layerGroups[sanitizedLayerName]; // 只添加根节点,不展开子节点 // IsolateSpecificItems 会自动处理子节点(通过 Descendants) layerResult.Items.Add(node); LogManager.Info($"[分层管理器] 添加根节点: {node.DisplayName}"); // 记录这个分支的根节点 var rootNodes = layerResult.Metadata["RootNodes"] as List; rootNodes.Add(node); // 更新分支计数 layerResult.Metadata["BranchCount"] = rootNodes.Count; layerResult.Metadata["EstimatedNodeCount"] = rootNodes.Count; // 只是根节点数量 LogManager.Info($"[分层管理器] 合并到楼层 '{sanitizedLayerName}',现有 {rootNodes.Count} 个根节点"); return; // 关键:停止遍历该分支 } // 未找到分层属性且未达深度限制,继续遍历子节点 if (currentDepth < config.MaxDepth && node.Children != null) { foreach (ModelItem child in node.Children) { TraverseAndRecord(child, strategy, config, layerGroups, currentDepth + 1); } } } catch (Exception ex) { LogManager.Warning($"[分层管理器] 遍历节点失败: {node?.DisplayName ?? "null"}, 错误: {ex.Message}"); } } // ExpandNodeTree 方法已删除,不再需要展开节点树 // IsolateSpecificItems 会自动处理子节点(通过 Descendants) /// /// 创建轻量化分层预览结果 - 只包含必要信息,不做统计计算 /// /// /// 创建轻量化分层预览结果 - 只包含必要信息,不做统计计算 /// private SplitPreviewResult CreateLayerResult(string layerValue, ModelItem rootNode, string groupTypeName, SplitStrategy strategy, string detectedAttributeName = null) { // 性能优化:只保存根节点,不展开子节点 // IsolateSpecificItems 会自动处理子节点(通过 Descendants) var allNodes = new ModelItemCollection(); allNodes.Add(rootNode); // 快速统计子节点数量(可选,用于显示信息) int estimatedNodeCount = 1; try { // 只统计直接子节点数量,不递归遍历 if (rootNode.Children != null && rootNode.Children.Count() > 0) { estimatedNodeCount += rootNode.Children.Count(); LogManager.Info($"[分层管理器] 节点 '{rootNode.DisplayName}' 包含 {rootNode.Children.Count()} 个直接子节点"); } } catch (Exception ex) { LogManager.Warning($"[分层管理器] 统计子节点时出现异常: {ex.Message}"); } var metadata = new Dictionary { ["LayerValue"] = layerValue, ["RootNodeReference"] = rootNode, ["GroupType"] = groupTypeName, ["TraversalMode"] = "SmartTraversal", ["EstimatedNodeCount"] = estimatedNodeCount // 只是估算值,用于显示 }; // 如果检测到了具体的属性类型,保存到元数据中 if (!string.IsNullOrEmpty(detectedAttributeName)) { metadata["DetectedAttributeName"] = detectedAttributeName; } return new SplitPreviewResult { LayerName = SanitizeLayerName(layerValue), LayerAttribute = GetAttributeDescription(strategy, layerValue, metadata), Items = allNodes, // 只包含根节点,导出时会自动处理子节点 Metadata = metadata }; } /// /// 处理单个分层(异步版本) /// private async Task ProcessSingleLayerAsync(SplitPreviewResult preview, SplitConfiguration config, CancellationToken cancellationToken, int currentIndex = 0, int totalCount = 0) { try { LogManager.Info($"[分层管理器] 开始处理分层: {preview.LayerName}, 类型: {preview.LayerAttribute}"); // 检查取消请求 cancellationToken.ThrowIfCancellationRequested(); // 生成输出文件路径(使用新的智能文件名格式) string fileName = GenerateFileName(preview.LayerName, config.Strategy, config); string outputPath = Path.Combine(config.OutputDirectory, fileName); LogManager.Info($"[分层管理器] 分层文件路径: {outputPath}"); // 直接在UI线程调用,不使用Task.Run包装 bool success = ExportLayerToNwd(preview, outputPath, config); if (success) { LogManager.Info($"[分层管理器] 分层 {preview.LayerName} 导出成功: {outputPath}"); } else { LogManager.Error($"[分层管理器] 分层 {preview.LayerName} 导出失败"); throw new InvalidOperationException($"分层 {preview.LayerName} 导出失败"); } } catch (Exception ex) { LogManager.Error($"[分层管理器] 处理分层失败 {preview.LayerName}: {ex.Message}"); throw; } } /// /// 处理单个分层(同步版本) /// private void ProcessSingleLayer(SplitPreviewResult preview, SplitConfiguration config, int currentIndex = 0, int totalCount = 0) { try { LogManager.Info($"[分层管理器] 开始同步处理分层: {preview.LayerName}, 类型: {preview.LayerAttribute}"); if (preview.Items == null || preview.Items.Count == 0) { LogManager.Warning($"[分层管理器] 分层 {preview.LayerName} 没有包含模型元素,跳过导出"); return; } // 生成输出文件路径(使用新的智能文件名格式) string fileName = GenerateFileName(preview.LayerName, config.Strategy, config); string outputPath = Path.Combine(config.OutputDirectory, fileName); LogManager.Info($"[分层管理器] 分层文件路径: {outputPath}"); // 检查模型项数量,对大量模型项进行特殊处理 if (preview.Items != null && preview.Items.Count > 100) { LogManager.Warning($"[分层管理器] 大量模型项检测:{preview.Items.Count}个,可能需要更多内存和时间"); // 强制垃圾回收,释放内存 GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); LogManager.Info($"[分层管理器] 垃圾回收完成,当前内存: {GC.GetTotalMemory(false) / 1024 / 1024} MB"); } // 更新状态:正在导出 string progressInfo = (currentIndex > 0 && totalCount > 0) ? $" ({currentIndex}/{totalCount})" : ""; OnStatusChanged($"正在导出{progressInfo}: {preview.LayerName}..."); // 使用TryExportToNwd API导出分层 bool success = ExportLayerToNwd(preview, outputPath, config); if (success) { LogManager.Info($"[分层管理器] 分层 {preview.LayerName} 导出成功: {outputPath}"); // 获取文件大小信息 string fileSizeInfo = ""; try { if (File.Exists(outputPath)) { var fileInfo = new FileInfo(outputPath); double sizeMB = fileInfo.Length / (1024.0 * 1024.0); fileSizeInfo = $" ({sizeMB:F1}MB)"; } } catch { } // 更新状态:导出成功 string successProgressInfo = (currentIndex > 0 && totalCount > 0) ? $" ({currentIndex}/{totalCount})" : ""; OnStatusChanged($"导出成功{successProgressInfo}: {preview.LayerName}{fileSizeInfo}"); } else { LogManager.Error($"[分层管理器] 分层 {preview.LayerName} 导出失败"); string failProgressInfo = (currentIndex > 0 && totalCount > 0) ? $" ({currentIndex}/{totalCount})" : ""; OnStatusChanged($"导出失败{failProgressInfo}: {preview.LayerName}"); throw new InvalidOperationException($"分层 {preview.LayerName} 导出失败"); } } catch (Exception ex) { LogManager.Error($"[分层管理器] 同步处理分层失败 {preview.LayerName}: {ex.Message}"); OnStatusChanged($"处理失败: {preview.LayerName} - {ex.Message}"); throw; } } /// /// 确保输出目录存在 /// private void EnsureOutputDirectory(string directory) { if (string.IsNullOrEmpty(directory)) throw new ArgumentException("输出目录不能为空"); if (!Directory.Exists(directory)) { Directory.CreateDirectory(directory); LogManager.Info($"[分层管理器] 创建输出目录: {directory}"); } } /// /// 清理分层名称(支持中文字符) /// private string SanitizeLayerName(string layerName) { if (string.IsNullOrEmpty(layerName)) return "未命名分层"; // 移除文件名中的非法字符,保留中文字符 var invalidChars = Path.GetInvalidFileNameChars(); string sanitized = layerName; foreach (char c in invalidChars) { sanitized = sanitized.Replace(c, '_'); } // 移除其他特殊字符,保留字母、数字、下划线和中文字符 sanitized = System.Text.RegularExpressions.Regex.Replace(sanitized, @"[^\w\u4e00-\u9fa5\-\.]", "_"); // 移除多余的下划线 sanitized = System.Text.RegularExpressions.Regex.Replace(sanitized, @"_{2,}", "_"); // 移除首尾下划线 sanitized = sanitized.Trim('_', ' '); // 限制长度 if (sanitized.Length > 50) { sanitized = sanitized.Substring(0, 50).TrimEnd('_'); } return string.IsNullOrEmpty(sanitized) ? "未命名分层" : sanitized; } /// /// 获取分层策略的属性描述 /// /// /// 获取具体的分层属性描述(实际属性值而非策略描述) /// /// 分层策略 /// 分层名称 /// 元数据,可能包含实际的属性信息 private string GetAttributeDescription(SplitStrategy strategy, string layerName, Dictionary metadata = null) { try { switch (strategy) { case SplitStrategy.BySmartFloorDetection: // 对于智能检测,直接返回元数据中检测到的真实属性名称 if (metadata != null && metadata.ContainsKey("DetectedAttributeName")) { return metadata["DetectedAttributeName"].ToString(); } // 如果没有元数据,通过分层名称推断属性类型 return InferAttributeTypeFromLayerName(layerName); case SplitStrategy.ByFloorAttribute: return "楼层"; case SplitStrategy.ByZoneAttribute: return "区域"; case SplitStrategy.BySubSystemAttribute: return "子系统"; default: return layerName; // 返回实际的分层名称 } } catch (Exception ex) { LogManager.Warning($"获取分层属性描述失败: {ex.Message}"); return layerName; // 失败时返回分层名称 } } /// /// 从分层名称推断属性类型(用于智能检测) /// private string InferAttributeTypeFromLayerName(string layerName) { if (string.IsNullOrEmpty(layerName)) return "未知属性"; string lowerName = layerName.ToLower(); // 楼层相关关键词 if (lowerName.Contains("floor") || lowerName.Contains("level") || lowerName.Contains("楼") || lowerName.Contains("层") || lowerName.Contains("f1") || lowerName.Contains("f2") || lowerName.Contains("f3")) { return "楼层"; } // 区域相关关键词 if (lowerName.Contains("zone") || lowerName.Contains("area") || lowerName.Contains("区") || lowerName.Contains("域") || lowerName.Contains("北") || lowerName.Contains("南") || lowerName.Contains("东") || lowerName.Contains("西")) { return "区域"; } // 子系统相关关键词 if (lowerName.Contains("system") || lowerName.Contains("subsystem") || lowerName.Contains("系统") || lowerName.Contains("机电") || lowerName.Contains("hvac") || lowerName.Contains("电气") || lowerName.Contains("给排水") || lowerName.Contains("消防")) { return "子系统"; } // 默认返回分层名称本身 return layerName; } /// /// 估算文件大小 /// private long EstimateFileSize(int itemCount) { // 简化的文件大小估算:每个元素约 1KB return itemCount * 1024L; } /// /// 生成文件名 - 新的智能格式:根节点名称_分层属性_属性值_时间戳.nwd /// /// 属性值(分层名称) /// 分层策略 /// 配置信息 /// 文件名(不包括路径) private string GenerateFileName(string attributeValue, SplitStrategy strategy, SplitConfiguration config) { try { // 获取根节点名称 string rootNodeName = GetRootNodeName(); // 获取分层属性类型名称 string attributeTypeName = GetAttributeTypeName(strategy); // 清理属性值(原分层名称) string sanitizedAttributeValue = SanitizeLayerName(attributeValue); // 生成时间戳 string timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss"); // 新的统一格式:根节点名称_分层属性_属性值_时间戳.nwd string fileName = $"{rootNodeName}_{attributeTypeName}_{sanitizedAttributeValue}_{timestamp}.nwd"; // 确保文件名唯一性 fileName = EnsureUniqueFileName(fileName, config.OutputDirectory); LogManager.Info($"[分层管理器] 生成智能文件名: {fileName}"); LogManager.Info($"[分层管理器] 文件名组成: 根节点='{rootNodeName}', 属性类型='{attributeTypeName}', 属性值='{sanitizedAttributeValue}', 时间戳='{timestamp}'"); return fileName; } catch (Exception ex) { LogManager.Error($"[分层管理器] 生成智能文件名失败: {ex.Message}"); // 失败时使用后备命名方式 string fallbackName = $"NavisworksModel_分层_{SanitizeLayerName(attributeValue)}_{DateTime.Now:yyyyMMdd_HHmmss}.nwd"; LogManager.Warning($"[分层管理器] 使用后备文件名: {fallbackName}"); return fallbackName; } } /// /// 获取根节点名称 - 新的智能文件名格式使用 /// 逻辑:文档文件名 → 第一个模型根项DisplayName → "NavisworksModel" /// /// 根节点名称 private string GetRootNodeName() { try { var document = NavisApplication.ActiveDocument; // 优先使用文档文件名(去除扩展名) if (document != null && !string.IsNullOrEmpty(document.FileName)) { string fileName = Path.GetFileNameWithoutExtension(document.FileName); if (!string.IsNullOrEmpty(fileName)) { return SanitizeLayerName(fileName); } } // 其次尝试使用第一个模型根项的DisplayName if (document?.Models != null && document.Models.Count > 0) { foreach (Model model in document.Models) { if (model.RootItem != null && !string.IsNullOrEmpty(model.RootItem.DisplayName)) { return SanitizeLayerName(model.RootItem.DisplayName); } } } // 最后使用默认名称 return "NavisworksModel"; } catch (Exception ex) { LogManager.Warning($"[分层管理器] 获取根节点名称失败: {ex.Message}"); return "NavisworksModel"; } } /// /// 获取当前项目名称(保留兼容性) /// /// 项目名称 private string GetCurrentProjectName() { return GetRootNodeName(); // 直接使用新的根节点名称方法 } /// /// 获取分层属性类型名称 /// /// 分层策略 /// 属性类型名称 private string GetAttributeTypeName(SplitStrategy strategy) { switch (strategy) { case SplitStrategy.BySmartFloorDetection: return "楼层"; case SplitStrategy.ByFloorAttribute: return "楼层"; case SplitStrategy.ByZoneAttribute: return "区域"; case SplitStrategy.BySubSystemAttribute: return "子系统"; default: return "分层"; } } /// /// 检查输出目录中是否存在同名文件并生成唯一文件名 /// /// 原始文件名 /// 输出目录 /// 唯一的文件名 private string EnsureUniqueFileName(string originalFileName, string outputDirectory) { try { string filePath = Path.Combine(outputDirectory, originalFileName); if (!File.Exists(filePath)) { return originalFileName; } string nameWithoutExtension = Path.GetFileNameWithoutExtension(originalFileName); string extension = Path.GetExtension(originalFileName); int counter = 1; string newFileName; do { newFileName = $"{nameWithoutExtension}_{counter:D2}{extension}"; filePath = Path.Combine(outputDirectory, newFileName); counter++; } while (File.Exists(filePath) && counter < 100); LogManager.Info($"[分层管理器] 文件名冲突,重命名为: {newFileName}"); return newFileName; } catch (Exception ex) { LogManager.Warning($"[分层管理器] 检查文件名唯一性失败: {ex.Message}"); return originalFileName; } } /// /// 使用正确的Navisworks API导出单个分层 - 基于示例中的最佳实践 /// public bool ExportLayerToNwd(SplitPreviewResult preview, string outputPath, SplitConfiguration config) { if (preview == null) { LogManager.Error($"[分层管理器] 预览结果为null"); return false; } try { LogManager.Info($"[分层管理器] ========== ExportLayerToNwd开始 =========="); LogManager.Info($"[分层管理器] 导出层: {preview.LayerName}"); LogManager.Info($"[分层管理器] 预览项数量: {preview.Items?.Count ?? 0}"); LogManager.Info($"[分层管理器] 输出路径: {outputPath}"); // 直接使用预览结果中的项目 if (preview.Items == null || preview.Items.Count == 0) { LogManager.Warning($"[分层管理器] 预览结果中没有模型项"); return false; } var itemsToExport = preview.Items; LogManager.Info($"[分层管理器] 将导出 {itemsToExport.Count} 个模型项"); // 检查线程状态 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 { LogManager.Info($"[分层管理器] 在主线程中执行导出操作"); var document = NavisApplication.ActiveDocument; // 保存当前可见性状态(在主线程中) LogManager.Info($"[分层管理器] 开始保存当前可见性状态"); var originalVisibilityState = SaveCurrentVisibilityState(document); LogManager.Info($"[分层管理器] 已保存 {originalVisibilityState.Count} 个项目的可见性状态"); try { // 直接使用预览结果中的项目,这些已经是展开的完整节点树 var itemsToIsolate = preview.Items; LogManager.Info($"[分层管理器] 准备隔离显示 {itemsToIsolate.Count} 个节点"); // 使用 VisibilityManager.IsolateSpecificItems 隔离显示 bool isolateSuccess = VisibilityHelper.IsolateSpecificItems(itemsToIsolate); if (!isolateSuccess) { throw new InvalidOperationException("隔离显示失败"); } LogManager.Info($"[分层管理器] 隔离显示成功"); // 创建导出选项 var exportOptions = new Autodesk.Navisworks.Api.NwdExportOptions { ExcludeHiddenItems = true, // 只导出可见项目 EmbedXrefs = config?.ExportOptions?.EmbedXrefs ?? false, PreventObjectPropertyExport = config?.ExportOptions?.PreventObjectPropertyExport ?? false }; LogManager.Info($"[分层管理器] 开始调用ExportToNwd API(主线程)"); LogManager.Info($"[分层管理器] 导出选项: ExcludeHiddenItems=true, EmbedXrefs={exportOptions.EmbedXrefs}, PreventObjectPropertyExport={exportOptions.PreventObjectPropertyExport}"); // 在主线程中执行导出 document.ExportToNwd(outputPath, exportOptions); LogManager.Info($"[分层管理器] ExportToNwd API调用完成(主线程)"); exportResult = true; } finally { // 恢复原始可见性状态(在主线程中) try { RestoreVisibilityState(document, originalVisibilityState); LogManager.Info($"[分层管理器] 已恢复原始可见性状态"); } catch (Exception restoreEx) { LogManager.Error($"[分层管理器] 恢复可见性失败: {restoreEx.Message}"); } } } catch (Exception ex) { exportException = ex; } }); // 检查导出结果 if (exportException != null) { LogManager.Error($"[分层管理器] 主线程导出异常: {exportException.Message}"); LogManager.Error($"[分层管理器] 异常堆栈: {exportException.StackTrace}"); return false; } LogManager.Info($"[分层管理器] ========== ExportLayerToNwd完成 ========== 成功导出到: {outputPath}"); return exportResult; } catch (Exception ex) { LogManager.Error($"[分层管理器] ExportLayerToNwd异常: {ex.Message}"); LogManager.Error($"[分层管理器] 异常堆栈: {ex.StackTrace}"); return false; } } /// /// 递归处理节点可见性 - 精细化控制每个节点 /// private void ProcessNodeVisibility(ModelItem node, HashSet exportItemsSet, ModelItemCollection itemsToHide, ref int processedCount, ref int hiddenCount) { if (node == null) return; processedCount++; // 检查当前节点是否在导出集合中 bool shouldExport = exportItemsSet.Contains(node); if (shouldExport) { // 这个节点要导出,不隐藏 // 继续处理其子节点(可能有些子节点不需要导出) if (node.Children != null) { foreach (ModelItem child in node.Children) { ProcessNodeVisibility(child, exportItemsSet, itemsToHide, ref processedCount, ref hiddenCount); } } } else { // 检查是否有任何子节点需要导出 bool hasExportChild = HasExportDescendant(node, exportItemsSet); if (hasExportChild) { // 有子节点需要导出,继续递归处理子节点 // 但不隐藏当前节点(因为需要保持结构) if (node.Children != null) { foreach (ModelItem child in node.Children) { ProcessNodeVisibility(child, exportItemsSet, itemsToHide, ref processedCount, ref hiddenCount); } } } else { // 当前节点及其所有子节点都不需要导出,隐藏整个分支 try { itemsToHide.Add(node); hiddenCount++; if (hiddenCount <= 10 || hiddenCount % 1000 == 0) { LogManager.Debug($"[分层管理器] 隐藏节点: {node.DisplayName}"); } } catch (Exception ex) { LogManager.Warning($"[分层管理器] 添加隐藏节点失败: {ex.Message}"); } // 不需要继续递归子节点,因为整个分支都隐藏了 } } } /// /// 检查节点是否有需要导出的后代 /// private bool HasExportDescendant(ModelItem node, HashSet exportItemsSet) { if (node?.Children == null || node.Children.Count() == 0) return false; // 使用队列进行广度优先搜索,避免深度递归 var queue = new Queue(); foreach (ModelItem child in node.Children) { queue.Enqueue(child); } while (queue.Count > 0) { var current = queue.Dequeue(); if (exportItemsSet.Contains(current)) { return true; // 找到需要导出的后代 } if (current.Children != null) { foreach (ModelItem child in current.Children) { queue.Enqueue(child); } } } return false; } /// /// 保存当前可见性状态(参考"保存当前选择项"的方法) /// private Dictionary SaveCurrentVisibilityState(Document document) { var visibilityState = new Dictionary(); try { // 获取所有顶级项目并记录它们的可见性状态 foreach (Model model in document.Models) { foreach (ModelItem topLevelItem in model.RootItem.Children) { try { // 记录是否隐藏(IsHidden为true表示隐藏,我们存储可见性所以取反) visibilityState[topLevelItem] = !topLevelItem.IsHidden; } catch { // 如果无法获取状态,默认为可见 visibilityState[topLevelItem] = true; } } } LogManager.Info($"[分层管理器] 保存可见性状态完成,记录了 {visibilityState.Count} 个顶级项目"); } catch (Exception ex) { LogManager.Error($"[分层管理器] 保存可见性状态失败: {ex.Message}"); } return visibilityState; } /// /// 获取分层对应的顶级层节点(不展开子节点) /// 根据API指南,我们应该选择顶级节点,让ExportToNwd自动处理其子树 /// /// /// 检查一个节点是否是顶级节点 /// private bool IsTopLevelNode(ModelItem item) { try { // 顶级节点的特征:父节点是RootItem,或者父节点为null,或者层级很浅 var parent = item.Parent; if (parent == null) { return true; // 没有父节点,可能是根节点 } // 检查父节点是否是模型的根项 var document = NavisApplication.ActiveDocument; if (document?.Models != null) { foreach (Model model in document.Models) { if (parent == model.RootItem) { return true; // 父节点是模型根项,说明这是顶级节点 } } } return false; } catch { return false; } } /// /// 查找一个节点的顶级父节点 /// private ModelItem FindTopLevelParent(ModelItem item) { try { var current = item; var document = NavisApplication.ActiveDocument; // 向上遍历直到找到顶级节点 while (current != null) { if (IsTopLevelNode(current)) { return current; } current = current.Parent; } return null; } catch { return null; } } /// /// 递归收集楼层顶层节点下的所有子节点 /// /// 楼层顶层节点集合 /// 包含所有子节点的完整模型项集合 private ModelItemCollection ExpandFloorItems(ModelItemCollection floorTopLevelItems) { try { LogManager.Info($"[分层管理器] ========== ExpandFloorItems开始 =========="); LogManager.Info($"[分层管理器] 输入顶层节点数量: {floorTopLevelItems.Count}"); var expandedItems = new ModelItemCollection(); int totalCollected = 0; foreach (ModelItem topLevelItem in floorTopLevelItems) { try { LogManager.Info($"[分层管理器] 开始展开顶层节点: '{topLevelItem.DisplayName}'"); // 添加顶层节点本身(如果它是具体的构件) if (IsActualComponent(topLevelItem)) { expandedItems.Add(topLevelItem); totalCollected++; } // 递归收集所有子节点 var childItems = CollectAllChildItems(topLevelItem, 0, 10); // 限制最大深度为10 // 验证收集到的子项是否有效 var validChildItems = ValidateModelItems(childItems); expandedItems.AddRange(validChildItems); totalCollected += validChildItems.Count; LogManager.Info($"[分层管理器] 顶层节点 '{topLevelItem.DisplayName}' 展开完成: 收集到{childItems.Count}个子项,有效{validChildItems.Count}个"); } catch (Exception ex) { LogManager.Warning($"[分层管理器] 展开顶层节点失败: {topLevelItem?.DisplayName ?? "null"}, 错误: {ex.Message}"); } } LogManager.Info($"[分层管理器] ========== ExpandFloorItems完成 ========== 总计收集: {totalCollected}个模型项"); return expandedItems; } catch (Exception ex) { LogManager.Error($"[分层管理器] ExpandFloorItems异常: {ex.Message}"); LogManager.Error($"[分层管理器] 异常堆栈: {ex.StackTrace}"); return new ModelItemCollection(); } } /// /// 递归收集模型项的所有子项 /// /// 父级模型项 /// 当前递归深度 /// 最大递归深度 /// 所有子项的集合 private ModelItemCollection CollectAllChildItems(ModelItem parentItem, int currentDepth, int maxDepth) { var childItems = new ModelItemCollection(); try { // 防止递归过深 if (currentDepth >= maxDepth) { LogManager.Warning($"[分层管理器] 达到最大递归深度 {maxDepth},停止展开: {parentItem?.DisplayName}"); return childItems; } if (parentItem?.Children == null || parentItem.Children.Count() == 0) { return childItems; } foreach (ModelItem child in parentItem.Children) { try { // 添加子项本身 childItems.Add(child); // 递归收集子项的子项 var grandChildren = CollectAllChildItems(child, currentDepth + 1, maxDepth); if (grandChildren.Count > 0) { childItems.AddRange(grandChildren); } // 每收集100个项目记录一次进度(只在顶层记录) if (currentDepth == 0 && childItems.Count % 100 == 0) { LogManager.Info($"[分层管理器] 已收集 {childItems.Count} 个子项..."); } } catch (Exception ex) { LogManager.Warning($"[分层管理器] 收集子项失败: {child?.DisplayName ?? "null"}, 错误: {ex.Message}"); } } } catch (Exception ex) { LogManager.Error($"[分层管理器] CollectAllChildItems异常: {ex.Message}"); } return childItems; } /// /// 验证模型项集合的有效性,过滤掉无效的模型项 /// /// 要验证的模型项集合 /// 有效的模型项集合 private ModelItemCollection ValidateModelItems(ModelItemCollection items) { var validItems = new ModelItemCollection(); int nullCount = 0; int invalidCount = 0; try { LogManager.Info($"[分层管理器] 开始验证 {items.Count} 个模型项的有效性..."); foreach (ModelItem item in items) { try { // 检查模型项是否为null if (item == null) { nullCount++; continue; } // 检查模型项是否可以访问基本属性(验证其有效性) string displayName = item.DisplayName; // 这会抛出异常如果项目无效 bool hasGeometry = item.HasGeometry; // 检查是否有几何体 // 如果能正常访问属性,则认为是有效的 validItems.Add(item); } catch (Exception ex) { invalidCount++; LogManager.Warning($"[分层管理器] 发现无效模型项: {ex.Message}"); } } LogManager.Info($"[分层管理器] 模型项验证完成: 总数{items.Count}, 有效{validItems.Count}, 空项{nullCount}, 无效{invalidCount}"); return validItems; } catch (Exception ex) { LogManager.Error($"[分层管理器] 验证模型项时发生异常: {ex.Message}"); // 异常时返回原始集合,避免完全失败 return items; } } /// /// 判断模型项是否是实际的构件(而不是组织结构节点) /// /// 模型项 /// 如果是实际构件返回true private bool IsActualComponent(ModelItem item) { try { if (item == null) return false; // 检查是否有几何体 - 有几何体的通常是实际构件 if (item.HasGeometry) { return true; } // 检查是否是叶子节点且有意义的名称 if (item.Children != null && item.Children.Count() == 0 && !string.IsNullOrEmpty(item.DisplayName)) { string name = item.DisplayName.ToLower(); // 排除一些明显的组织节点 if (!name.Contains("layer") && !name.Contains("group") && !name.Contains("floor")) { return true; } } return false; } catch (Exception ex) { LogManager.Warning($"[分层管理器] 判断构件类型失败: {ex.Message}"); return false; } } /// /// 恢复可见性状态 /// private void RestoreVisibilityState(Document document, Dictionary visibilityState) { try { LogManager.Info("[SimplifiedModelSplitter] 恢复可见性状态"); if (visibilityState == null || visibilityState.Count == 0) { LogManager.Warning("[SimplifiedModelSplitter] 没有可见性状态需要恢复,重置为全部可见"); document.Models.ResetAllHidden(); return; } // 使用成熟的可见性控制模式 - 分别收集要显示和隐藏的项目 var itemsToShow = new ModelItemCollection(); var itemsToHide = new ModelItemCollection(); foreach (var kvp in visibilityState) { try { if (kvp.Value) // 原来是可见的 { itemsToShow.Add(kvp.Key); } else // 原来是隐藏的 { itemsToHide.Add(kvp.Key); } } catch (Exception ex) { LogManager.Warning($"[分层管理器] 处理项目可见性状态时出错: {ex.Message}"); } } // 首先重置所有项目为可见状态 document.Models.ResetAllHidden(); // 然后隐藏原来应该隐藏的项目 if (itemsToHide.Count > 0) { document.Models.SetHidden(itemsToHide, true); LogManager.Info($"[分层管理器] 恢复隐藏 {itemsToHide.Count} 个项目"); } LogManager.Info("[SimplifiedModelSplitter] 可见性状态恢复完成"); } catch (Exception ex) { LogManager.Error($"[分层管理器] 恢复可见性状态失败: {ex.Message}"); // 失败时至少确保模型处于可见状态 try { document.Models.ResetAllHidden(); LogManager.Info("[SimplifiedModelSplitter] 已重置为全部可见状态"); } catch (Exception resetEx) { LogManager.Error($"[分层管理器] 重置可见性也失败: {resetEx.Message}"); } } } #endregion #region 辅助方法 /// /// 获取策略的显示名称 /// /// 分层策略 /// 显示名称 private string GetStrategyDisplayName(SplitStrategy strategy) { switch (strategy) { case SplitStrategy.BySmartFloorDetection: return "智能楼层检测分析"; case SplitStrategy.ByFloorAttribute: return "按楼层属性分析"; case SplitStrategy.ByZoneAttribute: return "按区域属性分析"; case SplitStrategy.BySubSystemAttribute: return "按子系统属性分析"; default: return "分层分析"; } } #endregion #region 事件触发 protected virtual void OnProgressChanged(ProgressChangedEventArgs e) { ProgressChanged?.Invoke(this, e); } protected virtual void OnStatusChanged(string status) { StatusChanged?.Invoke(this, status); } #endregion } }