mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-12 14:33:28 +00:00
The material manager now groups materials into categories
This commit is contained in:
@@ -28,6 +28,7 @@ classes = (
|
|||||||
operator.AddProfile,
|
operator.AddProfile,
|
||||||
operator.AssignMaterial,
|
operator.AssignMaterial,
|
||||||
operator.AssignParameterizedProfile,
|
operator.AssignParameterizedProfile,
|
||||||
|
operator.ContractMaterialCategory,
|
||||||
operator.CopyMaterial,
|
operator.CopyMaterial,
|
||||||
operator.DisableEditingAssignedMaterial,
|
operator.DisableEditingAssignedMaterial,
|
||||||
operator.DisableEditingMaterialSetItem,
|
operator.DisableEditingMaterialSetItem,
|
||||||
@@ -36,6 +37,7 @@ classes = (
|
|||||||
operator.EditMaterialSetItem,
|
operator.EditMaterialSetItem,
|
||||||
operator.EnableEditingAssignedMaterial,
|
operator.EnableEditingAssignedMaterial,
|
||||||
operator.EnableEditingMaterialSetItem,
|
operator.EnableEditingMaterialSetItem,
|
||||||
|
operator.ExpandMaterialCategory,
|
||||||
operator.LoadMaterials,
|
operator.LoadMaterials,
|
||||||
operator.RemoveConstituent,
|
operator.RemoveConstituent,
|
||||||
operator.RemoveLayer,
|
operator.RemoveLayer,
|
||||||
|
|||||||
@@ -778,3 +778,31 @@ class CopyMaterial(bpy.types.Operator):
|
|||||||
if material.id() in object_material_ids:
|
if material.id() in object_material_ids:
|
||||||
return
|
return
|
||||||
obj.data.materials.append(IfcStore.get_element(material.id()))
|
obj.data.materials.append(IfcStore.get_element(material.id()))
|
||||||
|
|
||||||
|
|
||||||
|
class ExpandMaterialCategory(bpy.types.Operator):
|
||||||
|
bl_idname = "bim.expand_material_category"
|
||||||
|
bl_label = "Expand Material Category"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
category: bpy.props.StringProperty()
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
props = context.scene.BIMMaterialProperties
|
||||||
|
for category in [c for c in props.materials if c.is_category and c.name == self.category]:
|
||||||
|
category.is_expanded = True
|
||||||
|
core.load_materials(tool.Material, props.material_type)
|
||||||
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
|
class ContractMaterialCategory(bpy.types.Operator):
|
||||||
|
bl_idname = "bim.contract_material_category"
|
||||||
|
bl_label = "Contract Material Category"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
category: bpy.props.StringProperty()
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
props = context.scene.BIMMaterialProperties
|
||||||
|
for category in [c for c in props.materials if c.is_category and c.name == self.category]:
|
||||||
|
category.is_expanded = False
|
||||||
|
core.load_materials(tool.Material, props.material_type)
|
||||||
|
return {"FINISHED"}
|
||||||
|
|||||||
@@ -109,6 +109,8 @@ def get_material_types(self, context):
|
|||||||
class Material(PropertyGroup):
|
class Material(PropertyGroup):
|
||||||
name: StringProperty(name="Name")
|
name: StringProperty(name="Name")
|
||||||
ifc_definition_id: IntProperty(name="IFC Definition ID")
|
ifc_definition_id: IntProperty(name="IFC Definition ID")
|
||||||
|
is_category: BoolProperty(name="Is Category", default=False)
|
||||||
|
is_expanded: BoolProperty(name="Is Expanded", default=True)
|
||||||
total_elements: IntProperty(name="Total Elements")
|
total_elements: IntProperty(name="Total Elements")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -61,16 +61,18 @@ class BIM_PT_materials(Panel):
|
|||||||
row.operator("bim.add_material", text="", icon="ADD")
|
row.operator("bim.add_material", text="", icon="ADD")
|
||||||
if self.props.materials and self.props.active_material_index < len(self.props.materials):
|
if self.props.materials and self.props.active_material_index < len(self.props.materials):
|
||||||
material = self.props.materials[self.props.active_material_index]
|
material = self.props.materials[self.props.active_material_index]
|
||||||
op = row.operator("bim.select_by_material", text="", icon="RESTRICT_SELECT_OFF")
|
if material.ifc_definition_id:
|
||||||
op.material = material.ifc_definition_id
|
op = row.operator("bim.select_by_material", text="", icon="RESTRICT_SELECT_OFF")
|
||||||
row.operator("bim.remove_material", text="", icon="X").material = material.ifc_definition_id
|
op.material = material.ifc_definition_id
|
||||||
|
row.operator("bim.remove_material", text="", icon="X").material = material.ifc_definition_id
|
||||||
else:
|
else:
|
||||||
row.operator("bim.add_material_set", text="", icon="ADD").set_type = self.props.material_type
|
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):
|
if self.props.materials and self.props.active_material_index < len(self.props.materials):
|
||||||
material = self.props.materials[self.props.active_material_index]
|
material = self.props.materials[self.props.active_material_index]
|
||||||
op = row.operator("bim.select_by_material", text="", icon="RESTRICT_SELECT_OFF")
|
if material.ifc_definition_id:
|
||||||
op.material = material.ifc_definition_id
|
op = row.operator("bim.select_by_material", text="", icon="RESTRICT_SELECT_OFF")
|
||||||
row.operator("bim.remove_material_set", text="", icon="X").material = material.ifc_definition_id
|
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")
|
self.layout.template_list("BIM_UL_materials", "", self.props, "materials", self.props, "active_material_index")
|
||||||
|
|
||||||
@@ -395,7 +397,21 @@ class BIM_UL_materials(UIList):
|
|||||||
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
|
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
|
||||||
if item:
|
if item:
|
||||||
row = layout.row(align=True)
|
row = layout.row(align=True)
|
||||||
row.label(text=item.name)
|
|
||||||
row2 = row.row()
|
if item.is_category:
|
||||||
row2.alignment = "RIGHT"
|
if item.is_expanded:
|
||||||
row2.label(text=str(item.total_elements))
|
row.operator(
|
||||||
|
"bim.contract_material_category", text="", emboss=False, icon="DISCLOSURE_TRI_DOWN"
|
||||||
|
).category = item.name
|
||||||
|
else:
|
||||||
|
row.operator(
|
||||||
|
"bim.expand_material_category", text="", emboss=False, icon="DISCLOSURE_TRI_RIGHT"
|
||||||
|
).category = item.name
|
||||||
|
row.label(text=item.name or "Uncategorised")
|
||||||
|
else:
|
||||||
|
row.label(text="", icon="BLANK1")
|
||||||
|
row.label(text=item.name, icon="MATERIAL")
|
||||||
|
|
||||||
|
row2 = row.row()
|
||||||
|
row2.alignment = "RIGHT"
|
||||||
|
row2.label(text=str(item.total_elements))
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ class Material(blenderbim.core.tool.Material):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def import_material_definitions(cls, material_type):
|
def import_material_definitions(cls, material_type):
|
||||||
props = bpy.context.scene.BIMMaterialProperties
|
props = bpy.context.scene.BIMMaterialProperties
|
||||||
|
expanded_categories = {m.name for m in props.materials if m.is_expanded}
|
||||||
props.materials.clear()
|
props.materials.clear()
|
||||||
get_name = lambda x: x.Name or "Unnamed"
|
get_name = lambda x: x.Name or "Unnamed"
|
||||||
if material_type == "IfcMaterialLayerSet":
|
if material_type == "IfcMaterialLayerSet":
|
||||||
@@ -62,11 +63,25 @@ class Material(blenderbim.core.tool.Material):
|
|||||||
elif material_type == "IfcMaterialList":
|
elif material_type == "IfcMaterialList":
|
||||||
get_name = lambda x: "Unnamed"
|
get_name = lambda x: "Unnamed"
|
||||||
materials = sorted(tool.Ifc.get().by_type(material_type), key=get_name)
|
materials = sorted(tool.Ifc.get().by_type(material_type), key=get_name)
|
||||||
for material in materials:
|
categories = {}
|
||||||
new = props.materials.add()
|
if material_type == "IfcMaterial":
|
||||||
new.ifc_definition_id = material.id()
|
[categories.setdefault(m.Category, []).append(m) for m in materials]
|
||||||
new.name = get_name(material)
|
for category, mats in categories.items():
|
||||||
new.total_elements = len(set(ifcopenshell.util.element.get_elements_by_material(tool.Ifc.get(), material)))
|
cat = props.materials.add()
|
||||||
|
cat.name = category or ""
|
||||||
|
cat.is_category = True
|
||||||
|
cat.is_expanded = cat.name in expanded_categories
|
||||||
|
for material in mats if cat.is_expanded else []:
|
||||||
|
new = props.materials.add()
|
||||||
|
new.ifc_definition_id = material.id()
|
||||||
|
new.name = get_name(material)
|
||||||
|
new.total_elements = len(set(ifcopenshell.util.element.get_elements_by_material(tool.Ifc.get(), material)))
|
||||||
|
else:
|
||||||
|
for material in materials:
|
||||||
|
new = props.materials.add()
|
||||||
|
new.ifc_definition_id = material.id()
|
||||||
|
new.name = get_name(material)
|
||||||
|
new.total_elements = len(set(ifcopenshell.util.element.get_elements_by_material(tool.Ifc.get(), material)))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def is_editing_materials(cls):
|
def is_editing_materials(cls):
|
||||||
|
|||||||
@@ -118,3 +118,18 @@ Scenario: Select by material
|
|||||||
And the variable "material" is "{ifc}.by_type('IfcMaterial')[0].id()"
|
And the variable "material" is "{ifc}.by_type('IfcMaterial')[0].id()"
|
||||||
When I press "bim.select_by_material(material={material})"
|
When I press "bim.select_by_material(material={material})"
|
||||||
Then nothing happens
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Expand material category
|
||||||
|
Given an empty IFC project
|
||||||
|
And I press "bim.load_materials"
|
||||||
|
And I press "bim.add_material(obj='')"
|
||||||
|
When I press "bim.expand_material_category(category='')"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Contract material category
|
||||||
|
Given an empty IFC project
|
||||||
|
And I press "bim.load_materials"
|
||||||
|
And I press "bim.add_material(obj='')"
|
||||||
|
And I press "bim.expand_material_category(category='')"
|
||||||
|
When I press "bim.contract_material_category(category='')"
|
||||||
|
Then nothing happens
|
||||||
|
|||||||
@@ -84,15 +84,30 @@ class TestGetName(NewFile):
|
|||||||
|
|
||||||
|
|
||||||
class TestImportMaterialDefinitions(NewFile):
|
class TestImportMaterialDefinitions(NewFile):
|
||||||
def test_import_materials(self):
|
def test_import_materials_grouped_by_categories(self):
|
||||||
ifc = ifcopenshell.file()
|
ifc = ifcopenshell.file()
|
||||||
tool.Ifc.set(ifc)
|
tool.Ifc.set(ifc)
|
||||||
material = ifc.createIfcMaterial(Name="Name")
|
material = ifc.createIfcMaterial(Name="Name", Category="Category")
|
||||||
subject.import_material_definitions("IfcMaterial")
|
subject.import_material_definitions("IfcMaterial")
|
||||||
props = bpy.context.scene.BIMMaterialProperties
|
props = bpy.context.scene.BIMMaterialProperties
|
||||||
assert props.materials[0].ifc_definition_id == material.id()
|
assert props.materials[0].ifc_definition_id == 0
|
||||||
assert props.materials[0].name == "Name"
|
assert props.materials[0].name == "Category"
|
||||||
assert props.materials[0].total_elements == 0
|
assert props.materials[0].is_category is True
|
||||||
|
assert props.materials[0].is_expanded is False
|
||||||
|
assert len(props.materials) == 1
|
||||||
|
|
||||||
|
def test_importing_expanded_material_categories(self):
|
||||||
|
ifc = ifcopenshell.file()
|
||||||
|
tool.Ifc.set(ifc)
|
||||||
|
material = ifc.createIfcMaterial(Name="Name", Category="Category")
|
||||||
|
subject.import_material_definitions("IfcMaterial")
|
||||||
|
props = bpy.context.scene.BIMMaterialProperties
|
||||||
|
props.materials[0].is_expanded = True
|
||||||
|
subject.import_material_definitions("IfcMaterial")
|
||||||
|
assert len(props.materials) == 2
|
||||||
|
assert props.materials[1].ifc_definition_id == material.id()
|
||||||
|
assert props.materials[1].name == "Name"
|
||||||
|
assert props.materials[1].total_elements == 0
|
||||||
|
|
||||||
def test_import_material_layer_sets(self):
|
def test_import_material_layer_sets(self):
|
||||||
ifc = ifcopenshell.file()
|
ifc = ifcopenshell.file()
|
||||||
|
|||||||
Reference in New Issue
Block a user