Files

558 lines
20 KiB
C#
Raw Permalink Normal View History

2024-09-22 11:05:41 +08:00
using System.Diagnostics;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Electrical;
2026-02-21 16:31:24 +08:00
namespace ShrlAlgoToolkit.RevitCore.Extensions;
2024-09-22 11:05:41 +08:00
2025-07-11 09:20:23 +08:00
public static class ConnectorExtensions
2024-09-22 11:05:41 +08:00
{
/// <summary>
/// 连接件管件连接,同管径,都为管线创建活接头
/// </summary>
/// <param name="first"></param>
/// <param name="second"></param>
/// <returns>连接的管件</returns>
public static FamilyInstance ConnectByFitting(this Connector first, Connector second)
{
if (first == null || second == null)
{
return null;
}
var document = first.Owner.Document;
2024-12-22 10:26:12 +08:00
var isSameSize = false; //相同规格、尺寸
2024-09-22 11:05:41 +08:00
if (first.Domain != second.Domain)
{
throw new ArgumentException("无法连接不同类型的管线");
}
switch (first.Domain)
{
case Domain.DomainHvac:
{
if (first.Shape == second.Shape)
{
var shape = first.Shape;
//判断管径是否一致
2024-12-22 10:26:12 +08:00
isSameSize = shape is ConnectorProfileType.Oval or ConnectorProfileType.Rectangular
2024-09-22 11:05:41 +08:00
? 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:
2024-12-22 10:26:12 +08:00
isSameSize = Math.Abs(first.Radius - second.Radius) < 0.0001;
2024-09-22 11:05:41 +08:00
break;
case Domain.DomainCableTrayConduit:
{
if (first.Owner.GetType() == second.Owner.GetType())
{
if (second.Owner is Conduit)
{
2024-12-22 10:26:12 +08:00
isSameSize = Math.Abs(first.Radius - second.Radius) < 0.0001;
2024-09-22 11:05:41 +08:00
}
if (second.Owner is CableTray)
{
2024-12-22 10:26:12 +08:00
isSameSize = Math.Abs(first.Width - second.Width) < 0.0001 && Math.Abs(first.Height - second.Height) < 0.0001;
2024-09-22 11:05:41 +08:00
}
}
break;
}
}
try
{
2024-12-22 10:26:12 +08:00
//平行时,创建过渡件和活接头
2024-09-22 11:05:41 +08:00
if (first.CoordinateSystem.BasisZ.IsParallelTo(second.CoordinateSystem.BasisZ))
{
2024-12-22 10:26:12 +08:00
//管径一致时,根据情况创建活接头
2025-04-24 20:56:44 +08:00
if (isSameSize)
2024-09-22 11:05:41 +08:00
{
//有一个是族的时候,始终直接连接,不创建活接头
if (first.Owner is MEPCurve ^ second.Owner is MEPCurve)
{
if (!first.IsConnectedTo(second))
{
first.ConnectTo(second);
}
}
2024-12-22 10:26:12 +08:00
//都是管线
2025-04-24 20:56:44 +08:00
if (first.Owner is MEPCurve && second.Owner is MEPCurve)
2024-09-22 11:05:41 +08:00
{
return document.Create.NewUnionFitting(first, second);
}
//都是族的连接件
2024-12-22 10:26:12 +08:00
if (first.Owner is FamilyInstance && second.Owner is FamilyInstance)
{
first.ConnectTo(second);
}
2025-04-24 20:56:44 +08:00
2024-09-22 11:05:41 +08:00
return null;
}
2024-12-22 10:26:12 +08:00
else
2024-09-22 11:05:41 +08:00
{
2024-12-22 10:26:12 +08:00
//管径不一致时,创建过渡件
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;
2024-09-22 11:05:41 +08:00
}
}
2024-12-22 10:26:12 +08:00
//不平行则创建弯头
2024-09-22 11:05:41 +08:00
return document.Create.NewElbowFitting(first, second);
}
catch (Exception)
{
return null;
}
}
2026-02-22 21:12:18 +08:00
2024-09-22 11:05:41 +08:00
/// <summary>
/// 分支连接
/// </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)
{
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));
//延长管线到交点处
2024-12-22 10:26:12 +08:00
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));
2024-09-22 11:05:41 +08:00
//复制支管创建垂直主管的管线
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<Connector>().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);
2024-12-22 10:26:12 +08:00
var l = branch.Owner.GetCurve() as Line;
2024-09-22 11:05:41 +08:00
var newBranchLine = l.ExtendLine(teeBranchConn!.Origin);
branch.Owner.SetLocationCurve(newBranchLine);
2024-12-22 10:26:12 +08:00
//Line line = branch.Owner.GetCurve() as Line;
2024-09-22 11:05:41 +08:00
//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;
}
/// <summary>
/// 获得所有连接的元素
/// </summary>
/// <param name="startConnector">起始连接件</param>
/// <param name="elemIdsConnected">连接的所有元素ID</param>
public static void GetAllRefElementIds(this Connector startConnector, ICollection<ElementId> 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);
}
}
}
}
/// <summary>
/// 获得所有连接的元素
/// </summary>
/// <param name="startConnector">起始连接件</param>
/// <param name="elemsConnected">连接的元素</param>
public static void GetAllRefsElements(this Connector startConnector, ICollection<Element> 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);
}
}
}
}
/// <summary>
/// 获取与当前连接件已连接的连接件
/// </summary>
/// <param name="connector">当前连接件</param>
/// <returns></returns>
public static Connector GetConnectedConnector(this Connector connector)
{
return connector.IsConnected
? connector.AllRefs.Cast<Connector>().FirstOrDefault(c => ConnectorType.End == c.ConnectorType && !c.Owner.Id.Equals(connector.Owner.Id))
: null;
}
/// <summary>
/// 得到元素所有连接件
/// </summary>
/// <param name="element"></param>
/// <param name="isUnused">True,获取未使用的连接件;False,获取所有连接件</param>
/// <returns></returns>
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
};
/// <summary>
/// 从连接件延伸长度
/// </summary>
/// <param name="connector"></param>
/// <returns></returns>
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,
2024-12-22 10:26:12 +08:00
Domain.DomainPiping => connector.Radius * 4,
2024-09-22 11:05:41 +08:00
Domain.DomainCableTrayConduit => 1,
_ => 0.5
};
}
/// <summary>
/// 距离所选点最远的连接件
/// </summary>
/// <param name="set"></param>
/// <param name="startPoint">选择点</param>
/// <returns></returns>
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;
}
/// <summary>
/// 获取两个元素最远的连接件
/// </summary>
/// <param name="first"></param>
/// <param name="second"></param>
/// <param name="isUnused">是否包含已经连接</param>
/// <returns></returns>
2025-07-11 09:20:23 +08:00
public static List<Connector> GetFarthestConnectors(this MEPCurve first, MEPCurve second, bool isUnused = true)
2024-09-22 11:05:41 +08:00
{
var list = new List<Connector>();
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;
}
///// <summary>
///// 流向相反,类型相同的管线连接件
///// </summary>
///// <param name="cA1">查询的连接件集合</param>
///// <param name="c">默认连接件</param>
///// <returns></returns>
//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;
//}
/// <summary>
/// 获取集合中距离最近的连接件(含未连接和已连接)
/// </summary>
/// <param name="set"></param>
/// <param name="startPoint"></param>
/// <returns></returns>
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;
}
/// <summary>
/// 最接近的两个连接件(排除重叠)
/// </summary>
/// <param name="set1">连接件合集</param>
/// <param name="set2">连接件合集</param>
/// <param name="domain">查找需要过滤管线的类型,undefined则查找全部类型</param>
/// <param name="exclusionConnected">排除已连接的连接件</param>
/// <returns></returns>
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;
}
/// <summary>
/// 获取最近的连接件
/// </summary>
/// <param name="element1">第一个元素</param>
/// <param name="element2"></param>
/// <param name="isUnused"></param>
/// <remarks>集合中的连接件的顺序与方法参数一一对应</remarks>
/// <returns>返回最近的连接件集合</returns>
2025-07-11 09:20:23 +08:00
public static List<Connector> GetNearestConnectors(this Element element1, Element element2, bool isUnused = true)
2024-09-22 11:05:41 +08:00
{
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 (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="element1"></param>
/// <param name="element2"></param>
/// <param name="isUnused"></param>
/// <returns>同领域的最近连接件,若无,则返回空集合</returns>
2025-07-11 09:20:23 +08:00
public static List<Connector> GetNearestDomainConnectors(this Element element1, Element element2, bool isUnused = true)
2024-09-22 11:05:41 +08:00
{
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;
}
}