From cd25a50e960292d0f2c7010e62af4b6f21681fc4 Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Fri, 12 Apr 2024 11:21:35 +0500 Subject: [PATCH] material.assign_material - support batching #4474 --- .../blenderbim/bim/module/model/mep.py | 2 +- .../blenderbim/bim/module/model/product.py | 2 +- .../blenderbim/bim/module/type/operator.py | 4 +- src/blenderbim/blenderbim/core/material.py | 2 +- src/blenderbim/blenderbim/tool/material.py | 2 +- src/blenderbim/scripts/generate_au_library.py | 6 +- .../scripts/generate_demo_library.py | 4 +- .../scripts/generate_furniture_library.py | 6 +- .../generate_steel_profiles_library.py | 2 +- src/blenderbim/test/tool/test_material.py | 2 +- .../ifcopenshell-python/geometry_creation.rst | 4 +- .../ifcopenshell/api/__init__.py | 3 + .../api/material/add_constituent.py | 2 +- .../ifcopenshell/api/material/add_layer.py | 2 +- .../api/material/add_list_item.py | 2 +- .../ifcopenshell/api/material/add_material.py | 2 +- .../api/material/add_material_set.py | 2 +- .../ifcopenshell/api/material/add_profile.py | 2 +- .../api/material/assign_material.py | 194 ++++++++++------ .../api/material/assign_profile.py | 4 +- .../api/material/edit_layer_usage.py | 4 +- .../api/material/edit_profile_usage.py | 4 +- .../api/material/unassign_material.py | 2 +- .../ifcopenshell/api/project/append_asset.py | 2 +- .../api/project/assign_declaration.py | 2 +- .../api/style/assign_material_style.py | 2 +- .../ifcopenshell/api/type/assign_type.py | 15 +- .../test/api/material/test_assign_material.py | 214 ++++++++++++++---- .../test/api/material/test_copy_material.py | 2 +- .../test/api/material/test_remove_material.py | 10 +- .../api/material/test_remove_material_set.py | 2 +- .../api/material/test_unassign_material.py | 26 +-- .../test/api/project/test_append_asset.py | 32 +-- .../test/api/root/test_remove_product.py | 2 +- .../api/style/test_assign_material_style.py | 2 +- .../api/style/test_unassign_material_style.py | 2 +- src/ifcopenshell-python/test/api/test_api.py | 10 + .../test/api/type/test_assign_type.py | 6 +- .../test/api/type/test_unassign_type.py | 2 +- .../test/util/test_element.py | 44 ++-- .../test/util/test_selector.py | 12 +- src/ifcpatch/test/test_MergeDuplicateTypes.py | 4 +- src/ifctester/test/test_facet.py | 18 +- 43 files changed, 432 insertions(+), 236 deletions(-) diff --git a/src/blenderbim/blenderbim/bim/module/model/mep.py b/src/blenderbim/blenderbim/bim/module/model/mep.py index cc3daa610d..c3a19c5727 100644 --- a/src/blenderbim/blenderbim/bim/module/model/mep.py +++ b/src/blenderbim/blenderbim/bim/module/model/mep.py @@ -542,7 +542,7 @@ class MEPGenerator: ifc_representation_class=None, ) - rel = ifcopenshell.api.run("material.assign_material", ifc_file, product=element, type="IfcMaterialProfileSet") + rel = ifcopenshell.api.run("material.assign_material", ifc_file, products=[element], type="IfcMaterialProfileSet") profile_set = rel.RelatingMaterial material_profile = ifcopenshell.api.run( "material.add_profile", ifc_file, profile_set=profile_set, material=material diff --git a/src/blenderbim/blenderbim/bim/module/model/product.py b/src/blenderbim/blenderbim/bim/module/model/product.py index 96cef5e893..f1aee69d64 100644 --- a/src/blenderbim/blenderbim/bim/module/model/product.py +++ b/src/blenderbim/blenderbim/bim/module/model/product.py @@ -515,7 +515,7 @@ def ensure_material_assigned(usecase_path, ifc_file, settings): if usecase_path == "material.assign_material": if not settings.get("material", None): return - elements = [settings["product"]] + elements = settings["products"] else: elements = [] for rel in ifc_file.by_type("IfcRelAssociatesMaterial"): diff --git a/src/blenderbim/blenderbim/bim/module/type/operator.py b/src/blenderbim/blenderbim/bim/module/type/operator.py index 76f58d42db..899dfe4ec1 100644 --- a/src/blenderbim/blenderbim/bim/module/type/operator.py +++ b/src/blenderbim/blenderbim/bim/module/type/operator.py @@ -283,7 +283,7 @@ class AddType(bpy.types.Operator, tool.Ifc.Operator): else: material = self.add_default_material() rel = ifcopenshell.api.run( - "material.assign_material", ifc_file, product=element, type="IfcMaterialLayerSet" + "material.assign_material", ifc_file, products=[element], type="IfcMaterialLayerSet" ) layer_set = rel.RelatingMaterial layer = ifcopenshell.api.run("material.add_layer", ifc_file, layer_set=layer_set, material=material) @@ -361,7 +361,7 @@ class AddType(bpy.types.Operator, tool.Ifc.Operator): ) rel = ifcopenshell.api.run( - "material.assign_material", ifc_file, product=element, type="IfcMaterialProfileSet" + "material.assign_material", ifc_file, products=[element], type="IfcMaterialProfileSet" ) profile_set = rel.RelatingMaterial material_profile = ifcopenshell.api.run( diff --git a/src/blenderbim/blenderbim/core/material.py b/src/blenderbim/blenderbim/core/material.py index ba1a19a1b0..f5cfcbf9ba 100644 --- a/src/blenderbim/blenderbim/core/material.py +++ b/src/blenderbim/blenderbim/core/material.py @@ -102,7 +102,7 @@ def assign_material(ifc, material_tool, material_type, objects): element = ifc.get_entity(obj) if not element: continue - ifc.run("material.assign_material", product=element, type=material_type, material=material) + ifc.run("material.assign_material", products=[element], type=material_type, material=material) assigned_material = material_tool.get_material(element) if material_tool.is_a_material_set(assigned_material): material_tool.add_material_to_set(material_set=assigned_material, material=material) diff --git a/src/blenderbim/blenderbim/tool/material.py b/src/blenderbim/blenderbim/tool/material.py index 70c64eeb83..8ebb745fa0 100644 --- a/src/blenderbim/blenderbim/tool/material.py +++ b/src/blenderbim/blenderbim/tool/material.py @@ -219,7 +219,7 @@ class Material(blenderbim.core.tool.Material): material = tool.Ifc.get().by_type("IfcMaterial")[0] else: blenderbim.core.material.unassign_material(tool.Ifc, tool.Material, objects=[tool.Ifc.get_object(element)]) - tool.Ifc.run("material.assign_material", product=element, type="IfcMaterialProfileSet", material=material) + tool.Ifc.run("material.assign_material", products=[element], type="IfcMaterialProfileSet", material=material) assinged_material = cls.get_material(element) material_profile = tool.Ifc.run("material.add_profile", profile_set=assinged_material, material=material) return material_profile diff --git a/src/blenderbim/scripts/generate_au_library.py b/src/blenderbim/scripts/generate_au_library.py index e1895fb44b..e75cf739b0 100644 --- a/src/blenderbim/scripts/generate_au_library.py +++ b/src/blenderbim/scripts/generate_au_library.py @@ -188,7 +188,7 @@ class LibraryGenerator: def create_layer_set_type(self, name, data): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class=data["type"], name=name) element.Description = data["Description"] - rel = ifcopenshell.api.run("material.assign_material", self.file, product=element, type="IfcMaterialLayerSet") + rel = ifcopenshell.api.run("material.assign_material", self.file, products=[element], type="IfcMaterialLayerSet") layer_set = rel.RelatingMaterial for layer_data in data["Layers"]: layer = ifcopenshell.api.run( @@ -201,7 +201,7 @@ class LibraryGenerator: def create_layer_type(self, ifc_class, name, thickness): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class=ifc_class, name=name) - rel = ifcopenshell.api.run("material.assign_material", self.file, product=element, type="IfcMaterialLayerSet") + rel = ifcopenshell.api.run("material.assign_material", self.file, products=[element], type="IfcMaterialLayerSet") layer_set = rel.RelatingMaterial layer = ifcopenshell.api.run("material.add_layer", self.file, layer_set=layer_set, material=self.materials["TBD"]["ifc"]) layer.LayerThickness = thickness @@ -210,7 +210,7 @@ class LibraryGenerator: def create_profile_type(self, ifc_class, name, profile): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class=ifc_class, name=name) - rel = ifcopenshell.api.run("material.assign_material", self.file, product=element, type="IfcMaterialProfileSet") + rel = ifcopenshell.api.run("material.assign_material", self.file, products=[element], type="IfcMaterialProfileSet") profile_set = rel.RelatingMaterial material_profile = ifcopenshell.api.run( "material.add_profile", self.file, profile_set=profile_set, material=self.materials["TBD"]["ifc"] diff --git a/src/blenderbim/scripts/generate_demo_library.py b/src/blenderbim/scripts/generate_demo_library.py index 26ab3ad278..14f97bc52d 100644 --- a/src/blenderbim/scripts/generate_demo_library.py +++ b/src/blenderbim/scripts/generate_demo_library.py @@ -205,7 +205,7 @@ class LibraryGenerator: def create_layer_type(self, ifc_class, name, thickness): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class=ifc_class, name=name) - rel = ifcopenshell.api.run("material.assign_material", self.file, product=element, type="IfcMaterialLayerSet") + rel = ifcopenshell.api.run("material.assign_material", self.file, products=[element], type="IfcMaterialLayerSet") layer_set = rel.RelatingMaterial layer = ifcopenshell.api.run("material.add_layer", self.file, layer_set=layer_set, material=self.material) layer.LayerThickness = thickness @@ -214,7 +214,7 @@ class LibraryGenerator: def create_profile_type(self, ifc_class, name, profile): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class=ifc_class, name=name) - rel = ifcopenshell.api.run("material.assign_material", self.file, product=element, type="IfcMaterialProfileSet") + rel = ifcopenshell.api.run("material.assign_material", self.file, products=[element], type="IfcMaterialProfileSet") profile_set = rel.RelatingMaterial material_profile = ifcopenshell.api.run( "material.add_profile", self.file, profile_set=profile_set, material=self.material diff --git a/src/blenderbim/scripts/generate_furniture_library.py b/src/blenderbim/scripts/generate_furniture_library.py index 2837096df7..6d38170ed0 100644 --- a/src/blenderbim/scripts/generate_furniture_library.py +++ b/src/blenderbim/scripts/generate_furniture_library.py @@ -1803,7 +1803,7 @@ class LibraryGenerator: def create_layer_set_type(self, name, data): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class=data["type"], name=name) element.Description = data["Description"] - rel = ifcopenshell.api.run("material.assign_material", self.file, product=element, type="IfcMaterialLayerSet") + rel = ifcopenshell.api.run("material.assign_material", self.file, products=[element], type="IfcMaterialLayerSet") layer_set = rel.RelatingMaterial for layer_data in data["Layers"]: layer = ifcopenshell.api.run( @@ -1816,7 +1816,7 @@ class LibraryGenerator: def create_layer_type(self, ifc_class, name, thickness): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class=ifc_class, name=name) - rel = ifcopenshell.api.run("material.assign_material", self.file, product=element, type="IfcMaterialLayerSet") + rel = ifcopenshell.api.run("material.assign_material", self.file, products=[element], type="IfcMaterialLayerSet") layer_set = rel.RelatingMaterial layer = ifcopenshell.api.run( "material.add_layer", self.file, layer_set=layer_set, material=self.materials["TBD"]["ifc"] @@ -1827,7 +1827,7 @@ class LibraryGenerator: def create_profile_type(self, ifc_class, name, profile): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class=ifc_class, name=name) - rel = ifcopenshell.api.run("material.assign_material", self.file, product=element, type="IfcMaterialProfileSet") + rel = ifcopenshell.api.run("material.assign_material", self.file, products=[element], type="IfcMaterialProfileSet") profile_set = rel.RelatingMaterial material_profile = ifcopenshell.api.run( "material.add_profile", diff --git a/src/blenderbim/scripts/generate_steel_profiles_library.py b/src/blenderbim/scripts/generate_steel_profiles_library.py index 8f7765eb5d..685435660f 100644 --- a/src/blenderbim/scripts/generate_steel_profiles_library.py +++ b/src/blenderbim/scripts/generate_steel_profiles_library.py @@ -175,7 +175,7 @@ class LibraryGenerator: def create_profile_type(self, ifc_class, name, profile): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class=ifc_class, name=name) - rel = ifcopenshell.api.run("material.assign_material", self.file, product=element, type="IfcMaterialProfileSet") + rel = ifcopenshell.api.run("material.assign_material", self.file, products=[element], type="IfcMaterialProfileSet") profile_set = rel.RelatingMaterial material_profile = ifcopenshell.api.run( "material.add_profile", self.file, profile_set=profile_set, material=self.material diff --git a/src/blenderbim/test/tool/test_material.py b/src/blenderbim/test/tool/test_material.py index 467eb34afe..6fd0a8ac68 100644 --- a/src/blenderbim/test/tool/test_material.py +++ b/src/blenderbim/test/tool/test_material.py @@ -79,7 +79,7 @@ class TestGetElementsByMaterial(NewFile): tool.Ifc.set(ifc) element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall") material = ifcopenshell.api.run("material.add_material", ifc) - ifcopenshell.api.run("material.assign_material", ifc, product=element, material=material) + ifcopenshell.api.run("material.assign_material", ifc, products=[element], material=material) assert subject.get_elements_by_material(material) == {element} diff --git a/src/ifcopenshell-python/docs/ifcopenshell-python/geometry_creation.rst b/src/ifcopenshell-python/docs/ifcopenshell-python/geometry_creation.rst index 408329c078..099e85f007 100644 --- a/src/ifcopenshell-python/docs/ifcopenshell-python/geometry_creation.rst +++ b/src/ifcopenshell-python/docs/ifcopenshell-python/geometry_creation.rst @@ -686,7 +686,7 @@ responsibility to make sure the geometry is correct. ifcopenshell.api.run("material.edit_layer", model, layer=layer, attributes={"LayerThickness": 13}) # Great! Let's assign our material set to our wall type. - ifcopenshell.api.run("material.assign_material", model, product=wall_type, material=material_set) + ifcopenshell.api.run("material.assign_material", model, products=[wall_type], material=material_set) # Now, let's create a wall at the origin. wall = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcWall") @@ -742,7 +742,7 @@ responsibility to make sure the geometry is correct. ifcopenshell.api.run("material.add_profile", model, profile_set=material_set, material=steel, profile=hea100) # Great! Let's assign our material set to our beam type. - ifcopenshell.api.run("material.assign_material", model, product=beam_type, material=material_set) + ifcopenshell.api.run("material.assign_material", model, products=[beam_type], material=material_set) # Now, let's create a beam at the origin. beam = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcBeam") diff --git a/src/ifcopenshell-python/ifcopenshell/api/__init__.py b/src/ifcopenshell-python/ifcopenshell/api/__init__.py index 9748c848a9..5a90b4dc7a 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/__init__.py +++ b/src/ifcopenshell-python/ifcopenshell/api/__init__.py @@ -85,6 +85,9 @@ ARGUMENTS_DEPRECATION = { "system.unassign_system": partial( batching_argument_deprecation, prev_argument="product", new_argument="products" ), + "material.assign_material": partial( + batching_argument_deprecation, prev_argument="product", new_argument="products" + ), } diff --git a/src/ifcopenshell-python/ifcopenshell/api/material/add_constituent.py b/src/ifcopenshell-python/ifcopenshell/api/material/add_constituent.py index e3cb94ef95..c45b5fb14d 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/material/add_constituent.py +++ b/src/ifcopenshell-python/ifcopenshell/api/material/add_constituent.py @@ -78,7 +78,7 @@ class Usecase: # our window too, but to keep this example simple, geometry is # optional and it is enough to say that this window is made out of # aluminium and glass. - ifcopenshell.api.run("material.assign_material", model, product=window_type, material=material_set) + ifcopenshell.api.run("material.assign_material", model, products=[window_type], material=material_set) """ self.file = file self.settings = {"constituent_set": constituent_set, "material": material} diff --git a/src/ifcopenshell-python/ifcopenshell/api/material/add_layer.py b/src/ifcopenshell-python/ifcopenshell/api/material/add_layer.py index 89c3e6b2a1..d0b36b4ec6 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/material/add_layer.py +++ b/src/ifcopenshell-python/ifcopenshell/api/material/add_layer.py @@ -76,7 +76,7 @@ class Usecase: ifcopenshell.api.run("material.edit_layer", model, layer=layer, attributes={"LayerThickness": 13}) # Great! Let's assign our material set to our wall type. - ifcopenshell.api.run("material.assign_material", model, product=wall_type, material=material_set) + ifcopenshell.api.run("material.assign_material", model, products=[wall_type], material=material_set) """ self.file = file self.settings = {"layer_set": layer_set, "material": material} diff --git a/src/ifcopenshell-python/ifcopenshell/api/material/add_list_item.py b/src/ifcopenshell-python/ifcopenshell/api/material/add_list_item.py index 4c80a5758c..92b873b198 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/material/add_list_item.py +++ b/src/ifcopenshell-python/ifcopenshell/api/material/add_list_item.py @@ -77,7 +77,7 @@ class Usecase: # our window too, but to keep this example simple, geometry is # optional and it is enough to say that this window is made out of # aluminium and glass. - ifcopenshell.api.run("material.assign_material", model, product=window_type, material=material_set) + ifcopenshell.api.run("material.assign_material", model, products=[window_type], material=material_set) """ self.file = file self.settings = {"material_list": material_list, "material": material} diff --git a/src/ifcopenshell-python/ifcopenshell/api/material/add_material.py b/src/ifcopenshell-python/ifcopenshell/api/material/add_material.py index 07b5882932..3959e4becd 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/material/add_material.py +++ b/src/ifcopenshell-python/ifcopenshell/api/material/add_material.py @@ -68,7 +68,7 @@ class Usecase: # Assign the concrete material to that bench. Note that no colour # "Style" has been specified. - ifcopenshell.api.run("material.assign_material", model, product=concrete_bench, material=concrete) + ifcopenshell.api.run("material.assign_material", model, products=[concrete_bench], material=concrete) """ self.file = file self.settings = {"name": name or "Unnamed", "category": category} diff --git a/src/ifcopenshell-python/ifcopenshell/api/material/add_material_set.py b/src/ifcopenshell-python/ifcopenshell/api/material/add_material_set.py index 802d1d38cc..5ec8a36623 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/material/add_material_set.py +++ b/src/ifcopenshell-python/ifcopenshell/api/material/add_material_set.py @@ -100,7 +100,7 @@ class Usecase: ifcopenshell.api.run("material.edit_layer", model, layer=layer, attributes={"LayerThickness": 13}) # Great! Let's assign our material set to our wall type. - ifcopenshell.api.run("material.assign_material", model, product=wall_type, material=material_set) + ifcopenshell.api.run("material.assign_material", model, products=[wall_type], material=material_set) """ self.file = file self.settings = {"name": name or "Unnamed", "set_type": set_type or "IfcMaterialConstituentSet"} diff --git a/src/ifcopenshell-python/ifcopenshell/api/material/add_profile.py b/src/ifcopenshell-python/ifcopenshell/api/material/add_profile.py index df53de69f8..8b322b71f7 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/material/add_profile.py +++ b/src/ifcopenshell-python/ifcopenshell/api/material/add_profile.py @@ -79,7 +79,7 @@ class Usecase: profile_set=material_set, material=steel, profile=hea100) # Great! Let's assign our material set to our beam type. - ifcopenshell.api.run("material.assign_material", model, product=beam_type, material=material_set) + ifcopenshell.api.run("material.assign_material", model, products=[beam_type], material=material_set) """ self.file = file self.settings = {"profile_set": profile_set, "material": material, "profile": profile} diff --git a/src/ifcopenshell-python/ifcopenshell/api/material/assign_material.py b/src/ifcopenshell-python/ifcopenshell/api/material/assign_material.py index aabbc49a16..2e91f2cce3 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/material/assign_material.py +++ b/src/ifcopenshell-python/ifcopenshell/api/material/assign_material.py @@ -27,11 +27,11 @@ class Usecase: def __init__( self, file: ifcopenshell.file, - product: ifcopenshell.entity_instance, + products: list[ifcopenshell.entity_instance], type: str = "IfcMaterial", material: Optional[ifcopenshell.entity_instance] = None, ): - """Assigns a material to a product + """Assigns a material to the list of products Will unassign previously assigned material. @@ -62,9 +62,9 @@ class Usecase: This allows individual occurrences to override the layered or profiled construction offset from a reference line. - :param product: The IfcProduct to assign the material or material set + :param products: The list of IfcProducts to assign the material or material set to. - :type product: ifcopenshell.entity_instance.entity_instance + :type products: list[ifcopenshell.entity_instance.entity_instance] :param type: Choose from "IfcMaterial", "IfcMaterialConstituentSet", "IfcMaterialLayerSet", "IfcMaterialLayerSetUsage", "IfcMaterialProfileSet", "IfcMaterialProfileSetUsage", or @@ -75,8 +75,14 @@ class Usecase: If type is Usage then no need to provide `material`, it will be deduced from the element type automatically. :type material: ifcopenshell.entity_instance.entity_instance, optional - :return: The IfcRelAssociatesMaterial entity - :rtype: ifcopenshell.entity_instance.entity_instance + :return: IfcRelAssociatesMaterial entity + or a list of IfcRelAssociatesMaterial entities + (possible if `type` is Usage + and `products` require different Usages) + or `None` if `products` was empty list. + :rtype: Union[ + ifcopenshell.entity_instance.entity_instance, + list[ifcopenshell.entity_instance.entity_instance], None] Example: @@ -89,7 +95,7 @@ class Usecase: # material. Let's assign it to the type. bench_type = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcFurnitureType") ifcopenshell.api.run("material.assign_material", model, - product=bench_type, type="IfcMaterial", material=concrete) + products=[bench_type], type="IfcMaterial", material=concrete) # Let's imagine there are a two occurrences of this bench. It's not # necessary to assign any material to these benches as they @@ -113,7 +119,7 @@ class Usecase: # Our wall type now has the layer set assigned to it ifcopenshell.api.run("material.assign_material", model, - product=wall_type, type="IfcMaterialLayerSet", material=material_set) + products=[wall_type], type="IfcMaterialLayerSet", material=material_set) # Let's imagine an occurrence of this wall type. wall = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcWall") @@ -125,7 +131,7 @@ class Usecase: # they automatically detect the inherited material set from the # type. You'd write similar code for a profile set. ifcopenshell.api.run("material.assign_material", model, - product=wall, type="IfcMaterialLayerSetUsage") + products=[wall], type="IfcMaterialLayerSetUsage") # To be complete, let's create the wall's axis and body # representation. Notice how the axis guides the walls "reference @@ -141,12 +147,19 @@ class Usecase: ifcopenshell.api.run("geometry.edit_object_placement", model, product=wall) """ self.file = file - self.settings = {"product": product, "type": type, "material": material} + self.settings = {"products": products, "type": type, "material": material} + + def execute(self) -> Union[ifcopenshell.entity_instance, list[ifcopenshell.entity_instance], None]: + self.products: set[ifcopenshell.entity_instance] = set(self.settings["products"]) + if not self.products: + return + + # NOTE: we always reassign material, even if it might be assigned before + for product in self.products: + material = ifcopenshell.util.element.get_material(product) + if material: + ifcopenshell.api.run("material.unassign_material", self.file, product=product) - def execute(self) -> ifcopenshell.entity_instance: - material = ifcopenshell.util.element.get_material(self.settings["product"]) - if material: - ifcopenshell.api.run("material.unassign_material", self.file, product=self.settings["product"]) if self.settings["type"] == "IfcMaterial" or ( self.settings["material"] and not self.settings["material"].is_a("IfcMaterial") ): @@ -161,71 +174,104 @@ class Usecase: return self.create_material_association(material_set) elif self.settings["type"] == "IfcMaterialLayerSetUsage": - element_type = ifcopenshell.util.element.get_type(self.settings["product"]) - if element_type: - element_type_material = ifcopenshell.util.element.get_material(element_type) - if element_type_material and element_type_material.is_a("IfcMaterialLayerSet"): - material_set = element_type_material + # NOTE: might return list of rels + types_to_products_layers_sets: dict[ + tuple[Union[ifcopenshell.entity_instance, None], str], tuple[ifcopenshell.entity_instance, list] + ] = dict() + + AXIS3_CLASSES = [ + "IfcSlab", + "IfcSlabStandardCase", + "IfcSlabElementedCase", + "IfcRoof", + "IfcRamp", + "IfcPlate", + "IfcPlateStandardCase", + ] + for product in self.products: + element_type = ifcopenshell.util.element.get_type(product) + layer_set_direction = "AXIS3" if product.is_a() in AXIS3_CLASSES else "AXIS2" + material_layer_type = (element_type, layer_set_direction) + + if material_layer_type in types_to_products_layers_sets: + types_to_products_layers_sets[material_layer_type][1].append(product) + continue + + if element_type: + element_type_material = ifcopenshell.util.element.get_material(element_type) + if element_type_material and element_type_material.is_a("IfcMaterialLayerSet"): + material_set = element_type_material + else: + material_set = self.file.create_entity("IfcMaterialLayerSet") else: material_set = self.file.create_entity("IfcMaterialLayerSet") - else: - material_set = self.file.create_entity("IfcMaterialLayerSet") - material_set_usage = self.create_layer_set_usage(material_set) - return self.create_material_association(material_set_usage) + types_to_products_layers_sets[material_layer_type] = (material_set, [product]) + + rels = [ + self.create_layer_set_usage(material_set, layer_set_direction, products) + for (_, layer_set_direction), (material_set, products) in types_to_products_layers_sets.items() + ] + return rels[0] if len(rels) == 1 else rels elif self.settings["type"] == "IfcMaterialProfileSet": material_set = self.file.create_entity(self.settings["type"]) return self.create_material_association(material_set) elif self.settings["type"] == "IfcMaterialProfileSetUsage": - element_type = ifcopenshell.util.element.get_type(self.settings["product"]) - if element_type: - element_type_material = ifcopenshell.util.element.get_material(element_type) - if element_type_material and element_type_material.is_a("IfcMaterialProfileSet"): - material_set = element_type_material + # NOTE: might return list of rels + types_to_products_profile_sets: dict[ + Union[ifcopenshell.entity_instance, None], tuple[ifcopenshell.entity_instance, list] + ] = dict() + for product in self.products: + element_type = ifcopenshell.util.element.get_type(product) + if element_type in types_to_products_profile_sets: + types_to_products_profile_sets[element_type][1].append(product) + continue + if element_type: + element_type_material = ifcopenshell.util.element.get_material(element_type) + if element_type_material and element_type_material.is_a("IfcMaterialProfileSet"): + material_set = element_type_material + else: + material_set = self.file.create_entity("IfcMaterialProfileSet") else: material_set = self.file.create_entity("IfcMaterialProfileSet") - else: - material_set = self.file.create_entity("IfcMaterialProfileSet") + types_to_products_profile_sets[element_type] = (material_set, [product]) - self.update_representation_profile(material_set) - material_set_usage = self.create_profile_set_usage(material_set) - return self.create_material_association(material_set_usage) + rels = [] + for _, (material_set, products) in types_to_products_profile_sets.items(): + self.update_representation_profile(material_set, products) + material_set_usage = self.create_profile_set_usage(material_set) + rels.append(self.create_material_association(material_set_usage, products)) + return rels[0] if len(rels) == 1 else rels elif self.settings["type"] == "IfcMaterialList": material_set = self.file.create_entity(self.settings["type"]) material_set.Materials = [self.settings["material"]] return self.create_material_association(material_set) - def update_representation_profile(self, material_set: ifcopenshell.entity_instance) -> None: + def update_representation_profile( + self, material_set: ifcopenshell.entity_instance, products: list[ifcopenshell.entity_instance] + ) -> None: profile = material_set.CompositeProfile if not profile and material_set.MaterialProfiles: profile = material_set.MaterialProfiles[0].Profile if not profile: return - representation = ifcopenshell.util.representation.get_representation( - self.settings["product"], "Model", "Body", "MODEL_VIEW" - ) - if not representation: - return - for subelement in self.file.traverse(representation): - if subelement.is_a("IfcSweptAreaSolid"): - subelement.SweptArea = profile + for product in products: + representation = ifcopenshell.util.representation.get_representation(product, "Model", "Body", "MODEL_VIEW") + if not representation: + return + for subelement in self.file.traverse(representation): + if subelement.is_a("IfcSweptAreaSolid"): + subelement.SweptArea = profile - def create_layer_set_usage(self, material_set: ifcopenshell.entity_instance) -> ifcopenshell.entity_instance: - if self.settings["product"].is_a() in [ - "IfcSlab", - "IfcSlabStandardCase", - "IfcSlabElementedCase", - "IfcRoof", - "IfcRamp", - "IfcPlate", - "IfcPlateStandardCase", - ]: - layer_set_direction = "AXIS3" - else: - layer_set_direction = "AXIS2" - return self.file.create_entity( + def create_layer_set_usage( + self, + material_set: ifcopenshell.entity_instance, + layer_set_direction: str, + products: list[ifcopenshell.entity_instance], + ) -> ifcopenshell.entity_instance: + usage = self.file.create_entity( "IfcMaterialLayerSetUsage", **{ "ForLayerSet": material_set, @@ -234,29 +280,34 @@ class Usecase: "OffsetFromReferenceLine": 0, } ) + return self.create_material_association(usage, products) def create_profile_set_usage(self, material_set: ifcopenshell.entity_instance) -> ifcopenshell.entity_instance: return self.file.create_entity("IfcMaterialProfileSetUsage", **{"ForProfileSet": material_set}) def assign_ifc_material(self) -> ifcopenshell.entity_instance: - rel = self.get_rel_associates_material(self.settings["material"]) + material = self.settings["material"] or self.file.create_entity("IfcMaterial") + rel = self.get_rel_associates_material(material) if not rel: - return self.create_material_association(self.settings["material"]) - related_objects = list(rel.RelatedObjects) - related_objects.append(self.settings["product"]) - rel.RelatedObjects = related_objects + return self.create_material_association(material) + previous_related_objects = set(rel.RelatedObjects) + rel.RelatedObjects = list(previous_related_objects | self.products) ifcopenshell.api.run("owner.update_owner_history", self.file, **{"element": rel}) return rel def create_material_association( - self, relating_material: ifcopenshell.entity_instance + self, + relating_material: ifcopenshell.entity_instance, + products: Optional[list[ifcopenshell.entity_instance]] = None, ) -> ifcopenshell.entity_instance: + if products is None: + products = list(self.products) return self.file.create_entity( "IfcRelAssociatesMaterial", **{ "GlobalId": ifcopenshell.guid.new(), "OwnerHistory": ifcopenshell.api.run("owner.create_owner_history", self.file), - "RelatedObjects": [self.settings["product"]], + "RelatedObjects": products, "RelatingMaterial": relating_material, } ) @@ -265,11 +316,12 @@ class Usecase: self, material: ifcopenshell.entity_instance ) -> Union[ifcopenshell.entity_instance, None]: if self.file.schema == "IFC2X3" or material.is_a("IfcMaterialList"): - rel = [ - r - for r in self.file.by_type("IfcRelAssociatesMaterial") - if r.RelatingMaterial == self.settings["material"] - ] - return rel[0] if rel else None - if self.settings["material"].AssociatedTo: - return self.settings["material"].AssociatedTo[0] + return next( + ( + r + for r in self.file.by_type("IfcRelAssociatesMaterial") + if r.RelatingMaterial == self.settings["material"] + ), + None, + ) + return next(iter(material.AssociatedTo), None) diff --git a/src/ifcopenshell-python/ifcopenshell/api/material/assign_profile.py b/src/ifcopenshell-python/ifcopenshell/api/material/assign_profile.py index ea3ed7610a..4acd6637e7 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/material/assign_profile.py +++ b/src/ifcopenshell-python/ifcopenshell/api/material/assign_profile.py @@ -66,12 +66,12 @@ class Usecase: profile_set=material_set, material=steel, profile=hea100) # Great! Let's assign our material set to our beam type. - ifcopenshell.api.run("material.assign_material", model, product=beam_type, material=material_set) + ifcopenshell.api.run("material.assign_material", model, products=[beam_type], material=material_set) # Let's create an occurrence of this beam. beam = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcBeam", name="B1.01") ifcopenshell.api.run("material.assign_material", model, - product=beam, type="IfcMaterialProfileSetUsage") + products=[beam], type="IfcMaterialProfileSetUsage") # Let's give a 1000mm long beam body representation. body = ifcopenshell.api.run("geometry.add_profile_representation", diff --git a/src/ifcopenshell-python/ifcopenshell/api/material/edit_layer_usage.py b/src/ifcopenshell-python/ifcopenshell/api/material/edit_layer_usage.py index 63aa2adda1..3e45c68c78 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/material/edit_layer_usage.py +++ b/src/ifcopenshell-python/ifcopenshell/api/material/edit_layer_usage.py @@ -55,7 +55,7 @@ class Usecase: # Our wall type now has the layer set assigned to it ifcopenshell.api.run("material.assign_material", model, - product=wall_type, type="IfcMaterialLayerSet", material=material_set) + products=[wall_type], type="IfcMaterialLayerSet", material=material_set) # Let's imagine an occurrence of this wall type. wall = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcWall") @@ -67,7 +67,7 @@ class Usecase: # they automatically detect the inherited material set from the # type. You'd write similar code for a profile set. rel = ifcopenshell.api.run("material.assign_material", model, - product=wall, type="IfcMaterialLayerSetUsage") + products=[wall], type="IfcMaterialLayerSetUsage") # Let's change the offset from the reference line to be 200mm # instead of the default of 0mm. diff --git a/src/ifcopenshell-python/ifcopenshell/api/material/edit_profile_usage.py b/src/ifcopenshell-python/ifcopenshell/api/material/edit_profile_usage.py index aace67e3d0..edd6f27fee 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/material/edit_profile_usage.py +++ b/src/ifcopenshell-python/ifcopenshell/api/material/edit_profile_usage.py @@ -70,12 +70,12 @@ class Usecase: profile_set=material_set, material=steel, profile=hea100) # Great! Let's assign our material set to our beam type. - ifcopenshell.api.run("material.assign_material", model, product=beam_type, material=material_set) + ifcopenshell.api.run("material.assign_material", model, products=[beam_type], material=material_set) # Let's create an occurrence of this beam. beam = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcBeam", name="B1.01") rel = ifcopenshell.api.run("material.assign_material", model, - product=beam, type="IfcMaterialProfileSetUsage") + products=[beam], type="IfcMaterialProfileSetUsage") # Let's give a 1000mm long beam body representation. body = ifcopenshell.api.run("geometry.add_profile_representation", diff --git a/src/ifcopenshell-python/ifcopenshell/api/material/unassign_material.py b/src/ifcopenshell-python/ifcopenshell/api/material/unassign_material.py index e59e510c40..f18065aec9 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/material/unassign_material.py +++ b/src/ifcopenshell-python/ifcopenshell/api/material/unassign_material.py @@ -44,7 +44,7 @@ class Usecase: # Let's imagine a concrete bench made out of concrete. bench_type = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcFurnitureType") ifcopenshell.api.run("material.assign_material", model, - product=bench_type, type="IfcMaterial", material=concrete) + products=[bench_type], type="IfcMaterial", material=concrete) # Let's change our mind and remove the concrete assignment. The # concrete material still exists, but the bench is no longer made diff --git a/src/ifcopenshell-python/ifcopenshell/api/project/append_asset.py b/src/ifcopenshell-python/ifcopenshell/api/project/append_asset.py index 991824859b..4bef25ee75 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/project/append_asset.py +++ b/src/ifcopenshell-python/ifcopenshell/api/project/append_asset.py @@ -72,7 +72,7 @@ class Usecase: wall_type = ifcopenshell.api.run("root.create_entity", library, ifc_class="IfcWallType", name="WAL01") concrete = ifcopenshell.api.run("material.add_material", self.file, name="CON", category="concrete") rel = ifcopenshell.api.run("material.assign_material", library, - product=wall_type, type="IfcMaterialLayerSet") + products=[wall_type], type="IfcMaterialLayerSet") layer = ifcopenshell.api.run("material.add_layer", library, layer_set=rel.RelatingMaterial, material=concrete) layer.Name = "Structure" diff --git a/src/ifcopenshell-python/ifcopenshell/api/project/assign_declaration.py b/src/ifcopenshell-python/ifcopenshell/api/project/assign_declaration.py index 626f4968b4..c11e84be9a 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/project/assign_declaration.py +++ b/src/ifcopenshell-python/ifcopenshell/api/project/assign_declaration.py @@ -65,7 +65,7 @@ class Usecase: wall_type = ifcopenshell.api.run("root.create_entity", library, ifc_class="IfcWallType", name="WAL01") concrete = ifcopenshell.api.run("material.add_material", self.file, name="CON", category="concrete") rel = ifcopenshell.api.run("material.assign_material", library, - product=wall_type, type="IfcMaterialLayerSet") + products=[wall_type], type="IfcMaterialLayerSet") layer = ifcopenshell.api.run("material.add_layer", library, layer_set=rel.RelatingMaterial, material=concrete) layer.Name = "Structure" diff --git a/src/ifcopenshell-python/ifcopenshell/api/style/assign_material_style.py b/src/ifcopenshell-python/ifcopenshell/api/style/assign_material_style.py index aeef68c8e3..d44c276e9f 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/style/assign_material_style.py +++ b/src/ifcopenshell-python/ifcopenshell/api/style/assign_material_style.py @@ -82,7 +82,7 @@ class Usecase: # Assign our concrete material to our wall ifcopenshell.api.run("material.assign_material", model, - product=wall, type="IfcMaterial", material=concrete) + products=[wall], type="IfcMaterial", material=concrete) # Create a new surface style style = ifcopenshell.api.run("style.add_style", model) diff --git a/src/ifcopenshell-python/ifcopenshell/api/type/assign_type.py b/src/ifcopenshell-python/ifcopenshell/api/type/assign_type.py index 6e3db8d595..dcafff9e88 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/type/assign_type.py +++ b/src/ifcopenshell-python/ifcopenshell/api/type/assign_type.py @@ -149,7 +149,7 @@ class Usecase: ifcopenshell.api.run("material.edit_layer", model, layer=layer, attributes={"LayerThickness": .013}) # Great! Let's assign our material set to our wall type. - ifcopenshell.api.run("material.assign_material", model, product=wall_type, material=material_set) + ifcopenshell.api.run("material.assign_material", model, products=[wall_type], material=material_set) # Now, let's create a wall. wall = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcWall") @@ -267,10 +267,9 @@ class Usecase: return ifc_class = type_material.is_a() if ifc_class in ("IfcMaterialLayerSet", "IfcMaterialProfileSet"): - for related_object in related_objects: - ifcopenshell.api.run( - "material.assign_material", - self.file, - product=related_object, - type=f"{ifc_class}Usage", - ) + ifcopenshell.api.run( + "material.assign_material", + self.file, + products=related_objects, + type=f"{ifc_class}Usage", + ) diff --git a/src/ifcopenshell-python/test/api/material/test_assign_material.py b/src/ifcopenshell-python/test/api/material/test_assign_material.py index c761e1052a..4577e7eed5 100644 --- a/src/ifcopenshell-python/test/api/material/test_assign_material.py +++ b/src/ifcopenshell-python/test/api/material/test_assign_material.py @@ -16,77 +16,209 @@ # You should have received a copy of the GNU Lesser General Public License # along with IfcOpenShell. If not, see . +import pytest import test.bootstrap import ifcopenshell.api import ifcopenshell.util.element -class TestAssignMaterial(test.bootstrap.IFC4): +class TestAssignMaterialIFC2X3(test.bootstrap.IFC2X3): def test_assign_element_single_material(self): - element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + element1 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") material = ifcopenshell.api.run("material.add_material", self.file, name="CON01") - ifcopenshell.api.run("material.assign_material", self.file, product=element, type="IfcMaterial", material=material) + ifcopenshell.api.run( + "material.assign_material", self.file, products=[element1, element2], type="IfcMaterial", material=material + ) assert len(self.file.by_type("IfcRelAssociatesMaterial")) == 1 - assert element.HasAssociations[0].RelatingMaterial == material + assert ifcopenshell.util.element.get_material(element1) == material + assert ifcopenshell.util.element.get_material(element2) == material + + def test_raise_exception_creating_ifc_material_without(self): + element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + ifcopenshell.api.run( + "material.assign_material", self.file, products=[element], type="IfcMaterial", material=None + ) + assert ifcopenshell.util.element.get_material(element) def test_assign_type_single_material(self): - element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") + element1 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") + element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") material = ifcopenshell.api.run("material.add_material", self.file, name="CON01") - ifcopenshell.api.run("material.assign_material", self.file, product=element, type="IfcMaterial", material=material) + ifcopenshell.api.run( + "material.assign_material", self.file, products=[element1, element2], type="IfcMaterial", material=material + ) assert len(self.file.by_type("IfcRelAssociatesMaterial")) == 1 - assert element.HasAssociations[0].RelatingMaterial == material + assert ifcopenshell.util.element.get_material(element1) == material + assert ifcopenshell.util.element.get_material(element2) == material def test_assign_type_material_layer_set(self): - element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") - ifcopenshell.api.run("material.assign_material", self.file, product=element, type="IfcMaterialLayerSet") + element1 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") + element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") + ifcopenshell.api.run( + "material.assign_material", self.file, products=[element1, element2], type="IfcMaterialLayerSet" + ) assert len(self.file.by_type("IfcRelAssociatesMaterial")) == 1 - material_set = element.HasAssociations[0].RelatingMaterial + material_set = ifcopenshell.util.element.get_material(element1) assert material_set.is_a("IfcMaterialLayerSet") assert not material_set.MaterialLayers + assert ifcopenshell.util.element.get_material(element2) == material_set def test_assign_type_material_layer_set_and_element_layer_set_usage(self): element_type = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") - element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") - ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element], relating_type=element_type) - ifcopenshell.api.run("material.assign_material", self.file, product=element_type, type="IfcMaterialLayerSet") - ifcopenshell.api.run("material.assign_material", self.file, product=element, type="IfcMaterialLayerSetUsage") - material_set = element_type.HasAssociations[0].RelatingMaterial - material_usage = element.HasAssociations[0].RelatingMaterial - assert material_usage.is_a("IfcMaterialLayerSetUsage") - assert material_usage.ForLayerSet == material_set + element1 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + ifcopenshell.api.run( + "type.assign_type", self.file, related_objects=[element1, element2], relating_type=element_type + ) + ifcopenshell.api.run("material.assign_material", self.file, products=[element_type], type="IfcMaterialLayerSet") + ifcopenshell.api.run( + "material.assign_material", self.file, products=[element1, element2], type="IfcMaterialLayerSetUsage" + ) + material_set = ifcopenshell.util.element.get_material(element_type) + material_usage1 = ifcopenshell.util.element.get_material(element1, should_inherit=False) + assert material_usage1.is_a("IfcMaterialLayerSetUsage") + assert material_usage1.ForLayerSet == material_set + assert ifcopenshell.util.element.get_material(element2, should_inherit=False) == material_usage1 - def test_assign_type_material_profile_set(self): - element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") - ifcopenshell.api.run("material.assign_material", self.file, product=element, type="IfcMaterialProfileSet") + def test_assign_type_material_layer_set_and_element_layer_set_usage_is_different_for_different_types(self): + element_type1 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") + element1 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element1], relating_type=element_type1) + ifcopenshell.api.run( + "material.assign_material", self.file, products=[element_type1], type="IfcMaterialLayerSet" + ) + + element_type2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") + element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element2], relating_type=element_type2) + ifcopenshell.api.run( + "material.assign_material", self.file, products=[element_type2], type="IfcMaterialLayerSet" + ) + + ifcopenshell.api.run( + "material.assign_material", self.file, products=[element1, element2], type="IfcMaterialLayerSetUsage" + ) + material_set1 = ifcopenshell.util.element.get_material(element_type1) + material_usage1 = ifcopenshell.util.element.get_material(element1, should_inherit=False) + assert material_usage1.is_a("IfcMaterialLayerSetUsage") + assert material_usage1.ForLayerSet == material_set1 + + material_set2 = ifcopenshell.util.element.get_material(element_type2) + material_usage2 = ifcopenshell.util.element.get_material(element2, should_inherit=False) + assert material_usage2.is_a("IfcMaterialLayerSetUsage") + assert material_usage2.ForLayerSet == material_set2 + assert material_usage2 != material_usage1 + + def test_assign_element_layer_set_usage_is_different_for_different_layer_set_directions(self): + element1 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcSlab") + ifcopenshell.api.run( + "material.assign_material", self.file, products=[element1, element2], type="IfcMaterialLayerSetUsage" + ) + + material_usage1 = ifcopenshell.util.element.get_material(element1, should_inherit=False) + assert material_usage1.is_a("IfcMaterialLayerSetUsage") + material_set1 = material_usage1.ForLayerSet + assert material_set1.is_a("IfcMaterialLayerSet") + assert material_usage1.LayerSetDirection == "AXIS2" + + material_usage2 = ifcopenshell.util.element.get_material(element2, should_inherit=False) + assert material_usage2.is_a("IfcMaterialLayerSetUsage") + material_set2 = material_usage2.ForLayerSet + assert material_set2.is_a("IfcMaterialLayerSet") + assert material_usage2.LayerSetDirection == "AXIS3" + + assert material_set1 != material_set2 + assert material_usage1 != material_usage2 + + def test_assign_element_material_list(self): + element1 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + material = ifcopenshell.api.run("material.add_material", self.file, name="CON01") + ifcopenshell.api.run( + "material.assign_material", + self.file, + products=[element1, element2], + type="IfcMaterialList", + material=material, + ) assert len(self.file.by_type("IfcRelAssociatesMaterial")) == 1 - material_set = element.HasAssociations[0].RelatingMaterial + material_list = ifcopenshell.util.element.get_material(element1) + assert material_list.is_a("IfcMaterialList") + assert material_list.Materials[0] == material + assert ifcopenshell.util.element.get_material(element2) == material_list + + +class TestAssignMaterialIFC4(test.bootstrap.IFC4, TestAssignMaterialIFC2X3): + def test_assign_type_material_profile_set(self): + element1 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") + element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") + ifcopenshell.api.run( + "material.assign_material", self.file, products=[element1, element2], type="IfcMaterialProfileSet" + ) + assert len(self.file.by_type("IfcRelAssociatesMaterial")) == 1 + material_set = ifcopenshell.util.element.get_material(element1) assert material_set.is_a("IfcMaterialProfileSet") assert not material_set.MaterialProfiles + assert ifcopenshell.util.element.get_material(element2) == material_set def test_assign_type_material_profile_set_and_element_profile_set_usage(self): element_type = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") - element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") - ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element], relating_type=element_type) - ifcopenshell.api.run("material.assign_material", self.file, product=element_type, type="IfcMaterialProfileSet") - ifcopenshell.api.run("material.assign_material", self.file, product=element, type="IfcMaterialProfileSetUsage") + element1 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + ifcopenshell.api.run( + "type.assign_type", self.file, related_objects=[element1, element2], relating_type=element_type + ) + ifcopenshell.api.run( + "material.assign_material", self.file, products=[element_type], type="IfcMaterialProfileSet" + ) + ifcopenshell.api.run( + "material.assign_material", self.file, products=[element1, element2], type="IfcMaterialProfileSetUsage" + ) material_set = element_type.HasAssociations[0].RelatingMaterial - material_usage = element.HasAssociations[0].RelatingMaterial - assert material_usage.is_a("IfcMaterialProfileSetUsage") - assert material_usage.ForProfileSet == material_set + material_usage1 = element1.HasAssociations[0].RelatingMaterial + assert material_usage1.is_a("IfcMaterialProfileSetUsage") + assert material_usage1.ForProfileSet == material_set + assert ifcopenshell.util.element.get_material(element2, should_inherit=False) == material_usage1 + + def test_assign_type_material_profile_set_and_element_profile_set_usage_is_different_for_different_types(self): + element_type1 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") + element1 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element1], relating_type=element_type1) + ifcopenshell.api.run( + "material.assign_material", self.file, products=[element_type1], type="IfcMaterialProfileSet" + ) + + element_type2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") + element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element2], relating_type=element_type2) + ifcopenshell.api.run( + "material.assign_material", self.file, products=[element_type2], type="IfcMaterialProfileSet" + ) + + ifcopenshell.api.run( + "material.assign_material", self.file, products=[element1, element2], type="IfcMaterialProfileSetUsage" + ) + material_set1 = ifcopenshell.util.element.get_material(element_type1) + material_usage1 = ifcopenshell.util.element.get_material(element1, should_inherit=False) + assert material_usage1.is_a("IfcMaterialProfileSetUsage") + assert material_usage1.ForProfileSet == material_set1 + + material_set2 = ifcopenshell.util.element.get_material(element_type2) + material_usage2 = ifcopenshell.util.element.get_material(element2, should_inherit=False) + assert material_usage2.is_a("IfcMaterialProfileSetUsage") + assert material_usage2.ForProfileSet == material_set2 + assert material_usage2 != material_usage1 def test_assign_type_material_constituent_set(self): - element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") - ifcopenshell.api.run("material.assign_material", self.file, product=element, type="IfcMaterialConstituentSet") + element1 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") + element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") + ifcopenshell.api.run( + "material.assign_material", self.file, products=[element1, element2], type="IfcMaterialConstituentSet" + ) assert len(self.file.by_type("IfcRelAssociatesMaterial")) == 1 - material_set = element.HasAssociations[0].RelatingMaterial + material_set = ifcopenshell.util.element.get_material(element1) assert material_set.is_a("IfcMaterialConstituentSet") assert not material_set.MaterialConstituents - - def test_assign_element_material_list(self): - element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") - material = ifcopenshell.api.run("material.add_material", self.file, name="CON01") - ifcopenshell.api.run("material.assign_material", self.file, product=element, type="IfcMaterialList", material=material) - assert len(self.file.by_type("IfcRelAssociatesMaterial")) == 1 - material_list = element.HasAssociations[0].RelatingMaterial - assert material_list.is_a("IfcMaterialList") - assert material_list.Materials[0] == material + assert ifcopenshell.util.element.get_material(element2) == material_set diff --git a/src/ifcopenshell-python/test/api/material/test_copy_material.py b/src/ifcopenshell-python/test/api/material/test_copy_material.py index ea172ca163..ce52bbd769 100644 --- a/src/ifcopenshell-python/test/api/material/test_copy_material.py +++ b/src/ifcopenshell-python/test/api/material/test_copy_material.py @@ -31,7 +31,7 @@ class TestCopyMaterial(test.bootstrap.IFC4): def test_assignments_are_not_copied(self): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") material = ifcopenshell.api.run("material.add_material", self.file, name="CON01") - ifcopenshell.api.run("material.assign_material", self.file, product=element, material=material) + ifcopenshell.api.run("material.assign_material", self.file, products=[element], material=material) new = ifcopenshell.api.run("material.copy_material", self.file, material=material) assert material.AssociatedTo assert not new.AssociatedTo diff --git a/src/ifcopenshell-python/test/api/material/test_remove_material.py b/src/ifcopenshell-python/test/api/material/test_remove_material.py index 80e0abb1f3..0670c09bbb 100644 --- a/src/ifcopenshell-python/test/api/material/test_remove_material.py +++ b/src/ifcopenshell-python/test/api/material/test_remove_material.py @@ -29,7 +29,7 @@ class TestRemoveMaterial(test.bootstrap.IFC4): def test_removing_material_with_associations(self): wall = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") material = ifcopenshell.api.run("material.add_material", self.file) - ifcopenshell.api.run("material.assign_material", self.file, product=wall, material=material) + ifcopenshell.api.run("material.assign_material", self.file, products=[wall], material=material) ifcopenshell.api.run("material.remove_material", self.file, material=material) assert len(self.file.by_type("IfcMaterial")) == 0 assert len(self.file.by_type("IfcRelAssociatesMaterial")) == 0 @@ -41,7 +41,7 @@ class TestRemoveMaterial(test.bootstrap.IFC4): "material.add_material_set", self.file, set_type="IfcMaterialLayerSet" ) ifcopenshell.api.run("material.add_layer", self.file, layer_set=material_set, material=material) - ifcopenshell.api.run("material.assign_material", self.file, product=wall, material=material_set) + ifcopenshell.api.run("material.assign_material", self.file, products=[wall], material=material_set) assert len(self.file.by_type("IfcMaterialLayerSet")[0].MaterialLayers) == 1 ifcopenshell.api.run("material.remove_material", self.file, material=material) assert len(self.file.by_type("IfcMaterial")) == 0 @@ -55,7 +55,7 @@ class TestRemoveMaterial(test.bootstrap.IFC4): "material.add_material_set", self.file, set_type="IfcMaterialProfileSet" ) ifcopenshell.api.run("material.add_profile", self.file, profile_set=material_set, material=material) - ifcopenshell.api.run("material.assign_material", self.file, product=wall, material=material_set) + ifcopenshell.api.run("material.assign_material", self.file, products=[wall], material=material_set) assert len(self.file.by_type("IfcMaterialProfileSet")[0].MaterialProfiles) == 1 ifcopenshell.api.run("material.remove_material", self.file, material=material) assert len(self.file.by_type("IfcMaterial")) == 0 @@ -69,7 +69,7 @@ class TestRemoveMaterial(test.bootstrap.IFC4): "material.add_material_set", self.file, set_type="IfcMaterialConstituentSet" ) ifcopenshell.api.run("material.add_constituent", self.file, constituent_set=material_set, material=material) - ifcopenshell.api.run("material.assign_material", self.file, product=wall, material=material_set) + ifcopenshell.api.run("material.assign_material", self.file, products=[wall], material=material_set) assert len(self.file.by_type("IfcMaterialConstituentSet")[0].MaterialConstituents) == 1 ifcopenshell.api.run("material.remove_material", self.file, material=material) assert len(self.file.by_type("IfcMaterial")) == 0 @@ -83,7 +83,7 @@ class TestRemoveMaterial(test.bootstrap.IFC4): "material.add_material_set", self.file, set_type="IfcMaterialList" ) ifcopenshell.api.run("material.add_list_item", self.file, material_list=material_set, material=material) - ifcopenshell.api.run("material.assign_material", self.file, product=wall, material=material_set) + ifcopenshell.api.run("material.assign_material", self.file, products=[wall], material=material_set) assert len(self.file.by_type("IfcMaterialList")[0].Materials) == 1 ifcopenshell.api.run("material.remove_material", self.file, material=material) assert len(self.file.by_type("IfcMaterial")) == 0 diff --git a/src/ifcopenshell-python/test/api/material/test_remove_material_set.py b/src/ifcopenshell-python/test/api/material/test_remove_material_set.py index fe78ce351c..7554225efe 100644 --- a/src/ifcopenshell-python/test/api/material/test_remove_material_set.py +++ b/src/ifcopenshell-python/test/api/material/test_remove_material_set.py @@ -29,7 +29,7 @@ class TestRemoveMaterialSet(test.bootstrap.IFC4): def test_removing_material_set_with_associations(self): wall = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") material = ifcopenshell.api.run("material.add_material_set", self.file, set_type="IfcMaterialLayerSet") - ifcopenshell.api.run("material.assign_material", self.file, product=wall, material=material) + ifcopenshell.api.run("material.assign_material", self.file, products=[wall], material=material) ifcopenshell.api.run("material.remove_material_set", self.file, material=material) assert len(self.file.by_type("IfcMaterialLayerSet")) == 0 assert len(self.file.by_type("IfcRelAssociatesMaterial")) == 0 diff --git a/src/ifcopenshell-python/test/api/material/test_unassign_material.py b/src/ifcopenshell-python/test/api/material/test_unassign_material.py index 9634941d21..ace766add0 100644 --- a/src/ifcopenshell-python/test/api/material/test_unassign_material.py +++ b/src/ifcopenshell-python/test/api/material/test_unassign_material.py @@ -26,7 +26,7 @@ class TestUnassignMaterial(test.bootstrap.IFC4): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") material = ifcopenshell.api.run("material.add_material", self.file, name="CON01") ifcopenshell.api.run( - "material.assign_material", self.file, product=element, type="IfcMaterial", material=material + "material.assign_material", self.file, products=[element], type="IfcMaterial", material=material ) ifcopenshell.api.run("material.unassign_material", self.file, product=element) assert len(self.file.by_type("IfcRelAssociatesMaterial")) == 0 @@ -38,10 +38,10 @@ class TestUnassignMaterial(test.bootstrap.IFC4): element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") material = ifcopenshell.api.run("material.add_material", self.file, name="CON01") ifcopenshell.api.run( - "material.assign_material", self.file, product=element1, type="IfcMaterial", material=material + "material.assign_material", self.file, products=[element1], type="IfcMaterial", material=material ) ifcopenshell.api.run( - "material.assign_material", self.file, product=element2, type="IfcMaterial", material=material + "material.assign_material", self.file, products=[element2], type="IfcMaterial", material=material ) ifcopenshell.api.run("material.unassign_material", self.file, product=element2) assert element1.HasAssociations @@ -53,7 +53,7 @@ class TestUnassignMaterial(test.bootstrap.IFC4): def test_unassign_material_layer_set_from_type(self): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") material = ifcopenshell.api.run("material.add_material", self.file, name="CON01") - ifcopenshell.api.run("material.assign_material", self.file, product=element, type="IfcMaterialLayerSet") + ifcopenshell.api.run("material.assign_material", self.file, products=[element], type="IfcMaterialLayerSet") ifcopenshell.api.run("material.unassign_material", self.file, product=element) assert len(self.file.by_type("IfcRelAssociatesMaterial")) == 0 assert len(self.file.by_type("IfcWallType")) == 1 @@ -64,8 +64,8 @@ class TestUnassignMaterial(test.bootstrap.IFC4): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element], relating_type=element_type) material = ifcopenshell.api.run("material.add_material", self.file, name="CON01") - ifcopenshell.api.run("material.assign_material", self.file, product=element_type, type="IfcMaterialLayerSet") - ifcopenshell.api.run("material.assign_material", self.file, product=element, type="IfcMaterialLayerSetUsage") + ifcopenshell.api.run("material.assign_material", self.file, products=[element_type], type="IfcMaterialLayerSet") + ifcopenshell.api.run("material.assign_material", self.file, products=[element], type="IfcMaterialLayerSetUsage") ifcopenshell.api.run("material.unassign_material", self.file, product=element) assert len(self.file.by_type("IfcRelAssociatesMaterial")) == 1 assert element_type.HasAssociations @@ -81,9 +81,9 @@ class TestUnassignMaterial(test.bootstrap.IFC4): ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element], relating_type=element_type) ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element2], relating_type=element_type) material = ifcopenshell.api.run("material.add_material", self.file, name="CON01") - ifcopenshell.api.run("material.assign_material", self.file, product=element_type, type="IfcMaterialLayerSet") + ifcopenshell.api.run("material.assign_material", self.file, products=[element_type], type="IfcMaterialLayerSet") rel = ifcopenshell.api.run( - "material.assign_material", self.file, product=element, type="IfcMaterialLayerSetUsage" + "material.assign_material", self.file, products=[element], type="IfcMaterialLayerSetUsage" ) # In some invalid IFCs from Revit, they reuse usages. Let's recreate this invalid scenario @@ -105,7 +105,7 @@ class TestUnassignMaterial(test.bootstrap.IFC4): def test_unassign_material_profile_set_from_type(self): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") material = ifcopenshell.api.run("material.add_material", self.file, name="CON01") - ifcopenshell.api.run("material.assign_material", self.file, product=element, type="IfcMaterialProfileSet") + ifcopenshell.api.run("material.assign_material", self.file, products=[element], type="IfcMaterialProfileSet") ifcopenshell.api.run("material.unassign_material", self.file, product=element) assert len(self.file.by_type("IfcRelAssociatesMaterial")) == 0 assert len(self.file.by_type("IfcWallType")) == 1 @@ -116,8 +116,8 @@ class TestUnassignMaterial(test.bootstrap.IFC4): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element], relating_type=element_type) material = ifcopenshell.api.run("material.add_material", self.file, name="CON01") - ifcopenshell.api.run("material.assign_material", self.file, product=element_type, type="IfcMaterialProfileSet") - ifcopenshell.api.run("material.assign_material", self.file, product=element, type="IfcMaterialProfileSetUsage") + ifcopenshell.api.run("material.assign_material", self.file, products=[element_type], type="IfcMaterialProfileSet") + ifcopenshell.api.run("material.assign_material", self.file, products=[element], type="IfcMaterialProfileSetUsage") ifcopenshell.api.run("material.unassign_material", self.file, product=element) assert len(self.file.by_type("IfcRelAssociatesMaterial")) == 1 assert element_type.HasAssociations @@ -129,7 +129,7 @@ class TestUnassignMaterial(test.bootstrap.IFC4): def test_unassign_material_constituent_set_from_type(self): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") material = ifcopenshell.api.run("material.add_material", self.file, name="CON01") - ifcopenshell.api.run("material.assign_material", self.file, product=element, type="IfcMaterialConstituentSet") + ifcopenshell.api.run("material.assign_material", self.file, products=[element], type="IfcMaterialConstituentSet") ifcopenshell.api.run("material.unassign_material", self.file, product=element) assert len(self.file.by_type("IfcRelAssociatesMaterial")) == 0 assert len(self.file.by_type("IfcWallType")) == 1 @@ -139,7 +139,7 @@ class TestUnassignMaterial(test.bootstrap.IFC4): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") material = ifcopenshell.api.run("material.add_material", self.file, name="CON01") ifcopenshell.api.run( - "material.assign_material", self.file, product=element, type="IfcMaterialList", material=material + "material.assign_material", self.file, products=[element], type="IfcMaterialList", material=material ) ifcopenshell.api.run("material.unassign_material", self.file, product=element) assert len(self.file.by_type("IfcRelAssociatesMaterial")) == 0 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 7c8ed8943a..84444218d6 100644 --- a/src/ifcopenshell-python/test/api/project/test_append_asset.py +++ b/src/ifcopenshell-python/test/api/project/test_append_asset.py @@ -70,8 +70,8 @@ class TestAppendAsset(test.bootstrap.IFC4): element = ifcopenshell.api.run("root.create_entity", library, ifc_class="IfcWallType") element2 = ifcopenshell.api.run("root.create_entity", library, ifc_class="IfcWallType") material = ifcopenshell.api.run("material.add_material", library, name="Material") - ifcopenshell.api.run("material.assign_material", library, product=element, material=material) - ifcopenshell.api.run("material.assign_material", library, product=element2, material=material) + ifcopenshell.api.run("material.assign_material", library, products=[element], material=material) + ifcopenshell.api.run("material.assign_material", library, products=[element2], material=material) ifcopenshell.api.run("project.append_asset", self.file, library=library, element=element) assert len(self.file.by_type("IfcWallType")) == 1 @@ -79,7 +79,7 @@ class TestAppendAsset(test.bootstrap.IFC4): library = ifcopenshell.api.run("project.create_file") element = ifcopenshell.api.run("root.create_entity", library, ifc_class="IfcWallType") material = ifcopenshell.api.run("material.add_material", library, name="Material") - ifcopenshell.api.run("material.assign_material", library, product=element, material=material) + ifcopenshell.api.run("material.assign_material", library, products=[element], material=material) ifcopenshell.api.run("project.append_asset", self.file, library=library, element=element) assert self.file.by_type("IfcWallType")[0].HasAssociations[0].RelatingMaterial.Name == "Material" @@ -90,9 +90,9 @@ class TestAppendAsset(test.bootstrap.IFC4): element_type2 = ifcopenshell.api.run("root.create_entity", library, ifc_class="IfcWallType") ifcopenshell.api.run("type.assign_type", library, related_objects=[element], relating_type=element_type) material = ifcopenshell.api.run("material.add_material", library, name="Material") - ifcopenshell.api.run("material.assign_material", library, product=element, material=material) - ifcopenshell.api.run("material.assign_material", library, product=element_type, material=material) - ifcopenshell.api.run("material.assign_material", library, product=element_type2, material=material) + ifcopenshell.api.run("material.assign_material", library, products=[element], material=material) + ifcopenshell.api.run("material.assign_material", library, products=[element_type], material=material) + ifcopenshell.api.run("material.assign_material", library, products=[element_type2], material=material) # appending another type not connected to IfcWall directly ifcopenshell.api.run("project.append_asset", self.file, library=library, element=element_type2) @@ -111,8 +111,8 @@ class TestAppendAsset(test.bootstrap.IFC4): pset = ifcopenshell.api.run("pset.add_pset", library, product=material, name="Foo_Bar") ifcopenshell.api.run("pset.edit_pset", library, pset=pset, properties={"Foo": "Bar"}) - ifcopenshell.api.run("material.assign_material", library, product=element1, material=material) - ifcopenshell.api.run("material.assign_material", library, product=element2, material=material) + ifcopenshell.api.run("material.assign_material", library, products=[element1], material=material) + ifcopenshell.api.run("material.assign_material", library, products=[element2], material=material) new1 = ifcopenshell.api.run("project.append_asset", self.file, library=library, element=element1) new2 = ifcopenshell.api.run("project.append_asset", self.file, library=library, element=element2) @@ -139,8 +139,8 @@ class TestAppendAsset(test.bootstrap.IFC4): ifcopenshell.api.run("material.add_layer", library, layer_set=layer_set2, material=material) ifcopenshell.api.run("material.add_layer", library, layer_set=layer_set2, material=material) - ifcopenshell.api.run("material.assign_material", library, product=element1, material=layer_set1) - ifcopenshell.api.run("material.assign_material", library, product=element2, material=layer_set2) + ifcopenshell.api.run("material.assign_material", library, products=[element1], material=layer_set1) + ifcopenshell.api.run("material.assign_material", library, products=[element2], material=layer_set2) new1 = ifcopenshell.api.run("project.append_asset", self.file, library=library, element=element1) new2 = ifcopenshell.api.run("project.append_asset", self.file, library=library, element=element2) @@ -160,7 +160,7 @@ class TestAppendAsset(test.bootstrap.IFC4): element.OwnerHistory = history material = ifcopenshell.api.run("material.add_material", library, name="Material") - rel = ifcopenshell.api.run("material.assign_material", library, product=element, material=material) + rel = ifcopenshell.api.run("material.assign_material", library, products=[element], material=material) # We share a history. This ensures that we continue to check all # whitelisted inverses even though one of the subelements (i.e. this # shared history) is already processed. See bug #2837. @@ -201,7 +201,7 @@ class TestAppendAsset(test.bootstrap.IFC4): element = ifcopenshell.api.run("root.create_entity", library, ifc_class="IfcWallType") material = ifcopenshell.api.run("material.add_material", library, name="Material") - ifcopenshell.api.run("material.assign_material", library, product=element, material=material) + ifcopenshell.api.run("material.assign_material", library, products=[element], material=material) style = ifcopenshell.api.run("style.add_style", library) ifcopenshell.api.run("style.assign_material_style", library, material=material, style=style, context=context) ifcopenshell.api.run("project.append_asset", self.file, library=library, element=element) @@ -378,7 +378,7 @@ class TestAppendAsset(test.bootstrap.IFC4): library = ifcopenshell.api.run("project.create_file") element = ifcopenshell.api.run("root.create_entity", library, ifc_class="IfcWall") material = ifcopenshell.api.run("material.add_material", library, name="Material") - ifcopenshell.api.run("material.assign_material", library, product=element, material=material) + ifcopenshell.api.run("material.assign_material", library, products=[element], material=material) ifcopenshell.api.run("project.append_asset", self.file, library=library, element=element) assert ifcopenshell.util.element.get_material(self.file.by_type("IfcWall")[0]).Name == "Material" @@ -389,9 +389,9 @@ class TestAppendAsset(test.bootstrap.IFC4): element_type2 = ifcopenshell.api.run("root.create_entity", library, ifc_class="IfcWallType") ifcopenshell.api.run("type.assign_type", library, related_objects=[element], relating_type=element_type) material = ifcopenshell.api.run("material.add_material", library, name="Material") - ifcopenshell.api.run("material.assign_material", library, product=element, material=material) - ifcopenshell.api.run("material.assign_material", library, product=element_type, material=material) - ifcopenshell.api.run("material.assign_material", library, product=element_type2, material=material) + ifcopenshell.api.run("material.assign_material", library, products=[element], material=material) + ifcopenshell.api.run("material.assign_material", library, products=[element_type], material=material) + ifcopenshell.api.run("material.assign_material", library, products=[element_type2], material=material) ifcopenshell.api.run("project.append_asset", self.file, library=library, element=element) assert [e.GlobalId for e in self.file.by_type("IfcWallType")] == [element_type.GlobalId] diff --git a/src/ifcopenshell-python/test/api/root/test_remove_product.py b/src/ifcopenshell-python/test/api/root/test_remove_product.py index 821e9cb3dc..ab2d2cf568 100644 --- a/src/ifcopenshell-python/test/api/root/test_remove_product.py +++ b/src/ifcopenshell-python/test/api/root/test_remove_product.py @@ -369,7 +369,7 @@ class TestRemoveProduct(test.bootstrap.IFC4): def test_removing_all_material_relationships_of_an_element(self): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") material = ifcopenshell.api.run("material.add_material", self.file, name="Foo") - ifcopenshell.api.run("material.assign_material", self.file, product=element, material=material) + ifcopenshell.api.run("material.assign_material", self.file, products=[element], material=material) ifcopenshell.api.run("root.remove_product", self.file, product=element) assert not self.file.by_type("IfcRelAssociatesMaterial") assert self.file.by_type("IfcMaterial") diff --git a/src/ifcopenshell-python/test/api/style/test_assign_material_style.py b/src/ifcopenshell-python/test/api/style/test_assign_material_style.py index 7c25ba578f..01325d8b99 100644 --- a/src/ifcopenshell-python/test/api/style/test_assign_material_style.py +++ b/src/ifcopenshell-python/test/api/style/test_assign_material_style.py @@ -75,7 +75,7 @@ class TestAssignMaterialStyle(test.bootstrap.IFC4): "material.add_constituent", self.file, constituent_set=material_set, material=material ) constituent.Name = name - ifcopenshell.api.run("material.assign_material", self.file, product=element, material=material_set) + ifcopenshell.api.run("material.assign_material", self.file, products=[element], material=material_set) ifcopenshell.api.run("style.assign_material_style", self.file, material=material, style=style, context=context) diff --git a/src/ifcopenshell-python/test/api/style/test_unassign_material_style.py b/src/ifcopenshell-python/test/api/style/test_unassign_material_style.py index 936af3aa96..47c6e6a928 100644 --- a/src/ifcopenshell-python/test/api/style/test_unassign_material_style.py +++ b/src/ifcopenshell-python/test/api/style/test_unassign_material_style.py @@ -71,7 +71,7 @@ class TestAssignMaterialStyle(test.bootstrap.IFC4): "material.add_constituent", self.file, constituent_set=material_set, material=material ) constituent.Name = name - ifcopenshell.api.run("material.assign_material", self.file, product=element, material=material_set) + ifcopenshell.api.run("material.assign_material", self.file, products=[element], material=material_set) ifcopenshell.api.run("style.assign_material_style", self.file, material=material, style=style, context=context) ifcopenshell.api.run( diff --git a/src/ifcopenshell-python/test/api/test_api.py b/src/ifcopenshell-python/test/api/test_api.py index acd375b203..7f19b170e2 100644 --- a/src/ifcopenshell-python/test/api/test_api.py +++ b/src/ifcopenshell-python/test/api/test_api.py @@ -164,3 +164,13 @@ class TestTemporarySupportForDeprecatedAPIArguments(test.bootstrap.IFC4): ifcopenshell.api.run("system.unassign_system", self.file, product=element2, system=system) assert ifcopenshell.util.system.get_system_elements(system) == [] + + @deprecation_check + def test_assign_element_single_material(self): + element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + material = ifcopenshell.api.run("material.add_material", self.file, name="CON01") + ifcopenshell.api.run( + "material.assign_material", self.file, product=element, type="IfcMaterial", material=material + ) + assert len(self.file.by_type("IfcRelAssociatesMaterial")) == 1 + assert element.HasAssociations[0].RelatingMaterial == material diff --git a/src/ifcopenshell-python/test/api/type/test_assign_type.py b/src/ifcopenshell-python/test/api/type/test_assign_type.py index 994146a16d..b7a9550b80 100644 --- a/src/ifcopenshell-python/test/api/type/test_assign_type.py +++ b/src/ifcopenshell-python/test/api/type/test_assign_type.py @@ -71,7 +71,7 @@ class TestAssignType(test.bootstrap.IFC4): context = self.file.createIfcGeometricRepresentationContext() rep = self.file.createIfcShapeRepresentation(ContextOfItems=context) ifcopenshell.api.run("geometry.assign_representation", self.file, product=element_type, representation=rep) - ifcopenshell.api.run("material.assign_material", self.file, product=element_type, type="IfcMaterialLayerSet") + ifcopenshell.api.run("material.assign_material", self.file, products=[element_type], type="IfcMaterialLayerSet") element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") ifcopenshell.api.run( @@ -120,7 +120,7 @@ class TestAssignType(test.bootstrap.IFC4): material_types += ("IfcMaterialProfileSet",) for material_type in material_types: element_type = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") - ifcopenshell.api.run("material.assign_material", self.file, product=element_type, type=material_type) + ifcopenshell.api.run("material.assign_material", self.file, products=[element_type], type=material_type) element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element], relating_type=element_type) material = ifcopenshell.util.element.get_material(element) @@ -130,7 +130,7 @@ class TestAssignType(test.bootstrap.IFC4): def test_do_not_reassign_material_if_it_was_assigned_previously(self): element1 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") element_type = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") - ifcopenshell.api.run("material.assign_material", self.file, product=element_type, type="IfcMaterialLayerSet") + ifcopenshell.api.run("material.assign_material", self.file, products=[element_type], type="IfcMaterialLayerSet") ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element1], relating_type=element_type) assert (material := ifcopenshell.util.element.get_material(element1)) material_id = material.id() diff --git a/src/ifcopenshell-python/test/api/type/test_unassign_type.py b/src/ifcopenshell-python/test/api/type/test_unassign_type.py index adab2387f9..2df994f4a9 100644 --- a/src/ifcopenshell-python/test/api/type/test_unassign_type.py +++ b/src/ifcopenshell-python/test/api/type/test_unassign_type.py @@ -48,7 +48,7 @@ class TestUnassignType(test.bootstrap.IFC4): context = self.file.createIfcGeometricRepresentationContext() rep = self.file.createIfcShapeRepresentation(ContextOfItems=context) ifcopenshell.api.run("geometry.assign_representation", self.file, product=element_type, representation=rep) - ifcopenshell.api.run("material.assign_material", self.file, product=element_type, type="IfcMaterialLayerSet") + ifcopenshell.api.run("material.assign_material", self.file, products=[element_type], type="IfcMaterialLayerSet") element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element], relating_type=element_type) diff --git a/src/ifcopenshell-python/test/util/test_element.py b/src/ifcopenshell-python/test/util/test_element.py index c4adf9c968..c8a63e299d 100644 --- a/src/ifcopenshell-python/test/util/test_element.py +++ b/src/ifcopenshell-python/test/util/test_element.py @@ -339,52 +339,52 @@ class TestGetMaterial(test.bootstrap.IFC4): def test_getting_the_material_of_a_product(self): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") material = ifcopenshell.api.run("material.add_material", self.file) - ifcopenshell.api.run("material.assign_material", self.file, product=element, material=material) + ifcopenshell.api.run("material.assign_material", self.file, products=[element], material=material) assert subject.get_material(element) == material def test_getting_a_material_list_of_a_product(self): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") material = ifcopenshell.api.run("material.add_material", self.file) rel = ifcopenshell.api.run( - "material.assign_material", self.file, product=element, type="IfcMaterialList", material=material + "material.assign_material", self.file, products=[element], type="IfcMaterialList", material=material ) assert subject.get_material(element) == rel.RelatingMaterial def test_getting_a_material_layer_set_of_a_product(self): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") - rel = ifcopenshell.api.run("material.assign_material", self.file, product=element, type="IfcMaterialLayerSet") + rel = ifcopenshell.api.run("material.assign_material", self.file, products=[element], type="IfcMaterialLayerSet") assert subject.get_material(element) == rel.RelatingMaterial def test_getting_a_material_profile_set_of_a_product(self): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") - rel = ifcopenshell.api.run("material.assign_material", self.file, product=element, type="IfcMaterialProfileSet") + rel = ifcopenshell.api.run("material.assign_material", self.file, products=[element], type="IfcMaterialProfileSet") assert subject.get_material(element) == rel.RelatingMaterial def test_getting_a_material_layer_set_usage_of_a_product(self): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") rel = ifcopenshell.api.run( - "material.assign_material", self.file, product=element, type="IfcMaterialLayerSetUsage" + "material.assign_material", self.file, products=[element], type="IfcMaterialLayerSetUsage" ) assert subject.get_material(element) == rel.RelatingMaterial def test_getting_a_material_profile_set_usage_of_a_product(self): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") rel = ifcopenshell.api.run( - "material.assign_material", self.file, product=element, type="IfcMaterialProfileSetUsage" + "material.assign_material", self.file, products=[element], type="IfcMaterialProfileSetUsage" ) assert subject.get_material(element) == rel.RelatingMaterial def test_getting_a_material_layer_set_indirectly_from_an_assigned_usage(self): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") rel = ifcopenshell.api.run( - "material.assign_material", self.file, product=element, type="IfcMaterialLayerSetUsage" + "material.assign_material", self.file, products=[element], type="IfcMaterialLayerSetUsage" ) assert subject.get_material(element, should_skip_usage=True) == rel.RelatingMaterial.ForLayerSet def test_getting_a_material_profile_set_indirectly_from_an_assigned_usage(self): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") rel = ifcopenshell.api.run( - "material.assign_material", self.file, product=element, type="IfcMaterialProfileSetUsage" + "material.assign_material", self.file, products=[element], type="IfcMaterialProfileSetUsage" ) assert subject.get_material(element, should_skip_usage=True) == rel.RelatingMaterial.ForProfileSet @@ -393,7 +393,7 @@ class TestGetMaterial(test.bootstrap.IFC4): element_type = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element], relating_type=element_type) material = ifcopenshell.api.run("material.add_material", self.file) - ifcopenshell.api.run("material.assign_material", self.file, product=element_type, material=material) + ifcopenshell.api.run("material.assign_material", self.file, products=[element_type], material=material) assert subject.get_material(element) == material def test_getting_an_overridden_material_from_the_elements_occurrence(self): @@ -401,9 +401,9 @@ class TestGetMaterial(test.bootstrap.IFC4): element_type = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element], relating_type=element_type) material = ifcopenshell.api.run("material.add_material", self.file) - ifcopenshell.api.run("material.assign_material", self.file, product=element_type, material=material) + ifcopenshell.api.run("material.assign_material", self.file, products=[element_type], material=material) material = ifcopenshell.api.run("material.add_material", self.file) - ifcopenshell.api.run("material.assign_material", self.file, product=element, material=material) + ifcopenshell.api.run("material.assign_material", self.file, products=[element], material=material) assert subject.get_material(element) == material def test_getting_direct_materials_without_checking_inheritance(self): @@ -411,7 +411,7 @@ class TestGetMaterial(test.bootstrap.IFC4): element_type = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element], relating_type=element_type) material = ifcopenshell.api.run("material.add_material", self.file) - ifcopenshell.api.run("material.assign_material", self.file, product=element_type, material=material) + ifcopenshell.api.run("material.assign_material", self.file, products=[element_type], material=material) assert subject.get_material(element, should_inherit=False) is None @@ -419,7 +419,7 @@ class TestGetMaterials(test.bootstrap.IFC4): def test_getting_the_materials_of_a_product(self): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") material = ifcopenshell.api.run("material.add_material", self.file) - ifcopenshell.api.run("material.assign_material", self.file, product=element, material=material) + ifcopenshell.api.run("material.assign_material", self.file, products=[element], material=material) assert subject.get_materials(element) == [material] @@ -440,7 +440,7 @@ class TestGetStyles(test.bootstrap.IFC4): ) material = ifcopenshell.api.run("material.add_material", self.file) - ifcopenshell.api.run("material.assign_material", self.file, product=element, material=material) + ifcopenshell.api.run("material.assign_material", self.file, products=[element], material=material) style = ifcopenshell.api.run("style.add_style", self.file) ifcopenshell.api.run( @@ -487,7 +487,7 @@ class TestGetElementsByMaterial(test.bootstrap.IFC4): def test_getting_elements_of_a_material(self): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") material = ifcopenshell.api.run("material.add_material", self.file) - ifcopenshell.api.run("material.assign_material", self.file, product=element, material=material) + ifcopenshell.api.run("material.assign_material", self.file, products=[element], material=material) assert subject.get_elements_by_material(self.file, material) == {element} def test_getting_elements_of_a_material_layer_set(self): @@ -497,8 +497,8 @@ class TestGetElementsByMaterial(test.bootstrap.IFC4): material = ifcopenshell.api.run("material.add_material", self.file) material_set = ifcopenshell.api.run("material.add_material_set", self.file, set_type="IfcMaterialLayerSet") ifcopenshell.api.run("material.add_layer", self.file, layer_set=material_set, material=material) - ifcopenshell.api.run("material.assign_material", self.file, product=element_type, material=material_set) - ifcopenshell.api.run("material.assign_material", self.file, product=element, type="IfcMaterialLayerSetUsage") + ifcopenshell.api.run("material.assign_material", self.file, products=[element_type], material=material_set) + ifcopenshell.api.run("material.assign_material", self.file, products=[element], type="IfcMaterialLayerSetUsage") usage = self.file.by_type("IfcMaterialLayerSetUsage")[0] assert subject.get_elements_by_material(self.file, material) == {element, element_type} assert subject.get_elements_by_material(self.file, material_set) == {element, element_type} @@ -511,8 +511,8 @@ class TestGetElementsByMaterial(test.bootstrap.IFC4): material = ifcopenshell.api.run("material.add_material", self.file) material_set = ifcopenshell.api.run("material.add_material_set", self.file, set_type="IfcMaterialProfileSet") ifcopenshell.api.run("material.add_profile", self.file, profile_set=material_set, material=material) - ifcopenshell.api.run("material.assign_material", self.file, product=element_type, material=material_set) - ifcopenshell.api.run("material.assign_material", self.file, product=element, type="IfcMaterialProfileSetUsage") + ifcopenshell.api.run("material.assign_material", self.file, products=[element_type], material=material_set) + ifcopenshell.api.run("material.assign_material", self.file, products=[element], type="IfcMaterialProfileSetUsage") usage = self.file.by_type("IfcMaterialProfileSetUsage")[0] assert subject.get_elements_by_material(self.file, material) == {element, element_type} assert subject.get_elements_by_material(self.file, material_set) == {element, element_type} @@ -525,7 +525,7 @@ class TestGetElementsByMaterial(test.bootstrap.IFC4): "material.add_material_set", self.file, set_type="IfcMaterialConstituentSet" ) ifcopenshell.api.run("material.add_constituent", self.file, constituent_set=material_set, material=material) - ifcopenshell.api.run("material.assign_material", self.file, product=element, material=material_set) + ifcopenshell.api.run("material.assign_material", self.file, products=[element], material=material_set) assert subject.get_elements_by_material(self.file, material) == {element} assert subject.get_elements_by_material(self.file, material_set) == {element} @@ -534,7 +534,7 @@ class TestGetElementsByMaterial(test.bootstrap.IFC4): material = ifcopenshell.api.run("material.add_material", self.file) material_set = ifcopenshell.api.run("material.add_material_set", self.file, set_type="IfcMaterialList") ifcopenshell.api.run("material.add_list_item", self.file, material_list=material_set, material=material) - ifcopenshell.api.run("material.assign_material", self.file, product=element, material=material_set) + ifcopenshell.api.run("material.assign_material", self.file, products=[element], material=material_set) assert subject.get_elements_by_material(self.file, material) == {element} assert subject.get_elements_by_material(self.file, material_set) == {element} @@ -585,7 +585,7 @@ class TestGetElementsByStyle(test.bootstrap.IFC4): def test_getting_elements_of_a_styled_material(self): element = self.file.createIfcWall() material = ifcopenshell.api.run("material.add_material", self.file) - ifcopenshell.api.run("material.assign_material", self.file, product=element, material=material) + ifcopenshell.api.run("material.assign_material", self.file, products=[element], material=material) style = self.file.createIfcSurfaceStyle() self.file.createIfcMaterialDefinitionRepresentation( RepresentedMaterial=material, diff --git a/src/ifcopenshell-python/test/util/test_selector.py b/src/ifcopenshell-python/test/util/test_selector.py index 6565142429..d8ba4bb174 100644 --- a/src/ifcopenshell-python/test/util/test_selector.py +++ b/src/ifcopenshell-python/test/util/test_selector.py @@ -85,7 +85,7 @@ class TestGetElementValue(test.bootstrap.IFC4): layer = ifcopenshell.api.run("material.add_layer", self.file, layer_set=material_set, material=material) layer.Name = "L2" ifcopenshell.api.run("material.edit_layer", self.file, layer=layer, attributes={"LayerThickness": 13}) - ifcopenshell.api.run("material.assign_material", self.file, product=element, material=material_set) + ifcopenshell.api.run("material.assign_material", self.file, products=[element], material=material_set) assert subject.get_element_value(element, "material.MaterialLayers.Name") == ["L1", "L2"] # Allow to use "item" to generically select an item in a material set assert subject.get_element_value(element, "material.item.Name") == ["L1", "L2"] @@ -109,7 +109,7 @@ class TestGetElementValue(test.bootstrap.IFC4): ) layer = ifcopenshell.api.run("material.add_layer", self.file, layer_set=material_set, material=material) layer.Name = "L1" - ifcopenshell.api.run("material.assign_material", self.file, product=element, material=material_set) + ifcopenshell.api.run("material.assign_material", self.file, products=[element], material=material_set) assert subject.get_element_value(element, "material.item.Name.0") == "L1" assert subject.get_element_value(element, "material.item.Name.1") is None @@ -180,7 +180,7 @@ class TestFilterElements(test.bootstrap.IFC4): element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") assert subject.filter_elements(self.file, "IfcWall, material=NULL") == {element, element2} material = ifcopenshell.api.run("material.add_material", self.file, name="CON01") - ifcopenshell.api.run("material.assign_material", self.file, product=element, material=material) + ifcopenshell.api.run("material.assign_material", self.file, products=[element], material=material) assert subject.filter_elements(self.file, "IfcWall, material=CON01") == {element} assert subject.filter_elements(self.file, "IfcWall, material!=CON01") == {element2} @@ -511,7 +511,7 @@ class TestSelector(test.bootstrap.IFC4): def test_selecting_via_a_material(self): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") material = ifcopenshell.api.run("material.add_material", self.file, name="CON01") - ifcopenshell.api.run("material.assign_material", self.file, product=element, material=material) + ifcopenshell.api.run("material.assign_material", self.file, products=[element], material=material) assert set(subject.Selector.parse(self.file, '.IfcWall[material.Name="CON01"]')) == {element} def test_selecting_via_a_material_set(self): @@ -522,7 +522,7 @@ class TestSelector(test.bootstrap.IFC4): ) layer = ifcopenshell.api.run("material.add_layer", self.file, layer_set=material_set, material=material) ifcopenshell.api.run("material.edit_layer", self.file, layer=layer, attributes={"LayerThickness": 13}) - ifcopenshell.api.run("material.assign_material", self.file, product=element, material=material_set) + ifcopenshell.api.run("material.assign_material", self.file, products=[element], material=material_set) assert set(subject.Selector.parse(self.file, '.IfcWall[material.LayerSetName="FOO"]')) == {element} def test_selecting_via_a_material_set_item(self): @@ -534,7 +534,7 @@ class TestSelector(test.bootstrap.IFC4): ) layer = ifcopenshell.api.run("material.add_layer", self.file, layer_set=material_set, material=material) layer = ifcopenshell.api.run("material.add_layer", self.file, layer_set=material_set, material=material2) - ifcopenshell.api.run("material.assign_material", self.file, product=element, material=material_set) + ifcopenshell.api.run("material.assign_material", self.file, products=[element], material=material_set) assert set(subject.Selector.parse(self.file, '.IfcWall[material.item.Material.Name="CON01"]')) == {element} assert set(subject.Selector.parse(self.file, '.IfcWall[material.item.Material.Name="CON02"]')) == {element} assert set(subject.Selector.parse(self.file, '.IfcWall[material.item.Material.Name="CON03"]')) == set() diff --git a/src/ifcpatch/test/test_MergeDuplicateTypes.py b/src/ifcpatch/test/test_MergeDuplicateTypes.py index 1b2be456d6..3149f30ca4 100644 --- a/src/ifcpatch/test/test_MergeDuplicateTypes.py +++ b/src/ifcpatch/test/test_MergeDuplicateTypes.py @@ -34,7 +34,7 @@ class TestMergeDuplicateTypes(test.bootstrap.IFC4): wall_type1 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType", name="WallType") rep = self.file.createIfcShapeRepresentation(ContextOfItems=context) ifcopenshell.api.run("geometry.assign_representation", self.file, product=wall_type1, representation=rep) - ifcopenshell.api.run("material.assign_material", self.file, product=wall_type1, type="IfcMaterialLayerSet") + ifcopenshell.api.run("material.assign_material", self.file, products=[wall_type1], type="IfcMaterialLayerSet") ifcopenshell.api.run( "type.assign_type", self.file, @@ -47,7 +47,7 @@ class TestMergeDuplicateTypes(test.bootstrap.IFC4): wall_type2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType", name="WallType") rep = self.file.createIfcShapeRepresentation(ContextOfItems=context) ifcopenshell.api.run("geometry.assign_representation", self.file, product=wall_type2, representation=rep) - ifcopenshell.api.run("material.assign_material", self.file, product=wall_type2, type="IfcMaterialLayerSet") + ifcopenshell.api.run("material.assign_material", self.file, products=[wall_type2], type="IfcMaterialLayerSet") ifcopenshell.api.run( "type.assign_type", self.file, diff --git a/src/ifctester/test/test_facet.py b/src/ifctester/test/test_facet.py index d34e9426f7..bd89a00946 100644 --- a/src/ifctester/test/test_facet.py +++ b/src/ifctester/test/test_facet.py @@ -1260,7 +1260,7 @@ class TestMaterial: element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall") run("Elements without a material always fail", facet=facet, inst=element, expected=False) material = ifcopenshell.api.run("material.add_material", ifc) - ifcopenshell.api.run("material.assign_material", ifc, product=element, material=material) + ifcopenshell.api.run("material.assign_material", ifc, products=[element], material=material) run("Elements with any material will pass an empty material facet", facet=facet, inst=element, expected=True) run("A required facet checks all parameters as normal", facet=facet, inst=element, expected=True) @@ -1275,7 +1275,7 @@ class TestMaterial: facet = Material(value="Foo") element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall") material = ifcopenshell.api.run("material.add_material", ifc) - ifcopenshell.api.run("material.assign_material", ifc, product=element, material=material) + ifcopenshell.api.run("material.assign_material", ifc, products=[element], material=material) material.Name = "Foo" run("A material name may pass the value check", facet=facet, inst=element, expected=True) material.Name = "Bar" @@ -1286,7 +1286,7 @@ class TestMaterial: facet = Material(value="Foo") element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall") material_set = ifcopenshell.api.run("material.add_material_set", ifc, set_type="IfcMaterialList") - ifcopenshell.api.run("material.assign_material", ifc, product=element, material=material_set) + ifcopenshell.api.run("material.assign_material", ifc, products=[element], material=material_set) material = ifcopenshell.api.run("material.add_material", ifc) ifcopenshell.api.run("material.add_list_item", ifc, material_list=material_set, material=material) material.Name = "Foo" @@ -1299,7 +1299,7 @@ class TestMaterial: facet = Material(value="Foo") element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall") material_set = ifcopenshell.api.run("material.add_material_set", ifc, set_type="IfcMaterialLayerSet") - ifcopenshell.api.run("material.assign_material", ifc, product=element, material=material_set) + ifcopenshell.api.run("material.assign_material", ifc, products=[element], material=material_set) material = ifcopenshell.api.run("material.add_material", ifc) layer = ifcopenshell.api.run("material.add_layer", ifc, layer_set=material_set, material=material) layer.Name = "Foo" @@ -1318,7 +1318,7 @@ class TestMaterial: facet = Material(value="Foo") element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall") material_set = ifcopenshell.api.run("material.add_material_set", ifc, set_type="IfcMaterialProfileSet") - ifcopenshell.api.run("material.assign_material", ifc, product=element, material=material_set) + ifcopenshell.api.run("material.assign_material", ifc, products=[element], material=material_set) material = ifcopenshell.api.run("material.add_material", ifc) profile = ifcopenshell.api.run("material.add_profile", ifc, profile_set=material_set, material=material) profile.Name = "Foo" @@ -1338,7 +1338,7 @@ class TestMaterial: facet = Material(value="Foo") element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall") material_set = ifcopenshell.api.run("material.add_material_set", ifc, set_type="IfcMaterialConstituentSet") - ifcopenshell.api.run("material.assign_material", ifc, product=element, material=material_set) + ifcopenshell.api.run("material.assign_material", ifc, products=[element], material=material_set) run("A constituent set with no data will fail a value check", facet=facet, inst=element, expected=False) material = ifcopenshell.api.run("material.add_material", ifc) constituent = ifcopenshell.api.run( @@ -1376,7 +1376,7 @@ class TestMaterial: element_type = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWallType") ifcopenshell.api.run("type.assign_type", ifc, related_objects=[element], relating_type=element_type) material = ifcopenshell.api.run("material.add_material", ifc) - ifcopenshell.api.run("material.assign_material", ifc, product=element_type, material=material) + ifcopenshell.api.run("material.assign_material", ifc, products=[element_type], material=material) material.Name = "Foo" facet = Material(value="Foo") run("Occurrences can inherit materials from their types", facet=facet, inst=element, expected=True) @@ -1386,10 +1386,10 @@ class TestMaterial: element_type = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWallType") ifcopenshell.api.run("type.assign_type", ifc, related_objects=[element], relating_type=element_type) material = ifcopenshell.api.run("material.add_material", ifc) - ifcopenshell.api.run("material.assign_material", ifc, product=element_type, material=material) + ifcopenshell.api.run("material.assign_material", ifc, products=[element_type], material=material) material.Name = "Bar" material = ifcopenshell.api.run("material.add_material", ifc) - ifcopenshell.api.run("material.assign_material", ifc, product=element, material=material) + ifcopenshell.api.run("material.assign_material", ifc, products=[element], material=material) material.Name = "Foo" facet = Material(value="Foo") run("Occurrences can override materials from their types", facet=facet, inst=element, expected=True)