diff --git a/src/ifcopenshell-python/ifcopenshell/api/system/assign_port.py b/src/ifcopenshell-python/ifcopenshell/api/system/assign_port.py new file mode 100644 index 0000000000..2473301327 --- /dev/null +++ b/src/ifcopenshell-python/ifcopenshell/api/system/assign_port.py @@ -0,0 +1,69 @@ +# IfcOpenShell - IFC toolkit and geometry engine +# Copyright (C) 2022 Dion Moult +# +# This file is part of IfcOpenShell. +# +# IfcOpenShell is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# IfcOpenShell is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with IfcOpenShell. If not, see . + +import ifcopenshell +import ifcopenshell.api + + +class Usecase: + def __init__(self, file, **settings): + self.file = file + self.settings = { + "element": None, + "port": None, + } + for key, value in settings.items(): + self.settings[key] = value + + def execute(self): + if self.file.schema == "IFC2X3": + return self.execute_ifc2x3() + + rels = self.settings["element"].IsNestedBy or [] + + for rel in rels: + if self.settings["port"] in rel.RelatedObjects: + return + + if not rels: + return self.file.create_entity( + "IfcRelNests", + GlobalId=ifcopenshell.guid.new(), + OwnerHistory=ifcopenshell.api.run("owner.create_owner_history", self.file), + RelatedObjects=[self.settings["port"]], + RelatingObject=self.settings["element"], + ) + + rel = rels[0] + related_objects = set(rel.RelatedObjects) or set() + related_objects.add(self.settings["port"]) + rel.RelatedObjects = list(related_objects) + ifcopenshell.api.run("owner.update_owner_history", self.file, **{"element": rel}) + return rel + + def execute_ifc2x3(self): + for rel in self.settings["element"].HasPorts or []: + if rel.RelatingPort == self.settings["port"]: + return + return self.file.create_entity( + "IfcRelConnectsPortToElement", + GlobalId=ifcopenshell.guid.new(), + OwnerHistory=ifcopenshell.api.run("owner.create_owner_history", self.file), + RelatingPort=self.settings["port"], + RelatedElement=self.settings["element"], + ) diff --git a/src/ifcopenshell-python/ifcopenshell/api/system/unassign_port.py b/src/ifcopenshell-python/ifcopenshell/api/system/unassign_port.py new file mode 100644 index 0000000000..96b3896729 --- /dev/null +++ b/src/ifcopenshell-python/ifcopenshell/api/system/unassign_port.py @@ -0,0 +1,51 @@ +# IfcOpenShell - IFC toolkit and geometry engine +# Copyright (C) 2022 Dion Moult +# +# This file is part of IfcOpenShell. +# +# IfcOpenShell is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# IfcOpenShell is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with IfcOpenShell. If not, see . + +import ifcopenshell +import ifcopenshell.api + + +class Usecase: + def __init__(self, file, **settings): + self.file = file + self.settings = { + "element": None, + "port": None, + } + for key, value in settings.items(): + self.settings[key] = value + + def execute(self): + if self.file.schema == "IFC2X3": + return self.execute_ifc2x3() + + for rel in self.settings["element"].IsNestedBy or []: + if self.settings["port"] in rel.RelatedObjects: + if len(rel.RelatedObjects) == 1: + self.file.remove(rel) + return + related_objects = set(rel.RelatedObjects) or set() + related_objects.remove(self.settings["port"]) + rel.RelatedObjects = list(related_objects) + ifcopenshell.api.run("owner.update_owner_history", self.file, **{"element": rel}) + + def execute_ifc2x3(self): + for rel in self.settings["element"].HasPorts or []: + if rel.RelatingPort == self.settings["port"]: + self.file.remove(rel) + return diff --git a/src/ifcopenshell-python/test/api/system/test_assign_port.py b/src/ifcopenshell-python/test/api/system/test_assign_port.py new file mode 100644 index 0000000000..b610d463fa --- /dev/null +++ b/src/ifcopenshell-python/test/api/system/test_assign_port.py @@ -0,0 +1,43 @@ +# IfcOpenShell - IFC toolkit and geometry engine +# Copyright (C) 2022 Dion Moult +# +# This file is part of IfcOpenShell. +# +# IfcOpenShell is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# IfcOpenShell is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with IfcOpenShell. If not, see . + +import test.bootstrap +import ifcopenshell.api +import ifcopenshell.util.system + + +class TestAssignPort(test.bootstrap.IFC4): + def test_assigning_a_port_once_only(self): + port = self.file.createIfcDistributionPort() + element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcChiller") + ifcopenshell.api.run("system.assign_port", self.file, element=element, port=port) + assert element.IsNestedBy[0].RelatedObjects == (port,) + assert ifcopenshell.util.system.get_ports(element) == [port] + ifcopenshell.api.run("system.assign_port", self.file, element=element, port=port) + assert ifcopenshell.util.system.get_ports(element) == [port] + + +class TestAssignPortIFC2X3(test.bootstrap.IFC2X3): + def test_assigning_a_port_once_only(self): + port = self.file.createIfcDistributionPort() + element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcFlowSegment") + ifcopenshell.api.run("system.assign_port", self.file, element=element, port=port) + assert element.HasPorts[0].RelatingPort == port + assert ifcopenshell.util.system.get_ports(element) == [port] + ifcopenshell.api.run("system.assign_port", self.file, element=element, port=port) + assert ifcopenshell.util.system.get_ports(element) == [port] diff --git a/src/ifcopenshell-python/test/api/system/test_unassign_port.py b/src/ifcopenshell-python/test/api/system/test_unassign_port.py new file mode 100644 index 0000000000..2edafa6c1d --- /dev/null +++ b/src/ifcopenshell-python/test/api/system/test_unassign_port.py @@ -0,0 +1,39 @@ +# IfcOpenShell - IFC toolkit and geometry engine +# Copyright (C) 2022 Dion Moult +# +# This file is part of IfcOpenShell. +# +# IfcOpenShell is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# IfcOpenShell is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with IfcOpenShell. If not, see . + +import test.bootstrap +import ifcopenshell.api +import ifcopenshell.util.system + + +class TestAssignPort(test.bootstrap.IFC4): + def test_assigning_a_port_once_only(self): + port = self.file.createIfcDistributionPort() + element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcChiller") + ifcopenshell.api.run("system.assign_port", self.file, element=element, port=port) + ifcopenshell.api.run("system.unassign_port", self.file, element=element, port=port) + assert ifcopenshell.util.system.get_ports(element) == [] + + +class TestAssignPortIFC2X3(test.bootstrap.IFC2X3): + def test_assigning_a_port_once_only(self): + port = self.file.createIfcDistributionPort() + element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcFlowSegment") + ifcopenshell.api.run("system.assign_port", self.file, element=element, port=port) + ifcopenshell.api.run("system.unassign_port", self.file, element=element, port=port) + assert ifcopenshell.util.system.get_ports(element) == []