Summary
Brainstorm The Tool Idea
Let's create a simple tool we could use.
For example, we could create a tool to select Rooms and then calculate their total sum of areas.
Let's break it down into the following steps:
Get Rooms
Get Room Name & Area
Calculate Total Sum with Rounded Area
Display Results
Script Template
Let's begin our script by copying our Imports & Variables from a script Template or one of the previous tools.
Modify Button Name and Description and this step is complete.
__title__ = "03.04 - Sum Rooms"
__doc__ = """Date = 02.01.2023
_____________________________________________________________________
Description:
Tool to Sum selected Rooms.
If no rooms selected, you will be asked to select them.
_____________________________________________________________________
Author: Erik Frits"""
from Autodesk.Revit.DB import *
from Autodesk.Revit.DB.Architecture import Room
from Autodesk.Revit.UI.Selection import (ObjectType,
PickBoxStyle,
Selection)
uidoc = __revit__.ActiveUIDocument
doc = __revit__.ActiveUIDocument.Document
selection = uidoc.Selection
Step 1: Get Rooms
Now let's select some Rooms.
By now you should be familiar with everything in the snippet below.
1️⃣ First, we attempt to get the currently selected rooms in Revit UI
2️⃣ If nothing is selected, we prompt the user to pick rooms using the PickObjects method and ISelectionFilter, which allows only Room selection.
3️⃣ Finally, verify that rooms were chosen or stop the script's execution.
from Snippets._selection import ISelectionFilter_Classes
selected_elements = [doc.GetElement(e_id) for e_id in selection.GetElementIds()]
selected_rooms = [el for el in selected_elements if type(el) == Room]
if not selected_rooms:
filter_types = ISelectionFilter_Classes([Room])
ref_picked_rooms = selection.PickObjects(ObjectType.Element, filter_types)
selected_rooms = [doc.GetElement(ref) for ref in ref_picked_rooms]
if not selected_rooms:
print('There were no Rooms selected. Please Try Again.')
import sys
sys.exit()
Step 2: Get Values
Once we have our rooms, we can iterate through them and get Room's Name and Area.
And since all units in Revit API are in feet we also should convert it to metric system, and round it so we can account for precision error when we start summing it up.
for room in selected_rooms:
room_name = room.get_Parameter(BuiltInParameter.ROOM_NAME).AsString()
area_m2 = convert_internal_units(room.Area, get_internal=False, units='m2')
area_m2_rounded = round(area_m2, 2)
Step 3: Calculate Sums
Now let's also create 2 sums.
Usually, we will need just single sum of room areas, but for this example I want to show you the difference between rounded and not-rounded values being added together.
total = 0
total_b = 0
for room in selected_rooms:
room_name = room.get_Parameter(BuiltInParameter.ROOM_NAME).AsString()
area_m2 = convert_internal_units(room.Area, get_internal=False, units='m2')
area_m2_rounded = round(area_m2, 2)
total += area_m2_rounded
print("{}: {}m²".format(room_name, area_m2_rounded))
print('-'*20)
print("Total: {}m²".format( total))
print('Selected {} Rooms.'.format(len(selected_rooms)))
🎦 Check the video to see the difference between Rounded/Not-Rounded values being summed up.
Why Rounding is Important
As I showed in the video, normally we see just 2 digits after comma on the screen.
But Revit actually keeps far more digits after that. And that's why sometimes our total sum might not be equal to the actual sum of numbers shown on screen.
👇 Example
On Screen
0,33
0,33
0,33
——————
0,99 Total
In Revit
0,334 312 356
0,334 312 356
0,334 312 356
—————————
1,002 937 068 Total
1,00 Rounded Total
💡 Be sure to round your values before you add them to the sum!
P.S. Did you know that your schedules sums are also wrong?
Check this video to see what I mean and how to fix your schedules.
Complete Code
👀 Here is the final code combined together.
__title__ = "03.04 - Sum Rooms"
__doc__ = """Date = 02.01.2023
_____________________________________________________________________
Description:
Tool to Sum selected Rooms.
If no rooms selected, you will be asked to select them.
_____________________________________________________________________
Author: Erik Frits"""
from Autodesk.Revit.DB import *
from Autodesk.Revit.DB.Architecture import Room
from Autodesk.Revit.UI.Selection import ObjectType, PickBoxStyle, Selection
from Snippets._selection import ISelectionFilter_Classes
from Snippets._convert import convert_internal_units
import clr
clr.AddReference("System")
from System.Collections.Generic import List
uidoc = __revit__.ActiveUIDocument
doc = __revit__.ActiveUIDocument.Document
selection = uidoc.Selection
selected_elements = [doc.GetElement(e_id) for e_id in selection.GetElementIds()]
selected_rooms = [el for el in selected_elements if type(el) == Room]
if not selected_rooms:
filter_types = ISelectionFilter_Classes([Room])
ref_picked_rooms = selection.PickObjects(ObjectType.Element, filter_types)
selected_rooms = [doc.GetElement(ref) for ref in ref_picked_rooms]
if not selected_rooms:
print('There were no Rooms selected. Please Try Again.')
import sys
sys.exit()
total = 0
total_b = 0
for room in selected_rooms:
room_name = room.get_Parameter(BuiltInParameter.ROOM_NAME).AsString()
area_m2 = convert_internal_units(room.Area, get_internal=False, units='m2')
area_m2_rounded = round(area_m2, 2)
total += area_m2_rounded
print("{}: {}m²".format(room_name, area_m2_rounded))
print('-'*20)
print("Total: {}m²".format( total))
print('Selected {} Rooms.'.format(len(selected_rooms)))
⚡ I think you are ready to create a simple tool on your own as well!
Try to practice your skills. It's best if you already have an idea for a tool, but I will also drop some simple ideas you could do.
💼 Tool Idea #1:
Create a report to check selected room's level. You can count how many rooms are placed on each unique level.
1️⃣ Select Rooms
2️⃣ Get Associated Level (Check .Level Property)
3️⃣ Count how many rooms associated with unique level
4️⃣ Create report with print() statements (Level 1 has 5 Rooms…)
💡You can use defaultdict for storing counting.
from collections import defaultdict
counts = defaultdict(int)
rooms = ...
for room in rooms:
room_level_name = ...
counts[room_level_name] += 1
for k,v in counts.items():
print('Level {} has {} Rooms')
💼 Tool Idea #2:
Select doors and change selection to only doors hosted on concrete walls.
1️⃣ Select Doors
2️⃣ Get Door's Host (Check .Host Property)
3️⃣ Get Type Name of a Host (See Code Snippet below)
4️⃣ Check if it has keyword for 'Concrete'
5️⃣ Create List[ElementId]() for new Selection
6️⃣ Change Revit UI Selection
💡 Doors use FamilyInstance Class!
wall_type_name = wall.get_Parameter(BuiltInParameter.ELEM_TYPE_PARAM).AsValueString()
new_selection = List[ElementId]()
new_selection.Add(ElementId(347164))
new_selection.Add(ElementId(347244))
selection.SetElementIds(new_selection)