From 248dab936d83e9357da6535e8101a005ea15f8bb Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Mon, 24 Oct 2022 13:36:50 +1100 Subject: [PATCH] Experimental reimplementation of reloading an updated IFC --- src/blenderbim/blenderbim/bim/ifc.py | 10 +++- src/blenderbim/blenderbim/bim/operator.py | 72 +++++++++++++++++++++-- 2 files changed, 76 insertions(+), 6 deletions(-) diff --git a/src/blenderbim/blenderbim/bim/ifc.py b/src/blenderbim/blenderbim/bim/ifc.py index 73be9ca371..b24ec89408 100644 --- a/src/blenderbim/blenderbim/bim/ifc.py +++ b/src/blenderbim/blenderbim/bim/ifc.py @@ -252,13 +252,19 @@ class IfcStore: if not obj: return if obj.BIMObjectProperties.ifc_definition_id: - element = IfcStore.get_file().by_id(obj.BIMObjectProperties.ifc_definition_id) + try: + element = IfcStore.get_file().by_id(obj.BIMObjectProperties.ifc_definition_id) + except: + return data = {"id": element.id(), "obj": obj.name} if hasattr(element, "GlobalId"): data["guid"] = element.GlobalId IfcStore.commit_link_element(data) if hasattr(obj, "BIMMaterialProperties") and obj.BIMMaterialProperties.ifc_style_id: - element = IfcStore.get_file().by_id(obj.BIMMaterialProperties.ifc_style_id) + try: + element = IfcStore.get_file().by_id(obj.BIMMaterialProperties.ifc_style_id) + except: + return data = {"id": element.id(), "obj": obj.name} IfcStore.commit_link_element(data) diff --git a/src/blenderbim/blenderbim/bim/operator.py b/src/blenderbim/blenderbim/bim/operator.py index 671a7eb492..5097257704 100644 --- a/src/blenderbim/blenderbim/bim/operator.py +++ b/src/blenderbim/blenderbim/bim/operator.py @@ -19,11 +19,14 @@ import os import bpy import json +import time +import logging import webbrowser import ifcopenshell import blenderbim.bim.handler import blenderbim.tool as tool from . import schema +from blenderbim.bim import import_ifc from blenderbim.bim.ifc import IfcStore from blenderbim.bim.prop import StrProperty from blenderbim.bim.ui import IFCFileSelector @@ -397,16 +400,77 @@ class BIM_OT_remove_section_plane(bpy.types.Operator): bpy.ops.object.delete({"selected_objects": [context.active_object]}) -class ReloadIfcFile(bpy.types.Operator): +class ReloadIfcFile(bpy.types.Operator, tool.Ifc.Operator): bl_idname = "bim.reload_ifc_file" bl_label = "Reload IFC File" bl_options = {"REGISTER", "UNDO"} - bl_description = "Reload the same IFC file" + bl_description = "Reload an updated IFC file" + filepath: bpy.props.StringProperty(subtype="FILE_PATH") + filter_glob: bpy.props.StringProperty(default="*.ifc", options={"HIDDEN"}) - def execute(self, context): - # TODO: reimplement. See #1222. + def _execute(self, context): + import ifcdiff + + old = tool.Ifc.get() + new = ifcopenshell.open(self.filepath) + + ifc_diff = ifcdiff.IfcDiff(old, new, relationships=[]) + ifc_diff.diff() + + changed_elements = set([k for k, v in ifc_diff.change_register.items() if "geometry_changed" in v]) + + for global_id in ifc_diff.deleted_elements | changed_elements: + element = tool.Ifc.get().by_guid(global_id) + obj = tool.Ifc.get_object(element) + if obj: + bpy.data.objects.remove(obj) + + # STEP IDs may change, but we assume the GlobalID to be constant + obj_map = {} + for obj in bpy.data.objects: + element = tool.Ifc.get_entity(obj) + if element and hasattr(element, "GlobalId"): + obj_map[obj.name] = element.GlobalId + + delta_elements = [new.by_guid(global_id) for global_id in ifc_diff.added_elements | changed_elements] + tool.Ifc.set(new) + + for obj in bpy.data.objects: + global_id = obj_map.get(obj.name) + if global_id: + try: + tool.Ifc.link(new.by_guid(global_id), obj) + except: + # Still prototyping, so things like types definitely won't work + print("Could not relink", obj) + + start = time.time() + logger = logging.getLogger("ImportIFC") + path_log = os.path.join(context.scene.BIMProperties.data_dir, "process.log") + if not os.access(context.scene.BIMProperties.data_dir, os.W_OK): + path_log = os.path.join(tempfile.mkdtemp(), "process.log") + logging.basicConfig( + filename=path_log, + filemode="a", + level=logging.DEBUG, + ) + settings = import_ifc.IfcImportSettings.factory(context, self.filepath, logger) + settings.has_filter = True + settings.should_filter_spatial_elements = False + settings.elements = delta_elements + settings.logger.info("Starting import") + ifc_importer = import_ifc.IfcImporter(settings) + ifc_importer.execute() + settings.logger.info("Import finished in {:.2f} seconds".format(time.time() - start)) + print("Import finished in {:.2f} seconds".format(time.time() - start)) + + context.scene.BIMProperties.ifc_file = self.filepath return {"FINISHED"} + def invoke(self, context, event): + context.window_manager.fileselect_add(self) + return {"RUNNING_MODAL"} + class AddIfcFile(bpy.types.Operator): bl_idname = "bim.add_ifc_file"