# 模型分层拆分功能设计方案 ## 需求分析 根据用户需求第6项:将大型建筑模型按照楼层等自定义属性,拆分成多个单独的文件保存(每层一个Navisworks文件) ## 功能概述 实现一个模型分层拆分管理器(ModelSplitterManager),能够: 1. 按楼层属性自动识别和分组模型元素 2. 按自定义属性进行模型分组 3. 将分组后的模型导出为独立的Navisworks文件 4. 提供批量处理和进度监控功能 5. 支持分层预览和验证功能 ## 技术架构设计 ### 1. 核心类设计 #### ModelSplitterManager 主管理类 ```csharp public class ModelSplitterManager { // 分层策略枚举 public enum SplitStrategy { ByFloor, // 按楼层 ByCustomAttribute, // 按自定义属性 ByCategory, // 按类别 BySelection // 按选择集 } // 分层配置 public class SplitConfiguration { public SplitStrategy Strategy { get; set; } public string AttributeName { get; set; } // 用于自定义属性分层 public string OutputDirectory { get; set; } public string FileNamePattern { get; set; } // 文件命名模式 public bool IncludeEmptyLayers { get; set; } public bool PreserveOriginalStructure { get; set; } } // 分层结果 public class SplitResult { public string LayerName { get; set; } public ModelItemCollection Items { get; set; } public string OutputFilePath { get; set; } public bool Success { get; set; } public string ErrorMessage { get; set; } public int ItemCount { get; set; } } } ``` #### FloorDetector 楼层检测器 ```csharp public class FloorDetector { // 楼层信息结构 public class FloorInfo { public string FloorName { get; set; } public double Elevation { get; set; } public BoundingBox3D Bounds { get; set; } public ModelItemCollection Items { get; set; } } // 检测方法 public List DetectFloors(ModelItemCollection allItems); public FloorInfo GetFloorByElevation(double elevation); public List GetAvailableFloorAttributes(); } ``` #### AttributeGrouper 属性分组器 ```csharp public class AttributeGrouper { // 分组结果 public class AttributeGroup { public string GroupName { get; set; } public string AttributeValue { get; set; } public ModelItemCollection Items { get; set; } public Dictionary Metadata { get; set; } } // 分组方法 public List GroupByAttribute(ModelItemCollection items, string attributeName); public List GetAvailableAttributes(ModelItemCollection items); public Dictionary GetAttributeValueCounts(ModelItemCollection items, string attributeName); } ``` ### 2. Navisworks API 集成 #### 文件导出核心逻辑 ```csharp public class NavisworksFileExporter { public bool ExportModelItems(ModelItemCollection items, string outputPath) { try { // 1. 创建新的文档实例 var tempDocument = Application.NewDocument(); // 2. 设置选择集 tempDocument.CurrentSelection.CopyFrom(items); // 3. 隐藏未选中的元素 HideUnselectedItems(tempDocument, items); // 4. 导出文件 tempDocument.SaveFile(outputPath); // 5. 清理临时文档 tempDocument.Close(); return true; } catch (Exception ex) { LogManager.Error($"导出文件失败: {ex.Message}"); return false; } } private void HideUnselectedItems(Document document, ModelItemCollection selectedItems) { // 使用VisibilityManager隐藏未选中的元素 var visibilityManager = new VisibilityManager(); // 获取所有模型元素 var allItems = document.Models.RootItemDescendantsAndSelf; // 创建要隐藏的元素集合 var itemsToHide = new ModelItemCollection(); foreach (ModelItem item in allItems) { if (!selectedItems.Contains(item)) { itemsToHide.Add(item); } } // 隐藏未选中的元素 visibilityManager.HideItems(itemsToHide); } } ``` ### 3. 楼层检测算法 #### 基于高程的楼层检测 ```csharp public class ElevationBasedFloorDetector { private const double FLOOR_HEIGHT_THRESHOLD = 2.5; // 最小楼层高度(米) private const double ELEVATION_TOLERANCE = 0.5; // 高程容差(米) public List DetectFloorsByElevation(ModelItemCollection items) { var floorGroups = new Dictionary>(); foreach (ModelItem item in items) { // 获取元素的边界框 var bounds = item.BoundingBox(); if (bounds.HasValue) { double elevation = bounds.Value.Min.Z; // 使用Z坐标最小值作为高程 // 查找相近的楼层组 double floorElevation = FindNearestFloorElevation(floorGroups.Keys, elevation); if (floorElevation == double.MinValue) { // 创建新楼层组 floorGroups[elevation] = new List { item }; } else { // 添加到现有楼层组 floorGroups[floorElevation].Add(item); } } } // 转换为FloorInfo列表 var floors = new List(); int floorIndex = 1; foreach (var kvp in floorGroups.OrderBy(x => x.Key)) { var floorItems = new ModelItemCollection(); floorItems.AddRange(kvp.Value); floors.Add(new FloorInfo { FloorName = $"Floor_{floorIndex:D2}", Elevation = kvp.Key, Items = floorItems, Bounds = CalculateBounds(floorItems) }); floorIndex++; } return floors; } private double FindNearestFloorElevation(IEnumerable existingElevations, double targetElevation) { foreach (double elevation in existingElevations) { if (Math.Abs(elevation - targetElevation) <= ELEVATION_TOLERANCE) { return elevation; } } return double.MinValue; } } ``` #### 基于属性的楼层检测 ```csharp public class AttributeBasedFloorDetector { private readonly string[] COMMON_FLOOR_ATTRIBUTES = { "Level", "Floor", "Storey", "楼层", "层", "Level Name", "Story" }; public List DetectFloorsByAttribute(ModelItemCollection items) { // 1. 查找楼层属性 string floorAttribute = FindFloorAttribute(items); if (string.IsNullOrEmpty(floorAttribute)) { LogManager.Warning("未找到楼层属性,使用高程检测"); return new ElevationBasedFloorDetector().DetectFloorsByElevation(items); } // 2. 按属性值分组 var attributeGrouper = new AttributeGrouper(); var groups = attributeGrouper.GroupByAttribute(items, floorAttribute); // 3. 转换为FloorInfo var floors = new List(); foreach (var group in groups) { floors.Add(new FloorInfo { FloorName = SanitizeFloorName(group.AttributeValue), Elevation = CalculateAverageElevation(group.Items), Items = group.Items, Bounds = CalculateBounds(group.Items) }); } return floors.OrderBy(f => f.Elevation).ToList(); } private string FindFloorAttribute(ModelItemCollection items) { var attributeCounts = new Dictionary(); // 统计各属性的出现频率 foreach (ModelItem item in items.Take(100)) // 采样前100个元素 { var properties = item.PropertyCategories; foreach (PropertyCategory category in properties) { foreach (DataProperty property in category.Properties) { string propName = property.DisplayName; if (COMMON_FLOOR_ATTRIBUTES.Any(attr => propName.IndexOf(attr, StringComparison.OrdinalIgnoreCase) >= 0)) { attributeCounts[propName] = attributeCounts.GetValueOrDefault(propName, 0) + 1; } } } } // 返回出现频率最高的楼层属性 return attributeCounts.OrderByDescending(kvp => kvp.Value).FirstOrDefault().Key; } } ``` ### 4. 用户界面设计 #### 分层配置对话框 ```csharp public partial class ModelSplitterDialog : Form { private ModelSplitterManager _splitterManager; private FloorDetector _floorDetector; // UI控件 private ComboBox _strategyComboBox; private ComboBox _attributeComboBox; private TextBox _outputDirectoryTextBox; private TextBox _fileNamePatternTextBox; private ListView _previewListView; private ProgressBar _progressBar; private Button _previewButton; private Button _executeButton; public ModelSplitterDialog() { InitializeComponent(); InitializeManagers(); LoadAvailableAttributes(); } private void InitializeManagers() { _splitterManager = new ModelSplitterManager(); _floorDetector = new FloorDetector(); // 订阅事件 _splitterManager.ProgressChanged += OnProgressChanged; _splitterManager.LayerProcessed += OnLayerProcessed; _splitterManager.SplitCompleted += OnSplitCompleted; } private void OnPreviewButtonClick(object sender, EventArgs e) { try { var config = GetCurrentConfiguration(); var previewResults = _splitterManager.PreviewSplit(config); UpdatePreviewList(previewResults); } catch (Exception ex) { MessageBox.Show($"预览失败: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); } } private void OnExecuteButtonClick(object sender, EventArgs e) { try { var config = GetCurrentConfiguration(); // 验证配置 if (!ValidateConfiguration(config)) return; // 开始分层处理 _executeButton.Enabled = false; _progressBar.Visible = true; Task.Run(() => _splitterManager.ExecuteSplit(config)); } catch (Exception ex) { MessageBox.Show($"执行失败: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); _executeButton.Enabled = true; _progressBar.Visible = false; } } } ``` ### 5. 集成到主插件 #### 在MainPlugin中添加分层功能 ```csharp // 在CreateSystemManagementTab方法中添加模型分层控件 private void CreateModelSplitterControls(GroupBox groupBox) { Button splitterButton = new Button { Text = "模型分层拆分", Location = new Point(15, 25), Size = new Size(120, 30), Font = new Font("微软雅黑", 8) }; groupBox.Controls.Add(splitterButton); splitterButton.Click += (sender, e) => { GlobalExceptionHandler.SafeExecute(() => { // 检查是否有打开的模型 if (Application.ActiveDocument?.Models?.Count == 0) { MessageBox.Show("请先打开一个Navisworks模型文件", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); return; } // 显示模型分层对话框 var splitterDialog = new ModelSplitterDialog(); splitterDialog.ShowDialog(); }, "打开模型分层对话框"); }; Label infoLabel = new Label { Text = "将大型模型按楼层或属性拆分为多个文件", Location = new Point(15, 65), Size = new Size(300, 40), Font = new Font("微软雅黑", 7), ForeColor = Color.Gray }; groupBox.Controls.Add(infoLabel); } ``` ## 实现步骤 ### 第一阶段:核心功能实现 1. 创建ModelSplitterManager基础框架 2. 实现FloorDetector楼层检测功能 3. 实现AttributeGrouper属性分组功能 4. 实现NavisworksFileExporter文件导出功能 ### 第二阶段:算法优化 1. 完善基于高程的楼层检测算法 2. 实现基于属性的楼层检测算法 3. 添加智能楼层识别和验证功能 4. 优化大模型处理性能 ### 第三阶段:用户界面 1. 创建ModelSplitterDialog配置对话框 2. 实现分层预览功能 3. 添加进度监控和错误处理 4. 集成到主插件界面 ### 第四阶段:测试和优化 1. 单元测试和集成测试 2. 性能优化和内存管理 3. 错误处理和异常恢复 4. 用户体验优化 ## 技术难点和解决方案 ### 1. Navisworks API限制 **问题**: Navisworks API不支持直接创建新文档并添加特定模型元素 **解决方案**: - 使用选择集和可见性控制来实现"虚拟分层" - 通过SaveFile API导出包含特定元素的文件 - 利用临时文档和选择集操作 ### 2. 大模型性能问题 **问题**: 处理大型模型时可能出现内存不足或处理缓慢 **解决方案**: - 分批处理模型元素 - 使用异步处理和进度监控 - 实现内存管理和垃圾回收优化 - 提供取消操作功能 ### 3. 楼层识别准确性 **问题**: 不同模型的楼层信息表示方式不统一 **解决方案**: - 多种检测算法组合使用 - 用户可手动调整检测结果 - 提供预览和验证功能 - 支持自定义楼层识别规则 ### 4. 文件命名和组织 **问题**: 生成的文件需要有意义的命名和良好的组织结构 **解决方案**: - 可配置的文件命名模式 - 自动创建目录结构 - 支持批量重命名功能 - 生成分层报告文档 ## 配置参数说明 ### 分层策略配置 ```json { "splitStrategy": "ByFloor", "attributeName": "Level", "outputDirectory": "C:\\NavisworksSplits", "fileNamePattern": "{ProjectName}_{LayerName}_{DateTime}", "includeEmptyLayers": false, "preserveOriginalStructure": true, "elevationTolerance": 0.5, "minFloorHeight": 2.5, "maxLayersPerFile": 1 } ``` ### 输出文件组织 ``` OutputDirectory/ ├── ProjectName_Floor_01_20250716/ │ ├── ProjectName_Floor_01.nwd │ ├── ProjectName_Floor_01_report.txt │ └── ProjectName_Floor_01_metadata.json ├── ProjectName_Floor_02_20250716/ │ ├── ProjectName_Floor_02.nwd │ ├── ProjectName_Floor_02_report.txt │ └── ProjectName_Floor_02_metadata.json └── split_summary_report.html ``` ## 扩展功能 ### 1. 批量处理支持 - 支持处理多个Navisworks文件 - 提供批处理脚本和命令行接口 - 支持网络路径和云存储 ### 2. 高级分层规则 - 支持复合条件分层(楼层+区域) - 支持正则表达式匹配 - 支持自定义脚本分层逻辑 ### 3. 质量检查功能 - 检查分层完整性 - 验证文件大小和元素数量 - 生成分层质量报告 ### 4. 集成其他功能 - 与路径规划功能联动 - 支持分层动画预览 - 集成到DELMIA导出流程 ## 总结 该设计方案提供了完整的模型分层拆分解决方案,能够满足用户需求第6项的要求。通过模块化设计和灵活的配置选项,可以适应不同类型的建筑模型和用户需求。同时考虑了Navisworks API的限制和大模型处理的性能问题,提供了可靠的技术实现路径。