diff --git a/src/bonsai/bonsai/core/geometry.py b/src/bonsai/bonsai/core/geometry.py index 7f35d3bd2a..99512f75b8 100644 --- a/src/bonsai/bonsai/core/geometry.py +++ b/src/bonsai/bonsai/core/geometry.py @@ -147,7 +147,7 @@ def remove_representation( assert element element_type = geometry.get_element_type(element) data = None - has_switched_from_data = False + data_removed_by_switch_representation = False if element_type and (geometry.is_mapped_representation(representation) or geometry.is_type_product(element)): representation = geometry.resolve_mapped_representation(representation) data = geometry.get_representation_data(representation) @@ -155,7 +155,7 @@ def remove_representation( for element in geometry.get_elements_of_type(element_type): obj = ifc.get_object(element) if obj: - has_switched_from_data = True + data_removed_by_switch_representation = True geometry.switch_from_representation(obj, representation) obj = ifc.get_object(element_type) if obj: @@ -164,12 +164,13 @@ def remove_representation( else: data = geometry.get_representation_data(representation) if data and geometry.has_data_users(data): - has_switched_from_data = True + data_removed_by_switch_representation = True geometry.switch_from_representation(obj, representation) ifc.run("geometry.unassign_representation", product=element, representation=representation) ifc.run("geometry.remove_representation", representation=representation) - if data and not has_switched_from_data: + + if data and not data_removed_by_switch_representation: geometry.delete_data(data) diff --git a/src/bonsai/bonsai/tool/geometry.py b/src/bonsai/bonsai/tool/geometry.py index 879df2adf0..83a9435665 100644 --- a/src/bonsai/bonsai/tool/geometry.py +++ b/src/bonsai/bonsai/tool/geometry.py @@ -1360,6 +1360,8 @@ class Geometry(bonsai.core.tool.Geometry): If no other representation present, will replace object with an empty. Method assumes that `obj` does have a current representation (it could be not `representation`). + + Will clean up old ``obj.data`` if no other users exist. """ element = tool.Ifc.get_entity(obj) assert element @@ -1378,7 +1380,11 @@ class Geometry(bonsai.core.tool.Geometry): # `representation` is the only representation for object. if new_representation is None: + old_data = obj.data + assert old_data is not None cls.recreate_object_with_data(obj, None) + if not cls.has_data_users(old_data): + cls.delete_data(old_data) return bonsai.core.geometry.switch_representation( diff --git a/src/bonsai/test/bim/feature/geometry.feature b/src/bonsai/test/bim/feature/geometry.feature index 9e1ac25245..3bbf22a5c2 100644 --- a/src/bonsai/test/bim/feature/geometry.feature +++ b/src/bonsai/test/bim/feature/geometry.feature @@ -102,8 +102,10 @@ Scenario: Remove representation - remove an active representation And I set "scene.BIMRootProperties.ifc_class" to "IfcWall" And I press "bim.assign_class" When the variable "representation_body" is "{ifc}.by_type('IfcShapeRepresentation')[0].id()" + And the variable "representation_context" is "{ifc}.by_type('IfcShapeRepresentation')[0].ContextOfItems.id()" And I press "bim.remove_representation(representation_id={representation_body})" Then the object "IfcWall/Cube" has no data + And the mesh "{representation_context}/{representation_body}" does not exist Scenario: Remove representation - remove an unloaded representation Given an empty IFC project diff --git a/src/bonsai/test/bim/test_feature.py b/src/bonsai/test/bim/test_feature.py index bcfcdfba47..fa5ccb36d0 100644 --- a/src/bonsai/test/bim/test_feature.py +++ b/src/bonsai/test/bim/test_feature.py @@ -1194,6 +1194,11 @@ def the_material_name_does_not_exist(name): assert bpy.data.materials.get(name) is None, "Material exists" +@then(parsers.parse('the mesh "{name}" does not exist')) +def the_mesh_name_does_not_exist(name: str) -> None: + assert bpy.data.meshes.get(name) is None, f"Mesh '{name}' exists" + + def get_ifc_material_by_name(name: str) -> Union[ifcopenshell.entity_instance, None]: ifc_file = tool.Ifc.get() material = next((m for m in ifc_file.by_type("IfcMaterial") if m.Name == name), None) diff --git a/src/bonsai/test/core/test_geometry.py b/src/bonsai/test/core/test_geometry.py index 75d6a6b728..c9e3392808 100644 --- a/src/bonsai/test/core/test_geometry.py +++ b/src/bonsai/test/core/test_geometry.py @@ -231,7 +231,6 @@ class TestRemoveRepresentation: geometry.switch_from_representation("type_obj", "representation").should_be_called() ifc.run("geometry.unassign_representation", product="type", representation="representation").should_be_called() ifc.run("geometry.remove_representation", representation="representation").should_be_called() - geometry.delete_data("data").should_be_called() subject.remove_representation(ifc, geometry, obj="obj", representation="mapped_rep") def test_removing_an_unused_mapped_representation(self, ifc, geometry): @@ -254,7 +253,6 @@ class TestRemoveRepresentation: "geometry.unassign_representation", product="element", representation="representation" ).should_be_called() ifc.run("geometry.remove_representation", representation="representation").should_be_called() - geometry.delete_data("data").should_be_called() subject.remove_representation(ifc, geometry, obj="obj", representation="representation") def test_removing_an_actively_used_representation(self, ifc, geometry): @@ -269,7 +267,6 @@ class TestRemoveRepresentation: "geometry.unassign_representation", product="element", representation="representation" ).should_be_called() ifc.run("geometry.remove_representation", representation="representation").should_be_called() - geometry.delete_data("data").should_be_called() subject.remove_representation(ifc, geometry, obj="obj", representation="representation") def test_removing_an_unused_representation(self, ifc, geometry):