Files
SzmediTools/Szmedi.Toolkit.Revit/RvExtensions/MEPExtensions.cs

217 lines
9.3 KiB
C#
Raw Normal View History

2025-09-16 16:06:41 +08:00

using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Mechanical;
using Autodesk.Revit.DB.Plumbing;
using System;
using System.Diagnostics;
using System.Linq;
namespace Szmedi.Toolkit.RvExtensions
{
public static class MEPExtensions
{
/// <summary>
/// 用点打断管线
/// </summary>
/// <param name="mepCurve"></param>
/// <param name="point"></param>
/// <returns>新的管线(定位线前端部分)</returns>
public static ElementId BreakByPoint(this MEPCurve mepCurve, XYZ point)
{
if (mepCurve is not InsulationLiningBase)
{
try
{
Document document = mepCurve.Document;
return mepCurve switch
{
Duct duct => MechanicalUtils.BreakCurve(document, duct.Id, point),
Pipe pipe => PlumbingUtils.BreakCurve(document, pipe.Id, point),
_ => mepCurve.BreakCurve(point)
};
}
catch (Exception e)
{
Debug.WriteLine(e.Message);
return ElementId.InvalidElementId;
}
}
throw new InvalidOperationException($"{nameof(mepCurve)}不是管线或不可打断");
}
/// <summary>
/// 复制并修改定位线,并可用来连接该管线,朝上方向的一致性
/// </summary>
/// <param name="mepCurve">用来复制的管线</param>
/// <param name="line">定位线</param>
/// <param name="canNewElbow">可以创建弯头</param>
/// <returns></returns>
public static MEPCurve CopyAndSetLocationCurve(this MEPCurve mepCurve, Line line)
{
var doc = mepCurve.Document;
var elemId = ElementTransformUtils.CopyElement(doc, mepCurve.Id, XYZ.Zero).FirstOrDefault();
var newMepCurve = doc.GetElement(elemId) as MEPCurve;
newMepCurve.SetLocationCurve(line);
doc.Regenerate();
//立管的断面可能错误,需要旋转截面
if (line.Direction.CrossProduct(XYZ.BasisZ).IsZeroLength())
{
var conns = ConnectorExtensions.GetNearestConnectors(mepCurve, newMepCurve);
var hand = conns[0].CoordinateSystem.BasisX;
//取反向
var newHand = conns[1].CoordinateSystem.BasisX;
//点积
var cos = hand.DotProduct(newHand);
//夹角
var radian = Math.Acos(cos);
////旋转轴向
//var d = hand.CrossProduct(newHand);
//当两个BasisX相反时则为可正确连接的不需要旋转
if (hand.IsAlmostEqualTo(-newHand))
{
return newMepCurve;
}
//连接件的BasisZ就是轴向
var d = conns[1].CoordinateSystem.BasisZ;
//以立管或倾斜管作为参考轴
var ax = Line.CreateUnbound(conns[1].Origin, d);
//保证夹角为180度故旋转角用Π-夹角
ElementTransformUtils.RotateElement(doc, elemId, ax, Math.PI - radian);
//double radian = default;
//Line axis = null;
//foreach (Connector connector in mepCurve.ConnectorManager.Connectors)
//{
// foreach (Connector connector1 in newMepCurve.ConnectorManager.Connectors)
// {
// //侧面向量
// var dotProduct = connector1.CoordinateSystem.BasisX.DotProduct(connector.CoordinateSystem.BasisX);
// radian = Math.Acos(dotProduct);
// //为0的时候即两个侧面向量重合或相反表明要么正好合适要么需要旋转180度
// var direction =
// Math.Sin(radian) < 0.0001 ? XYZ.BasisZ : connector1.CoordinateSystem.BasisX.CrossProduct(connector.CoordinateSystem.BasisX);
// if (!direction.IsZeroLength())
// {
// axis = Line.CreateUnbound(connector1.Origin, direction);
// }
// //radian = Math.PI - radian;
// }
//}
//ElementTransformUtils.RotateElement(doc, elemId, axis, radian);
}
return newMepCurve;
}
/// <summary>
/// 打断直线管线
/// </summary>
/// <param name="electricMepCurve"></param>
/// <param name="point"></param>
/// <remarks>新创建的管线距离起点近,返回Id=-1时不能打断管线</remarks>
/// <returns></returns>
private static ElementId BreakCurve(this MEPCurve electricMepCurve, XYZ point)
{
var document = electricMepCurve.Document;
var application = document.Application;
var conns = electricMepCurve.ConnectorManager.Connectors.OfType<Connector>().Where(c => c.ConnectorType == ConnectorType.End);
//原管线连接的接头
var originConn1 = conns.ElementAt(0);
var originConn2 = conns.ElementAt(1);
//已连接的连接件
var connectedConn1 = originConn1.GetConnectedConnector();
var connectedConn2 = originConn2.GetConnectedConnector();
Debug.WriteLine($"起点连接件{connectedConn1}");
Debug.WriteLine($"终点连接件{connectedConn2}");
connectedConn1?.DisconnectFrom(originConn1);
connectedConn2?.DisconnectFrom(originConn2);
document.Regenerate();
//投影点
if (
electricMepCurve.GetLocCurve() is not Line line
|| electricMepCurve is FlexDuct
|| electricMepCurve is FlexPipe
|| electricMepCurve is PipeInsulation
|| electricMepCurve is DuctInsulation
)
{
//throw new InvalidOperationException("不可打断的类型");
return ElementId.InvalidElementId;
}
var projectPoint = line.Project(point).XYZPoint;
if ((electricMepCurve.GetLocCurve() as Line).IsInsideEx(point, application.ShortCurveTolerance))
{
var startLine = Line.CreateBound(line.GetEndPoint(0), projectPoint);
var endLine = Line.CreateBound(projectPoint, line.GetEndPoint(1));
var electricMepCurveCopyId = ElementTransformUtils.CopyElement(document, electricMepCurve.Id, XYZ.Zero).FirstOrDefault();
var electricMepCurveCopy = document.GetElement(electricMepCurveCopyId) as MEPCurve;
//起点线
electricMepCurveCopy.SetLocationCurve(startLine);
electricMepCurve.SetLocationCurve(endLine);
Debug.WriteLine($"设置定位线");
document.Regenerate();
Debug.WriteLine($"原有接头{connectedConn1?.Origin}");
Debug.WriteLine($"原有接头{connectedConn2?.Origin}");
foreach (Connector conn1 in electricMepCurveCopy!.ConnectorManager.Connectors)
{
Debug.WriteLine($"复制管连接件{conn1.Origin}");
if (connectedConn1 != null)
{
if (conn1.Origin.DistanceTo(connectedConn1.Origin) < application.ShortCurveTolerance)
{
Debug.WriteLine("复制管连接连接件1");
conn1.ConnectTo(connectedConn1);
break;
}
}
if (connectedConn2 != null)
{
if (conn1.Origin.DistanceTo(connectedConn2.Origin) < application.ShortCurveTolerance)
{
Debug.WriteLine("复制管连接连接件2");
conn1.ConnectTo(connectedConn2);
break;
}
}
}
foreach (Connector conn1 in electricMepCurve!.ConnectorManager.Connectors)
{
if (connectedConn1 != null)
{
if (conn1.Origin.DistanceTo(connectedConn1.Origin) < application.ShortCurveTolerance)
{
Debug.WriteLine("原有管连接连接件1");
conn1.ConnectTo(connectedConn1);
break;
}
}
if (connectedConn2 != null)
{
if (conn1.Origin.DistanceTo(connectedConn2.Origin) < application.ShortCurveTolerance)
{
Debug.WriteLine("原有管连接连接件2");
conn1.ConnectTo(connectedConn2);
break;
}
}
}
return electricMepCurveCopyId;
}
return ElementId.InvalidElementId;
}
}
}