using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using RevitHttpControl.Models;
namespace RevitHttpControl.Services
{
///
/// Revit API 操作服务
///
public static class RevitService
{
///
/// 获取当前文档信息
///
/// 当前文档信息
public static CurrentDocumentInfo GetCurrentDocumentInfo()
{
var documentInfo = new CurrentDocumentInfo
{
IsOpen = false,
FileName = null,
FilePath = null
};
try
{
// 尝试获取当前活动文档信息
if (App.Instance != null)
{
// 通过队列执行获取文档信息的操作
var docInfoResult = new CurrentDocumentInfo
{
IsOpen = false,
FileName = null,
FilePath = null
};
var completed = false;
Exception executionException = null;
App.Instance.EnqueueCommand(uiApp =>
{
try
{
System.Diagnostics.Debug.WriteLine("RevitService: Getting document info...");
var activeDoc = uiApp.ActiveUIDocument?.Document;
if (activeDoc != null)
{
System.Diagnostics.Debug.WriteLine($"RevitService: Found active document: {activeDoc.Title}");
docInfoResult.IsOpen = true;
// 处理文档路径
var pathName = activeDoc.PathName;
if (!string.IsNullOrEmpty(pathName))
{
docInfoResult.FileName = Path.GetFileName(pathName);
docInfoResult.FilePath = pathName;
System.Diagnostics.Debug.WriteLine($"RevitService: Document path: {pathName}");
}
else
{
// 对于未保存的文档,使用Title
docInfoResult.FileName = activeDoc.Title;
docInfoResult.FilePath = null;
System.Diagnostics.Debug.WriteLine($"RevitService: Unsaved document: {activeDoc.Title}");
}
}
else
{
System.Diagnostics.Debug.WriteLine("RevitService: No active document found");
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"RevitService: Exception getting document info: {ex.Message}");
executionException = ex;
}
finally
{
completed = true;
}
});
// 等待命令执行完成(最多等待3秒)
var timeout = DateTime.Now.AddSeconds(3);
while (!completed && DateTime.Now < timeout)
{
System.Threading.Thread.Sleep(50);
}
if (!completed)
{
System.Diagnostics.Debug.WriteLine("RevitService: Timeout waiting for document info");
return documentInfo; // 返回默认值
}
if (executionException != null)
{
System.Diagnostics.Debug.WriteLine($"RevitService: Execution failed: {executionException.Message}");
return documentInfo; // 返回默认值
}
return docInfoResult;
}
else
{
System.Diagnostics.Debug.WriteLine("RevitService: App.Instance is null");
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"RevitService: Outer exception: {ex.Message}");
}
return documentInfo;
}
///
/// 获取元素统计数量
///
/// 统计类型
/// 元素数量
public static int GetElementCount(StatsType type)
{
try
{
var count = 0;
var completed = false;
Exception capturedException = null;
App.Instance.EnqueueCommand(uiApp =>
{
try
{
var doc = uiApp.ActiveUIDocument?.Document;
if (doc != null)
{
var collector = new FilteredElementCollector(doc);
var category = GetBuiltInCategory(type);
count = collector.OfCategory(category).Count();
}
}
catch (Exception ex)
{
capturedException = ex;
}
finally
{
completed = true;
}
});
// 等待命令执行完成(最多等待5秒)
var timeout = DateTime.Now.AddSeconds(5);
while (!completed && DateTime.Now < timeout)
{
System.Threading.Thread.Sleep(50);
}
if (capturedException != null)
throw capturedException;
return count;
}
catch (Exception ex)
{
throw new InvalidOperationException($"获取 {type} 统计数据失败: {ex.Message}", ex);
}
}
///
/// 异步获取元素统计数量
///
/// 统计类型
/// 任务ID
/// 任务管理器
public static void GetElementCountAsync(StatsType type, Guid taskId, TaskManager taskManager)
{
try
{
App.Instance.EnqueueCommand(uiApp =>
{
try
{
var doc = uiApp.ActiveUIDocument?.Document;
if (doc != null)
{
var collector = new FilteredElementCollector(doc);
var category = GetBuiltInCategory(type);
var count = collector.OfCategory(category).Count();
// 构建完整的统计响应
var statsResponse = new SyncStatsResponse
{
ElementType = type.ToString(),
Count = count,
Details = new StatsDetails
{
TypeName = GetStatsTypeDisplayName(type),
TypeId = (int)category
}
};
// 将完整结果存储到任务管理器
taskManager.CompleteTask(taskId, statsResponse);
}
else
{
taskManager.FailTask(taskId, "没有打开的文档");
}
}
catch (Exception ex)
{
taskManager.FailTask(taskId, ex.Message);
}
});
}
catch (Exception ex)
{
taskManager.FailTask(taskId, ex.Message);
}
}
///
/// 统计类型到 BuiltInCategory 的映射
///
/// 统计类型
/// 对应的 BuiltInCategory
public static BuiltInCategory GetBuiltInCategory(StatsType type)
{
switch (type)
{
case StatsType.Wall:
return BuiltInCategory.OST_Walls;
case StatsType.Door:
return BuiltInCategory.OST_Doors;
case StatsType.Window:
return BuiltInCategory.OST_Windows;
case StatsType.Floor:
return BuiltInCategory.OST_Floors;
case StatsType.Ceiling:
return BuiltInCategory.OST_Ceilings;
case StatsType.Roof:
return BuiltInCategory.OST_Roofs;
case StatsType.Column:
return BuiltInCategory.OST_Columns;
case StatsType.Beam:
return BuiltInCategory.OST_StructuralFraming;
case StatsType.Furniture:
return BuiltInCategory.OST_Furniture;
case StatsType.Room:
return BuiltInCategory.OST_Rooms;
default:
throw new ArgumentException($"不支持的统计类型: {type}");
}
}
///
/// 获取元素统计详细信息
///
/// 统计类型
/// 详细统计信息
public static SyncStatsResponse GetElementStatsDetail(StatsType type)
{
try
{
var count = 0;
var completed = false;
Exception capturedException = null;
App.Instance.EnqueueCommand(uiApp =>
{
try
{
var doc = uiApp.ActiveUIDocument?.Document;
if (doc != null)
{
var collector = new FilteredElementCollector(doc);
var category = GetBuiltInCategory(type);
count = collector.OfCategory(category).Count();
}
}
catch (Exception ex)
{
capturedException = ex;
}
finally
{
completed = true;
}
});
// 等待命令执行完成(最多等待5秒)
var timeout = DateTime.Now.AddSeconds(5);
while (!completed && DateTime.Now < timeout)
{
System.Threading.Thread.Sleep(50);
}
if (capturedException != null)
throw capturedException;
// 构建完整的响应
return new SyncStatsResponse
{
ElementType = type.ToString(),
Count = count,
Details = new StatsDetails
{
TypeName = GetStatsTypeDisplayName(type),
TypeId = (int)GetBuiltInCategory(type)
}
};
}
catch (Exception ex)
{
throw new InvalidOperationException($"获取 {type} 统计数据失败: {ex.Message}", ex);
}
}
///
/// 获取统计类型的中文显示名称
///
/// 统计类型
/// 中文名称
public static string GetStatsTypeDisplayName(StatsType type)
{
switch (type)
{
case StatsType.Wall:
return "墙体";
case StatsType.Door:
return "门";
case StatsType.Window:
return "窗";
case StatsType.Floor:
return "楼板";
case StatsType.Ceiling:
return "天花板";
case StatsType.Roof:
return "屋顶";
case StatsType.Column:
return "柱";
case StatsType.Beam:
return "梁";
case StatsType.Furniture:
return "家具";
case StatsType.Room:
return "房间";
default:
return type.ToString();
}
}
///
/// 快速获取模型总览信息
///
/// 模型总览信息
public static ModelOverviewResponse GetModelOverview()
{
try
{
ModelOverviewResponse overview = null;
var completed = false;
Exception capturedException = null;
App.Instance.EnqueueCommand(uiApp =>
{
try
{
var doc = uiApp.ActiveUIDocument?.Document;
if (doc == null)
{
throw new InvalidOperationException("没有打开的文档");
}
// 1. 项目基本信息
var filePath = doc.IsWorkshared ?
(doc.GetWorksharingCentralModelPath()?.ToString() ?? "中心文件路径未知") :
(!string.IsNullOrEmpty(doc.PathName) ? doc.PathName : "未保存");
// 获取文件大小
long fileSizeBytes = 0;
string fileSizeDisplay = "未知";
try
{
if (!string.IsNullOrEmpty(doc.PathName) && System.IO.File.Exists(doc.PathName))
{
var fileInfo = new System.IO.FileInfo(doc.PathName);
fileSizeBytes = fileInfo.Length;
fileSizeDisplay = FormatFileSize(fileSizeBytes);
}
else if (doc.IsWorkshared)
{
var centralPath = doc.GetWorksharingCentralModelPath();
if (centralPath != null)
{
var centralPathString = centralPath.ToString();
if (!string.IsNullOrEmpty(centralPathString) && System.IO.File.Exists(centralPathString))
{
var fileInfo = new System.IO.FileInfo(centralPathString);
fileSizeBytes = fileInfo.Length;
fileSizeDisplay = FormatFileSize(fileSizeBytes);
}
}
}
else
{
fileSizeDisplay = "未保存";
}
}
catch
{
fileSizeDisplay = "无法获取";
}
var projectInfo = new Models.ProjectInfo
{
Name = string.IsNullOrEmpty(doc.Title) ? "未命名项目" : doc.Title,
FilePath = filePath,
RevitVersion = uiApp.Application.VersionName,
IsCentralFile = doc.IsWorkshared,
Status = doc.IsModified ? "已修改" : "已保存",
FileSizeBytes = fileSizeBytes,
FileSizeDisplay = fileSizeDisplay,
PolygonCount = CalculatePolygonCountFast(doc, maxElements: 200, maxMilliseconds: 1200),
FeatureCount = CalculateFeatureCount(doc)
};
// 2. 快速统计主要构件(批量获取避免多次调用)
var elementCounts = new ElementCounts
{
Walls = new FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Walls).Count(),
Doors = new FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Doors).Count(),
Windows = new FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Windows).Count(),
Floors = new FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Floors).Count(),
Ceilings = new FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Ceilings).Count(),
Columns = new FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Columns).Count(),
Beams = new FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_StructuralFraming).Count(),
Rooms = new FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Rooms).Count()
};
// 3. 模型组织结构信息
var structure = new ModelStructure
{
Levels = new FilteredElementCollector(doc).OfClass(typeof(Level)).Count(),
FloorPlans = new FilteredElementCollector(doc).OfClass(typeof(ViewPlan)).Count(),
Views3D = new FilteredElementCollector(doc).OfClass(typeof(View3D)).Count(),
Elevations = new FilteredElementCollector(doc).OfClass(typeof(View))
.Cast().Count(v => v.ViewType == ViewType.Elevation),
Sections = new FilteredElementCollector(doc).OfClass(typeof(ViewSection)).Count(),
Sheets = new FilteredElementCollector(doc).OfClass(typeof(ViewSheet)).Count()
};
// 4. 模型层级信息
var hierarchy = new ModelHierarchy
{
Levels = new List(),
Groups = new FilteredElementCollector(doc).OfClass(typeof(Group)).Count(),
Worksets = doc.IsWorkshared ? new FilteredWorksetCollector(doc).Count() : 0,
Phases = new FilteredElementCollector(doc).OfClass(typeof(Phase)).Count(),
DesignOptions = new FilteredElementCollector(doc).OfClass(typeof(DesignOption)).Count()
};
// 获取楼层详细信息
var levels = new FilteredElementCollector(doc)
.OfClass(typeof(Level))
.Cast()
.OrderBy(l => l.Elevation)
.ToList();
foreach (var level in levels)
{
hierarchy.Levels.Add(new LevelInfo
{
Name = level.Name,
Elevation = level.Elevation * 304.8 // 转换为毫米
});
}
// 5. 链接文件统计
var links = new LinkFiles
{
RevitLinks = new LinkCategory(),
CadLinks = new LinkCategory(),
PointClouds = 0,
Images = 0
};
// Revit链接统计
// 使用OfClass确保只获取RevitLinkInstance类型的元素
var revitLinkInstances = new FilteredElementCollector(doc)
.OfClass(typeof(RevitLinkInstance))
.Cast();
links.RevitLinks.Total = revitLinkInstances.Count();
links.RevitLinks.Loaded = revitLinkInstances.Count(link => link.GetLinkDocument() != null);
links.RevitLinks.Unloaded = links.RevitLinks.Total - links.RevitLinks.Loaded;
// CAD链接统计
var cadLinkTypes = new FilteredElementCollector(doc)
.OfClass(typeof(CADLinkType))
.Cast();
links.CadLinks.Total = cadLinkTypes.Count();
// CAD链接状态检查(通过实例检查)
var cadInstances = new FilteredElementCollector(doc)
.OfClass(typeof(ImportInstance))
.Cast();
var loadedCadCount = 0;
foreach (var cadType in cadLinkTypes)
{
var hasInstance = cadInstances.Any(inst => inst.GetTypeId() == cadType.Id);
if (hasInstance) loadedCadCount++;
}
links.CadLinks.Loaded = loadedCadCount;
links.CadLinks.Unloaded = links.CadLinks.Total - links.CadLinks.Loaded;
// 点云链接
links.PointClouds = new FilteredElementCollector(doc)
.OfCategory(BuiltInCategory.OST_PointClouds).Count();
// 图像链接
links.Images = new FilteredElementCollector(doc)
.OfClass(typeof(ImageType)).Count();
// 生成链接文件总结
var totalLinks = links.RevitLinks.Total + links.CadLinks.Total + links.PointClouds + links.Images;
var loadedLinks = links.RevitLinks.Loaded + links.CadLinks.Loaded + links.PointClouds + links.Images;
links.Summary = totalLinks > 0 ?
$"{totalLinks}个链接文件,{loadedLinks}个已加载" :
"无链接文件";
// 组装总览响应
overview = new ModelOverviewResponse
{
Project = projectInfo,
Elements = elementCounts,
Structure = structure,
Hierarchy = hierarchy,
Links = links,
GeneratedAt = DateTime.Now
};
}
catch (Exception ex)
{
capturedException = ex;
}
finally
{
completed = true;
}
});
// 等待命令执行完成(最多等待10秒,因为信息较多)
var timeout = DateTime.Now.AddSeconds(10);
while (!completed && DateTime.Now < timeout)
{
System.Threading.Thread.Sleep(50);
}
if (capturedException != null)
throw capturedException;
if (!completed)
throw new TimeoutException("获取模型总览信息超时");
return overview;
}
catch (Exception ex)
{
throw new InvalidOperationException($"获取模型总览失败: {ex.Message}", ex);
}
}
///
/// 格式化文件大小显示
///
/// 文件大小(字节)
/// 格式化的文件大小字符串
private static string FormatFileSize(long bytes)
{
const long KB = 1024;
const long MB = KB * 1024;
const long GB = MB * 1024;
if (bytes >= GB)
{
return $"{bytes / (double)GB:F1} GB";
}
else if (bytes >= MB)
{
return $"{bytes / (double)MB:F1} MB";
}
else if (bytes >= KB)
{
return $"{bytes / (double)KB:F1} KB";
}
else
{
return $"{bytes} 字节";
}
}
///
/// 计算模型面片总数(基于可三角化几何)
///
/// Revit文档
/// 面片总数
private static long CalculatePolygonCountFast(Document doc, int maxElements, int maxMilliseconds)
{
long totalTriangles = 0;
var processedElements = 0;
var stopwatch = System.Diagnostics.Stopwatch.StartNew();
try
{
var options = new Options
{
ComputeReferences = false,
IncludeNonVisibleObjects = false,
DetailLevel = ViewDetailLevel.Medium
};
var elements = new FilteredElementCollector(doc)
.WhereElementIsNotElementType()
.Where(e => e.Category != null && e.Category.CategoryType == CategoryType.Model);
foreach (var element in elements)
{
if (processedElements >= maxElements || stopwatch.ElapsedMilliseconds >= maxMilliseconds)
{
break;
}
GeometryElement geometry = null;
try
{
geometry = element.get_Geometry(options);
}
catch
{
continue;
}
if (geometry == null)
continue;
totalTriangles += CountTrianglesFromGeometry(geometry);
processedElements++;
}
}
catch
{
// 忽略计算异常并返回已累计值
}
return totalTriangles;
}
///
/// 统计模型特征数(按模型类别去重)
///
/// Revit文档
/// 模型特征数
private static int CalculateFeatureCount(Document doc)
{
try
{
return new FilteredElementCollector(doc)
.WhereElementIsNotElementType()
.Where(e => e.Category != null && e.Category.CategoryType == CategoryType.Model)
.Select(e => e.Category.Id.IntegerValue)
.Distinct()
.Count();
}
catch
{
return 0;
}
}
///
/// 递归统计几何中的三角面片数量
///
/// 几何对象集合
/// 三角面片数量
private static long CountTrianglesFromGeometry(GeometryElement geometry)
{
long triangles = 0;
foreach (var obj in geometry)
{
if (obj is Solid solid && solid.Faces != null && solid.Faces.Size > 0)
{
foreach (Face face in solid.Faces)
{
try
{
var mesh = face.Triangulate();
if (mesh != null)
triangles += mesh.NumTriangles;
}
catch
{
// 忽略单个面三角化失败
}
}
continue;
}
if (obj is Mesh meshObj)
{
triangles += meshObj.NumTriangles;
continue;
}
if (obj is GeometryInstance instance)
{
try
{
var instanceGeometry = instance.GetInstanceGeometry();
if (instanceGeometry != null)
triangles += CountTrianglesFromGeometry(instanceGeometry);
}
catch
{
// 忽略单个实例解析失败
}
}
}
return triangles;
}
///
/// 获取文档文件大小(字节)
///
private static long GetDocumentFileSize(Document doc)
{
try
{
if (doc == null)
return 0;
if (!string.IsNullOrEmpty(doc.PathName) && File.Exists(doc.PathName))
return new FileInfo(doc.PathName).Length;
if (doc.IsWorkshared)
{
var centralPath = doc.GetWorksharingCentralModelPath();
var centralPathString = centralPath?.ToString();
if (!string.IsNullOrEmpty(centralPathString) && File.Exists(centralPathString))
return new FileInfo(centralPathString).Length;
}
}
catch
{
// 忽略文件大小获取异常,保持分析结果可用
}
return 0;
}
///
/// 基于真实文件大小和可删除比例填充动态估算信息
///
private static void ApplyDynamicSizeEstimate(Document doc, ShellAnalyzeResponse response)
{
if (doc == null || response?.Analysis == null)
return;
var summary = response.Analysis;
var originalSize = GetDocumentFileSize(doc);
if (originalSize <= 0)
return;
var removeRatio = summary.TotalElements > 0
? Math.Max(0.0, Math.Min(1.0, summary.RemoveElements / (double)summary.TotalElements))
: 0.0;
var estimatedOptimizedBytes = (long)Math.Round(originalSize * (1.0 - removeRatio));
if (estimatedOptimizedBytes < 0)
estimatedOptimizedBytes = 0;
summary.OriginalSize = FormatFileSize(originalSize);
summary.EstimatedOptimizedSize = FormatFileSize(estimatedOptimizedBytes);
summary.EstimatedReduction = $"{(removeRatio * 100.0):F1}%";
}
///
/// 分析薄壳优化方案
///
/// 优化模式
/// 分析结果
public static ShellAnalyzeResponse AnalyzeShellOptimization(ShellOptimizeMode mode)
{
ShellAnalyzeResponse result = null;
Exception capturedException = null;
bool completed = false;
try
{
App.Instance.EnqueueCommand(uiApp =>
{
try
{
var doc = uiApp.ActiveUIDocument?.Document;
if (doc == null)
throw new InvalidOperationException("没有打开的Revit文档");
var analyzer = new ShellAnalyzer();
result = analyzer.AnalyzeModel(doc, mode);
ApplyDynamicSizeEstimate(doc, result);
}
catch (Exception ex)
{
capturedException = ex;
}
finally
{
completed = true;
}
});
// 等待命令执行完成(最多等待30秒,分析可能需要较长时间)
var timeout = DateTime.Now.AddSeconds(30);
while (!completed && DateTime.Now < timeout)
{
System.Threading.Thread.Sleep(100);
}
if (capturedException != null)
throw capturedException;
if (!completed)
throw new TimeoutException("薄壳分析超时");
return result;
}
catch (Exception ex)
{
throw new InvalidOperationException($"薄壳分析失败: {ex.Message}", ex);
}
}
///
/// 执行薄壳优化(同步)
///
/// 优化模式
/// 是否备份原文件
/// 执行结果
public static ShellOptimizeResult ExecuteShellOptimization(ShellOptimizeMode mode, bool backupOriginal = true)
{
ShellOptimizeResult result = null;
Exception capturedException = null;
bool completed = false;
try
{
App.Instance.EnqueueCommand(uiApp =>
{
try
{
var doc = uiApp.ActiveUIDocument?.Document;
if (doc == null)
throw new InvalidOperationException("没有打开的Revit文档");
var optimizer = new ShellOptimizer();
result = optimizer.ExecuteOptimization(doc, mode, backupOriginal);
}
catch (Exception ex)
{
capturedException = ex;
}
finally
{
completed = true;
}
});
// 等待命令执行完成(最多等待5分钟,删除操作可能需要较长时间)
var timeout = DateTime.Now.AddMinutes(5);
while (!completed && DateTime.Now < timeout)
{
System.Threading.Thread.Sleep(200);
}
if (capturedException != null)
throw capturedException;
if (!completed)
throw new TimeoutException("薄壳优化执行超时");
return result;
}
catch (Exception ex)
{
throw new InvalidOperationException($"薄壳优化执行失败: {ex.Message}", ex);
}
}
///
/// 按类别执行自定义删除(同步)
///
public static ShellOptimizeResult ExecuteShellOptimizationByCategories(IEnumerable categoryIds, bool backupOriginal = true)
{
ShellOptimizeResult result = null;
Exception capturedException = null;
bool completed = false;
try
{
App.Instance.EnqueueCommand(uiApp =>
{
try
{
var doc = uiApp.ActiveUIDocument?.Document;
if (doc == null)
throw new InvalidOperationException("没有打开的Revit文档");
var optimizer = new ShellOptimizer();
result = optimizer.ExecuteOptimizationByCategories(doc, categoryIds, backupOriginal);
}
catch (Exception ex)
{
capturedException = ex;
}
finally
{
completed = true;
}
});
// 等待命令执行完成(最多等待5分钟)
var timeout = DateTime.Now.AddMinutes(5);
while (!completed && DateTime.Now < timeout)
{
System.Threading.Thread.Sleep(200);
}
if (capturedException != null)
throw capturedException;
if (!completed)
throw new TimeoutException("自定义类别删除执行超时");
return result;
}
catch (Exception ex)
{
throw new InvalidOperationException($"自定义类别删除执行失败: {ex.Message}", ex);
}
}
///
/// 执行薄壳优化(异步)
///
/// 优化模式
/// 是否备份原文件
/// 任务ID
/// 任务管理器
public static void ExecuteShellOptimizationAsync(ShellOptimizeMode mode, bool backupOriginal, Guid taskId, TaskManager taskManager)
{
try
{
App.Instance.EnqueueCommand(uiApp =>
{
try
{
var doc = uiApp.ActiveUIDocument?.Document;
if (doc == null)
{
taskManager.FailTask(taskId, "没有打开的Revit文档");
return;
}
var optimizer = new ShellOptimizer();
// 更新任务状态为进行中
taskManager.SetTaskRunning(taskId);
// 执行优化
var result = optimizer.ExecuteOptimization(doc, mode, backupOriginal);
// 设置任务完成
taskManager.CompleteTask(taskId, result);
}
catch (Exception ex)
{
taskManager.FailTask(taskId, $"薄壳优化执行失败: {ex.Message}");
}
});
}
catch (Exception ex)
{
taskManager.FailTask(taskId, $"启动薄壳优化任务失败: {ex.Message}");
}
}
}
}