From 4896a699813b5c2b5cb227d13a61794765996be8 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Sat, 19 Apr 2025 13:42:36 +1000 Subject: [PATCH] Add test cases for drawing duplication and shapely fill mode. --- .../bonsai/bim/module/drawing/operator.py | 1 + src/bonsai/bonsai/core/drawing.py | 6 ++ src/bonsai/bonsai/tool/blender.py | 4 ++ src/bonsai/bonsai/tool/drawing.py | 1 - src/bonsai/test/bim/feature/drawing.feature | 71 ++++++++++++++++++- src/bonsai/test/bim/test_feature.py | 18 ++++- 6 files changed, 98 insertions(+), 3 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/drawing/operator.py b/src/bonsai/bonsai/bim/module/drawing/operator.py index ae1061903a..67d4a465ed 100644 --- a/src/bonsai/bonsai/bim/module/drawing/operator.py +++ b/src/bonsai/bonsai/bim/module/drawing/operator.py @@ -180,6 +180,7 @@ class DuplicateDrawing(bpy.types.Operator, tool.Ifc.Operator): props = tool.Drawing.get_document_props() core.duplicate_drawing( tool.Ifc, + tool.Blender, tool.Drawing, tool.Geometry, drawing=tool.Ifc.get().by_id(self.drawing), diff --git a/src/bonsai/bonsai/core/drawing.py b/src/bonsai/bonsai/core/drawing.py index a87a5a8eee..d7d63baf88 100644 --- a/src/bonsai/bonsai/core/drawing.py +++ b/src/bonsai/bonsai/core/drawing.py @@ -296,6 +296,7 @@ def add_drawing( def duplicate_drawing( ifc: tool.Ifc, + blender: tool.Blender, drawing_tool: tool.Drawing, geometry: tool.Geometry, drawing: ifcopenshell.entity_instance, @@ -315,6 +316,11 @@ def duplicate_drawing( annotation_objs = [ifc.get_object(a) for a in drawing_tool.get_group_elements(group) if a != drawing] old_to_new, _ = geometry.duplicate_ifc_objects(annotation_objs) for new_elements in old_to_new.values(): + # Remove the Blender object, since we haven't actually activated the duplicated drawing + for new_element in new_elements: + print('new element', new_element) + print('gonna remove', ifc.get_object(new_element)) + blender.remove_object(ifc.get_object(new_element)) new_annotations.extend(new_elements) new_annotation = set(new_annotations) ifc.run("group.unassign_group", group=group, products=new_annotations) diff --git a/src/bonsai/bonsai/tool/blender.py b/src/bonsai/bonsai/tool/blender.py index a7d4e4b80f..546161bb33 100644 --- a/src/bonsai/bonsai/tool/blender.py +++ b/src/bonsai/bonsai/tool/blender.py @@ -744,6 +744,10 @@ class Blender(bonsai.core.tool.Blender): getattr(data_to, data_block_type).append(name) return {"data_block": getattr(data_to, data_block_type)[0], "msg": ""} + @classmethod + def remove_object(cls, obj: bpy.types.Object) -> None: + bpy.data.objects.remove(obj) + @classmethod def remove_data_block(cls, data_block: bpy.types.ID, do_unlink=True) -> None: """Removes a datablock (such as a mesh) diff --git a/src/bonsai/bonsai/tool/drawing.py b/src/bonsai/bonsai/tool/drawing.py index 3db1cf5851..a9a6ebcd06 100644 --- a/src/bonsai/bonsai/tool/drawing.py +++ b/src/bonsai/bonsai/tool/drawing.py @@ -2031,7 +2031,6 @@ class Drawing(bonsai.core.tool.Drawing): cls.import_camera_props(drawing, camera.data) for obj in selected_objects_before: - obj.hide_set(False) obj.select_set(True) @classmethod diff --git a/src/bonsai/test/bim/feature/drawing.feature b/src/bonsai/test/bim/feature/drawing.feature index 489956fd36..fdf359694b 100644 --- a/src/bonsai/test/bim/feature/drawing.feature +++ b/src/bonsai/test/bim/feature/drawing.feature @@ -19,6 +19,52 @@ Scenario: Duplicate drawing When I press "bim.duplicate_drawing(drawing={drawing})" Then nothing happens +Scenario: Duplicate drawing - without duplicating annotations + Given an empty IFC project + And I add a cube + And the object "Cube" is selected + And I look at the "Class" panel + And I set the "Products" property to "IfcElement" + And I set the "Class" property to "IfcWall" + And I click "Assign IFC Class" + And I save sample test files + And I look at the "Drawings" panel + And I click "IMPORT" + And I click "ADD" + And I press "bim.expand_target_view(target_view='PLAN_VIEW')" + And I select the "PLAN_VIEW" item in the "BIM_UL_drawinglist" list + And I click "OUTLINER_OB_CAMERA" + And I press "bim.add_annotation" + And the variable "drawing" is "IfcStore.get_file().by_type('IfcAnnotation')[0].id()" + When I press "bim.duplicate_drawing(drawing={drawing})" + And I select the "PLAN_VIEW-X" item in the "BIM_UL_drawinglist" list + And I click "OUTLINER_OB_CAMERA" + Then the object "IfcAnnotation/TEXT" is not selected + And the object "IfcAnnotation/TEXT.001" does not exist + +Scenario: Duplicate drawing - with duplicating annotations + Given an empty IFC project + And I add a cube + And the object "Cube" is selected + And I look at the "Class" panel + And I set the "Products" property to "IfcElement" + And I set the "Class" property to "IfcWall" + And I click "Assign IFC Class" + And I save sample test files + And I look at the "Drawings" panel + And I click "IMPORT" + And I click "ADD" + And I press "bim.expand_target_view(target_view='PLAN_VIEW')" + And I select the "PLAN_VIEW" item in the "BIM_UL_drawinglist" list + And I click "OUTLINER_OB_CAMERA" + And I press "bim.add_annotation" + And the variable "drawing" is "IfcStore.get_file().by_type('IfcAnnotation')[0].id()" + When I press "bim.duplicate_drawing(drawing={drawing}, should_duplicate_annotations=True)" + And I select the "PLAN_VIEW-X" item in the "BIM_UL_drawinglist" list + And I click "OUTLINER_OB_CAMERA" + Then the object "IfcAnnotation/TEXT" is not selected + And the object "IfcAnnotation/TEXT.001" exists + Scenario: Create drawing Given an empty IFC project And I add a cube @@ -35,7 +81,8 @@ Scenario: Create drawing When I select the "PLAN_VIEW" item in the "BIM_UL_drawinglist" list And I click "OUTLINER_OB_CAMERA" And I click "OUTPUT" - Then nothing happens + Then the drawing "PLAN_VIEW.svg" contains "cut" + And the drawing "PLAN_VIEW.svg" contains "IfcWall" Scenario: Create drawing after deleting a duplicated object Given an empty IFC project @@ -171,3 +218,25 @@ Scenario: Add annotation - auto create context if it doesn't exist And I click "OUTLINER_OB_CAMERA" When I press "bim.add_annotation" Then the object "IfcAnnotation/TEXT" is selected + +Scenario: Create drawing - using shapely fill mode + Given an empty IFC project + And I add a cube + And the object "Cube" is selected + And I look at the "Class" panel + And I set the "Products" property to "IfcElement" + And I set the "Class" property to "IfcWall" + And I click "Assign IFC Class" + And I save sample test files + And I look at the "Drawings" panel + And I click "IMPORT" + And I set the "location_hint" property to "My Storey" + And I click "ADD" + And I press "bim.expand_target_view(target_view='PLAN_VIEW')" + When I select the "MY STOREY PLAN" item in the "BIM_UL_drawinglist" list + And I click "OUTLINER_OB_CAMERA" + And I look at the "Active Drawing" panel + And I set the "Fill Mode" property to "Shapely" + And I look at the "Drawings" panel + And I click "OUTPUT" + Then the drawing "MY STOREY PLAN.svg" contains "IfcWall material-null surface" diff --git a/src/bonsai/test/bim/test_feature.py b/src/bonsai/test/bim/test_feature.py index 565c82b575..271223a6e4 100644 --- a/src/bonsai/test/bim/test_feature.py +++ b/src/bonsai/test/bim/test_feature.py @@ -670,6 +670,12 @@ def then_the_object_name_is_selected(name): assert obj in bpy.context.selected_objects +@then(parsers.parse('the object "{name}" is not selected')) +def then_the_object_name_is_not_selected(name): + obj = the_object_name_exists(name) + assert obj not in bpy.context.selected_objects + + @given(parsers.parse('the object "{name}" is rotated by "{rotation_deg}" deg')) @when(parsers.parse('the object "{name}" is rotated by "{rotation_deg}" deg')) def the_object_name_is_rotated_by(name, rotation_deg): @@ -1487,7 +1493,7 @@ def the_obj1_and_obj2_belong_the_same_linked_aggregate_group(obj_name1, obj_name @when(parsers.parse('the object layer length is set to "{value}"')) -def the_obj_layer_lenght_is_set_to(value): +def the_obj_layer_length_is_set_to(value): value = float(value) try: eval("bpy.context.scene.BIMModelProperties.length") @@ -1498,6 +1504,16 @@ def the_obj_layer_lenght_is_set_to(value): bpy.ops.bim.change_layer_length(length=value) +@then(parsers.parse('the drawing "{filename}" contains "{text}"')) +def the_drawing_filename_contains_text(filename, text): + filepath = f"{variables['cwd']}/test/files/temp/drawings/{filename}" + with open(filepath, "r") as f: + content = f.read() + if text in content: + return True + assert False, f"Drawing {filename} does not contain {text}:\n{filepath}\n{content}" + + # These definitions are not to be used in tests but simply in debugging failing tests