From 7116a9f71a2b8367c8e1c6440bd638515793a62f Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Fri, 4 Feb 2022 10:54:18 +1100 Subject: [PATCH] Removing drawings now roundtrips in IFC. See #1153. --- .../blenderbim/bim/module/drawing/operator.py | 13 ++--- src/blenderbim/blenderbim/core/drawing.py | 11 ++++ src/blenderbim/blenderbim/core/tool.py | 5 ++ src/blenderbim/blenderbim/tool/drawing.py | 28 +++++++++ src/blenderbim/blenderbim/tool/ifc.py | 4 ++ src/blenderbim/test/tool/test_drawing.py | 58 +++++++++++++++++++ 6 files changed, 110 insertions(+), 9 deletions(-) diff --git a/src/blenderbim/blenderbim/bim/module/drawing/operator.py b/src/blenderbim/blenderbim/bim/module/drawing/operator.py index 1ee6427847..5fa650016b 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/operator.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/operator.py @@ -816,21 +816,16 @@ class ResizeText(bpy.types.Operator): return {"FINISHED"} -class RemoveDrawing(bpy.types.Operator): +class RemoveDrawing(bpy.types.Operator, Operator): bl_idname = "bim.remove_drawing" bl_label = "Remove Drawing" bl_options = {"REGISTER", "UNDO"} index: bpy.props.IntProperty() - def execute(self, context): + def _execute(self, context): props = context.scene.DocProperties - camera = props.drawings[self.index].camera - collection = camera.users_collection[0] - for obj in collection.objects: - bpy.data.objects.remove(obj) - bpy.data.collections.remove(collection, do_unlink=True) - props.drawings.remove(self.index) - return {"FINISHED"} + drawing = tool.Ifc.get().by_id(props.drawings[self.index].ifc_definition_id) + core.remove_drawing(tool.Ifc, tool.Drawing, drawing=drawing) class AddDrawingStyle(bpy.types.Operator): diff --git a/src/blenderbim/blenderbim/core/drawing.py b/src/blenderbim/blenderbim/core/drawing.py index 26a3a96d47..7c36073df1 100644 --- a/src/blenderbim/blenderbim/core/drawing.py +++ b/src/blenderbim/blenderbim/core/drawing.py @@ -117,3 +117,14 @@ def add_drawing(ifc, collector, drawing, target_view=None, location_hint=None): pset = ifc.run("pset.add_pset", product=element, name="EPset_Drawing") ifc.run("pset.edit_pset", pset=pset, properties={"TargetView": target_view, "Scale": "1/100"}) drawing.import_drawings() + + +def remove_drawing(ifc, drawing_tool, drawing=None): + collection = drawing_tool.get_drawing_collection(drawing) + group = drawing_tool.get_drawing_group(drawing) + if group: + drawing_tool.delete_drawing_elements(drawing_tool.get_group_elements(group)) + ifc.run("group.remove_group", group=group) + drawing_tool.delete_collection(collection) + ifc.run("root.remove_product", product=drawing) + drawing_tool.import_drawings() diff --git a/src/blenderbim/blenderbim/core/tool.py b/src/blenderbim/blenderbim/core/tool.py index 73866bee55..f1676b4b4f 100644 --- a/src/blenderbim/blenderbim/core/tool.py +++ b/src/blenderbim/blenderbim/core/tool.py @@ -137,6 +137,8 @@ class Debug: class Drawing: def create_camera(cls, name, matrix): pass def create_svg_sheet(cls, document, titleblock): pass + def delete_collection(cls, collection): pass + def delete_drawing_elements(cls, elements): pass def disable_editing_drawings(cls): pass def disable_editing_sheets(cls): pass def disable_editing_text(cls, obj): pass @@ -151,6 +153,9 @@ class Drawing: def generate_drawing_matrix(cls, target_view, location_hint): pass def generate_sheet_identification(cls): pass def get_body_context(cls): pass + def get_drawing_collection(cls, drawing): pass + def get_drawing_group(cls, drawing): pass + def get_group_elements(cls, group): pass def get_sheet_filename(cls, document): pass def get_text_literal(cls, obj): pass def get_text_product(cls, element): pass diff --git a/src/blenderbim/blenderbim/tool/drawing.py b/src/blenderbim/blenderbim/tool/drawing.py index d7ad08489a..5fb23f5b49 100644 --- a/src/blenderbim/blenderbim/tool/drawing.py +++ b/src/blenderbim/blenderbim/tool/drawing.py @@ -49,6 +49,18 @@ class Drawing(blenderbim.core.tool.Drawing): sheet_builder.data_dir = bpy.context.scene.BIMProperties.data_dir sheet_builder.create(cls.get_sheet_filename(document), titleblock) + @classmethod + def delete_collection(cls, collection): + bpy.data.collections.remove(collection, do_unlink=True) + + @classmethod + def delete_drawing_elements(cls, elements): + for element in elements: + tool.Ifc.delete(element) + obj = tool.Ifc.get_object(element) + if obj: + bpy.data.objects.remove(obj) + @classmethod def disable_editing_drawings(cls): bpy.context.scene.DocProperties.is_editing_drawings = False @@ -108,6 +120,22 @@ class Drawing(blenderbim.core.tool.Drawing): def get_body_context(cls): return ifcopenshell.util.representation.get_context(tool.Ifc.get(), "Model", "Body", "MODEL_VIEW") + @classmethod + def get_drawing_collection(cls, drawing): + obj = tool.Ifc.get_object(drawing) + return obj.users_collection[0] + + @classmethod + def get_drawing_group(cls, drawing): + for rel in drawing.HasAssignments or []: + if rel.is_a("IfcRelAssignsToGroup"): + return rel.RelatingGroup + + @classmethod + def get_group_elements(cls, group): + for rel in group.IsGroupedBy or []: + return rel.RelatedObjects + @classmethod def get_sheet_filename(cls, document): if hasattr(document, "Identification"): diff --git a/src/blenderbim/blenderbim/tool/ifc.py b/src/blenderbim/blenderbim/tool/ifc.py index 22bdc6428d..4651d04ab9 100644 --- a/src/blenderbim/blenderbim/tool/ifc.py +++ b/src/blenderbim/blenderbim/tool/ifc.py @@ -62,6 +62,10 @@ class Ifc(blenderbim.core.tool.Ifc): def link(cls, element, obj): IfcStore.link_element(element, obj) + @classmethod + def delete(cls, element): + IfcStore.delete_element(element) + @classmethod def unlink(cls, element=None, obj=None): IfcStore.unlink_element(element, obj) diff --git a/src/blenderbim/test/tool/test_drawing.py b/src/blenderbim/test/tool/test_drawing.py index b530473cd8..ebda43d59e 100644 --- a/src/blenderbim/test/tool/test_drawing.py +++ b/src/blenderbim/test/tool/test_drawing.py @@ -24,6 +24,7 @@ import blenderbim.core.tool import blenderbim.tool as tool from test.bim.bootstrap import NewFile from blenderbim.tool.drawing import Drawing as subject +from blenderbim.bim.ifc import IfcStore class TestImplementsTool(NewFile): @@ -50,6 +51,30 @@ class TestCreateSvgSheet(NewFile): assert os.path.isfile(os.path.join(bpy.context.scene.BIMProperties.data_dir, "sheets", "X - FOOBAR.svg")) +class TestDeleteCollection(NewFile): + def test_run(self): + collection = bpy.data.collections.new("Foobar") + subject.delete_collection(collection) + assert not bpy.data.collections.get("Foobar") + + +class TestDeleteDrawingElements(NewFile): + def test_run(self): + ifc = ifcopenshell.file() + tool.Ifc.set(ifc) + obj = bpy.data.objects.new("Object", None) + collection = bpy.data.collections.new("Collection") + bpy.context.scene.collection.children.link(collection) + collection.objects.link(obj) + element = ifc.createIfcAnnotation() + tool.Ifc.link(element, obj) + + element_id = element.id() + subject.delete_drawing_elements([element]) + assert element_id in IfcStore.deleted_ids + assert not bpy.data.objects.get("Object") + + class TestDisableEditingDrawings(NewFile): def test_run(self): bpy.context.scene.DocProperties.is_editing_drawings = True @@ -159,6 +184,39 @@ class TestGetBodyContext(NewFile): assert subject.get_body_context() == context +class TestGetDrawingCollection(NewFile): + def test_run(self): + ifc = ifcopenshell.file() + tool.Ifc.set(ifc) + obj = bpy.data.objects.new("Object", None) + collection = bpy.data.collections.new("Collection") + bpy.context.scene.collection.children.link(collection) + collection.objects.link(obj) + element = ifc.createIfcAnnotation() + tool.Ifc.link(element, obj) + assert subject.get_drawing_collection(element) == collection + + +class TestGetDrawingGroup(NewFile): + def test_run(self): + ifc = ifcopenshell.file() + tool.Ifc.set(ifc) + element = ifc.createIfcAnnotation() + group = ifcopenshell.api.run("group.add_group", ifc) + ifcopenshell.api.run("group.assign_group", ifc, product=element, group=group) + assert subject.get_drawing_group(element) == group + + +class TestGetGroupElements(NewFile): + def test_run(self): + ifc = ifcopenshell.file() + tool.Ifc.set(ifc) + element = ifc.createIfcAnnotation() + group = ifcopenshell.api.run("group.add_group", ifc) + ifcopenshell.api.run("group.assign_group", ifc, product=element, group=group) + assert subject.get_group_elements(group) == (element,) + + class TestGetSheetFilename(NewFile): def test_run(self): ifc = ifcopenshell.file()