using Autodesk.Revit.DB; using Autodesk.Revit.DB.Architecture; using Autodesk.Revit.DB.Structure; namespace ShrlAlgoToolkit.RevitCore.Extensions; public static class ElementExtensions { /// /// 镜像元素 /// /// /// /// public static Element Mirror(this Element element, Plane plane) { ElementTransformUtils.MirrorElement(element.Document, element.Id, plane); return element; } public static bool IsVisible(this Element elem, View view) => FilteredElementCollector.IsViewValidForElementIteration(elem.Document, view.Id) && new FilteredElementCollector(elem.Document, view.Id).ToElementIds().Any(id => id == elem.Id); /// /// 移动元素 /// /// /// /// /// /// public static Element Move(this Element element, double deltaX, double deltaY, double deltaZ) { ElementTransformUtils.MoveElement(element.Document, element.Id, new XYZ(deltaX, deltaY, deltaZ)); return element; } /// /// 移动元素 /// /// /// /// public static Element Move(this Element element, XYZ vector) { ElementTransformUtils.MoveElement(element.Document, element.Id, vector); return element; } public static void MoveElement(this Element item, XYZ vector) { if (item.Pinned || !item.IsValidObject || item == null) { return; } var doc = item.Document; var levels = doc.OfClass().OfType().OrderBy(l => l.Elevation).ToList(); if (item is FamilyInstance instance) { var baseElev = instance.get_BoundingBox(null).Min.Z + vector.Z; var topElev = instance.get_BoundingBox(null).Max.Z + vector.Z; var baseLevel = GetClosetLevel(levels, baseElev); var topLevel = GetClosetLevel(levels, topElev); switch (instance.Symbol.Family.FamilyPlacementType) { //柱 case FamilyPlacementType.TwoLevelsBased: { instance.Location.Move(vector); instance.get_Parameter(BuiltInParameter.FAMILY_BASE_LEVEL_PARAM).Set(baseLevel.Id); instance.get_Parameter(BuiltInParameter.FAMILY_BASE_LEVEL_OFFSET_PARAM).Set(baseElev - baseLevel.Elevation); instance.get_Parameter(BuiltInParameter.FAMILY_TOP_LEVEL_PARAM).Set(topLevel.Id); instance.get_Parameter(BuiltInParameter.FAMILY_TOP_LEVEL_OFFSET_PARAM).Set(topElev - topLevel.Elevation); } break; case FamilyPlacementType.ViewBased: break; case FamilyPlacementType.WorkPlaneBased: { //instance.Location.Move(vector); var param = instance.get_Parameter(BuiltInParameter.INSTANCE_ELEVATION_PARAM); if (param != null && !param.IsReadOnly) { ElementTransformUtils.MoveElement(doc, instance.Id, XYZ.BasisZ * vector.Z); //var value = param.AsDouble() + vector.Z; //param.Set(value); } doc.Regenerate(); if (instance.Host == null) { ElementTransformUtils.MoveElement(doc, instance.Id, vector.Flatten()); } } break; case FamilyPlacementType.OneLevelBased: { ElementTransformUtils.MoveElement(doc, instance.Id, vector); } break; case FamilyPlacementType.OneLevelBasedHosted: { var ins = doc.Create .NewFamilyInstance( instance.GetLocXYZ(), instance.Symbol, instance.Host, baseLevel, StructuralType.NonStructural); ins.get_Parameter(BuiltInParameter.INSTANCE_SILL_HEIGHT_PARAM) .Set(baseElev - baseLevel.Elevation); doc.Delete(instance.Id); } break; case FamilyPlacementType.CurveBased: { instance.Location.Move(vector); //var loc = instance.GetLocCurve().CreateTransformed(Transform.CreateTranslation(vector)) as Line; //doc.Create.NewFamilyInstance(instance.HostFace, loc, instance.Symbol); //doc.Delete(instance.Id); } break; case FamilyPlacementType.CurveBasedDetail: break; //梁 case FamilyPlacementType.CurveDrivenStructural: { //instance.Location.Move(vector); var loc = instance.GetCurve().CreateTransformed(Autodesk.Revit.DB.Transform.CreateTranslation(vector)); //var newLoc = doc.Create.NewFamilyInstance(loc, instance.Symbol, baseLevel, StructuralType.Beam); doc.Delete(instance.Id); //ElementTransformUtils.MoveElement(doc, instance.Id, vector.Flatten()); } break; case FamilyPlacementType.Adaptive: break; case FamilyPlacementType.Invalid: break; default: break; } } else if (item is Wall wall) { var flat = vector.Flatten(); ElementTransformUtils.MoveElement(doc, wall.Id, flat); doc.Regenerate(); SetWallHeight(vector, levels, wall); var elemIds = wall.FindInserts(true, true, true, true); foreach (var id in elemIds) { var elem = doc.GetElement(id); if (elem is Wall nestWall) { SetWallHeight(vector, levels, nestWall); } else { MoveElement(elem, vector); } } //墙饰条 var sweeps = doc.OfClass ().OfType().Where(s => s.GetHostIds().Contains(wall.Id)); foreach (var sweep in sweeps) { //ElementTransformUtils.MoveElement(doc, sweep.Id, flat); var boundingBox = sweep.get_BoundingBox(null); var offset = boundingBox.Min.Z + vector.Z; var baseLevel = levels.First(l => Math.Abs(l.Elevation - offset) == levels.Min(l => Math.Abs(l.Elevation - offset))); sweep.get_Parameter(BuiltInParameter.WALL_SWEEP_LEVEL_PARAM).Set(baseLevel.Id); sweep.get_Parameter(BuiltInParameter.WALL_SWEEP_OFFSET_PARAM).Set(offset - baseLevel.Elevation); } //依附在墙上的实例 var instances = doc.OfClass().OfType().Where(s => { var stackedWallIds = wall.GetStackedWallMemberIds(); if (stackedWallIds.Count > 0) { return stackedWallIds.Any(id => s.Host?.Id == id); } return s.Host?.Id == wall.Id; }).ToList(); foreach (var ins in instances) { //ins.Location.Move(vector); ElementTransformUtils.MoveElement(doc, ins.Id, vector.Z * XYZ.BasisZ); } //ElementTransformUtils.CopyElements(v1, [wall.Id], v2, Transform.Identity, new CopyPasteOptions()); //var b = wall.Location.Move(vector); //var loc = wall.GetLocCurve(); //var c = loc.CreateTransformed(Transform.CreateTranslation(vector)); //(wall.Location as LocationCurve).Curve = c; //可以移动,但是偏移量属性没更新 } else if (item is Room room) { } else if (item is Stairs stairs) { var flat = vector.Flatten(); ElementTransformUtils.MoveElement(doc, item.Id, flat); } else if (item is ModelCurve curve)//房间分割 { } else if (item is Railing railing) { if (railing.HasHost) { } else//连带主体移动 { ElementTransformUtils.MoveElement(doc, item.Id, vector); } } //坡道 else if (item.Category.ToBuiltInCategory() == BuiltInCategory.OST_Ramps) { var flat = vector.Flatten(); ElementTransformUtils.MoveElement(doc, item.Id, flat); } else if (item is TopographySurface surface) { } else if (item is SlabEdge or Fascia or Gutter) { return; } //else if (item is CeilingAndFloor ceilingAndFloor) //{ // ElementTransformUtils.MoveElement(doc, ceilingAndFloor.Id, vector); //} else if (item is Opening opening) { if (opening.Host is Wall) { ElementTransformUtils.MoveElement(doc, opening.Id, vector.Z * XYZ.BasisZ); } } else { ElementTransformUtils.MoveElement(doc, item.Id, vector); } } /// /// 设置墙高度 /// /// /// /// private static void SetWallHeight(XYZ vector, List levels, Wall wall) { var boundingBox = wall.get_BoundingBox(null); //底部实际高度 var bottomElev = boundingBox.Min.Z + vector.Z; var topElev = boundingBox.Max.Z + vector.Z; //查找距离底部偏移最近的Level var baseLevel = GetClosetLevel(levels, bottomElev); wall.get_Parameter(BuiltInParameter.WALL_BASE_CONSTRAINT).Set(baseLevel.Id); wall.get_Parameter(BuiltInParameter.WALL_BASE_OFFSET).Set(bottomElev - baseLevel.Elevation); //是否有顶部约束 var topContraint = wall.get_Parameter(BuiltInParameter.WALL_HEIGHT_TYPE).AsElementId(); if (topContraint != ElementId.InvalidElementId) { var topLevel = GetClosetLevel(levels, topElev); wall.get_Parameter(BuiltInParameter.WALL_HEIGHT_TYPE).Set(topLevel.Id); wall.get_Parameter(BuiltInParameter.WALL_TOP_OFFSET).Set(topElev - topLevel.Elevation); } } /// /// 获取距离最近的标高 /// /// /// 高度 /// private static Level GetClosetLevel(List levels, double elev) { return levels.First(l => Math.Abs(l.Elevation - elev) == levels.Min(l => Math.Abs(l.Elevation - elev))); } /// /// 旋转元素 /// /// /// /// /// public static Element Rotate(this Element element, Line axis, double angle) { ElementTransformUtils.RotateElement(element.Document, element.Id, axis, angle); return element; } /// /// 能否镜像 /// /// /// public static bool CanBeMirrored(this Element element) { return ElementTransformUtils.CanMirrorElement(element.Document, element.Id); } /// /// 获取标高 /// /// /// public static ElementId GetLevelId(this Element element) { // 定义需要检查的参数列表 var parametersToCheck = new BuiltInParameter[] { BuiltInParameter.WALL_BASE_CONSTRAINT, // 墙 BuiltInParameter.SCHEDULE_BASE_LEVEL_PARAM, // 柱子标高 BuiltInParameter.INSTANCE_REFERENCE_LEVEL_PARAM, // 梁标高 BuiltInParameter.STAIRS_BASE_LEVEL_PARAM, // 楼梯标高 BuiltInParameter.INSTANCE_ELEVATION_PARAM, // 族实例明细表标高 BuiltInParameter.ROOF_CONSTRAINT_LEVEL_PARAM,//屋顶 BuiltInParameter.INSTANCE_SCHEDULE_ONLY_LEVEL_PARAM,// 族实例明细表标高 BuiltInParameter.RBS_START_LEVEL_PARAM// 管线标高 }; // 依次检查每个参数 foreach (var param in parametersToCheck) { var baseLevelId = element.get_Parameter(param)?.AsElementId(); if (baseLevelId != ElementId.InvalidElementId && baseLevelId != null) { return baseLevelId; } } //最后检查楼板或族基准标高 return element.LevelId; } /// /// 转换类型 /// /// /// /// public static T Cast(this Element element) where T : Element { return (T)element; } /// /// 合并几何 /// /// /// public static void JoinGeometry(this Element firstElement, Element secondElement) { JoinGeometryUtils.JoinGeometry(firstElement.Document, firstElement, secondElement); } /// /// 分离几何 /// /// /// public static void UnJoinGeometry(this Element firstElement, Element secondElement) { JoinGeometryUtils.UnjoinGeometry(firstElement.Document, firstElement, secondElement); } /// /// 是否连接 /// /// /// /// public static bool AreElementsJoined(this Element firstElement, Element secondElement) { return JoinGeometryUtils.AreElementsJoined(firstElement.Document, firstElement, secondElement); } /// /// 切换连接顺序 /// /// /// public static void SwitchJoinOrder(this Element firstElement, Element secondElement) { JoinGeometryUtils.SwitchJoinOrder(firstElement.Document, firstElement, secondElement); } /// /// 确定两个连接元素中的第一个是否正在切割第二个元素 /// /// /// /// public static bool IsCuttingElementInJoin(this Element firstElement, Element secondElement) { return JoinGeometryUtils.IsCuttingElementInJoin(firstElement.Document, firstElement, secondElement); } /// /// 获取连接的元素 /// /// /// public static ICollection GetJoinedElements(this Element element) { return JoinGeometryUtils.GetJoinedElements(element.Document, element); } public static bool SetValue(this Parameter parameter, object value) { var result = false; if (parameter.IsReadOnly) return false; switch (parameter.StorageType) { case StorageType.Integer: if (value is int i) { result = parameter.Set(i); } break; case StorageType.Double: if (value is double d) { result = parameter.Set(d); } break; case StorageType.String: if (value is string str) { result = parameter.Set(str); } break; case StorageType.ElementId: if (value is ElementId id) { result = parameter.Set(id); } break; case StorageType.None: break; default: throw new ArgumentOutOfRangeException(); } return result; } /// /// 获取参数值 /// /// /// public static object GetValue(this Parameter parameter) { object result = null; if (parameter == null) { throw new ArgumentNullException(nameof(parameter)); } switch (parameter.StorageType) { case StorageType.None: break; case StorageType.Integer: result = parameter.AsInteger(); break; case StorageType.Double: result = parameter.AsDouble(); break; case StorageType.String: //Revit数据库存储的值 var str = parameter.AsString(); if (string.IsNullOrEmpty(str)) { //用户可见的前端显示,如根据单位设置而显示的值 result = parameter.AsValueString(); } else { result = str; } break; case StorageType.ElementId: result = parameter.AsElementId(); break; } return result; } public static void SetElementTransparency(this Element element, int transparency) { try { var document = element.Document; var elementOverrides = document.ActiveView.GetElementOverrides(element.Id); elementOverrides.SetSurfaceTransparency(transparency); document.ActiveView.SetElementOverrides(element.Id, elementOverrides); } catch (Exception) { // ignored } } /// /// 优先获取实例参数,若无则获取类型参数 /// /// /// /// public static Parameter GetParameter(this Element element, string parameterName) { if (!element.IsValidObject) { throw new ArgumentNullException(nameof(element)); } //var parameterName = elem.LookupParameter(paramName); //if (parameterName == null) //{ // ElementId typeId = elem.GetTypeId(); // if (typeId != ElementId.InvalidElementId) // { // var elementFunc = elem.doc?.GetElement(typeId); // parameterName = elementFunc?.LookupParameter(paramName); // } //} var instanceParameter = element.LookupParameter(parameterName); if (instanceParameter is { HasValue: true }) { return instanceParameter; } var elementTypeId = element.GetTypeId(); if (elementTypeId == ElementId.InvalidElementId) { return instanceParameter; } var elementType = element.Document.GetElement(elementTypeId); var symbolParameter = elementType.LookupParameter(parameterName); return symbolParameter ?? instanceParameter; } /// /// 管理图元在各个视图的可见性 /// /// /// public static void AccessFamilyElementVisibility(this GenericForm form, FamilyElementVisibility visibility) { // 得到管理拉伸体的可见性的实例,并读取详细程度的设置 //FamilyElementVisibility visibility = form.GetVisibility(); //FamilyElementVisibilityType visibilityType = visibility.VisibilityType; //bool shownInCoarse = visibility.IsShownInCoarse; //bool shownInMedium = visibility.IsShownInMedium; //bool shownInFine = visibility.IsShownInFine; //// 设置为在各种详细程度中都显示拉伸体 //visibility.IsShownInTopBottom = false; //visibility.IsShownInCoarse = true; //visibility.IsShownInMedium = true; //visibility.IsShownInFine = true; // 注意:必须把可见性的修改设置回拉伸体 form.SetVisibility(visibility); } /// /// 线性阵列 /// public static void CreateLinearArray(this Element element, XYZ vector, int count, ArrayAnchorMember arrayAnchorMember) { var document = element.Document; LinearArray.Create(document, document.ActiveView, element.Id, count, vector, arrayAnchorMember); } public static void GetGeometryObj(this Element element, out List faces, out List edges) { //实例族的GeometryElement集合中具有Solid等几何对象的原因是由于族实例对象碰撞后,软件自动会使用geometryInstance用来指定其位置(即使碰撞后,移开),用Solid作为其几何体 //GeometryInstance Transform是族实例在全局坐标系的变换 faces = []; edges = []; //var references = new List(); Options geomOptions = new() { ComputeReferences = true, DetailLevel = ViewDetailLevel.Medium, IncludeNonVisibleObjects = true }; var geoElem = element.get_Geometry(geomOptions); foreach (var obj in geoElem) { if (obj is GeometryInstance instance) { if (instance.GetSymbolGeometry().Any()) { foreach (var item in instance.GetSymbolGeometry()) { if (item is Solid solid) { if (solid.Edges.Size > 0) { edges.AddRange(solid.Edges.OfType()); } if (solid.Faces.Size > 0) { faces.AddRange(solid.Faces.OfType()); } } } } } else { if (obj is not Solid solid) { continue; } if (solid.Edges.Size > 0) { edges.AddRange(from Edge edge in solid.Edges select edge); } if (solid.Faces.Size > 0) { faces.AddRange(from Face face in solid.Faces select face); } } } } /// /// 修改元素面颜色(待测试) /// /// /// /// public static void ModifyElementFaceDisplay(this Element element, string materialName, Color color) { var doc = element.Document; var material = doc.GetElement(Material.Create(doc, materialName)) as Material; material!.Color = color; Options options = new() { ComputeReferences = true, DetailLevel = ViewDetailLevel.Medium }; var e = element.get_Geometry(options); foreach (var geometryObject in e) { var geoInstance = geometryObject as GeometryInstance; if (geoInstance != null) { var geoElement = geoInstance.GetInstanceGeometry(); foreach (var obj2 in geoElement) { var solid = obj2 as Solid; if (solid.SurfaceArea != 0) { foreach (Face face in solid.Faces) { doc.Paint(element.Id, face, material.Id); } } } } } } }