Python floor.create() with revit api 2022

Hi All,

i’m trying to create a floor within my python script using:

Floor.Create(doc,CurveArray, ‘Placa Maciza E=15cm’, level,True,0,0)

Can someone tell me the new process for use correct, new commmands FLOOR.CREATE with new revit api 2022.

this the code:

#importar revit api
import clr
clr.AddReference(‘ProtoGeometry’)
from Autodesk.DesignScript.Geometry import *

from math import *

import clr
clr.AddReference(“RevitNodes”)
import Revit
clr.ImportExtensions(Revit.Elements)
clr.AddReference(“RevitServices”)

import RevitServices
from RevitServices.Persistence import *
from RevitServices.Transactions import *

doc = DocumentManager.Instance.CurrentDBDocument

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

#importar excel
import os

localapp = os.getenv(r’LOCALAPPDATA’)

sys.path.append(os.path.join(localapp, r’python-3.8.3-embed-amd64\Lib\site-packages’))

#DECLARACIÓN VARIABLES IMPORTAR EXCEL

import openpyxl
from openpyxl import *

book=load_workbook(r’D:\PINITOS.xlsx’)
sheet=book[“REVIT”]

#sheet=book.active
#a1=sheet[“B1”].value
#a2=sheet[“B2”].value

def conversion(x):
uid = UnitTypeId.Feet
uid2 = UnitTypeId.Meters
return UnitUtils.Convert(x,uid2,uid)

row_count = sheet.max_row
#column_count = sheet.max_column

x_1=
for col in range(row_count):
x_1.append(sheet.cell(col+1, 2).value)

y_1=
for col in range(row_count):
y_1.append(sheet.cell(col+1, 3).value)

level = UnwrapElement(IN[0]).Id

#dibujo de placas

#niveles = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Levels).WhereElementIsNotElementType().ToElements()
slabs = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Floors).WhereElementIsElementType().ToElements()

for slab in slabs:
name = slab.get_Parameter(BuiltInParameter.SYMBOL_NAME_PARAM).AsString()
if name == ‘Placa Maciza E=15cm’:
floorType = slab

muros =

TransactionManager.Instance.EnsureInTransaction(doc)

for col in range(row_count):
try:
a=x_1[col]
a=conversion(a)
b=y_1[col]
b=conversion(b)
c=x_1[col+1]
c=conversion(c)
d=y_1[col+1]
d=conversion(d)
linea = Line.CreateBound(XYZ(a,b,0),XYZ(c,d,0))
curveArray = CurveLoop.Create(linea)
loop=[curveArray]
except IndexError:
c=x_1[col]
c=conversion(c)
d=y_1[col]
d=conversion(d)
e=x_1[0]
e=conversion(e)
f=y_1[0]
f=conversion(f)
linea = Line.CreateBound(XYZ(c,d,0),XYZ(e,f,0))
curveArray.Append(linea)
curveArray = CurveLoop.Create(linea)
loop=[curveArray]
muro = Wall.Create(doc, linea, level, True)
muros.append(muro)

slab_new = Floor.Create(doc,loop, ‘Placa Maciza E=15cm’, level,True,0,0)
offset = slab_new.get_Parameter(BuiltInParameter.FLOOR_HEIGHTABOVELEVEL_PARAM)
offset.Set(0)

TransactionManager.Instance.TransactionTaskDone()

OUT=doc

Thanks, DAVID CAMILO.

1 Like

You need to pass a floor type element, not just use the string name of the floor type.

1 Like

Looks like Sean found the issue, but I’ve got a video as well which runs through in Python how to use this method correctly if it helps too:

I ended up using it to make a node in my package (Crumple) as well called ‘FloorsByCurveloops’.

I’ve pasted its code below for reference:

# Made by Gavin Crump
# 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)

def listpad(lst,count):
	padded = []
	length = len(lst)
	for i in range(0,count):
		if i < length:
			padded.append(lst[i])
		else:
			padded.append(lst[-1])
	return padded

# Preparing input from dynamo to revit
roomset = IN[0]
maxlst = len(roomset)

types  = listpad(uwlist(IN[1]),maxlst)
levels = listpad(uwlist(IN[2]),maxlst)

floors = []

TransactionManager.Instance.EnsureInTransaction(doc)

for rm,f,l in zip(roomset,types,levels):
	curveloops = []
	for crv_setd in rm:
		crv_setr = []
		for crv_d in crv_setd:
			crv_setr.append(crv_d.ToRevitType())
		curveloop = CurveLoop.Create(crv_setr)
		curveloops.append(curveloop)
	flr = Floor.Create(doc, curveloops, f.Id, l.Id)
	floors.append(flr)

TransactionManager.Instance.TransactionTaskDone()

# Preparing output to Dynamo
OUT = floors

As the naming implies, I typically use it to deal with room finish boundaries, and the node requires curves to be in closed sets, so it’s a list of list of lists in structure. I use the ‘listpad’ function primarily to simulate a longest lacing technique for the remaining inputs as I found ziplongest from itertools wasn’t working typically.

2 Likes

thanks a lot

1 Like

Hi there! I am troubled with a similar issue in pyRevit. Here’s my script for creating a simple new Revit triangular Floor starting from three vertices. I am currently using Revit 2023.

When I run my code, I get the error message “ArgumentException : The input curve loops cannot compose a valid boundary, that means: the “curveLoops” collection is empty; or some curve loops intersect with each other; or each curve loop is not closed individually; or each curve loop is not planar; or each curve loop is not in a plane parallel to the horizontal(XY) plane; or input curves contain at least one helical curve. Parameter name: profile at Autodesk.Revit.DB.Floor.Create(Document document, IList`1 profile, ElementId floorTypeId, ElementId levelId)”. Upon further inspection, I have checked the CurveLoop() and everything seems to be in order (it’s planar, closed, and counterclockwise).

I would greatly appreciate any help in resolving this issue.

#! python3

#----------------------------------------------------------------------------------------------
# IMPORT LIBRARIES
#  System library
import sys

#  Autodesk Revit API
import clr
clr.AddReference('RevitAPI')
clr.AddReference('RevitAPIUI')
from Autodesk.Revit.DB import Transaction
from Autodesk.Revit.UI import TaskDialog
from Autodesk.Revit.DB import *
from Autodesk.Revit.DB import XYZ, UV, Line, CurveLoop, Level, Floor, FloorType
from System.Collections.Generic import List

# Function to convert centimeters to feet
def centimeters_to_feet(centimeters):
    return centimeters * 0.0328084

doc = __revit__.ActiveUIDocument.Document

# Coordinates
a = 0.0
b = 10.0
c = 0.0

# Input elevation (in centimeters)
elevation_cm = c
elevation_ft = centimeters_to_feet(elevation_cm)

# Create a new level at the given elevation
new_level = None

# Start a new transaction to modify the Revit document creating a new level
transaction = Transaction(doc, 'Create New Level')
transaction.Start()

try:
    new_level = Level.Create(doc, elevation_ft)
    
    # Assign a new name to the level
    new_level_name = "elBS_BuildingStorey_{:.0f}cm".format(elevation_cm)
    new_level.Name = new_level_name

    transaction.Commit()
except Exception as e:
    # If an error occurs, roll back the transaction and show an error message
    transaction.RollBack()
    TaskDialog.Show('Error', 'Failed to create level. Error: {}'.format(e))

if new_level:
    TaskDialog.Show('Success', 'Level created at elevation: {} centimeters'.format(elevation_cm))

# Create new floor

point0 = XYZ(a, a, c)
point1 = XYZ(b, a, c)
point2 = XYZ(b, b, c)

line01 = Line.CreateBound(point0,point1).ToRevitType()
line12= Line.CreateBound(point1,point2).ToRevitType()
line23 = Line.CreateBound(point2,point0).ToRevitType()

curveloop = CurveLoop()

curveloop.Append(line01)
curveloop.Append(line12)
curveloop.Append(line23)

print("numberOfcurves: ",curveloop.NumberOfCurves())
print("IsOpen: ",curveloop.IsOpen())
print("HasPlane: ",curveloop.HasPlane())


# Collect floor types
floortypes = FilteredElementCollector(doc).OfClass(FloorType)
floortypes = [f for f in floortypes]
floortypes_id = [f.Id for f in floortypes]
floortype_id = floortypes_id[0]
print("floortype id:",floortype_id)

# Collect building storeys
el_BuildingStoreys = FilteredElementCollector(doc).OfClass(Level)
el_BuildingStoreys_id = []
for el in el_BuildingStoreys:
    el_BuildingStoreys_id.append(el.Id)
level_id = el_BuildingStoreys_id[0]
print("level id: ",level_id)

# Start transaction
t = Transaction(doc, "Create new floor")
t.Start()

# Create the floor
new_floor = Floor.Create(doc, List[CurveLoop](curveloop), floortype_id, new_level.Id)
t.Commit()

Not sure if it matters, but try removing the .ToRevitType() in the lines where you create the curves.

Sorry, with ToRevitType() the code returns a different error. Without it, it returns the error reported in my previous message.

Hello, I feel like you miss him
import System

edit: with additions and change to your code ended up working:

#! python3

#----------------------------------------------------------------------------------------------
# IMPORT LIBRARIES
#  System library
import sys
import System
#  Autodesk Revit API
import clr
clr.AddReference('RevitAPI')
clr.AddReference('RevitAPIUI')
from Autodesk.Revit.DB import Transaction
from Autodesk.Revit.UI import TaskDialog
from Autodesk.Revit.DB import *
from Autodesk.Revit.DB import XYZ, UV, Line, CurveLoop, Level, Floor, FloorType
from System.Collections.Generic import List
clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

# Function to convert centimeters to feet
def centimeters_to_feet(centimeters):
    return centimeters * 0.0328084

doc = DocumentManager.Instance.CurrentDBDocument

# Coordinates
a = 0.0
b = 10.0
c = 0.0

# Input elevation (in centimeters)
elevation_cm = c
elevation_ft = centimeters_to_feet(elevation_cm)

# Create a new level at the given elevation
new_level = None

# Start a new transaction to modify the Revit document creating a new level
transaction = Transaction(doc, 'Create New Level')
transaction.Start()

try:
    new_level = Level.Create(doc, elevation_ft)
    
    # Assign a new name to the level
    new_level_name = "elBS_BuildingStorey_{:.0f}cm".format(elevation_cm)
    new_level.Name = new_level_name

    transaction.Commit()
except Exception as e:
    # If an error occurs, roll back the transaction and show an error message
    transaction.RollBack()
    TaskDialog.Show('Error', 'Failed to create level. Error: {}'.format(e))

if new_level:
    TaskDialog.Show('Success', 'Level created at elevation: {} centimeters'.format(elevation_cm))

# Create new floor

point0 = XYZ(a, a, c)
point1 = XYZ(b, a, c)
point2 = XYZ(b, b, c)

line01 = Line.CreateBound(point0,point1)
line12= Line.CreateBound(point1,point2)
line23 = Line.CreateBound(point2,point0)


curv=CurveLoop()
curv.Append(line01)
curv.Append(line12)
curv.Append(line23)

print("numberOfcurves: ",curv.NumberOfCurves())
print("IsOpen: ",curv.IsOpen())
print("HasPlane: ",curv.HasPlane())
print("type: ",type(curv))


# Collect floor types
floortypes = FilteredElementCollector(doc).OfClass(FloorType)
floortypes = [f for f in floortypes]
floortypes_id = [f.Id for f in floortypes]
floortype_id = floortypes_id[0]
print("floortype id:",floortype_id)

# Collect building storeys
el_BuildingStoreys = FilteredElementCollector(doc).OfClass(Level)
el_BuildingStoreys_id = []
for el in el_BuildingStoreys:
    el_BuildingStoreys_id.append(el.Id)
level_id = el_BuildingStoreys_id[0]
print("level id: ",level_id)

# Start transaction
t = Transaction(doc, "Create new floor")
t.Start()

# Create the floor
new_floor = Floor.Create(doc,List[CurveLoop]([curv]), floortype_id, new_level.Id)
t.Commit()

cordially
christian.stan

1 Like

Thank you very much for the code! In my case, I noticed that it only runs with IronPython by removing the first #! python3 line. However, I need to run it with the CPython interpreter in order to work with the numpy library in Revit-Python, so the issue is still open.

2 Likes

I got there with this engine, but as I’m a beginner it’s not what you’re probably talking about.

I thought the # canceled the rest of the command line

Cordially
christian.stan

1 Like

I am also new to the topic. I think that when working in pyRevit the ‘#! python3’ line serves for running the code with CPython and not with IronPython, but I’m not sure. I’ll wait for a reply from an expert. Thanks again a lot! :slight_smile:

1 Like

The engine selector in Dynamo being set to CPython3 is the equivalent of the PyRevit comment #!python3 at the start of your code.

If the issue persists it may be best to take this to the PyRevit forum as the Python posted by @christian.stan certainly works in CPython3 (thereby giving access to numpy and the rest if you’ve configured your environment for such).

3 Likes

Read this and laugh out loud…

@christian.stan you’re selling yourself very short here! You are well past that - I’d go so far as to say expert level, and by all means an awesome member of the community!

3 Likes

hello, thanks for the compliment always had the soul of a technician rather than commercial.
I will decide on advanced beginner :wink:
Cordially
christian.stan

Got! Many thanks for your reply.

1 Like

Hi @christian.stan! Can I ask you what python version are you using?

Hello, no worries, nothing secret Cpython3, I only have this default engine installed
But I want to install IronPython3 soon (Mr. Poupin is testing it extensively and across)
cordially
christian.stan