From 1a881911737f7c50fe1166d5889107c73f1ea482 Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Thu, 3 Aug 2023 14:46:59 +0500 Subject: [PATCH] remove_product to remove object placement too previously it wasn't deleting object placement when you removed the objects (and related elements like IfcDirections etc) and working on project long enough you might had a bunch of orphaned data in it --- .../ifcopenshell/api/root/remove_product.py | 5 ++++ .../test/api/root/test_remove_product.py | 28 +++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/src/ifcopenshell-python/ifcopenshell/api/root/remove_product.py b/src/ifcopenshell-python/ifcopenshell/api/root/remove_product.py index 17752a6168..c3577a43e0 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/root/remove_product.py +++ b/src/ifcopenshell-python/ifcopenshell/api/root/remove_product.py @@ -65,6 +65,11 @@ class Usecase: representations = self.settings["product"].Representation.Representations or [] else: representations = [] + + object_placement = self.settings["product"].ObjectPlacement + if object_placement and self.file.get_total_inverses(object_placement) == 1: + self.settings["product"].ObjectPlacement = None # remove the inverse for remove_deep2 to work + ifcopenshell.util.element.remove_deep2(self.file, object_placement) elif self.settings["product"].is_a("IfcTypeProduct"): representations = [rm.MappedRepresentation for rm in self.settings["product"].RepresentationMaps or []] for representation in representations: diff --git a/src/ifcopenshell-python/test/api/root/test_remove_product.py b/src/ifcopenshell-python/test/api/root/test_remove_product.py index c37048874a..d45b306e76 100644 --- a/src/ifcopenshell-python/test/api/root/test_remove_product.py +++ b/src/ifcopenshell-python/test/api/root/test_remove_product.py @@ -26,6 +26,34 @@ class TestRemoveProduct(test.bootstrap.IFC4): ifcopenshell.api.run("root.remove_product", self.file, product=element) assert len(self.file.by_type("IfcWall")) == 0 + def test_removing_an_element_local_placement(self): + # just removing the product with the placement + element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + placement = ifcopenshell.api.run("geometry.edit_object_placement", self.file, product=element) + ifcopenshell.api.run("root.remove_product", self.file, product=element) + assert len(self.file.by_type("IfcObjectPlacement")) == 0 + + # removing the product that shares the placement with other product + element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + placement = ifcopenshell.api.run("geometry.edit_object_placement", self.file, product=element) + element1 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + element1.ObjectPlacement = placement + ifcopenshell.api.run("root.remove_product", self.file, product=element) + assert len(self.file.by_type("IfcObjectPlacement")) == 1 + ifcopenshell.api.run("root.remove_product", self.file, product=element1) + assert len(self.file.by_type("IfcObjectPlacement")) == 0 + + # removing the product that's placement used as a reference point for another placement + element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + placement = ifcopenshell.api.run("geometry.edit_object_placement", self.file, product=element) + element1 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + placement1 = ifcopenshell.api.run("geometry.edit_object_placement", self.file, product=element1) + placement.PlacementRelTo = placement1 + ifcopenshell.api.run("root.remove_product", self.file, product=element) + assert len(self.file.by_type("IfcObjectPlacement")) == 1 + ifcopenshell.api.run("root.remove_product", self.file, product=element1) + assert len(self.file.by_type("IfcObjectPlacement")) == 0 + def test_removing_all_representations_of_an_element(self): ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcProject") ifcopenshell.api.run("unit.assign_unit", self.file)