support assigning existing non-ifcmaterials materials

Example - https://imgur.com/a/KN8mQPL

Also added some description to material operators (https://imgur.com/a/eIVNEdU). Need to somehow emphasize that this UI is only for IfcMaterials and cannot be used to assign existing layer sets, profile sets, etc...
This commit is contained in:
Andrej730
2024-07-08 13:43:42 +05:00
parent ee5b3d1775
commit 10b5910654
7 changed files with 79 additions and 10 deletions
@@ -28,6 +28,7 @@ classes = (
operator.AddMaterialSet,
operator.AddProfile,
operator.AssignMaterial,
operator.AssignMaterialToSelected,
operator.AssignParameterizedProfile,
operator.ContractMaterialCategory,
operator.DisableEditingAssignedMaterial,
@@ -117,6 +117,7 @@ class AssignParameterizedProfile(bpy.types.Operator, tool.Ifc.Operator):
class AddMaterial(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.add_material"
bl_label = "Add Material"
bl_description = "Create a new IfcMaterial"
bl_options = {"REGISTER", "UNDO"}
name: bpy.props.StringProperty(default="Default")
category: bpy.props.StringProperty(default="")
@@ -185,6 +186,32 @@ class RemoveMaterialSet(bpy.types.Operator, tool.Ifc.Operator):
core.remove_material_set(tool.Ifc, tool.Material, material=tool.Ifc.get().by_id(self.material))
class AssignMaterialToSelected(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.assign_material_to_selected"
bl_label = "Assign Material To Selected"
bl_description = "Assign currently selected material in Materials UI to the selected objects"
bl_options = {"REGISTER", "UNDO"}
material: bpy.props.IntProperty(name="Material IFC ID")
@classmethod
def poll(cls, context):
if not context.selected_objects:
cls.poll_message_set("No objects selected")
return False
return True
def _execute(self, context):
material = tool.Ifc.get().by_id(self.material)
objects = tool.Blender.get_selected_objects()
core.assign_material(
tool.Ifc,
tool.Material,
material_type=tool.Material.get_active_material_type(),
objects=objects,
material=material,
)
class AssignMaterial(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.assign_material"
bl_label = "Assign Material"
@@ -192,6 +219,18 @@ class AssignMaterial(bpy.types.Operator, tool.Ifc.Operator):
obj: bpy.props.StringProperty()
material_type: bpy.props.StringProperty()
@classmethod
def description(cls, context, properties):
if not (material_type := properties.material_type):
if not (obj := context.active_object):
return ""
material_type = obj.BIMObjectMaterialProperties.material_type
description = "Assign current IfcMaterial to the selected objects"
if material_type != "IfcMaterial":
description += f" as part of a new {material_type}"
return description
def _execute(self, context):
objects = [bpy.data.objects.get(self.obj)] if self.obj else tool.Blender.get_selected_objects()
core.assign_material(tool.Ifc, tool.Material, material_type=self.material_type, objects=objects)
@@ -143,7 +143,7 @@ class BIMMaterialProperties(PropertyGroup):
class BIMObjectMaterialProperties(PropertyGroup):
material_type: EnumProperty(items=get_object_material_type, name="Material Type")
material: EnumProperty(items=get_materials, name="Material")
material: EnumProperty(items=get_materials, name="Material", description="Currently selected IfcMaterial")
is_editing: BoolProperty(name="Is Editing", default=False)
material_set_usage_attributes: CollectionProperty(name="Material Set Usage Attributes", type=Attribute)
material_set_attributes: CollectionProperty(name="Material Set Attributes", type=Attribute)
@@ -67,6 +67,8 @@ class BIM_PT_materials(Panel):
op.material = material.ifc_definition_id
op = row.operator("bim.select_by_material", text="", icon="RESTRICT_SELECT_OFF")
op.material = material.ifc_definition_id
op = row.operator("bim.assign_material_to_selected", text="", icon="BRUSH_DATA")
op.material = material.ifc_definition_id
op = row.operator("bim.enable_editing_material", text="", icon="GREASEPENCIL")
op.material = material.ifc_definition_id
op = row.operator("bim.enable_editing_material_style", text="", icon="SHADING_RENDERED")
@@ -81,6 +83,8 @@ class BIM_PT_materials(Panel):
if material.ifc_definition_id:
op = row.operator("bim.select_by_material", text="", icon="RESTRICT_SELECT_OFF")
op.material = material.ifc_definition_id
op = row.operator("bim.assign_material_to_selected", text="", icon="BRUSH_DATA")
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")
+20 -4
View File
@@ -99,17 +99,33 @@ def disable_editing_material(material_tool: tool.Material) -> None:
def assign_material(
ifc: tool.Ifc, material_tool: tool.Material, material_type: Union[str, None], objects: list[bpy.types.Object]
ifc: tool.Ifc,
material_tool: tool.Material,
material_type: Union[str, None],
objects: list[bpy.types.Object],
material: Optional[ifcopenshell.entity_instance] = None,
) -> None:
material_type = material_type or material_tool.get_active_object_material()
material = material_tool.get_active_material()
"""Assign material to the provided objects.
If `material_type` or `material` are not provided, the active ones from
Object Materials UI is used.
"""
material_type = material_type or material_tool.get_object_ui_material_type()
material = material or material_tool.get_object_ui_active_material()
for obj in objects:
element = ifc.get_entity(obj)
if not element:
continue
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):
assert assigned_material # Type checker.
if material_tool.is_a_material_set(material):
# Ensure set is a valid IFC.
default_material = material_tool.get_default_material()
material_tool.add_material_to_set(material_set=material, material=default_material)
elif material_tool.is_a_material_set(assigned_material):
material_tool.add_material_to_set(material_set=assigned_material, material=material)
+1 -1
View File
@@ -493,7 +493,7 @@ class Material:
def enable_editing_materials(cls): pass
def get_active_material(cls): pass
def get_active_material_type(cls): pass
def get_active_object_material(cls, obj): pass
def get_active_object_material_type(cls, obj): pass
def get_elements_by_material(cls, material): pass
def get_material(cls, element, should_inherit): pass
def get_material_attributes(cls): pass
+13 -4
View File
@@ -19,6 +19,7 @@
from __future__ import annotations
import bpy
import ifcopenshell
import ifcopenshell.api.material
import blenderbim.core.tool
import blenderbim.core.material
import blenderbim.tool as tool
@@ -165,19 +166,27 @@ class Material(blenderbim.core.tool.Material):
props.active_material_id = 0
props.editing_material_type = ""
@classmethod
def get_default_material(cls) -> ifcopenshell.entity_instance:
"""Return first found IfcMaterial in IFC file or create a new default material."""
ifc_file = tool.Ifc.get()
material = next(iter(ifc_file.by_type("IfcMaterial")), None)
if material:
return material
material = ifcopenshell.api.material.add_material(ifc_file, name="Default")
return material
@classmethod
def get_type(cls, element: ifcopenshell.entity_instance) -> Union[ifcopenshell.entity_instance, None]:
return ifcopenshell.util.element.get_type(element)
@classmethod
def get_active_object_material(cls) -> Union[str, None]:
def get_object_ui_material_type(cls) -> str:
active_obj = bpy.context.active_object
if not active_obj:
return
return active_obj.BIMObjectMaterialProperties.material_type
@classmethod
def get_active_material(cls) -> ifcopenshell.entity_instance:
def get_object_ui_active_material(cls) -> ifcopenshell.entity_instance:
return tool.Ifc.get().by_id(int(bpy.context.active_object.BIMObjectMaterialProperties.material))
@classmethod