using System.Diagnostics; using Autodesk.Revit.DB; using Autodesk.Revit.DB.Electrical; namespace Sai.Toolkit.Revit.Assist; public static class ConnectorAssist { /// /// 连接件管件连接,同管径,都为管线创建活接头 /// /// /// /// 连接的管件 public static FamilyInstance ConnectByFitting(this Connector first, Connector second) { if (first == null || second == null) { return null; } var document = first.Owner.Document; var isSameSize = false; //相同规格、尺寸 if (first.Domain != second.Domain) { throw new ArgumentException("无法连接不同类型的管线"); } switch (first.Domain) { case Domain.DomainHvac: { if (first.Shape == second.Shape) { var shape = first.Shape; //判断管径是否一致 isSameSize = shape is ConnectorProfileType.Oval or ConnectorProfileType.Rectangular ? Math.Abs(first.Width - second.Width) < 0.0001 && Math.Abs(first.Height - second.Height) < 0.0001 : Math.Abs(first.Radius - second.Radius) < 0.0001; } break; } case Domain.DomainPiping: isSameSize = Math.Abs(first.Radius - second.Radius) < 0.0001; break; case Domain.DomainCableTrayConduit: { if (first.Owner.GetType() == second.Owner.GetType()) { if (second.Owner is Conduit) { isSameSize = Math.Abs(first.Radius - second.Radius) < 0.0001; } if (second.Owner is CableTray) { isSameSize = Math.Abs(first.Width - second.Width) < 0.0001 && Math.Abs(first.Height - second.Height) < 0.0001; } } break; } } try { //平行时,创建过渡件和活接头 if (first.CoordinateSystem.BasisZ.IsParallelTo(second.CoordinateSystem.BasisZ)) { //管径一致时,根据情况创建活接头 if (isSameSize) { //有一个是族的时候,始终直接连接,不创建活接头 if (first.Owner is MEPCurve ^ second.Owner is MEPCurve) { if (!first.IsConnectedTo(second)) { first.ConnectTo(second); } } //都是管线 if (first.Owner is MEPCurve && second.Owner is MEPCurve) { return document.Create.NewUnionFitting(first, second); } //都是族的连接件 if (first.Owner is FamilyInstance && second.Owner is FamilyInstance) { first.ConnectTo(second); } return null; } else { //管径不一致时,创建过渡件 if (first.Owner is MEPCurve) { return document.Create.NewTransitionFitting(first, second); } if (second.Owner is MEPCurve) { return document.Create.NewTransitionFitting(second, first); } //都是族的连接件 if (first.Owner is FamilyInstance && second.Owner is FamilyInstance) { first.ConnectTo(second); } return null; } } //不平行则创建弯头 return document.Create.NewElbowFitting(first, second); } catch (Exception) { return null; } } /// /// 分支连接 /// /// 支管连接件 /// /// /// public static FamilyInstance ConnectByTee(this Connector branch, Connector connector, Connector connector1) { var document = branch.Owner.Document; //获取垂直主管的向量 var normal = connector.CoordinateSystem.BasisZ.CrossProduct(branch.CoordinateSystem.BasisZ); var vertical = connector.CoordinateSystem.BasisZ.CrossProduct(normal); var mainLine = Line.CreateUnbound(connector.Origin, connector.CoordinateSystem.BasisZ); var branchLine = Line.CreateUnbound(branch.Origin, branch.CoordinateSystem.BasisZ); //分支和主管的角度 var cos = branch.CoordinateSystem.BasisZ.DotProduct(connector.CoordinateSystem.BasisZ); var angle = Math.Acos(cos); //主管和分支管的交点 var intersect = mainLine.IntersectionPoint(branchLine); //垂直主管的分支管,为了创建默认三通 var verticalLine = Line.CreateBound(intersect, intersect + (3.0 * vertical)); //延长管线到交点处 branch.Owner.SetLocationCurve((branch.Owner.GetCurve() as Line).ExtendLine(intersect)); connector.Owner.SetLocationCurve((connector.Owner.GetCurve() as Line).ExtendLine(intersect)); connector1.Owner.SetLocationCurve((connector1.Owner.GetCurve() as Line).ExtendLine(intersect)); //复制支管创建垂直主管的管线 var verticalMEPCurveId = ElementTransformUtils.CopyElement(document, branch.Owner.Id, XYZ.Zero).FirstOrDefault(); var verticalMEPCurve = document.GetElement(verticalMEPCurveId) as MEPCurve; verticalMEPCurve.SetLocationCurve(verticalLine); //获取垂直管的连接件 var tempBranchConnector = verticalMEPCurve.GetConnectors().GetNearestConnector(intersect); //创建三通 var tee = document.Create.NewTeeFitting(connector, connector1, tempBranchConnector); if (tempBranchConnector.GetConnectedConnector().Owner.Id != tee.Id) { document.Delete(tempBranchConnector.GetConnectedConnector().Owner.Id); } document.Delete(verticalMEPCurveId); //三通中未连接的连接件即分支连接件 var teeBranchConn = tee.GetConnectors(true).OfType().FirstOrDefault(); try { //设置三通角度 teeBranchConn!.Angle = Math.PI - angle; } catch (Autodesk.Revit.Exceptions.InvalidOperationException) { Debug.WriteLine("无法修改管线角度"); } document.Regenerate(); //Connector branchFarConn = branch.Owner.GetConnectors().GetFarthestConnector(intersect); //Line newBranch = Line.CreateBound(branchFarConn.Origin, teeBranchConn.Origin); var l = branch.Owner.GetCurve() as Line; var newBranchLine = l.ExtendLine(teeBranchConn!.Origin); branch.Owner.SetLocationCurve(newBranchLine); //Line line = branch.Owner.GetCurve() 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(); //} var newBranchConn = GetNearestConnector(branch.Owner.GetConnectors(), intersect); newBranchConn.ConnectByFitting(teeBranchConn); return tee; } /// /// 获得所有连接的元素 /// /// 起始连接件 /// 连接的所有元素ID public static void GetAllRefElementIds(this Connector startConnector, ICollection elemIdsConnected) { if (!startConnector.IsConnected) { return; } if (!elemIdsConnected.Contains(startConnector.Owner.Id)) { elemIdsConnected.Add(startConnector.Owner.Id); } //连接的元素 //得到与当前连接件连接的连接件 foreach (Connector currentConn in startConnector.AllRefs) { //连接的连接件 if (currentConn.ConnectorType == ConnectorType.End && currentConn.Owner.Id != startConnector.Owner.Id) { if (elemIdsConnected.Contains(currentConn.Owner.Id)) { continue; } elemIdsConnected.Add(currentConn.Owner.Id); var allConnectors = currentConn.Owner.GetConnectors(); //找到连接的连接件 foreach (Connector item in allConnectors) { if (startConnector.Origin.IsAlmostEqualTo(item.Origin)) //沿着往下找 { continue; } GetAllRefElementIds(item, elemIdsConnected); } } } } /// /// 获得所有连接的元素 /// /// 起始连接件 /// 连接的元素 public static void GetAllRefsElements(this Connector startConnector, ICollection elemsConnected) { if (!startConnector.IsConnected) { return; } if (!elemsConnected.Contains(startConnector.Owner)) { elemsConnected.Add(startConnector.Owner); } //连接的元素 //得到与当前连接件连接的连接件 foreach (Connector currentConn in startConnector.AllRefs) { //连接的连接件 if (currentConn.ConnectorType == ConnectorType.End && currentConn.Owner.Id != startConnector.Owner.Id) { if (elemsConnected.Contains(currentConn.Owner)) { continue; } elemsConnected.Add(currentConn.Owner); var allConnectors = currentConn.Owner.GetConnectors(); //找到连接的元素的连接件 foreach (Connector item in allConnectors) { if (startConnector.Origin.IsAlmostEqualTo(item.Origin)) //沿着往下找 { continue; } GetAllRefsElements(item, elemsConnected); } } } } /// /// 获取与当前连接件已连接的连接件 /// /// 当前连接件 /// public static Connector GetConnectedConnector(this Connector connector) { return connector.IsConnected ? connector.AllRefs.Cast().FirstOrDefault(c => ConnectorType.End == c.ConnectorType && !c.Owner.Id.Equals(connector.Owner.Id)) : null; } /// /// 得到元素所有连接件 /// /// /// True,获取未使用的连接件;False,获取所有连接件 /// public static ConnectorSet GetConnectors(this Element element, bool isUnused = false) => element switch { FamilyInstance familyInstance => isUnused ? familyInstance.MEPModel?.ConnectorManager.UnusedConnectors : familyInstance.MEPModel?.ConnectorManager.Connectors, MEPCurve mepCurve => isUnused ? mepCurve.ConnectorManager.UnusedConnectors : mepCurve.ConnectorManager.Connectors, FabricationPart fabricationPart => isUnused ? fabricationPart.ConnectorManager.UnusedConnectors : fabricationPart.ConnectorManager.Connectors, _ => null }; /// /// 从连接件延伸长度 /// /// /// public static double GetExtensionLength(this Connector connector) { return connector.Domain switch { Domain.DomainHvac when connector.Shape == ConnectorProfileType.Rectangular => (connector.Width * 0.2) + (connector.Height * 0.2), Domain.DomainHvac when connector.Shape == ConnectorProfileType.Oval => (connector.Width * 0.2) + (connector.Height * 0.2), Domain.DomainHvac when connector.Shape == ConnectorProfileType.Round => connector.Radius * 0.5, Domain.DomainPiping => connector.Radius * 4, Domain.DomainCableTrayConduit => 1, _ => 0.5 }; } /// /// 距离所选点最远的连接件 /// /// /// 选择点 /// public static Connector GetFarthestConnector(this ConnectorSet set, XYZ startPoint) { Connector result = null; var minValue = double.MinValue; foreach (Connector connector in set) { var d = connector.Origin.DistanceTo(startPoint); if (d > minValue) { minValue = d; result = connector; } } return result; } /// /// 获取两个元素最远的连接件 /// /// /// /// 是否包含已经连接 /// public static List GetFarthestConnectors(MEPCurve first, MEPCurve second, bool isUnused = true) { var list = new List(); Connector conn = null; Connector conn2 = null; var distance = double.MinValue; foreach (Connector connTemp in first.GetConnectors(isUnused)) { foreach (Connector connTemp2 in second.GetConnectors(isUnused)) { var tempDistance = connTemp.Origin.DistanceTo(connTemp2.Origin); if (distance < tempDistance) { distance = tempDistance; conn = connTemp; conn2 = connTemp2; } } } if (conn != null) { list.Add(conn); } if (conn2 != null) { list.Add(conn2); } return list; } ///// ///// 流向相反,类型相同的管线连接件 ///// ///// 查询的连接件集合 ///// 默认连接件 ///// //public static Connector GetNearestConnector(Connector c, ConnectorSet cA1) //{ // Connector result = null; // double num = double.MaxValue; // foreach (Connector current in cA1) // { // if (current.IsConnected) // { // continue; // } // if (current.Origin == c.Origin) continue; // double num3 = current.Origin.DistanceTo(c.Origin); // if (num3 < num && current.Domain == c.Domain && // c.CoordinateSystem.BasisZ.DotProduct(current.CoordinateSystem.BasisZ) < -0.9) // { // num = num3; // result = current; // } // } // return result; //} /// /// 获取集合中距离最近的连接件(含未连接和已连接) /// /// /// /// public static Connector GetNearestConnector(this ConnectorSet set, XYZ startPoint) { Connector result = null; var maxValue = double.MaxValue; foreach (Connector connector in set) { var value = connector.Origin.DistanceTo(startPoint); if (value < maxValue) { maxValue = value; result = connector; } } return result; } /// /// 最接近的两个连接件(排除重叠) /// /// 连接件合集 /// 连接件合集 /// 查找需要过滤管线的类型,undefined则查找全部类型 /// 排除已连接的连接件 /// public static Connector GetNearestConnectorByConnectSet( ConnectorSet set1, ConnectorSet set2, Domain domain = Domain.DomainUndefined, bool exclusionConnected = false ) { Connector result = null; var tempMax = double.MaxValue; foreach (Connector connector1 in set1) { if (exclusionConnected && connector1.IsConnected) { continue; } foreach (Connector connector2 in set2) { if (exclusionConnected && connector2.IsConnected) { continue; } if (connector2.Origin == connector1.Origin) { continue; } var distanceTo = connector2.Origin.DistanceTo(connector1.Origin); if (distanceTo < tempMax && (domain == Domain.DomainUndefined || connector2.Domain == domain)) { tempMax = distanceTo; result = connector2; } } } return result; } /// /// 获取最近的连接件 /// /// 第一个元素 /// /// /// 集合中的连接件的顺序与方法参数一一对应 /// 返回最近的连接件集合 public static List GetNearestConnectors(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 (distance > tempDistance) { distance = tempDistance; conn = connTemp; conn2 = connTemp2; } } } if (conn != null) { list.Add(conn); } if (conn2 != null) { list.Add(conn2); } return list; } /// /// 同领域的最近连接件 /// /// /// /// /// 同领域的最近连接件,若无,则返回空集合 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; } }