From 2129350ab725af37dfc2876eeb5130a74642ca29 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Sat, 29 Jun 2024 17:03:26 +1000 Subject: [PATCH] Fix bug where MergeProject didn't clean up duplicate CRS and coordinate operations --- src/ifcpatch/ifcpatch/recipes/MergeProject.py | 13 +++++++++--- src/ifcpatch/test/test_MergeProject.py | 21 ++++++++++++++++++- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/ifcpatch/ifcpatch/recipes/MergeProject.py b/src/ifcpatch/ifcpatch/recipes/MergeProject.py index 6bbc9bc9de..a65cbeeaac 100644 --- a/src/ifcpatch/ifcpatch/recipes/MergeProject.py +++ b/src/ifcpatch/ifcpatch/recipes/MergeProject.py @@ -90,11 +90,18 @@ class Patcher: equivalent_existing_context = self.get_equivalent_existing_context(added_context) if equivalent_existing_context: for inverse in self.file.get_inverse(added_context): + if self.file.schema != "IFC2X3": + if inverse.is_a("IfcCoordinateOperation"): + to_delete.add(inverse.id()) + continue ifcopenshell.util.element.replace_attribute(inverse, added_context, equivalent_existing_context) - to_delete.add(added_context) + to_delete.add(added_context.id()) - for added_context in to_delete: - ifcopenshell.util.element.remove_deep2(self.file, added_context) + for element_id in to_delete: + try: + ifcopenshell.util.element.remove_deep2(self.file, self.file.by_id(element_id)) + except: + pass def get_equivalent_existing_context( self, added_context: ifcopenshell.entity_instance diff --git a/src/ifcpatch/test/test_MergeProject.py b/src/ifcpatch/test/test_MergeProject.py index 93e9b9bbb5..685f4326a5 100644 --- a/src/ifcpatch/test/test_MergeProject.py +++ b/src/ifcpatch/test/test_MergeProject.py @@ -33,9 +33,11 @@ class TestMergeProject(test.bootstrap.IFC4): if ifc_file is None: ifc_file = ifcopenshell.file(schema=self.file.schema) - project = ifcopenshell.api.run("root.create_entity", ifc_file, ifc_class="IfcProject") + ifcopenshell.api.run("root.create_entity", ifc_file, ifc_class="IfcProject") unit = ifcopenshell.api.run("unit.add_si_unit", ifc_file, unit_type="LENGTHUNIT", prefix=prefix) ifcopenshell.api.run("unit.assign_unit", ifc_file, units=[unit]) + model = ifcopenshell.api.context.add_context(ifc_file, "Model") + ifcopenshell.api.context.add_context(ifc_file, "Model", "Body", "MODEL_VIEW", parent=model) matrix = np.eye(4) matrix[:, 3] = (1, 2, 3, 1) @@ -50,6 +52,7 @@ class TestMergeProject(test.bootstrap.IFC4): second_file.write(temp_path) output = ifcpatch.execute({"file": self.file, "recipe": "MergeProject", "arguments": [str(temp_path)]}) + assert self.file == output assert len(output.by_type("IfcWall")) == 2 wall1, wall2 = output.by_type("IfcWall") @@ -61,6 +64,22 @@ class TestMergeProject(test.bootstrap.IFC4): matrix[:, 3] = (1, 2, 3, 1) assert to_tuple(placement1) == to_tuple(placement2) == to_tuple(matrix) + def test_reusing_geometric_contexts(self): + self.file = self.setup_project(self.file) + second_file = self.setup_project() + output = ifcpatch.execute({"file": self.file, "recipe": "MergeProject", "arguments": [second_file]}) + assert len(output.by_type("IfcGeometricRepresentationContext")) == 2 + + def test_using_the_georeferencing_of_the_original_project(self): + if self.file.schema == "IFC2X3": + return + self.file = self.setup_project(self.file) + second_file = self.setup_project() + ifcopenshell.api.georeference.add_georeferencing(self.file) + ifcopenshell.api.georeference.add_georeferencing(second_file) + output = ifcpatch.execute({"file": self.file, "recipe": "MergeProject", "arguments": [second_file]}) + assert len(output.by_type("IfcProjectedCRS")) == 1 + assert len(output.by_type("IfcMapConversion")) == 1 class TestMergeProjectIFC2X3(test.bootstrap.IFC2X3, TestMergeProject): pass