2538 lines
110 KiB
C#
2538 lines
110 KiB
C#
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
|
||
{
|
||
/// <summary>
|
||
/// 简化版模型分层管理器 - 为新UI设计的轻量级分层管理
|
||
/// 功能范围:楼层分析、属性设置、分层保存、选中保存
|
||
/// </summary>
|
||
public class SimplifiedModelSplitterManager
|
||
{
|
||
#region 枚举和数据结构
|
||
|
||
/// <summary>
|
||
/// 简化的分层策略
|
||
/// </summary>
|
||
public enum SplitStrategy
|
||
{
|
||
BySmartFloorDetection, // 智能检测楼层(原ByFloor)
|
||
ByFloorAttribute, // 按楼层属性(原ByCustomFloor)
|
||
ByZoneAttribute, // 按区域属性
|
||
BySubSystemAttribute // 按子系统属性
|
||
}
|
||
|
||
/// <summary>
|
||
/// 分层分组策略接口
|
||
/// </summary>
|
||
private interface IGroupingStrategy
|
||
{
|
||
string GroupTypeName { get; }
|
||
string UnclassifiedLabel { get; }
|
||
Dictionary<string, GroupItem> GroupItems(ModelItemCollection items, SplitConfiguration config);
|
||
|
||
/// <summary>
|
||
/// 提取单个节点的属性值,用于智能遍历
|
||
/// </summary>
|
||
string ExtractAttributeValue(ModelItem node);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 分组项信息
|
||
/// </summary>
|
||
private class GroupItem
|
||
{
|
||
public string GroupName { get; set; }
|
||
public string OriginalName { get; set; }
|
||
public List<ModelItem> Items { get; set; } = new List<ModelItem>();
|
||
public Dictionary<string, object> Metadata { get; set; } = new Dictionary<string, object>();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 楼层检测分组策略 - 使用统一的深度遍历结果
|
||
/// </summary>
|
||
private class FloorDetectionStrategy : IGroupingStrategy
|
||
{
|
||
private readonly FloorDetector _floorDetector;
|
||
|
||
public string GroupTypeName => "楼层";
|
||
public string UnclassifiedLabel => "未检测到楼层";
|
||
|
||
public FloorDetectionStrategy(FloorDetector floorDetector)
|
||
{
|
||
_floorDetector = floorDetector;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 实现IGroupingStrategy接口的ExtractAttributeValue方法
|
||
/// 使用FloorDetector进行智能楼层检测
|
||
/// </summary>
|
||
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;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 从节点获取指定属性的值
|
||
/// </summary>
|
||
private string GetAttributeValueFromNode(ModelItem item, string attributeName)
|
||
{
|
||
try
|
||
{
|
||
foreach (PropertyCategory category in item.PropertyCategories)
|
||
{
|
||
foreach (DataProperty property in category.Properties)
|
||
{
|
||
if (string.Equals(property.DisplayName, attributeName, StringComparison.OrdinalIgnoreCase))
|
||
{
|
||
return property.Value?.ToDisplayString();
|
||
}
|
||
}
|
||
}
|
||
return null;
|
||
}
|
||
catch
|
||
{
|
||
return null;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取检测到的属性类型信息(属性名称和值)
|
||
/// </summary>
|
||
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<string, GroupItem> GroupItems(ModelItemCollection items, SplitConfiguration config)
|
||
{
|
||
var result = new Dictionary<string, GroupItem>();
|
||
|
||
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<ModelItem>(),
|
||
Metadata = new Dictionary<string, object>
|
||
{
|
||
["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;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 属性分组策略基类
|
||
/// </summary>
|
||
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);
|
||
|
||
/// <summary>
|
||
/// 实现IGroupingStrategy接口的ExtractAttributeValue方法
|
||
/// 直接调用子类已实现的GetAttributeValue方法
|
||
/// </summary>
|
||
public string ExtractAttributeValue(ModelItem node)
|
||
{
|
||
return GetAttributeValue(node);
|
||
}
|
||
|
||
public Dictionary<string, GroupItem> GroupItems(ModelItemCollection items, SplitConfiguration config)
|
||
{
|
||
var result = new Dictionary<string, GroupItem>();
|
||
|
||
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<string, int>();
|
||
|
||
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<string, object>
|
||
{
|
||
["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;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 楼层属性分组策略
|
||
/// </summary>
|
||
private class FloorAttributeStrategy : AttributeGroupingStrategy
|
||
{
|
||
public override string GroupTypeName => "楼层";
|
||
public override string UnclassifiedLabel => "未设置楼层";
|
||
|
||
protected override string GetAttributeValue(ModelItem item)
|
||
{
|
||
return _floorManager.GetFloorLevel(item);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 区域属性分组策略
|
||
/// </summary>
|
||
private class ZoneAttributeStrategy : AttributeGroupingStrategy
|
||
{
|
||
public override string GroupTypeName => "区域";
|
||
public override string UnclassifiedLabel => "未设置区域";
|
||
|
||
protected override string GetAttributeValue(ModelItem item)
|
||
{
|
||
return _floorManager.GetZoneAttribute(item);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 子系统属性分组策略
|
||
/// </summary>
|
||
private class SubSystemAttributeStrategy : AttributeGroupingStrategy
|
||
{
|
||
public override string GroupTypeName => "子系统";
|
||
public override string UnclassifiedLabel => "未设置子系统";
|
||
|
||
protected override string GetAttributeValue(ModelItem item)
|
||
{
|
||
return _floorManager.GetSubSystemAttribute(item);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 简化的分层配置
|
||
/// </summary>
|
||
public class SplitConfiguration
|
||
{
|
||
/// <summary>
|
||
/// 分层策略
|
||
/// </summary>
|
||
public SplitStrategy Strategy { get; set; } = SplitStrategy.BySmartFloorDetection;
|
||
|
||
/// <summary>
|
||
/// 属性名称(用于自定义分层时使用)
|
||
/// </summary>
|
||
public string AttributeName { get; set; } = "Level";
|
||
|
||
/// <summary>
|
||
/// 输出目录
|
||
/// </summary>
|
||
public string OutputDirectory { get; set; } = "";
|
||
|
||
/// <summary>
|
||
/// 文件命名模式
|
||
/// </summary>
|
||
public string FileNamePattern { get; set; } = "{ProjectName}_{LayerName}";
|
||
|
||
/// <summary>
|
||
/// 遍历深度限制(1=仅第一级,2=到第二级,3=到第三级,0=所有级别)
|
||
/// </summary>
|
||
public int MaxDepth { get; set; } = 1;
|
||
|
||
/// <summary>
|
||
/// 导出选项配置 - 用户可配置的NWD导出选项
|
||
/// </summary>
|
||
public NwdExportUserOptions ExportOptions { get; set; } = new NwdExportUserOptions();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 用户可配置的NWD导出选项 - 对应截图中的选项
|
||
/// </summary>
|
||
public class NwdExportUserOptions
|
||
{
|
||
/// <summary>
|
||
/// 嵌入 ReCap 和纹理数据 - 对应截图中的复选框
|
||
/// </summary>
|
||
public bool EmbedXrefs { get; set; } = false;
|
||
|
||
/// <summary>
|
||
/// 阻止导出对象特性 - 对应截图中的复选框
|
||
/// </summary>
|
||
public bool PreventObjectPropertyExport { get; set; } = false;
|
||
|
||
/// <summary>
|
||
/// Navisworks 版本 - 对应截图中的下拉框(暂时使用默认值)
|
||
/// </summary>
|
||
public string FileVersion { get; set; } = "2026";
|
||
}
|
||
|
||
/// <summary>
|
||
/// 分层预览结果
|
||
/// </summary>
|
||
public class SplitPreviewResult
|
||
{
|
||
public string LayerName { get; set; }
|
||
public string LayerAttribute { get; set; }
|
||
public ModelItemCollection Items { get; set; } = new ModelItemCollection();
|
||
public Dictionary<string, object> Metadata { get; set; } = new Dictionary<string, object>();
|
||
|
||
/// <summary>
|
||
/// 是否选中用于保存,默认为true
|
||
/// </summary>
|
||
public bool IsSelectedForSave { get; set; } = true;
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 事件定义
|
||
|
||
public event EventHandler<ProgressChangedEventArgs> ProgressChanged;
|
||
public event EventHandler<string> StatusChanged;
|
||
|
||
#endregion
|
||
|
||
#region 私有字段
|
||
|
||
/// <summary>
|
||
/// 静态实例,方便其他类调用缓存清除功能
|
||
/// </summary>
|
||
public static SimplifiedModelSplitterManager Instance { get; private set; }
|
||
|
||
private readonly FloorDetector _floorDetector;
|
||
|
||
// 楼层检测结果缓存
|
||
private readonly Dictionary<string, List<SplitPreviewResult>> _floorCache;
|
||
private readonly object _cacheLock;
|
||
|
||
#endregion
|
||
|
||
#region 构造函数
|
||
|
||
public SimplifiedModelSplitterManager()
|
||
{
|
||
// 设置静态实例
|
||
Instance = this;
|
||
|
||
_floorDetector = new FloorDetector();
|
||
|
||
// 初始化缓存
|
||
_floorCache = new Dictionary<string, List<SplitPreviewResult>>();
|
||
_cacheLock = new object();
|
||
|
||
// 验证Navisworks运行时环境
|
||
ValidateNavisworksRuntime();
|
||
|
||
LogManager.Info("[SimplifiedModelSplitter] 简化分层管理器已初始化,包含缓存机制和运行时验证");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 验证Navisworks运行时环境 - 基于示例中的最佳实践
|
||
/// </summary>
|
||
private void ValidateNavisworksRuntime()
|
||
{
|
||
try
|
||
{
|
||
LogManager.Info("[SimplifiedModelSplitter] 开始验证Navisworks运行时环境...");
|
||
|
||
// 1. 检查线程模型 - 必须在STA线程中
|
||
var apartmentState = System.Threading.Thread.CurrentThread.GetApartmentState();
|
||
LogManager.Info($"[SimplifiedModelSplitter] 当前线程状态: {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($"[SimplifiedModelSplitter] Navisworks API不可用: {apiEx.Message}");
|
||
LogManager.Error("[SimplifiedModelSplitter] 解决方案:确保在Navisworks环境中运行此插件");
|
||
}
|
||
|
||
// 3. 检查文档状态
|
||
try
|
||
{
|
||
var document = NavisApplication.ActiveDocument;
|
||
if (document != null)
|
||
{
|
||
LogManager.Info($"[SimplifiedModelSplitter] 活动文档: {document.FileName ?? "未命名"}");
|
||
LogManager.Info($"[SimplifiedModelSplitter] 文档模型数量: {document.Models?.Count ?? 0}");
|
||
}
|
||
else
|
||
{
|
||
LogManager.Warning("[SimplifiedModelSplitter] 当前没有活动文档");
|
||
}
|
||
}
|
||
catch (Exception docEx)
|
||
{
|
||
LogManager.Warning($"[SimplifiedModelSplitter] 检查文档状态时出错: {docEx.Message}");
|
||
}
|
||
|
||
// 4. 内存状态检查
|
||
long memoryMB = GC.GetTotalMemory(false) / 1024 / 1024;
|
||
LogManager.Info($"[SimplifiedModelSplitter] 当前内存使用: {memoryMB} MB");
|
||
|
||
LogManager.Info("[SimplifiedModelSplitter] Navisworks运行时环境验证完成");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"[SimplifiedModelSplitter] 运行时环境验证失败: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 公共方法
|
||
|
||
/// <summary>
|
||
/// 清除缓存
|
||
/// </summary>
|
||
public void ClearCache()
|
||
{
|
||
lock (_cacheLock)
|
||
{
|
||
_floorCache.Clear();
|
||
LogManager.Info("[SimplifiedModelSplitter] 缓存已清除");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 预览分层结果(简化版本,带缓存和进度报告)
|
||
/// </summary>
|
||
public List<SplitPreviewResult> PreviewSplit(SplitConfiguration config)
|
||
{
|
||
try
|
||
{
|
||
LogManager.Info($"[SimplifiedModelSplitter] 开始智能遍历分层预览,策略: {config.Strategy},深度限制: {config.MaxDepth}");
|
||
|
||
// 步骤1:初始化和缓存检查 (0-10%)
|
||
OnStatusChanged("正在初始化智能分层预览...");
|
||
OnProgressChanged(new ProgressChangedEventArgs(0, "准备智能遍历配置"));
|
||
|
||
// 生成缓存键(注意:智能遍历的缓存键需要区别于原有方式)
|
||
string cacheKey = GenerateSmartTraversalCacheKey(config);
|
||
LogManager.Info($"[SimplifiedModelSplitter] 生成智能遍历缓存键: {cacheKey}");
|
||
|
||
OnProgressChanged(new ProgressChangedEventArgs(5, "检查缓存"));
|
||
|
||
// 检查缓存
|
||
List<SplitPreviewResult> cachedResults = GetFromCache(config.Strategy, cacheKey);
|
||
if (cachedResults != null && cachedResults.Count > 0)
|
||
{
|
||
LogManager.Info($"[SimplifiedModelSplitter] 使用缓存结果,共 {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($"[SimplifiedModelSplitter] 文档验证完成,包含 {document.Models.Count} 个模型");
|
||
|
||
// 步骤3:执行智能遍历分层分析 (15-90%)
|
||
OnStatusChanged($"正在执行{GetStrategyDisplayName(config.Strategy)}...");
|
||
OnProgressChanged(new ProgressChangedEventArgs(20, "开始智能遍历分析"));
|
||
|
||
var previewResults = new List<SplitPreviewResult>();
|
||
var strategy = CreateStrategy(config.Strategy);
|
||
|
||
// 关键改变:直接使用智能遍历,不再预收集所有节点
|
||
LogManager.Info($"[SimplifiedModelSplitter] 使用智能遍历算法,策略: {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($"[SimplifiedModelSplitter] 智能遍历预览完成,共识别 {previewResults.Count} 个分层(深度: {config.MaxDepth}级),已缓存");
|
||
|
||
return previewResults;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"[SimplifiedModelSplitter] 智能遍历预览失败: {ex.Message}", ex);
|
||
OnStatusChanged($"预览失败: {ex.Message}");
|
||
OnProgressChanged(new ProgressChangedEventArgs(0, $"预览失败: {ex.Message}"));
|
||
throw;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成缓存键 - 使用统一的深度遍历
|
||
/// </summary>
|
||
private string GenerateCacheKey(SplitConfiguration config)
|
||
{
|
||
return $"{config.Strategy}_{config.MaxDepth}_{config.AttributeName ?? "Floor"}_" +
|
||
$"{GetItemsByDepthUnified(config.MaxDepth).Count}";
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成智能遍历专用的缓存键 - 区别于原有的预收集模式
|
||
/// </summary>
|
||
private string GenerateSmartTraversalCacheKey(SplitConfiguration config)
|
||
{
|
||
// 智能遍历的缓存键包含特殊标识,避免与原有缓存冲突
|
||
return $"SmartTraversal_{config.Strategy}_{config.MaxDepth}_{config.AttributeName ?? "Default"}_{DateTime.Now:yyyyMMdd}";
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 创建分层策略实例
|
||
/// </summary>
|
||
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}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 从缓存获取结果
|
||
/// </summary>
|
||
private List<SplitPreviewResult> GetFromCache(SplitStrategy strategy, string cacheKey)
|
||
{
|
||
lock (_cacheLock)
|
||
{
|
||
// 只支持楼层缓存和自定义楼层缓存
|
||
var cache = _floorCache;
|
||
return cache.ContainsKey(cacheKey) ? cache[cacheKey] : null;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 保存结果到缓存
|
||
/// </summary>
|
||
private void SaveToCache(SplitStrategy strategy, string cacheKey, List<SplitPreviewResult> results)
|
||
{
|
||
lock (_cacheLock)
|
||
{
|
||
// 只支持楼层缓存和自定义楼层缓存
|
||
var cache = _floorCache;
|
||
cache[cacheKey] = results;
|
||
LogManager.Info($"[SimplifiedModelSplitter] 结果已缓存: {strategy}, 键: {cacheKey}, 数量: {results.Count}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 执行分层保存(异步,简化版本)
|
||
/// </summary>
|
||
public async Task ExecuteSplitAsync(SplitConfiguration config, CancellationToken cancellationToken = default)
|
||
{
|
||
try
|
||
{
|
||
LogManager.Info($"[SimplifiedModelSplitter] 开始执行分层,策略: {config.Strategy}");
|
||
OnStatusChanged("正在准备分层...");
|
||
|
||
// 优先从缓存获取分层结果,避免重复检测
|
||
string cacheKey = GenerateCacheKey(config);
|
||
var previewResults = GetFromCache(config.Strategy, cacheKey);
|
||
|
||
if (previewResults == null || previewResults.Count == 0)
|
||
{
|
||
LogManager.Info($"[SimplifiedModelSplitter] 缓存中没有结果,重新预览分层");
|
||
previewResults = PreviewSplit(config);
|
||
if (previewResults.Count == 0)
|
||
{
|
||
throw new InvalidOperationException("没有可分层的内容");
|
||
}
|
||
}
|
||
else
|
||
{
|
||
LogManager.Info($"[SimplifiedModelSplitter] 使用缓存的分层结果,共 {previewResults.Count} 个分层");
|
||
}
|
||
|
||
// 过滤出需要保存的分层
|
||
var layersToSave = previewResults.Where(p => p.IsSelectedForSave).ToList();
|
||
if (layersToSave.Count == 0)
|
||
{
|
||
LogManager.Warning("[SimplifiedModelSplitter] 没有选中任何分层进行保存");
|
||
OnStatusChanged("没有选中任何分层进行保存");
|
||
return;
|
||
}
|
||
|
||
LogManager.Info($"[SimplifiedModelSplitter] 将保存 {layersToSave.Count}/{previewResults.Count} 个选中的分层");
|
||
|
||
// 确保输出目录存在
|
||
EnsureOutputDirectory(config.OutputDirectory);
|
||
|
||
// 逐个处理分层,增强错误处理
|
||
int successCount = 0;
|
||
var failedLayers = new List<string>();
|
||
|
||
for (int i = 0; i < layersToSave.Count; i++)
|
||
{
|
||
if (cancellationToken.IsCancellationRequested)
|
||
{
|
||
LogManager.Info($"[SimplifiedModelSplitter] 用户取消分层操作,已处理 {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);
|
||
successCount++;
|
||
LogManager.Info($"[SimplifiedModelSplitter] 分层 {preview.LayerName} 处理成功 ({successCount}/{layersToSave.Count})");
|
||
}
|
||
catch (Exception layerEx)
|
||
{
|
||
string errorMsg = $"分层 {preview.LayerName} 处理失败: {layerEx.Message}";
|
||
LogManager.Error($"[SimplifiedModelSplitter] {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($"[SimplifiedModelSplitter] {finalMessage}");
|
||
}
|
||
else
|
||
{
|
||
LogManager.Info($"[SimplifiedModelSplitter] {finalMessage}");
|
||
}
|
||
|
||
OnStatusChanged(finalMessage);
|
||
|
||
// 如果所有分层都失败,抛出异常
|
||
if (successCount == 0 && layersToSave.Count > 0)
|
||
{
|
||
throw new InvalidOperationException($"所有选中的分层处理都失败了,共 {layersToSave.Count} 个分层");
|
||
}
|
||
|
||
LogManager.Info($"[SimplifiedModelSplitter] 分层执行完成:成功 {successCount}/{layersToSave.Count}");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"[SimplifiedModelSplitter] 分层执行失败: {ex.Message}");
|
||
OnStatusChanged($"分层失败: {ex.Message}");
|
||
throw;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 执行分层保存(同步版本,用于UI线程调用)
|
||
/// </summary>
|
||
public void ExecuteSplit(SplitConfiguration config)
|
||
{
|
||
try
|
||
{
|
||
LogManager.Info($"[SimplifiedModelSplitter] 开始执行分层,策略: {config.Strategy}");
|
||
OnStatusChanged("正在准备分层...");
|
||
|
||
// 优先从缓存获取分层结果,避免重复检测
|
||
string cacheKey = GenerateCacheKey(config);
|
||
var previewResults = GetFromCache(config.Strategy, cacheKey);
|
||
|
||
if (previewResults == null || previewResults.Count == 0)
|
||
{
|
||
LogManager.Info($"[SimplifiedModelSplitter] 缓存中没有结果,重新预览分层");
|
||
previewResults = PreviewSplit(config);
|
||
if (previewResults.Count == 0)
|
||
{
|
||
throw new InvalidOperationException("没有可分层的内容");
|
||
}
|
||
}
|
||
else
|
||
{
|
||
LogManager.Info($"[SimplifiedModelSplitter] 使用缓存的分层结果,共 {previewResults.Count} 个分层");
|
||
}
|
||
|
||
// 过滤出需要保存的分层
|
||
var layersToSave = previewResults.Where(p => p.IsSelectedForSave).ToList();
|
||
if (layersToSave.Count == 0)
|
||
{
|
||
LogManager.Warning("[SimplifiedModelSplitter] 没有选中任何分层进行保存");
|
||
OnStatusChanged("没有选中任何分层进行保存");
|
||
return;
|
||
}
|
||
|
||
LogManager.Info($"[SimplifiedModelSplitter] 将保存 {layersToSave.Count}/{previewResults.Count} 个选中的分层");
|
||
|
||
// 确保输出目录存在
|
||
EnsureOutputDirectory(config.OutputDirectory);
|
||
|
||
// 逐个处理分层,增强错误处理(同步版本)
|
||
int successCount = 0;
|
||
var failedLayers = new List<string>();
|
||
|
||
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);
|
||
successCount++;
|
||
LogManager.Info($"[SimplifiedModelSplitter] 分层 {preview.LayerName} 处理成功 ({successCount}/{layersToSave.Count})");
|
||
}
|
||
catch (Exception layerEx)
|
||
{
|
||
string errorMsg = $"分层 {preview.LayerName} 处理失败: {layerEx.Message}";
|
||
LogManager.Error($"[SimplifiedModelSplitter] {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($"[SimplifiedModelSplitter] {finalMessage}");
|
||
}
|
||
else
|
||
{
|
||
LogManager.Info($"[SimplifiedModelSplitter] {finalMessage}");
|
||
}
|
||
|
||
OnStatusChanged(finalMessage);
|
||
|
||
// 如果所有分层都失败,抛出异常
|
||
if (successCount == 0 && layersToSave.Count > 0)
|
||
{
|
||
throw new InvalidOperationException($"所有选中的分层处理都失败了,共 {layersToSave.Count} 个分层");
|
||
}
|
||
|
||
LogManager.Info($"[SimplifiedModelSplitter] 分层执行完成:成功 {successCount}/{layersToSave.Count}");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"[SimplifiedModelSplitter] 分层执行失败: {ex.Message}");
|
||
OnStatusChanged($"分层失败: {ex.Message}");
|
||
throw;
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 私有方法
|
||
|
||
/// <summary>
|
||
/// 统一的深度遍历核心函数 - 精确控制深度逻辑
|
||
/// </summary>
|
||
/// <param name="maxDepth">最大深度,1=仅第一级,2=到第二级,3=到第三级,4=到第四级,5=到第五级,0=所有级别</param>
|
||
/// <returns>按深度筛选的模型项集合</returns>
|
||
private ModelItemCollection GetItemsByDepthUnified(int maxDepth)
|
||
{
|
||
try
|
||
{
|
||
LogManager.Info($"[SimplifiedModelSplitter] ===== 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($"[SimplifiedModelSplitter] 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($"[SimplifiedModelSplitter] ===== GetItemsByDepthUnified完成 ===== 返回{result.Count}个模型项(深度:{maxDepth}级)");
|
||
return result;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"[SimplifiedModelSplitter] GetItemsByDepthUnified异常: {ex.Message}");
|
||
return new ModelItemCollection();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 递归添加子节点到指定深度
|
||
/// </summary>
|
||
/// <param name="parentItem">父节点</param>
|
||
/// <param name="result">结果集合</param>
|
||
/// <param name="currentDepth">当前深度</param>
|
||
/// <param name="maxDepth">最大深度</param>
|
||
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);
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取所有模型元素(支持深度限制)- 使用统一的深度遍历函数
|
||
/// </summary>
|
||
private ModelItemCollection GetAllModelItems(int maxDepth = 1)
|
||
{
|
||
return GetItemsByDepthUnified(maxDepth);
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 通用属性预览分层方法(基于分组策略模式)
|
||
/// </summary>
|
||
private List<SplitPreviewResult> PreviewSplitByAttribute(ModelItemCollection items, SplitConfiguration config, IGroupingStrategy strategy)
|
||
{
|
||
var results = new List<SplitPreviewResult>();
|
||
|
||
try
|
||
{
|
||
// 属性分组阶段 (35-70%)
|
||
OnProgressChanged(new ProgressChangedEventArgs(40, $"正在分析 {items.Count} 个模型元素的{strategy.GroupTypeName}信息"));
|
||
|
||
var groups = strategy.GroupItems(items, config);
|
||
LogManager.Info($"[SimplifiedModelSplitter] {strategy.GroupTypeName}属性检测完成,发现 {groups?.Count ?? 0} 个{strategy.GroupTypeName}分组");
|
||
|
||
OnProgressChanged(new ProgressChangedEventArgs(70, $"{strategy.GroupTypeName}分组完成,发现 {groups?.Count ?? 0} 个{strategy.GroupTypeName}"));
|
||
|
||
if (groups != null && groups.Count > 0)
|
||
{
|
||
// 生成预览结果阶段 (70-85%)
|
||
OnProgressChanged(new ProgressChangedEventArgs(75, $"正在生成{strategy.GroupTypeName}预览结果"));
|
||
|
||
int processedGroups = 0;
|
||
foreach (var group in groups.Values)
|
||
{
|
||
var previewResult = new SplitPreviewResult
|
||
{
|
||
LayerName = SanitizeLayerName(group.GroupName),
|
||
LayerAttribute = GetAttributeDescription(config.Strategy, group.GroupName, group.Metadata),
|
||
Items = new ModelItemCollection()
|
||
};
|
||
|
||
// 添加模型项到集合中
|
||
if (group.Items != null && group.Items.Count > 0)
|
||
{
|
||
previewResult.Items.AddRange(group.Items);
|
||
LogManager.Info($"[SimplifiedModelSplitter] {strategy.GroupTypeName}预览结果已缓存模型项: {strategy.GroupTypeName}='{previewResult.LayerName}', 模型项数量={previewResult.Items.Count}");
|
||
}
|
||
else
|
||
{
|
||
LogManager.Warning($"[SimplifiedModelSplitter] {strategy.GroupTypeName}预览结果没有模型项: {strategy.GroupTypeName}='{previewResult.LayerName}'");
|
||
}
|
||
|
||
// 添加元数据
|
||
previewResult.Metadata["Original" + strategy.GroupTypeName + "Name"] = group.OriginalName;
|
||
previewResult.Metadata[strategy.GroupTypeName + "Name"] = group.GroupName;
|
||
previewResult.Metadata["MaxDepth"] = config.MaxDepth;
|
||
|
||
// 复制分组的自定义元数据
|
||
foreach (var meta in group.Metadata)
|
||
{
|
||
previewResult.Metadata[meta.Key] = meta.Value;
|
||
}
|
||
|
||
results.Add(previewResult);
|
||
|
||
// 更新进度
|
||
processedGroups++;
|
||
int progressPercent = 75 + (processedGroups * 10 / groups.Count);
|
||
OnProgressChanged(new ProgressChangedEventArgs(progressPercent,
|
||
$"已处理 {processedGroups}/{groups.Count} 个{strategy.GroupTypeName}分组"));
|
||
}
|
||
|
||
OnProgressChanged(new ProgressChangedEventArgs(85, $"{strategy.GroupTypeName}预览结果生成完成,共 {results.Count} 个分层"));
|
||
}
|
||
else
|
||
{
|
||
OnProgressChanged(new ProgressChangedEventArgs(85, $"未检测到{strategy.GroupTypeName}信息"));
|
||
LogManager.Warning($"[SimplifiedModelSplitter] 未检测到任何{strategy.GroupTypeName}信息");
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"[SimplifiedModelSplitter] 按{strategy.GroupTypeName}属性预览失败: {ex.Message}", ex);
|
||
OnProgressChanged(new ProgressChangedEventArgs(35, $"{strategy.GroupTypeName}分析失败: {ex.Message}"));
|
||
throw;
|
||
}
|
||
|
||
return results;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 智能遍历分层预览 - 边遍历边检查边停止的新算法
|
||
/// 替代原有的预收集模式,大幅提升预览性能
|
||
/// </summary>
|
||
private List<SplitPreviewResult> PreviewSplitWithSmartTraversal(SplitConfiguration config, IGroupingStrategy strategy)
|
||
{
|
||
var results = new List<SplitPreviewResult>();
|
||
|
||
try
|
||
{
|
||
LogManager.Info($"[SimplifiedModelSplitter] ========== 开始智能遍历分层预览 ==========");
|
||
LogManager.Info($"[SimplifiedModelSplitter] 策略: {strategy.GroupTypeName}, 深度限制: {config.MaxDepth}");
|
||
|
||
var document = NavisApplication.ActiveDocument;
|
||
if (document?.Models?.Count == 0)
|
||
{
|
||
LogManager.Warning("[SimplifiedModelSplitter] 当前文档没有模型");
|
||
return results;
|
||
}
|
||
|
||
// 从每个模型的一级节点开始智能遍历
|
||
int processedTopNodes = 0;
|
||
foreach (Model model in document.Models)
|
||
{
|
||
if (model.RootItem?.Children != null)
|
||
{
|
||
foreach (ModelItem rootChild in model.RootItem.Children)
|
||
{
|
||
processedTopNodes++;
|
||
TraverseAndRecord(rootChild, strategy, config, results, 1);
|
||
|
||
// 每处理10个顶级节点记录一次进度
|
||
if (processedTopNodes % 10 == 0)
|
||
{
|
||
LogManager.Info($"[SimplifiedModelSplitter] 已处理 {processedTopNodes} 个顶级节点,找到 {results.Count} 个分层");
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
LogManager.Info($"[SimplifiedModelSplitter] ========== 智能遍历完成 ==========");
|
||
LogManager.Info($"[SimplifiedModelSplitter] 处理了 {processedTopNodes} 个顶级节点,识别到 {results.Count} 个{strategy.GroupTypeName}分层");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"[SimplifiedModelSplitter] 智能遍历失败: {ex.Message}", ex);
|
||
throw;
|
||
}
|
||
|
||
return results;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 递归遍历节点并记录分层结果的核心方法
|
||
/// </summary>
|
||
private void TraverseAndRecord(ModelItem node, IGroupingStrategy strategy,
|
||
SplitConfiguration config, List<SplitPreviewResult> results, 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($"[SimplifiedModelSplitter] 智能检测到属性类型: '{attributeName}', 值: '{attributeValue}'");
|
||
}
|
||
|
||
// 创建轻量化预览结果,停止该分支遍历
|
||
var layerResult = CreateLayerResult(layerValue, node, strategy.GroupTypeName, config.Strategy, detectedAttributeName);
|
||
results.Add(layerResult);
|
||
|
||
LogManager.Info($"[SimplifiedModelSplitter] 找到{strategy.GroupTypeName}分层: '{layerValue}' 于节点 '{node.DisplayName}' (深度{currentDepth})");
|
||
return; // 关键:停止遍历该分支
|
||
}
|
||
|
||
// 未找到分层属性且未达深度限制,继续遍历子节点
|
||
if (currentDepth < config.MaxDepth && node.Children != null)
|
||
{
|
||
foreach (ModelItem child in node.Children)
|
||
{
|
||
TraverseAndRecord(child, strategy, config, results, currentDepth + 1);
|
||
}
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Warning($"[SimplifiedModelSplitter] 遍历节点失败: {node?.DisplayName ?? "null"}, 错误: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建轻量化分层预览结果 - 只包含必要信息,不做统计计算
|
||
/// </summary>
|
||
/// <summary>
|
||
/// 创建轻量化分层预览结果 - 只包含必要信息,不做统计计算
|
||
/// </summary>
|
||
private SplitPreviewResult CreateLayerResult(string layerValue, ModelItem rootNode, string groupTypeName, SplitStrategy strategy, string detectedAttributeName = null)
|
||
{
|
||
var metadata = new Dictionary<string, object>
|
||
{
|
||
["LayerValue"] = layerValue,
|
||
["RootNodeReference"] = rootNode,
|
||
["GroupType"] = groupTypeName,
|
||
["TraversalMode"] = "SmartTraversal" // 标记使用智能遍历
|
||
};
|
||
|
||
// 如果检测到了具体的属性类型,保存到元数据中
|
||
if (!string.IsNullOrEmpty(detectedAttributeName))
|
||
{
|
||
metadata["DetectedAttributeName"] = detectedAttributeName;
|
||
}
|
||
|
||
return new SplitPreviewResult
|
||
{
|
||
LayerName = SanitizeLayerName(layerValue),
|
||
LayerAttribute = GetAttributeDescription(strategy, layerValue, metadata),
|
||
Items = new ModelItemCollection { rootNode }, // 只保存根节点引用
|
||
Metadata = metadata
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 处理单个分层(异步版本)
|
||
/// </summary>
|
||
private async Task ProcessSingleLayerAsync(SplitPreviewResult preview, SplitConfiguration config, CancellationToken cancellationToken)
|
||
{
|
||
try
|
||
{
|
||
LogManager.Info($"[SimplifiedModelSplitter] 开始处理分层: {preview.LayerName}, 类型: {preview.LayerAttribute}");
|
||
|
||
// 检查取消请求
|
||
cancellationToken.ThrowIfCancellationRequested();
|
||
|
||
// 生成输出文件路径(使用新的智能文件名格式)
|
||
string fileName = GenerateFileName(preview.LayerName, config.Strategy, config);
|
||
string outputPath = Path.Combine(config.OutputDirectory, fileName);
|
||
|
||
LogManager.Info($"[SimplifiedModelSplitter] 分层文件路径: {outputPath}");
|
||
|
||
// 直接在UI线程调用,不使用Task.Run包装
|
||
bool success = ExportLayerToNwd(preview, outputPath, config);
|
||
|
||
if (success)
|
||
{
|
||
LogManager.Info($"[SimplifiedModelSplitter] 分层 {preview.LayerName} 导出成功: {outputPath}");
|
||
}
|
||
else
|
||
{
|
||
LogManager.Error($"[SimplifiedModelSplitter] 分层 {preview.LayerName} 导出失败");
|
||
throw new InvalidOperationException($"分层 {preview.LayerName} 导出失败");
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"[SimplifiedModelSplitter] 处理分层失败 {preview.LayerName}: {ex.Message}");
|
||
throw;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 处理单个分层(同步版本)
|
||
/// </summary>
|
||
private void ProcessSingleLayer(SplitPreviewResult preview, SplitConfiguration config)
|
||
{
|
||
try
|
||
{
|
||
LogManager.Info($"[SimplifiedModelSplitter] 开始同步处理分层: {preview.LayerName}, 类型: {preview.LayerAttribute}");
|
||
|
||
if (preview.Items == null || preview.Items.Count == 0)
|
||
{
|
||
LogManager.Warning($"[SimplifiedModelSplitter] 分层 {preview.LayerName} 没有包含模型元素,跳过导出");
|
||
return;
|
||
}
|
||
|
||
// 生成输出文件路径(使用新的智能文件名格式)
|
||
string fileName = GenerateFileName(preview.LayerName, config.Strategy, config);
|
||
string outputPath = Path.Combine(config.OutputDirectory, fileName);
|
||
|
||
LogManager.Info($"[SimplifiedModelSplitter] 分层文件路径: {outputPath}");
|
||
|
||
// 检查模型项数量,对大量模型项进行特殊处理
|
||
if (preview.Items != null && preview.Items.Count > 100)
|
||
{
|
||
LogManager.Warning($"[SimplifiedModelSplitter] 大量模型项检测:{preview.Items.Count}个,可能需要更多内存和时间");
|
||
|
||
// 强制垃圾回收,释放内存
|
||
GC.Collect();
|
||
GC.WaitForPendingFinalizers();
|
||
GC.Collect();
|
||
|
||
LogManager.Info($"[SimplifiedModelSplitter] 垃圾回收完成,当前内存: {GC.GetTotalMemory(false) / 1024 / 1024} MB");
|
||
}
|
||
|
||
// 使用TryExportToNwd API导出分层
|
||
bool success = ExportLayerToNwd(preview, outputPath, config);
|
||
|
||
if (success)
|
||
{
|
||
LogManager.Info($"[SimplifiedModelSplitter] 分层 {preview.LayerName} 导出成功: {outputPath}");
|
||
}
|
||
else
|
||
{
|
||
LogManager.Error($"[SimplifiedModelSplitter] 分层 {preview.LayerName} 导出失败");
|
||
throw new InvalidOperationException($"分层 {preview.LayerName} 导出失败");
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"[SimplifiedModelSplitter] 同步处理分层失败 {preview.LayerName}: {ex.Message}");
|
||
throw;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 确保输出目录存在
|
||
/// </summary>
|
||
private void EnsureOutputDirectory(string directory)
|
||
{
|
||
if (string.IsNullOrEmpty(directory))
|
||
throw new ArgumentException("输出目录不能为空");
|
||
|
||
if (!Directory.Exists(directory))
|
||
{
|
||
Directory.CreateDirectory(directory);
|
||
LogManager.Info($"[SimplifiedModelSplitter] 创建输出目录: {directory}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 清理分层名称(支持中文字符)
|
||
/// </summary>
|
||
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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取分层策略的属性描述
|
||
/// </summary>
|
||
/// <summary>
|
||
/// 获取具体的分层属性描述(实际属性值而非策略描述)
|
||
/// </summary>
|
||
/// <param name="strategy">分层策略</param>
|
||
/// <param name="layerName">分层名称</param>
|
||
/// <param name="metadata">元数据,可能包含实际的属性信息</param>
|
||
private string GetAttributeDescription(SplitStrategy strategy, string layerName, Dictionary<string, object> 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; // 失败时返回分层名称
|
||
}
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 从分层名称推断属性类型(用于智能检测)
|
||
/// </summary>
|
||
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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 估算文件大小
|
||
/// </summary>
|
||
private long EstimateFileSize(int itemCount)
|
||
{
|
||
// 简化的文件大小估算:每个元素约 1KB
|
||
return itemCount * 1024L;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成文件名 - 新的智能格式:根节点名称_分层属性_属性值_时间戳.nwd
|
||
/// </summary>
|
||
/// <param name="attributeValue">属性值(分层名称)</param>
|
||
/// <param name="strategy">分层策略</param>
|
||
/// <param name="config">配置信息</param>
|
||
/// <returns>文件名(不包括路径)</returns>
|
||
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($"[SimplifiedModelSplitter] 生成智能文件名: {fileName}");
|
||
LogManager.Info($"[SimplifiedModelSplitter] 文件名组成: 根节点='{rootNodeName}', 属性类型='{attributeTypeName}', 属性值='{sanitizedAttributeValue}', 时间戳='{timestamp}'");
|
||
|
||
return fileName;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"[SimplifiedModelSplitter] 生成智能文件名失败: {ex.Message}");
|
||
// 失败时使用后备命名方式
|
||
string fallbackName = $"NavisworksModel_分层_{SanitizeLayerName(attributeValue)}_{DateTime.Now:yyyyMMdd_HHmmss}.nwd";
|
||
LogManager.Warning($"[SimplifiedModelSplitter] 使用后备文件名: {fallbackName}");
|
||
return fallbackName;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成文件名(旧版本兼容性方法)
|
||
/// </summary>
|
||
/// <param name="layerName">分层名称</param>
|
||
/// <param name="config">配置信息</param>
|
||
/// <returns>文件名(不包括路径)</returns>
|
||
private string GenerateFileName(string layerName, SplitConfiguration config)
|
||
{
|
||
// 使用默认策略调用新版本方法
|
||
return GenerateFileName(layerName, config.Strategy, config);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取根节点名称 - 新的智能文件名格式使用
|
||
/// 逻辑:文档文件名 → 第一个模型根项DisplayName → "NavisworksModel"
|
||
/// </summary>
|
||
/// <returns>根节点名称</returns>
|
||
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($"[SimplifiedModelSplitter] 获取根节点名称失败: {ex.Message}");
|
||
return "NavisworksModel";
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取当前项目名称(保留兼容性)
|
||
/// </summary>
|
||
/// <returns>项目名称</returns>
|
||
private string GetCurrentProjectName()
|
||
{
|
||
return GetRootNodeName(); // 直接使用新的根节点名称方法
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取分层属性类型名称
|
||
/// </summary>
|
||
/// <param name="strategy">分层策略</param>
|
||
/// <returns>属性类型名称</returns>
|
||
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 "分层";
|
||
}
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 检查输出目录中是否存在同名文件并生成唯一文件名
|
||
/// </summary>
|
||
/// <param name="originalFileName">原始文件名</param>
|
||
/// <param name="outputDirectory">输出目录</param>
|
||
/// <returns>唯一的文件名</returns>
|
||
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($"[SimplifiedModelSplitter] 文件名冲突,重命名为: {newFileName}");
|
||
return newFileName;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Warning($"[SimplifiedModelSplitter] 检查文件名唯一性失败: {ex.Message}");
|
||
return originalFileName;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 使用正确的Navisworks API导出单个分层 - 基于示例中的最佳实践
|
||
/// </summary>
|
||
public bool ExportLayerToNwd(SplitPreviewResult preview, string outputPath, SplitConfiguration config)
|
||
{
|
||
if (preview == null)
|
||
{
|
||
LogManager.Error($"[SimplifiedModelSplitter] 预览结果为null");
|
||
return false;
|
||
}
|
||
|
||
try
|
||
{
|
||
LogManager.Info($"[SimplifiedModelSplitter] ========== ExportLayerToNwd开始 ==========");
|
||
LogManager.Info($"[SimplifiedModelSplitter] 导出层: {preview.LayerName}");
|
||
LogManager.Info($"[SimplifiedModelSplitter] 预览项数量: {preview.Items?.Count ?? 0}");
|
||
LogManager.Info($"[SimplifiedModelSplitter] 输出路径: {outputPath}");
|
||
|
||
// 直接使用预览结果中的项目
|
||
if (preview.Items == null || preview.Items.Count == 0)
|
||
{
|
||
LogManager.Warning($"[SimplifiedModelSplitter] 预览结果中没有模型项");
|
||
return false;
|
||
}
|
||
|
||
var itemsToExport = preview.Items;
|
||
LogManager.Info($"[SimplifiedModelSplitter] 将导出 {itemsToExport.Count} 个模型项");
|
||
|
||
// 检查线程状态
|
||
var apartmentState = System.Threading.Thread.CurrentThread.GetApartmentState();
|
||
LogManager.Info($"[SimplifiedModelSplitter] 当前线程状态: {apartmentState}");
|
||
|
||
// 核心修复:确保在主 UI 线程中执行 Navisworks API 调用
|
||
bool exportResult = false;
|
||
Exception exportException = null;
|
||
|
||
// 使用 Application.Current.Dispatcher.Invoke 确保在主线程中执行
|
||
System.Windows.Application.Current.Dispatcher.Invoke(() =>
|
||
{
|
||
try
|
||
{
|
||
LogManager.Info($"[SimplifiedModelSplitter] 在主线程中执行导出操作");
|
||
var document = NavisApplication.ActiveDocument;
|
||
|
||
// 保存当前可见性状态(在主线程中)
|
||
LogManager.Info($"[SimplifiedModelSplitter] 开始保存当前可见性状态");
|
||
var originalVisibilityState = SaveCurrentVisibilityState(document);
|
||
LogManager.Info($"[SimplifiedModelSplitter] 已保存 {originalVisibilityState.Count} 个项目的可见性状态");
|
||
|
||
try
|
||
{
|
||
// 采用智能隐藏策略:只操作顶级节点,避免遍历所有项目
|
||
var allTopLevelItems = new List<ModelItem>();
|
||
|
||
// 只获取顶级节点,不遍历全部项目
|
||
foreach (Model model in document.Models)
|
||
{
|
||
foreach (ModelItem topLevelItem in model.RootItem.Children)
|
||
{
|
||
allTopLevelItems.Add(topLevelItem);
|
||
}
|
||
}
|
||
|
||
LogManager.Info($"[SimplifiedModelSplitter] 收集到 {allTopLevelItems.Count} 个顶级节点");
|
||
|
||
// 智能隐藏策略:如果顶级节点包含要导出的项目,则保持可见;否则隐藏整个顶级分支
|
||
var itemsToHide = new ModelItemCollection();
|
||
int hiddenCount = 0;
|
||
|
||
foreach (ModelItem topLevelItem in allTopLevelItems)
|
||
{
|
||
bool shouldKeepTopLevel = false;
|
||
|
||
// 检查这个顶级节点本身是否在导出列表中
|
||
foreach (ModelItem exportItem in itemsToExport)
|
||
{
|
||
if (topLevelItem.Equals(exportItem))
|
||
{
|
||
shouldKeepTopLevel = true;
|
||
LogManager.Info($"[SimplifiedModelSplitter] 顶级节点 {topLevelItem.DisplayName} 本身被选中,保持可见");
|
||
break;
|
||
}
|
||
}
|
||
|
||
// 如果顶级节点本身不在导出列表中,检查是否有任何导出项是它的后代
|
||
if (!shouldKeepTopLevel)
|
||
{
|
||
foreach (var exportItem in itemsToExport)
|
||
{
|
||
var current = exportItem;
|
||
while (current != null)
|
||
{
|
||
if (current == topLevelItem)
|
||
{
|
||
shouldKeepTopLevel = true;
|
||
LogManager.Info($"[SimplifiedModelSplitter] 顶级节点 {topLevelItem.DisplayName} 包含导出项目,保持可见");
|
||
break;
|
||
}
|
||
current = current.Parent;
|
||
}
|
||
if (shouldKeepTopLevel) break;
|
||
}
|
||
}
|
||
|
||
// 如果这个顶级节点不需要保持可见,则隐藏它
|
||
if (!shouldKeepTopLevel)
|
||
{
|
||
try
|
||
{
|
||
itemsToHide.Add(topLevelItem);
|
||
hiddenCount++;
|
||
LogManager.Info($"[SimplifiedModelSplitter] 隐藏顶级节点: {topLevelItem.DisplayName}");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Warning($"[SimplifiedModelSplitter] 添加隐藏项目失败: {topLevelItem.DisplayName} - {ex.Message}");
|
||
}
|
||
}
|
||
}
|
||
|
||
// 执行隐藏操作
|
||
if (itemsToHide.Count > 0)
|
||
{
|
||
try
|
||
{
|
||
document.Models.SetHidden(itemsToHide, true);
|
||
LogManager.Info($"[SimplifiedModelSplitter] 成功隐藏 {hiddenCount} 个顶级节点,保留导出项目可见");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Warning($"[SimplifiedModelSplitter] 隐藏操作失败: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
// 创建导出选项
|
||
var exportOptions = new Autodesk.Navisworks.Api.NwdExportOptions
|
||
{
|
||
ExcludeHiddenItems = true, // 只导出可见项目
|
||
EmbedXrefs = false,
|
||
PreventObjectPropertyExport = false
|
||
};
|
||
|
||
LogManager.Info($"[SimplifiedModelSplitter] 开始调用ExportToNwd API(主线程)");
|
||
|
||
// 在主线程中执行导出
|
||
document.ExportToNwd(outputPath, exportOptions);
|
||
|
||
LogManager.Info($"[SimplifiedModelSplitter] ExportToNwd API调用完成(主线程)");
|
||
exportResult = true;
|
||
}
|
||
finally
|
||
{
|
||
// 恢复原始可见性状态(在主线程中)
|
||
try
|
||
{
|
||
RestoreVisibilityState(document, originalVisibilityState);
|
||
LogManager.Info($"[SimplifiedModelSplitter] 已恢复原始可见性状态");
|
||
}
|
||
catch (Exception restoreEx)
|
||
{
|
||
LogManager.Error($"[SimplifiedModelSplitter] 恢复可见性失败: {restoreEx.Message}");
|
||
}
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
exportException = ex;
|
||
}
|
||
});
|
||
|
||
// 检查导出结果
|
||
if (exportException != null)
|
||
{
|
||
LogManager.Error($"[SimplifiedModelSplitter] 主线程导出异常: {exportException.Message}");
|
||
LogManager.Error($"[SimplifiedModelSplitter] 异常堆栈: {exportException.StackTrace}");
|
||
return false;
|
||
}
|
||
|
||
LogManager.Info($"[SimplifiedModelSplitter] ========== ExportLayerToNwd完成 ========== 成功导出到: {outputPath}");
|
||
return exportResult;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"[SimplifiedModelSplitter] ExportLayerToNwd异常: {ex.Message}");
|
||
LogManager.Error($"[SimplifiedModelSplitter] 异常堆栈: {ex.StackTrace}");
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 保存当前可见性状态(参考"保存当前选择项"的方法)
|
||
/// </summary>
|
||
private Dictionary<ModelItem, bool> SaveCurrentVisibilityState(Document document)
|
||
{
|
||
var visibilityState = new Dictionary<ModelItem, bool>();
|
||
|
||
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($"[SimplifiedModelSplitter] 保存可见性状态完成,记录了 {visibilityState.Count} 个顶级项目");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"[SimplifiedModelSplitter] 保存可见性状态失败: {ex.Message}");
|
||
}
|
||
|
||
return visibilityState;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取分层对应的顶级层节点(不展开子节点)
|
||
/// 根据API指南,我们应该选择顶级节点,让ExportToNwd自动处理其子树
|
||
/// </summary>
|
||
|
||
/// <summary>
|
||
/// 检查一个节点是否是顶级节点
|
||
/// </summary>
|
||
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;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 查找一个节点的顶级父节点
|
||
/// </summary>
|
||
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;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 递归收集楼层顶层节点下的所有子节点
|
||
/// </summary>
|
||
/// <param name="floorTopLevelItems">楼层顶层节点集合</param>
|
||
/// <returns>包含所有子节点的完整模型项集合</returns>
|
||
private ModelItemCollection ExpandFloorItems(ModelItemCollection floorTopLevelItems)
|
||
{
|
||
try
|
||
{
|
||
LogManager.Info($"[SimplifiedModelSplitter] ========== ExpandFloorItems开始 ==========");
|
||
LogManager.Info($"[SimplifiedModelSplitter] 输入顶层节点数量: {floorTopLevelItems.Count}");
|
||
|
||
var expandedItems = new ModelItemCollection();
|
||
int totalCollected = 0;
|
||
|
||
foreach (ModelItem topLevelItem in floorTopLevelItems)
|
||
{
|
||
try
|
||
{
|
||
LogManager.Info($"[SimplifiedModelSplitter] 开始展开顶层节点: '{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($"[SimplifiedModelSplitter] 顶层节点 '{topLevelItem.DisplayName}' 展开完成: 收集到{childItems.Count}个子项,有效{validChildItems.Count}个");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Warning($"[SimplifiedModelSplitter] 展开顶层节点失败: {topLevelItem?.DisplayName ?? "null"}, 错误: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
LogManager.Info($"[SimplifiedModelSplitter] ========== ExpandFloorItems完成 ========== 总计收集: {totalCollected}个模型项");
|
||
return expandedItems;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"[SimplifiedModelSplitter] ExpandFloorItems异常: {ex.Message}");
|
||
LogManager.Error($"[SimplifiedModelSplitter] 异常堆栈: {ex.StackTrace}");
|
||
return new ModelItemCollection();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 递归收集模型项的所有子项
|
||
/// </summary>
|
||
/// <param name="parentItem">父级模型项</param>
|
||
/// <param name="currentDepth">当前递归深度</param>
|
||
/// <param name="maxDepth">最大递归深度</param>
|
||
/// <returns>所有子项的集合</returns>
|
||
private ModelItemCollection CollectAllChildItems(ModelItem parentItem, int currentDepth, int maxDepth)
|
||
{
|
||
var childItems = new ModelItemCollection();
|
||
|
||
try
|
||
{
|
||
// 防止递归过深
|
||
if (currentDepth >= maxDepth)
|
||
{
|
||
LogManager.Warning($"[SimplifiedModelSplitter] 达到最大递归深度 {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($"[SimplifiedModelSplitter] 已收集 {childItems.Count} 个子项...");
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Warning($"[SimplifiedModelSplitter] 收集子项失败: {child?.DisplayName ?? "null"}, 错误: {ex.Message}");
|
||
}
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"[SimplifiedModelSplitter] CollectAllChildItems异常: {ex.Message}");
|
||
}
|
||
|
||
return childItems;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 验证模型项集合的有效性,过滤掉无效的模型项
|
||
/// </summary>
|
||
/// <param name="items">要验证的模型项集合</param>
|
||
/// <returns>有效的模型项集合</returns>
|
||
private ModelItemCollection ValidateModelItems(ModelItemCollection items)
|
||
{
|
||
var validItems = new ModelItemCollection();
|
||
int nullCount = 0;
|
||
int invalidCount = 0;
|
||
|
||
try
|
||
{
|
||
LogManager.Info($"[SimplifiedModelSplitter] 开始验证 {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($"[SimplifiedModelSplitter] 发现无效模型项: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
LogManager.Info($"[SimplifiedModelSplitter] 模型项验证完成: 总数{items.Count}, 有效{validItems.Count}, 空项{nullCount}, 无效{invalidCount}");
|
||
|
||
return validItems;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"[SimplifiedModelSplitter] 验证模型项时发生异常: {ex.Message}");
|
||
// 异常时返回原始集合,避免完全失败
|
||
return items;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 判断模型项是否是实际的构件(而不是组织结构节点)
|
||
/// </summary>
|
||
/// <param name="item">模型项</param>
|
||
/// <returns>如果是实际构件返回true</returns>
|
||
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($"[SimplifiedModelSplitter] 判断构件类型失败: {ex.Message}");
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取指定楼层的模型项
|
||
/// </summary>
|
||
private ModelItemCollection GetFloorItems(ModelItemCollection allItems, string floorName, int maxDepth)
|
||
{
|
||
var floorItems = new ModelItemCollection();
|
||
|
||
try
|
||
{
|
||
LogManager.Info($"[SimplifiedModelSplitter] ===== GetFloorItems开始 =====");
|
||
LogManager.Info($"[SimplifiedModelSplitter] 目标楼层名称: '{floorName}'");
|
||
LogManager.Info($"[SimplifiedModelSplitter] 输入模型项数: {allItems.Count}");
|
||
|
||
int checkedCount = 0;
|
||
int matchedCount = 0;
|
||
|
||
// 这里需要实现根据楼层名称筛选模型项的逻辑
|
||
// 暂时使用简化实现:遍历所有项目,检查其属性是否匹配楼层名称
|
||
foreach (ModelItem item in allItems)
|
||
{
|
||
try
|
||
{
|
||
checkedCount++;
|
||
|
||
// 检查项目的楼层属性
|
||
bool hasMatch = HasFloorAttribute(item, floorName);
|
||
|
||
if (hasMatch)
|
||
{
|
||
floorItems.Add(item);
|
||
matchedCount++;
|
||
|
||
if (matchedCount <= 5) // 只记录前5个匹配的详细信息
|
||
{
|
||
LogManager.Info($"[SimplifiedModelSplitter] 找到匹配模型项 #{matchedCount}: {item.DisplayName}");
|
||
}
|
||
}
|
||
|
||
// 每处理1000个项记录进度
|
||
if (checkedCount % 1000 == 0)
|
||
{
|
||
LogManager.Info($"[SimplifiedModelSplitter] 已检查 {checkedCount}/{allItems.Count} 个模型项,找到 {matchedCount} 个匹配");
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Warning($"[SimplifiedModelSplitter] 检查模型项楼层属性时出错: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
LogManager.Info($"[SimplifiedModelSplitter] ===== GetFloorItems完成 ===== 检查了 {checkedCount} 个模型项,找到 {matchedCount} 个匹配的楼层项目");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"[SimplifiedModelSplitter] 获取楼层项目失败: {ex.Message}");
|
||
}
|
||
|
||
return floorItems;
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 检查模型项是否具有指定的楼层属性
|
||
/// </summary>
|
||
private bool HasFloorAttribute(ModelItem item, string floorName)
|
||
{
|
||
try
|
||
{
|
||
// 检查常见的楼层属性名称
|
||
string[] floorAttributeNames = { "Level", "Floor", "楼层", "层", "Story", "Storey" };
|
||
|
||
var categories = item.PropertyCategories;
|
||
if (categories != null)
|
||
{
|
||
foreach (PropertyCategory category in categories)
|
||
{
|
||
var properties = category.Properties;
|
||
if (properties != null)
|
||
{
|
||
foreach (DataProperty property in properties)
|
||
{
|
||
if (floorAttributeNames.Any(attr =>
|
||
property.DisplayName.IndexOf(attr, StringComparison.OrdinalIgnoreCase) >= 0))
|
||
{
|
||
string propValue = property.Value?.ToString() ?? "";
|
||
bool isMatch = propValue.IndexOf(floorName, StringComparison.OrdinalIgnoreCase) >= 0;
|
||
|
||
// 详细调试日志 - 当找到楼层相关属性时
|
||
if (!string.IsNullOrEmpty(propValue))
|
||
{
|
||
LogManager.Info($"[SimplifiedModelSplitter] 楼层属性检查: 项目='{item.DisplayName}', 属性='{property.DisplayName}', 值='{propValue}', 目标='{floorName}', 匹配={isMatch}");
|
||
}
|
||
|
||
if (isMatch)
|
||
{
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Warning($"[SimplifiedModelSplitter] 检查楼层属性时出错: {ex.Message}");
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 检查模型项是否具有指定的属性值
|
||
/// </summary>
|
||
private bool HasAttributeValue(ModelItem item, string attributeName, string targetValue)
|
||
{
|
||
try
|
||
{
|
||
var categories = item.PropertyCategories;
|
||
if (categories != null)
|
||
{
|
||
foreach (PropertyCategory category in categories)
|
||
{
|
||
var properties = category.Properties;
|
||
if (properties != null)
|
||
{
|
||
foreach (DataProperty property in properties)
|
||
{
|
||
if (property.DisplayName.Equals(attributeName, StringComparison.OrdinalIgnoreCase))
|
||
{
|
||
string propValue = property.Value?.ToString() ?? "";
|
||
return propValue.Equals(targetValue, StringComparison.OrdinalIgnoreCase);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Warning($"[SimplifiedModelSplitter] 检查属性值时出错: {ex.Message}");
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 恢复可见性状态
|
||
/// </summary>
|
||
private void RestoreVisibilityState(Document document, Dictionary<ModelItem, bool> 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($"[SimplifiedModelSplitter] 处理项目可见性状态时出错: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
// 首先重置所有项目为可见状态
|
||
document.Models.ResetAllHidden();
|
||
|
||
// 然后隐藏原来应该隐藏的项目
|
||
if (itemsToHide.Count > 0)
|
||
{
|
||
document.Models.SetHidden(itemsToHide, true);
|
||
LogManager.Info($"[SimplifiedModelSplitter] 恢复隐藏 {itemsToHide.Count} 个项目");
|
||
}
|
||
|
||
LogManager.Info("[SimplifiedModelSplitter] 可见性状态恢复完成");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"[SimplifiedModelSplitter] 恢复可见性状态失败: {ex.Message}");
|
||
// 失败时至少确保模型处于可见状态
|
||
try
|
||
{
|
||
document.Models.ResetAllHidden();
|
||
LogManager.Info("[SimplifiedModelSplitter] 已重置为全部可见状态");
|
||
}
|
||
catch (Exception resetEx)
|
||
{
|
||
LogManager.Error($"[SimplifiedModelSplitter] 重置可见性也失败: {resetEx.Message}");
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 简化的环境诊断方法 - 快速检查API是否可用
|
||
/// </summary>
|
||
/// <returns>诊断报告</returns>
|
||
public string DiagnoseEnvironment()
|
||
{
|
||
var report = new System.Text.StringBuilder();
|
||
report.AppendLine("=== Navisworks API环境诊断报告 ===");
|
||
|
||
try
|
||
{
|
||
// 1. 线程状态
|
||
var apartmentState = System.Threading.Thread.CurrentThread.GetApartmentState();
|
||
report.AppendLine($"线程状态: {apartmentState} {(apartmentState == System.Threading.ApartmentState.STA ? "✓" : "✗")}");
|
||
|
||
// 2. API可用性
|
||
try
|
||
{
|
||
var app = NavisApplication.ActiveDocument;
|
||
report.AppendLine("API可用性: 可用 ✓");
|
||
}
|
||
catch (Exception apiEx)
|
||
{
|
||
report.AppendLine($"API可用性: 异常 - {apiEx.Message} ✗");
|
||
}
|
||
|
||
// 3. 文档状态
|
||
try
|
||
{
|
||
var document = NavisApplication.ActiveDocument;
|
||
if (document != null)
|
||
{
|
||
report.AppendLine($"活动文档: {document.FileName ?? "未命名"} ✓");
|
||
report.AppendLine($"模型数量: {document.Models?.Count ?? 0}");
|
||
}
|
||
else
|
||
{
|
||
report.AppendLine("活动文档: 无 ✗");
|
||
}
|
||
}
|
||
catch (Exception docEx)
|
||
{
|
||
report.AppendLine($"活动文档: 异常 - {docEx.Message} ✗");
|
||
}
|
||
|
||
// 4. 内存状态
|
||
long memoryMB = GC.GetTotalMemory(false) / 1024 / 1024;
|
||
report.AppendLine($"当前内存: {memoryMB} MB");
|
||
|
||
report.AppendLine("=== 诊断完成 ===");
|
||
|
||
string result = report.ToString();
|
||
LogManager.Info($"[SimplifiedModelSplitter] 环境诊断报告:\n{result}");
|
||
return result;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
string error = $"诊断过程出错: {ex.Message}";
|
||
report.AppendLine(error);
|
||
LogManager.Error($"[SimplifiedModelSplitter] {error}");
|
||
return report.ToString();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试导出功能:导出少量模型项以验证基础功能
|
||
/// </summary>
|
||
/// <param name="outputPath">测试文件输出路径</param>
|
||
/// <param name="maxItems">最大测试项目数(默认5个)</param>
|
||
/// <returns>测试是否成功</returns>
|
||
public bool TestBasicExport(string outputPath, int maxItems = 5)
|
||
{
|
||
try
|
||
{
|
||
LogManager.Info($"[SimplifiedModelSplitter] ========== 开始基础导出测试 ==========");
|
||
LogManager.Info($"[SimplifiedModelSplitter] 测试文件路径: {outputPath}");
|
||
LogManager.Info($"[SimplifiedModelSplitter] 最大测试项目数: {maxItems}");
|
||
|
||
var document = NavisApplication.ActiveDocument;
|
||
if (document?.Models?.Count == 0)
|
||
{
|
||
LogManager.Error("[SimplifiedModelSplitter] 当前文档无效,无法进行测试");
|
||
return false;
|
||
}
|
||
|
||
// 获取少量模型项进行测试
|
||
var allItems = GetAllModelItems(1); // 只获取第一层
|
||
if (allItems.Count == 0)
|
||
{
|
||
LogManager.Error("[SimplifiedModelSplitter] 没有可用的模型项进行测试");
|
||
return false;
|
||
}
|
||
|
||
// 限制测试项目数量
|
||
var testItems = new ModelItemCollection();
|
||
int addedCount = 0;
|
||
foreach (ModelItem item in allItems)
|
||
{
|
||
if (addedCount >= maxItems) break;
|
||
|
||
try
|
||
{
|
||
// 验证项目有效性
|
||
string displayName = item.DisplayName;
|
||
testItems.Add(item);
|
||
addedCount++;
|
||
LogManager.Info($"[SimplifiedModelSplitter] 添加测试项目 #{addedCount}: {displayName}");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Warning($"[SimplifiedModelSplitter] 跳过无效测试项目: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
if (testItems.Count == 0)
|
||
{
|
||
LogManager.Error("[SimplifiedModelSplitter] 没有有效的测试项目");
|
||
return false;
|
||
}
|
||
|
||
LogManager.Info($"[SimplifiedModelSplitter] 准备测试导出 {testItems.Count} 个模型项");
|
||
|
||
// 确保输出目录存在
|
||
string directory = Path.GetDirectoryName(outputPath);
|
||
if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
|
||
{
|
||
Directory.CreateDirectory(directory);
|
||
LogManager.Info($"[SimplifiedModelSplitter] 创建测试输出目录: {directory}");
|
||
}
|
||
|
||
// 创建测试预览结果
|
||
var testPreview = new SplitPreviewResult
|
||
{
|
||
LayerName = "测试导出",
|
||
LayerAttribute = "测试",
|
||
Items = testItems
|
||
};
|
||
|
||
// 创建测试配置
|
||
var testConfig = new SplitConfiguration
|
||
{
|
||
Strategy = SplitStrategy.BySmartFloorDetection,
|
||
OutputDirectory = directory,
|
||
ExportOptions = new NwdExportUserOptions() // 使用默认选项
|
||
};
|
||
|
||
// 执行测试导出
|
||
bool testResult = ExportLayerToNwd(testPreview, outputPath, testConfig);
|
||
|
||
LogManager.Info($"[SimplifiedModelSplitter] ========== 基础导出测试完成 ========== 结果: {testResult}");
|
||
|
||
if (testResult && File.Exists(outputPath))
|
||
{
|
||
var fileInfo = new FileInfo(outputPath);
|
||
LogManager.Info($"[SimplifiedModelSplitter] 测试文件生成成功,大小: {fileInfo.Length / 1024} KB");
|
||
}
|
||
|
||
return testResult;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"[SimplifiedModelSplitter] 基础导出测试失败: {ex.Message}");
|
||
LogManager.Error($"[SimplifiedModelSplitter] 测试异常堆栈: {ex.StackTrace}");
|
||
return false;
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 辅助方法
|
||
|
||
/// <summary>
|
||
/// 获取策略的显示名称
|
||
/// </summary>
|
||
/// <param name="strategy">分层策略</param>
|
||
/// <returns>显示名称</returns>
|
||
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
|
||
}
|
||
} |