From e17ae4ef616cc89792865ef25d87dce9fa642c24 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Wed, 13 Oct 2021 11:55:03 +1100 Subject: [PATCH] Fix #1792. Regression caused by other improvements in editing object placement. --- .../api/geometry/edit_object_placement.py | 32 ++++++++++++------- .../geometry/test_edit_object_placement.py | 31 ++++++++++++++++++ 2 files changed, 52 insertions(+), 11 deletions(-) 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 5e0053c9aa..bc299b917f 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/geometry/edit_object_placement.py +++ b/src/ifcopenshell-python/ifcopenshell/api/geometry/edit_object_placement.py @@ -18,25 +18,30 @@ class Usecase: self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(self.file) if not self.settings["is_si"]: - self.settings["matrix"][0][3] *= self.unit_scale - self.settings["matrix"][1][3] *= self.unit_scale - self.settings["matrix"][2][3] *= self.unit_scale + self.convert_matrix_to_si(self.settings["matrix"]) children_settings = [] if not self.settings["should_transform_children"]: children_settings = self.get_children_settings(self.settings["product"].ObjectPlacement) placement_rel_to = self.get_placement_rel_to() - placement = self.file.createIfcLocalPlacement(placement_rel_to, self.get_relative_placement(placement_rel_to)) + relative_placement = self.get_relative_placement(placement_rel_to) + new_placement = self.file.createIfcLocalPlacement(placement_rel_to, relative_placement) + old_placement = self.settings["product"].ObjectPlacement + if old_placement: - self.settings["product"].ObjectPlacement = None inverses = self.file.get_inverse(old_placement) - for inverse in inverses: - ifcopenshell.util.element.replace_attribute(inverse, old_placement, placement) - old_placement.PlacementRelTo = None - ifcopenshell.util.element.remove_deep(self.file, old_placement) - self.settings["product"].ObjectPlacement = placement + if len(inverses) == 1: + self.settings["product"].ObjectPlacement = None + old_placement.PlacementRelTo = None + ifcopenshell.util.element.remove_deep(self.file, old_placement) + else: + for inverse in inverses: + if inverse.is_a("IfcLocalPlacement"): + ifcopenshell.util.element.replace_attribute(inverse, old_placement, new_placement) + + self.settings["product"].ObjectPlacement = new_placement ifcopenshell.api.run("owner.update_owner_history", self.file, **{"element": self.settings["product"]}) @@ -44,7 +49,12 @@ class Usecase: self.settings = settings self.execute() - return placement + return new_placement + + def convert_matrix_to_si(self, matrix): + matrix[0][3] *= self.unit_scale + matrix[1][3] *= self.unit_scale + matrix[2][3] *= self.unit_scale def get_placement_rel_to(self): if getattr(self.settings["product"], "ContainedInStructure", None): diff --git a/src/ifcopenshell-python/test/api/geometry/test_edit_object_placement.py b/src/ifcopenshell-python/test/api/geometry/test_edit_object_placement.py index 339e06e5aa..f2df16ff87 100644 --- a/src/ifcopenshell-python/test/api/geometry/test_edit_object_placement.py +++ b/src/ifcopenshell-python/test/api/geometry/test_edit_object_placement.py @@ -85,6 +85,37 @@ class TestEditObjectPlacement(test.bootstrap.IFC4): with pytest.raises(RuntimeError): self.file.by_id(element_id) + def test_changing_an_object_placement_used_by_other_products(self): + ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcProject") + ifcopenshell.api.run("unit.assign_unit", self.file) + element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + matrix1 = numpy.array( + ( + (1.0, 0.0, 0.0, 1.0), + (0.0, 1.0, 0.0, 2.0), + (0.0, 0.0, 1.0, 3.0), + (0.0, 0.0, 0.0, 1.0), + ) + ) + matrix2 = numpy.array( + ( + (1.0, 0.0, 0.0, 4.0), + (0.0, 1.0, 0.0, 5.0), + (0.0, 0.0, 1.0, 6.0), + (0.0, 0.0, 0.0, 1.0), + ) + ) + ifcopenshell.api.run( + "geometry.edit_object_placement", self.file, product=element, matrix=matrix1.copy(), is_si=False + ) + element2.ObjectPlacement = element.ObjectPlacement + ifcopenshell.api.run( + "geometry.edit_object_placement", self.file, product=element, matrix=matrix2.copy(), is_si=False + ) + assert numpy.array_equal(ifcopenshell.util.placement.get_local_placement(element.ObjectPlacement), matrix2) + assert element.ObjectPlacement != element2.ObjectPlacement + def test_changing_placements_relative_to_a_spatial_container(self): ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcProject") ifcopenshell.api.run("unit.assign_unit", self.file)