Fix bug where deleting the drawing object could lead to orphaned relationships

This commit is contained in:
Dion Moult
2023-03-19 18:15:09 +11:00
parent 3da718a6d1
commit 2816d7f522
5 changed files with 56 additions and 7 deletions
@@ -28,6 +28,7 @@ import ifcopenshell.api
import blenderbim.core.geometry as core import blenderbim.core.geometry as core
import blenderbim.core.style import blenderbim.core.style
import blenderbim.core.root import blenderbim.core.root
import blenderbim.core.drawing
import blenderbim.tool as tool import blenderbim.tool as tool
import blenderbim.bim.handler import blenderbim.bim.handler
from mathutils import Vector from mathutils import Vector
@@ -357,6 +358,8 @@ class OverrideDeleteTrait:
element = tool.Ifc.get_entity(obj) element = tool.Ifc.get_entity(obj)
if not element: if not element:
return return
if element.is_a("IfcAnnotation") and element.ObjectType == "DRAWING":
return blenderbim.core.drawing.remove_drawing(tool.Ifc, tool.Drawing, drawing=element)
IfcStore.delete_element(element) IfcStore.delete_element(element)
if obj.users_collection and obj.users_collection[0].name == obj.name: if obj.users_collection and obj.users_collection[0].name == obj.name:
parent = ifcopenshell.util.element.get_aggregate(element) parent = ifcopenshell.util.element.get_aggregate(element)
@@ -425,7 +428,11 @@ class OverrideDelete(bpy.types.Operator, OverrideDeleteTrait):
def _execute(self, context): def _execute(self, context):
for obj in context.selected_objects: for obj in context.selected_objects:
self.delete_ifc_object(obj) self.delete_ifc_object(obj)
bpy.data.objects.remove(obj) try:
obj.name
bpy.data.objects.remove(obj)
except:
pass
# Required otherwise gizmos are still visible # Required otherwise gizmos are still visible
context.view_layer.objects.active = None context.view_layer.objects.active = None
return {"FINISHED"} return {"FINISHED"}
+3 -3
View File
@@ -191,13 +191,13 @@ def duplicate_drawing(ifc, drawing_tool, drawing=None, should_duplicate_annotati
def remove_drawing(ifc, drawing_tool, drawing=None): def remove_drawing(ifc, drawing_tool, drawing=None):
collection = drawing_tool.get_drawing_collection(drawing)
if collection:
drawing_tool.delete_collection(collection)
group = drawing_tool.get_drawing_group(drawing) group = drawing_tool.get_drawing_group(drawing)
if group: if group:
drawing_tool.delete_drawing_elements(drawing_tool.get_group_elements(group)) drawing_tool.delete_drawing_elements(drawing_tool.get_group_elements(group))
ifc.run("group.remove_group", group=group) ifc.run("group.remove_group", group=group)
collection = drawing_tool.get_drawing_collection(drawing)
if collection:
drawing_tool.delete_collection(collection)
for reference in drawing_tool.get_drawing_references(drawing): for reference in drawing_tool.get_drawing_references(drawing):
reference_obj = ifc.get_object(reference) reference_obj = ifc.get_object(reference)
if reference_obj: if reference_obj:
@@ -47,3 +47,29 @@ Scenario: Create drawing after deleting a duplicated object
And I press "object.delete(use_global=False)" And I press "object.delete(use_global=False)"
When I press "bim.create_drawing" When I press "bim.create_drawing"
Then nothing happens Then nothing happens
Scenario: Remove drawing
Given an empty IFC project
And I add a cube
And the object "Cube" is selected
And I set "scene.BIMRootProperties.ifc_class" to "IfcWall"
And I press "bim.assign_class"
And the variable "wall1" is "IfcStore.get_file().by_type('IfcWall')[-1].id()"
And I press "bim.add_drawing"
And the variable "drawing" is "IfcStore.get_file().by_type('IfcAnnotation')[0].id()"
And the collection "IfcGroup/PLAN_VIEW" exists
When I press "bim.remove_drawing(drawing={drawing})"
Then the collection "IfcGroup/PLAN_VIEW" does not exist
Scenario: Remove drawing - via object deletion
Given an empty IFC project
And I add a cube
And the object "Cube" is selected
And I set "scene.BIMRootProperties.ifc_class" to "IfcWall"
And I press "bim.assign_class"
And the variable "wall1" is "IfcStore.get_file().by_type('IfcWall')[-1].id()"
And I press "bim.add_drawing"
And the variable "drawing" is "IfcStore.get_file().by_type('IfcAnnotation')[0].id()"
And the object "IfcAnnotation/PLAN_VIEW" is selected
When I press "bim.override_object_delete"
Then the collection "IfcGroup/PLAN_VIEW" does not exist
@@ -262,7 +262,7 @@ Scenario: Override delete - without active IFC data
Given an empty Blender session Given an empty Blender session
And I add a cube And I add a cube
And the object "Cube" is selected And the object "Cube" is selected
When I press "object.delete" When I press "bim.override_object_delete"
Then the object "Cube" does not exist Then the object "Cube" does not exist
Scenario: Override delete - with active IFC data Scenario: Override delete - with active IFC data
@@ -272,7 +272,7 @@ Scenario: Override delete - with active IFC data
And I set "scene.BIMRootProperties.ifc_class" to "IfcWall" And I set "scene.BIMRootProperties.ifc_class" to "IfcWall"
And I press "bim.assign_class" And I press "bim.assign_class"
And the object "IfcWall/Cube" is selected And the object "IfcWall/Cube" is selected
When I press "object.delete" When I press "bim.override_object_delete"
Then the object "IfcWall/Cube" does not exist Then the object "IfcWall/Cube" does not exist
Scenario: Override outliner delete Scenario: Override outliner delete
+17 -1
View File
@@ -301,6 +301,16 @@ def the_object_name_exists(name) -> bpy.types.Object:
return obj return obj
@given(parsers.parse('the collection "{name}" exists'))
@when(parsers.parse('the collection "{name}" exists'))
@then(parsers.parse('the collection "{name}" exists'))
def the_collection_name_exists(name) -> bpy.types.Collection:
obj = bpy.data.collections.get(name)
if not obj:
assert False, f'The collection "{name}" does not exist'
return obj
@then(parsers.parse('the object "{name1}" and "{name2}" are different elements')) @then(parsers.parse('the object "{name1}" and "{name2}" are different elements'))
def the_object_name1_and_name2_are_different_elements(name1, name2): def the_object_name1_and_name2_are_different_elements(name1, name2):
ifc = an_ifc_file_exists() ifc = an_ifc_file_exists()
@@ -585,7 +595,13 @@ def the_collection_name1_is_in_the_collection_name2(name1, name2):
@then(parsers.parse('the object "{name}" does not exist')) @then(parsers.parse('the object "{name}" does not exist'))
def the_object_name_does_not_exist(name): def the_object_name_does_not_exist(name):
obj = bpy.data.objects.get(name) obj = bpy.data.objects.get(name)
assert obj is None or len(obj.users_collection) == 0, "Object exists" assert obj is None or len(obj.users_collection) == 0, f"Object {name} exists"
@then(parsers.parse('the collection "{name}" does not exist'))
def the_collection_name_does_not_exist(name):
obj = bpy.data.collections.get(name)
assert obj is None, f"Collection {name} exists"
@then(parsers.parse('objects starting with "{name}" do not exist')) @then(parsers.parse('objects starting with "{name}" do not exist'))