From a00e47f8229206bfdfddc67e85d65bfd48d21daa Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Thu, 13 Jul 2023 16:25:37 +1000 Subject: [PATCH] Fix #3300. Bug where it was impossible to delete normal Blender objects in the outliner when an IFC existed. Also port over batch deletion to the outliner override. --- .../bim/module/geometry/operator.py | 44 ++++++++++++++++++- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/src/blenderbim/blenderbim/bim/module/geometry/operator.py b/src/blenderbim/blenderbim/bim/module/geometry/operator.py index 3d13feacd5..a6f29b3354 100644 --- a/src/blenderbim/blenderbim/bim/module/geometry/operator.py +++ b/src/blenderbim/blenderbim/bim/module/geometry/operator.py @@ -451,6 +451,7 @@ class OverrideOutlinerDelete(bpy.types.Operator): bl_label = "IFC Delete" bl_options = {"REGISTER", "UNDO"} hierarchy: bpy.props.BoolProperty(default=False) + is_batch: bpy.props.BoolProperty(name="Is Batch", default=False) @classmethod def poll(cls, context): @@ -483,7 +484,26 @@ class OverrideOutlinerDelete(bpy.types.Operator): bpy.data.collections.remove(collection) return {"FINISHED"} + def invoke(self, context, event): + if tool.Ifc.get(): + total_elements = len(tool.Ifc.get().wrapped_data.entity_names()) + total_polygons = sum([len(o.data.polygons) for o in context.selected_objects if o.type == "MESH"]) + # These numbers are a bit arbitrary, but basically batching is only + # really necessary on large models and large geometry removals. + self.is_batch = total_elements > 500000 and total_polygons > 2000 + if self.is_batch: + return context.window_manager.invoke_props_dialog(self) + return self.execute(context) + + def draw(self, context): + row = self.layout.row() + row.label(text="Warning: Faster deletion will use more memory.", icon="ERROR") + row = self.layout.row() + row.prop(self, "is_batch", text="Enable Faster Deletion") + def _execute(self, context): + if self.is_batch: + ifcopenshell.util.element.batch_remove_deep2(tool.Ifc.get()) objects_to_delete = set() collections_to_delete = set() for item in context.selected_ids: @@ -496,8 +516,20 @@ class OverrideOutlinerDelete(bpy.types.Operator): elif item.bl_rna.identifier == "Object": objects_to_delete.add(bpy.data.objects.get(item.name)) for obj in objects_to_delete: - # This is the only difference - tool.Geometry.delete_ifc_object(obj) + if tool.Ifc.get_entity(obj): + tool.Geometry.delete_ifc_object(obj) + else: + bpy.data.objects.remove(obj) + for collection in collections_to_delete: + bpy.data.collections.remove(collection) + if self.is_batch: + old_file = tool.Ifc.get() + old_file.end_transaction() + new_file = ifcopenshell.util.element.unbatch_remove_deep2(tool.Ifc.get()) + new_file.begin_transaction() + tool.Ifc.set(new_file) + self.transaction_data = {"old_file": old_file, "new_file": new_file} + IfcStore.add_transaction_operation(self) return {"FINISHED"} def get_collection_objects_and_children(self, collection): @@ -512,6 +544,14 @@ class OverrideOutlinerDelete(bpy.types.Operator): children = children.union(collection.children) return {"objects": objects, "children": children} + def rollback(self, data): + tool.Ifc.set(data["old_file"]) + data["old_file"].undo() + + def commit(self, data): + data["old_file"].redo() + tool.Ifc.set(data["new_file"]) + class OverrideDuplicateMoveMacro(bpy.types.Macro): bl_idname = "bim.override_object_duplicate_move_macro"