Grouping connected LinkElements (cable trays and fittings)

Hi all,

I have linked cable trays and cable trays with fittings and I want to identify runs of the cable trays, or at least get the straight sections (separated by a bend) in separate lists. Ideally these would be ordered in sequence as they are connected, so I can treat them as a single line that I can create points over i.e. a point at every X distance.

I have tried to recreate attempts on some other forum posts but have had no success: Get Conduit Network (all connected elements), Sequence of Connected Mechanical Elements etc. …

Currently trying the MEPover Elements in connected network node but the elements are returning null. The elements are LinkElements from Bimorph Nodes if it is relevant.

Hi @Grace.8Y72Z not really sure but if you are after get line from every run, you could try something here…here for 3 runs

1 Like

Thank you for help @sovitek I tried your method and have the following results which I will try to modify further to suit what I need. But I was wondering how did you choose an appropriate margin for the Geometry.GroupByDistance node?

This is okay, however, I also have some instances of cable tray fittings that form part of the cable tray run. I notice these are represented by points rather than lines/curves. Would I instead have to look at start/end points and try to figure it out that way?

Thanks

Hi @Grace.8Y72Z yeah many things can go wrong depends :wink: you could try something here and see if it could be better…you are welcome to share a sample rvt we can test on…but will probably not work on random projects…

cablelink.dyn (33.4 KB)

1 Like

Thank you @sovitek for your help! This way works well for my project, as well as for this small sample Revit file which includes cable trays as well as fittings. They are solids though so I’ve given it a few attempts but not sure how I would get points (XYZ) along each separate run. I will continue trying and can hopefully update with a solution later …

cablelink_RVT.rvt (4.1 MB)
cablelink_DYN.dyn (32.1 KB)


Hi @Grace.8Y72Z you can get the connected from link this way here, could probably help
Revit_oGEMY8vybT
cablelink_DYN.dyn (13.0 KB)

2 Likes

Hi @sovitek, this is what I was after - thank you! For use in my project, I used AI to edit the code slightly as I was having some trouble with the MEPModel attribute error. Also included the input element in the output list too i.e. if a single cable tray has no connections/fittings, the single cable tray will still be in the output list. Thanks again :slight_smile:

import clr
import sys

pyt_path = r'C:\\Program Files (x86)\\IronPython 2.7\\Lib'
sys.path.append(pyt_path)
import System

clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument

clr.AddReference("RevitAPI")
import Autodesk
from Autodesk.Revit.DB import *

clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)

import collections

linked_docs = [doc]
for link in FilteredElementCollector(doc).OfClass(RevitLinkInstance):
    linked_doc = link.GetLinkDocument()
    if linked_doc:
        linked_docs.append(linked_doc)

if isinstance(IN[0], list):
    connector = UnwrapElement(IN[0])
    toggle = 0
else:
    connector = [UnwrapElement(IN[0])]
    toggle = 1

bool = IN[1]

def getElementFromAllDocs(element_id):
    for linked_doc in linked_docs:
        try:
            element = linked_doc.GetElement(element_id)
            if element:
                return element
        except:
            continue
    return None

def nextElements(elem):
    listout = []
    if isinstance(elem, Connector):
        conn = elem
        for c in conn.AllRefs:
            if c.Owner.Id.Equals(elem.Owner.Id):
                continue
            elif isinstance(c.Owner, MEPSystem):
                continue
            else:
                newelem = getElementFromAllDocs(c.Owner.Id)
            listout.append(newelem)
        return listout
    try:
        connectors = elem.ConnectorManager.Connectors
    except AttributeError:
        connectors = elem.MEPModel.ConnectorManager.Connectors if hasattr(elem, 'MEPModel') else []
    for conn in connectors:
        for c in conn.AllRefs:
            if c.Owner.Id.Equals(elem.Id):
                continue
            elif isinstance(c.Owner, MEPSystem):
                continue
            elif c.Owner.Id.Equals(ownerId):
                continue
            else:
                newelem = getElementFromAllDocs(c.Owner.Id)
            listout.append(newelem)
    return listout

def nextElementsWithOwner(elem):
    listout = []
    if isinstance(elem, Connector):
        conn = elem
        for c in conn.AllRefs:
            if c.Owner.Id.Equals(elem.Owner.Id):
                continue
            elif isinstance(c.Owner, MEPSystem):
                continue
            else:
                newelem = getElementFromAllDocs(c.Owner.Id)
            listout.append(newelem)
        return listout
    try:
        connectors = elem.ConnectorManager.Connectors
    except AttributeError:
        connectors = elem.MEPModel.ConnectorManager.Connectors if hasattr(elem, 'MEPModel') else []
    for conn in connectors:
        for c in conn.AllRefs:
            if c.Owner.Id.Equals(elem.Id):
                continue
            elif isinstance(c.Owner, MEPSystem):
                continue
            else:
                newelem = getElementFromAllDocs(c.Owner.Id)
            listout.append(newelem)
    return listout

def collector(elem):
    cont = 0
    elements = nextElements(elem)
    lookup[elem.Id] = elem  # Include the original element in the lookup dictionary
    for x in elements:
        if x.Id in lookup:
            cont += 1
        else:
            item = getElementFromAllDocs(x.Id)
            lookup[x.Id] = item
            collector(x)
    if cont == len(elements):
        return elem

def collectorWithOwner(elem):
    cont = 0
    elements = nextElementsWithOwner(elem)
    lookup[elem.Id] = elem  # Include the original element in the lookup dictionary
    for x in elements:
        if x.Id in lookup:
            cont += 1
        else:
            item = getElementFromAllDocs(x.Id)
            lookup[x.Id] = item
            collectorWithOwner(x)
    if cont == len(elements):
        return elem

listout = []
if bool:
    for x in connector:
        lookup = collections.OrderedDict()
        collectorWithOwner(x)
        listout.append(list(lookup.values()))   
else:
    for x in connector:
        lookup = collections.OrderedDict()
        if isinstance(x, Connector):
            ownerId = x.Owner.Id
        else:
            ownerId = x.Id
        collector(x)
        listout.append(list(lookup.values()))

if toggle:
    OUT = list(lookup.values())  
else:
    OUT = listout