From dd561d37032e667a805bb55f19a4edc978e7a0a8 Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Mon, 8 Jul 2024 15:23:13 +0500 Subject: [PATCH] remove material assignment listener #4843 --- .../blenderbim/bim/module/model/handler.py | 13 ------ .../blenderbim/bim/module/model/product.py | 32 -------------- src/blenderbim/blenderbim/core/material.py | 1 + src/blenderbim/blenderbim/tool/material.py | 42 ++++++++++++++++++- src/blenderbim/test/tool/test_model.py | 7 ++++ 5 files changed, 49 insertions(+), 46 deletions(-) diff --git a/src/blenderbim/blenderbim/bim/module/model/handler.py b/src/blenderbim/blenderbim/bim/module/model/handler.py index 181eeb7146..328ceaab31 100644 --- a/src/blenderbim/blenderbim/bim/module/model/handler.py +++ b/src/blenderbim/blenderbim/bim/module/model/handler.py @@ -37,19 +37,6 @@ def load_post(*args): "sequence.edit_task_time", "BlenderBIM.Task.CalculateQuantities", task.calculate_quantities ) - for usecase in [ - "material.assign_material", - "material.edit_constituent", - "material.edit_layer", - "material.edit_profile", - "material.add_constituent", - "material.add_layer", - "material.add_profile", - ]: - ifcopenshell.api.add_post_listener( - usecase, "BlenderBIM.Product.EnsureMaterialAssigned", product.ensure_material_assigned - ) - ifcopenshell.api.add_post_listener( "material.edit_profile_usage", "BlenderBIM.Product.RegenerateProfileUsage", diff --git a/src/blenderbim/blenderbim/bim/module/model/product.py b/src/blenderbim/blenderbim/bim/module/model/product.py index 86e82a4582..837c74f364 100644 --- a/src/blenderbim/blenderbim/bim/module/model/product.py +++ b/src/blenderbim/blenderbim/bim/module/model/product.py @@ -38,7 +38,6 @@ from blenderbim.bim.ifc import IfcStore from blenderbim.bim.module.model.data import AuthoringData from mathutils import Vector, Matrix from bpy_extras.object_utils import AddObjectHelper -from . import prop import json from typing import Any, Union, Optional, assert_never @@ -511,34 +510,3 @@ def regenerate_profile_usage(usecase_path, ifc_file, settings): is_global=True, should_sync_changes_first=False, ) - - -def ensure_material_assigned(usecase_path: str, ifc_file: ifcopenshell.file, settings: dict[str, Any]) -> None: - return # TODO ensure this now works with the new approach of styles - elements = settings["products"] - material = settings.get("material") - if material: - assigned_material = settings["material"] - else: - material_type: ifcopenshell.util.element.MATERIAL_TYPE = settings["type"] - element = elements[0] - if material_type == "IfcMaterial": - assigned_material = ifcopenshell.util.element.get_material(element, should_inherit=False) - assert assigned_material # Type checker. - # Material usages just inherit the style from the type material, so can't override it. - elif material_type in ("IfcMaterialLayerSetUsage", "IfcMaterialProfileSetUsage"): - return - # If type is Set and no material argument were provided, then Set was just created - # and not yet have any IfcMaterials. - elif material_type in ("IfcMaterialConstituentSet", "IfcMaterialLayerSet", "IfcMaterialProfileSet"): - return - elif material_type == "IfcMaterialList": - assert False, "Current assign_material implementation requires 'material' argument for IfcMaterialList." - else: - assert_never(material_type) - - for element in elements[:]: - if element.is_a("IfcElementType"): - elements.extend(tool.Model.get_occurrences_without_material_override(element)) - - tool.Model.apply_ifc_material_changes(elements, assigned_material=settings["material"]) diff --git a/src/blenderbim/blenderbim/core/material.py b/src/blenderbim/blenderbim/core/material.py index 75c9e8b97e..8c12d2b8c5 100644 --- a/src/blenderbim/blenderbim/core/material.py +++ b/src/blenderbim/blenderbim/core/material.py @@ -118,6 +118,7 @@ def assign_material( continue ifc.run("material.assign_material", products=[element], type=material_type, material=material) + material_tool.ensure_material_assigned(elements=[element], material_type=material_type, material=material) assigned_material = material_tool.get_material(element) assert assigned_material # Type checker. diff --git a/src/blenderbim/blenderbim/tool/material.py b/src/blenderbim/blenderbim/tool/material.py index 85b2a5144f..a6a667b732 100644 --- a/src/blenderbim/blenderbim/tool/material.py +++ b/src/blenderbim/blenderbim/tool/material.py @@ -27,7 +27,7 @@ import blenderbim.bim.helper import ifcopenshell.util.unit import ifcopenshell.util.element from collections import defaultdict -from typing import Union, Any, TYPE_CHECKING +from typing import Union, Any, TYPE_CHECKING, Optional, assert_never if TYPE_CHECKING: # Avoid circular imports. @@ -308,3 +308,43 @@ class Material(blenderbim.core.tool.Material): if element.is_a("IfcElementType"): elements.extend(tool.Model.get_occurrences_without_material_override(element)) tool.Model.apply_ifc_material_changes(elements) + + @classmethod + def ensure_material_assigned( + cls, + elements: list[ifcopenshell.entity_instance], + material_type: ifcopenshell.util.element.MATERIAL_TYPE = "IfcMaterial", + material: Optional[ifcopenshell.entity_instance] = None, + ) -> None: + """Ensure blender materials are updated after a material assignment. + + Designed to be called after material.assign_material API call.""" + + # NOTE: adding/editing/removing layers/profiles/constituents is not supported. + # Adding support for profiles/layers it only will be possible when we'll be adding styles + # to the representations generated from layer and profile sets. + + if material: + assigned_material = material + else: + element = elements[0] + if material_type == "IfcMaterial": + assigned_material = ifcopenshell.util.element.get_material(element, should_inherit=False) + assert assigned_material # Type checker. + # Material usages just inherit the style from the type material, so can't override it. + elif material_type in ("IfcMaterialLayerSetUsage", "IfcMaterialProfileSetUsage"): + return + # If type is Set and no material argument were provided, then Set was just created + # and not yet have any IfcMaterials. + elif material_type in ("IfcMaterialConstituentSet", "IfcMaterialLayerSet", "IfcMaterialProfileSet"): + return + elif material_type == "IfcMaterialList": + assert False, "Current assign_material implementation requires 'material' argument for IfcMaterialList." + else: + assert_never(material_type) + + for element in elements[:]: + if element.is_a("IfcElementType"): + elements.extend(tool.Model.get_occurrences_without_material_override(element)) + + tool.Model.apply_ifc_material_changes(elements, assigned_material=assigned_material) diff --git a/src/blenderbim/test/tool/test_model.py b/src/blenderbim/test/tool/test_model.py index d4cdc7ef72..65278949db 100644 --- a/src/blenderbim/test/tool/test_model.py +++ b/src/blenderbim/test/tool/test_model.py @@ -523,6 +523,7 @@ class TestApplyIfcMaterialChanges(NewFile): ifcopenshell.api.material.assign_material( ifc_file, products=[tool.Ifc.get_entity(with_material)], material=blue_material ) + tool.Material.ensure_material_assigned([tool.Ifc.get_entity(with_material)], material=blue_material) assert self.get_used_styles(element_type_obj) == set() for element in ifc_file.by_type("IfcActuator"): @@ -539,6 +540,7 @@ class TestApplyIfcMaterialChanges(NewFile): blue_style = next((i for i in ifc_file.by_type("IfcSurfaceStyle") if i.Name == "Blue")) ifcopenshell.api.material.assign_material(ifc_file, material=red_material, products=[element_type]) + tool.Material.ensure_material_assigned([element_type], material=red_material) assert self.get_used_styles(tool.Ifc.get_object(element_type)) == {red_style} for element in ifc_file.by_type("IfcActuator"): obj = tool.Ifc.get_object(element) @@ -568,6 +570,7 @@ class TestApplyIfcMaterialChanges(NewFile): bpy.ops.bim.assign_style_to_selected(style_id=green_style.id()) ifcopenshell.api.material.assign_material(ifc_file, material=red_material, products=[element_type]) + tool.Material.ensure_material_assigned([element_type], material=red_material) assert self.get_used_styles(tool.Ifc.get_object(element_type)) == {green_style} for element in ifc_file.by_type("IfcActuator"): obj = tool.Ifc.get_object(element) @@ -613,6 +616,7 @@ class TestApplyIfcMaterialChanges(NewFile): assert set(mesh.materials) == {bpy.data.materials["Green"], None} ifcopenshell.api.material.assign_material(ifc_file, products=[element], material=red_material) + tool.Material.ensure_material_assigned([element], material=red_material) assert self.get_used_styles(obj) == {green_style, red_style} ifcopenshell.api.material.unassign_material(ifc_file, products=[element]) tool.Material.ensure_material_unassigned([element]) @@ -628,6 +632,7 @@ class TestApplyIfcMaterialChanges(NewFile): assert set(mesh.materials) == {bpy.data.materials["Red"], None} ifcopenshell.api.material.assign_material(ifc_file, products=[element], material=red_material) + tool.Material.ensure_material_assigned([element], material=red_material) assert mesh.materials[:] == [bpy.data.materials["Red"]] # All polygons are just reassigned to the existing material. assert set(get_material_indices(mesh)) == {mesh.materials.find("Red")} @@ -649,9 +654,11 @@ class TestApplyIfcMaterialChanges(NewFile): element = tool.Ifc.get_entity(obj) ifcopenshell.api.material.assign_material(ifc_file, material=red_material, products=[element_type]) + tool.Material.ensure_material_assigned([element_type], material=red_material) # Override type material. ifcopenshell.api.material.assign_material(ifc_file, material=no_style_material, products=[element]) + tool.Material.ensure_material_assigned([element], material=no_style_material) assert self.get_mesh(obj).materials[:] == [] ifcopenshell.api.material.unassign_material(ifc_file, products=[element])