Door/Window Numbering with Dynamo
I was recently working on a tool that will help us automate the process of numbering Windows and Doors in Revit based on the Room that they are in. Below is a detailed explanation of how it works so far.
Steps:
Collect Doors/Windows: First, I collected all of the doors/windows in the project. "Get Family Instances by Category" is a custom node that can be downloaded from the Package Manager.
Extract Room Assignment: Once you have all the doors in the project, it’s time to extract their room assignment information. Each door in Revit can contain information about what room it swings into. This is done by enabling Room Calculation Point in a Door Family Editor. I am using Revit API to extract that information:
doc = __doc__
room_number = []
room_name = []
doors = []
room = []
filter_1 = IN1
fam_inst = IN0
collector = FilteredElementCollector(doc)
phase_collector = collector.OfClass(Phase)
for i in phase_collector:
if i.Name == "New Construction":
phase = i
else:
print("no phase w/ specified name exists")
for i in fam_inst:
to_room = i.ToRoom[phase]
from_room = i.FromRoom[phase]
After gathering the room assignments, filters are applied based on whether the door swings into circulation space or if it is exterior.
if to_room is None or to_room.get_Parameter("Name").AsString() == filter_1:
if from_room is None:
room_number.append("No To or From Room")
room_name.append("No To or From Room")
doors.append("No To or From Room")
else:
room_number.append(from_room.get_Parameter("Number").AsString())
room_name.append(from_room.get_Parameter("Name").AsString())
doors.append(i)
room.append(from_room)
else:
room_number.append(to_room.get_Parameter("Number").AsString())
room_name.append(to_room.get_Parameter("Name").AsString())
doors.append(i)
room.append(to_room)
Finally, output the results:
OUT = [[room_number], [room_name], [doors], [room]]
- Build Numbering Sequence: The next step is to build a numbering sequence for our doors. I decided to number them in a clockwise fashion with each consecutive door/window getting a room number + letter suffix, e.g., 100A, 100B, etc.
To measure an angle between door location and the room location:
import math
door_x = IN0
room_x = IN1
angle = IN2
result = []
for i, j, k in zip(door_x, room_x, angle):
if i <= j:
result.append(math.pi+((math.pi)-k))
else:
result.append(k)
OUT = result
Sort Angles and Doors: Now that we have the proper angles, doors, and room numbers we need to sort them before assigning parameters.
from itertools import groupby room_number = IN0 angle = IN1 door = IN2 grps = sorted(zip(room_number, angle, door), key=lambda x: (x[0], x[1])) room_number, angle, door = [], [], [] for i, grp in groupby(grps, lambda x: x[0]): sub_rm_number, sub_angle, sub_door = [], [], [] for j in grp: sub_rm_number.append(j[0]) sub_angle.append(j[1]) sub_door.append(j[2]) room_number.append(sub_rm_number) angle.append(sub_angle) door.append(sub_door) OUT = [[room_number], [angle], [door]]Generate Mark Values: Using the sorted room number list, the marks are assigned values:
sequence = IN uniq_seq = []
def increment_item(item = 'A'): next_char = [ord(char) for char in item] next_char[-1] += 1 for index in range(len(next_char)-1, -1, -1): if next_char[index] > ord('Z'): next_char[index] = ord('A') if index > 0: next_char[index-1] += 1 else: next_char.append(ord('A')) return "".join((chr(char) for char in next_char))
def char_generator(start = 'A'): current = start yield start while True: current = increment_item(current) yield current
def build_unique_sequence(sequence): key_set = dict([item, char_generator()] for item in set(sequence)) return map(lambda item: '{}{}'.format(item, key_set[item].next()), sequence) OUT = build_unique_sequence(sequence)
The final outcome is doors and windows numbered based on the Rooms they are in or swing into.