Hello,
I’m working on a script to transform all room existing in a linked file to spaces for MEP use.
It will be helpfull, if somebody can point me to a such script or something like already done.
If not can someone help me by telling me the easiest way to achieve this script?
Thank you in advance
This sounds like a great script idea! Have you tried asking ChatGPT about it? If you do, just be sure to say “in python using the Revit API” to clue ChatGPT into what you’re working with. It usually has really good suggestions.
Thank you for the reply and Happy new year.
I tried some AI like GPT, Bard and Codeium. Thes answers are more or less the same, but they point me to wrong classes or methodes. here an example from Bard:
import clr
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *
# Get the current document and active view
doc = __revit__.ActiveUIDocument.Document
view = doc.ActiveView
# Get the linked model
linked_models = FilteredElementCollector(doc).OfClass(RevitLinkInstance).ToElements()
linked_model = linked_models[0] # Assuming you want to work with the first linked model
# Access elements in the linked model
link_doc = linked_model.GetLinkDocument()
# Get rooms from the linked model
rooms = FilteredElementCollector(link_doc).OfCategory(BuiltInCategory.OST_Rooms).WhereElementIsNotElementType().ToElements()
# Create corresponding spaces in the current document
for room in rooms:
# Map room properties to space properties as needed
space = Space.Create(doc, room.Location.Point, room.LevelId)
space.Name = room.Name
# ... Add more property mappings as needed ...
# Place the space in the same location as the room
space.Location = room.Location
# Add the space to the active view
view.AddElement(space)
But to be honest, it help me, in some way, to structure the workflow to realise the script.
A pretty simple script… just write some code.
Get the rooms with a FilteredElementCollector. Ignore rooms not placed (no area).
Iterate over the rooms and use the location point, phase and level to place spaces inside a transaction.
myspace = doc.Create.NewSpace(level, phase, new UV(locationPoint.X, locationPoint.Y))
You can refine the script by checking if there are already spaces so you don’t get duplicates in case this is a second run. And you might want to work with linked files if the rooms are coming from a separate linked Revit file.
Things to watch for are phasing and levels. If they match up - great. If not - you need to map levels and phases from file to file.
You also need to watch geometry translation from file to file if they don’t share the same file coordinate system (best to have that just in case.) Code below doesn’t catch all that, but is a start.
# -*- coding: utf-8 -*-
from pyrevit import revit, DB, forms
from Autodesk.Revit.DB import (
FilteredElementCollector,
BuiltInCategory,
BuiltInParameter,
RevitLinkInstance,
Transaction,
LocationPoint,
UV
)
from Autodesk.Revit.UI.Selection import ObjectType, ISelectionFilter
doc = revit.doc
uidoc = revit.uidoc
class RevitLinkSelectionFilter(ISelectionFilter):
def AllowElement(self, elem):
return isinstance(elem, RevitLinkInstance)
def AllowReference(self, ref, point):
return False
def get_param_value(elem, bip):
p = elem.get_Parameter(bip)
if p:
return p.AsString() or ""
return ""
def find_host_level_by_elevation(z, tolerance=0.5):
levels = (
FilteredElementCollector(doc)
.OfClass(DB.Level)
.WhereElementIsNotElementType()
.ToElements()
)
closest = None
closest_delta = None
for lvl in levels:
delta = abs(lvl.Elevation - z)
if closest is None or delta < closest_delta:
closest = lvl
closest_delta = delta
if closest and closest_delta <= tolerance:
return closest
return closest
# Select linked model
ref = uidoc.Selection.PickObject(
ObjectType.Element,
RevitLinkSelectionFilter(),
"Select linked model containing Rooms"
)
link_inst = doc.GetElement(ref.ElementId)
link_doc = link_inst.GetLinkDocument()
if not link_doc:
forms.alert("Could not access linked document.", exitscript=True)
link_transform = link_inst.GetTotalTransform()
rooms = (
FilteredElementCollector(link_doc)
.OfCategory(BuiltInCategory.OST_Rooms)
.WhereElementIsNotElementType()
.ToElements()
)
created = 0
skipped = []
t = Transaction(doc, "Create Spaces From Linked Rooms")
t.Start()
for room in rooms:
try:
if room.Area <= 0:
skipped.append("{} - no area".format(room.Id))
continue
loc = room.Location
if not isinstance(loc, LocationPoint):
skipped.append("{} - no location point".format(room.Id))
continue
# Transform linked room point into host coordinates
link_pt = loc.Point
host_pt = link_transform.OfPoint(link_pt)
host_level = find_host_level_by_elevation(host_pt.Z)
if not host_level:
skipped.append("{} - no matching host level".format(room.Id))
continue
space = doc.Create.NewSpace(host_level, UV(host_pt.X, host_pt.Y))
if not space:
skipped.append("{} - space not created".format(room.Id))
continue
# Copy Room Number
room_number = room.Number
try:
space.Number = room_number
except:
p = space.get_Parameter(BuiltInParameter.ROOM_NUMBER)
if p and not p.IsReadOnly:
p.Set(room_number)
# Copy Room Name
room_name = room.Name
try:
space.Name = room_name
except:
p = space.get_Parameter(BuiltInParameter.ROOM_NAME)
if p and not p.IsReadOnly:
p.Set(room_name)
created += 1
except Exception as ex:
skipped.append("{} - {}".format(room.Id, ex))
t.Commit()
forms.alert(
"Created {} spaces from linked rooms.\nSkipped {} rooms.".format(
created,
len(skipped)
),
title="Spaces From Linked Rooms"
)