How to paint every wall surface

hi, i want to paint every single surface wall on a proyect. is there a way to do it?

Hi @marguello49J42,

You’re looking for something like that.

1 Like

hi, thank u very much for answering, its been a first step. but im looking for a way to apply a different material paint on every wall surface, so i can export it to lumion to apply different materials. should have said that at the begining, didnt i? sorry for that, im kind of new around here

See here for an example of painting surfaces with a material.

1 Like

I’m having trouble with painting wall surfaces too. This thread wasn’t helpful, multiple people had errors with the Python scripts posted and no one seemed to get a solution or a .dyn posted.

What have you tried?

Hi Alex,

It’s good practice here, to post what sort of progress you’ve made on your own.

What sort of errors do you get, when you are trying to run said python scripts? Are you trying to paint all faces of the walls, or is it specific faces you want to paint?

To make it even easier for people trying to help you, you could attach a small Revit test file and your dyn.

I got this Python script from one of the prior threads, but I’m getting the same error someone else got: “TypeError: Multiple targets could match: GetElement(Reference), GetElement(str), GetElement(ElementId)”

Script attached. Select a room with some bordering walls. For now just pulling the first Material in the library:
Paint Walls in Room.dyn (12.8 KB)

Edit: in the model, it’s highlighting the wall faces in an orange, like an error/warning:

The orange faces are the Dynamo preview geometry.

The issue here is that you are working with three different types of faces.

  1. The Dynamo geometry, referred to as a surface in common preview, but the actual object type (use an Object.Type node liberally to get to the root of this) is Autodesk.DesignScript.Geometry.Surface.
  2. The faces which make up the invisible room geometry, which are Revit geometry elements, having a Autodesk.Revit.DB.PlanarFace object.
  3. The faces of the walls which make up the wall geometry, which are actual Revit elements, having the associated geometry values (likely Autodesk.Revit.DB.PlanarFace again but I didn’t check).

It isn’t my code so I am hesitant to comment on it, but the paint method which is illustrated in the thread linked above, you need to feed in a Dynamo surface, which then finds the ‘closest matching Revit face’ from that shape. This starts with the line “surf.Tags.LookupTag(‘RevitFaceReference’)” where it pulls the face reference, then gets the element from that value, and then the element which contains the face, and then pulls the actual Revit face itself, at which point it asks “Is the face painted? If not paint it, otherwise do nothing.” In your case, you’re feeding it a Revit face and it can’t find the underlying Revit face so it’s failing. It’s like asking to divide 1 by “zebra” - Dynamo (or rather Revit via Dynamo) is telling you “you don’t make sense because there is no number called zebra”, or in this case "you don’t make sense as there is no way to pull an associated Revit face from a Revit face.

So that said, hopefully you have an understanding of why this is happening, but not yet how to fix it.

And fixing it is a more difficult issue, as it depends on a variety of stuff including how you are modeling and what you’re really after.

Note that in the UI if you ‘paint’ a wall which runs continuously across rooms as you indicate above, it will spill across rooms. if you’re ok with this, then no need to change anything or complicate it. If you aren’t, then you’ll have to split the face of each wall at the limits of the room just like in real the UI. This can be done either manually or via the Dynamo/API (I don’t have an example of this handy, but I recall seeing them around). Be sure to catch the vertical separations as well (below the floors, above the ceilings, etc). Once that is done your efforts get a LOT simpler as the face of the room may actually return the face of the wall (they’ll now be the same size(ish)), and you should be able to rig up some Python to paint inside the lines via the Revit Autodesk.Revit.DB.PlanarFace objects.

If you don’t do that, or if you don’t want to fiddle with Python, you’ll have to take the time to check which overlapping wall surfaces intersect with the room geometry, and feed those surfaces into the Python node. This does require a few Boolean filters to see which wall surfaces intersect the room geometry, and then which intersecting surfaces are actual surfaces not lines. Once you’re done you can move along pretty quickly to the Python without edits. Graph winds up looking something like this:

Hopefully this sheds enough light and you can make some headway. Keep in mind that the variety of methods used for working in Revit means that you’ll vary rarely find ‘ready to play’ graphs unless your work methods align perfectly with whoever’s code you’re using, and the methods of applying Room finishes is certainly one such application where this variety makes things VERY difficult to easily share.

2 Likes

Nice write up, @JacobSmall :slight_smile:

You covered everything there is to cover, but I thought I’d just chip in as well:

Python Script:

import clr
import sys

sys.path.append(r'C:\Program Files (x86)\IronPython 2.7\Lib')

clr.AddReference('RevitAPI')
clr.AddReference('RevitServices')

import Autodesk
import RevitServices

from Autodesk.Revit.DB import *
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

doc =  DocumentManager.Instance.CurrentDBDocument


faces = UnwrapElement(IN[0])
elems = UnwrapElement(IN[1])
material = UnwrapElement(IN[2])
bool = IN[3]

output = []

if bool:
	try:
		errorReport = None
		TransactionManager.Instance.EnsureInTransaction(doc)
		for i,j in zip(faces, elems):
			doc.Paint(j.Id, i, material.Id)
			output.append('Wall with Element Id ' + '{}'.format(j.Id) + ' was painted')
		TransactionManager.Instance.TransactionTaskDone()
	except:
		import traceback
		errorReport = traceback.format_exc()
		
	if None == errorReport:
		OUT = output
	else:
		OUT = errorReport

else:
	OUT = 'Set bool to true' 

This does feel a bit glitchy though, and the workflow should be optimised according to Jacobs explenation, regarding walls going through multiple rooms. It also seems to not like curtain walls very much. But anyways - here’s something to work with, as a suplement to Jacobs solution.

Good luck :slight_smile:

3 Likes

This is very helpful. I guess I didn’t realize that Room elements had invisible faces on them, though it makes sense considering the error, and how it seems the Room.Finishes node gets its faces. I think I have enough to work with between yours and MartinSpence’s replies. Thank you again!

1 Like

After you get yourself squared away remember to come back and ‘mark’ a solution so others don’t struggle as much as yours.

FWIW I would give it to Martin here as his has code that others can just use (should it work, which I think it will :slight_smile: )