diff --git a/src/ifcopenshell-python/ifcopenshell/api/root/copy_class.py b/src/ifcopenshell-python/ifcopenshell/api/root/copy_class.py index 531e34480b..4224bfb95b 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/root/copy_class.py +++ b/src/ifcopenshell-python/ifcopenshell/api/root/copy_class.py @@ -78,9 +78,10 @@ class Usecase: if to_element.ObjectPlacement: new_opening.ObjectPlacement.PlacementRelTo = to_element.ObjectPlacement # For now, we do copy opening representations - new_opening.Representation = ifcopenshell.util.element.copy_deep( - self.file, opening.Representation - ) + if opening.Representation: + new_opening.Representation = ifcopenshell.util.element.copy_deep( + self.file, opening.Representation + ) elif inverse.is_a("IfcRelFillsElement"): continue elif inverse.is_a("IfcRelConnectsPathElements"): diff --git a/src/ifcopenshell-python/ifcopenshell/api/root/remove_product.py b/src/ifcopenshell-python/ifcopenshell/api/root/remove_product.py index 0181924b47..38973f973b 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/root/remove_product.py +++ b/src/ifcopenshell-python/ifcopenshell/api/root/remove_product.py @@ -53,7 +53,24 @@ class Usecase: # TODO: remove object placement and other relationships for inverse in self.file.get_inverse(self.settings["product"]): - if inverse.is_a("IfcRelFillsElement"): + if inverse.is_a("IfcRelDefinesByProperties"): + ifcopenshell.api.run( + "pset.remove_pset", + self.file, + product=self.settings["product"], + pset=inverse.RelatingPropertyDefinition, + ) + elif inverse.is_a("IfcRelAssociatesMaterial"): + ifcopenshell.api.run("material.unassign_material", self.file, product=self.settings["product"]) + elif inverse.is_a("IfcRelDefinesByType"): + if inverse.RelatingType == self.settings["product"]: + for related_object in inverse.RelatedObjects: + ifcopenshell.api.run("type.unassign_type", self.file, related_object=related_object) + else: + ifcopenshell.api.run("type.unassign_type", self.file, related_object=self.settings["product"]) + elif inverse.is_a("IfcRelSpaceBoundary"): + self.file.remove(inverse) + elif inverse.is_a("IfcRelFillsElement"): self.file.remove(inverse) elif inverse.is_a("IfcRelVoidsElement"): self.file.remove(inverse) 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 e30ca2a1d4..48b4a81305 100644 --- a/src/ifcopenshell-python/test/api/root/test_remove_product.py +++ b/src/ifcopenshell-python/test/api/root/test_remove_product.py @@ -76,7 +76,7 @@ class TestRemoveProduct(test.bootstrap.IFC4): total_entities = len(list(self.file)) assert len(self.file.by_type("IfcShapeRepresentation")) == 2 ifcopenshell.api.run("root.remove_product", self.file, product=element) - assert len(list(self.file)) == total_entities - 5 + assert len(list(self.file)) == total_entities - 6 assert len(self.file.by_type("IfcProductDefinitionShape")) == 0 assert len(self.file.by_type("IfcShapeRepresentation")) == 1 assert len(self.file.by_type("IfcMappedItem")) == 0 @@ -195,3 +195,46 @@ class TestRemoveProduct(test.bootstrap.IFC4): assert len(self.file.by_type("IfcRelConnectsPathElements")) == 0 assert len(self.file.by_type("IfcColumn")) == 1 assert len(self.file.by_type("IfcBeam")) == 0 + + def test_removing_all_property_relationships_of_an_element(self): + element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + pset = ifcopenshell.api.run("pset.add_pset", self.file, product=element, name="Foo_Bar") + ifcopenshell.api.run("pset.edit_pset", self.file, pset=pset, properties={"Foo": "Bar"}) + ifcopenshell.api.run("root.remove_product", self.file, product=element) + assert not self.file.by_type("IfcRelDefinesByProperties") + assert not self.file.by_type("IfcPropertySet") + assert not self.file.by_type("IfcPropertySingleValue") + + def test_removing_all_material_relationships_of_an_element(self): + element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + material = ifcopenshell.api.run("material.add_material", self.file, name="Foo") + ifcopenshell.api.run("material.assign_material", self.file, product=element, material=material) + ifcopenshell.api.run("root.remove_product", self.file, product=element) + assert not self.file.by_type("IfcRelAssociatesMaterial") + assert self.file.by_type("IfcMaterial") + + def test_removing_all_type_relationships_of_an_element(self): + element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + element_type = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") + ifcopenshell.api.run("type.assign_type", self.file, related_object=element, relating_type=element_type) + ifcopenshell.api.run("root.remove_product", self.file, product=element) + assert not self.file.by_type("IfcRelDefinesByType") + assert self.file.by_type("IfcWallType") + + def test_removing_all_type_relationships_of_an_element_type(self): + element1 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + element_type = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") + ifcopenshell.api.run("type.assign_type", self.file, related_object=element1, relating_type=element_type) + ifcopenshell.api.run("type.assign_type", self.file, related_object=element2, relating_type=element_type) + ifcopenshell.api.run("root.remove_product", self.file, product=element_type) + assert not self.file.by_type("IfcRelDefinesByType") + assert self.file.by_type("IfcWall") + + def test_removing_all_space_boundaries_of_an_element(self): + element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + boundary = self.file.createIfcRelSpaceBoundary2ndLevel( + GlobalId=ifcopenshell.guid.new(), RelatedBuildingElement=element + ) + ifcopenshell.api.run("root.remove_product", self.file, product=element) + assert not self.file.by_type("IfcRelSpaceBoundary")