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 { /// /// 用点打断管线 /// /// /// /// 新的管线(定位线前端部分) 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)}不是管线或不可打断"); } /// /// 复制并修改定位线,并可用来连接该管线,朝上方向的一致性 /// /// 用来复制的管线 /// 定位线 /// 可以创建弯头 /// 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; } /// /// 打断直线管线 /// /// /// /// 新创建的管线距离起点近,返回Id=-1时,不能打断管线 /// private static ElementId BreakCurve(this MEPCurve electricMepCurve, XYZ point) { var document = electricMepCurve.Document; var application = document.Application; var conns = electricMepCurve.ConnectorManager.Connectors.OfType().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; } } }