diff --git a/src/blenderbim/blenderbim/bim/module/material/__init__.py b/src/blenderbim/blenderbim/bim/module/material/__init__.py index 47bd7b6d0f..8ba682ae5c 100644 --- a/src/blenderbim/blenderbim/bim/module/material/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/material/__init__.py @@ -44,6 +44,7 @@ classes = ( operator.RemoveMaterialSet, operator.RemoveProfile, operator.ReorderMaterialSetItem, + operator.SelectByMaterial, operator.UnassignMaterial, operator.UnlinkMaterial, prop.Material, diff --git a/src/blenderbim/blenderbim/bim/module/material/data.py b/src/blenderbim/blenderbim/bim/module/material/data.py index 9d758e685a..8929bd00bc 100644 --- a/src/blenderbim/blenderbim/bim/module/material/data.py +++ b/src/blenderbim/blenderbim/bim/module/material/data.py @@ -41,6 +41,12 @@ class MaterialsData: @classmethod def total_materials(cls): + if tool.Ifc.get_schema() == "IFC2X3": + return ( + len(tool.Ifc.get().by_type("IfcMaterial")) + + len(tool.Ifc.get().by_type("IfcMaterialLayerSet")) + + len(tool.Ifc.get().by_type("IfcMaterialList")) + ) return ( len(tool.Ifc.get().by_type("IfcMaterial")) + len(tool.Ifc.get().by_type("IfcMaterialConstituentSet")) diff --git a/src/blenderbim/blenderbim/bim/module/material/operator.py b/src/blenderbim/blenderbim/bim/module/material/operator.py index e2d0542ae8..37e4781581 100644 --- a/src/blenderbim/blenderbim/bim/module/material/operator.py +++ b/src/blenderbim/blenderbim/bim/module/material/operator.py @@ -49,6 +49,16 @@ class DisableEditingMaterials(bpy.types.Operator, tool.Ifc.Operator): core.disable_editing_materials(tool.Material) +class SelectByMaterial(bpy.types.Operator, tool.Ifc.Operator): + bl_idname = "bim.select_by_material" + bl_label = "Select By Material" + bl_options = {"REGISTER", "UNDO"} + material: bpy.props.IntProperty() + + def _execute(self, context): + core.select_by_material(tool.Material, material=tool.Ifc.get().by_id(self.material)) + + class AssignParameterizedProfile(bpy.types.Operator): bl_idname = "bim.assign_parameterized_profile" bl_label = "Assign Parameterized Profile" diff --git a/src/blenderbim/blenderbim/bim/module/material/ui.py b/src/blenderbim/blenderbim/bim/module/material/ui.py index e6e6418fb5..7791466af6 100644 --- a/src/blenderbim/blenderbim/bim/module/material/ui.py +++ b/src/blenderbim/blenderbim/bim/module/material/ui.py @@ -61,11 +61,15 @@ class BIM_PT_materials(Panel): row.operator("bim.add_material", text="", icon="ADD") if self.props.materials and self.props.active_material_index < len(self.props.materials): material = self.props.materials[self.props.active_material_index] + op = row.operator("bim.select_by_material", text="", icon="RESTRICT_SELECT_OFF") + op.material = material.ifc_definition_id row.operator("bim.remove_material", text="", icon="X").material = material.ifc_definition_id else: row.operator("bim.add_material_set", text="", icon="ADD").set_type = self.props.material_type if self.props.materials and self.props.active_material_index < len(self.props.materials): material = self.props.materials[self.props.active_material_index] + op = row.operator("bim.select_by_material", text="", icon="RESTRICT_SELECT_OFF") + op.material = material.ifc_definition_id row.operator("bim.remove_material_set", text="", icon="X").material = material.ifc_definition_id self.layout.template_list("BIM_UL_materials", "", self.props, "materials", self.props, "active_material_index") diff --git a/src/blenderbim/blenderbim/core/material.py b/src/blenderbim/blenderbim/core/material.py index 15dd2442e8..48a9136ca8 100644 --- a/src/blenderbim/blenderbim/core/material.py +++ b/src/blenderbim/blenderbim/core/material.py @@ -66,3 +66,7 @@ def load_materials(material, material_type): def disable_editing_materials(material): material.disable_editing_materials() + + +def select_by_material(material_tool, material=None): + material_tool.select_elements(material_tool.get_elements_by_material(material)) diff --git a/src/blenderbim/blenderbim/core/tool.py b/src/blenderbim/blenderbim/core/tool.py index 21f8796d6c..b18e73000a 100644 --- a/src/blenderbim/blenderbim/core/tool.py +++ b/src/blenderbim/blenderbim/core/tool.py @@ -280,9 +280,11 @@ class Material: def disable_editing_materials(cls): pass def enable_editing_materials(cls): pass def get_active_material_type(cls): pass + def get_elements_by_material(cls, material): pass def get_name(cls, obj): pass def import_material_definitions(cls, material_type): pass def is_editing_materials(cls): pass + def select_elements(cls, elements): pass @interface diff --git a/src/blenderbim/blenderbim/tool/material.py b/src/blenderbim/blenderbim/tool/material.py index b2193b5dc2..9ac4345587 100644 --- a/src/blenderbim/blenderbim/tool/material.py +++ b/src/blenderbim/blenderbim/tool/material.py @@ -44,6 +44,10 @@ class Material(blenderbim.core.tool.Material): def get_active_material_type(cls): return bpy.context.scene.BIMMaterialProperties.material_type + @classmethod + def get_elements_by_material(cls, material): + return set(ifcopenshell.util.element.get_elements_by_material(tool.Ifc.get(), material)) + @classmethod def get_name(cls, obj): return obj.name @@ -66,3 +70,10 @@ class Material(blenderbim.core.tool.Material): @classmethod def is_editing_materials(cls): return bpy.context.scene.BIMMaterialProperties.is_editing + + @classmethod + def select_elements(cls, elements): + for element in elements: + obj = tool.Ifc.get_object(element) + if obj: + obj.select_set(True) diff --git a/src/blenderbim/test/bim/feature/material.feature b/src/blenderbim/test/bim/feature/material.feature index cbea52096b..8d8b87694d 100644 --- a/src/blenderbim/test/bim/feature/material.feature +++ b/src/blenderbim/test/bim/feature/material.feature @@ -110,3 +110,12 @@ Scenario: Assign material - Assign a material profile set When I set "active_object.BIMObjectMaterialProperties.material_type" to "IfcMaterialProfileSet" And I press "bim.assign_material" Then nothing happens + +Scenario: Select by material +Scenario: Load materials - then add material + Given an empty IFC project + And I press "bim.load_materials" + And I press "bim.add_material(obj='')" + And the variable "material" is "{ifc}.by_type('IfcMaterial')[0].id()" + When I press "bim.select_by_material(material={material})" + Then nothing happens diff --git a/src/blenderbim/test/core/test_material.py b/src/blenderbim/test/core/test_material.py index accf5b50b7..e589c55357 100644 --- a/src/blenderbim/test/core/test_material.py +++ b/src/blenderbim/test/core/test_material.py @@ -147,3 +147,10 @@ class TestDisableEditingMaterials: def test_run(self, material): material.disable_editing_materials().should_be_called() subject.disable_editing_materials(material) + + +class TestSelectByMaterial: + def test_run(self, material): + material.get_elements_by_material("material").should_be_called().will_return("elements") + material.select_elements("elements").should_be_called() + subject.select_by_material(material, material="material") diff --git a/src/blenderbim/test/tool/test_material.py b/src/blenderbim/test/tool/test_material.py index 1637a00440..4ce5af138f 100644 --- a/src/blenderbim/test/tool/test_material.py +++ b/src/blenderbim/test/tool/test_material.py @@ -68,6 +68,16 @@ class TestGetActiveMaterialType(NewFile): assert subject.get_active_material_type() == "IfcMaterialLayerSet" +class TestGetElementsByMaterial(NewFile): + def test_run(self): + ifc = ifcopenshell.file() + 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) + assert subject.get_elements_by_material(material) == {element} + + class TestGetName(NewFile): def test_run(self): assert subject.get_name(bpy.data.materials.new("Material")) == "Material" @@ -131,3 +141,15 @@ class TestIsEditingMaterials(NewFile): subject.is_editing_materials() is False bpy.context.scene.BIMMaterialProperties.is_editing = True subject.is_editing_materials() is True + + +class TestSelectElements(NewFile): + def test_run(self): + ifc = ifcopenshell.file() + tool.Ifc().set(ifc) + element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcPump") + obj = bpy.data.objects.new("Object", None) + bpy.context.scene.collection.objects.link(obj) + tool.Ifc.link(element, obj) + subject.select_elements([element]) + assert obj in bpy.context.selected_objects