ʳʰʸᵗʰᵐ|FamilyInstances.RetrieveNestedComponents vs GetSubComponent

Hi all,

Can someone help me with this issue?
I use a python script to get the nested family but the Rhythm node retrieve more nested family.

I see the Rhythm node use a while but I don’t know how to use it inside this script:

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

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

items = UnwrapElement(IN[0])
elementlist = list()

for item in items:
	itemlist = list()
	try:
		for subcomp in item.GetSubComponentIds():
			itemlist.append(item.Document.GetElement(subcomp).ToDSType(True))
	except:
		itemlist .append(None)
	elementlist.append(itemlist)
OUT = elementlist
1 Like

Let me see what I can come up with. But for anyone else curious how Rhythm does it, the source code is here:

2 Likes

I hope you know how to do it in Python, I don’t have knowledge of c# haha

I was hoping you knew what I was doing in the C#, because looking back I am not sure either. :woozy_face:

2 Likes

I think this will do it:

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

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

def GetNestedFamilies(fi):
	# this allows us to dig down
	internalFamilies = []
	
	# add each family to this list to work down
	internalFamilies.append(fi)
	
	# for us to output (this can be adapted to be nested further)
	nestedList = []
	
	# for us to step through the families
	flag = 0
	
	# fwiw, this could also be an int
	stopString = "keepGoing"

	while stopString == "keepGoing":
		if flag != internalFamilies.Count:
			#go through all the subcomponents (while adding them to the overall list, to then iterate through)
			for subComponent in internalFamilies[flag].GetSubComponentIds():
				
				famDoc = internalFamilies[flag].Document
	
				internalFamily = famDoc.GetElement(subComponent)
				# this enables the further digging
				internalFamilies.append(internalFamily)
				
				nestedList.append(internalFamily.ToDSType(True))
			# increment the flag
			flag = flag + 1
			stopString = "keepGoing"
		else:
			stopString = "stahp it"

	return nestedList
	
def tolist(obj1):
	if hasattr(obj1,"__iter__"): return obj1
	else: return [obj1]

familyInstances = tolist(UnwrapElement(IN[0]))

subLists = []

# iterate through the given instances
for fi in familyInstances:
	subLists.append(GetNestedFamilies(fi))

		
OUT = subLists

and also in the Rhythm repo under the python resources now:

2 Likes

With a recursive Python function

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

clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)
	
def get_SubComponent2(item, i = 0):
	"""get SubComponents recursively"""
	i += 1
	if i < 100: # avoid infinite loop
		allSub = [item.Document.GetElement(subcompId)for subcompId in item.GetSubComponentIds()]
		# return the list and check if SubComponent have a SubComponent too
		# use sum trick to flat the python list
		return allSub + sum([get_SubComponent2(subitem, i) for subitem in allSub], [])
	return []


toList = lambda x : x if hasattr(x, '__iter__') else [x]
lst_item = toList(UnwrapElement(IN[0]))

OUT = [get_SubComponent2(item) for item in lst_item]
4 Likes

@john_pierson @c.poupin Wauw this is awesome what you both did! :grin:
Thanks alot for the help, I see someone give the solution already so I don’t have to choose :sweat_smile:

1 Like