Get Room.Floors?

Hello @all,
is there a way to get the floors of a room as a list?
i was trying to look after the geometry of rooms and floors for geometry.doesintersect but its really time consuming and not all geometry can be read.
so is there a better way to do this?

Room.Boundaries will work if the floors are room bounding and volumetric boundaries are enabled.

If they aren’t then you’re stuck with geometry tests as floors can span multiple rooms and rooms can span multiple floors, so sampling a single point doesn’t help.

hello @jacob.small,
thank you for the quick response!
Could you show me how to check up or active the voumetric boundaries?
I guess by default it is deactivated?

for now i got the room solids translated by a short distance for getting the intersected elements…
but this is not so accurate… and i got a lot of empty results…
it is because of shafts i think…

Volumetric calculations are enabled here:

As far as their default status, that will depend on your template.

This Python may help identify the floors in the room (FYI @cintiamiranda21 this might help you with some of the work you were asking about yesterday as well).

########################################
############## Properties ##############
########################################
__author__ = 'Jacob Small'
__version__ = '0.1.0'
__description__ = """Gets the bounding elements from a room in a dictionary format using the category as the key."""
__RevitBuilds__ = "2024.1"
__DynamoBuilds__ = "2.18.1"
__ReleaseNotes__ = """ """
__Dependancies__ = "-"
__Copyright__ = "2024, Autodesk Inc."
__License__ = """MIT"""

########################################
### Configure the Python environment ###
########################################
### standard imports ###
import sys #add the sys class to the Python environment so we can work with the sys objects
import clr #add the CLR (common language runtime) class to the Python environment so we can work with .net libraries
### Dynamo Revit imports ###
clr.AddReference("RevitNodes") #add Dynamo's Revit nodes library to the clr
import Revit #import Dynamo's Revit node class
clr.ImportExtensions(Revit.Elements) #add the element conversion methods to the CLR
clr.AddReference("RevitServices") #add the Revit services library to the CLR
import RevitServices #import the Revit services class to the Python environment
from RevitServices.Persistence import DocumentManager #import the document manager class to the Python environment 
### Revit API imports ###
clr.AddReference("RevitAPI") #add the Revit API to the CLR
import Autodesk #add the Autodesk class to the Python environment 
from Autodesk.Revit.DB import * #import every class of the Revit API to the Python environment

#########################################
############# Start of code #############
#########################################
#get the document and unwrap the input, converting to a list if needed
doc = DocumentManager.Instance.CurrentDBDocument #the current Revit document
rooms = UnwrapElement(IN[0]) #import the elements from IN[0] of the Dynamo environment and convert to native Revit elements
if not rooms.__class__ == [].__class__ : rooms = [rooms] #ensure that elems is a list, not an individual object, so that we can always prepare for a loop

#generate the spatial element boundary calculation options 
spatialCalcOptions = SpatialElementBoundaryOptions() #setup the spatial coudary calculation options
spatialCalcOptions.SpatialElementBoundaryLocation = SpatialElementBoundaryLocation.Finish #set the boundary calcuation to the finish face
spatialElementGeometryCalculator = SpatialElementGeometryCalculator(doc,spatialCalcOptions) #generate a spatial element calculator
OUT = [] #define OUT as a list so we can add stuff to it
#iterate voer the rooms to get the bounding elements into a dictionary using the category names as keys
for room in rooms: #for every room
    results = {"Room": room} #build a dictionary containing the room in the room key
    elementList = [] #build an empty list for the bounding elements
    spatialGeometry = spatialElementGeometryCalculator.CalculateSpatialElementGeometry(room) #get the spatial element's geometry
    faces = spatialGeometry.GetGeometry().Faces #get the faces of the spatial geometry
    #get the element ID for each bounding element of each face and add it to the element list
    for f in faces: #for every face
        faceInfoSet = spatialGeometry.GetBoundaryFaceInfo(f) #get the boundary face info
        for faceInfo in faceInfoSet: #for every face info
            linkElemId = faceInfo.SpatialBoundaryElement #get the spatial boundary element
            if linkElemId.HostElementId != ElementId.InvalidElementId: elem = linkElemId.HostElementId  #if the element isn't in a link, set the element variable to the bounding element's element id
            else: elem = "handling of links is not currently supported" #if the element is in a link, thank you mario but our princess is in another castle
            #If you need to work with links, look into the LinkElementId class of the Revit API
            elementList.append(elem) #append the element id to the elements list
    #get the unique element IDs from the list and convert to the actual elements
    elementList = list(set(elementList)) #get the unique element ids in the elements list
    elementList = [doc.GetElement(i) for i in elementList] #get the element for each element ID
    #set the keys for the results dictionary to the category names
    categories = [] #build an empty list for category names
    [categories.append(i.Category.Name) for i in elementList if i.Category.Name not in categories] #append each new category name onto the categories list
    for i in categories: results[i] = [] #set the result dictionary's key for each category name to an empty list
    #add the elements to the associated list in the dictionary
    for elem in elementList: #for every element
        cat = elem.Category.Name #get the category name
        results[cat].append(elem)#append the element to the list in the result dictioanry's key for the category
    #collect the results
    OUT.append(results) #append the results list to the OUT variable

Hello,

Did you try Room.Boundaries node from Clockwork package as suggested? It usually works very well with detecting floors.

Maybe if you get centre of floors, go up by a nominal distance and use room.atpoint, then ask which of those match the nominated room number(s)?

What if I have one continuous tile floor from my living room, into my kitchen, and then into the hallway? Center of that floor will only hit one of those 3 rooms (if a room at all).

Yes the only way to do that I guess would be using solid intersections between room and floors. Quite costly computationally.

If it’s a simple model, or you just want to collect the vast majority something like this might be fine:

room at point floors.dyn (30.2 KB)

The Python I posted above uses the SpatialElementGeometryCalculator class, which is more or less a topology based approach which should be a few orders of magnitude quicker.

2 Likes


yes, i tried Clockwork and archilab nodes, but none of them get me the floors.

this is the setting of the volumetric boundaries…

Try the Python I posted above. If that doesn’t work:

  • Open the model detached
  • Delete everything except for two rooms and their bounding elements
  • Delete all views except for a 3D view
  • Purge unused 3x
  • Save the model
  • Upload it here or in another file sharing site with no log-in

@jacob.small
thank you for your help and the python code - i really appreciate it!


it works indeed, but not on every room, and not as a list of rooms as input…

unfortunately i cannot upload the file here due to restrictions of my work :confused:

Have you removed any unplaced or unbound rooms from the list?

Looks like you are also using a rather old version - 2021 or older? Might be that you’re too far behind to utilize some of these tools.

Sadly if you can’t share content to reproduce the error I can’t help much more. I guess try processing in groups of 10, recording the data as needed until you find the failing element(s) at which point you can skip those and do them manually.

yes i know, but thank you anyway :slight_smile: @jacob.small
i am working with Revit 2022.1 and Dynamo 2.12.1.8246


for now i am going with this workaround… retrieving the bounding box of the rooms - looking after element intersections. then to ensure that only the floors within a the room are selected, i am filtering after the midpoints of the floors - checking for the point inside of the specific room…
this may not work for not rectangular shaped floors, just going a bit into one room, so the midpoint is not detected for the room - but in our case here the floors are constructed splitted anyway because of the joints…