Files
SzmediTools/Szmedi.Toolkit.Revit/RvExtensions/ElementExtensions.cs
2025-09-16 16:06:41 +08:00

1052 lines
37 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 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
{
/// <summary>
/// 容差
/// </summary>
private const double Tolerance = 0.0001;
/// <summary>
/// 有类型定义的DirectShape
/// </summary>
/// <param name="doc"></param>
/// <param name="definitionId">定义名称,即是族名称、类型名称(强制一致),创建多个实例时,如果相同,则会合并在一个族中</param>
/// <param name="category">族类别</param>
/// <param name="geos">几何</param>
/// <returns></returns>
public static DirectShape CreateDirectShapeInstance(this Document doc, string definitionId, BuiltInCategory category, List<GeometryObject> 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;
}
/// <summary>
/// 已经打开的视图中缩放视图,最大化图元
/// </summary>
/// <param name="view"></param>
/// <param name="uidoc"></param>
/// <param name="elementId"></param>
/// <param name="extend">扩宽范围</param>
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);
/// <summary>
/// 无名称定义的DirectShape
/// </summary>
/// <param name="doc"></param>
/// <param name="geos"></param>
/// <param name="category"></param>
/// <returns></returns>
public static DirectShape CreateDirectShape(this Document doc, List<GeometryObject> geos, BuiltInCategory category)
{
var shape = DirectShape.CreateElement(doc, new ElementId(category));
shape.SetShape(geos);
return shape;
}
/// <summary>
/// 扩展包围盒的大小
/// </summary>
/// <param name="boundingBox"></param>
/// <param name="distance"></param>
/// <returns></returns>
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<T> GetGeoObjects<T>(this GeometryObject geoObject)
where T : GeometryObject
{
List<T> 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<T>());
}
else if (typeof(T) == typeof(Edge) && instSolid.Edges.Size > 0)
{
geometryObjects.AddRange(instSolid.Edges.Cast<T>());
}
}
return geometryObjects;
}
/// <summary>
/// 主次分支连接
/// </summary>
/// <param name="mainMepCurve">主管</param>
/// <param name="branchMepCurve">分支</param>
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);
}
/// <summary>
/* 项目“Szmedi.Toolkit (net48)”的未合并的更改
在此之前:
/// 分支连接
/// </summary>
/// <param name="branch"></param>
/// <param name="connector"></param>
/// <param name="connector1"></param>
/// <returns></returns>
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<Connector>().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;
}
/// <summary>
/// 新建视图并设置剖切框
在此之后:
/// 新建视图并设置剖切框
*/
/// <summary>
/// 新建视图并设置剖切框
/// </summary>
/// <param name="doc"></param>
/// <param name="view3D">复制的三维视图</param>
/// <param name="elementIds"></param>
/// <returns></returns>
public static View3D CreateSectionBox(this View3D view3D, IEnumerable<ElementId> 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;
}
/// <summary>
/// 延长或缩短直线
/// </summary>
/// <param name="line"></param>
/// <param name="endPoint"></param>
/// <param name="startSection">保留部分,为空时,保留长的部分</param>
/// <returns></returns>
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("不可延伸到该点");
}
/// <summary>
/// 延长直线
/// </summary>
/// <param name="line"></param>
/// <param name="distance"></param>
/// <param name="isInteractive">是否双向延申,单向延长终点</param>
/// <returns></returns>
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);
}
/// <summary>
/// 点拍平到xy平面
/// </summary>
/// <param name="xyz"></param>
/// <returns></returns>
public static XYZ Flatten(this XYZ xyz)
{
return xyz.Subtract(XYZ.BasisZ * xyz.Z);
}
/// <summary>
/// 点拍平到标高平面
/// </summary>
/// <param name="xyz"></param>
/// <returns></returns>
public static XYZ FlattenTo(this XYZ xyz, Level level)
{
var z = level.Elevation;
return xyz.Add(XYZ.BasisZ * (z - xyz.Z));
}
/// <summary>
/// 获取块参照实例
/// </summary>
/// <param name="dwg"></param>
/// <param name="reference"></param>
/// <returns></returns>
public static List<GeometryInstance> 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<GeometryInstance> 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;
}
/// <summary>
/// 得到元素所有连接件
/// </summary>
/// <param name="element"></param>
/// <param name="isUnused">获取未使用的连接件,否则获取全部</param>
/// <returns></returns>
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;
}
/// <summary>
/// 获取dwg的曲线
/// </summary>
/// <param name="importInstance"></param>
/// <returns></returns>
public static List<Curve> GetCurves(this ImportInstance importInstance)
{
List<Curve> 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;
}
/// <summary>
/// 获取顶层的几何(非嵌套)
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="elem"></param>
/// <returns></returns>
public static List<GeometryObject> GetGeometryObjects(this Element elem)
{
List<GeometryObject> 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;
}
/// <summary>
/// 获取几何对象
/// </summary>
/// <typeparam name="T">对应类型的几何对象如Solid、Face、Edge</typeparam>
/// <param name="elem">获取的元素</param>
/// <returns></returns>
public static List<T> GetGeometryObjects<T>(this Element elem)
where T : GeometryObject
{
List<T> 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<T>());
}
}
geometryObjects.AddRange(geomObj.GetGeoObjects<T>());
}
return geometryObjects;
}
/// <summary>
/// 获取参考所在的图层名称
/// </summary>
/// <param name="dwg"></param>
/// <param name="reference"></param>
/// <returns></returns>
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;
}
/// <summary>
/// 获取标高
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
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;
}
/// <summary>
/// 获取元素定位线
/// </summary>
/// <param name="instance">以曲线定位的实例</param>
/// <returns></returns>
public static Curve GetLocCurve(this Element instance)
{
return instance.Location is LocationCurve lc ? lc.Curve : null;
}
/// <summary>
/// 获取元素定位点
/// </summary>
/// <param name="instance">以点定位的实例</param>
/// <returns></returns>
public static XYZ GetLocXYZ(this Element instance)
{
return instance.Location is LocationPoint lc ? lc.Point : null;
}
/// <summary>
/// 同专业类型的最近连接件
/// </summary>
/// <param name="element1"></param>
/// <param name="element2"></param>
/// <param name="isUnused"></param>
/// <returns></returns>
public static List<Connector> GetNearestDomainConnectors(Element element1, Element element2, bool isUnused = true)
{
List<Connector> 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;
}
/// <summary>
/// 计算两条线的交点
/// </summary>
/// <param name="curve1"></param>
/// <param name="curve2"></param>
/// <returns></returns>
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;
}
/// <summary>
/// 点是否在直线范围内
/// </summary>
/// <param name="line"></param>
/// <param name="point"></param>
/// <param name="endParameter">两边端点距离</param>
/// <returns></returns>
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;
}
/// <summary>
/// 判断直线是否平行或重合
/// </summary>
/// <param name="line"></param>
/// <param name="checkedLine"></param>
/// <returns></returns>
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;
}
/// <summary>
/// 判断方向是否平行
/// </summary>
/// <param name="direction1"></param>
/// <param name="direction2"></param>
/// <returns></returns>
public static bool IsParallelTo(this XYZ direction1, XYZ direction2)
{
return direction1.CrossProduct(direction2).IsZeroLength() || direction1.CrossProduct(direction2).IsAlmostEqualTo(XYZ.Zero);
}
/// <summary>
/// 判断直线是否垂直
/// </summary>
/// <param name="line"></param>
/// <param name="checkedLine"></param>
/// <param name="tolerance"></param>
/// <returns></returns>
public static bool IsPerpendicularTo(this Line line, Line checkedLine, double tolerance = Tolerance)
{
return Math.Abs(line.Direction.DotProduct(checkedLine.Direction)) < tolerance; //点乘满足交换律不影响计算结果
}
/// <summary>
/// 直线在平面上的投影
/// </summary>
/// <param name="plane"></param>
/// <param name="line"></param>
/// <returns></returns>
public static Line ProjectOnto(this Plane plane, Line line)
{
return Line.CreateBound(plane.ProjectOnto(line.GetEndPoint(0)), plane.ProjectOnto(line.GetEndPoint(1)));
}
/// <summary>
/// 点在几何面的投影
/// </summary>
/// <param name="plane"></param>
/// <param name="p"></param>
/// <returns></returns>
public static XYZ ProjectOnto(this PlanarFace plane, XYZ p)
{
var d = plane.SignedDistanceTo(p, out _);
var q = p - d * plane.FaceNormal;
return q;
}
/// <summary>
/// 点在参照平面上的投影
/// </summary>
/// <param name="plane"></param>
/// <param name="p"></param>
/// <returns></returns>
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<FillPatternElement>()
.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<FillPatternElement>()
.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
}
/// <summary>
/// 设置元素定位线
/// </summary>
/// <param name="instance"></param>
/// <param name="curve"></param>
/// <returns></returns>
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("无法修改定位线");
}
}
}
/// <summary>
/// 点与几何平面的距离(可正可负)
/// </summary>
/// <param name="plane"></param>
/// <param name="p"></param>
/// <param name="projectPoint"></param>
/// <returns></returns>
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;
}
/// <summary>
/// 点与平面的距离(可正可负)
/// </summary>
/// <param name="plane"></param>
/// <param name="p"></param>
/// <param name="projectPoint"></param>
/// <returns></returns>
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);
}
}