Create Opening in Floor - Python 2 to Python 3 - Revit 2024

Hi everyone

I’m trying to get a script to create an opening on the top slab for an inspection pit. I took the python code from Spring nodes & upgraded it to Python 3 (.txt file attached) and it seems to run through, but it returns null as per the screenshot. (the current Spring nodes also returns null result)

I don’t quite understand how the python script works and not really sure where to go from here. Any pointers will be a great help :slight_smile:

Thanks

I’m using Revit 2024 & Dynamo 2.17

import clr

clr.AddReference("RevitAPI")
from Autodesk.Revit.DB import *

clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc =  DocumentManager.Instance.CurrentDBDocument

clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)

def tolist(obj1):
       if hasattr(obj1,"__iter__"): return obj1
       else: return [obj1]

flr = UnwrapElement(tolist(IN[0]) )
hole = UnwrapElement(IN[1])

openings = []
newhl = []

if not any(hasattr(h,"__iter__") for h in hole):
       hole = [hole]
TransactionManager.Instance.EnsureInTransaction(doc)
for i in range(len(hole)):
       z = CurveArray()
       [z.Append(j.ToRevitType()) for j in hole[i] ]
       newhl.append(z)
if len(flr) == 1 :
       for i in range(len(newhl)):
               try:
                       x = doc.Create.NewOpening(flr[0],newhl[i],True)
                       openings.append(x.ToDSType(False))
               except:
                       openings.append(None)
else:
       for f, h in zip(flr, newhl):
               try:
                       x = doc.Create.NewOpening(f,h,True)
                       openings.append(x.ToDSType(False))
               except:
                       openings.append(None)
TransactionManager.Instance.TransactionTaskDone()
OUT = openings

Hi

I did a bit of research and followed @GavinCrump youtube tutorial at Floors/Ceilings with holes in Revit (2022) using Dynamo! - YouTube

I’ve adapted the python script as per below but the Floor.Create function seems to read only the outer curveloop and not creating the inner hole.

I’ve posted my revit file and .dyn here for reference.

# Free for use
# BIM Guru, www.bimguru.com.au

# Boilerplate text
import clr

clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)

clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager 
from RevitServices.Transactions import TransactionManager 

clr.AddReference("RevitAPI")

import Autodesk 
from Autodesk.Revit.DB import *

# Current doc/app/ui
doc = DocumentManager.Instance.CurrentDBDocument

# Define list/unwrap list functions
def uwlist(input):
    result = input if isinstance(input, list) else [input]
    return UnwrapElement(result)

# Preparing input from dynamo to revit
curve = IN[0]
type  = uwlist(IN[1])
level = uwlist(IN[2])

slab_list = []

# Do some action in a Transaction
TransactionManager.Instance.EnsureInTransaction(doc)
for c,t,l in zip(curve,type,level):
    curve_loop_list = []
    curve_set_list = []
    for curve_set in c:
        curve_set_list.append(curve_set.ToRevitType())
    curve_loop = CurveLoop.Create(curve_set_list)
    curve_loop_list.append(curve_loop) 
    slab = Floor.Create(doc, curve_loop_list, t.Id, l.Id) 
    slab_list.append(slab)    

TransactionManager.Instance.TransactionTaskDone()

# Preparing output to Dynamo
OUT = slab_list

Developer 4.rvt (7.5 MB)
Pit.R1.dyn (103.7 KB)

Good morning,
here is an approach working under revit 2023
coding can be improved
I added doc.Regenerate() (I had read that it needed it at times in one of the topics)
and System.Collection.Generic


image
code

Script Python
import sys
import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *

clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *

clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

import System
from System.Collections.Generic import List

clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)

doc = DocumentManager.Instance.CurrentDBDocument

# Inputs
curv=(IN[0])
Lvl_Id=UnwrapElement(IN[1]).Id
Floor_Type_Id=UnwrapElement(IN[2]).Id

curv_l,curv_int=CurveLoop(),CurveLoop()
for i in curv[0]:
    curv_l.Append(i.ToRevitType())
for i in curv[1]:
    curv_int.Append(i.ToRevitType())
TransactionManager.Instance.EnsureInTransaction(doc)
flr=Floor.Create(doc,List[CurveLoop]([curv_l,curv_int]), Floor_Type_Id, Lvl_Id)
doc.Regenerate()
TransactionManager.Instance.TransactionTaskDone()
# Affectez la sortie à la variable OUT.
OUT = flr,{"lines out":curv[0],"lines in":curv[1]}

Cordially
christian.stan

4 Likes

Yup, imported this and it’s working on Revit 2024 too.

My node expects IN[0] to be in the form of a list of lists of curves, as it works for multiple floors.

hi, I also got it to work with the following script below

If you don’t mind this is my current understanding of what the script is doing. Is it right?
I’d keep the list structure, but let’s say if I don’t really need it to work for multiple floors (e.g. civil infra jobs), can I flatten the list by 1 level and skip say step (b) in the script?

# Boilerplate text
import clr

clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)

clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager 
from RevitServices.Transactions import TransactionManager 

clr.AddReference("RevitAPI")

import Autodesk 
from Autodesk.Revit.DB import *

# Current doc/app/ui
doc = DocumentManager.Instance.CurrentDBDocument

# Define list/unwrap list functions
def uwlist(input):
    result = input if isinstance(input, list) else [input]
    return UnwrapElement(result)

# Preparing input from dynamo to revit
curve = IN[0]
type  = uwlist(IN[1])
level = uwlist(IN[2])

output_list = []

# Do some action in a Transaction
TransactionManager.Instance.EnsureInTransaction(doc)
for curve_L3,t,l in zip(curve,type,level):
    curve_loop_list = []
    for curve_L2 in curve_L3:
        curve_set = []
        for curve_L1 in curve_L2:
            curve_set.append(curve_L1.ToRevitType())
        curve_loop = CurveLoop.Create(curve_set)
        curve_loop_list.append(curve_loop) 
    output = Floor.Create(doc, curve_loop_list, t.Id, l.Id) 
    output_list.append(output)    

TransactionManager.Instance.TransactionTaskDone()

# Preparing output to Dynamo
OUT = output_list

Python requires a predictable depth of input to iterate properly. Because a floor can have multiple curve loops I have built my script to only work if the list structure is a list of lists of curves. You could adjust the Python to work with a list of curves if you wanted to, but it would be limited to floors with only one curveloop being accepted by the node.

Commentary added below to explain what it is doing…

# for each list, type and level in IN[0],IN[1] and IN[2]...
for curve_L3,t,l in zip(curve,type,level):
	# Make an empty list to store curveloops into...
	curve_loop_list = []
	# For each list of curves in the list...
	for curve_L2 in curve_L3:
		# Begin a list to turn into a curve loop...
		curve_set = []
		# For each curve in the list of curves...
		for curve_L1 in curve_L2:
			# Append its RevitType (Dynamo > Revit element) to the curve set
			curve_set.append(curve_L1.ToRevitType())
		# Turn the curve set/list into a new curveloop
		curve_loop = CurveLoop.Create(curve_set)
		# Append that curve loop to the curve loop list
		curve_loop_list.append(curve_loop) 
	# Using the curve loop list, create a floor using those curve loops
	output = Floor.Create(doc, curve_loop_list, t.Id, l.Id) 
	# Append it to the output for the script
	output_list.append(output)
	# Keep looping for each floor to be created...
3 Likes