优化了分层预览的遍历机制,提高性能
This commit is contained in:
parent
2b92e783bb
commit
4dc989926e
448
doc/working/LayerPreview_SmartTraversal_Requirements_Analysis.md
Normal file
448
doc/working/LayerPreview_SmartTraversal_Requirements_Analysis.md
Normal file
@ -0,0 +1,448 @@
|
||||
# 分层预览智能遍历需求分析
|
||||
|
||||
## 需求概述
|
||||
|
||||
### 新的分层处理逻辑需求
|
||||
|
||||
修改分层预览的业务逻辑,实现基于属性的智能停止遍历机制:
|
||||
|
||||
1. **智能遍历逻辑**:从一级节点开始,遍历每个节点查找指定的分层属性
|
||||
2. **分支停止机制**:如果找到分层属性,记录下来作为一个分层,不再遍历其下级节点
|
||||
3. **深度递归控制**:如果没找到,继续遍历其子节点,直到找到为止,遍历深度受到用户指定的遍历深度限制
|
||||
4. **智能检测特殊处理**:使用一组候选的分层属性,对每个节点进行查找,按属性的评分(优先级)确定选择何种属性
|
||||
5. **自定义查找特殊处理**:用指定的分层属性,在每个节点的"分层信息"属性类别中查找
|
||||
|
||||
## 现有架构分析
|
||||
|
||||
### 1. 当前遍历机制的局限性
|
||||
|
||||
**现有实现方式**:
|
||||
|
||||
```csharp
|
||||
// 当前的两阶段处理方式
|
||||
var allItems = GetAllModelItems(config.MaxDepth); // 阶段1:收集所有指定深度内的节点
|
||||
var groups = strategy.GroupItems(allItems, config); // 阶段2:对所有节点进行属性分析和分组
|
||||
```
|
||||
|
||||
**存在的问题**:
|
||||
|
||||
- 采用固定深度遍历,无法实现智能停止
|
||||
- 先收集所有节点,再统一分组,无法在遍历过程中动态决策
|
||||
- **核心问题:无法实现"找到属性就停止该分支遍历"的逻辑**
|
||||
|
||||
**需要的新逻辑**:
|
||||
|
||||
```csharp
|
||||
// 需要的边遍历边检查逻辑
|
||||
foreach (一级节点) {
|
||||
if (节点有指定分层属性) {
|
||||
记录为分层,停止遍历该分支;
|
||||
} else {
|
||||
递归遍历子节点(深度限制);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 现有策略接口的不足
|
||||
|
||||
**当前IGroupingStrategy接口**:
|
||||
|
||||
```csharp
|
||||
public interface IGroupingStrategy
|
||||
{
|
||||
Dictionary<string, GroupItem> GroupItems(ModelItemCollection items, SplitConfiguration config);
|
||||
}
|
||||
```
|
||||
|
||||
**接口局限性**:
|
||||
|
||||
- 只能处理预收集的节点集合
|
||||
- 无法在遍历过程中动态决策是否继续遍历
|
||||
- 不支持单节点的属性检查和分支控制
|
||||
|
||||
### 3. 属性检查机制的缺陷
|
||||
|
||||
**现有策略类的问题**:
|
||||
|
||||
- 如`FloorAttributeStrategy`仅检查特定的固定属性
|
||||
- 没有通用的"分层信息"属性类别检查机制
|
||||
- 不支持候选属性组和优先级评分
|
||||
- 缺乏多属性竞争选择逻辑
|
||||
|
||||
## 架构改造方案
|
||||
|
||||
### 1. 核心遍历算法重设计
|
||||
|
||||
**新的智能遍历算法**:
|
||||
|
||||
```csharp
|
||||
public List<SplitPreviewResult> PreviewSplitWithSmartTraversal(
|
||||
SplitConfiguration config, ISmartGroupingStrategy strategy)
|
||||
{
|
||||
var results = new List<SplitPreviewResult>();
|
||||
|
||||
// 从每个模型的一级节点开始遍历
|
||||
foreach (Model model in document.Models)
|
||||
{
|
||||
foreach (ModelItem rootChild in model.RootItem.Children)
|
||||
{
|
||||
TraverseNodeWithAttributeCheck(rootChild, strategy, config, results, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
private void TraverseNodeWithAttributeCheck(ModelItem node,
|
||||
ISmartGroupingStrategy strategy, SplitConfiguration config,
|
||||
List<SplitPreviewResult> results, int currentDepth)
|
||||
{
|
||||
// 检查当前节点是否有分层属性
|
||||
var layerInfo = strategy.ExtractLayerInfo(node);
|
||||
|
||||
if (layerInfo != null && layerInfo.IsValid)
|
||||
{
|
||||
// 找到分层属性,停止遍历该分支,添加到结果
|
||||
var layerResult = CreateLayerResult(layerInfo, node);
|
||||
results.Add(layerResult);
|
||||
return; // 关键:停止该分支遍历
|
||||
}
|
||||
|
||||
// 未找到属性且未达深度限制,继续遍历子节点
|
||||
if (currentDepth < config.MaxDepth && node.Children != null)
|
||||
{
|
||||
foreach (ModelItem child in node.Children)
|
||||
{
|
||||
TraverseNodeWithAttributeCheck(child, strategy, config, results, currentDepth + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 新策略接口设计
|
||||
|
||||
**ISmartGroupingStrategy接口**:
|
||||
|
||||
```csharp
|
||||
public interface ISmartGroupingStrategy
|
||||
{
|
||||
string GroupTypeName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 核心方法:检查单个节点的分层信息
|
||||
/// </summary>
|
||||
LayerInfo ExtractLayerInfo(ModelItem node);
|
||||
|
||||
/// <summary>
|
||||
/// 支持候选属性组的智能检测
|
||||
/// </summary>
|
||||
LayerInfo ExtractBestLayerInfo(ModelItem node, List<AttributeCandidate> candidates);
|
||||
}
|
||||
```
|
||||
|
||||
**支持数据结构**:
|
||||
|
||||
```csharp
|
||||
public class LayerInfo
|
||||
{
|
||||
public bool IsValid { get; set; }
|
||||
public string LayerName { get; set; }
|
||||
public string AttributeName { get; set; }
|
||||
public string AttributeValue { get; set; }
|
||||
public int Priority { get; set; } // 用于智能检测的优先级
|
||||
public string CategoryName { get; set; } // 属性类别
|
||||
}
|
||||
|
||||
public class AttributeCandidate
|
||||
{
|
||||
public string AttributeName { get; set; }
|
||||
public string CategoryName { get; set; } // 如"分层信息"
|
||||
public int Priority { get; set; } // 优先级评分
|
||||
public Func<string, string> ValueProcessor { get; set; } // 值处理函数
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 智能检测策略实现
|
||||
|
||||
**SmartLayerDetectionStrategy类**:
|
||||
|
||||
```csharp
|
||||
public class SmartLayerDetectionStrategy : ISmartGroupingStrategy
|
||||
{
|
||||
private readonly List<AttributeCandidate> _candidates = new List<AttributeCandidate>
|
||||
{
|
||||
// 按优先级排序的候选属性
|
||||
new AttributeCandidate { AttributeName = "楼层", CategoryName = "分层信息", Priority = 10 },
|
||||
new AttributeCandidate { AttributeName = "Floor", CategoryName = "Identity Data", Priority = 9 },
|
||||
new AttributeCandidate { AttributeName = "Level", CategoryName = "Constraints", Priority = 8 },
|
||||
new AttributeCandidate { AttributeName = "分区", CategoryName = "分层信息", Priority = 7 },
|
||||
new AttributeCandidate { AttributeName = "Zone", CategoryName = "Identity Data", Priority = 6 },
|
||||
new AttributeCandidate { AttributeName = "子系统", CategoryName = "分层信息", Priority = 5 },
|
||||
new AttributeCandidate { AttributeName = "System Type", CategoryName = "Mechanical", Priority = 4 },
|
||||
// ... 更多候选属性
|
||||
};
|
||||
|
||||
public LayerInfo ExtractLayerInfo(ModelItem node)
|
||||
{
|
||||
return ExtractBestLayerInfo(node, _candidates);
|
||||
}
|
||||
|
||||
public LayerInfo ExtractBestLayerInfo(ModelItem node, List<AttributeCandidate> candidates)
|
||||
{
|
||||
LayerInfo bestMatch = null;
|
||||
int highestPriority = -1;
|
||||
|
||||
// 遍历所有候选属性,找到优先级最高的有效属性
|
||||
foreach (var candidate in candidates)
|
||||
{
|
||||
var value = GetAttributeValue(node, candidate.CategoryName, candidate.AttributeName);
|
||||
if (!string.IsNullOrEmpty(value) && candidate.Priority > highestPriority)
|
||||
{
|
||||
bestMatch = new LayerInfo
|
||||
{
|
||||
IsValid = true,
|
||||
LayerName = candidate.ValueProcessor?.Invoke(value) ?? value,
|
||||
AttributeName = candidate.AttributeName,
|
||||
AttributeValue = value,
|
||||
Priority = candidate.Priority,
|
||||
CategoryName = candidate.CategoryName
|
||||
};
|
||||
highestPriority = candidate.Priority;
|
||||
}
|
||||
}
|
||||
|
||||
return bestMatch ?? new LayerInfo { IsValid = false };
|
||||
}
|
||||
|
||||
private string GetAttributeValue(ModelItem node, string categoryName, string attributeName)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 实现Navisworks属性检查逻辑
|
||||
foreach (PropertyCategory category in node.PropertyCategories)
|
||||
{
|
||||
if (category.DisplayName == categoryName)
|
||||
{
|
||||
foreach (DataProperty property in category.Properties)
|
||||
{
|
||||
if (property.DisplayName == attributeName)
|
||||
{
|
||||
return property.Value.ToDisplayString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Warning($"获取属性值失败: {ex.Message}");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 自定义属性检查策略
|
||||
|
||||
**CustomAttributeStrategy类**:
|
||||
|
||||
```csharp
|
||||
public class CustomAttributeStrategy : ISmartGroupingStrategy
|
||||
{
|
||||
private readonly string _targetAttributeName;
|
||||
private readonly string _targetCategoryName;
|
||||
|
||||
public string GroupTypeName => $"自定义属性({_targetAttributeName})";
|
||||
|
||||
public CustomAttributeStrategy(string attributeName, string categoryName = "分层信息")
|
||||
{
|
||||
_targetAttributeName = attributeName;
|
||||
_targetCategoryName = categoryName;
|
||||
}
|
||||
|
||||
public LayerInfo ExtractLayerInfo(ModelItem node)
|
||||
{
|
||||
var value = GetAttributeValue(node, _targetCategoryName, _targetAttributeName);
|
||||
|
||||
if (!string.IsNullOrEmpty(value))
|
||||
{
|
||||
return new LayerInfo
|
||||
{
|
||||
IsValid = true,
|
||||
LayerName = value,
|
||||
AttributeName = _targetAttributeName,
|
||||
AttributeValue = value,
|
||||
Priority = 1,
|
||||
CategoryName = _targetCategoryName
|
||||
};
|
||||
}
|
||||
|
||||
return new LayerInfo { IsValid = false };
|
||||
}
|
||||
|
||||
public LayerInfo ExtractBestLayerInfo(ModelItem node, List<AttributeCandidate> candidates)
|
||||
{
|
||||
// 对于自定义策略,只检查指定的单个属性
|
||||
return ExtractLayerInfo(node);
|
||||
}
|
||||
|
||||
private string GetAttributeValue(ModelItem node, string categoryName, string attributeName)
|
||||
{
|
||||
// 与智能检测策略相同的实现
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5. 遍历结果处理
|
||||
|
||||
**CreateLayerResult方法设计**:
|
||||
|
||||
```csharp
|
||||
private SplitPreviewResult CreateLayerResult(LayerInfo layerInfo, ModelItem rootNode)
|
||||
{
|
||||
// 收集该节点下的所有子项
|
||||
var allChildItems = new ModelItemCollection();
|
||||
CollectAllDescendants(rootNode, allChildItems);
|
||||
|
||||
return new SplitPreviewResult
|
||||
{
|
||||
LayerName = SanitizeLayerName(layerInfo.LayerName),
|
||||
ItemCount = allChildItems.Count,
|
||||
EstimatedFileSize = EstimateFileSize(allChildItems.Count),
|
||||
Status = "就绪",
|
||||
Items = allChildItems,
|
||||
Metadata = new Dictionary<string, object>
|
||||
{
|
||||
["AttributeName"] = layerInfo.AttributeName,
|
||||
["AttributeValue"] = layerInfo.AttributeValue,
|
||||
["CategoryName"] = layerInfo.CategoryName,
|
||||
["Priority"] = layerInfo.Priority,
|
||||
["RootNodeName"] = rootNode.DisplayName
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void CollectAllDescendants(ModelItem rootNode, ModelItemCollection collection)
|
||||
{
|
||||
// 添加根节点本身
|
||||
collection.Add(rootNode);
|
||||
|
||||
// 递归添加所有后代节点
|
||||
if (rootNode.Children != null)
|
||||
{
|
||||
foreach (ModelItem child in rootNode.Children)
|
||||
{
|
||||
CollectAllDescendants(child, collection);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 配置和UI适配
|
||||
|
||||
### 1. 分层策略配置
|
||||
|
||||
**新的策略类型枚举**:
|
||||
|
||||
```csharp
|
||||
public enum SmartSplitStrategy
|
||||
{
|
||||
SmartLayerDetection, // 智能检测
|
||||
CustomFloorAttribute, // 自定义楼层属性
|
||||
CustomZoneAttribute, // 自定义分区属性
|
||||
CustomSystemAttribute, // 自定义系统属性
|
||||
CustomAttribute // 完全自定义属性
|
||||
}
|
||||
```
|
||||
|
||||
### 2. UI配置选项
|
||||
|
||||
**智能检测配置**:
|
||||
|
||||
- 候选属性优先级设置
|
||||
- 属性类别选择
|
||||
- 值处理规则配置
|
||||
|
||||
**自定义查找配置**:
|
||||
|
||||
- 属性名称输入
|
||||
- 属性类别选择(默认"分层信息")
|
||||
- 值过滤规则
|
||||
|
||||
## 兼容性考虑
|
||||
|
||||
### 1. 向后兼容
|
||||
|
||||
**保留现有接口**:
|
||||
|
||||
- 现有的`IGroupingStrategy`接口和实现类保持不变
|
||||
- 在`SimplifiedModelSplitterManager`中增加新的智能遍历方法
|
||||
- UI层提供策略选择开关
|
||||
|
||||
**渐进式迁移**:
|
||||
|
||||
```csharp
|
||||
public List<SplitPreviewResult> PreviewSplit(SplitConfiguration config)
|
||||
{
|
||||
// 根据配置选择使用新的智能遍历还是传统方式
|
||||
if (config.UseSmartTraversal)
|
||||
{
|
||||
return PreviewSplitWithSmartTraversal(config, CreateSmartStrategy(config));
|
||||
}
|
||||
else
|
||||
{
|
||||
// 保留原有的实现逻辑
|
||||
return PreviewSplitTraditional(config);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 性能考虑
|
||||
|
||||
**优化策略**:
|
||||
|
||||
- 属性检查缓存机制
|
||||
- 早期终止优化(找到高优先级属性立即停止)
|
||||
- 内存管理优化(避免大量节点同时加载)
|
||||
|
||||
## 实施复杂度评估
|
||||
|
||||
### 高复杂度任务
|
||||
|
||||
1. **核心遍历算法重写**:需要完全重新设计遍历逻辑
|
||||
2. **属性检查机制实现**:涉及Navisworks API的深度使用
|
||||
3. **测试验证**:需要大量的模型测试和边界情况验证
|
||||
|
||||
### 中等复杂度任务
|
||||
|
||||
1. **新策略接口和实现类**:相对标准的面向对象设计
|
||||
2. **UI适配**:在现有界面基础上增加配置选项
|
||||
|
||||
### 低复杂度任务
|
||||
|
||||
1. **配置管理**:基于现有的配置系统扩展
|
||||
2. **日志和错误处理**:基于现有的LogManager扩展
|
||||
|
||||
## 结论
|
||||
|
||||
**现有架构评估**:
|
||||
|
||||
- **不满足新需求**:当前的"先收集后分组"模式无法实现智能停止遍历
|
||||
- **需要重大改造**:核心算法、策略接口、属性检查机制都需要重新设计
|
||||
- **改造工作量大**:预计需要重写30%以上的核心代码
|
||||
|
||||
**建议实施策略**:
|
||||
|
||||
1. **并行开发**:新旧算法并存,确保系统稳定性
|
||||
2. **分阶段验证**:先实现基础功能,再逐步完善高级特性
|
||||
3. **充分测试**:准备多种类型的测试模型,验证各种边界情况
|
||||
4. **性能监控**:关注新算法的性能表现,必要时进行优化
|
||||
|
||||
**预期收益**:
|
||||
|
||||
- **更精确的分层**:基于实际属性内容而非固定深度
|
||||
- **更高的效率**:避免不必要的深度遍历
|
||||
- **更灵活的配置**:支持多种属性检查策略
|
||||
- **更好的用户体验**:提供智能化的分层建议
|
||||
260
doc/working/SmartTraversal_Lightweight_Preview_Implementation.md
Normal file
260
doc/working/SmartTraversal_Lightweight_Preview_Implementation.md
Normal file
@ -0,0 +1,260 @@
|
||||
# 轻量化智能遍历预览实施方案
|
||||
|
||||
## 目标
|
||||
实现基于属性的智能遍历算法,替代现有的固定深度收集方式,专注于预览性能提升。保存逻辑暂时不修改。
|
||||
|
||||
## 核心修改点
|
||||
|
||||
### 1. 新增智能遍历算法(SimplifiedModelSplitterManager.cs)
|
||||
|
||||
**PreviewSplitWithSmartTraversal方法**:
|
||||
```csharp
|
||||
private List<SplitPreviewResult> PreviewSplitWithSmartTraversal(
|
||||
SplitConfiguration config, IGroupingStrategy strategy)
|
||||
{
|
||||
var results = new List<SplitPreviewResult>();
|
||||
|
||||
foreach (Model model in document.Models)
|
||||
{
|
||||
foreach (ModelItem rootChild in model.RootItem.Children)
|
||||
{
|
||||
TraverseAndRecord(rootChild, strategy, config, results, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
```
|
||||
|
||||
**TraverseAndRecord递归方法**:
|
||||
```csharp
|
||||
private void TraverseAndRecord(ModelItem node, IGroupingStrategy strategy,
|
||||
SplitConfiguration config, List<SplitPreviewResult> results, int currentDepth)
|
||||
{
|
||||
// 检查当前节点的分层属性
|
||||
string layerValue = strategy.ExtractAttributeValue(node);
|
||||
|
||||
if (!string.IsNullOrEmpty(layerValue))
|
||||
{
|
||||
// 找到分层属性,创建预览结果,停止该分支遍历
|
||||
var layerResult = CreateLightweightLayerResult(layerValue, node, strategy.GroupTypeName);
|
||||
results.Add(layerResult);
|
||||
return; // 关键:停止遍历该分支
|
||||
}
|
||||
|
||||
// 未找到分层属性且未达深度限制,继续遍历子节点
|
||||
if (currentDepth < config.MaxDepth && node.Children != null)
|
||||
{
|
||||
foreach (ModelItem child in node.Children)
|
||||
{
|
||||
TraverseAndRecord(child, strategy, config, results, currentDepth + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 最简化预览结果创建
|
||||
|
||||
**CreateLightweightLayerResult方法**:
|
||||
```csharp
|
||||
private SplitPreviewResult CreateLightweightLayerResult(string layerValue, ModelItem rootNode, string groupTypeName)
|
||||
{
|
||||
return new SplitPreviewResult
|
||||
{
|
||||
LayerName = SanitizeLayerName(layerValue),
|
||||
Items = new ModelItemCollection { rootNode },
|
||||
Metadata = new Dictionary<string, object>
|
||||
{
|
||||
["LayerValue"] = layerValue,
|
||||
["RootNodeReference"] = rootNode,
|
||||
["GroupType"] = groupTypeName
|
||||
}
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
**说明**:
|
||||
- 不设置 ItemCount、EstimatedFileSize、Status 等字段
|
||||
- 只包含预览必需的信息:LayerName、根节点引用、元数据
|
||||
- 避免任何不必要的计算和统计
|
||||
|
||||
### 3. 策略接口扩展
|
||||
|
||||
**IGroupingStrategy接口新增方法**:
|
||||
```csharp
|
||||
public interface IGroupingStrategy
|
||||
{
|
||||
string GroupTypeName { get; }
|
||||
|
||||
// 现有方法保持不变
|
||||
Dictionary<string, GroupItem> GroupItems(ModelItemCollection items, SplitConfiguration config);
|
||||
|
||||
// 新增:单节点属性检测
|
||||
string ExtractAttributeValue(ModelItem node);
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 示例策略类升级
|
||||
|
||||
**FloorAttributeStrategy新增实现**:
|
||||
```csharp
|
||||
public string ExtractAttributeValue(ModelItem node)
|
||||
{
|
||||
// 优先在"分层信息"类别中查找楼层属性
|
||||
return GetAttributeFromCategory(node, "分层信息", "楼层") ??
|
||||
GetAttributeFromCategory(node, "Identity Data", "Floor") ??
|
||||
GetAttributeFromCategory(node, "Constraints", "Level");
|
||||
}
|
||||
|
||||
private string GetAttributeFromCategory(ModelItem node, string categoryName, string attributeName)
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (PropertyCategory category in node.PropertyCategories)
|
||||
{
|
||||
if (category.DisplayName == categoryName)
|
||||
{
|
||||
foreach (DataProperty property in category.Properties)
|
||||
{
|
||||
if (property.DisplayName == attributeName)
|
||||
{
|
||||
return property.Value.ToDisplayString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Warning($"获取属性失败: {ex.Message}");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
```
|
||||
|
||||
### 5. 主入口方法修改
|
||||
|
||||
**PreviewSplit方法调整**:
|
||||
```csharp
|
||||
public List<SplitPreviewResult> PreviewSplit(SplitConfiguration config)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 缓存检查等现有逻辑保持不变...
|
||||
|
||||
var strategy = CreateStrategy(config.Strategy);
|
||||
|
||||
// 使用新的智能遍历,完全替代GetItemsByDepthUnified
|
||||
LogManager.Info($"开始智能遍历分层预览,策略: {config.Strategy},深度限制: {config.MaxDepth}");
|
||||
var previewResults = PreviewSplitWithSmartTraversal(config, strategy);
|
||||
LogManager.Info($"智能遍历完成,识别到 {previewResults.Count} 个分层");
|
||||
|
||||
// 缓存和状态更新等现有逻辑保持不变...
|
||||
|
||||
return previewResults;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"智能遍历预览失败: {ex.Message}", ex);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 性能优势
|
||||
|
||||
### 避免的性能瓶颈
|
||||
- **不再调用GetItemsByDepthUnified()**:避免收集所有深度内的节点
|
||||
- **不进行子节点收集**:预览时只保存根节点引用
|
||||
- **不计算统计信息**:ItemCount、EstimatedFileSize、Status全部跳过
|
||||
- **智能分支停止**:找到分层属性立即停止该分支遍历
|
||||
|
||||
### 预期性能提升
|
||||
- **内存占用大幅降低**:从数万节点减少到只有分层根节点
|
||||
- **响应速度显著提升**:预览结果近乎实时生成
|
||||
- **CPU使用率降低**:避免大量不必要的节点遍历和属性检查
|
||||
|
||||
## 算法逻辑对比
|
||||
|
||||
### 原有算法(性能瓶颈)
|
||||
```
|
||||
1. 收集所有指定深度内的节点(GetItemsByDepthUnified)
|
||||
└── 可能收集数万个节点到内存
|
||||
2. 遍历所有节点检查属性(GroupItems)
|
||||
└── 对每个节点都进行属性查找
|
||||
3. 统计每个分组的节点数量和文件大小
|
||||
└── 额外的计算开销
|
||||
```
|
||||
|
||||
### 新算法(智能优化)
|
||||
```
|
||||
1. 从根节点开始递归遍历
|
||||
├── 检查当前节点属性
|
||||
├── 找到分层属性 → 停止该分支,记录结果
|
||||
└── 未找到 → 继续遍历子节点(受深度限制)
|
||||
2. 只保存分层根节点引用
|
||||
└── 最小内存占用
|
||||
3. 跳过所有统计计算
|
||||
└── 零额外开销
|
||||
```
|
||||
|
||||
## 实施步骤
|
||||
|
||||
1. **第一步**:在SimplifiedModelSplitterManager中实现智能遍历算法
|
||||
2. **第二步**:扩展IGroupingStrategy接口,添加ExtractAttributeValue方法
|
||||
3. **第三步**:升级FloorAttributeStrategy实现ExtractAttributeValue
|
||||
4. **第四步**:修改PreviewSplit方法使用新算法
|
||||
5. **第五步**:测试验证楼层分层的智能预览效果
|
||||
6. **第六步**:逐步升级其他策略类(ZoneAttributeStrategy、SubSystemAttributeStrategy等)
|
||||
|
||||
## 兼容性保证
|
||||
|
||||
- **保留现有方法**:所有原有方法和属性完全保持不变
|
||||
- **保存逻辑不变**:当前的ExecuteSplitAsync等保存方法完全不修改
|
||||
- **可回滚设计**:如有问题可轻松恢复到原有实现
|
||||
|
||||
## 扩展性考虑
|
||||
|
||||
### 其他策略类升级
|
||||
按照相同模式升级其他策略类:
|
||||
- **ZoneAttributeStrategy**: 在"分层信息"中查找"分区"属性
|
||||
- **SubSystemAttributeStrategy**: 在"分层信息"中查找"子系统"属性
|
||||
- **FloorDetectionStrategy**: 实现智能楼层检测逻辑
|
||||
|
||||
### 自定义属性支持
|
||||
为用户自定义分层属性预留接口:
|
||||
```csharp
|
||||
public class CustomAttributeStrategy : IGroupingStrategy
|
||||
{
|
||||
private string _targetAttribute;
|
||||
private string _targetCategory;
|
||||
|
||||
public string ExtractAttributeValue(ModelItem node)
|
||||
{
|
||||
return GetAttributeFromCategory(node, _targetCategory, _targetAttribute);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 测试验证计划
|
||||
|
||||
### 性能测试
|
||||
- **对比测试**:新旧算法在相同模型上的性能表现
|
||||
- **内存监控**:预览过程中的内存使用情况
|
||||
- **响应时间**:从触发预览到显示结果的时间
|
||||
|
||||
### 功能测试
|
||||
- **分层准确性**:确保智能遍历找到的分层与预期一致
|
||||
- **深度控制**:验证遍历深度限制正常工作
|
||||
- **边界情况**:测试无分层属性、深度为0等特殊情况
|
||||
|
||||
## 预期收益
|
||||
|
||||
此方案专注于预览性能优化,预计将带来:
|
||||
- **90%以上的内存使用量减少**
|
||||
- **80%以上的预览响应时间提升**
|
||||
- **完全兼容现有功能**,风险极低
|
||||
- **为后续智能检测功能奠定基础**
|
||||
|
||||
通过这次重构,分层预览将从当前的性能瓶颈转变为系统的性能优势点。
|
||||
@ -244,6 +244,17 @@ namespace NavisworksTransport.Core
|
||||
LogManager.Info($"[FloorAttributeManager] ✅ 成功创建{attributeType}属性 (索引=0)");
|
||||
}
|
||||
|
||||
// 属性修改成功,清除分层缓存确保下次预览使用最新数据
|
||||
try
|
||||
{
|
||||
SimplifiedModelSplitterManager.Instance?.ClearCache();
|
||||
LogManager.Info("[FloorAttributeManager] 属性修改成功,已清除分层缓存");
|
||||
}
|
||||
catch (Exception cacheEx)
|
||||
{
|
||||
LogManager.Warning($"[FloorAttributeManager] 清除缓存时出错: {cacheEx.Message}");
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
@ -339,55 +350,12 @@ namespace NavisworksTransport.Core
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取模型项的区域属性值,支持继承查询
|
||||
/// 直接获取对象的楼层属性
|
||||
/// </summary>
|
||||
/// <param name="item">目标模型项</param>
|
||||
/// <param name="searchParents">是否向上查找父节点的区域属性</param>
|
||||
/// <returns>区域属性值,未找到返回null</returns>
|
||||
public string GetZoneAttribute(ModelItem item, bool searchParents = true)
|
||||
{
|
||||
if (item == null) return null;
|
||||
|
||||
try
|
||||
{
|
||||
// 首先检查当前节点的区域属性
|
||||
string zone = GetZoneAttributeDirect(item);
|
||||
if (!string.IsNullOrEmpty(zone))
|
||||
{
|
||||
return zone;
|
||||
}
|
||||
|
||||
// 如果启用父节点搜索,向上查找
|
||||
if (searchParents)
|
||||
{
|
||||
var current = item.Parent;
|
||||
while (current != null)
|
||||
{
|
||||
zone = GetZoneAttributeDirect(current);
|
||||
if (!string.IsNullOrEmpty(zone))
|
||||
{
|
||||
LogManager.Debug($"[FloorAttributeManager] 从父节点 {current.DisplayName} 继承区域属性 {zone}");
|
||||
return zone;
|
||||
}
|
||||
current = current.Parent;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"[FloorAttributeManager] 获取区域属性失败:{ex.Message}", ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 直接获取对象的区域属性(不进行继承查找)
|
||||
/// </summary>
|
||||
private string GetZoneAttributeDirect(ModelItem item)
|
||||
/// <returns>楼层标识,未找到返回null</returns>
|
||||
public string GetFloorLevel(ModelItem item)
|
||||
{
|
||||
if (item == null) return null;
|
||||
|
||||
@ -399,6 +367,33 @@ namespace NavisworksTransport.Core
|
||||
ComApi.InwOaPath comPath = ComApiBridge.ToInwOaPath(item);
|
||||
ComApi.InwGUIPropertyNode2 propertyNode =
|
||||
(ComApi.InwGUIPropertyNode2)state.GetGUIPropertyNode(comPath, false);
|
||||
return GetFloorLevelFromProperty(propertyNode);
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"[FloorAttributeManager] 直接获取楼层属性失败:{ex.Message}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 直接获取对象的区域属性
|
||||
/// </summary>
|
||||
/// <param name="item">目标模型项</param>
|
||||
/// <returns>区域属性值,未找到返回null</returns>
|
||||
public string GetZoneAttribute(ModelItem item)
|
||||
{
|
||||
if (item == null) return null;
|
||||
|
||||
try
|
||||
{
|
||||
return ExecuteWithUIThread(() =>
|
||||
{
|
||||
ComApi.InwOpState10 state = ComApiBridge.State;
|
||||
ComApi.InwOaPath comPath = ComApiBridge.ToInwOaPath(item);
|
||||
ComApi.InwGUIPropertyNode2 propertyNode =
|
||||
(ComApi.InwGUIPropertyNode2)state.GetGUIPropertyNode(comPath, false);
|
||||
|
||||
return GetZoneFromProperty(propertyNode);
|
||||
});
|
||||
@ -411,53 +406,11 @@ namespace NavisworksTransport.Core
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取模型项的子系统属性值,支持继承查询
|
||||
/// 直接获取对象的子系统属性
|
||||
/// </summary>
|
||||
/// <param name="item">目标模型项</param>
|
||||
/// <param name="searchParents">是否向上查找父节点的子系统属性</param>
|
||||
/// <returns>子系统属性值,未找到返回null</returns>
|
||||
public string GetSubSystemAttribute(ModelItem item, bool searchParents = true)
|
||||
{
|
||||
if (item == null) return null;
|
||||
|
||||
try
|
||||
{
|
||||
// 首先检查当前节点的子系统属性
|
||||
string subSystem = GetSubSystemAttributeDirect(item);
|
||||
if (!string.IsNullOrEmpty(subSystem))
|
||||
{
|
||||
return subSystem;
|
||||
}
|
||||
|
||||
// 如果启用父节点搜索,向上查找
|
||||
if (searchParents)
|
||||
{
|
||||
var current = item.Parent;
|
||||
while (current != null)
|
||||
{
|
||||
subSystem = GetSubSystemAttributeDirect(current);
|
||||
if (!string.IsNullOrEmpty(subSystem))
|
||||
{
|
||||
LogManager.Debug($"[FloorAttributeManager] 从父节点 {current.DisplayName} 继承子系统属性 {subSystem}");
|
||||
return subSystem;
|
||||
}
|
||||
current = current.Parent;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"[FloorAttributeManager] 获取子系统属性失败:{ex.Message}", ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 直接获取对象的子系统属性(不进行继承查找)
|
||||
/// </summary>
|
||||
private string GetSubSystemAttributeDirect(ModelItem item)
|
||||
public string GetSubSystemAttribute(ModelItem item)
|
||||
{
|
||||
if (item == null) return null;
|
||||
|
||||
@ -480,50 +433,6 @@ namespace NavisworksTransport.Core
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取对象的楼层标识,支持继承查询
|
||||
/// </summary>
|
||||
/// <param name="item">目标模型项</param>
|
||||
/// <param name="searchParents">是否向上查找父节点的楼层属性</param>
|
||||
/// <returns>楼层标识,未找到返回null</returns>
|
||||
public string GetFloorLevel(ModelItem item, bool searchParents = true)
|
||||
{
|
||||
if (item == null) return null;
|
||||
|
||||
try
|
||||
{
|
||||
// 首先检查当前节点的楼层属性
|
||||
string floorLevel = GetFloorLevelDirect(item);
|
||||
if (!string.IsNullOrEmpty(floorLevel))
|
||||
{
|
||||
return floorLevel;
|
||||
}
|
||||
|
||||
// 如果启用父节点搜索,向上查找
|
||||
if (searchParents)
|
||||
{
|
||||
var current = item.Parent;
|
||||
while (current != null)
|
||||
{
|
||||
floorLevel = GetFloorLevelDirect(current);
|
||||
if (!string.IsNullOrEmpty(floorLevel))
|
||||
{
|
||||
LogManager.Debug($"[FloorAttributeManager] 从父节点 {current.DisplayName} 继承楼层属性 {floorLevel}");
|
||||
return floorLevel;
|
||||
}
|
||||
current = current.Parent;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"[FloorAttributeManager] 获取楼层属性失败:{ex.Message}", ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 批量设置楼层属性
|
||||
/// </summary>
|
||||
@ -588,7 +497,7 @@ namespace NavisworksTransport.Core
|
||||
{
|
||||
try
|
||||
{
|
||||
string floorLevel = GetFloorLevel(item, true);
|
||||
string floorLevel = GetFloorLevel(item);
|
||||
if (!string.IsNullOrEmpty(floorLevel))
|
||||
{
|
||||
if (!floorGroups.ContainsKey(floorLevel))
|
||||
@ -671,6 +580,17 @@ namespace NavisworksTransport.Core
|
||||
if (result)
|
||||
{
|
||||
NavisworksApiHelper.SafeCacheRefresh("FloorAttributeManager");
|
||||
|
||||
// 属性清除成功,清除分层缓存确保下次预览使用最新数据
|
||||
try
|
||||
{
|
||||
SimplifiedModelSplitterManager.Instance?.ClearCache();
|
||||
LogManager.Info("[FloorAttributeManager] 属性清除成功,已清除分层缓存");
|
||||
}
|
||||
catch (Exception cacheEx)
|
||||
{
|
||||
LogManager.Warning($"[FloorAttributeManager] 清除缓存时出错: {cacheEx.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
@ -686,48 +606,6 @@ namespace NavisworksTransport.Core
|
||||
|
||||
#region 私有方法
|
||||
|
||||
/// <summary>
|
||||
/// 直接获取对象的楼层属性(不进行继承查找)
|
||||
/// </summary>
|
||||
private string GetFloorLevelDirect(ModelItem item)
|
||||
{
|
||||
if (item == null) return null;
|
||||
|
||||
try
|
||||
{
|
||||
return ExecuteWithUIThread(() =>
|
||||
{
|
||||
ComApi.InwOpState10 state = ComApiBridge.State;
|
||||
ComApi.InwOaPath comPath = ComApiBridge.ToInwOaPath(item);
|
||||
ComApi.InwGUIPropertyNode2 propertyNode =
|
||||
(ComApi.InwGUIPropertyNode2)state.GetGUIPropertyNode(comPath, false);
|
||||
|
||||
// 遍历所有属性分类
|
||||
foreach (ComApi.InwGUIAttribute2 attribute in propertyNode.GUIAttributes())
|
||||
{
|
||||
if (attribute.ClassUserName == FLOOR_CATEGORY)
|
||||
{
|
||||
// 在楼层属性分类中查找Floor_Level属性
|
||||
foreach (ComApi.InwOaProperty property in attribute.Properties())
|
||||
{
|
||||
if (property.name == FLOOR_LEVEL_PROPERTY)
|
||||
{
|
||||
return property.value?.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"[FloorAttributeManager] 直接获取楼层属性失败:{ex.Message}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加楼层属性到属性分类
|
||||
/// </summary>
|
||||
|
||||
@ -38,6 +38,11 @@ namespace NavisworksTransport
|
||||
string GroupTypeName { get; }
|
||||
string UnclassifiedLabel { get; }
|
||||
Dictionary<string, GroupItem> GroupItems(ModelItemCollection items, SplitConfiguration config);
|
||||
|
||||
/// <summary>
|
||||
/// 提取单个节点的属性值,用于智能遍历
|
||||
/// </summary>
|
||||
string ExtractAttributeValue(ModelItem node);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -66,6 +71,90 @@ namespace NavisworksTransport
|
||||
_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>();
|
||||
@ -140,6 +229,15 @@ namespace NavisworksTransport
|
||||
|
||||
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>();
|
||||
@ -219,7 +317,7 @@ namespace NavisworksTransport
|
||||
|
||||
protected override string GetAttributeValue(ModelItem item)
|
||||
{
|
||||
return _floorManager.GetFloorLevel(item, true);
|
||||
return _floorManager.GetFloorLevel(item);
|
||||
}
|
||||
}
|
||||
|
||||
@ -233,7 +331,7 @@ namespace NavisworksTransport
|
||||
|
||||
protected override string GetAttributeValue(ModelItem item)
|
||||
{
|
||||
return _floorManager.GetZoneAttribute(item, true); // 启用继承查询
|
||||
return _floorManager.GetZoneAttribute(item);
|
||||
}
|
||||
}
|
||||
|
||||
@ -247,7 +345,7 @@ namespace NavisworksTransport
|
||||
|
||||
protected override string GetAttributeValue(ModelItem item)
|
||||
{
|
||||
return _floorManager.GetSubSystemAttribute(item, true); // 启用继承查询
|
||||
return _floorManager.GetSubSystemAttribute(item);
|
||||
}
|
||||
}
|
||||
|
||||
@ -309,14 +407,12 @@ namespace NavisworksTransport
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 简化的分层预览结果
|
||||
/// 分层预览结果
|
||||
/// </summary>
|
||||
public class SplitPreviewResult
|
||||
{
|
||||
public string LayerName { get; set; }
|
||||
public int ItemCount { get; set; }
|
||||
public long EstimatedFileSize { get; set; }
|
||||
public string Status { 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>();
|
||||
|
||||
@ -337,6 +433,11 @@ namespace NavisworksTransport
|
||||
|
||||
#region 私有字段
|
||||
|
||||
/// <summary>
|
||||
/// 静态实例,方便其他类调用缓存清除功能
|
||||
/// </summary>
|
||||
public static SimplifiedModelSplitterManager Instance { get; private set; }
|
||||
|
||||
private readonly FloorDetector _floorDetector;
|
||||
|
||||
// 楼层检测结果缓存
|
||||
@ -349,6 +450,9 @@ namespace NavisworksTransport
|
||||
|
||||
public SimplifiedModelSplitterManager()
|
||||
{
|
||||
// 设置静态实例
|
||||
Instance = this;
|
||||
|
||||
_floorDetector = new FloorDetector();
|
||||
|
||||
// 初始化缓存
|
||||
@ -446,15 +550,15 @@ namespace NavisworksTransport
|
||||
{
|
||||
try
|
||||
{
|
||||
LogManager.Info($"[SimplifiedModelSplitter] 开始预览分层,策略: {config.Strategy},深度限制: {config.MaxDepth}");
|
||||
LogManager.Info($"[SimplifiedModelSplitter] 开始智能遍历分层预览,策略: {config.Strategy},深度限制: {config.MaxDepth}");
|
||||
|
||||
// 步骤1:初始化和缓存检查 (0-10%)
|
||||
OnStatusChanged("正在初始化分层预览...");
|
||||
OnProgressChanged(new ProgressChangedEventArgs(0, "准备分层配置"));
|
||||
OnStatusChanged("正在初始化智能分层预览...");
|
||||
OnProgressChanged(new ProgressChangedEventArgs(0, "准备智能遍历配置"));
|
||||
|
||||
// 生成缓存键
|
||||
string cacheKey = GenerateCacheKey(config);
|
||||
LogManager.Info($"[SimplifiedModelSplitter] 生成缓存键: {cacheKey}");
|
||||
// 生成缓存键(注意:智能遍历的缓存键需要区别于原有方式)
|
||||
string cacheKey = GenerateSmartTraversalCacheKey(config);
|
||||
LogManager.Info($"[SimplifiedModelSplitter] 生成智能遍历缓存键: {cacheKey}");
|
||||
|
||||
OnProgressChanged(new ProgressChangedEventArgs(5, "检查缓存"));
|
||||
|
||||
@ -468,44 +572,31 @@ namespace NavisworksTransport
|
||||
return cachedResults;
|
||||
}
|
||||
|
||||
// 步骤2:获取模型元素 (10-30%)
|
||||
OnStatusChanged("正在获取模型元素...");
|
||||
OnProgressChanged(new ProgressChangedEventArgs(10, $"获取深度 {config.MaxDepth} 级的模型元素"));
|
||||
// 步骤2:验证文档状态 (10-15%)
|
||||
OnStatusChanged("正在验证模型文档...");
|
||||
OnProgressChanged(new ProgressChangedEventArgs(10, "验证Navisworks文档状态"));
|
||||
|
||||
var allItems = GetAllModelItems(config.MaxDepth);
|
||||
if (allItems.Count == 0)
|
||||
var document = NavisApplication.ActiveDocument;
|
||||
if (document?.Models?.Count == 0)
|
||||
{
|
||||
throw new InvalidOperationException("当前文档中没有模型元素");
|
||||
throw new InvalidOperationException("当前文档中没有模型");
|
||||
}
|
||||
|
||||
OnProgressChanged(new ProgressChangedEventArgs(15, $"文档验证完成,包含 {document.Models.Count} 个模型"));
|
||||
LogManager.Info($"[SimplifiedModelSplitter] 文档验证完成,包含 {document.Models.Count} 个模型");
|
||||
|
||||
OnProgressChanged(new ProgressChangedEventArgs(30, $"获取到 {allItems.Count} 个模型元素"));
|
||||
LogManager.Info($"[SimplifiedModelSplitter] 获取到 {allItems.Count} 个模型元素(深度: {config.MaxDepth}级)");
|
||||
|
||||
// 步骤3:执行分层分析 (30-90%)
|
||||
// 步骤3:执行智能遍历分层分析 (15-90%)
|
||||
OnStatusChanged($"正在执行{GetStrategyDisplayName(config.Strategy)}...");
|
||||
OnProgressChanged(new ProgressChangedEventArgs(35, "开始分层分析"));
|
||||
OnProgressChanged(new ProgressChangedEventArgs(20, "开始智能遍历分析"));
|
||||
|
||||
var previewResults = new List<SplitPreviewResult>();
|
||||
var strategy = CreateStrategy(config.Strategy);
|
||||
|
||||
// 关键改变:直接使用智能遍历,不再预收集所有节点
|
||||
LogManager.Info($"[SimplifiedModelSplitter] 使用智能遍历算法,策略: {strategy.GroupTypeName}");
|
||||
previewResults = PreviewSplitWithSmartTraversal(config, strategy);
|
||||
|
||||
switch (config.Strategy)
|
||||
{
|
||||
case SplitStrategy.BySmartFloorDetection:
|
||||
previewResults = PreviewSplitByAttribute(allItems, config, new FloorDetectionStrategy(_floorDetector));
|
||||
break;
|
||||
case SplitStrategy.ByFloorAttribute:
|
||||
previewResults = PreviewSplitByAttribute(allItems, config, new FloorAttributeStrategy());
|
||||
break;
|
||||
case SplitStrategy.ByZoneAttribute:
|
||||
previewResults = PreviewSplitByAttribute(allItems, config, new ZoneAttributeStrategy());
|
||||
break;
|
||||
case SplitStrategy.BySubSystemAttribute:
|
||||
previewResults = PreviewSplitByAttribute(allItems, config, new SubSystemAttributeStrategy());
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException($"不支持的分层策略: {config.Strategy}");
|
||||
}
|
||||
|
||||
OnProgressChanged(new ProgressChangedEventArgs(90, $"分析完成,识别到 {previewResults.Count} 个分层"));
|
||||
OnProgressChanged(new ProgressChangedEventArgs(90, $"智能分析完成,识别到 {previewResults.Count} 个分层"));
|
||||
|
||||
// 步骤4:缓存结果和完成 (90-100%)
|
||||
OnStatusChanged("正在保存分析结果...");
|
||||
@ -515,16 +606,16 @@ namespace NavisworksTransport
|
||||
SaveToCache(config.Strategy, cacheKey, previewResults);
|
||||
|
||||
// 完成
|
||||
OnStatusChanged($"预览完成,识别到 {previewResults.Count} 个分层");
|
||||
OnStatusChanged($"智能预览完成,识别到 {previewResults.Count} 个分层");
|
||||
OnProgressChanged(new ProgressChangedEventArgs(100, $"预览完成,共 {previewResults.Count} 个分层"));
|
||||
|
||||
LogManager.Info($"[SimplifiedModelSplitter] 预览完成,共识别 {previewResults.Count} 个分层(深度: {config.MaxDepth}级),已缓存");
|
||||
LogManager.Info($"[SimplifiedModelSplitter] 智能遍历预览完成,共识别 {previewResults.Count} 个分层(深度: {config.MaxDepth}级),已缓存");
|
||||
|
||||
return previewResults;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"[SimplifiedModelSplitter] 预览分层失败: {ex.Message}");
|
||||
LogManager.Error($"[SimplifiedModelSplitter] 智能遍历预览失败: {ex.Message}", ex);
|
||||
OnStatusChanged($"预览失败: {ex.Message}");
|
||||
OnProgressChanged(new ProgressChangedEventArgs(0, $"预览失败: {ex.Message}"));
|
||||
throw;
|
||||
@ -539,6 +630,36 @@ namespace NavisworksTransport
|
||||
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>
|
||||
/// 从缓存获取结果
|
||||
@ -638,7 +759,6 @@ namespace NavisworksTransport
|
||||
string errorMsg = $"分层 {preview.LayerName} 处理失败: {layerEx.Message}";
|
||||
LogManager.Error($"[SimplifiedModelSplitter] {errorMsg}");
|
||||
failedLayers.Add(preview.LayerName);
|
||||
preview.Status = "处理失败";
|
||||
|
||||
// 继续处理其他分层,不因单个失败而中断整个进程
|
||||
OnStatusChanged(errorMsg);
|
||||
@ -745,7 +865,6 @@ namespace NavisworksTransport
|
||||
string errorMsg = $"分层 {preview.LayerName} 处理失败: {layerEx.Message}";
|
||||
LogManager.Error($"[SimplifiedModelSplitter] {errorMsg}");
|
||||
failedLayers.Add(preview.LayerName);
|
||||
preview.Status = "处理失败";
|
||||
|
||||
// 继续处理其他分层,不因单个失败而中断整个进程
|
||||
OnStatusChanged(errorMsg);
|
||||
@ -909,9 +1028,7 @@ namespace NavisworksTransport
|
||||
var previewResult = new SplitPreviewResult
|
||||
{
|
||||
LayerName = SanitizeLayerName(group.GroupName),
|
||||
ItemCount = group.Items.Count,
|
||||
EstimatedFileSize = EstimateFileSize(group.Items.Count),
|
||||
Status = "就绪",
|
||||
LayerAttribute = GetAttributeDescription(config.Strategy, group.GroupName, group.Metadata),
|
||||
Items = new ModelItemCollection()
|
||||
};
|
||||
|
||||
@ -964,9 +1081,133 @@ namespace NavisworksTransport
|
||||
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>
|
||||
/// 处理单个分层(异步版本)
|
||||
@ -975,7 +1216,7 @@ namespace NavisworksTransport
|
||||
{
|
||||
try
|
||||
{
|
||||
LogManager.Info($"[SimplifiedModelSplitter] 开始处理分层: {preview.LayerName}, 元素数量: {preview.ItemCount}");
|
||||
LogManager.Info($"[SimplifiedModelSplitter] 开始处理分层: {preview.LayerName}, 类型: {preview.LayerAttribute}");
|
||||
|
||||
// 检查取消请求
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
@ -992,19 +1233,16 @@ namespace NavisworksTransport
|
||||
if (success)
|
||||
{
|
||||
LogManager.Info($"[SimplifiedModelSplitter] 分层 {preview.LayerName} 导出成功: {outputPath}");
|
||||
preview.Status = "导出成功";
|
||||
}
|
||||
else
|
||||
{
|
||||
LogManager.Error($"[SimplifiedModelSplitter] 分层 {preview.LayerName} 导出失败");
|
||||
preview.Status = "导出失败";
|
||||
throw new InvalidOperationException($"分层 {preview.LayerName} 导出失败");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"[SimplifiedModelSplitter] 处理分层失败 {preview.LayerName}: {ex.Message}");
|
||||
preview.Status = "导出异常";
|
||||
throw;
|
||||
}
|
||||
}
|
||||
@ -1016,7 +1254,7 @@ namespace NavisworksTransport
|
||||
{
|
||||
try
|
||||
{
|
||||
LogManager.Info($"[SimplifiedModelSplitter] 开始同步处理分层: {preview.LayerName}, 元素数量: {preview.ItemCount}");
|
||||
LogManager.Info($"[SimplifiedModelSplitter] 开始同步处理分层: {preview.LayerName}, 类型: {preview.LayerAttribute}");
|
||||
|
||||
if (preview.Items == null || preview.Items.Count == 0)
|
||||
{
|
||||
@ -1049,19 +1287,16 @@ namespace NavisworksTransport
|
||||
if (success)
|
||||
{
|
||||
LogManager.Info($"[SimplifiedModelSplitter] 分层 {preview.LayerName} 导出成功: {outputPath}");
|
||||
preview.Status = "导出成功";
|
||||
}
|
||||
else
|
||||
{
|
||||
LogManager.Error($"[SimplifiedModelSplitter] 分层 {preview.LayerName} 导出失败");
|
||||
preview.Status = "导出失败";
|
||||
throw new InvalidOperationException($"分层 {preview.LayerName} 导出失败");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"[SimplifiedModelSplitter] 同步处理分层失败 {preview.LayerName}: {ex.Message}");
|
||||
preview.Status = "导出异常";
|
||||
throw;
|
||||
}
|
||||
}
|
||||
@ -1116,6 +1351,91 @@ namespace NavisworksTransport
|
||||
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>
|
||||
@ -2140,9 +2460,8 @@ namespace NavisworksTransport
|
||||
var testPreview = new SplitPreviewResult
|
||||
{
|
||||
LayerName = "测试导出",
|
||||
ItemCount = testItems.Count,
|
||||
Items = testItems,
|
||||
Status = "测试中"
|
||||
LayerAttribute = "测试",
|
||||
Items = testItems
|
||||
};
|
||||
|
||||
// 创建测试配置
|
||||
|
||||
@ -426,9 +426,9 @@ namespace NavisworksTransport.UI.WPF.Commands
|
||||
var previewItems = previewResults.Select(result => new SplitPreviewItem
|
||||
{
|
||||
LayerName = result.LayerName,
|
||||
ObjectCount = result.ItemCount,
|
||||
EstimatedSize = FormatFileSize(result.EstimatedFileSize),
|
||||
Status = "就绪",
|
||||
LayerAttribute = result.LayerAttribute ?? GetLayerAttributeDescription(_config.Strategy, result.LayerName),
|
||||
EstimatedSize = "0 KB", // 不再显示文件大小
|
||||
Status = "就绪", // 保持UI兼容性
|
||||
IsSelectedForSave = result.IsSelectedForSave,
|
||||
Items = result.Items
|
||||
}).ToList();
|
||||
@ -478,6 +478,33 @@ namespace NavisworksTransport.UI.WPF.Commands
|
||||
return $"{bytes / KB:F1} KB";
|
||||
return $"{bytes} B";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据分层策略和分层名称生成属性描述
|
||||
/// </summary>
|
||||
/// <summary>
|
||||
/// 根据分层策略和分层名称生成属性描述
|
||||
/// </summary>
|
||||
private string GetLayerAttributeDescription(SimplifiedModelSplitterManager.SplitStrategy strategy, string layerName)
|
||||
{
|
||||
switch (strategy)
|
||||
{
|
||||
case SimplifiedModelSplitterManager.SplitStrategy.BySmartFloorDetection:
|
||||
return "智能楼层检测";
|
||||
|
||||
case SimplifiedModelSplitterManager.SplitStrategy.ByFloorAttribute:
|
||||
return "按楼层属性";
|
||||
|
||||
case SimplifiedModelSplitterManager.SplitStrategy.ByZoneAttribute:
|
||||
return "按区域属性";
|
||||
|
||||
case SimplifiedModelSplitterManager.SplitStrategy.BySubSystemAttribute:
|
||||
return "按子系统属性";
|
||||
|
||||
default:
|
||||
return "未知属性";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -10,7 +10,7 @@ namespace NavisworksTransport.UI.WPF.Models
|
||||
public class SplitPreviewItem : INotifyPropertyChanged
|
||||
{
|
||||
private string _layerName;
|
||||
private int _objectCount;
|
||||
private string _layerAttribute;
|
||||
private string _estimatedSize;
|
||||
private string _status;
|
||||
|
||||
@ -33,15 +33,18 @@ namespace NavisworksTransport.UI.WPF.Models
|
||||
/// <summary>
|
||||
/// 对象数量
|
||||
/// </summary>
|
||||
public int ObjectCount
|
||||
/// <summary>
|
||||
/// 分层属性
|
||||
/// </summary>
|
||||
public string LayerAttribute
|
||||
{
|
||||
get => _objectCount;
|
||||
get => _layerAttribute;
|
||||
set
|
||||
{
|
||||
if (_objectCount != value)
|
||||
if (_layerAttribute != value)
|
||||
{
|
||||
_objectCount = value;
|
||||
OnPropertyChanged(nameof(ObjectCount));
|
||||
_layerAttribute = value;
|
||||
OnPropertyChanged(nameof(LayerAttribute));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,6 +56,8 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
private bool _needsManualFloorSetup;
|
||||
private bool _showPreviewResults;
|
||||
private bool _showPreviewPrompt = true;
|
||||
private bool _showPreviewInfo;
|
||||
private string _previewInfoMessage = "";
|
||||
private string _floorAnalysisResult = "点击[分析楼层]开始检测";
|
||||
private Brush _floorAnalysisResultColor = Brushes.Gray;
|
||||
private string _selectedFloorAttribute;
|
||||
@ -237,7 +239,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
case "5级":
|
||||
return 5;
|
||||
case "全部":
|
||||
return 0;
|
||||
return 1000;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
@ -390,6 +392,24 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
set => SetPropertyThreadSafe(ref _showPreviewPrompt, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否显示预览信息
|
||||
/// </summary>
|
||||
public bool ShowPreviewInfo
|
||||
{
|
||||
get => _showPreviewInfo;
|
||||
set => SetPropertyThreadSafe(ref _showPreviewInfo, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 预览信息提示消息
|
||||
/// </summary>
|
||||
public string PreviewInfoMessage
|
||||
{
|
||||
get => _previewInfoMessage;
|
||||
set => SetPropertyThreadSafe(ref _previewInfoMessage, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前选择文本
|
||||
/// </summary>
|
||||
@ -704,7 +724,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
// 检查是否有任何选中模型拥有分层属性
|
||||
foreach (ModelItem item in document.CurrentSelection.SelectedItems)
|
||||
{
|
||||
string floorLevel = floorManager.GetFloorLevel(item, false); // 不搜索父节点
|
||||
string floorLevel = floorManager.GetFloorLevel(item);
|
||||
if (!string.IsNullOrEmpty(floorLevel))
|
||||
{
|
||||
return true; // 只要找到一个有属性的就可以清除
|
||||
@ -923,6 +943,10 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
CurrentOperationText = "正在分析楼层...";
|
||||
ProgressDetailText = "检测模型中的楼层属性";
|
||||
ProgressPercentage = 0;
|
||||
|
||||
// 初始化预览状态
|
||||
ShowPreviewInfo = true;
|
||||
PreviewInfoMessage = "正在使用智能遍历模式快速生成预览,仅显示关键节点...";
|
||||
});
|
||||
|
||||
try
|
||||
@ -1165,14 +1189,14 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
// 显示加载状态
|
||||
ShowPreviewResults = false;
|
||||
ShowPreviewPrompt = false;
|
||||
ShowPreviewInfo = true;
|
||||
PreviewInfoMessage = "正在使用智能遍历模式快速生成预览...";
|
||||
|
||||
// 添加加载提示项
|
||||
var loadingItem = new SplitPreviewItem
|
||||
{
|
||||
LayerName = "正在分析...",
|
||||
ObjectCount = 0,
|
||||
EstimatedSize = "0 KB",
|
||||
Status = "分析中,请稍候..."
|
||||
LayerAttribute = "分析中"
|
||||
};
|
||||
SplitPreviewResults.Add(loadingItem);
|
||||
ShowPreviewResults = true;
|
||||
@ -1218,23 +1242,18 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
|
||||
ShowPreviewResults = true;
|
||||
ShowPreviewPrompt = false;
|
||||
ShowPreviewInfo = true;
|
||||
PreviewInfoMessage = $"预览完成:共检测到 {SplitPreviewResults.Count} 个分层(智能遍历仅显示关键节点)";
|
||||
ProgressDetailText = $"预览完成,共 {SplitPreviewResults.Count} 个分层";
|
||||
}
|
||||
else
|
||||
{
|
||||
// 显示错误信息
|
||||
var errorItem = new SplitPreviewItem
|
||||
{
|
||||
LayerName = "错误提示",
|
||||
ObjectCount = 0,
|
||||
EstimatedSize = "0 KB",
|
||||
Status = result.ErrorMessage ?? "预览失败,请检查模型和设置"
|
||||
};
|
||||
SplitPreviewResults.Add(errorItem);
|
||||
|
||||
ShowPreviewResults = true;
|
||||
ShowPreviewPrompt = false;
|
||||
ProgressDetailText = result.ErrorMessage ?? "预览失败,请检查模型和设置";
|
||||
// 预览失败或无结果,不在列表中显示错误项,而是隐藏结果列表并显示提示
|
||||
ShowPreviewResults = false;
|
||||
ShowPreviewPrompt = true; // 显示提示信息
|
||||
ShowPreviewInfo = true; // 显示预览信息提示
|
||||
PreviewInfoMessage = result.ErrorMessage ?? "未找到任何分层属性,请先设置模型的分层属性(楼层、区域或子系统)";
|
||||
ProgressDetailText = result.ErrorMessage ?? "未找到任何分层属性,请先设置模型的分层属性(楼层、区域或子系统)";
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -1245,20 +1264,13 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
// 异常UI更新
|
||||
await _uiStateManager.ExecuteUIUpdateAsync(() =>
|
||||
{
|
||||
// 清空加载提示,显示异常信息
|
||||
// 清空加载提示,隐藏结果列表并显示异常提示
|
||||
SplitPreviewResults.Clear();
|
||||
|
||||
var errorItem = new SplitPreviewItem
|
||||
{
|
||||
LayerName = "异常错误",
|
||||
ObjectCount = 0,
|
||||
EstimatedSize = "0 KB",
|
||||
Status = $"预览异常: {ex.Message}"
|
||||
};
|
||||
SplitPreviewResults.Add(errorItem);
|
||||
|
||||
ShowPreviewResults = true;
|
||||
ShowPreviewPrompt = false;
|
||||
ShowPreviewResults = false;
|
||||
ShowPreviewPrompt = true; // 显示提示信息
|
||||
ShowPreviewInfo = true; // 显示预览信息提示
|
||||
PreviewInfoMessage = $"预览异常: {ex.Message}";
|
||||
ProgressDetailText = $"预览异常: {ex.Message}";
|
||||
});
|
||||
}
|
||||
@ -1269,7 +1281,11 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
{
|
||||
IsProcessing = false;
|
||||
ShowCancelButton = false;
|
||||
CurrentOperationText = "";
|
||||
// 只有在预览成功时才清空操作文本,失败时保留提示信息
|
||||
if (SplitPreviewResults.Count > 0)
|
||||
{
|
||||
CurrentOperationText = "";
|
||||
}
|
||||
ProgressPercentage = 0;
|
||||
});
|
||||
}
|
||||
@ -1343,9 +1359,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
var previewResultsForSave = layersToSave.Select(item => new SimplifiedModelSplitterManager.SplitPreviewResult
|
||||
{
|
||||
LayerName = item.LayerName,
|
||||
ItemCount = item.ObjectCount,
|
||||
EstimatedFileSize = item.EstimatedFileSize,
|
||||
Status = item.Status,
|
||||
LayerAttribute = item.LayerAttribute,
|
||||
Items = item.Items,
|
||||
IsSelectedForSave = item.IsSelectedForSave
|
||||
}).ToList();
|
||||
@ -1440,7 +1454,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
string errorMsg = $"分层 {preview.LayerName} 处理失败: {layerEx.Message}";
|
||||
LogManager.Error($"[LayerManagementViewModel] {errorMsg}");
|
||||
failedLayers.Add(preview.LayerName);
|
||||
preview.Status = "处理失败";
|
||||
|
||||
// 继续处理其他分层,不因单个失败而中断整个进程
|
||||
await _uiStateManager.ExecuteUIUpdateAsync(() =>
|
||||
@ -1489,7 +1502,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
{
|
||||
try
|
||||
{
|
||||
LogManager.Info($"[LayerManagementViewModel] 开始处理分层: {preview.LayerName}, 元素数量: {preview.ItemCount}");
|
||||
LogManager.Info($"[LayerManagementViewModel] 开始处理分层: {preview.LayerName}, 类型: {preview.LayerAttribute}");
|
||||
|
||||
// 检查取消请求
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
@ -1525,19 +1538,16 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
if (success)
|
||||
{
|
||||
LogManager.Info($"[LayerManagementViewModel] 分层 {preview.LayerName} 导出成功: {outputPath}");
|
||||
preview.Status = "导出成功";
|
||||
}
|
||||
else
|
||||
{
|
||||
LogManager.Error($"[LayerManagementViewModel] 分层 {preview.LayerName} 导出失败");
|
||||
preview.Status = "导出失败";
|
||||
throw new InvalidOperationException($"分层 {preview.LayerName} 导出失败");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"[LayerManagementViewModel] 处理分层失败 {preview.LayerName}: {ex.Message}");
|
||||
preview.Status = "导出异常";
|
||||
throw;
|
||||
}
|
||||
}
|
||||
@ -3212,7 +3222,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
{
|
||||
try
|
||||
{
|
||||
string floorLevel = floorManager.GetFloorLevel(item, true);
|
||||
string floorLevel = floorManager.GetFloorLevel(item);
|
||||
string itemName = item.DisplayName ?? "未命名";
|
||||
|
||||
if (!string.IsNullOrEmpty(floorLevel))
|
||||
|
||||
@ -234,7 +234,7 @@ NavisworksTransport 分层管理页签视图 - 重构优化版本
|
||||
</GridViewColumn.CellTemplate>
|
||||
</GridViewColumn>
|
||||
<GridViewColumn Header="分层名称" DisplayMemberBinding="{Binding LayerName}" Width="120"/>
|
||||
<GridViewColumn Header="对象数量" DisplayMemberBinding="{Binding ItemCount}" Width="80"/>
|
||||
<GridViewColumn Header="分层属性" DisplayMemberBinding="{Binding LayerAttribute}" Width="80"/>
|
||||
<GridViewColumn Header="是否保存" Width="80">
|
||||
<GridViewColumn.HeaderContainerStyle>
|
||||
<Style TargetType="GridViewColumnHeader">
|
||||
@ -286,6 +286,16 @@ NavisworksTransport 分层管理页签视图 - 重构优化版本
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<!-- 预览信息提示区域 -->
|
||||
<StackPanel Margin="0,5,0,0"
|
||||
Visibility="{Binding ShowPreviewInfo, Converter={StaticResource BoolToVisConverter}}">
|
||||
<TextBlock Text="{Binding PreviewInfoMessage}"
|
||||
Style="{StaticResource StatusTextStyle}"
|
||||
TextWrapping="Wrap"
|
||||
HorizontalAlignment="Left"
|
||||
Margin="5,0,5,0"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user