using System.Diagnostics; using Autodesk.Revit.DB; using Autodesk.Revit.DB.Electrical; using Autodesk.Revit.DB.Mechanical; using Autodesk.Revit.DB.Plumbing; using Autodesk.Revit.UI.Selection; using Nice3point.Revit.Toolkit.External; using ShrlAlgoToolkit.RevitAddins.RvMEP; using ShrlAlgoToolkit; using ShrlAlgoToolkit.RevitAddins; namespace ShrlAlgoToolkit.RevitAddins.Mep; [Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)] [Autodesk.Revit.Attributes.Regeneration(Autodesk.Revit.Attributes.RegenerationOption.Manual)] internal class BloomConnectorCmd : ExternalCommand //根据连接件创建一根短管 { public override void Execute() { try { var elemIds = UiDocument.Selection.GetElementIds(); if (elemIds.Count == 0) { var reference = UiDocument.Selection .PickObject( ObjectType.Element, new FuncFilter(e => e is FamilyInstance ins && ins.GetConnectors(true).Size > 0), "请选择族实例"); elemIds.Add(Document.GetElement(reference).Id); } foreach (var elemId in elemIds) { var pipeTypeId = Document.OfClass().FirstElementId(); var cableTrayTypeId = Document.OfClass().FirstElementId(); var conduitTypeId = Document.OfClass().FirstElementId(); var ductTypeCollector = Document.OfClass().Cast(); var roundDuctTypeId = ElementId.InvalidElementId; var rectangleDuctTypeId = ElementId.InvalidElementId; var ovalDuctTypeId = ElementId.InvalidElementId; //设置默认的风管类型 foreach (var ductType in ductTypeCollector) { if (ductType.FamilyName == "圆形风管" || ductType.FamilyName.Contains("Round Duct")) { roundDuctTypeId = ductType.Id; } else if (ductType.FamilyName == "矩形风管" || ductType.FamilyName.Contains("Rectangular Duct")) { rectangleDuctTypeId = ductType.Id; } else if (ductType.FamilyName == "椭圆形风管" || ductType.FamilyName.Contains("Oval Duct")) { ovalDuctTypeId = ductType.Id; } } var fabricationConfiguration = FabricationConfiguration.GetFabricationConfiguration(Document); var elem = Document.GetElement(elemId); if (elem.GetConnectors(true).IsEmpty && elem is not FamilyInstance) { continue; } CableTray referCabTray = null; Conduit referConduit = null; //根据连接件拿到连接的管线的类型 foreach (Connector conn in elem.GetConnectors()) { if (conn.IsConnected) { var connector = conn.GetConnectedConnector(); if (connector == null) { continue; } if (conn.Domain == Domain.DomainPiping && connector.Owner is Pipe) { pipeTypeId = connector.Owner.GetTypeId(); } else if (conn.Domain == Domain.DomainHvac) { switch (connector.Shape) { case ConnectorProfileType.Invalid: break; case ConnectorProfileType.Round: roundDuctTypeId = connector.Owner.GetTypeId(); break; case ConnectorProfileType.Rectangular: rectangleDuctTypeId = connector.Owner.GetTypeId(); break; case ConnectorProfileType.Oval: ovalDuctTypeId = connector.Owner.GetTypeId(); break; default: break; } } else if (conn.Domain == Domain.DomainCableTrayConduit) { if (connector.Owner is CableTray cableTray) { referCabTray = cableTray; cableTrayTypeId = cableTray.GetTypeId(); } else if (connector.Owner is Conduit conduit) { referConduit = conduit; conduitTypeId = conduit.GetTypeId(); } } } } Document.Invoke( _ => { var connectors = elem.GetConnectors(true); foreach (Connector connector in connectors) { Element element = null; if (elem.Category.Id.IntegerValue == (int)BuiltInCategory.OST_FabricationPipework) { var serviceId = (elem as FabricationPart).ServiceId; var button = fabricationConfiguration.GetService(serviceId).GetButton(0, 0); var fabricationPart = FabricationPart.Create(Document, button, 0, elem.LevelId); var enumerator2 = fabricationPart.ConnectorManager.Connectors.GetEnumerator(); if (enumerator2.MoveNext()) { var connector2 = (Connector)enumerator2.Current; ElementTransformUtils.MoveElement( Document, fabricationPart.Id, connector.Origin - connector2.Origin ); var basisZ = connector.CoordinateSystem.BasisZ; var basisZ2 = connector2.CoordinateSystem.BasisZ; var num = basisZ.DotProduct(basisZ2); if (Math.Abs(num - -1.0) < 0.0001) { connector2.ConnectTo(connector); continue; } var xyz = basisZ.CrossProduct(basisZ2); var line = Line.CreateBound(connector.Origin, connector.Origin + (10000000000000000.0 * xyz)); var angleTo = basisZ.AngleTo(basisZ2); var angle = Math.PI - angleTo; ElementTransformUtils.RotateElement(Document, fabricationPart.Id, line, angle); if (connector2.Shape == ConnectorProfileType.Invalid) { connector2.Radius = connector.Radius; } else { connector2.Width = connector.Width; connector2.Height = connector.Height; } } continue; } var extensionLength = connector.GetExtensionLength(); var origin = connector.Origin; //延伸后的点 var xyz2 = origin + (extensionLength * connector.CoordinateSystem.BasisZ); var levelId = elem.LevelId; if (levelId == ElementId.InvalidElementId) { var pa = elem.get_Parameter(BuiltInParameter.RBS_START_LEVEL_PARAM); if (pa != null) { levelId = pa.AsElementId(); } } if (levelId == ElementId.InvalidElementId) { if (elem is FamilyInstance { Host: Level } instance) { levelId = instance.Host.Id; } } switch (connector.Domain) { //未定义 case Domain.DomainUndefined: break; //风管 case Domain.DomainHvac: //var mechanicalSystemTypes = new FilteredElementCollector(Document) // .OfClass(typeof(MechanicalSystemType)) // .Cast(); ////风管系统类型 //var mechanicalSystem = // connector.MEPSystem == null // ? connector.DuctSystemType switch // { // //送风 // DuctSystemType.SupplyAir // => mechanicalSystemTypes.FirstOrDefault( // pst => // pst.SystemClassification // == Autodesk.Revit.DB.MEPSystemClassification.SupplyAir // ), // //回风 // DuctSystemType.ReturnAir // => mechanicalSystemTypes.FirstOrDefault( // pst => // pst.SystemClassification // == Autodesk.Revit.DB.MEPSystemClassification.ReturnAir // ), // //排风 // DuctSystemType.ExhaustAir // => mechanicalSystemTypes.FirstOrDefault( // pst => // pst.SystemClassification // == Autodesk.Revit.DB.MEPSystemClassification.ExhaustAir // ), // _ // => mechanicalSystemTypes.FirstOrDefault( // pst => // pst.SystemClassification // == Autodesk.Revit.DB.MEPSystemClassification.OtherAir // ) // } // : Document.GetElement(connector.MEPSystem.GetTypeId()) as MechanicalSystemType; //if (new FilteredElementCollector(Document).OfClass(typeof(DuctType)).FirstElement() is not DuctType) //{ // break; //} //风管形状 switch (connector.Shape) { case ConnectorProfileType.Round: element = Duct.Create( Document, roundDuctTypeId, levelId, connector, xyz2 ); Document.Regenerate(); element.get_Parameter(BuiltInParameter.RBS_CURVE_DIAMETER_PARAM).Set(connector.Radius * 2); break; case ConnectorProfileType.Rectangular: element = Duct.Create( Document, rectangleDuctTypeId, levelId, connector, xyz2 ); Document.Regenerate(); var width = Math.Max(connector.Width, connector.Height); var height = Math.Min(connector.Width, connector.Height); element.get_Parameter(BuiltInParameter.RBS_CURVE_WIDTH_PARAM).Set(width); element.get_Parameter(BuiltInParameter.RBS_CURVE_HEIGHT_PARAM).Set(height); break; case ConnectorProfileType.Oval: element = Duct.Create(Document, ovalDuctTypeId, levelId, connector, xyz2); Document.Regenerate(); var w = Math.Max(connector.Width, connector.Height); var h = Math.Min(connector.Width, connector.Height); element.get_Parameter(BuiltInParameter.RBS_CURVE_WIDTH_PARAM).Set(w); element.get_Parameter(BuiltInParameter.RBS_CURVE_HEIGHT_PARAM).Set(h); break; default: element = Duct.Create( Document, roundDuctTypeId, levelId, connector, xyz2 ); break; } break; //电气 case Domain.DomainElectrical: break; //水管 case Domain.DomainPiping: var pipingSystemTypes = new FilteredElementCollector(Document) .OfClass(typeof(PipingSystemType)) .Cast(); if (pipeTypeId == ElementId.InvalidElementId) { pipeTypeId = Document.OfClass().FirstElementId(); } var system = connector.MEPSystem; var pipingSystemType = system != null ? Document.GetElement(system.GetTypeId()) as PipingSystemType : connector.PipeSystemType switch { //循环供水 PipeSystemType.SupplyHydronic => pipingSystemTypes.FirstOrDefault( pst => pst.SystemClassification == Autodesk.Revit.DB.MEPSystemClassification.SupplyHydronic ), //循环回水 PipeSystemType.ReturnHydronic => pipingSystemTypes.FirstOrDefault( pst => pst.SystemClassification == Autodesk.Revit.DB.MEPSystemClassification.ReturnHydronic ), //卫生设备 PipeSystemType.Sanitary => pipingSystemTypes.FirstOrDefault( pst => pst.SystemClassification == Autodesk.Revit.DB.MEPSystemClassification.Sanitary ), //家用热水 PipeSystemType.DomesticHotWater => pipingSystemTypes.FirstOrDefault( pst => pst.SystemClassification == Autodesk.Revit.DB.MEPSystemClassification.DomesticHotWater ), //家用冷水 PipeSystemType.DomesticColdWater => pipingSystemTypes.FirstOrDefault( pst => pst.SystemClassification == Autodesk.Revit.DB.MEPSystemClassification.DomesticColdWater ), //其他 PipeSystemType.OtherPipe => pipingSystemTypes.FirstOrDefault( pst => pst.SystemClassification == Autodesk.Revit.DB.MEPSystemClassification.OtherPipe ), //湿式消防系统 PipeSystemType.FireProtectWet => pipingSystemTypes.FirstOrDefault( pst => pst.SystemClassification == Autodesk.Revit.DB.MEPSystemClassification.FireProtectWet ), //干式消防系统 PipeSystemType.FireProtectDry => pipingSystemTypes.FirstOrDefault( pst => pst.SystemClassification == Autodesk.Revit.DB.MEPSystemClassification.FireProtectDry ), //预作用消防系统 PipeSystemType.FireProtectPreaction => pipingSystemTypes.FirstOrDefault( pst => pst.SystemClassification == Autodesk.Revit.DB.MEPSystemClassification.FireProtectPreaction ), //其他消防系统 PipeSystemType.FireProtectOther => pipingSystemTypes.FirstOrDefault( pst => pst.SystemClassification == Autodesk.Revit.DB.MEPSystemClassification.FireProtectOther ), //通风孔 PipeSystemType.Vent => pipingSystemTypes.FirstOrDefault( pst => pst.SystemClassification == Autodesk.Revit.DB.MEPSystemClassification.Vent ), _ => pipingSystemTypes.FirstOrDefault( pst => pst.SystemClassification == Autodesk.Revit.DB.MEPSystemClassification.OtherPipe ) }; element = Pipe.Create(Document, pipingSystemType.Id, pipeTypeId, levelId, origin, xyz2); element.get_Parameter(BuiltInParameter.RBS_PIPE_DIAMETER_PARAM).Set(connector.Radius * 2); break; //电力 case Domain.DomainCableTrayConduit: //if (cableTrayTypeId == ElementId.InvalidElementId) //{ // cableTrayTypeId = new FilteredElementCollector(Document) // .OfClass(typeof(CableTrayType)) // .FirstElementId(); //} //if (conduitTypeId == ElementId.InvalidElementId) //{ // conduitTypeId = new FilteredElementCollector(Document) // .OfClass(typeof(ConduitType)) // .FirstElementId(); //} //switch (connector.ElectricalSystemType) //{ // //电力 // case ElectricalSystemType.PowerCircuit: // break; //} switch (connector.Shape) { case ConnectorProfileType.Invalid: break; case ConnectorProfileType.Round: element = Conduit.Create(Document, conduitTypeId, origin, xyz2, levelId); element.get_Parameter(BuiltInParameter.RBS_CONDUIT_DIAMETER_PARAM).Set(connector.Radius * 2); if (referConduit != null) { var value = referConduit.get_Parameter( BuiltInParameter.RBS_CTC_SERVICE_TYPE) .AsString(); element.get_Parameter(BuiltInParameter.RBS_CTC_SERVICE_TYPE).Set(value); } break; case ConnectorProfileType.Rectangular: var width = Math.Max(connector.Width, connector.Height); var height = Math.Min(connector.Width, connector.Height); element = CableTray.Create(Document, cableTrayTypeId, origin, xyz2, levelId); element.get_Parameter(BuiltInParameter.RBS_CABLETRAY_WIDTH_PARAM).Set(width); element.get_Parameter(BuiltInParameter.RBS_CABLETRAY_HEIGHT_PARAM).Set(height); if (referCabTray != null) { var value = referCabTray.get_Parameter( BuiltInParameter.RBS_CTC_SERVICE_TYPE) .AsString(); element.get_Parameter(BuiltInParameter.RBS_CTC_SERVICE_TYPE).Set(value); } break; case ConnectorProfileType.Oval: break; } break; } Document.Regenerate(); //新建管线连接 if (element == null) { continue; } var curve = element as MEPCurve; var conns = curve.ConnectorManager.UnusedConnectors.Cast(); foreach (var connect in conns) { if (connect.Origin.IsAlmostEqualTo(connector.Origin)) { Debug.WriteLine("新建管线:"); Debug.WriteLine(connect.CoordinateSystem.BasisX); Debug.WriteLine(connect.CoordinateSystem.BasisY); Debug.WriteLine(connect.CoordinateSystem.BasisZ); Debug.WriteLine("管件:"); Debug.WriteLine(connector.CoordinateSystem.BasisX); Debug.WriteLine(connector.CoordinateSystem.BasisY); Debug.WriteLine(connector.CoordinateSystem.BasisZ); var isStandMEPCurve = connect.CoordinateSystem.BasisZ.CrossProduct(XYZ.BasisZ).IsAlmostEqualTo(XYZ.Zero); if (isStandMEPCurve) { var angleX = Math.Acos(connect.CoordinateSystem.BasisX.DotProduct(connector.CoordinateSystem.BasisX)); Debug.WriteLine(angleX); var crossProduct = connect.CoordinateSystem.BasisX .CrossProduct(connector.CoordinateSystem.BasisX).Normalize(); var angle = Math.Acos(connect.CoordinateSystem.BasisX.DotProduct(connector.CoordinateSystem.BasisX)); if (crossProduct.IsAlmostEqualTo(XYZ.Zero)) { if (connect.CoordinateSystem.BasisX .IsAlmostEqualTo(connector.CoordinateSystem.BasisX)) { ElementTransformUtils.RotateElement( Document, element.Id, Line.CreateUnbound(origin, XYZ.BasisZ), Math.PI / 2); } } else { if (angleX > Math.PI / 2) { ElementTransformUtils.RotateElement( Document, element.Id, Line.CreateUnbound(origin, XYZ.BasisZ), angleX - Math.PI / 2); } else { ElementTransformUtils.RotateElement( Document, element.Id, Line.CreateUnbound(origin, XYZ.BasisZ), Math.PI / 2 - angleX); } } //if (Math.Abs(angleX - Math.PI / 2) > 0.001) //{ // ElementTransformUtils.RotateElement( // Document, // element.Id, // Line.CreateUnbound(origin, crossProduct), // angleX - Math.PI / 2 // ); // Debug.WriteLine("旋转后新建管线:"); // Debug.WriteLine(connect.CoordinateSystem.BasisX); // Debug.WriteLine(connect.CoordinateSystem.BasisY); // Debug.WriteLine(connect.CoordinateSystem.BasisZ); // Document.Regenerate(); // angle = Math.Acos(connect.CoordinateSystem.BasisX.DotProduct(connector.CoordinateSystem.BasisX)); // Debug.WriteLine(nameof(angle) + angle); //} } var conn = elem.GetConnectors(true).GetNearestConnector(connector.Origin); if (!connect.IsConnectedTo(connector)) { connect.ConnectTo(connector); } break; } } } }, "引出短管" ); } } catch (Autodesk.Revit.Exceptions.OperationCanceledException) { Result = Result.Cancelled; } } }