Sum Selected Rooms

Let's put all our new seleciton skills to use right now. Let's create a simple tool to select Rooms in a view, and sum their Areas.

Sum Selected Rooms

Let's put all our new seleciton skills to use right now. Let's create a simple tool to select Rooms in a view, and sum their Areas.

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.

# -*- coding: utf-8 -*-
__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"""

# ╦╔╦╗╔═╗╔═╗╦═╗╔╦╗╔═╗
# ║║║║╠═╝║ ║╠╦╝ ║ ╚═╗
# ╩╩ ╩╩  ╚═╝╩╚═ ╩ ╚═╝ IMPORTS
#==================================================
from Autodesk.Revit.DB import *
from Autodesk.Revit.DB.Architecture import Room
from Autodesk.Revit.UI.Selection import (ObjectType,          
                                        PickBoxStyle,
                                        Selection)

# ╦  ╦╔═╗╦═╗╦╔═╗╔╗ ╦  ╔═╗╔═╗
# ╚╗╔╝╠═╣╠╦╝║╠═╣╠╩╗║  ║╣ ╚═╗
#  ╚╝ ╩ ╩╩╚═╩╩ ╩╚═╝╩═╝╚═╝╚═╝ VARIABLES
#==================================================
uidoc = __revit__.ActiveUIDocument
doc   = __revit__.ActiveUIDocument.Document

selection = uidoc.Selection # type: 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.

#📥 Custom Import
from Snippets._selection import ISelectionFilter_Classes

#1️⃣ GET SELECTED ROOMS
selected_elements = [doc.GetElement(e_id) for e_id in selection.GetElementIds()]
selected_rooms    = [el for el in selected_elements if type(el) == Room]

#2️⃣ Pick Rooms if none selected
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]

#3️⃣ Ensure Rooms Selected
if not selected_rooms:
    print('There were no Rooms selected. Please Try Again.')
    import sys
    sys.exit()
    # 👀 Alternative to Exit script with an Alert.
    # from pyrevit import forms
    # forms.alert('There were no Rooms selected. Please Try Again', 
    #              exitscript = True)
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.

# GET VALUES
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.

# GET VALUES
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 RESULTS
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.

# -*- coding: utf-8 -*-
__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"""

# ╦╔╦╗╔═╗╔═╗╦═╗╔╦╗╔═╗
# ║║║║╠═╝║ ║╠╦╝ ║ ╚═╗
# ╩╩ ╩╩  ╚═╝╩╚═ ╩ ╚═╝ IMPORTS
#==================================================
from Autodesk.Revit.DB import *
from Autodesk.Revit.DB.Architecture import Room
from Autodesk.Revit.UI.Selection import ObjectType, PickBoxStyle, Selection

# CUstom
from Snippets._selection import ISelectionFilter_Classes
from Snippets._convert import convert_internal_units

# .NET Imports
import clr
clr.AddReference("System")
from System.Collections.Generic import List

# ╦  ╦╔═╗╦═╗╦╔═╗╔╗ ╦  ╔═╗╔═╗
# ╚╗╔╝╠═╣╠╦╝║╠═╣╠╩╗║  ║╣ ╚═╗
#  ╚╝ ╩ ╩╩╚═╩╩ ╩╚═╝╩═╝╚═╝╚═╝ VARIABLES
#==================================================
uidoc = __revit__.ActiveUIDocument
doc   = __revit__.ActiveUIDocument.Document

selection = uidoc.Selection # type: Selection

# ╔╦╗╔═╗╦╔╗╔
# ║║║╠═╣║║║║
# ╩ ╩╩ ╩╩╝╚╝
#==================================================

# GET ROOMS
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()

# GET VALUES
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 RESULTS
print('-'*20)
print("Total: {}m²".format( total))
print('Selected {} Rooms.'.format(len(selected_rooms)))

HomeWork

⚡ 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) 
#👆 This will make 0 as default value instead of missing key error!

rooms = ... #TODO Select Rooms

for room in rooms:
    room_level_name = ... #TODO Get Room's 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!

#🔷 Get Wall Type Name
wall_type_name = wall.get_Parameter(BuiltInParameter.ELEM_TYPE_PARAM).AsValueString()
#💡 We will cover parameters in the next module!

#🔷 Set Selection in Revit UI Example
new_selection = List[ElementId]()
new_selection.Add(ElementId(347164))
new_selection.Add(ElementId(347244))

selection.SetElementIds(new_selection)

⌨️ Happy Coding!

Discuss the lesson:

P.S. Sometimes this chat might experience connection issues.
Please be patient or join via Discord app so you can get the most out of this community and get access to even more chats.

P.S. Sometimes this chat might experience connection issues.
Please be patient or join via Discord app so you can get the most out of this community and get access to even more chats.

© 2023-2024 EF Learn Revit API

© 2023-2024 EF Learn Revit API

© 2023-2024 EF Learn Revit API