diff --git a/src/ifcopenshell-python/ifcopenshell/api/control/assign_control.py b/src/ifcopenshell-python/ifcopenshell/api/control/assign_control.py index fd4471c9d8..867089137f 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/control/assign_control.py +++ b/src/ifcopenshell-python/ifcopenshell/api/control/assign_control.py @@ -40,8 +40,9 @@ class Usecase: :type relating_control: ifcopenshell.entity_instance.entity_instance :param related_object: The IfcObjectDefinition that is being controlled :type related_object: ifcopenshell.entity_instance.entity_instance - :return: The newly created IfcRelAssignsToControl - :rtype: ifcopenshell.entity_instance.entity_instance + :return: The newly created IfcRelAssignsToControl. If relationship already + existed before and wasn't changed then returns None. + :rtype: ifcopenshell.entity_instance.entity_instance, None Example: @@ -76,7 +77,7 @@ class Usecase: if self.settings["related_object"].HasAssignments: for assignment in self.settings["related_object"].HasAssignments: if ( - assignment.is_a("IfclRelAssignsToControl") + assignment.is_a("IfcRelAssignsToControl") and assignment.RelatingControl == self.settings["relating_control"] ): return @@ -86,6 +87,8 @@ class Usecase: controls = self.settings["relating_control"].Controls[0] if controls: + if self.settings["related_object"] in controls.RelatedObjects: + return related_objects = set(controls.RelatedObjects) related_objects.add(self.settings["related_object"]) controls.RelatedObjects = list(related_objects) diff --git a/src/ifcopenshell-python/test/api/control/test_assign_control.py b/src/ifcopenshell-python/test/api/control/test_assign_control.py new file mode 100644 index 0000000000..18670c86e4 --- /dev/null +++ b/src/ifcopenshell-python/test/api/control/test_assign_control.py @@ -0,0 +1,50 @@ +# 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 + + +class TestAssignControl(test.bootstrap.IFC4): + def test_run(self): + wall = self.file.createIfcWall() + control = ifcopenshell.api.run("cost.add_cost_schedule", self.file) + + # simple assignment + relation = ifcopenshell.api.run( + "control.assign_control", self.file, relating_control=control, related_object=wall + ) + assert len(self.file.by_type("IfcRelAssignsToControl")) == 1 + assert relation.RelatingControl == control + assert relation.RelatedObjects == (wall,) + + # trying to establish existing relationship + relation = ifcopenshell.api.run( + "control.assign_control", self.file, relating_control=control, related_object=wall + ) + assert relation is None + + # assigning same control to another object + wall1 = self.file.createIfcWall() + relation = ifcopenshell.api.run( + "control.assign_control", self.file, relating_control=control, related_object=wall1 + ) + assert relation is not None + assert len(self.file.by_type("IfcRelAssignsToControl")) == 1 + assert relation.RelatingControl == control + assert set(relation.RelatedObjects) == set((wall, wall1)) diff --git a/src/ifcopenshell-python/test/api/control/test_unassign_control.py b/src/ifcopenshell-python/test/api/control/test_unassign_control.py new file mode 100644 index 0000000000..c31014f008 --- /dev/null +++ b/src/ifcopenshell-python/test/api/control/test_unassign_control.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 + + +class TestUnassignControl(test.bootstrap.IFC4): + def test_run(self): + wall = self.file.createIfcWall() + control = ifcopenshell.api.run("cost.add_cost_schedule", self.file) + + # assign and unassign + relation = ifcopenshell.api.run( + "control.assign_control", self.file, relating_control=control, related_object=wall + ) + ifcopenshell.api.run("control.unassign_control", self.file, relating_control=control, related_object=wall) + assert len(self.file.by_type("IfcRelAssignsToControl")) == 0 + + # 1 control 2 related objects + wall1 = self.file.createIfcWall() + relation = ifcopenshell.api.run( + "control.assign_control", self.file, relating_control=control, related_object=wall + ) + ifcopenshell.api.run("control.assign_control", self.file, relating_control=control, related_object=wall1) + ifcopenshell.api.run("control.unassign_control", self.file, relating_control=control, related_object=wall1) + assert len(self.file.by_type("IfcRelAssignsToControl")) == 1 + assert relation.RelatedObjects == (wall,)