I want to calculate values off the doors and windows in a room. I use Room.Doors & Room.Windows to return all the doors and windows accordingly. I then take the lists and run their seperate Windows.Room and Doors.Room then using the roomCount Variable I can see if its connected to more than just one room (I’m trying to only count for doors and windows on the exterior of the building and not interior doors or windows). if anyone has any better ideas of how to calculate if a door or window is on the exterior of a building id be more than happy to hear!
However I don’t know how to remove the doors/windows that have more than 1 connected room from the original Room.Doors/Windows list. How would I go about doing it?
For my example I’m just using doors to keep it simple:
Do all your doors and windows have the Room Calculation point turned on? (I assume they do based on your description.) If that is the case, you don’t need any programing to find the exterior doors and windows. Just look at the From Room and To Room values. If a door only has one of the values, it is on the exterior. If all your doors are built the same way and swing out - then you can just check to see if To Room is null. If some doors swing in and some swing out - then you’ll have to check both values. If one is blank - then it is exterior.
Of course, the FromRoom and ToRoom properties are phase specific, so watch that if you are doing a multiphase project.
I planned on using the roomCount value because I thought of it to be as simple as, if the door is in the interior of a building it has to connect between two rooms. However an exterior door only connects to a interior room as their is no room outside. This would remove having to check both fromRoom and toRoom values and phase checking.
My main issue was only how to edit the original list of door elements and remove the ones which roomCounts are above 1.
Some things are just faster in python using the API. Basically, one line of code.
phases = doc.Phases
phase = phases[phases.Size - 1]
exteriordoors = [d for d in FilteredElementCollector(doc).OfClass(FamilyInstance).OfCategory(BuiltInCategory.OST_Doors).WhereElementIsNotElementType().ToElements() if d.ToRoom[phase] == None]
for x in exteriordoors:
print(x.FromRoom[phase].Id)
You can change the if to if or if you want to check both ToRoom and FromRoom
exteriordoors = [d for d in FilteredElementCollector(doc).OfClass(FamilyInstance).OfCategory(BuiltInCategory.OST_Doors).WhereElementIsNotElementType().ToElements() if d.ToRoom[phase] == None or FromRoom[phase] == None].
There is no IN needed. The FilteredElementCollector is doing all the work. It is the basic Revit API tool to get all the objects you want. The OUT is the exteriordoors.
To get a reference to the current document - you need to initialize and load the related libraries.
import RevitServices
from RevitServices.Persistence import DocumentManager
doc = DocumentManager.Instance.CurrentDBDocument
This is a good reference to a basic dyanmo header. Boilerplate
As to doing this in Dynamo - just use the roomCount connected to an If function node to filter your list. But like I noted, that’s a bunch of connect the dots where you can do everything in just one step.
And note - you should still consider Phases. May not be needed for Project A. But it will bite you in the end if you don’t plan for it.
Since I am not as experienced in such coding I would prefer to keep it in dynamo as connecting the dots helps explain the entire process better i.e. the entire reason visual programming exists as for the people who need a more visual help.
How would I go about using the if function to edit the original list of doors to only remain the doors that have only a single connected room?
I would input the list of doors into the test and how would I get the roomCount function to run in the true section of the function?
If this is using your original python script then I simply must be getting something wrong as the script won’t function properly. Even using the mentioned baseplate template the error:
Also, another reason why I preferred roomCount over toRoom and fromRoom function is certain projects may have doors that swing inwards to enter and building compared to the typical outswing meaning using the two other functions would lead to issues no?
I see this as apples to onions situation. Having the door function be assigned by type means that whoever is placing the doors knows the door they are placing is the correct function for how they plan to use the door. Certain doors in Revit are completely fine to use as interior doors as well so therefore you should duplicate the door just to have its function be different? This could lead to a lot more doors where the only difference is the function in its type. This is arguably as meticulous as placing the rooms for each space is it not?
There are edge cases to watch out for like others have mentioned, but that’s going to be the case for any solution.
Your initial attempt was actually really close. Instead of using List.Filter (which filters the list that it’s applying the conditional to) use List.FilterByBoolMask (which allows you to filter a separate list from the conditional test). Just check to see which values are >1 and then filter the list of doors.
Perfect! it took me a while to get it to work (my Dynamo and Revit decided to crash several times). Had a bit of issues getting the bool system to work but this looks perfect.
This is the important bit to remember. However I’ll throw one more option into the mix: use the building envelope analyzer and grab anything in the door category.
Of course there are instances of exterior “rooms”. We use quite a few of those where we might have a trellised patio, deck or numerous “yard” spaces that need to be included in code and occupancy calculations. So, filtering can get a little more challenging depending on what a room is.
Here’s the fully expanded code for demonstration…
It will take a dynamo phase as input. Or that can be omitted and it will use the last phase of the project.
import clr
import sys
clr.AddReference("RevitAPI")
from Autodesk.Revit.DB import *
import RevitServices
from RevitServices.Persistence import DocumentManager
doc = DocumentManager.Instance.CurrentDBDocument
phasein = IN[0]
phasein = doc.GetElement(ElementId(str(phasein.Id)))
if phasein == None:
phases = doc.Phases
phase = phases[phases.Size - 1]
else:
phase = phasein
doors = FilteredElementCollector(doc).OfClass(FamilyInstance).OfCategory(BuiltInCategory.OST_Doors).WhereElementIsNotElementType().ToElements()
exteriordoors = []
for d in doors:
if d.get_ToRoom(phase) == None or d.get_FromRoom(phase) == None:
exteriordoors.append(d)
OUT = exteriordoors