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}"); } } } }