diff --git a/src/ifcopenshell-python/ifcopenshell/api/project/append_asset.py b/src/ifcopenshell-python/ifcopenshell/api/project/append_asset.py index 5eb502ce99..0274521deb 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/project/append_asset.py +++ b/src/ifcopenshell-python/ifcopenshell/api/project/append_asset.py @@ -323,12 +323,16 @@ class Usecase: element_identity = element.wrapped_data.identity() - # check if inverse element were created before - if self.reuse_identities.get(element_identity) is not None: - return - - new = self.file.create_entity(element.is_a()) - self.reuse_identities[element_identity] = new + # Check if inverse element was created before. + # Still need to recreate it again - e.g. it could be some rel + # that now needs it's RelatingObjects to be extended by the current asset. + if (new := self.reuse_identities.get(element_identity)) is not None: + # Currently known cases requiring attributes reassignment are rels. + if not new.is_a("IfcRelationship"): + return + else: + new = self.file.create_entity(element.is_a()) + self.reuse_identities[element_identity] = new for i, attribute in enumerate(element): new_attribute = None @@ -346,11 +350,21 @@ class Usecase: new[i] = new_attribute def is_another_asset(self, element: ifcopenshell.entity_instance) -> bool: + """Is IFC entity from inverse attribute is another asset to append that should be skipped.""" + + def by_guid(guid: str) -> Union[ifcopenshell.entity_instance, None]: + try: + return self.file.by_guid(guid) + except RuntimeError: + return None + if element == self.settings["element"]: return False elif element.is_a("IfcFeatureElement"): # Feature elements match the target class but aren't considered "assets" return False + elif element.is_a("IfcRoot") and by_guid(element.GlobalId) is not None: + return False elif element.is_a(self.target_class): return True elif self.target_class == "IfcProduct" and element.is_a("IfcTypeProduct"): diff --git a/src/ifcopenshell-python/test/api/project/test_append_asset.py b/src/ifcopenshell-python/test/api/project/test_append_asset.py index e467bd4937..224d2f9d1b 100644 --- a/src/ifcopenshell-python/test/api/project/test_append_asset.py +++ b/src/ifcopenshell-python/test/api/project/test_append_asset.py @@ -433,6 +433,24 @@ class TestAppendAssetIFC2X3(test.bootstrap.IFC2X3): del shading_colour_info["id"], shading_colour_info["type"] assert shading_colour_info == shading_attrs["SurfaceColour"] + def test_update_rels_appending_subsequent_assets(self): + library = ifcopenshell.api.project.create_file(version=self.file.schema) + element1 = ifcopenshell.api.root.create_entity(library, ifc_class="IfcWall") + pset = ifcopenshell.api.pset.add_pset(library, product=element1, name="Test") + element2 = ifcopenshell.api.root.create_entity(library, ifc_class="IfcWall") + ifcopenshell.api.pset.assign_pset(library, pset=pset, products=[element2]) + + reuse_identities = {} + element1_ = ifcopenshell.api.project.append_asset( + self.file, library, element1, reuse_identities=reuse_identities + ) + element2_ = ifcopenshell.api.project.append_asset( + self.file, library, element2, reuse_identities=reuse_identities + ) + pset_data = ifcopenshell.util.element.get_psets(element1_) + assert "Test" in pset_data + assert ifcopenshell.util.element.get_psets(element2_) == pset_data + class TestAppendAssetIFC4(test.bootstrap.IFC4, TestAppendAssetIFC2X3): # NOTE: breaks in IFC2X3 since IfcProfileDef doesn't have "HasProperties" inverse in ifc2x3