/// <summary> /// Remember to check for con.IsConnected! /// </summary> /// <param name="con">Connector for which to get the correspoinding ref con.</param> /// <param name="elem">The host element of the original connector.</param> /// <returns>The corresponding reference connector.</returns> public static Connector GetRefConnnector(this Connector con, Element elem) { var allRefsNotFiltered = MepUtils.GetAllConnectorsFromConnectorSet(con.AllRefs); var correspondingCon = allRefsNotFiltered .Where(x => x.Domain == Domain.DomainPiping) .Where(x => x.Owner.Id.IntegerValue != elem.Id.IntegerValue).FirstOrDefault(); return(correspondingCon); }
internal static XYZ OletP1Point(Cons cons) { XYZ endPointOriginOletPrimary = cons.Primary.Origin; XYZ endPointOriginOletSecondary = cons.Secondary.Origin; //get reference elements var refCons = MepUtils.GetAllConnectorsFromConnectorSet(cons.Primary.AllRefs); Connector refCon = refCons.Where(x => x.Owner.IsType <Pipe>()).FirstOrDefault(); if (refCon == null) { throw new Exception("refCon Owner cannot find a Pipe for element!"); } Pipe refPipe = (Pipe)refCon.Owner; Cons refPipeCons = Shared.MepUtils.GetConnectors(refPipe); //Following code is ported from my python solution in Dynamo. //The olet geometry is analyzed with congruent rectangles to find the connection point on the pipe even for angled olets. XYZ B = endPointOriginOletPrimary; XYZ D = endPointOriginOletSecondary; XYZ pipeEnd1 = refPipeCons.Primary.Origin; XYZ pipeEnd2 = refPipeCons.Secondary.Origin; XYZ BDvector = D - B; XYZ ABvector = pipeEnd1 - pipeEnd2; double angle = Conversion.RadianToDegree(ABvector.AngleTo(BDvector)); if (angle > 90) { ABvector = -ABvector; angle = Conversion.RadianToDegree(ABvector.AngleTo(BDvector)); } Line refsLine = Line.CreateBound(pipeEnd1, pipeEnd2); XYZ C = refsLine.Project(B).XYZPoint; double L3 = B.DistanceTo(C); XYZ E = refsLine.Project(D).XYZPoint; double L4 = D.DistanceTo(E); double ratio = L4 / L3; double L1 = E.DistanceTo(C); double L5 = L1 / (ratio - 1); XYZ A; if (angle < 89) { XYZ ECvector = C - E; ECvector = ECvector.Normalize(); double L = L1 + L5; ECvector = ECvector.Multiply(L); A = E.Add(ECvector); } else { A = E; } return(A); }
public static int OletRefOwnerIdAsInt(this Element e) { var cons = MepUtils.GetConnectors(e); var refCons = MepUtils.GetAllConnectorsFromConnectorSet(cons.Primary.AllRefs); Connector refCon = refCons.Where(x => x.Owner.IsType <Pipe>()).FirstOrDefault(); if (refCon == null) { throw new Exception("Olet id " + e.Id.ToString() + " has no reference connector! Check connectivity."); } Element owner = refCon.Owner; return(owner.Id.IntegerValue); }
public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements) { UIApplication uiApp = commandData.Application; Document doc = commandData.Application.ActiveUIDocument.Document; UIDocument uidoc = uiApp.ActiveUIDocument; try { using (Transaction tx = new Transaction(doc)) { var allAccessories = fi.GetElements <Element, BuiltInCategory>(doc, BuiltInCategory.OST_PipeAccessory); tx.Start("Populate tilkoblet"); foreach (var el in allAccessories) { Cons cons = new Cons(el); Connector firstSideCon = cons.Primary; Connector secondSideCon = cons.Secondary; Connector refFirstCon = null; Connector refSecondCon = null; if (firstSideCon != null && firstSideCon.IsConnected) { var refFirstCons = MepUtils.GetAllConnectorsFromConnectorSet(firstSideCon.AllRefs); refFirstCon = refFirstCons.FirstOrDefault(); } else if (firstSideCon != null) { refFirstCon = DetectUnconnectedConnector(doc, firstSideCon); } if (secondSideCon != null && secondSideCon.IsConnected) { var refSecondCons = MepUtils.GetAllConnectorsFromConnectorSet(secondSideCon.AllRefs); refSecondCon = refSecondCons.FirstOrDefault(); } else if (secondSideCon != null) { refSecondCon = DetectUnconnectedConnector(doc, secondSideCon); } Element firstSideOwner = null; Element secondSideOwner = null; string commentsContent = string.Empty; string firstSideComments = string.Empty; string secondSideComments = string.Empty; if (refFirstCon != null) { firstSideOwner = refFirstCon.Owner; Parameter tag1par = firstSideOwner.LookupParameter("TAG 1"); if (tag1par != null) { string tag1 = firstSideOwner.LookupParameter("TAG 1").AsString(); string tag2 = firstSideOwner.LookupParameter("TAG 2").AsString(); string tag3 = firstSideOwner.LookupParameter("TAG 3").AsString(); string tag4 = firstSideOwner.LookupParameter("TAG 4").AsString(); firstSideComments = string.Empty; if (!string.IsNullOrEmpty(tag1)) { firstSideComments += tag1; } if (!string.IsNullOrEmpty(tag2)) { firstSideComments += "_" + tag2; } if (!string.IsNullOrEmpty(tag3)) { firstSideComments += "_" + tag3; } if (!string.IsNullOrEmpty(tag4)) { firstSideComments += "_" + tag4; } } } if (refSecondCon != null) { secondSideOwner = refSecondCon.Owner; Parameter tag1par = secondSideOwner.LookupParameter("TAG 1"); if (tag1par != null) { string tag1 = secondSideOwner.LookupParameter("TAG 1").AsString(); string tag2 = secondSideOwner.LookupParameter("TAG 2").AsString(); string tag3 = secondSideOwner.LookupParameter("TAG 3").AsString(); string tag4 = secondSideOwner.LookupParameter("TAG 4").AsString(); secondSideComments = string.Empty; if (!string.IsNullOrEmpty(tag1)) { secondSideComments += tag1; } if (!string.IsNullOrEmpty(tag2)) { secondSideComments += "_" + tag2; } if (!string.IsNullOrEmpty(tag3)) { secondSideComments += "_" + tag3; } if (!string.IsNullOrEmpty(tag4)) { secondSideComments += "_" + tag4; } } } if (string.IsNullOrEmpty(firstSideComments) && string.IsNullOrEmpty(secondSideComments)) { continue; } else if (string.IsNullOrEmpty(firstSideComments) || string.IsNullOrEmpty(secondSideComments)) { if (!string.IsNullOrEmpty(firstSideComments)) { commentsContent = firstSideComments; } else if (!string.IsNullOrEmpty(secondSideComments)) { commentsContent = secondSideComments; } } else { commentsContent = $"{firstSideComments}; {secondSideComments}"; } Parameter comments = el.get_Parameter(BuiltInParameter.ALL_MODEL_INSTANCE_COMMENTS); comments.Set(commentsContent); } tx.Commit(); return(Result.Succeeded); } } catch (Autodesk.Revit.Exceptions.OperationCanceledException) { return(Result.Cancelled); } catch (Exception ex) { throw new Exception(ex.Message); } }
public static StringBuilder DetectAndWriteEndsAndConnections( string key, HashSet <Element> pipes, HashSet <Element> fittings, HashSet <Element> accessories, Document doc) { StringBuilder sb = new StringBuilder(); HashSet <Element> all = new HashSet <Element>(pipes); all.UnionWith(fittings); all.UnionWith(accessories); //Iterate over all elements and check their connected counterparts //If they satisfy certain conditions -> write end continuation property //Cases for connected connectors: //1) In different PipingSystem -> Pipeline continuation //1.1) If Selection and connector belongs to an element not in selection -> Pipeline continuation //2) Belongs to MechanicalEquipment -> Equipment continuation -> write tags //3) Free end -> Null connection foreach (Element elem in all) { HashSet <Connector> cons = new HashSet <Connector>(); switch (elem) { case Pipe pipe: var consPipe = new Cons(elem); cons.Add(consPipe.Primary); cons.Add(consPipe.Secondary); break; case FamilyInstance fi: cons = MepUtils.GetALLConnectorsFromElements(elem); break; default: continue; } foreach (Connector con in cons) { //This if should also filter out free ends... if (con.IsConnected) { var allRefsNotFiltered = MepUtils.GetAllConnectorsFromConnectorSet(con.AllRefs); var correspondingCon = allRefsNotFiltered .Where(x => x.Domain == Domain.DomainPiping) .Where(x => x.Owner.Id.IntegerValue != elem.Id.IntegerValue).FirstOrDefault(); //CASE: Free end -> Do nothing yet, for simplicity //This also catches empty cons on multicons accessories //Example: pressure take outs on filters. if (correspondingCon == null) { continue; } //CASE: If selection is exported, continuation for elements not in selection //Even if same pipeline if (iv.ExportSelection) { bool inElementsList = !all.Any(x => x.Id.IntegerValue == correspondingCon.Owner.Id.IntegerValue); //bool inDiscardedPipes = !discardedPipes.Any(x => x.Id.IntegerValue == correspondingCon.Owner.Id.IntegerValue); if (inElementsList)// && inDiscardedPipes) { //CASE: Con belongs to MechanicalEquipment if (correspondingCon.Owner.Category.Id.IntegerValue == (int)BuiltInCategory.OST_MechanicalEquipment) { sb.AppendLine("END-CONNECTION-EQUIPMENT"); sb.Append(PCF_Functions.EndWriter.WriteCO(correspondingCon.Origin)); sb.Append(PCF_Functions.ParameterDataWriter .ParameterValue("CONNECTION-REFERENCE", new[] { "TAG 1", "TAG 2", "TAG 3", "TAG 4" }, correspondingCon.Owner)); continue; } //CASE: Any other component else { sb.AppendLine("END-CONNECTION-PIPELINE"); sb.Append(PCF_Functions.EndWriter.WriteCO(correspondingCon.Origin)); sb.AppendLine(" PIPELINE-REFERENCE " + correspondingCon.MEPSystemAbbreviation(doc)); continue; } } //CASE: None of the above hit -> continue with loop execution //To prevent from falling through to non selection cases. continue; } //CASE: Con belongs to MechanicalEquipment else if (correspondingCon.Owner.Category.Id.IntegerValue == (int)BuiltInCategory.OST_MechanicalEquipment) { sb.AppendLine("END-CONNECTION-EQUIPMENT"); sb.Append(PCF_Functions.EndWriter.WriteCO(correspondingCon.Origin)); sb.Append(PCF_Functions.ParameterDataWriter .ParameterValue("CONNECTION-REFERENCE", new[] { "TAG 1", "TAG 2", "TAG 3", "TAG 4" }, correspondingCon.Owner)); continue; } //CASE: If corrCon belongs to different Pipeline -> unconditional end //MechanicalEquipment cons should belong to the same Piping System, else... else if (correspondingCon.MEPSystemAbbreviation(doc) != key) { sb.AppendLine("END-CONNECTION-PIPELINE"); sb.Append(PCF_Functions.EndWriter.WriteCO(correspondingCon.Origin)); sb.AppendLine(" PIPELINE-REFERENCE " + correspondingCon.MEPSystemAbbreviation(doc)); continue; } //CASE: If corrCon belongs to EXISTING component //Write PIPELINE-REFERENCE -> EXISTING Element hostElement = correspondingCon.Owner; //GUID is for PCF_ELEM_SPEC Parameter existingParameter = hostElement.get_Parameter(new Guid("90be8246-25f7-487d-b352-554f810fcaa7")); if (existingParameter.AsString() == "EXISTING") { sb.AppendLine("END-CONNECTION-PIPELINE"); sb.Append(PCF_Functions.EndWriter.WriteCO(correspondingCon.Origin)); sb.AppendLine(" PIPELINE-REFERENCE EKSISTERENDE"); } } } } return(sb); }
public static void ConnectTheConnectors(ExternalCommandData commandData) { try { bool ctrl = false; bool shft = false; if ((int)Keyboard.Modifiers == 2) { ctrl = true; } if ((int)Keyboard.Modifiers == 4) { shft = true; } var app = commandData.Application; var uiDoc = app.ActiveUIDocument; var doc = uiDoc.Document; var selection = uiDoc.Selection.GetElementIds(); //If no elements selected, connect ALL connectors to ALL connectors //Or if more than two -- connect to each other if ((selection.Count == 0 || selection.Count > 2) && !ctrl) { //Argh! It seems Revit2019 doesn't break when connecting pipes at angle!!! ////To filter out PCF_ELEM_EXCL set to true ////Collecting pipes, fittings, accessories ////Filtering out those with "true" value ////The Guid below is for PCF_ELEM_EXCL //var exclFilter = fi.ParameterValueGenericFilter(doc, 0, new Guid("CC8EC292-226C-4677-A32D-10B9736BFC1A")); //FilteredElementCollector col1 = new FilteredElementCollector(doc); //col1.WherePasses( // new LogicalOrFilter( // new List<ElementFilter> // { // new ElementCategoryFilter(BuiltInCategory.OST_PipeFitting), // new ElementCategoryFilter(BuiltInCategory.OST_PipeAccessory), // new ElementClassFilter(typeof (Pipe)) // }));//.WherePasses(exclFilter); //var col2 = mp.GetElementsOfBuiltInCategory(doc, BuiltInCategory.OST_MechanicalEquipment); //HashSet<Element> elements = new HashSet<Element>(); //elements.UnionWith(col1); //elements.UnionWith(col2); //When selection is 0 IList <Connector> allConnectors; if (selection.Count == 0) { allConnectors = mp.GetALLConnectorsInDocument(doc, true) .Where(c => !c.IsConnected) .ExceptWhere(c => c.MEPSystemAbbreviation(doc, true) == "ARGD") .ToList(); } //Selection is more than 2 else { allConnectors = mp.GetALLConnectorsFromElements((from ElementId id in selection select doc.GetElement(id)).ToHashSet()).ToList(); } //Employ reverse iteration to be able to modify the collection while iterating over it for (int i = allConnectors.Count - 1; i > 0; i--) { if (allConnectors.Count < 2) { break; } Connector c1 = allConnectors[i]; allConnectors.RemoveAt(i); if (c1.IsConnected) { continue; //Need: connectors connected in this loop are still in collection } Connector c2 = (from Connector c in allConnectors where c.Equalz(c1, Extensions._1mmTol) select c).FirstOrDefault(); try { if (c1?.Owner.Id.IntegerValue == c2?.Owner.Id.IntegerValue) { continue; } c2?.ConnectTo(c1); } catch (Exception) { throw new Exception($"Element {c1.Owner.Id.ToString()} is already connected to element {c2.Owner.Id.ToString()}"); } } return; } else if (selection.Count == 1 && shft) { ElementId hangerId = selection.First(); Element hanger = doc.GetElement(hangerId); Cons cons = new Cons(hanger); var allConnectors = mp.GetALLConnectorsInDocument(doc).ToList(); var query = allConnectors.Where(c => c.Equalz(cons.Primary, Extensions._1mmTol)).Where(c => c.Owner.Id.IntegerValue != hanger.Id.IntegerValue).ToList(); //Disconnect connectors of the existing components if the hanger was moved in place Connector con1 = query.FirstOrDefault(); if (con1 == null) { throw new Exception("Detection of existing con1 failed!"); } Connector con2 = query.LastOrDefault(); if (con2 == null) { throw new Exception("Detection of existing con2 failed!"); } if (con1.IsConnectedTo(con2)) { con1.DisconnectFrom(con2); } //If the hanger was created by placing on element and thus auto connected -> disconnect both connectors //Dunno if this is needed and placing by auto connect does orient the connectors correctly //Until it is proven true, both connectors are disconnected if (cons.Primary.IsConnected) { var refCons = cons.Primary.AllRefs; var refCon = MepUtils.GetAllConnectorsFromConnectorSet(refCons) .Where(c => c.Owner.IsType <Pipe>() || c.Owner.IsType <FamilyInstance>()).FirstOrDefault(); if (refCon != null) { cons.Primary.DisconnectFrom(refCon); } } if (cons.Secondary.IsConnected) { var refCons = cons.Secondary.AllRefs; var refCon = MepUtils.GetAllConnectorsFromConnectorSet(refCons) .Where(c => c.Owner.IsType <Pipe>() || c.Owner.IsType <FamilyInstance>()).FirstOrDefault(); if (refCon != null) { cons.Primary.DisconnectFrom(refCon); } } doc.Regenerate(); //Start connecting hanger connectors //https://stackoverflow.com/questions/7572640/how-do-i-know-if-two-vectors-are-near-parallel var detectOpposite1 = query.Where(c => cons.Primary.CoordinateSystem.BasisZ.DotProduct(c.CoordinateSystem.BasisZ) < -1 + Extensions._epx); Connector opposite1 = detectOpposite1.FirstOrDefault(); if (opposite1 == null) { throw new Exception("Opposite primary detection failed!"); } cons.Primary.ConnectTo(opposite1); var detectOpposite2 = query.Where(c => cons.Secondary.CoordinateSystem.BasisZ.DotProduct(c.CoordinateSystem.BasisZ) < -1 + Extensions._epx); Connector opposite2 = detectOpposite2.FirstOrDefault(); if (opposite2 == null) { throw new Exception("Opposite secondary detection failed!"); } cons.Secondary.ConnectTo(opposite2); return; } else if (selection.Count == 1 && !ctrl) //If one and no CTRL key, connect the element { var elements = new HashSet <Element>(from ElementId id in selection select doc.GetElement(id)); var elementConnectors = mp.GetALLConnectorsFromElements(elements); var allConnectors = mp.GetALLConnectorsInDocument(doc, true).Where(c => !c.IsConnected).ToList(); IList <Connector> list1 = new List <Connector>(); IList <Connector> list2 = new List <Connector>(); foreach (var c1 in elementConnectors) { foreach (var c2 in allConnectors) { if (c1.Id != c2.Id && !c1.IsConnected && c1.Equalz(c2, Extensions._1mmTol)) { list1.Add(c1); list2.Add(c2); } } } if (list1.Count == 0 && list2.Count == 0) { throw new Exception("No matches found! Check alignment!"); } foreach (var(c1, c2) in list1.Zip(list2, (x, y) => (c1: x, c2: y))) { c1.ConnectTo(c2); } return; } else if ((selection.Count == 1 || selection.Count > 2) && ctrl) //If one and CTRL key is pressed, disconnect the element { var elements = new HashSet <Element>(from ElementId id in selection select doc.GetElement(id)); var elementConnectors = mp.GetALLConnectorsFromElements(elements); foreach (Connector c1 in elementConnectors) { if (c1.IsConnected) { var set = c1.AllRefs; foreach (Connector c2 in set) { if (c1.IsConnectedTo(c2)) { c1.DisconnectFrom(c2); } } } } return; } //Connect or disconnect the connectors of selection //Only works on selection of two adjacent elements //That means only two connectors get connected to or disconnected from each other else if (selection.Count == 2) { var elements = new HashSet <Element>(from ElementId id in selection select doc.GetElement(id)); var connectors = mp.GetALLConnectorsFromElements(elements).ToList(); for (int i = connectors.Count - 1; i > 0; i--) { if (connectors.Count < 2) { throw new Exception("No eligible connectors found! Check alignment."); } Connector c1 = connectors[i]; connectors.RemoveAt(i); Connector c2 = (from Connector c in connectors where c.Equalz(c1, Extensions._1mmTol) select c).FirstOrDefault(); if (c2 != null) { if (c1.Owner.Id.IntegerValue == c2.Owner.Id.IntegerValue) { continue; } if (c1.IsConnected) { c2.DisconnectFrom(c1); } else { c2.ConnectTo(c1); } } } return; } else { throw new Exception("Not correct amount of elements selected for the command! Choose none, one or two!"); } } catch (Exception e) { throw new Exception(e.Message); } }