From 3eb7c7a6a1a728756b8b63ac32345e6282d9896e Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Fri, 17 Sep 2021 17:13:20 +1000 Subject: [PATCH] Fix bug where assigning a new container would shift object placements incorrectly due to SI unit conversion --- .../api/geometry/edit_object_placement.py | 2 - .../api/spatial/assign_container.py | 1 + .../test/api/spatial/test_assign_container.py | 79 +++++++++++++++++++ 3 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 src/ifcopenshell-python/test/api/spatial/test_assign_container.py diff --git a/src/ifcopenshell-python/ifcopenshell/api/geometry/edit_object_placement.py b/src/ifcopenshell-python/ifcopenshell/api/geometry/edit_object_placement.py index 93536bddfb..5e0053c9aa 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/geometry/edit_object_placement.py +++ b/src/ifcopenshell-python/ifcopenshell/api/geometry/edit_object_placement.py @@ -13,7 +13,6 @@ class Usecase: self.settings[key] = value def execute(self): - print('EXECUTING', self.settings["product"]) if not hasattr(self.settings["product"], "ObjectPlacement"): return self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(self.file) @@ -25,7 +24,6 @@ class Usecase: children_settings = [] if not self.settings["should_transform_children"]: - print("THIS IS RUNNING") children_settings = self.get_children_settings(self.settings["product"].ObjectPlacement) placement_rel_to = self.get_placement_rel_to() diff --git a/src/ifcopenshell-python/ifcopenshell/api/spatial/assign_container.py b/src/ifcopenshell-python/ifcopenshell/api/spatial/assign_container.py index fe46877cae..40c8744b94 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/spatial/assign_container.py +++ b/src/ifcopenshell-python/ifcopenshell/api/spatial/assign_container.py @@ -51,4 +51,5 @@ class Usecase: self.file, product=self.settings["product"], matrix=ifcopenshell.util.placement.get_local_placement(self.settings["product"].ObjectPlacement), + is_si=False, ) diff --git a/src/ifcopenshell-python/test/api/spatial/test_assign_container.py b/src/ifcopenshell-python/test/api/spatial/test_assign_container.py new file mode 100644 index 0000000000..a91857a32c --- /dev/null +++ b/src/ifcopenshell-python/test/api/spatial/test_assign_container.py @@ -0,0 +1,79 @@ +import numpy +import pytest +import test.bootstrap +import ifcopenshell.api +import ifcopenshell.util.element +import ifcopenshell.util.placement + + +class TestEditObjectPlacement(test.bootstrap.IFC4): + def test_assigning_a_container(self): + element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcBuilding") + subelement = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + ifcopenshell.api.run("spatial.assign_container", self.file, product=subelement, relating_structure=element) + assert ifcopenshell.util.element.get_container(subelement) == element + + def test_doing_nothing_if_the_container_is_already_assigned(self): + element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcBuilding") + subelement = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + ifcopenshell.api.run("spatial.assign_container", self.file, product=subelement, relating_structure=element) + total_elements = len([e for e in self.file]) + ifcopenshell.api.run("spatial.assign_container", self.file, product=subelement, relating_structure=element) + assert len([e for e in self.file]) == total_elements + + def test_that_old_containment_relationships_are_updated_if_they_still_contain_elements(self): + element1 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcBuilding") + element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcBuilding") + subelement1 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + subelement2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + ifcopenshell.api.run("spatial.assign_container", self.file, product=subelement1, relating_structure=element1) + ifcopenshell.api.run("spatial.assign_container", self.file, product=subelement2, relating_structure=element1) + rel = subelement1.ContainedInStructure[0] + assert len(rel.RelatedElements) == 2 + ifcopenshell.api.run("spatial.assign_container", self.file, product=subelement1, relating_structure=element2) + assert len(rel.RelatedElements) == 1 + + def test_that_old_containment_relationships_are_purged_if_no_more_elements_are_contained(self): + element1 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcBuilding") + element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcBuilding") + subelement1 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + ifcopenshell.api.run("spatial.assign_container", self.file, product=subelement1, relating_structure=element1) + rel_id = subelement1.ContainedInStructure[0].id() + ifcopenshell.api.run("spatial.assign_container", self.file, product=subelement1, relating_structure=element2) + with pytest.raises(RuntimeError): + self.file.by_id(rel_id) + + def test_assigning_a_container_does_not_shift_object_placements(self): + ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcProject") + ifcopenshell.api.run("unit.assign_unit", self.file) + element1 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcBuilding") + element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcBuilding") + subelement = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + ifcopenshell.api.run("spatial.assign_container", self.file, product=subelement, relating_structure=element1) + matrix1 = numpy.array( + ( + (1.0, 0.0, 0.0, 1.0), + (0.0, 1.0, 0.0, 1.0), + (0.0, 0.0, 1.0, 1.0), + (0.0, 0.0, 0.0, 1.0), + ) + ) + matrix2 = numpy.array( + ( + (1.0, 0.0, 0.0, 2.0), + (0.0, 1.0, 0.0, 2.0), + (0.0, 0.0, 1.0, 2.0), + (0.0, 0.0, 0.0, 1.0), + ) + ) + ifcopenshell.api.run( + "geometry.edit_object_placement", self.file, product=element1, matrix=matrix1.copy(), is_si=False + ) + ifcopenshell.api.run( + "geometry.edit_object_placement", self.file, product=element2, matrix=matrix2.copy(), is_si=False + ) + ifcopenshell.api.run( + "geometry.edit_object_placement", self.file, product=subelement, matrix=matrix1.copy(), is_si=False + ) + ifcopenshell.api.run("spatial.assign_container", self.file, product=subelement, relating_structure=element2) + assert numpy.array_equal(ifcopenshell.util.placement.get_local_placement(subelement.ObjectPlacement), matrix1)