Color Rebar by property with IfcOpenShell
There are a lot of nested objects to go through to get to the colours of objects in IFC, and there are two paths to follow:
print("Colour in material:")
print(rebars[1].HasAssociations[0].RelatingMaterial.HasRepresentation[0].Representations[0].Items[0].Styles[0].Styles[0].Styles[0].SurfaceColour)
print("Colour in representation:")
print(rebars[1].Representation.Representations[0].Items[0].StyledByItem[0].Styles[0].Styles[0].Styles[0].SurfaceColour)
Here is a script I made to set colors to rebars based on different values of an attribute. I need one IfcStyledItem
per Rebar instance, but do I need one new of the three styles (IfcSurfaceStyleRendering, IfcSurfaceStyle, IfcPresentationStyleAssignment
) for each color, or could I reuse them?
import ifcopenshell
f = ifcopenshell.open(r"Rebar-diameter.ifc")
rebars = f.by_type('IfcReinforcingBar')
colours = (
("darkslategray", "#2f4f4f"),
("darkolivegreen", "#556b2f"),
("saddlebrown", "#8b4513"),
("olivedrab", "#6b8e23"),
("seagreen", "#2e8b57"),
("maroon", "#800000"),
("midnightblue", "#191970"),
("slategray", "#708090"),
("green", "#008000"),
("peru", "#cd853f"),
("steelblue", "#4682b4"),
("navy", "#000080"),
("yellowgreen", "#9acd32"),
("lightseagreen", "#20b2aa"),
("indianred", "#cd5c5c"),
("limegreen", "#32cd32"),
("goldenrod", "#daa520"),
("darkseagreen", "#8fbc8f"),
("purple", "#800080"),
("darkorchid", "#9932cc"),
("red", "#ff0000"),
("darkorange", "#ff8c00"),
("gold", "#ffd700"),
("yellow", "#ffff00"),
("mediumblue", "#0000cd"),
("burlywood", "#deb887"),
("lime", "#00ff00"),
("springgreen", "#00ff7f"),
("royalblue", "#4169e1"),
("darksalmon", "#e9967a"),
("crimson", "#dc143c"),
("aqua", "#00ffff"),
("deepskyblue", "#00bfff"),
("blue", "#0000ff"),
("purple3", "#a020f0"),
("greenyellow", "#adff2f"),
("tomato", "#ff6347"),
("fuchsia", "#ff00ff"),
("palevioletred", "#db7093"),
("khaki", "#f0e68c"),
("cornflower", "#6495ed"),
("plum", "#dda0dd"),
("skyblue", "#87ceeb"),
("deeppink", "#ff1493"),
("violet", "#ee82ee"),
("palegreen", "#98fb98"),
("aquamarine", "#7fffd4"),
("hotpink", "#ff69b4"),
("pink", "#ffc0cb")
)
import itertools, math
rebar_groups = []
for k,g in itertools.groupby(rebars, lambda x: x.NominalDiameter):
rebar_groups.append(list(g))
num_groups = len(rebar_groups)
colours = colours*math.ceil(len(rebar_groups)/len(colours))
colours = colours[:len(rebar_groups)]
rgb_colours = list()
for hex in colours:
h = hex[1].lstrip('#')
rgb = tuple(int(h[i:i+2], 16)/255 for i in (0, 2, 4))
rgb_colours.append(f.createIfcColourRgb(hex[0], rgb[0], rgb[1], rgb[2]))
i = 0
for i, group in enumerate(rebar_groups):
colour = rgb_colours[i]
surfaceStyleRendering = f.createIfcSurfaceStyleRendering()
surfaceStyleRendering.SurfaceColour = colour
surfaceStyle = f.createIfcSurfaceStyle(colour.Name, "BOTH",(surfaceStyleRendering,))
presStyleAssign = f.createIfcPresentationStyleAssignment((surfaceStyle,))
i=i+1
for rebar in group:
item = rebar.Representation.Representations[0].Items[0]
f.createIfcStyledItem(item, (presStyleAssign,), colour.Name)
f.write(r"Rebar-diameter-modiefied.ifc")
Tagged:
Comments
Before I answer - are you sure you want to do this? Most IFC viewing has a function to colour by attribute / property without needing to patch the IFC file, including the BlenderBIM Add-on. Wouldn't that be simpler?
For instance Dalux BIM viewer can not. And rebars are so small and densly placed that it is almost not possible to tell the different bars apart without color.
I see. It'd be cool to turn this into an IfcPatch recipe then! Let's workshop it!
IfcPresentationStyleAssignment
is deprecated. However, I do know that in Revit, they ignore the deprecation and actually colours fail if you don't use it. So you should offer a boolean toggle to use it or not.As for
IfcSurfaceStyle
, I see nothing in the spec that prohibits reuse. Go ahead! As forIfcSurfaceStyleRendering
, can I recommendIfcSurfaceStyleShading
instead, as you are only dealing with simple colours? Both can be reused I think, I didn't spot anything in the spec that prohibits it.IfcSurfaceStyleShading
works just as good!As long as the
IfcColorRgb
-object is a direct attribute of theIfcSurfaceStyleShading
-object and so on, it seems like they need to be unique entities per color? (Still not too steady on the IFC terminology)@Einar yes. Unique per colour.
Since
IfcPresentationStyleAssignment
is deprecated theIfcSurfaceStyle
should be plugged directly intoIfcStyledItem
right? That doesn't work in Solibri with my test file IFC 2x3 CV2.0, maybe it would work with IFC4. Here is a recipie that can be used with ifcpatch:@Einar Correct, it should plug directly. The assignment keyword is like a useless middle layer.
I think I recall that Revit has a bug where if you don't use the assignment, it won't read colour. IfcOpenShell actually also had this bug until it was fixed half a year ago or so. So maybe Solibri has this bug too?
The best way to know if colours are correct is to test with the latest version of the BlenderBIM Add-on (use the latest v0.6.0 branch, as I've recently pushed a bunch of fixes to materials and colours since the last release). If colours show, your IFC is correct and its likely a bug with other software.