Setting Compound Layer Function (Python Script)

python
clockwork

#1

I’m trying to put together a graph to set the function of layers in compound families (walls, roofs, floors, ceilings) and am stuck on the actual implementation of setting the function. I’ve shamelessly hacked up the FamilyType.SetCompoundLayerMaterial node from Clockwork and managed to restructure the node itself (woo!) and have managed to get the python to set the function IF I force it using MaterialFunctionAssignment.Substrate (or Finish1, Structure, etc.) However, that isn’t very useful long-term since the function might need to be something different depending on the family.

So - I’m obviously missing something in the Python code itself on how to allow the Layer Function to be an input and then executed based on the input but I’m stumped. Long term goal with this is to be able to filter everything by the material (i.e. 1/2" Metal Furring) and have all layers that have that material be set to a particular function (i.e. Substrate); however the application could easily go in a variety of other directions.

Stuff I’ve looked through that helped some:
http://www.revitapidocs.com/2018.1/1cbeb006-f7a2-f6d2-491f-faa0b9a006fc.htm

The overall graph (currently only worrying about the function, the Substrate text in the code block doesn’t do anything at the moment.)

The hacked-up node:

The even more hacked up Python:

The code itself:

#from FamilyType.SetCompountLayerWidth
#Clockwork Package
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
famtypes = UnwrapElement(IN[0])
indices = IN[1]
function = IN[2]
booleans = list()
counter = 0

TransactionManager.Instance.EnsureInTransaction(doc)
for ft in famtypes:
	try:
		cs = ft.GetCompoundStructure()
		cs.SetLayerFunction(indices[counter],MaterialFunctionAssignment.Substrate)
		ft.SetCompoundStructure(cs)
		booleans.append(True)
	except:
		booleans.append(False)
	counter += 1	
TransactionManager.Instance.TransactionTaskDone()

OUT = (famtypes,booleans)

TL;DR: How can I make the MaterialFunctionAssignment an input that will read a value (probably a string?), and pass it through the Python to modify the family?

:beers:


#2
import clr
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import MaterialFunctionAssignment

material_function_string = IN[0]

if material_function_string == '0':
    material_function = MaterialFunctionAssignment.Structure

OUT = material_function

#3

Thanks.
After stumbling around this for a while I’m a bit lost (my python knowledge is… limited); I’ll try and work on it a bit more today and come back with some actual questions rather than just stating I’m lost.

:beers:


#4

A couple questions/thoughts:

  1. What’s the benefit of using IF rather than TRY in this instance? I looked them up and it seems the main reason to use one or the other has to do with error handling, but I don’t quite have a full grasp on it.
  2. Does the IF nest inside of the TRY statement or is it a replacement? I’ve tried both but haven’t had much luck…
  3. The 0 in the if material_function_string == ‘0’ string corresponds to the 0 in the IN[0] statement correct? So if I have multiple inputs that could be a 2, as long as both of them are 2?
  4. The bigger issue I’m running into is your code still forces the assignment by using MaterialFunctionAssignment.Structure. In theory what I want to achieve is MaterialFunctionAssignment.(material_function_string), where the (material_function_string) could be Structure, or Substrate, or FInish1, etc.

In the attached version I fumbled through the Python (script from string) and at least managed to get it to not error, but the OUT on the node returns the name of the wall, rather than the function, which probably relates to item 3 above…

:beers:


Walls-Layers-Function.dyn (6.9 KB)
FamilyType.SetCompoundLayerFunction_chad.dyf (13.4 KB)


#5

1.The benefit of using ‘if’ is creating a conditional statement. We want to assign MaterialFunctionAssignment.Structure to material_function if the given string on the input is equal “0” (as a letter). You can change “0” to “structure” for example. Then you can add another if statement:

if material_function_string == 'structure':
    material_function = MaterialFunctionAssignment.Structure
if material_function_string == 'finish':
    material_function = MaterialFunctionAssignment.Finish1

2 - Both ‘if’ and ‘try’ can be nested inside each other but they have two different purposes. Please see Python documentation.

3 - No, it does not correspond. The IN[0] is assigned here:

material_function_string = IN[0]

Wherever you see ‘material_function_string’ you shoud read it as ‘IN[0]’. You only change value you feed to input.

4 - See point 2.


#6

Try:


#7

Regarding if/else vs. try/except: