Files
ShrlAlgoToolkit/ShrlAlgoToolkit.RevitCore/Extensions/ElementExtensions.cs
2026-02-22 21:12:18 +08:00

682 lines
25 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Architecture;
using Autodesk.Revit.DB.Structure;
namespace ShrlAlgoToolkit.RevitCore.Extensions;
public static class ElementExtensions
{
/// <summary>
/// 镜像元素
/// </summary>
/// <param name="element"></param>
/// <param name="plane"></param>
/// <returns></returns>
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);
/// <summary>
/// 移动元素
/// </summary>
/// <param name="element"></param>
/// <param name="deltaX"></param>
/// <param name="deltaY"></param>
/// <param name="deltaZ"></param>
/// <returns></returns>
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;
}
/// <summary>
/// 移动元素
/// </summary>
/// <param name="element"></param>
/// <param name="vector"></param>
/// <returns></returns>
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<Level>().OfType<Level>().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
<WallSweep>().OfType<WallSweep>().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<FamilyInstance>().OfType<FamilyInstance>().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);
}
}
/// <summary>
/// 设置墙高度
/// </summary>
/// <param name="vector"></param>
/// <param name="levels"></param>
/// <param name="wall"></param>
private static void SetWallHeight(XYZ vector, List<Level> 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);
}
}
/// <summary>
/// 获取距离最近的标高
/// </summary>
/// <param name="levels"></param>
/// <param name="elev">高度</param>
/// <returns></returns>
private static Level GetClosetLevel(List<Level> levels, double elev)
{
return levels.First(l => Math.Abs(l.Elevation - elev) == levels.Min(l => Math.Abs(l.Elevation - elev)));
}
/// <summary>
/// 旋转元素
/// </summary>
/// <param name="element"></param>
/// <param name="axis"></param>
/// <param name="angle"></param>
/// <returns></returns>
public static Element Rotate(this Element element, Line axis, double angle)
{
ElementTransformUtils.RotateElement(element.Document, element.Id, axis, angle);
return element;
}
/// <summary>
/// 能否镜像
/// </summary>
/// <param name="element"></param>
/// <returns></returns>
public static bool CanBeMirrored(this Element element)
{
return ElementTransformUtils.CanMirrorElement(element.Document, element.Id);
}
/// <summary>
/// 获取标高
/// </summary>
/// <param name="element"></param>
/// <returns></returns>
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;
}
/// <summary>
/// 转换类型
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="element"></param>
/// <returns></returns>
public static T Cast<T>(this Element element) where T : Element
{
return (T)element;
}
/// <summary>
/// 合并几何
/// </summary>
/// <param name="firstElement"></param>
/// <param name="secondElement"></param>
public static void JoinGeometry(this Element firstElement, Element secondElement)
{
JoinGeometryUtils.JoinGeometry(firstElement.Document, firstElement, secondElement);
}
/// <summary>
/// 分离几何
/// </summary>
/// <param name="firstElement"></param>
/// <param name="secondElement"></param>
public static void UnJoinGeometry(this Element firstElement, Element secondElement)
{
JoinGeometryUtils.UnjoinGeometry(firstElement.Document, firstElement, secondElement);
}
/// <summary>
/// 是否连接
/// </summary>
/// <param name="firstElement"></param>
/// <param name="secondElement"></param>
/// <returns></returns>
public static bool AreElementsJoined(this Element firstElement, Element secondElement)
{
return JoinGeometryUtils.AreElementsJoined(firstElement.Document, firstElement, secondElement);
}
/// <summary>
/// 切换连接顺序
/// </summary>
/// <param name="firstElement"></param>
/// <param name="secondElement"></param>
public static void SwitchJoinOrder(this Element firstElement, Element secondElement)
{
JoinGeometryUtils.SwitchJoinOrder(firstElement.Document, firstElement, secondElement);
}
/// <summary>
/// 确定两个连接元素中的第一个是否正在切割第二个元素
/// </summary>
/// <param name="firstElement"></param>
/// <param name="secondElement"></param>
/// <returns></returns>
public static bool IsCuttingElementInJoin(this Element firstElement, Element secondElement)
{
return JoinGeometryUtils.IsCuttingElementInJoin(firstElement.Document, firstElement, secondElement);
}
/// <summary>
/// 获取连接的元素
/// </summary>
/// <param name="element"></param>
/// <returns></returns>
public static ICollection<ElementId> 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;
}
/// <summary>
/// 获取参数值
/// </summary>
/// <param name="parameter"></param>
/// <returns></returns>
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
}
}
/// <summary>
/// 优先获取实例参数,若无则获取类型参数
/// </summary>
/// <param name="element"></param>
/// <param name="parameterName"></param>
/// <returns></returns>
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;
}
/// <summary>
/// 管理图元在各个视图的可见性
/// </summary>
/// <param name="form"></param>
/// <param name="visibility"></param>
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);
}
/// <summary>
/// 线性阵列
/// </summary>
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<Face> faces, out List<Edge> edges)
{
//实例族的GeometryElement集合中具有Solid等几何对象的原因是由于族实例对象碰撞后软件自动会使用geometryInstance用来指定其位置即使碰撞后移开用Solid作为其几何体
//GeometryInstance Transform是族实例在全局坐标系的变换
faces = [];
edges = [];
//var references = new List<Reference>();
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<Edge>());
}
if (solid.Faces.Size > 0)
{
faces.AddRange(solid.Faces.OfType<Face>());
}
}
}
}
}
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);
}
}
}
}
/// <summary>
/// 修改元素面颜色(待测试)
/// </summary>
/// <param name="element"></param>
/// <param name="materialName"></param>
/// <param name="color"></param>
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);
}
}
}
}
}
}
}