diff --git a/src/bonsai/bonsai/bim/module/debug/operator.py b/src/bonsai/bonsai/bim/module/debug/operator.py index 966d7006fe..7e89eda418 100644 --- a/src/bonsai/bonsai/bim/module/debug/operator.py +++ b/src/bonsai/bonsai/bim/module/debug/operator.py @@ -183,6 +183,9 @@ class ValidateIfcAssets(bpy.types.Operator): ifc_classes = { "IfcMaterial": "Name", + "IfcMaterialLayerSet": "LayerSetName", + "IfcMaterialConstituentSet": "Name", + "IfcMaterialProfileSet": "Name", "IfcProfileDef": "ProfileName", "IfcPresentationStyle": "Name", } diff --git a/src/ifcopenshell-python/ifcopenshell/api/project/append_asset.py b/src/ifcopenshell-python/ifcopenshell/api/project/append_asset.py index 00c11dc72c..f074129b1f 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/project/append_asset.py +++ b/src/ifcopenshell-python/ifcopenshell/api/project/append_asset.py @@ -40,6 +40,7 @@ APPENDABLE_ASSET = Literal[ "IfcPresentationStyle", ] APPENDABLE_ASSET_TYPES = get_args(APPENDABLE_ASSET) +MATERIAL_SETS = ("IfcMaterialLayerSet", "IfcMaterialConstituentSet", "IfcMaterialProfileSet") def append_asset( @@ -261,6 +262,15 @@ class Usecase: elif element.is_a("IfcMaterial"): name = element.Name return next((e for e in self.file.by_type("IfcMaterial") if e.Name == name), None) + + elif element in MATERIAL_SETS: + ifc_class = element.is_a() + name_attr = "LayerSetName" if ifc_class == "IfcMaterialLayerSet" else "Name" + material_set_name = getattr(element, name_attr) + if material_set_name is None: + return + return next((e for e in self.file.by_type(ifc_class) if getattr(e, name_attr) == material_set_name), None) + elif element.is_a("IfcProfileDef"): profile_name = element.ProfileName if profile_name is None: @@ -644,6 +654,17 @@ class Usecase: reuse_identities[element_identity] = existing_material return existing_material + elif ifc_class in MATERIAL_SETS: + name_attr = "LayerSetName" if ifc_class == "IfcMaterialLayerSet" else "Name" + material_set_name = getattr(element, name_attr) + if material_set_name is not None: + existing_material_set = next( + (e for e in ifc_file.by_type(ifc_class) if getattr(e, name_attr) == material_set_name), None + ) + if existing_material_set is not None: + reuse_identities[element_identity] = existing_material_set + return existing_material_set + elif element.is_a("IfcPresentationStyle"): style_name = element.Name if style_name is not None: 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 5fc6127c21..f0f4abe53e 100644 --- a/src/ifcopenshell-python/test/api/project/test_append_asset.py +++ b/src/ifcopenshell-python/test/api/project/test_append_asset.py @@ -774,3 +774,47 @@ class TestAppendAssetIFC4(test.bootstrap.IFC4, TestAppendAssetIFC2X3): assert len(materials) == 2 and all(m.Name == "TestMaterial" for m in materials) styles = self.file.by_type("IfcSurfaceStyle") assert len(styles) == 2 and all(s.Name == "TestStyle" for s in styles) + + def test_not_duplicate_material_sets_based_on_name(self): + # Setup library. + library = ifcopenshell.api.project.create_file(version=self.file.schema) + ifcopenshell.api.root.create_entity(library, ifc_class="IfcProject") + model = ifcopenshell.api.context.add_context(library, context_type="Model") + body = ifcopenshell.api.context.add_context( + library, context_type="Model", context_identifier="Body", target_view="MODEL_VIEW", parent=model + ) + column_type = ifcopenshell.api.root.create_entity(library, "IfcColumnType") + material_set = ifcopenshell.api.material.add_material_set( + library, set_type="IfcMaterialProfileSet", name="TestProfileSet" + ) + ifcopenshell.api.material.assign_material( + library, [column_type], material=material_set, type="IfcMaterialProfileSet" + ) + + ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcProject") + # Test adding a profile with existing name. + ifcopenshell.api.material.add_material_set(self.file, set_type="IfcMaterialProfileSet", name="TestProfileSet") + ifcopenshell.api.project.append_asset(self.file, library, column_type) + assert len(self.file.by_type("IfcMaterialProfileSet")) == 1 + + def test_duplicate_material_sets_if_uniqueness_is_not_assumed(self): + # Setup library. + library = ifcopenshell.api.project.create_file(version=self.file.schema) + ifcopenshell.api.root.create_entity(library, ifc_class="IfcProject") + model = ifcopenshell.api.context.add_context(library, context_type="Model") + body = ifcopenshell.api.context.add_context( + library, context_type="Model", context_identifier="Body", target_view="MODEL_VIEW", parent=model + ) + column_type = ifcopenshell.api.root.create_entity(library, "IfcColumnType") + material_set = ifcopenshell.api.material.add_material_set( + library, set_type="IfcMaterialProfileSet", name="TestProfileSet" + ) + ifcopenshell.api.material.assign_material( + library, [column_type], material=material_set, type="IfcMaterialProfileSet" + ) + + ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcProject") + # Test adding a profile with existing name. + ifcopenshell.api.material.add_material_set(self.file, set_type="IfcMaterialProfileSet", name="TestProfileSet") + ifcopenshell.api.project.append_asset(self.file, library, column_type, assume_asset_uniqueness_by_name=False) + assert len(self.file.by_type("IfcMaterialProfileSet")) == 2