TellmeRevitPluging/Services/ShellOptimizer.cs
2025-12-09 17:43:30 +08:00

361 lines
12 KiB
C#

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Autodesk.Revit.DB;
using RevitHttpControl.Models;
namespace RevitHttpControl.Services
{
/// <summary>
/// 薄壳优化执行服务
/// </summary>
public class ShellOptimizer
{
private readonly ShellAnalyzer _analyzer;
public ShellOptimizer()
{
_analyzer = new ShellAnalyzer();
}
/// <summary>
/// 执行薄壳优化
/// </summary>
public ShellOptimizeResult ExecuteOptimization(Document doc, ShellOptimizeMode mode, bool backupOriginal = true)
{
if (doc == null)
throw new ArgumentNullException(nameof(doc));
var stopwatch = Stopwatch.StartNew();
var result = new ShellOptimizeResult();
try
{
// 1. 获取原始文件大小
var originalSize = GetDocumentFileSize(doc);
result.OriginalSize = FormatFileSize(originalSize);
// 2. 分析模型获取删除列表
var analysis = _analyzer.AnalyzeModel(doc, mode);
var elementsToDelete = GetElementsToDelete(doc, analysis);
// 3. 创建备份(如果需要)
if (backupOriginal)
{
result.BackupPath = CreateBackup(doc);
}
// 4. 执行删除操作
var deletedCount = DeleteElements(doc, elementsToDelete);
result.RemovedCount = deletedCount;
// 5. 保存文档并计算优化后大小
SaveDocument(doc);
var optimizedSize = GetDocumentFileSize(doc);
result.OptimizedSize = FormatFileSize(optimizedSize);
// 6. 计算减少百分比
if (originalSize > 0)
{
var reduction = ((double)(originalSize - optimizedSize) / originalSize) * 100;
result.Reduction = $"{reduction:F1}%";
}
else
{
result.Reduction = "0%";
}
stopwatch.Stop();
result.ProcessingTimeSeconds = stopwatch.Elapsed.TotalSeconds;
return result;
}
catch (Exception ex)
{
stopwatch.Stop();
result.ProcessingTimeSeconds = stopwatch.Elapsed.TotalSeconds;
// 如果有备份且操作失败,可以考虑恢复备份
throw new InvalidOperationException($"薄壳优化执行失败: {ex.Message}", ex);
}
}
/// <summary>
/// 根据分析结果获取需要删除的构件
/// </summary>
private List<ElementId> GetElementsToDelete(Document doc, ShellAnalyzeResponse analysis)
{
var elementsToDelete = new List<ElementId>();
// 重新分析获取详细的构件列表(为了安全性)
var analyzer = new ShellAnalyzer();
var detailedAnalysis = analyzer.AnalyzeModel(doc, ShellOptimizeMode.Standard);
// 获取所有需要删除的构件
var allElements = new FilteredElementCollector(doc)
.WhereElementIsNotElementType()
.WhereElementIsViewIndependent()
.ToElements();
foreach (var element in allElements)
{
if (ShouldDeleteElement(element, analysis))
{
elementsToDelete.Add(element.Id);
}
}
return elementsToDelete;
}
/// <summary>
/// 判断构件是否应该删除
/// </summary>
private bool ShouldDeleteElement(Element element, ShellAnalyzeResponse analysis)
{
if (element.Category == null)
return false;
var categoryName = element.Category.Name;
var categoryStats = analysis.Categories.FirstOrDefault(c => c.Name == categoryName);
// 如果该类别没有删除项,则不删除
if (categoryStats == null || categoryStats.Remove == 0)
return false;
// 这里可以实现更复杂的逻辑,比如优先删除某些构件
// 目前简化为按类别统计比例删除
return true;
}
/// <summary>
/// 批量删除构件
/// </summary>
private int DeleteElements(Document doc, List<ElementId> elementIds)
{
if (elementIds == null || elementIds.Count == 0)
return 0;
int deletedCount = 0;
const int batchSize = 100; // 批量处理大小
// 分批删除以提高性能和稳定性
for (int i = 0; i < elementIds.Count; i += batchSize)
{
var batch = elementIds.Skip(i).Take(batchSize).ToList();
deletedCount += DeleteElementBatch(doc, batch);
}
return deletedCount;
}
/// <summary>
/// 删除一批构件
/// </summary>
private int DeleteElementBatch(Document doc, List<ElementId> elementIds)
{
using (var transaction = new Transaction(doc, "薄壳优化删除构件"))
{
transaction.Start();
try
{
// 过滤出可以删除的构件
var deletableIds = new List<ElementId>();
foreach (var id in elementIds)
{
var element = doc.GetElement(id);
if (element != null && CanDeleteElement(element))
{
deletableIds.Add(id);
}
}
// 执行删除
if (deletableIds.Count > 0)
{
var deletedIds = doc.Delete(deletableIds);
transaction.Commit();
return deletedIds.Count;
}
else
{
transaction.RollBack();
return 0;
}
}
catch (Exception ex)
{
transaction.RollBack();
// 记录错误但继续处理其他构件
System.Diagnostics.Debug.WriteLine($"删除构件批次失败: {ex.Message}");
return 0;
}
}
}
/// <summary>
/// 检查构件是否可以安全删除
/// </summary>
private bool CanDeleteElement(Element element)
{
try
{
// 检查构件是否被锁定
if (element.Pinned)
return false;
// 检查构件是否在工作集中被其他用户编辑
var worksetId = element.WorksetId;
if (worksetId != WorksetId.InvalidWorksetId)
{
var doc = element.Document;
var worksetTable = doc.GetWorksetTable();
var workset = worksetTable.GetWorkset(worksetId);
if (workset.IsOpen && workset.Owner != doc.Application.Username)
return false;
}
// 检查是否有依赖关系(如主体构件)
if (HasCriticalDependencies(element))
return false;
return true;
}
catch
{
// 如果检查过程出错,为安全起见不删除
return false;
}
}
/// <summary>
/// 检查构件是否有关键依赖关系
/// </summary>
private bool HasCriticalDependencies(Element element)
{
try
{
// 对于墙体,检查是否有门窗等构件托管在上面
if (element is Wall wall)
{
var doc = wall.Document;
var collector = new FilteredElementCollector(doc);
var familyInstances = collector.OfClass(typeof(FamilyInstance)).ToElements();
// 检查是否有门窗托管在这面墙上
foreach (Element e in familyInstances)
{
var familyInstance = e as FamilyInstance;
if (familyInstance?.Host?.Id == wall.Id)
{
return true; // 有构件托管在这面墙上,不能删除
}
}
}
return false;
}
catch
{
return true; // 无法确定时,为安全起见认为有依赖
}
}
/// <summary>
/// 创建文件备份
/// </summary>
private string CreateBackup(Document doc)
{
try
{
var originalPath = doc.PathName;
if (string.IsNullOrEmpty(originalPath))
{
// 如果文档未保存,先保存
throw new InvalidOperationException("文档必须先保存才能创建备份");
}
var directory = Path.GetDirectoryName(originalPath);
var fileName = Path.GetFileNameWithoutExtension(originalPath);
var extension = Path.GetExtension(originalPath);
var timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss");
var backupFileName = $"{fileName}_backup_{timestamp}{extension}";
var backupPath = Path.Combine(directory, backupFileName);
// 复制文件
File.Copy(originalPath, backupPath, false);
return backupPath;
}
catch (Exception ex)
{
throw new InvalidOperationException($"创建备份失败: {ex.Message}", ex);
}
}
/// <summary>
/// 保存文档
/// </summary>
private void SaveDocument(Document doc)
{
try
{
if (doc.IsModified)
{
doc.Save();
}
}
catch (Exception ex)
{
throw new InvalidOperationException($"保存文档失败: {ex.Message}", ex);
}
}
/// <summary>
/// 获取文档文件大小
/// </summary>
private long GetDocumentFileSize(Document doc)
{
try
{
var filePath = doc.PathName;
if (string.IsNullOrEmpty(filePath) || !File.Exists(filePath))
return 0;
var fileInfo = new FileInfo(filePath);
return fileInfo.Length;
}
catch
{
return 0;
}
}
/// <summary>
/// 格式化文件大小显示
/// </summary>
private string FormatFileSize(long bytes)
{
if (bytes == 0) return "0 字节";
string[] sizes = { "字节", "KB", "MB", "GB", "TB" };
int order = 0;
double size = bytes;
while (size >= 1024 && order < sizes.Length - 1)
{
order++;
size /= 1024;
}
return $"{size:F2} {sizes[order]}";
}
}
}