如何筛选用户指定的两台机械设备之间的关联构件?
Got it, let's fix this to target exactly the connected components between two user-specified mechanical equipment. Your current approach uses bounding box intersection, which can pick up unrelated elements that just happen to overlap with the equipment's box. Instead, we'll leverage Revit's connector system to trace actual physical connections between the two devices.
Step 1: Define How to Select the Two Target Equipment
First, we need a way to identify the two specific equipment the user cares about. For this example, we'll use the ALL_MODEL_INSTANCE_COMMENTS parameter to match user-defined labels (like "EM-01" and "EM-02"). You could also adapt this to let users pick the equipment directly via a selection dialog if needed.
Step 2: Trace Connected Components Recursively
We'll recursively traverse the connectors starting from the first equipment, collecting all relevant pipes, fittings, and accessories until we reach the second equipment. This ensures we only get elements that are actually part of the connection path between the two devices.
Adjusted Code Implementation
using Autodesk.Revit.DB; using Autodesk.Revit.UI; using System.Collections.Generic; using System.Linq; public void FilterComponentsBetweenTwoEquipment(UIDocument uiDoc) { Document doc = uiDoc.Document; // --- Step 1: Get the two target mechanical equipment (customize this to match your user's selection method) string targetEM1Comment = "EM-01"; // Replace with user's first equipment identifier string targetEM2Comment = "EM-02"; // Replace with user's second equipment identifier FilteredElementCollector equipmentCollector = new FilteredElementCollector(doc) .OfClass(typeof(FamilyInstance)) .OfCategory(BuiltInCategory.OST_MechanicalEquipment); FamilyInstance em1 = equipmentCollector .Cast<FamilyInstance>() .FirstOrDefault(em => em.get_Parameter(BuiltInParameter.ALL_MODEL_INSTANCE_COMMENTS)?.AsString() == targetEM1Comment); FamilyInstance em2 = equipmentCollector .Cast<FamilyInstance>() .FirstOrDefault(em => em.get_Parameter(BuiltInParameter.ALL_MODEL_INSTANCE_COMMENTS)?.AsString() == targetEM2Comment); if (em1 == null || em2 == null) { TaskDialog.Show("Error", "Could not find one or both target mechanical equipment."); return; } // --- Step 2: Define the types of elements we want to collect HashSet<ElementId> collectedElementIds = new HashSet<ElementId>(); HashSet<Connector> visitedConnectors = new HashSet<Connector>(); // Recursive function to trace connected elements void TraceConnectedElements(Connector startConnector) { if (visitedConnectors.Contains(startConnector)) return; visitedConnectors.Add(startConnector); Element currentElement = startConnector.Owner; // Add the element to our collection if it's a pipe, fitting, or accessory if (currentElement.Category.Id.IntegerValue == (int)BuiltInCategory.OST_PipeCurves || currentElement.Category.Id.IntegerValue == (int)BuiltInCategory.OST_PipeFitting || currentElement.Category.Id.IntegerValue == (int)BuiltInCategory.OST_PipeAccessory) { collectedElementIds.Add(currentElement.Id); } // Check if we've reached the second equipment if (currentElement.Id == em2.Id) { return; } // Traverse all connected connectors foreach (Connector connectedConnector in startConnector.AllRefs) { TraceConnectedElements(connectedConnector); } } // Start tracing from all connectors on the first equipment foreach (Connector connector in em1.MEPModel.Connectors) { TraceConnectedElements(connector); } // --- Step 3: Display the results string report = string.Empty; foreach (ElementId elemId in collectedElementIds) { Element elem = doc.GetElement(elemId); report += $"Name = {elem.Name} | Element Id: {elemId}\n"; } TaskDialog.Show("Connected Components Between Equipment", $"Found {collectedElementIds.Count} elements in the connection path:\n\n{report}"); }
Key Improvements Over Your Original Code
- Targeted Equipment Selection: We explicitly pick the two user-specified devices instead of iterating all equipment in the view.
- Connection-Based Tracing: Uses Revit's
Connectorsystem to follow actual physical connections, so we don't get false positives from bounding box overlaps. - Recursive Traversal: Ensures we capture all elements along the path between the two devices, including pipes, fittings, and accessories.
Customization Tips
- If you want users to select the equipment interactively, replace the parameter-based selection with
uiDoc.Selection.PickObjects(ObjectType.Element, ...)to let them click the two devices. - You can expand the category filter to include other element types (like ducts, if needed) by adding their
BuiltInCategoryvalues to the check in the recursive function.
内容的提问来源于stack exchange,提问作者Nathan Franco

