Material Creation/Override with Python

Marco,

The code below will achieve your goal, I believe.

#PROTO_Material Creation / Management v2 (Color and Surface Pattern control)
# by David Dória
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
#Inputs

names = IN[0]
cols = IN[1]
surfPatFor = IN[2]
surfPatForCl = IN[3]
surfPatBkg = IN[4]
surfPatBkgCl = IN[5]

#New materials OUT list
newMaterials = []
#Overwritten materials OUT list
ovwMaterials = []

def ToRevitColor(dynamoColor):
	return Color(dynamoColor.Red, dynamoColor.Green, dynamoColor.Blue)
	
#Avoid instance input problem
if isinstance(names, list):
	names = names
else: names = [names]

if isinstance(cols, list):
	cols = cols
else: cols = [cols]

if isinstance(surfPatFor, list):
	surfPatFor = surfPatFor
else: surfPatFor = [surfPatFor]

if isinstance(surfPatForCl, list):
	surfPatForCl = surfPatForCl
else: surfPatForCl = [surfPatForCl]

if isinstance(surfPatBkg, list):
	surfPatBkg = surfPatBkg
else: surfPatBkg = [surfPatBkg]

if isinstance(surfPatBkgCl, list):
	surfPatBkgCl = surfPatBkgCl
else: surfPatBkgCl = [surfPatBkgCl]

#Get Pattern Id
	

#Iterate through the input names list
for n, cl,spfor,spforC, spBkg, spBkgC  in zip(names,cols,surfPatFor,surfPatForCl,surfPatBkg,surfPatBkgCl):
	#Check if the material with the specified name already exists
	if Material.IsNameUnique(doc,n):
		#If name is unique, create material
		TransactionManager.Instance.EnsureInTransaction(doc)
		new_mat_id = Material.Create(doc, n)
		new_mat = doc.GetElement(new_mat_id)
		new_mat.Color = ToRevitColor(cl)
		new_mat.SurfaceForegroundPatternId = FillPatternElement.GetFillPatternElementByName(doc, FillPatternTarget.Drafting,spfor).Id
		
		new_mat.SurfaceForegroundPatternColor = ToRevitColor(spforC)
		
		new_mat.SurfaceBackgroundPatternId = FillPatternElement.GetFillPatternElementByName(doc, FillPatternTarget.Drafting,spBkg).Id
		
		new_mat.SurfaceBackgroundPatternColor = ToRevitColor(spBkgC)
		

		TransactionManager.Instance.TransactionTaskDone()
		newMaterials.append(n)
	else:
		#If it already exists, collect it and modify it
		TransactionManager.Instance.EnsureInTransaction(doc)
		namePar = ParameterValueProvider(ElementId(BuiltInParameter.MATERIAL_NAME))
		fRule = FilterStringRule(namePar,FilterStringEquals(),n, True)
		filter = ElementParameterFilter(fRule)
		exist_mat = FilteredElementCollector(doc).OfClass(Material).WherePasses(filter).ToElements()
		#Iteration is necessary because the output of exist_mat is invariably a list
		for em in exist_mat:
			#Modify the Material Properties and Parameters
			em.Color = ToRevitColor(cl)
			em.SurfaceForegroundPatternId = FillPatternElement.GetFillPatternElementByName(doc, FillPatternTarget.Drafting,spfor).Id
			
			em.SurfaceForegroundPatternColor = ToRevitColor(spforC)
			
			em.SurfaceBackgroundPatternId = FillPatternElement.GetFillPatternElementByName(doc, FillPatternTarget.Drafting,spBkg).Id
			
			em.SurfaceBackgroundPatternColor = ToRevitColor(spBkgC)
			
			ovwMaterials.append(n)
		TransactionManager.Instance.TransactionTaskDone()
		
OUT = newMaterials, ovwMaterials

Be aware that this is based on the Revit 2019 Materials, which have Foreground and Background surface patterns. If using an older version of Revit, replace the SurfaceForegroundPatternColor and the SurfaceForegroundPatternId with SurfacePatternColor and SurfacePatternId

Also, I suggest adding another input to control the Drafting or Model variable of the GetFillPatternElementByName(doc, FillPatternTarget.Drafting/Model,name) function, to facilitate the control via a external Database with different types of Fill Patterns.

Best,
David Dória

2 Likes