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