From 846dbc341d9ee3ad6591b60e5020d19cca207f90 Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Fri, 14 Jul 2023 15:47:36 +0500 Subject: [PATCH] root.copy_class to support copying ports in ifc2x3 --- .../ifcopenshell/api/root/copy_class.py | 48 ++++++++++++------- .../test/api/root/test_copy_class.py | 12 +++++ 2 files changed, 44 insertions(+), 16 deletions(-) diff --git a/src/ifcopenshell-python/ifcopenshell/api/root/copy_class.py b/src/ifcopenshell-python/ifcopenshell/api/root/copy_class.py index a2618078e1..061b695d24 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/root/copy_class.py +++ b/src/ifcopenshell-python/ifcopenshell/api/root/copy_class.py @@ -86,24 +86,40 @@ class Usecase: inverse.RelatedObjects = [to_element] pset = ifcopenshell.util.element.copy_deep(self.file, inverse.RelatingPropertyDefinition) inverse.RelatingPropertyDefinition = pset - elif inverse.is_a("IfcRelNests") and inverse.RelatingObject == from_element: - ports = [e for e in inverse.RelatedObjects if e.is_a("IfcDistributionPort")] - if ports: - new_ports = [ifcopenshell.api.run("root.copy_class", self.file, product=p) for p in ports] - inverse = ifcopenshell.util.element.copy(self.file, inverse) + elif ( + inverse.is_a("IfcRelNests") + and inverse.RelatingObject == from_element + or inverse.is_a("IfcRelConnectsPortToElement") + and inverse.RelatedElement == from_element + ): + # IfcRelConnectsPortToElement was used in IFC2X3 + if inverse.is_a("IfcRelNests"): + ports = [e for e in inverse.RelatedObjects if e.is_a("IfcDistributionPort")] + else: # IfcRelConnectsPortToElement + ports = [inverse.RelatingPort] + if not ports: + continue + new_ports = [ifcopenshell.api.run("root.copy_class", self.file, product=p) for p in ports] + inverse = ifcopenshell.util.element.copy(self.file, inverse) + + if inverse.is_a("IfcRelNests"): inverse.RelatingObject = to_element inverse.RelatedObjects = new_ports - for port in new_ports: - ifcopenshell.api.run("system.unassign_port", self.file, element=from_element, port=port) - matrix = ifcopenshell.util.placement.get_local_placement(port.ObjectPlacement) - ifcopenshell.api.run( - "geometry.edit_object_placement", - self.file, - product=port, - matrix=matrix, - is_si=False, - should_transform_children=False, - ) + else: + inverse.RelatedElement = to_element + inverse.RelatingPort = new_ports[0] + + for port in new_ports: + ifcopenshell.api.run("system.unassign_port", self.file, element=from_element, port=port) + matrix = ifcopenshell.util.placement.get_local_placement(port.ObjectPlacement) + ifcopenshell.api.run( + "geometry.edit_object_placement", + self.file, + product=port, + matrix=matrix, + is_si=False, + should_transform_children=False, + ) elif inverse.is_a("IfcRelAggregates") and inverse.RelatingObject == from_element: continue elif inverse.is_a("IfcRelContainedInSpatialStructure") and inverse.RelatingStructure == from_element: diff --git a/src/ifcopenshell-python/test/api/root/test_copy_class.py b/src/ifcopenshell-python/test/api/root/test_copy_class.py index 9512fe1014..ab65d8ccfa 100644 --- a/src/ifcopenshell-python/test/api/root/test_copy_class.py +++ b/src/ifcopenshell-python/test/api/root/test_copy_class.py @@ -232,3 +232,15 @@ class TestCopyClass(test.bootstrap.IFC4): new = ifcopenshell.api.run("root.copy_class", self.file, product=element) assert len(self.file.by_type("IfcRelAssignsToGroup")) == 1 assert new.HasAssignments[0].RelatingGroup == group + + +class TestCopyClassIFC2X3(test.bootstrap.IFC2X3): + def test_copying_distribution_ports_bug(self): + element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcFlowTerminal") + port = ifcopenshell.api.run("system.add_port", self.file) + ifcopenshell.api.run("system.assign_port", self.file, element=element, port=port) + new = ifcopenshell.api.run("root.copy_class", self.file, product=element) + new_ports = ifcopenshell.util.system.get_ports(new) + assert port not in new_ports + assert new_ports[0].is_a("IfcDistributionPort") + assert ifcopenshell.util.system.get_ports(element) == [port]