Create Material

I’m trying to make a “create Materials” custom node, based on this thread

I’ve got two problems:
First is that I’m trying to set other properties of the Material (Surface… and CutPatternColor), but I’m not getting an error code or a result.
All I’ve done is added the bold lines. But nothing happens differently than without them.

new_mat_id = Material.Create(doc, mat_name)
new_mat = doc.GetElement(new_mat_id)
new_mat.Color = ToRevitColor(color)
new_mat.SurfacePatternColor = ToRevitColor(color)
new_mat.CutPatternColor = ToRevitColor(color)
new_mat.Transparency = transparency
newMaterials.append(ToDynamoObject(new_mat))

Second issue is that I’d like to make this a node that accepts a single input, and can be run in different locations in my graph. But when I run it a second time, it overwrites the material created from the first run.

Forgot to mention: I’ve tried this in both Revit 2017 and 2018.2, as I understand more of the Materials API has been exposed.
But the same results on both versions

Can you copy and paste the full Python code here (as preformatted text)?

Typically rerunning a graph with new inputs will “undo” the actions of running the graph the previous time, but it could depend on how your graph is set up so a screenshot of your graph will provide more insight.

3 Likes

I think you (and the community) may actually be best served by uploading the full dyn here - in addition to the screenshot and the formatted Python code. There are a few dozen possible issues here, we don’t have anything good to troubleshoot as there isn’t an error, and you’re at the cutting edge of the software as you’re looking to use aspects of the API which have only just been exposed so there aren’t as many examples (functioning and incorrect) to reference here.

3 Likes

Here’s a stripped down version of what I’m trying to do.
Create RGB Materials2.dyn (9.6 KB)

I didn’t upload the entire graph before because there’s a lot of other unrelated stuff.
This piece just has you enter three values, R, G, & B.
Then it builds a string out of those for the Material name, and uses a Python script to create the material.
The Python code came pretty much from the thread I linked above
If I put a Watch on the Material created, I see it is getting a new Element ID the second time I run it, but the one created o the first run is removed.

OK, weird. It seems to be creating materials properly and not deleting the previous ones. I’m not sure why.
So, back to my original question.
I’m getting the Material (Shading) Color set, but the Surface Pattern and the Cut Pattern are not.
Those are the two lines in BOLD in the snip at top

1 Like

Did you create a new instance of the Python node, or have you been closing and reopening Dynamo between runs? Those are the only likely explanations for it to be working properly. That or, editing the Python code between runs. Otherwise Dynamo would be treating consecutive runs of the script you shared above as “redoing” the transaction, so to speak, so your overwriting problem might return.

As to your original problem, my first thoughts were that maybe the surface pattern and cut pattern colors were not changing because you were not setting any surface pattern or cut pattern… (thinking maybe Revit wouldn’t want to set a color to “no pattern”) but after modifying the Python code to also set the surface patterns and the cut patterns, I still haven’t managed to modify the colors either.

Will see what I can figure out when I have more time to experiment with it, hopefully someone else might be able to shed some light. For those who wish to have a look at this without downloading @DaveP’s dyn file attached above, here is the code he is working with (with my addition of setting the surface pattern and cut patterns):

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
clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)

#Creación de variables de inicio

def ToRevitColor(dynamoColor):return Color(dynamoColor.Red, dynamoColor.Green, dynamoColor.Blue)
def ToDynamoObject(revitObject, isRevitOwned=False):return revitObject.ToDSType(isRevitOwned)
doc = DocumentManager.Instance.CurrentDBDocument

newMaterials = []

# -----CREACIÓN DE MATERIALES


TransactionManager.Instance.EnsureInTransaction(doc)#Función ionicial

 # Llamada a cada elemento de los vectores (arrays) de names y colors

mat_name = IN[0]
color = ToRevitColor(IN[1])
transparency = IN[2]
spattern = IN[3]
cpattern = IN[4]

 # Proceso de generación de materiales

new_mat_id = Material.Create(doc, mat_name)
new_mat = doc.GetElement(new_mat_id)
new_mat.Color = color
new_mat.SurfacePatternId = spattern
new_mat.SurfacePatternColor = color
new_mat.CutPatternId = cpattern
new_mat.CutPatternColor = color
new_mat.Transparency = transparency
newMaterials.append(ToDynamoObject(new_mat))

TransactionManager.Instance.TransactionTaskDone()#siguiente función

#Extracción de materiales

OUT = newMaterials

And the graph is set up as so:

1 Like

When I had to do something similar I too had to select the fill and cut pattern outside of python with the “All Elements of Type” node: Cattura
Then I had to get that element from its ID (I’m sure there is a quicker and not-so-stupid way but it was the first that worked for me and so it lazily stuck around)

sp=UnwrapElement(doc.GetElement(spattern)).Id
cp=UnwrapElement(doc.GetElement(cpattern)).Id



new_mat.CutPatternColor=ToRevitColor(color)
new_mat.CutPatternId=sp

new_mat.SurfacePatternColor=ToRevitColor(color)
new_mat.SurfacePatternId=cp

I tried adapting snipets of code to your example but did not actually try it, please excuse me

@GregX yeah, setting the pattern ids worked fine for me, but that is not what the OP is having trouble with.

When you had to do something similar, were you successful in also setting the surface and cut pattern’s colors? The code above doesn’t show results for the patterns’ colors, but does show results for the patternIds.

1 Like

I thought the reason with the colors not coming up had something to do with the way python reads FillPatternElements, so I pointed that out. Then I was curious and tried using your script (@awilliams awilliams) but on my machine (Italian Revit 2016 right now) I get this error:

Traceback (most recent call last):
File “”, line 38, in
TypeError: expected ElementId, got FillPatternElement

So I got back using that weird UnwrapElement(doc.GetElement thing from my previous experiments which worked and I found out that if i set the shaded color right away it won’t work:


001_1
But if i set it AFTER setting the surface and cut colors it works:

002_2

import clr
clr.AddReference("RevitAPI")
clr.AddReference("System.Core")
import System
clr.ImportExtensions(System.Linq)
from Autodesk.Revit.DB import *
clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)
def ToRevitColor(dynamoColor):return Color(dynamoColor.Red, dynamoColor.Green, dynamoColor.Blue)

def ToDynamoObject(revitObject, isRevitOwned=False):return revitObject.ToDSType(isRevitOwned)

doc = DocumentManager.Instance.CurrentDBDocument

mat_name=IN[0]
color=ToRevitColor(IN[1])
transparency=IN[2]
spattern=UnwrapElement(doc.GetElement(IN[3])).Id
cpattern=UnwrapElement(doc.GetElement(IN[4])).Id
 
TransactionManager.Instance.EnsureInTransaction(doc)
	
new_mat_id=Material.Create(doc,mat_name)
new_mat=doc.GetElement(new_mat_id)
#new_mat.Color=color
new_mat.SurfacePatternId = spattern
new_mat.SurfacePatternColor = color
new_mat.CutPatternId = cpattern
new_mat.CutPatternColor = color
new_mat.Transparency = transparency
new_mat.Color=color
	
TransactionManager.Instance.TransactionTaskDone()

OUT=ToDynamoObject(new_mat)
2 Likes

@GregX The set up that I was using did not produce that error, but in Revit 2018; I haven’t tried the code in Revit 2016 so maybe it is an API improvement :slight_smile:

Moving the new_mat.Color = color line to after surface/cut pattern color lines worked on my code as well! How strange, I wonder why that is.

I’m not entirely sure how this Element.GetPropertyNames node works (from the Wombat package), but it does list the properties in some sort of order that isn’t alphabetical like the API docs list them.


If there is some hierarchical ordering to the list of properties that Element.GetPropertyNames follows, it does show that the “Color” property comes after the surface/cut pattern color properties. Transparency, however is shown after color, and that part of the Python code works fine…maybe the ordering doesn’t cause issue because its input is an integer? :thinking: I’ll have to experiment with comparing other Python code executions to the “ordered” list of properties from the Element.GetPropertyName node to see if that ordering does have some significance in different scenarios.

Anyway, I’m sure @DaveP will be very glad (and maybe a little frustrated :sweat_smile: ) that you found the solution in reordering the lines of code! :slight_smile:

2 Likes

Sorry I haven’t responded for awhile. Darn project get in the way!
Thanks for all the digging, folks. Odd solution! Whatever made you think of switching the order?

Anyway, seems to be working fine for me now.
I’ve got a few more hooks I’d like to add, then I’ll share my final solution.

One more question: Can I rely on Solid fill ALWAYS being the first pattern in the list, or should I filter/seek it out?

Thanks again.

Since elements are listed in the order of their creation, and “solid fill” comes standard with Revit, I think its a fair assumption that solid will always be the first pattern. No harm in setting up a filter with the Element.Name node so your graph can be easily adjusted if you want to use a different pattern :slight_smile:

Best way to check would be starting a new project with no template and seeing what order they run with. It may be possible to have the solid fill removed from the project after creation via some horrible nightmare Demario, but that’s very unlikely.

I found a pretty simple way to feed in the “Solid Fill” pattern using a couple of Core Revit nodes:
Solid fill
Or any other pattern, for that matter.

I really hate how that works. Makes it tough to debug multiple runs if I have to keep closing and re-opening.
And the fact that it DOESN’T behave like that in the Player feels inconsistent to me.
I had a similar discussion here, but I thought that was just limited to Family.Instance

It can be frustrating certainly, but remember you are always an undo in Revit away from what you had before.

The Dynamo Player behavior actually makes sense when you think about how it runs under the hood. Each time the player is run it

  1. Opens the graph
  2. Finds the editable inputs
  3. Asks the user to give a value for each input
  4. Runs the graph
  5. Closes it the graph

Once that runs the user is asked if they want to open another graph and start the process over again. Inputs are reset and created elements are maintained as a result.

this is great but doesnt allow multiple entries? I have tried to modify it with my uber-beginner skills to no avail. this will create one material but doesn’t work to make multiple materials.

Hi @AdamHamilton

Could you please start new topic and drop all your contents there. Thanks!

1 Like

Hi @AdamHamilton,

did you started the new discussion? I need to understand how to manage the input of multiple values ​​that came from “FillPatternElement.GetByName”.

Thank you and best regards,
Michele