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
}
}