using System;
using System.Collections.Generic;
using System.Linq;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
namespace Szmedi.Toolkit.RvExtensions;
public static class ElementExtensions
{
///
/// 容差
///
private const double Tolerance = 0.0001;
///
/// 有类型定义的DirectShape
///
///
/// 定义名称,即是族名称、类型名称(强制一致),创建多个实例时,如果相同,则会合并在一个族中
/// 族类别
/// 几何
///
public static DirectShape CreateDirectShapeInstance(this Document doc, string definitionId, BuiltInCategory category, List geos)
{
DirectShapeLibrary directShapeLibrary = DirectShapeLibrary.GetDirectShapeLibrary(doc);
ElementId directShapeTypeId = directShapeLibrary.FindDefinitionType(definitionId);
if (doc.GetElement(directShapeTypeId) == null)
{
var directShapeType = DirectShapeType.Create(doc, definitionId, new ElementId(category));
directShapeTypeId = directShapeType.Id;
directShapeLibrary.AddDefinitionType(definitionId, directShapeTypeId);
}
//else
//{
// directShapeLibrary.AddDefinition(definitionId, geos);
//}
var shape = DirectShape.CreateElementInstance(doc, directShapeTypeId, new ElementId(category), definitionId, Transform.Identity);
//shape.SetTypeId(directShapeTypeId);
shape.SetName(definitionId);
shape.SetShape(geos);
return shape;
}
///
/// 已经打开的视图中缩放视图,最大化图元
///
///
///
///
/// 扩宽范围
public static void ZoomElement(this View view, UIDocument uidoc, ElementId elementId, int extend = 2)
{
var elem = uidoc.Document.GetElement(elementId);
if (!elem.IsValidObject || !elem.IsVisible(view)) return;
var box = elem.get_BoundingBox(view);
if (box == null) return;
box = box.Extend(extend);
var uiView = uidoc.GetOpenUIViews().FirstOrDefault(v => v.ViewId == uidoc.ActiveGraphicalView.Id);
uiView?.ZoomAndCenterRectangle(box.Min, box.Max);
}
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);
///
/// 无名称定义的DirectShape
///
///
///
///
///
public static DirectShape CreateDirectShape(this Document doc, List geos, BuiltInCategory category)
{
var shape = DirectShape.CreateElement(doc, new ElementId(category));
shape.SetShape(geos);
return shape;
}
///
/// 扩展包围盒的大小
///
///
///
///
public static BoundingBoxXYZ Extend(this BoundingBoxXYZ boundingBox, double distance = 2.0)
{
var transform = boundingBox.Transform;
var max = boundingBox.Max + distance * (transform.BasisX + transform.BasisY + transform.BasisZ);
var min = boundingBox.Min - distance * (transform.BasisX + transform.BasisY + transform.BasisZ);
return new BoundingBoxXYZ() { Max = max, Min = min, Transform = transform };
}
private static List GetGeoObjects(this GeometryObject geoObject)
where T : GeometryObject
{
List geometryObjects = [];
if (geoObject is Solid instSolid)
{
if (typeof(T) == typeof(Solid))
{
geometryObjects.Add(instSolid as T);
}
if (typeof(T) == typeof(Face) && instSolid.Faces.Size > 0)
{
geometryObjects.AddRange(instSolid.Faces.Cast());
}
else if (typeof(T) == typeof(Edge) && instSolid.Edges.Size > 0)
{
geometryObjects.AddRange(instSolid.Edges.Cast());
}
}
return geometryObjects;
}
///
/// 主次分支连接
///
/// 主管
/// 分支
public static void ConnectTo(this MEPCurve mainMepCurve, MEPCurve branchMepCurve)
{
var document = mainMepCurve.Document;
var unboundBranchCurve = branchMepCurve.GetLocCurve();
unboundBranchCurve.MakeUnbound();
var unboundMainCurve = mainMepCurve.GetLocCurve();
unboundMainCurve.MakeUnbound();
var intersection = unboundBranchCurve.IntersectionPoint(unboundMainCurve) ?? throw new InvalidOperationException("主次分支管线不存在交点");
var line = mainMepCurve.GetLocCurve() as Line;
//根据交点在管线内的位置,判断是形成弯头还是三通
if (line.IsInsideEx(intersection, 0.5)) //三通
{
var newMainMEPCurveId = mainMepCurve.BreakByPoint(intersection);
var newMainMEPCurve = document.GetElement(newMainMEPCurveId) as MEPCurve;
var mainConnectors = ConnectorExtensions.GetNearestConnectors(mainMepCurve, newMainMEPCurve);
var branchConnector = branchMepCurve.GetConnectors(true).GetNearestConnector(intersection);
/* 项目“Szmedi.Toolkit (net48)”的未合并的更改
在此之前:
branchConnector.ConnectByTee(mainConnectors[0], mainConnectors[1]);
在此之后:
branchConnector.ConnectByTee(mainConnectors[0], mainConnectors[1]);
*/
branchConnector.ConnectByTee(mainConnectors[0], mainConnectors[1]);
}
else //弯头
{
var conn = mainMepCurve.GetConnectors(true).GetNearestConnector(intersection);
var conn2 = branchMepCurve.GetConnectors(true).GetNearestConnector(intersection);
/* 项目“Szmedi.Toolkit (net48)”的未合并的更改
在此之前:
conn.ConnectByFitting(conn2);
在此之后:
conn.ConnectByFitting(conn2);
*/
conn.ConnectByFitting(conn2);
}
}
public static HermiteSpline ConverToHermiteSpline(this PolyLine polyLine)
{
var list = polyLine.GetCoordinates();
return HermiteSpline.Create(list, false);
}
///
/* 项目“Szmedi.Toolkit (net48)”的未合并的更改
在此之前:
/// 分支连接
///
///
///
///
///
public static FamilyInstance ConnectByTee(this Connector branch, Connector connector, Connector connector1)
{
doc doc = branch.Owner.doc;
//获取垂直主管的向量
XYZ normal = connector.CoordinateSystem.BasisZ.CrossProduct(branch.CoordinateSystem.BasisZ);
XYZ vertical = connector.CoordinateSystem.BasisZ.CrossProduct(normal);
Line mainLine = Line.CreateUnbound(connector.Origin, connector.CoordinateSystem.BasisZ);
Line branchLine = Line.CreateUnbound(branch.Origin, branch.CoordinateSystem.BasisZ);
//分支和主管的角度
double cos = branch.CoordinateSystem.BasisZ.DotProduct(connector.CoordinateSystem.BasisZ);
double angle = Math.Acos(cos);
//主管和分支管的交点
XYZ intersect = mainLine.IntersectionPoint(branchLine);
//垂直主管的分支管,为了创建默认三通
Line verticalLine = Line.CreateBound(intersect, intersect + (3.0 * vertical));
//延长管线到交点处
branch.Owner.SetLocationCurve((branch.Owner.GetLocCurve() as Line).ExtendLine(intersect));
connector.Owner.SetLocationCurve((connector.Owner.GetLocCurve() as Line).ExtendLine(intersect));
connector1.Owner.SetLocationCurve((connector1.Owner.GetLocCurve() as Line).ExtendLine(intersect));
//复制支管创建垂直主管的管线
ElementId verticalMEPCurveId = ElementTransformUtils.CopyElement(doc, branch.Owner.Id, XYZ.Zero).FirstOrDefault();
MEPCurve verticalMEPCurve = doc.GetElement(verticalMEPCurveId) as MEPCurve;
verticalMEPCurve.SetLocationCurve(verticalLine);
//获取垂直管的连接件
Connector tempBranchConnector = verticalMEPCurve.GetConnectors().GetNearestConnector(intersect);
//创建三通
FamilyInstance tee = doc.Create.NewTeeFitting(connector, connector1, tempBranchConnector);
if (tempBranchConnector.GetConnectedConnector().Owner.Id != tee.Id)
{
doc.Delete(tempBranchConnector.GetConnectedConnector().Owner.Id);
}
doc.Delete(verticalMEPCurveId);
//三通中未连接的连接件即分支连接件
Connector teeBranchConn = tee.GetConnectors(true).OfType().FirstOrDefault();
try
{
//设置三通角度
teeBranchConn!.Angle = Math.PI - angle;
}
catch (Autodesk.Revit.Exceptions.InvalidOperationException)
{
Debug.WriteLine("无法修改管线角度");
}
doc.Regenerate();
//Connector branchFarConn = branch.Owner.GetConnectors().GetFarthestConnector(intersect);
//Line newBranch = Line.CreateBound(branchFarConn.Origin, teeBranchConn.Origin);
Line l = branch.Owner.GetLocCurve() as Line;
Line newBranchLine = l.ExtendLine(teeBranchConn!.Origin);
branch.Owner.SetLocationCurve(newBranchLine);
//Line line = branch.Owner.GetLocCurve() as Line;
//if (newBranch.Direction.IsAlmostEqualTo(line.Direction))
//{
// (branch.Owner.Location as LocationCurve).Curve = newBranch;
//}
//else if (newBranch.Direction.IsAlmostEqualTo(-line.Direction))
//{
// (branch.Owner.Location as LocationCurve).Curve = newBranch.CreateReversed();
//}
Connector newBranchConn = GetNearestConnector(branch.Owner.GetConnectors(), intersect);
newBranchConn.ConnectByFitting(teeBranchConn);
return tee;
}
///
/// 新建视图并设置剖切框
在此之后:
/// 新建视图并设置剖切框
*/
///
/// 新建视图并设置剖切框
///
///
/// 复制的三维视图
///
///
public static View3D CreateSectionBox(this View3D view3D, IEnumerable elementIds, bool inCurrentView)
{
var doc = view3D.Document;
XYZ extendXyz = new(1, 1, 1);
BoundingBoxXYZ b;
if (elementIds.Count() == 1)
{
var e = doc.GetElement(elementIds.FirstOrDefault());
b = e.get_BoundingBox(view3D);
var max = b.Max + extendXyz;
var min = b.Min - extendXyz;
b = new BoundingBoxXYZ { Max = max, Min = min };
}
else
{
var f = doc.GetElement(elementIds.FirstOrDefault(elem => doc.GetElement(elem).get_BoundingBox(view3D) != null));
b = f.get_BoundingBox(view3D);
var maxX = b.Max.X;
var maxY = b.Max.Y;
var maxZ = b.Max.Z;
var minX = b.Min.X;
var minY = b.Min.Y;
var minZ = b.Min.Z;
foreach (var elementId in elementIds)
{
var e = doc.GetElement(elementId);
var bb = e.get_BoundingBox(doc.ActiveView);
if (bb.Max.X >= maxX)
{
maxX = bb.Max.X;
}
if (bb.Max.Y >= maxY)
{
maxY = bb.Max.Y;
}
if (bb.Max.Z >= maxZ)
{
maxZ = bb.Max.Z;
}
if (bb.Min.X <= minX)
{
minX = bb.Min.X;
}
if (bb.Min.Y <= minY)
{
minY = bb.Min.Y;
}
if (bb.Min.Z <= minZ)
{
minZ = bb.Min.Z;
}
}
var max = new XYZ(maxX, maxY, maxZ) + extendXyz;
var min = new XYZ(minX, minY, minZ) - extendXyz;
b = new BoundingBoxXYZ { Max = max, Min = min };
}
if (!view3D.IsSectionBoxActive)
{
view3D.IsSectionBoxActive = true;
}
if (inCurrentView)
{
view3D.SetSectionBox(b);
return view3D;
}
var viewCopyId = view3D.Duplicate(ViewDuplicateOption.WithDetailing);
var viewCopy = doc.GetElement(viewCopyId) as View3D;
viewCopy?.SetSectionBox(b);
return viewCopy;
}
public static double Distance(this Line line1, Line line2)
{
double distance;
var v1 = line1.Direction;
var p1 = line1.GetEndPoint(0);
var v2 = line2.Direction;
var p2 = line2.GetEndPoint(0);
var a = p1.X - p2.X;
var b = p1.Y - p2.Y;
var c = p1.Z - p2.Z;
var pq = v1.X * v2.Y - v2.X * v1.Y;
var qr = v1.Y * v2.Z - v2.Y * v1.Z;
var rp = v1.Z * v2.X - v2.Z * v1.X;
var dev = Math.Sqrt(Math.Pow(qr, 2) + Math.Pow(rp, 2) + Math.Pow(pq, 2));
if (dev < 1e-9)
{
var bp = b * v1.X;
var br = b * v1.Z;
var cp = c * v1.X;
var cq = c * v1.Y;
var aq = a * v1.Y;
var ar = a * v1.Z;
distance =
Math.Sqrt(Math.Pow(br - cq, 2) + Math.Pow(cp - ar, 2) + Math.Pow(aq - bp, 2))
/ Math.Sqrt(Math.Pow(v1.X, 2) + Math.Pow(v1.Y, 2) + Math.Pow(v1.Z, 2));
}
else
{
distance = Math.Abs((qr * a + rp * b + pq * c) / dev);
}
return distance;
}
///
/// 延长或缩短直线
///
///
///
/// 保留部分,为空时,保留长的部分
///
public static Line ExtendLine(this Line line, XYZ endPoint, bool? startSection = null)
{
var v = endPoint - line.GetEndPoint(0);
var v2 = endPoint - line.GetEndPoint(1);
//点刚好是直线端点
if (v.IsZeroLength() || v2.IsZeroLength())
{
return line;
}
//必须平行才能延伸
if (v.IsParallelTo(v2))
{
//点在直线外,同方向
if (line.Direction.DotProduct(v) > 0.0 && line.Direction.DotProduct(v2) > 0.0)
{
return Line.CreateBound(line.GetEndPoint(0), endPoint);
}
//点在直线外,反方向
if (line.Direction.DotProduct(v) < 0.0 && line.Direction.DotProduct(v2) < 0.0)
{
return Line.CreateBound(endPoint, line.GetEndPoint(1));
}
//点在直线内
return v.DotProduct(v2) < 0.0
? startSection == null
? v.GetLength() >= v2.GetLength()
? Line.CreateBound(line.GetEndPoint(0), endPoint)
: Line.CreateBound(endPoint, line.GetEndPoint(1))
: startSection == true
? Line.CreateBound(line.GetEndPoint(0), endPoint)
: Line.CreateBound(endPoint, line.GetEndPoint(1))
: null;
}
return line;
//throw new InvalidOperationException("不可延伸到该点");
}
///
/// 延长直线
///
///
///
/// 是否双向延申,单向延长终点
///
public static Line ExtendLine(this Line line, double distance, bool isInteractive = false)
{
var endPoint = line.GetEndPoint(1) + line.Direction * distance;
var startPoint = line.GetEndPoint(0);
if (isInteractive)
{
startPoint += line.Direction.Negate() * distance;
}
return Line.CreateBound(startPoint, endPoint);
}
///
/// 点拍平到xy平面
///
///
///
public static XYZ Flatten(this XYZ xyz)
{
return xyz.Subtract(XYZ.BasisZ * xyz.Z);
}
///
/// 点拍平到标高平面
///
///
///
public static XYZ FlattenTo(this XYZ xyz, Level level)
{
var z = level.Elevation;
return xyz.Add(XYZ.BasisZ * (z - xyz.Z));
}
///
/// 获取块参照实例
///
///
///
///
public static List GetBlockInstance(this ImportInstance dwg, Reference reference)
{
var geoElem = dwg.get_Geometry(new Options());
var geoObj = dwg.GetGeometryObjectFromReference(reference);
GeometryInstance referBlock = null;
foreach (var obj in geoElem)
{
if (obj is GeometryInstance dwgGeo) //dwg几何实例
{
foreach (var block in dwgGeo.SymbolGeometry) //块
{
if (block is GeometryInstance ins)
{
if (ins.GetHashCode() == geoObj.GetHashCode())
{
referBlock = ins;
break;
}
else
{
foreach (var subBlock in ins.SymbolGeometry) //嵌套块/子块
{
if (subBlock is GeometryInstance subIns && subIns.GetHashCode() == geoObj.GetHashCode())
{
referBlock = ins;
break;
}
}
}
}
}
}
}
if (referBlock == null)
{
return null;
}
List blocks = [];
foreach (var obj in geoElem)
{
if (obj is GeometryInstance dwgGeo)
{
foreach (var block in dwgGeo.SymbolGeometry) //图元
{
if (block is GeometryInstance ins && ins.Symbol.Name == referBlock.Symbol.Name)
{
blocks.Add(ins);
}
}
}
}
return blocks;
}
///
/// 得到元素所有连接件
///
///
/// 获取未使用的连接件,否则获取全部
///
public static ConnectorSet GetConnectors(this Element element, bool isUnused = false)
{
var connectorSet = new ConnectorSet();
switch (element)
{
case FamilyInstance familyInstance:
connectorSet = isUnused
? familyInstance.MEPModel.ConnectorManager?.UnusedConnectors
: familyInstance.MEPModel?.ConnectorManager?.Connectors;
break;
case MEPCurve mepCurve:
connectorSet = isUnused ? mepCurve.ConnectorManager.UnusedConnectors : mepCurve.ConnectorManager.Connectors;
break;
case FabricationPart fabricationPart:
connectorSet = isUnused ? fabricationPart.ConnectorManager.UnusedConnectors : fabricationPart.ConnectorManager.Connectors;
break;
}
return connectorSet;
}
///
/// 获取dwg的曲线
///
///
///
public static List GetCurves(this ImportInstance importInstance)
{
List curves = [];
var geoElem = importInstance.get_Geometry(new Options());
foreach (var geomObj in geoElem)
{
var geomInstance = geomObj as GeometryInstance;
if (geomInstance != null)
{
foreach (var instObj in geomInstance.GetInstanceGeometry())
{
//polyLine拆成线
if (instObj is PolyLine line)
{
var poly = line.GetCoordinates();
for (var i = 0; i < poly.Count - 1; i++)
{
var l = Line.CreateBound(poly[i], poly[i + 1]);
curves.Add(l);
}
}
if (instObj is Arc arc)
{
curves.Add(arc);
}
}
}
}
return curves;
}
public static ElementId GetElementId(this BuiltInCategory builtInCategory, Document doc)
{
return Category.GetCategory(doc, builtInCategory).Id;
}
///
/// 获取顶层的几何(非嵌套)
///
///
///
///
public static List GetGeometryObjects(this Element elem)
{
List geometryObjects = [];
Options option = new() { ComputeReferences = true, DetailLevel = ViewDetailLevel.Fine };
var geometry = elem.get_Geometry(option);
foreach (var geomObj in geometry)
{
geometryObjects.Add(geomObj);
}
return geometryObjects;
}
///
/// 获取几何对象
///
/// 对应类型的几何对象,如Solid、Face、Edge
/// 获取的元素
///
public static List GetGeometryObjects(this Element elem)
where T : GeometryObject
{
List geometryObjects = [];
Options option = new() { ComputeReferences = true, DetailLevel = ViewDetailLevel.Fine };
var geometry = elem.get_Geometry(option);
foreach (var geomObj in geometry)
{
if (geomObj is GeometryInstance geomInstance)
{
var usesSymbolGeometry = elem is FamilyInstance instance && !instance.HasModifiedGeometry();
var geometryElement = usesSymbolGeometry ? geomInstance.GetSymbolGeometry() : geomInstance.GetInstanceGeometry();
foreach (var geoObject in geometryElement)
{
geometryObjects.AddRange(geoObject.GetGeoObjects());
}
}
geometryObjects.AddRange(geomObj.GetGeoObjects());
}
return geometryObjects;
}
///
/// 获取参考所在的图层名称
///
///
///
///
public static string GetLayerName(this ImportInstance dwg, Reference reference)
{
var obj = dwg.GetGeometryObjectFromReference(reference);
var style = dwg.Document.GetElement(obj.GraphicsStyleId) as GraphicsStyle;
return style?.GraphicsStyleCategory.Name;
}
///
/// 获取标高
///
///
///
public static ElementId GetLevelId(this Element model)
{
// 定义需要检查的参数列表
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 = model.get_Parameter(param)?.AsElementId();
if (baseLevelId != ElementId.InvalidElementId && baseLevelId != null)
{
return baseLevelId;
}
}
//最后检查楼板或族基准标高
return model.LevelId;
}
///
/// 获取元素定位线
///
/// 以曲线定位的实例
///
public static Curve GetLocCurve(this Element instance)
{
return instance.Location is LocationCurve lc ? lc.Curve : null;
}
///
/// 获取元素定位点
///
/// 以点定位的实例
///
public static XYZ GetLocXYZ(this Element instance)
{
return instance.Location is LocationPoint lc ? lc.Point : null;
}
///
/// 同专业类型的最近连接件
///
///
///
///
///
public static List GetNearestDomainConnectors(Element element1, Element element2, bool isUnused = true)
{
List list = [];
Connector conn = null;
Connector conn2 = null;
var distance = double.MaxValue;
foreach (Connector connTemp in element1.GetConnectors(isUnused))
{
foreach (Connector connTemp2 in element2.GetConnectors(isUnused))
{
var tempDistance = connTemp.Origin.DistanceTo(connTemp2.Origin);
if (connTemp.Domain == connTemp2.Domain && distance > tempDistance)
{
distance = tempDistance;
conn = connTemp;
conn2 = connTemp2;
}
}
}
if (conn != null)
{
list.Add(conn);
}
if (conn2 != null)
{
list.Add(conn2);
}
return list;
}
///
/// 计算两条线的交点
///
///
///
///
public static XYZ IntersectionPoint(this Curve curve1, Curve curve2)
{
var comparisonR = curve1.Intersect(curve2, out var intersectionR);
XYZ intersectionResult = null;
if (SetComparisonResult.Disjoint != comparisonR) // Disjoint无交点
{
try
{
if (intersectionR != null && !intersectionR.IsEmpty)
{
intersectionResult = intersectionR.get_Item(0).XYZPoint;
}
}
catch
{
// ignored
}
}
return intersectionResult;
}
public static XYZ IntersectPoint(this Plane plane, Line line)
{
var startPoint = line.Origin;
var projectPoint = plane.ProjectOnto(startPoint);
if (Math.Abs(line.Direction.DotProduct(plane.Normal)) < 10E-8) //是否平行
{
return null;
}
var length = startPoint.DistanceTo(projectPoint);
if (length < 10E-8) //不平行,但刚好是Origin,即为交点
{
return projectPoint;
}
var vector = projectPoint - startPoint;
//var per = Line.CreateBound(startPoint, projectPoint);//垂线
if (vector.IsParallelTo(line.Direction))
{
return projectPoint;
}
var cos = plane.Normal.DotProduct(line.Direction);
if (cos < 0)
{
cos = plane.Normal.Negate().DotProduct(line.Direction);
}
var distance = length / cos;
return vector.Normalize().DotProduct(line.Direction) < 0
? startPoint - line.Direction * distance
: startPoint + line.Direction * distance;
}
///
/// 点是否在直线范围内
///
///
///
/// 两边端点距离
///
public static bool IsInsideEx(this Line line, XYZ point, double endParameter = 0.0)
{
var flag = line == null;
if (flag)
{
throw new ArgumentNullException(nameof(line));
}
var isBound = line.IsBound;
bool result;
if (isBound)
{
var d = point.DistanceTo(line.GetEndPoint(0));
var d2 = point.DistanceTo(line.GetEndPoint(1));
result = d + d2 - line.Length < 1E-05 && d >= endParameter && d2 >= endParameter;
}
else
{
result = false;
}
return result;
}
///
/// 判断直线是否平行或重合
///
///
///
///
public static bool IsParallelTo(this Line line, Line checkedLine)
{
var a = line.Direction.CrossProduct(checkedLine.Direction).IsZeroLength();
var b = line.Direction.CrossProduct(checkedLine.Direction).IsAlmostEqualTo(XYZ.Zero);
var c = 1 - Math.Abs(line.Direction.DotProduct(checkedLine.Direction)) < Tolerance;
return a || b || c;
}
///
/// 判断方向是否平行
///
///
///
///
public static bool IsParallelTo(this XYZ direction1, XYZ direction2)
{
return direction1.CrossProduct(direction2).IsZeroLength() || direction1.CrossProduct(direction2).IsAlmostEqualTo(XYZ.Zero);
}
///
/// 判断直线是否垂直
///
///
///
///
///
public static bool IsPerpendicularTo(this Line line, Line checkedLine, double tolerance = Tolerance)
{
return Math.Abs(line.Direction.DotProduct(checkedLine.Direction)) < tolerance; //点乘满足交换律不影响计算结果
}
///
/// 直线在平面上的投影
///
///
///
///
public static Line ProjectOnto(this Plane plane, Line line)
{
return Line.CreateBound(plane.ProjectOnto(line.GetEndPoint(0)), plane.ProjectOnto(line.GetEndPoint(1)));
}
///
/// 点在几何面的投影
///
///
///
///
public static XYZ ProjectOnto(this PlanarFace plane, XYZ p)
{
var d = plane.SignedDistanceTo(p, out _);
var q = p - d * plane.FaceNormal;
return q;
}
///
/// 点在参照平面上的投影
///
///
///
///
public static XYZ ProjectOnto(this Plane plane, XYZ p)
{
var d = plane.SignedDistanceTo(p, out _);
var q = p - d * plane.Normal;
return q;
}
public static void SetBorderColor(this Element element, Color color, View view = null)
{
var doc = element.Document;
view ??= doc.ActiveView;
var overrideGraphicSettings = view.GetElementOverrides(element.Id);
var pat = new FilteredElementCollector(doc)
.OfClass(typeof(FillPatternElement))
.ToElements()
.Cast()
.Where(pattern =>
{
var fill = pattern.GetFillPattern();
return fill.Target == FillPatternTarget.Drafting
&& fill.HostOrientation == FillPatternHostOrientation.ToView
&& fill.IsSolidFill;
})
.FirstOrDefault();
overrideGraphicSettings.SetProjectionLineColor(color);
overrideGraphicSettings.SetCutLineColor(color);
view.SetElementOverrides(element.Id, overrideGraphicSettings);
}
public static void SetFillColor(this Element element, Color color, View view = null)
{
var doc = element.Document;
view ??= doc.ActiveView;
var overrideGraphicSettings = view.GetElementOverrides(element.Id);
var pat = new FilteredElementCollector(doc)
.OfClass(typeof(FillPatternElement))
.ToElements()
.Cast()
.Where(pattern =>
{
var fill = pattern.GetFillPattern();
return fill.Target == FillPatternTarget.Drafting
&& fill.HostOrientation == FillPatternHostOrientation.ToView
&& fill.IsSolidFill;
})
.FirstOrDefault();
#if REVIT2018
overrideGraphicSettings.SetProjectionFillPatternId(pat.Id);
overrideGraphicSettings.SetProjectionLineColor(color);
overrideGraphicSettings.SetCutFillPatternId(pat.Id);
overrideGraphicSettings.SetCutLineColor(color);
view.SetElementOverrides(element.Id, overrideGraphicSettings);
#elif REVIT2020
overrideGraphicSettings.SetSurfaceForegroundPatternColor(color);
overrideGraphicSettings.SetSurfaceForegroundPatternId(pat.Id); //实体填充
overrideGraphicSettings.SetCutForegroundPatternColor(color);
overrideGraphicSettings.SetCutForegroundPatternId(pat.Id); //实体填充
#endif
}
///
/// 设置元素定位线
///
///
///
///
public static void SetLocationCurve(this Element instance, Curve curve)
{
if (instance == null)
{
throw new ArgumentNullException(nameof(instance));
}
if (curve == null)
{
throw new ArgumentNullException(nameof(curve));
}
if (instance.Location is LocationCurve lc)
{
try
{
lc.Curve = curve;
}
catch (Exception)
{
throw new InvalidOperationException("无法修改定位线");
}
}
}
///
/// 点与几何平面的距离(可正可负)
///
///
///
///
///
public static double SignedDistanceTo(this PlanarFace plane, XYZ p, out XYZ projectPoint)
{
var v = p - plane.Origin;
//垂向距离(可正可负,夹角钝角为负)
var perp = v.DotProduct(plane.FaceNormal);
projectPoint = p - perp * plane.FaceNormal;
return perp;
}
///
/// 点与平面的距离(可正可负)
///
///
///
///
///
public static double SignedDistanceTo(this Plane plane, XYZ p, out XYZ projectPoint)
{
var v = p - plane.Origin;
//垂向距离(可正可负,夹角钝角为负)
var perp = v.DotProduct(plane.Normal);
projectPoint = p - perp * plane.Normal;
return perp;
}
public static BuiltInCategory ToBuiltInCategory(this Category category)
{
var builtInCategory = (BuiltInCategory)category.Id.IntegerValue;
return Enum.IsDefined(typeof(BuiltInCategory), builtInCategory)
? builtInCategory
: throw new ArgumentNullException(nameof(category), "不存在该内建类别");
}
public static Element ToElement(this ElementId id, Document doc)
{
return doc.GetElement(id);
}
}