Trying to create wall by levels using python

I am learning python can anyone say whats is the problem in this script

import clr
clr.AddReference(“RevitNodes”)
import Revit
clr.ImportExtensions(Revit.Elements)
clr.AddReference(“RevitServices”)
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
clr.AddReference(‘RevitAPI’)
from Autodesk.Revit.DB import *
doc = DocumentManager.Instance.CurrentDBDocument
baseLevel = UnwrapElement(IN[0])
topLevel = UnwrapElement(IN[1])
wallType = UnwrapElement(IN[2])
pt1 = XYZ(0, 0, 0)
pt2 = XYZ(10, 0, 0)
TransactionManager.Instance.EnsureInTransaction(doc)
line = Line.CreateBound(pt1, pt2)
wall = Wall.Create(doc, line, baseLevel.Id, False)
wall.WallType = wallType
topConstraint = wall.get_Parameter(BuiltInParameter.WALL_HEIGHT_TYPE)
topConstraint.Set(topLevel.Id)
TransactionManager.Instance.TransactionTaskDone()
OUT = wall

Hey,

This works for me… There were things that were right and a few things to change, I would look at the Clockwork and Archi-lab nodes to see how they are working.

Hope that helps,

Mark

P.S. when pasting code, please use image to format it

#thanks to clockwork and Archi-lab

import clr
clr.AddReference('RevitNodes')

import Revit
clr.ImportExtensions(Revit.Elements)
clr.AddReference('RevitServices')

import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

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


doc = DocumentManager.Instance.CurrentDBDocument

baseLevel = UnwrapElement(IN[0])
topLevel = UnwrapElement(IN[1])
wallType = UnwrapElement(IN[2])

pt1 = XYZ(0, 0, 0)
pt2 = XYZ(10, 0, 0)

TransactionManager.Instance.EnsureInTransaction(doc)

line = Line.CreateBound(pt1, pt2)
wall = Wall.Create(doc, line, baseLevel.Id, False)

#we need to get an id from the type to use in setting the type, this must be an integer, to make an integer we need to convert the id to a string first
typeId = int(str(wallType.Id))

#change type, this needs an element id which is defined by the typeid
wall.ChangeTypeId(ElementId(typeId))


#to isolate the built in parameter we want, we first get all of them, then add the one which matches the name to our list.
builtInParams = System.Enum.GetValues(BuiltInParameter)
for i in builtInParams:
	if i.ToString() == 'WALL_HEIGHT_TYPE':
		bip = i
	else:
		continue
		
#as above we need an id from the top constraint to set the parameter value
topLevelId = int(str(topLevel.Id))

#we first get the wall parameter then we set it 
wall.get_Parameter(bip).Set(ElementId(topLevelId))


TransactionManager.Instance.TransactionTaskDone()

OUT = wall,
1 Like

Hi @Mark.Ackerley,
Good to see you again. The code you posted here has been helpful to experiment with. Thank you. As for my current stumbling block - I’m trying to create levels without inputting them into the node in dynamo. Ie -
topLevelId = int(str(baseLevel.Id)) + 1

Can i call out the next level without having to input the level from the node? First - I’ve pasted your code as I’m altering.

Then see further below for a version of my code I am trying to get to work. I guess I don’t really understand the builtInParams part of your code.
Thanks again for your time.

#thanks to clockwork and Archi-lab

import clr
clr.AddReference('RevitNodes')

import Revit
clr.ImportExtensions(Revit.Elements)
clr.AddReference('RevitServices')

import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

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


doc = DocumentManager.Instance.CurrentDBDocument

baseLevel = UnwrapElement(IN[0])
#topLevel = UnwrapElement(IN[1])
wallType = UnwrapElement(IN[2])

pt1 = XYZ(0, 0, 0)
pt2 = XYZ(10, 0, 0)

TransactionManager.Instance.EnsureInTransaction(doc)

line = Line.CreateBound(pt1, pt2)
wall = Wall.Create(doc, line, baseLevel.Id, False)

#we need to get an id from the type to use in setting the type, this must be an integer, to make an integer we need to convert the id to a string first
typeId = int(str(wallType.Id))

#change type, this needs an element id which is defined by the typeid
wall.ChangeTypeId(ElementId(typeId))


#to isolate the built in parameter we want, we first get all of them, then add the one which matches the name to our list.
builtInParams = System.Enum.GetValues(BuiltInParameter)
for i in builtInParams:
	if i.ToString() == 'WALL_HEIGHT_TYPE':
		bip = i
	else:
		continue
		
#as above we need an id from the top constraint to set the parameter value
topLevelId = int(str(baseLevel.Id)) + 1

#we first get the wall parameter then we set it 
wall.get_Parameter(bip).Set(ElementId(topLevelId))


TransactionManager.Instance.TransactionTaskDone()

OUT = wall

This is my code I’m trying to manipulate:

import clr
clr.AddReference('RevitNodes')

import Revit
clr.ImportExtensions(Revit.Elements)
clr.AddReference('RevitServices')

import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

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


doc = DocumentManager.Instance.CurrentDBDocument

baseLevel = UnwrapElement(IN[0])

pt1 = XYZ(0,0,0)
pt2 = XYZ(IN[2],0,0)
pt3 = XYZ(IN[2],IN[1],0)
pt4 = XYZ(0,IN[1],0)

wallType = UnwrapElement(IN[3])

pts = [pt1, pt2, pt3, pt4]
walls = []

levelOut = int(str(baseLevel.Id)) + 1

TransactionManager.Instance.EnsureInTransaction(doc)

for n, pt in enumerate(pts):
	try:
		wall_line = Line.CreateBound(pt, pts[n+1])
	except IndexError:
		wall_line = Line.CreateBound(pt, pts[0])
	wall = Wall.Create(doc, wall_line, baseLevel.Id, False).ToDSType(False)
#	wall = Wall.Create(doc, wall_line, wallType.Id, baseLevel.Id, 10.0, 1.2, False, False).ToDSType(False)
	wall.get_Parameter.WALL_HEIGHT_TYPE.Set(ElementId(levelOut))

	walls.append(wall)

TransactionManager.Instance.TransactionTaskDone()

OUT = walls, baseLevel.Id, levelOut

the error I get is: AttributeError: ‘Wall’ object has no attribute ‘get_Parameter’

Hey,

Apologies, I’m on holiday :slight_smile: just a couple of thoughts…

The BIP part… we need the to set the parameter, to set it we need it’s ID… so we get every BIP and filter to get only the one we want…

I suspect that you might do the same with levels… use filtered element collector… (sort them by elevation?) get the level which matches the IN[0] name… then get the next index on…?

@Daniel_Woodcock1 has great stuff on his website that might get you going? Maybe @kennyb6 has some time?

Apologies,

Mark

2 Likes

Just from a quick glance, the error is because wall.get_Parameter is a method, not a property. The difference is that methods are functions that require parentheses to call them while properties are just a property of the class and don’t need parentheses.

Basically, you didn’t use parentheses with your function. Also the call for WALL_HEIGHT_TYPE was wrong. Maybe try wall.get_Parameter(BuiltInParameter.WALL_HEIGHT_TYPE).Set(ElementId(levelOut))

Also important, you are turning the wall you just created into a Dynamo wrapped element before you try to call API functions onto it, which isn’t allowed. Take out the .ToDSType(False) until after you are done modifying it.
See more here: https://github.com/DynamoDS/Dynamo/wiki/Python-0.6.3-to-0.7.x-Migration in the section Unwrapping and Wrapping.

Edit: Fixed the caps on WALL_HEIGHT_TYPE.

3 Likes

@Mark.Ackerley thanks for the referral. @kennyb6, Thank you for your time and looking over my code. You were right on the parentheses. I no longer get an error, but the wall is not extending to the 3rd floor.
See below for my code now. I’ll keep messing with it.

import clr
clr.AddReference('RevitNodes')

import Revit
clr.ImportExtensions(Revit.Elements)
clr.AddReference('RevitServices')

import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

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

doc = DocumentManager.Instance.CurrentDBDocument

baseLevel = UnwrapElement(IN[0])

pt1 = XYZ(0,0,0)
pt2 = XYZ(IN[2],0,0)
pt3 = XYZ(IN[2],IN[1],0)
pt4 = XYZ(0,IN[1],0)

wallType = UnwrapElement(IN[3])

pts = [pt1, pt2, pt3, pt4]
wallList = []

levelOut = int(str(baseLevel.Id)) + 3

TransactionManager.Instance.EnsureInTransaction(doc)

for n, pt in enumerate(pts):
	try:
		wall_line = Line.CreateBound(pt, pts[n+1])
	except IndexError:
		wall_line = Line.CreateBound(pt, pts[0])
	wall = Wall.Create(doc, wall_line, baseLevel.Id, False)

#	wall = Wall.Create(doc, wall_line, wallType.Id, baseLevel.Id, 10.0, 1.2, False, False).ToDSType(False)
	wall.get_Parameter(BuiltInParameter.WALL_HEIGHT_TYPE).Set(ElementId(levelOut))

#.ToDSType(False)

	wallList.append(wall)

TransactionManager.Instance.TransactionTaskDone()

OUT = wallList, baseLevel.Id, levelOut

That’s good that the error is gone. If there are no more errors on it, but it still isn’t doing what you expect, then this is where testing each input starts. Check the ElementId(levelOut).Name and see if it is the right level.

If you are just trying to make it go to the next level above whatever the input is, what I have done before is sort the levels by elevation and take the index + 1 to find the next. This is an old python section I wrote:

elevations = [x.Elevation for x in levels]
sorts = [y for x,y in sorted(zip(elevations, levels))]

nextlevel = sorts[sorts.index(elemLevel)+1]

where levels is the input of all levels from Dynamo and elemLevel is the current level of the element. Keep in mind that all of the levels are still wrapped so if you are trying to compare it to an element you are making using API, you might need to UnwrapElement(sorts) first.

1 Like

Thanks @kennyb6 - I’m working through it but did not solve the issue.

I attempted:
OUT = ElementId(levelOut).Name
but i received an error - AttributeError: ‘ElementId’ object has no attribute ‘Name’
I also tried to set to a variable and then OUT = variable

What is a good reference for methods & classes available to call? ie - the call you are advising:
ElementId(variable).classVariable
(if I am understanding the syntax correctly.)
I’m referencing - http://www.revitapidocs.com
I am trying to understand the properties accessible to Levels - http://www.revitapidocs.com/2016/1c606456-b458-803d-15bc-23052a50e859.htm - ElementId(levelOut).Name seems to make sense per api docs.

http://www.revitapidocs.com/2016/0ce4c555-4cee-f5fd-2e84-43cacf34ac5c.htm - helped creating the height of the wall - unconnected to a floor.

I’m also looking at Clockwork & Archi-lab nodes - a lot to wade through.

Thank you. I am trying to get to the point where I can control most needs through python as opposed to dyanmo. My next hurdle is placing doors and windows. (I know this is getting off the thread topic, but I am searching for resources so I can figure more out on my own.)

Thanks!

Sorry, what I wrote was wrong. Right now, your levelOut is an elementid representing a level, not a level. You will need to get the element using the elementid for .Name to work. You can do that using the Document class method GetElement()

Try doc.GetElement(levelOut).Name

1 Like

Hi, I’m working with the script you shared, and I want to create walls that belong to the base level and top level. how can i solve this?
With the current script, a wall with a height of 4,000 mm is simply created with only the base level recognized…

#thanks to clockwork and Archi-lab

import clr
clr.AddReference('RevitNodes')

import Revit
clr.ImportExtensions(Revit.Elements)
clr.AddReference('RevitServices')

import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

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


doc = DocumentManager.Instance.CurrentDBDocument

baseLevel = UnwrapElement(IN[0])
topLevel = UnwrapElement(IN[1])
wallType = UnwrapElement(IN[2])

pt1 = XYZ(0, 0, 0)
pt2 = XYZ(10, 0, 0)

TransactionManager.Instance.EnsureInTransaction(doc)

line = Line.CreateBound(pt1, pt2)
wall = Wall.Create(doc, line, baseLevel.Id, False)

#we need to get an id from the type to use in setting the type, this must be an integer, to make an integer we need to convert the id to a string first
typeId = int(str(wallType.Id))

#change type, this needs an element id which is defined by the typeid
wall.ChangeTypeId(ElementId(typeId))


#to isolate the built in parameter we want, we first get all of them, then add the one which matches the name to our list.
builtInParams = System.Enum.GetValues(BuiltInParameter)
for i in builtInParams:
	if i.ToString() == 'WALL_HEIGHT_TYPE':
		bip = i
	else:
		continue
		
#as above we need an id from the top constraint to set the parameter value
topLevelId = int(str(topLevel.Id))

#we first get the wall parameter then we set it 
wall.get_Parameter(bip).Set(ElementId(topLevelId))


TransactionManager.Instance.TransactionTaskDone()

OUT = wall,

Hey,

So there were 2 things failing for me when I re-ran the code.

The first was that when I iterated through System.Enum.GetValues(BuiltInParameter) I was getting the integer values. Even though if I OUT it, it returns the text values (WALL_HEIGHT_TYPE etc.). So I have had to work out which integer responded to the BIP.

Secondly, there is a known bug with ChangeTypeID…

The suggested workaround failed for me, so I used the Dynamo method instead.

Hope that helps,

Mark

#thanks to clockwork and Archi-lab

import clr
clr.AddReference('RevitNodes')

import Revit
clr.ImportExtensions(Revit.Elements)
clr.AddReference('RevitServices')

import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

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

clr.ImportExtensions(Revit.Elements)


doc = DocumentManager.Instance.CurrentDBDocument

baseLevel = UnwrapElement(IN[0])
topLevel = UnwrapElement(IN[1])
wallType = IN[2] #no need to unwrap as we are going to use Dynamo methods

pt1 = XYZ(0, 0, 0)
pt2 = XYZ(10, 0, 0)

TransactionManager.Instance.EnsureInTransaction(doc)

line = Line.CreateBound(pt1, pt2)
wall = Wall.Create(doc, line, baseLevel.Id, False)

#to isolate the built in parameter we want, we first get all of them, then add the one which matches the name to our list.
builtInParams = System.Enum.GetValues(BuiltInParameter)

#when we iterate through the BuiltInParameter enum, it is returning integers not the name, which is a change from previously
# I have worked out the integer for WALL_HEIGHT_TYPE and added it, i believe this will be static.
for s in builtInParams :
    if s == -1001103:
        bip = s

#as above we need an id from the top constraint to set the parameter value
topLevelId = int(str(topLevel.Id))

#we first get the wall parameter then we set it 
wall.get_Parameter(bip).Set(ElementId(topLevelId))

#change type, this needs an element id which is defined by the typeid
#there is seemingly a known bug using CPython3 where this method does not work
#wall.ChangeTypeId(ElementId(typeId))

#instead I am wrapping and using a Dynamo method to set the type
wallDS = wall.ToDSType(True)
wallDS.SetParameterByName('Type', wallType)

TransactionManager.Instance.TransactionTaskDone()

OUT = wallDS