Script to resync a blender/ifc file

@Moult wrote the following to help me resync a blender/ifc file.
He mentioned making this integral to BB, but in the meantime wanted to paste it here for others, and save for the future, if necessary.

import bpy
import logging
import ifcopenshell
import blenderbim.tool as tool
import blenderbim.bim.handler
import blenderbim.bim.import_ifc as import_ifc
from blenderbim.bim.ifc import IfcStore



def execute():
    f = tool.Ifc.get()

    project_collections = set()
    queue = []
    project_collection = bpy.data.collections.get('IfcProject/My Project')
    if project_collection:
        queue.append(project_collection)
    while queue:
        collection = queue.pop()
        project_collections.add(collection)
        queue.extend(collection.children)
    print(project_collections)
    for obj in bpy.data.objects:
        ifc_id = obj.BIMObjectProperties.ifc_definition_id
        if ifc_id:
            try:
                element = f.by_id(ifc_id)
            except:
                print("Object not validly linked to anything", obj)
                bpy.data.objects.remove(obj)
                continue
            ifc_class = obj.name.split("/")[0]
            if not element.is_a(ifc_class):
                print("Object linked to different class", obj, element)
                bpy.data.objects.remove(obj)
            elif element.is_a("IfcAnnotation"):
                bpy.data.objects.remove(obj) # Annotations are lazy loaded
            elif not element.is_a("IfcContext") and not element.is_a("IfcProduct") and not element.is_a("IfcTypeProduct"):
                print("Object linked to strange element", obj, element)
                bpy.data.objects.remove(obj)
        else:
            for collection in obj.users_collection:
                if collection in project_collections:
                    print('uhoh', obj, collection) # Deal with this situation if it turns up
#    return


    for collection in bpy.data.collections:
        if "Ifc" in collection.name or collection in project_collections:
            bpy.data.collections.remove(collection)

    project = tool.Ifc.get().by_type("IfcProject")[0]
    project_obj = tool.Ifc.get_object(project)
    bpy.data.objects.remove(project_obj)

    logger = logging.getLogger("ImportIFC")
    ifc_import_settings = import_ifc.IfcImportSettings.factory(bpy.context, tool.Ifc.get_path(), logger)
    ifc_importer = import_ifc.IfcImporter(ifc_import_settings)
    ifc_importer.file = tool.Ifc.get()
    ifc_importer.spatial_elements = set(tool.Ifc.get().by_type("IfcSpatialElement"))
    ifc_importer.create_project()
    ifc_importer.process_context_filter()
    ifc_importer.create_collections()

    materials = {}
    existing_styles = {}
    for material in bpy.data.materials:
        ifc_id = material.BIMObjectProperties.ifc_definition_id
        if ifc_id:
            materials[ifc_id] = material
        ifc_id = material.BIMMaterialProperties.ifc_style_id
        if ifc_id:
            existing_styles[ifc_id] = material

    ifc_importer.material_creator.materials = materials
    ifc_importer.material_creator.styles = existing_styles

    for material in tool.Ifc.get().by_type("IfcMaterial"):
        if material.id() not in materials:
            print("Material not in blend", material)
            ifc_importer.create_material(material)

    # create styles

    parsed_styles = set()

    for material_definition_representation in tool.Ifc.get().by_type("IfcMaterialDefinitionRepresentation"):
        material = material_definition_representation.RepresentedMaterial
        blender_material = ifc_importer.material_creator.materials[material.id()]
        for representation in material_definition_representation.Representations:
            styles = []
            for styled_item in representation.Items:
                styles.extend(styled_item.Styles)
            while styles:
                style = styles.pop()
                if style.is_a("IfcSurfaceStyle"):
                    if style.id() not in existing_styles:
                        print("Material style not in blend", style, blender_material)
                        ifc_importer.create_style(style, blender_material)
                        parsed_styles.add(style.id())
                elif style.is_a("IfcPresentationStyleAssignment"):
                    styles.extend(style.Styles)

    for style in tool.Ifc.get().by_type("IfcSurfaceStyle"):
        if style.id() in parsed_styles:
            continue
        if style.id() not in existing_styles:
            print("Style not in blend", style)
            ifc_importer.create_style(style)

    # Done

    elements = tool.Ifc.get().by_type("IfcElement")
    missing_elements = set()
    missing_elements2 = set()
    for element in elements:
        if element.is_a("IfcOpeningElement"):
            continue
        obj = tool.Ifc.get_object(element)
        if not obj:
            print("Object does not exist", element)
            missing_elements.add(element)
            missing_elements2.add(element)

    ifc_importer.create_generic_elements(missing_elements)

    for missing_element in missing_elements2:
        print("Created missing element", tool.Ifc.get_object(missing_element))

    element_types = tool.Ifc.get().by_type("IfcTypeProduct")
    for element in element_types:
        obj = tool.Ifc.get_object(element)
        if not obj:
            print("Object does not exist", element)

    blenderbim.bim.handler.loadIfcStore(bpy.context.scene)
    ifc_importer.added_data = IfcStore.id_map

    ifc_importer.place_objects_in_collections()

    project_obj = tool.Ifc.get_object(project)
    bpy.context.scene.collection.children.link(project_obj.BIMObjectProperties.collection)

    for mat in bpy.data.materials:
        if mat.BIMObjectProperties.ifc_definition_id or mat.BIMMaterialProperties.ifc_style_id:
            mat.use_fake_user = True

execute()
Acebruno_perdigaoOwura_quArvdimitarAndrej730

Comments

  • @theoryshaw would be helpful to create a new button near the existing "save ifc* button that executes this script? Like a " resync ifc/blender file" button...

  • Sorry for the dumb question. What is a resync? When should you need a resync?

    Nigel
  • @Bimlooser i'm not an expert, but explain what i know. Sometimes the working .blend file disconnects from the .ifc file.
    For example, you think that an object is saved in the .ifc file and it's not or you see .ifc properties about an object and these properties are not stored in the .ifc file.
    I don't know the causes but it could be wrong modeling actions, bugs, BBim updates, etc...
    This is the reason that the best practice is to save and load directly the .ifc file so you are sure that what you see is really stored in the .ifc file.

    Nigel
  • Yep, @Massimo is correct.
    For this project, since we were using Blender materials, constraints, and procedural materials for rendering/animations, we kept the blender/ifc connection alive.

    NigelCoen
  • For this project, since we were using Blender materials, constraints, and procedural materials for rendering/animations, we kept the blender/ifc connection alive.

    For example, if you use a blender array modifier, on an IFC object. It will store the array modifier and keep it in sync with the ifc file using this script?

  • No, i dont think it works this way, unfortuately.

  • I've used this script quite a few times, thank you. :)

  • I think I may be experiencing this bug. I have a saved IFC file set up and a number of floors that use modifiers. They seem to be saved with the array modifier when viewing the IFC, but the booleans don't seems like they are applied in the IFC. when applying the modifiers and saving the IFC, upon opening it separately, they still look the same without being applied.

  • edited October 2023

    Does this help?
    https://www.dropbox.com/scl/fi/ynavngoyqsz2ptdk8k3g6/2023-10-07_10-51-00_Blender_blender.mp4?rlkey=asy43qtfjboqreze3h7h6qfhm&dl=0

    If you're arraying specifically, I would use the special IFC array. The video shows how.
    That way, all the floors stay intelligent floors, and you don't have to tessellate them.

Sign In or Register to comment.