How to change basement of a placed room?

Hello,

actually i am not the first who has this wish… today i did for 30 rooms one by one. delete room → place room.

# -*- coding: utf-8 -*-
__title__ = "SetBasementRooms"
__doc__ = """Version = 1.0
Date    = 29.10.2023Version = 1.0

Date    = 29.10.2023
_____________________________________________________________________
Description:
This is a template file for pyRevit Scripts.
_____________________________________________________________________
How-to:
-> Click on the button
_____________________________________________________________________
Last update:
- [24.04.2022] - 1.0 RELEASE
_____________________________________________________________________
To-Do:
- 
"""


# IMPORTS
# ==================================================
# Regular + Autodesk
from Autodesk.Revit.DB import *
from Autodesk.Revit.UI.Selection import ISelectionFilter, ObjectType, Selection
# pyRevit
from pyrevit import script, revit, forms

# .NET Imports
import clr

clr.AddReference("System")


from pyrevit import script
from Autodesk.Revit.DB import *

import time
start_time = time.time()

import clr
clr.AddReference("RevitAPI")
clr.AddReference("RevitAPIUI")

from System.Collections.Generic import List
from System import EventHandler
from System.Windows.Forms import Form, Button, CheckBox, ComboBox, DialogResult, Label, ListView, TextBox, View
from System.Drawing import Point
from Autodesk.Revit.DB.Events import TransactionGroupAfterFailureEventArgs
from Autodesk.Revit.Exceptions import OperationCanceledException



doc = __revit__.ActiveUIDocument.Document
uidoc = __revit__.ActiveUIDocument
app = __revit__.Application
selection = uidoc.Selection # type: Selection


class TestForm(Form):
    def __init__(self, _doc):
        self.doc = _doc

        self.InitializeComponent()

    def InitializeComponent(self):
        self.Text = "TestForm"
        self.Width = 500
        self.Height = 500

        self.listView1 = ListView()
        self.listView1.Location = Point(10, 10)
        self.listView1.Size = (300, 200)
        self.listView1.CheckBoxes = True
        self.Controls.Add(self.listView1)

        self.cboLevel = ComboBox()
        self.cboLevel.Location = Point(10, 220)
        self.cboLevel.Size = (300, 20)
        self.Controls.Add(self.cboLevel)

        self.btnClose = Button()
        self.btnClose.Location = Point(10, 250)
        self.btnClose.Size = (100, 30)
        self.btnClose.Text = "Close"
        self.btnClose.Click += self.btnClose_Click
        self.Controls.Add(self.btnClose)

        self.btnOK = Button()
        self.btnOK.Location = Point(120, 250)
        self.btnOK.Size = (100, 30)
        self.btnOK.Text = "OK"
        self.btnOK.Click += self.btnOK_Click
        self.Controls.Add(self.btnOK)

        self.Load += self.TestForm_Load

    def btnClose_Click(self, sender, args):
        self.Close()

    def TestForm_Load(self, sender, args):
        rooms = FilteredElementCollector(self.doc).OfCategory(BuiltInCategory.OST_Rooms).WhereElementIsNotElementType().ToElements()
        for room in rooms:
            if room.Area > 0 and room.Location != None:
                item = ListViewItem(room.Number + " - " + room.Name)
                item.Tag = room
                self.listView1.Items.Add(item)

        levels = {}
        for level in FilteredElementCollector(self.doc).OfCategory(BuiltInCategory.OST_Levels).WhereElementIsNotElementType().ToElements():
            levels[level.Name] = level

        self.cboLevel.DataSource = list(levels.keys())
        self.cboLevel.DisplayMember = "Key"
        self.cboLevel.ValueMember = "Value"

    def btnOK_Click(self, sender, args):
        try:
            transGroup = TransactionGroup(self.doc, "Move Rooms")
            transGroup.Start()

            for item in self.listView1.CheckedItems:
                room = item.Tag
                rmPT = room.Location.Point
                roomPoint = XYZ(rmPT.X, rmPT.Y, rmPT.Z)
                offset = room.get_Parameter(BuiltInParameter.ROOM_UPPER_LEVEL).AsDouble()

                trans1 = Transaction(self.doc, "Unplace Room")
                trans1.Start()

                failOptions = trans1.GetFailureHandlingOptions()
                failOptions.SetFailuresPreprocessor(UnplacedRoomWarning())
                trans1.SetFailureHandlingOptions(failOptions)

                room.Unplace()
                trans1.Commit()

                trans2 = Transaction(self.doc, "New Room")
                trans2.Start()

                level = self.cboLevel.SelectedItem
                topo = self.doc.GetPlanTopology(level)
                circuits = topo.Circuits

                for circuit in circuits:
                    if not circuit.IsRoomLocated:
                        newRoom = self.doc.Create.NewRoom(room, circuit)
                        newRoom.get_Parameter(BuiltInParameter.ROOM_UPPER_LEVEL).Set(level.Id)
                        newRoom.get_Parameter(BuiltInParameter.ROOM_LOWER_OFFSET).Set(offset)
                        move = XYZ(roomPoint.X - rmPT.X, roomPoint.Y - rmPT.Y, rmPT.Z)
                        ElementTransformUtils.MoveElement(self.doc, newRoom.Id, move)
                        break

                trans2.Commit()

            transGroup.Assimilate()
            self.Close()
        except OperationCanceledException as ex:
            pass
        except Exception as ex:
            forms.alert("An error occurred: {}".format(ex))

class UnplacedRoomWarning(IFailuresPreprocessor):
    def PreprocessFailures(self, failuresAccessor):
        failures = failuresAccessor.GetFailureMessages()
        for failure in failures:
            if failure.GetSeverity() == FailureSeverity.Warning:
                failureId = failure.GetFailureDefinitionId()
                if failureId == BuiltInFailures.RoomFailures.RoomUnplaceWarning or failureId == BuiltInFailures.RoomFailures.RoomHeightNegative:
                    failuresAccessor.DeleteWarning(failure)
            else:
                failuresAccessor.ResolveFailure(failure)
                return FailureProcessingResult.ProceedWithCommit
        return FailureProcessingResult.Continue


form = TestForm(doc)
form.ShowDialog()

i try to debug this code, here is the sourcecode in C#

i am already able to select my rooms with this:

# 🛒 classes
class ISelectionFilter_Classes(ISelectionFilter):
    def __init__(self, allowed_types):
        """ ISelectionFilter made to filter with types
        :param allowed_types: list of allowed Types"""
        self.allowed_types = allowed_types

    def AllowElement(self, element):
        if type(element) in self.allowed_types:
            return True

# 0️⃣ PickElementsByRectangle
selected_elements = [doc.GetElement(e_id) for e_id in selection.GetElementIds()]
selected_rooms = [el for el in selected_elements if type == 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("Please select a Room")
    import sys
    sys.exit()

currentBasement = [p.get_Parameter(BuiltInParameter.ROOM_LEVEL_ID).AsElementId() for p in selected_rooms]
print(currentBasement)
# ✅END

first how can i get rid of this error message… ?

Since you don’t even use that object in your code, just remove it from the imports :wink:

As a reminder, most of the boilerplate code you have in your template is already taken care for by pyrevit itself; for example there’s no need to add the reference to System, revitapi and revitapiui (especially after you already imported the Revit.DB namespace)

1 Like