using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Reflection; using Autodesk.Revit.DB; using Autodesk.Revit.DB.Architecture; using Autodesk.Revit.DB.Electrical; using Autodesk.Revit.DB.Mechanical; using Autodesk.Revit.DB.Plumbing; using Szmedi.RevitToolkit.Approval.Models; namespace Szmedi.RevitToolkit.Approval.Extensions; public static class DocumentExtensions { /// /// 是否存在该项目参数 /// /// /// /// /// /// public static bool IsExistProjectParam(this Document doc, string paramName, out Definition definition, out ElementBinding binding) { DefinitionBindingMap map = doc.ParameterBindings; var dep = map.ForwardIterator(); var isExist = false; binding = null; definition = null; while (dep.MoveNext()) { definition = dep.Key; var definitionName = definition.Name; binding = dep.Current as ElementBinding; if (definitionName == paramName) { isExist = true; break; } } return isExist; } public static Major GetMajor(this Document Document, out string majorName) { var hasDoor = Document.OfClass().OfCategory(BuiltInCategory.OST_Doors).Any(); var hasWindow = Document.OfClass().OfCategory(BuiltInCategory.OST_Windows).Any(); var hasBeam = Document.OfClass().OfCategory(BuiltInCategory.OST_StructuralFraming).Any(); var hasDuct = Document.OfClass().Any(); var hasPipe = Document.OfClass().Any(); var hasCableTray = Document.OfClass().Any(); Major major = Major.MasterPlan; if (hasDoor && hasWindow) { major = Major.Architecture; } if (hasBeam) { major = Major.Structure; } if (hasDuct) { major = Major.Mechanical; } if (hasCableTray) { major = Major.Electrical; } if (hasPipe && !hasDuct) { major = Major.Piping; } //获取枚举类的描述特性 var fieldInfo = major.GetType().GetField(major.ToString()); DescriptionAttribute descriptionAttribute = fieldInfo.GetCustomAttribute(); majorName = descriptionAttribute.Description; return major; } /// /// 添加自定义共享参数,已经添加事务 /// /// /// /// /// public static bool AddSharedParameter(this Document doc, string paramName, CategorySet categorySet, BuiltInParameterGroup group, ParameterType type = ParameterType.Text) { string AddInPath = Assembly.GetExecutingAssembly().Location; string DirAssembly = Path.GetDirectoryName(AddInPath); bool isSuccessed = false; doc.Invoke( ts => { var filePath = Path.Combine(DirAssembly, $"AFCASharedParameters.txt"); var app = doc.Application; var originSharedParametersFile = app.SharedParametersFilename.Clone().ToString(); DefinitionFile tempFile = SharedParameterAssists.CreateSharedParameterFile(app, filePath); var g = tempFile.Groups.Create("AFCAGroup"); var newInstanceBinding = app.Create.NewInstanceBinding(categorySet); ExternalDefinitionCreationOptions options = new(paramName, type); try { var definition = g.Definitions.Create(options); isSuccessed = doc.ParameterBindings.Insert(definition, newInstanceBinding, group); } finally { app.SharedParametersFilename = originSharedParametersFile.ToString(); File.Delete(tempFile.Filename); } }, $"<{paramName}>共享参数"); return isSuccessed; } /// /// 文档的收集器 /// /// public static FilteredElementCollector OfCollector(this Document document) => document == null ? throw new ArgumentNullException(nameof(document), "文档为空") : new(document); /// /// 类型的元素集合 /// /// /// /// public static FilteredElementCollector QueryElementsByType(this Document doc) where T : Element { return doc.OfCollector().OfClass(typeof(T)); } /// /// 收集特定类别 /// /// /// /// public static FilteredElementCollector QueryElementsByCategory(this Document doc, BuiltInCategory builtInCategory) { return doc.OfCollector().OfCategory(builtInCategory); } /// /// 收集特定类型 /// /// /// /// /// public static FilteredElementCollector QueryElementsByTypeAndCategory(this Document doc, BuiltInCategory builtInCategory) where T : Element { return doc.OfCollector().OfClass(typeof(T)).OfCategory(builtInCategory); } public static FilteredElementCollector OfCollector(this View view) { //if (view == null) //{ // throw new ArgumentNullException(nameof(view)); //} //if (!view.IsTemplate) //{ // return new FilteredElementCollector(view.doc, view.Id); //} return FilteredElementCollector.IsViewValidForElementIteration(view.Document, view.Id) ? new FilteredElementCollector(view.Document, view.Id) : throw new ArgumentException("当前视图不可应用收集器"); } /// /// 收集当前平面视图的某类图元 /// /// /// /// public static FilteredElementCollector QueryInstancesByType(this View view) where T : Element { return view.OfCollector().OfClass(typeof(T)).WhereElementIsNotElementType(); } /// /// 收集当前平面视图的某类别图元 /// /// /// /// public static FilteredElementCollector QueryElementsByCategoryInView(this View view, BuiltInCategory builtInCategory) { return view.OfCollector().OfCategory(builtInCategory).WhereElementIsNotElementType(); } /// /// 收集当前平面视图的某类图元 /// /// /// /// /// public static FilteredElementCollector QueryElementsByTypeAndCategory(this View view, BuiltInCategory builtInCategory) where T : Element { return view.OfCollector().OfClass(typeof(T)).OfCategory(builtInCategory).WhereElementIsNotElementType(); } /// /// 过滤项目文件独立模型元素,包含依附在主体上的元素,如楼板边缘、屋顶边缘、墙饰条、封檐板,檐沟等等 /// /// 元素集合 public static FilteredElementCollector OfParentModelCollector(this Document doc) { var col = doc.OfCollector() .WhereElementIsNotElementType() .Where( e => e is TopographySurface || e is DirectShape || e.CanHaveTypeAssigned() && e.IsValidObject && e.HasPhases() && e.ArePhasesModifiable() && e.get_BoundingBox(null) != null && e.Category is { CategoryType: CategoryType.Model } && (e is HostObject || e.Category.Parent == null) && e is not Panel && e is not Mullion && e is not RevitLinkInstance ).Select(e => e.Id).ToList(); if (col.Count == 0) { return null; } return new FilteredElementCollector(doc, col).WhereElementIsNotElementType(); } /// /// 过滤项目文件的所有模型元素 /// /// 元素集合 public static FilteredElementCollector OfAllModelCollector(this Document doc) { if (doc == null) { throw new ArgumentNullException(nameof(doc), "文档为空"); } var col = doc.OfCollector() .WhereElementIsNotElementType() .Where( e => e is TopographySurface || e is DirectShape || e.CanHaveTypeAssigned() && e.IsValidObject && e.HasPhases() && e.ViewSpecific == false && e.Category is { CategoryType: CategoryType.Model, AllowsBoundParameters: true } && e.get_BoundingBox(null) != null && e is not RevitLinkInstance).Select(e => e.Id).ToList(); if (col.Count == 0) { return null; } return new FilteredElementCollector(doc, col).WhereElementIsNotElementType(); } ///// ///// 获取所有最高层级的模型元素,不包含子模型 ///// ///// ///// //public static IEnumerable OfModelElements(this Document doc) //{ // return doc.OfCollector() // .WhereElementIsNotElementType() // .Where( // e => e is TopographySurface || ( // e.CanHaveTypeAssigned() // && e.IsValidObject // && e.get_BoundingBox(null) != null // && e.HasPhases() // && e.ViewSpecific == false // && e.Category is { Parent: null, CategoryType: CategoryType.Model, AllowsBoundParameters: true } // && e is not Panel // && e is not Mullion // && e is not RevitLinkInstance) // ); //} ///// ///// 所有元素不包括幕墙嵌板,幕墙竖梃、依附图元等等 ///// ///// ///// //public static FilteredElementCollector OfModelCollector(this Document doc) //{ // if (doc == null) // { // throw new ArgumentNullException(nameof(doc), "文档为空"); // } // var li = doc.OfCollector().WhereElementIsNotElementType() // .Where( // e => e is TopographySurface || // (e.CanHaveTypeAssigned() && // e.HasPhases() && // e.Category is { Parent: null, CategoryType: CategoryType.Model } && // e is not Panel && // e is not Mullion && // e is not RevitLinkInstance)).Select(e => e.Id).ToList(); // return new FilteredElementCollector(doc, li).WhereElementIsNotElementType(); //} /// /// 获取对应类型的元素收集器 /// /// /// /// public static IEnumerable OfType(this Document doc) where T : Element => doc.OfCollector().OfClass(typeof(T)).OfType(); public static FilteredElementCollector OfClass(this Document doc) where T : Element { return doc.OfCollector().OfClass(typeof(T)); } /// /// 射线法查找所有的Element /// /// Dcument /// 例如:ElementClassFilter filter = new ElementClassFilter(typeof(CableTray)) /// 目标对象 /// 射源 /// 方向 /// 返回该射线 public static IList XRayFindAll( this Document doc, ElementFilter filter, FindReferenceTarget targetRef, XYZ center, XYZ direction ) { FilteredElementCollector collector = new(doc); Func isNotTemplate = v3 => !v3.IsTemplate; var view3D = collector.OfClass(typeof(View3D)).Cast().First(isNotTemplate); ReferenceIntersector refIntersector = new(filter, targetRef, view3D); var refWithContexts = refIntersector.Find(center, direction); if (null == refWithContexts) { return null; } IList resultElements = []; foreach (var rwc in refWithContexts) { var reference = rwc.GetReference(); var hitElement = doc.GetElement(reference); if (hitElement != null) { resultElements.Add(hitElement); } } return resultElements; } /// /// 获取标高范围框 /// /// 最低标高除了包含以上部分,还包含以下部分,最高标高包含以上部分 /// /// public static Dictionary GetLevelRanges(this Document doc) { var levels = doc.OfType().Cast().OrderBy(l => l.Elevation).ToList(); Dictionary levelOutlines = []; //获取标高范围 for (var i = 0; i < levels.Count; i++) { var baseLevel = levels[i]; XYZ min = new(double.MinValue, double.MinValue, baseLevel.Elevation); XYZ max; Outline outline; if (i == 0) { min = new XYZ(double.MinValue, double.MinValue, double.MinValue); var topLevel = levels[i + 1]; max = new XYZ(double.MaxValue, double.MaxValue, topLevel.Elevation); outline = new Outline(min, max); } else if (i < levels.Count - 1) { var topLevel = levels[i + 1]; max = new XYZ(double.MaxValue, double.MaxValue, topLevel.Elevation); outline = new Outline(min, max); } else//最后一个标高以上 { max = new XYZ(double.MaxValue, double.MaxValue, double.MaxValue); outline = new Outline(min, max); } levelOutlines.Add(baseLevel, outline); } return levelOutlines; } /// /// 射线法查找最近的Element /// /// Dcument /// 例如:ElementClassFilter filter = new ElementClassFilter(typeof(CableTray)) /// 目标对象 /// 射源 /// 方向 /// 被击中的Element /// 返回该射线 public static Line XRayFindNearest( this Document doc, ElementFilter filter, FindReferenceTarget targetRef, XYZ center, XYZ direction, ref Element hitElement ) { FilteredElementCollector collector = new(doc); var view3D = collector.OfClass(typeof(View3D)).Cast().First(v3 => !v3.IsTemplate); var rwc = new ReferenceIntersector(filter, targetRef, view3D).FindNearest(center, direction); if (null == rwc) { return null; } var reference = rwc.GetReference(); var intersection = reference.GlobalPoint; hitElement = doc.GetElement(reference); Line result = null; if (!center.IsAlmostEqualTo(intersection)) { result = Line.CreateBound(center, intersection); } else { hitElement = null; } return result; } public static TResult Invoke(this Document doc, Func func, string name = "default") { using var tr = new Transaction(doc, name); tr.Start(); var result = func(tr); var status = tr.GetStatus(); switch (status) { case TransactionStatus.Started: tr.Commit(); return result; case TransactionStatus.Committed: case TransactionStatus.RolledBack: return result; case TransactionStatus.Error: tr.RollBack(); return result; default: return result; } } public static TResult InvokeGroup(this Document doc, Func func, string name = "default") { using var tg = new TransactionGroup(doc, name); tg.Start(); var result = func(tg); var status = tg.GetStatus(); switch (status) { case TransactionStatus.Started: tg.Assimilate(); //tr.Commit(); return result; case TransactionStatus.Committed: case TransactionStatus.RolledBack: return result; case TransactionStatus.Error: tg.RollBack(); return result; default: return result; } } public static TResult InvokeSub(this Document doc, Func func) { using var st = new SubTransaction(doc); st.Start(); var result = func(st); var status = st.GetStatus(); switch (status) { case TransactionStatus.Started: st.Commit(); return result; case TransactionStatus.Committed: case TransactionStatus.RolledBack: return result; case TransactionStatus.Error: st.RollBack(); return result; default: return result; } } //private static void UsingThisClass(doc doc) //{ // //无返回值 // doc.Invoke(m => { }, "x"); // //有返回值 // doc.Invoke(m => // { // return Level.Create(doc, 5); // }, "x"); // doc.InvokeGroup(m => { doc.Invoke(mn => { }, "x"); }, "x"); // doc.InvokeGroup(m => { doc.Invoke(mn => { }, "x"); doc.Invoke(mn => { }, "Y"); return Level.Create(doc, 5); }, "x"); // doc.InvokeSub(m => { }); // doc.InvokeSub(m => { return Level.Create(doc, 5); }); //} public static void Invoke(this Document doc, Action action, string name = "default") { using var tr = new Transaction(doc, name); tr.Start(); action(tr); var status = tr.GetStatus(); switch (status) { case TransactionStatus.Started: tr.Commit(); return; case TransactionStatus.Committed: case TransactionStatus.RolledBack: return; case TransactionStatus.Error: tr.RollBack(); return; default: return; } } public static void InvokeGroup(this Document doc, Action action, string name = "default") { using var tg = new TransactionGroup(doc, name); tg.Start(); action(tg); var status = tg.GetStatus(); switch (status) { case TransactionStatus.Started: //tr.Commit(); tg.Assimilate(); return; case TransactionStatus.Committed: case TransactionStatus.RolledBack: break; case TransactionStatus.Error: tg.RollBack(); return; default: return; } } public static void InvokeSub(this Document doc, Action action) { using var st = new SubTransaction(doc); st.Start(); action(st); var status = st.GetStatus(); switch (status) { case TransactionStatus.Started: st.Commit(); return; case TransactionStatus.Committed: case TransactionStatus.RolledBack: break; case TransactionStatus.Error: st.RollBack(); return; default: return; } } }