diff --git a/src/blenderbim/blenderbim/bim/module/material/prop.py b/src/blenderbim/blenderbim/bim/module/material/prop.py index 9789dd18e7..4b83a1e042 100644 --- a/src/blenderbim/blenderbim/bim/module/material/prop.py +++ b/src/blenderbim/blenderbim/bim/module/material/prop.py @@ -114,6 +114,7 @@ def get_material_types(self, context): class Material(PropertyGroup): name: StringProperty(name="Name") ifc_definition_id: IntProperty(name="IFC Definition ID") + total_elements: IntProperty(name="Total Elements") class BIMMaterialProperties(PropertyGroup): diff --git a/src/blenderbim/blenderbim/bim/module/material/ui.py b/src/blenderbim/blenderbim/bim/module/material/ui.py index 7ea70c5813..e6e6418fb5 100644 --- a/src/blenderbim/blenderbim/bim/module/material/ui.py +++ b/src/blenderbim/blenderbim/bim/module/material/ui.py @@ -389,3 +389,6 @@ class BIM_UL_materials(UIList): if item: row = layout.row(align=True) row.label(text=item.name) + row2 = row.row() + row2.alignment = "RIGHT" + row2.label(text=str(item.total_elements)) diff --git a/src/blenderbim/blenderbim/tool/material.py b/src/blenderbim/blenderbim/tool/material.py index 0e27d54803..b2193b5dc2 100644 --- a/src/blenderbim/blenderbim/tool/material.py +++ b/src/blenderbim/blenderbim/tool/material.py @@ -61,6 +61,7 @@ class Material(blenderbim.core.tool.Material): new.name = "Unnamed" else: new.name = material.Name or "Unnamed" + new.total_elements = len(set(ifcopenshell.util.element.get_elements_by_material(tool.Ifc.get(), material))) @classmethod def is_editing_materials(cls): diff --git a/src/blenderbim/test/tool/test_material.py b/src/blenderbim/test/tool/test_material.py index 093aabec41..1637a00440 100644 --- a/src/blenderbim/test/tool/test_material.py +++ b/src/blenderbim/test/tool/test_material.py @@ -82,6 +82,7 @@ class TestImportMaterialDefinitions(NewFile): props = bpy.context.scene.BIMMaterialProperties assert props.materials[0].ifc_definition_id == material.id() assert props.materials[0].name == "Name" + assert props.materials[0].total_elements == 0 def test_import_material_layer_sets(self): ifc = ifcopenshell.file() @@ -91,6 +92,7 @@ class TestImportMaterialDefinitions(NewFile): props = bpy.context.scene.BIMMaterialProperties assert props.materials[0].ifc_definition_id == material.id() assert props.materials[0].name == "Name" + assert props.materials[0].total_elements == 0 def test_import_material_profile_sets(self): ifc = ifcopenshell.file() @@ -100,6 +102,7 @@ class TestImportMaterialDefinitions(NewFile): props = bpy.context.scene.BIMMaterialProperties assert props.materials[0].ifc_definition_id == material.id() assert props.materials[0].name == "Name" + assert props.materials[0].total_elements == 0 def test_import_material_constituent_sets(self): ifc = ifcopenshell.file() @@ -109,6 +112,7 @@ class TestImportMaterialDefinitions(NewFile): props = bpy.context.scene.BIMMaterialProperties assert props.materials[0].ifc_definition_id == material.id() assert props.materials[0].name == "Name" + assert props.materials[0].total_elements == 0 def test_import_material_lists(self): ifc = ifcopenshell.file() @@ -118,6 +122,7 @@ class TestImportMaterialDefinitions(NewFile): props = bpy.context.scene.BIMMaterialProperties assert props.materials[0].ifc_definition_id == material.id() assert props.materials[0].name == "Unnamed" + assert props.materials[0].total_elements == 0 class TestIsEditingMaterials(NewFile): diff --git a/src/ifcopenshell-python/ifcopenshell/util/element.py b/src/ifcopenshell-python/ifcopenshell/util/element.py index 0f7b1b1c66..caa618d373 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/element.py +++ b/src/ifcopenshell-python/ifcopenshell/util/element.py @@ -133,6 +133,29 @@ def get_material(element, should_skip_usage=False): return get_material(relating_type, should_skip_usage) +def get_elements_by_material(ifc_file, material): + results = [] + for inverse in ifc_file.get_inverse(material): + if inverse.is_a("IfcRelAssociatesMaterial"): + results.extend(inverse.RelatedObjects) + elif inverse.is_a("IfcMaterialLayer"): + for material_set in inverse.ToMaterialLayerSet: + results.extend(get_elements_by_material(ifc_file, material_set)) + elif inverse.is_a("IfcMaterialProfile"): + for material_set in inverse.ToMaterialProfileSet: + results.extend(get_elements_by_material(ifc_file, material_set)) + elif inverse.is_a("IfcMaterialConstituent"): + for material_set in inverse.ToMaterialConstituentSet: + results.extend(get_elements_by_material(ifc_file, material_set)) + elif inverse.is_a("IfcMaterialLayerSetUsage"): + results.extend(get_elements_by_material(ifc_file, inverse)) + elif inverse.is_a("IfcMaterialProfileSetUsage"): + results.extend(get_elements_by_material(ifc_file, inverse)) + elif inverse.is_a("IfcMaterialList"): + results.extend(get_elements_by_material(ifc_file, inverse)) + return results + + def get_layers(ifc_file, element): layers = [] representations = [] diff --git a/src/ifcopenshell-python/test/util/test_element.py b/src/ifcopenshell-python/test/util/test_element.py index 3ad1ecc4cd..8a14e6993f 100644 --- a/src/ifcopenshell-python/test/util/test_element.py +++ b/src/ifcopenshell-python/test/util/test_element.py @@ -268,6 +268,60 @@ class TestGetMaterial(test.bootstrap.IFC4): assert subject.get_material(element) == material +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) + assert subject.get_elements_by_material(self.file, material) == [element] + + def test_getting_elements_of_a_material_layer_set(self): + element = 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("type.assign_type", self.file, related_object=element, relating_type=element_type) + 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") + usage = self.file.by_type("IfcMaterialLayerSetUsage")[0] + assert set(subject.get_elements_by_material(self.file, material)) == {element, element_type} + assert set(subject.get_elements_by_material(self.file, material_set)) == {element, element_type} + assert set(subject.get_elements_by_material(self.file, usage)) == {element} + + def test_getting_elements_of_a_material_profile_set(self): + element = 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("type.assign_type", self.file, related_object=element, relating_type=element_type) + 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") + usage = self.file.by_type("IfcMaterialProfileSetUsage")[0] + assert set(subject.get_elements_by_material(self.file, material)) == {element, element_type} + assert set(subject.get_elements_by_material(self.file, material_set)) == {element, element_type} + assert set(subject.get_elements_by_material(self.file, usage)) == {element} + + def test_getting_elements_of_a_material_constituent_set(self): + element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + material = ifcopenshell.api.run("material.add_material", self.file) + material_set = ifcopenshell.api.run("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) + assert set(subject.get_elements_by_material(self.file, material)) == {element} + assert set(subject.get_elements_by_material(self.file, material_set)) == {element} + + def test_getting_elements_of_a_material_list(self): + element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + 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) + assert set(subject.get_elements_by_material(self.file, material)) == {element} + assert set(subject.get_elements_by_material(self.file, material_set)) == {element} + + class TestGetlayers(test.bootstrap.IFC4): def test_getting_the_layer_of_a_product_representation(self): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")