# 模型分层拆分功能设计方案

## 需求分析

根据用户需求第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<FloorInfo> DetectFloors(ModelItemCollection allItems);
    public FloorInfo GetFloorByElevation(double elevation);
    public List<string> 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<string, object> Metadata { get; set; }
    }
    
    // 分组方法
    public List<AttributeGroup> GroupByAttribute(ModelItemCollection items, string attributeName);
    public List<string> GetAvailableAttributes(ModelItemCollection items);
    public Dictionary<string, int> 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<FloorInfo> DetectFloorsByElevation(ModelItemCollection items)
    {
        var floorGroups = new Dictionary<double, List<ModelItem>>();
        
        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<ModelItem> { item };
                }
                else
                {
                    // 添加到现有楼层组
                    floorGroups[floorElevation].Add(item);
                }
            }
        }
        
        // 转换为FloorInfo列表
        var floors = new List<FloorInfo>();
        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<double> 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<FloorInfo> 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<FloorInfo>();
        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<string, int>();
        
        // 统计各属性的出现频率
        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的限制和大模型处理的性能问题，提供了可靠的技术实现路径。