OSArch Community

[IfcOpenShell-Python] How do I change the color from an ifc entity?

  1. M

    Hi all

    so here i have a simple cube in an ifc file.

    !

    When i open it in an ifc-viewer, the cube is gray like in the image above in the spoiler tag.

    So how can i change the color from this cube with ifcopenshell-python?

    Thanks for the reply :)

  2. A

    Hey @Martin156131, I don't know how to do it with just IfcOpenShell, but with Blenderbim that would be about changing the IfcStyle:

    Here's a thread with the same request:

    https://community.osarch.org/discussion/comment/8780/#Comment_8780

    You change the colour in the viewport display tab and then click update IFCstyle to save it

  3. A

    Here is a red ifc cube for example:

  4. M

    Thanks for the feedback!

    So it is possible to change the color, however I search the method how to do it in python.

    Because i am trying to write a script to make from different obj files one ifc file, so it could be nice when the different ifc entity have a different color, instead having all uniformly gray shading.

  5. A

    If I look at your cube Ifc written out vs the red one you need to include these elements:

    
    #79=IFCSURFACESTYLE('Red',.BOTH.,(#80));
    
    #80=IFCSURFACESTYLERENDERING(#81,0.,#82,$,$,$,IFCNORMALISEDRATIOMEASURE(0.),IFCSPECULARROUGHNESS(0.4),.NOTDEFINED.);
    
    #81=IFCCOLOURRGB($,0.800000071525574,0.0212754905223846,0.0212754905223846);
    
    #82=IFCCOLOURRGB($,0.800000011920929,0.800000011920929,0.800000011920929);
    
    #83=IFCSTYLEDITEM(#73,(#79),'Material');
    
    #84=IFCMATERIAL('Red',$,$);
    
    #85=IFCSTYLEDITEM($,(#79),'Material');
    
    #86=IFCSTYLEDREPRESENTATION(#15,'Body',$,(#85));
    
    #87=IFCMATERIALDEFINITIONREPRESENTATION($,$,(#86),#84);
    

    I don't code so my usefulness ends here

  6. C

    @Martin156131

    So it is possible to change the color, however I search the method how to do it in python. Because i am trying to write a script to make from different obj files one ifc file, so it could be nice when the different ifc entity have a different color,

    You could try this code snippet, I copied it from @brunopostle

    
            mymaterial = ifcfile.createIfcMaterial("wall material")
    
            material_layer = ifcfile.createIfcMaterialLayer(mymaterial, 0.2, None)
    
            material_layer_set = ifcfile.createIfcMaterialLayerSet([material_layer], None)
    
            material_layer_set_usage = ifcfile.createIfcMaterialLayerSetUsage(material_layer_set, "AXIS2", "POSITIVE", -0.1)
    
    
    
    
    
            style = ifcopenshell.api.run("style.add_style", ifcfile, name="brick")
    
            ifcopenshell.api.run(
    
                "style.add_surface_style",
    
                ifcfile,
    
                style=style,
    
                attributes={
    
                    "SurfaceColour": {
    
                        "Name": None,
    
                        "Red": 2.2,
    
                        "Green": 0.8,
    
                        "Blue": 0.5,
    
                    },
    
                    "DiffuseColour": {
    
                        "Name": None,
    
                        "Red": 2.2,
    
                        "Green": 0.8,
    
                        "Blue": 0.5,
    
                    },
    
                    "Transparency": 0.0,
    
                    "ReflectanceMethod": "PLASTIC",
    
                },
    
            )
    
            ifcopenshell.api.run(
    
                "style.assign_material_style",
    
                ifcfile,
    
                material=mymaterial,
    
                style=style,
    
                context=context,
    
            )
    
    
          ifcfile.createIfcRelAssociatesMaterial(create_guid(), owner_history, RelatedObjects=[ifc_wall], RelatingMaterial=material_layer_set_usage)
    

  7. M

    There are two ways for an object to receive a colour: 1) its geometry could directly have a style, or 2) it can be associated with a material, and that material can have a style. @Coen's code snippet shows the latter. The former, however, is more appropriate for your usecase as you don't have any materials it seems.

    
    # Create a blank style
    
    style = ifcopenshell.api.run("style.add_style", ifc, name="My style")
    
    # Give that style a surface shading colour
    
    ifcopenshell.api.run("style.add_surface_style", ifc, style=style, ifc_class="IfcSurfaceStyleShading", attributes={
    
                "SurfaceColour": { "Name": None, "Red": 1., "Green": 0., "Blue": 0. }
    
            })
    
    # Assign the style to your geometry's representation (IfcShapeRepresentation)
    
    ifcopenshell.api.run("style.assign_representation_styles", ifc, shape_representation=representation, styles=[style])
    
  8. M

    Thank you all for your awesome help!

    The jupyternotebook code, that i used:

    !

    My yellow cube ?:

    !

  9. G

    @Coen Thanks for the snippet ! Just as a heads up AFAIK unless you're working with HDR images you should not set the color channels with values > 1.0, the result may not be physically correct or may be clamped by the software you'll open it in. For instance Blender technically supports RGB channels with values > 1 (you have to type it in the fields since the slider doesn't let you) but I'm not sure how it will be handled by other softs. Cheers :)

  10. C

    I am a bit confused why this happens, I've made an IfcWallType instance and added to a project with this script:

    
    import ifcopenshell
    
    from ifcopenshell.api import run
    
    import numpy
    
    import bpy
    
    
    ifc_file = ifcopenshell.file()
    
    project = run("root.create_entity", ifc_file, ifc_class="IfcProject", name="Demo")
    
    
    run("unit.assign_unit", ifc_file, length={"is_metric": True, "raw": "METERS"})
    
    context = run("context.add_context", ifc_file, context_type="Model")
    
    body = run("context.add_context", ifc_file,context_type="Model", context_identifier="Body", target_view="MODEL_VIEW", parent=context)
    
    
    # Create a site, building, and storey. Many hierarchies are possible.
    
    site = run("root.create_entity", ifc_file, ifc_class="IfcSite", name="My Site")
    
    building = run("root.create_entity", ifc_file, ifc_class="IfcBuilding", name="Building A")
    
    storey = run("root.create_entity", ifc_file, ifc_class="IfcBuildingStorey", name="Ground Floor")
    
    
    # Since the site is our top level location, assign it to the project
    
    # Then place our building on the site, and our storey in the building
    
    run("aggregate.assign_object", ifc_file, relating_object=project, product=site)
    
    run("aggregate.assign_object", ifc_file, relating_object=site, product=building)
    
    run("aggregate.assign_object", ifc_file, relating_object=building, product=storey)
    
    
    
    
    def read_from_csv():
    
        print ('read from csv')
    
    
    def create_wall():
    
    
    
        ifc_material = run("material.add_material", ifc_file, name="brick")
    
        ifc_walltype = run("root.create_entity", ifc_file, ifc_class="IfcWallType", name="wall_demo")
    
        relating_material = run("material.assign_material", ifc_file, product=ifc_walltype, type="IfcMaterialLayerSet")
    
        layer_set = relating_material.RelatingMaterial
    
        layer = run("material.add_layer", ifc_file, layer_set=layer_set, material=ifc_material)
    
        layer.LayerThickness = 0.2
    
    
    
        print ('hier', ifc_walltype)
    
    
    
    
        ifc_walltype_instance = run("root.create_entity", ifc_file, ifc_class="IfcWall", relating_type=ifc_walltype, name='walltype_instance')
    
    
        representation = run("geometry.add_wall_representation",ifc_file,context=body,length=5,height=3,thickness=layer.LayerThickness)
    
    
        matrix_1 = numpy.array(
    
                (
    
                    (1.0, 0.0, 0.0, 0.0),
    
                    (0.0, 1.0, 0.0, 0.0),
    
                    (0.0, 0.0, 1.0, 0.0),
    
                    (0.0, 0.0, 0.0, 1.0),
    
                )
    
            )
    
    
    
        run("type.assign_type", ifc_file, related_object=ifc_walltype_instance, relating_type=ifc_walltype)   
    
        run("geometry.edit_object_placement",ifc_file,product=ifc_walltype_instance ,matrix=matrix_1)
    
        run("spatial.assign_container", ifc_file, relating_structure=storey, product=ifc_walltype_instance)
    
        run("geometry.assign_representation", ifc_file, product=ifc_walltype, representation=representation)
    
    
    
    
    
    
    
        style = ifcopenshell.api.run("style.add_style", ifc_file, name="My style")
    
    
    
        run("style.add_surface_style", ifc_file, style=style, ifc_class="IfcSurfaceStyleShading", attributes={
    
                    "SurfaceColour": { "Name": None, "Red": 1., "Green": 0., "Blue": 0. }
    
               })
    
        run("style.assign_representation_styles", ifc_file, shape_representation=representation, styles=[style])
    
    
    
    
    
    
    def create_beam():
    
        #create material
    
        #create ifcmaterialprofileset
    
        #assign material to profileset
    
        #create type
    
        #create occurence
    
        #place occurence
    
        #representation = run("geometry.add_profile_representation", ifc_file, context=representations["body"], profile=profile, depth=5)
    
        print ('create beam')
    
    
    
    
    create_wall()
    
    
    file_name="demo_library"
    
    folder_path = "C:\\Algemeen\\00_prive\\BlenderScripts\\BlenderBIM_create_objects\\ifc_library\\" 
    
    filename = str(file_name) + ".ifc"
    
    file_path = (folder_path + filename)
    
    ifc_file.write(file_path)
    
    
    def load_ifc_automatically():
    
    
        if (bool(ifc_file)) == True:
    
            project = ifc_file.by_type('IfcProject')
    
    
    
            if project is not None:
    
                for i in project:
    
                    collection_name = 'IfcProject/' + i.Name
    
    
    
                collection = bpy.data.collections.get(str(collection_name))
    
    
    
                if collection is not None:
    
                    for obj in collection.objects:
    
                        bpy.data.objects.remove(obj, do_unlink=True)
    
    
    
                    bpy.data.collections.remove(collection)
    
    
    
            #for material in bpy.data.materials:
    
            #    material.user_clear()
    
            #    bpy.data.materials.remove(material)
    
    
    
            bpy.ops.outliner.orphans_purge(do_local_ids=True, do_linked_ids=True, do_recursive=True)         
    
            bpy.ops.bim.load_project(filepath=file_path)
    
    
    
    load_ifc_automatically()
    

    Creates a beautiful red wall

    Now when I open the BIM tool in BlenderBIM, and want to add another IfcWallType instance, this happens:

    When trying to save the project Blender crashes, when I remove the colours I just get a grey colour and BlenderBIM works

    When I open the project in BIM Vision I see this:

    My aim is to create a library of different coloured WallType instances.

    This is the line where BIMVision claims there is an error

    
    #107=IFCCARTESIANTRANSFORMATIONOPERATOR3D(#104,#105,#103,1.,#106);
    
    #108=IFCMAPPEDITEM(#95,#107);
    
    #109=IFCSHAPEREPRESENTATION(#11,'Body','MappedRepresentation',(#108));
    
  11. C

    Some further experimenting, when I use this for assigning a colour:

    
    #brunopostle gorgious snippet
    
       style = run("style.add_style", ifc_file, name=ifc_material.Name)
    
       run("style.add_surface_style",ifc_file,style=style,attributes={"SurfaceColour": {"Name": ifc_material.Name,"Red": 0.8,"Green": 0.5,"Blue": 0.2,},"Transparency": 0,"ReflectanceMethod": "PLASTIC",})
    
        run("style.assign_material_style",ifc_file,material=ifc_material,style=style,context=context)
    

    Instead of this like my previous post:

    
        #moult snippet
    
        style = ifcopenshell.api.run("style.add_style", ifc_file, name="My style")
    
        run("style.add_surface_style", ifc_file, style=style, ifc_class="IfcSurfaceStyleShading", attributes={"SurfaceColour": { "Name": None, "Red": 1., "Green": 0., "Blue": 0. }})
    
        run("style.assign_representation_styles", ifc_file, shape_representation=representation, styles=[style])
    

    It creates also a colour, and when I try to add an IfcWallType instance it preserves the colour:

    However I am unable to open it in BIMVision, BIM Vision gives this log:

    
    #67 0YP$_BwmD0kQ48ohs7NscA  Wall    wall_demo       
    
  12. C

    When I try to save the IFC project when adding another wall I get this weird error when I ran Blender form the command prompt:

    
    fake_module: addon missing 'bl_info' gives bad performance!: 'C:\\Users\\cclaus\\AppData\\Roaming\\Blender Foundation\\Blender\\3.3\\scripts\\addons\\Z-Anatomy\\__init__.py'
    
    Error   : EXCEPTION_ACCESS_VIOLATION
    
    Address : 0x00007FFF744712B9
    
    Module  : _ifcopenshell_wrapper.pyd
    
    Thread  : 00003678
    
    Writing: C:\Users\cclaus\AppData\Local\Temp\blender.crash.txt
    
  13. C

    Don't understand why the IfcWallType instance suddenly is transparant and why it crashes :(

  14. C

    Even when I remove all the style lines and the load_ifc_automaticaly method, then manullay loading it in Blender. Like so:

    
    import ifcopenshell
    
    from ifcopenshell.api import run
    
    import numpy
    
    import bpy
    
    
    ifc_file = ifcopenshell.file()
    
    project = run("root.create_entity", ifc_file, ifc_class="IfcProject", name="Demo")
    
    
    run("unit.assign_unit", ifc_file, length={"is_metric": True, "raw": "METERS"})
    
    context = run("context.add_context", ifc_file, context_type="Model")
    
    body = run("context.add_context", ifc_file,context_type="Model", context_identifier="Body", target_view="MODEL_VIEW", parent=context)
    
    
    # Create a site, building, and storey. Many hierarchies are possible.
    
    site = run("root.create_entity", ifc_file, ifc_class="IfcSite", name="My Site")
    
    building = run("root.create_entity", ifc_file, ifc_class="IfcBuilding", name="Building A")
    
    storey = run("root.create_entity", ifc_file, ifc_class="IfcBuildingStorey", name="Ground Floor")
    
    
    # Since the site is our top level location, assign it to the project
    
    # Then place our building on the site, and our storey in the building
    
    run("aggregate.assign_object", ifc_file, relating_object=project, product=site)
    
    run("aggregate.assign_object", ifc_file, relating_object=site, product=building)
    
    run("aggregate.assign_object", ifc_file, relating_object=building, product=storey)
    
    
    
    
    def read_from_csv():
    
        print ('read from csv')
    
    
    def create_wall():
    
    
    
        ifc_material = run("material.add_material", ifc_file, name="brick")
    
        ifc_walltype = run("root.create_entity", ifc_file, ifc_class="IfcWallType", name="wall_demo")
    
        relating_material = run("material.assign_material", ifc_file, product=ifc_walltype, type="IfcMaterialLayerSet")
    
        layer_set = relating_material.RelatingMaterial
    
        layer = run("material.add_layer", ifc_file, layer_set=layer_set, material=ifc_material)
    
        layer.LayerThickness = 0.2
    
    
    
        print ('hier', ifc_walltype)
    
    
    
    
        ifc_walltype_instance = run("root.create_entity", ifc_file, ifc_class="IfcWall", relating_type=ifc_walltype, name='wall_demo')
    
    
        representation = run("geometry.add_wall_representation",ifc_file,context=body,length=5,height=3,thickness=layer.LayerThickness)
    
    
        matrix_1 = numpy.array(
    
                (
    
                    (1.0, 0.0, 0.0, 0.0),
    
                    (0.0, 1.0, 0.0, 0.0),
    
                    (0.0, 0.0, 1.0, 0.0),
    
                    (0.0, 0.0, 0.0, 1.0),
    
                )
    
            )
    
    
    
        #moult snippet
    
        #style = ifcopenshell.api.run("style.add_style", ifc_file, name="My style")
    
        #run("style.add_surface_style", ifc_file, style=style, ifc_class="IfcSurfaceStyleShading", attributes={"SurfaceColour": { "Name": 'red', "Red": 1., "Green": 0., "Blue": 0. }})
    
        #run("style.assign_representation_styles", ifc_file, shape_representation=representation, styles=[style])
    
    
    
        #brunopostle gorgious snippet
    
        #style = run("style.add_style", ifc_file, name=ifc_material.Name)
    
        #run("style.add_surface_style",ifc_file,style=style,attributes={"SurfaceColour": {"Name": ifc_material.Name,"Red": 0.8,"Green": 0.5,"Blue": 0.2,},"Transparency": 0,"ReflectanceMethod": "PLASTIC",})
    
        #run("style.assign_material_style",ifc_file,material=ifc_material,style=style,context=context)
    
    
    
    
    
    
    
        run("type.assign_type", ifc_file, related_object=ifc_walltype_instance, relating_type=ifc_walltype)   
    
        run("geometry.edit_object_placement",ifc_file,product=ifc_walltype_instance ,matrix=matrix_1)
    
        run("spatial.assign_container", ifc_file, relating_structure=storey, product=ifc_walltype_instance)
    
        run("geometry.assign_representation", ifc_file, product=ifc_walltype, representation=representation)
    
        create_wall()
    

    Then, I close Blender, open it in BIMVision:

    Opening it in BlenderBIM

    Then trying to add a wall, this works, when when trying to Miter join with Shift+Y or Shift+T

    I get this crash

    
    Error: Python: Traceback (most recent call last):
    
      File "C:\Users\cclaus\AppData\Roaming\Blender Foundation\Blender\3.3\scripts\addons\blenderbim\bim\module\model\workspace.py", line 394, in invoke
    
        return self.execute(context)
    
      File "C:\Users\cclaus\AppData\Roaming\Blender Foundation\Blender\3.3\scripts\addons\blenderbim\tool\ifc.py", line 105, in execute
    
        IfcStore.execute_ifc_operator(self, context)
    
      File "C:\Users\cclaus\AppData\Roaming\Blender Foundation\Blender\3.3\scripts\addons\blenderbim\bim\ifc.py", line 418, in execute_ifc_operator
    
        result = getattr(operator, "_execute")(context)
    
      File "C:\Users\cclaus\AppData\Roaming\Blender Foundation\Blender\3.3\scripts\addons\blenderbim\bim\module\model\workspace.py", line 385, in _execute
    
        getattr(self, f"hotkey_{self.hotkey}")()
    
      File "C:\Users\cclaus\AppData\Roaming\Blender Foundation\Blender\3.3\scripts\addons\blenderbim\bim\module\model\workspace.py", line 500, in hotkey_S_Y
    
        bpy.ops.bim.join_wall(join_type="V")
    
      File "C:\Program Files\Blender Foundation\Blender 3.3\3.3\scripts\modules\bpy\ops.py", line 113, in __call__
    
        ret = _op_call(self.idname_py(), None, kw)
    
    RuntimeError: Error: Python: Traceback (most recent call last):
    
      File "C:\Users\cclaus\AppData\Roaming\Blender Foundation\Blender\3.3\scripts\addons\blenderbim\tool\ifc.py", line 105, in execute
    
        IfcStore.execute_ifc_operator(self, context)
    
      File "C:\Users\cclaus\AppData\Roaming\Blender Foundation\Blender\3.3\scripts\addons\blenderbim\bim\ifc.py", line 418, in execute_ifc_operator
    
        result = getattr(operator, "_execute")(context)
    
      File "C:\Users\cclaus\AppData\Roaming\Blender Foundation\Blender\3.3\scripts\addons\blenderbim\bim\module\model\wall.py", line 106, in _execute
    
        joiner.join_V([o for o in selected_objs if o != context.active_object][0], context.active_object)
    
      File "C:\Users\cclaus\AppData\Roaming\Blender Foundation\Blender\3.3\scripts\addons\blenderbim\bim\module\model\wall.py", line 1072, in join_V
    
        self.recreate_wall(element1, wall1, axis1["reference"], axis1["reference"])
    
      File "C:\Users\cclaus\AppData\Roaming\Blender Foundation\Blender\3.3\scripts\addons\blenderbim\bim\module\model\wall.py", line 1168, in recreate_wall
    
        if tool.Ifc.is_moved(obj):
    
      File "C:\Users\cclaus\AppData\Roaming\Blender Foundation\Blender\3.3\scripts\addons\blenderbim\tool\ifc.py", line 59, in is_moved
    
        if not obj.BIMObjectProperties.location_checksum:
    
    ReferenceError: StructRNA of type Object has been removed
    
    Location: C:\Program Files\Blender Foundation\Blender 3.3\3.3\scripts\modules\bpy\ops.py:113
    
  15. T

    I can replicate your problem.

    That's all i got. ;)

  16. C

    @theoryshaw said:

    I can replicate your problem.

    That's all i got. ;)

    At least it's excluded it's not some funny add-on on my end which is causing this :-)

  17. C

    When I use python to create an IfcProjectLibrary instead of IfProject and load them into BlenderBIM, everything works fine. Just wondering how I would use python to load IFC files from the IfcProjectLibrary automatically.

Login or Register to reply.