mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-11 02:02:22 +00:00
bim.add_material_set to ensure adding valid material sets
This commit is contained in:
@@ -156,6 +156,7 @@ class DuplicateMaterial(bpy.types.Operator, tool.Ifc.Operator):
|
||||
class AddMaterialSet(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.add_material_set"
|
||||
bl_label = "Add Material Set"
|
||||
bl_description = "Create a new material set, will use a default material/profile as a placeholder"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
set_type: bpy.props.StringProperty()
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ def add_material(
|
||||
|
||||
def add_material_set(ifc: tool.Ifc, material: tool.Material, set_type: str) -> ifcopenshell.entity_instance:
|
||||
ifc_material = ifc.run("material.add_material_set", name="Unnamed", set_type=set_type)
|
||||
material.ensure_new_material_set_is_valid(ifc_material)
|
||||
if material.is_editing_materials():
|
||||
material.import_material_definitions(material.get_active_material_type())
|
||||
return ifc_material
|
||||
|
||||
@@ -510,6 +510,7 @@ class Material:
|
||||
def enable_editing_materials(cls): pass
|
||||
def ensure_material_assigned(cls, elements, material_type, material): pass
|
||||
def ensure_material_unassigned(cls, elements): pass
|
||||
def ensure_new_material_set_is_valid(cls, material): pass
|
||||
def get_active_material_item(cls): pass
|
||||
def get_active_material_type(cls): pass
|
||||
def get_default_material(cls): pass
|
||||
|
||||
@@ -27,7 +27,8 @@ import bonsai.bim.helper
|
||||
import ifcopenshell.util.unit
|
||||
import ifcopenshell.util.element
|
||||
from collections import defaultdict
|
||||
from typing import Union, Any, TYPE_CHECKING, Optional
|
||||
from typing import Union, Any, TYPE_CHECKING, Optional, Literal
|
||||
from typing_extensions import assert_never
|
||||
|
||||
if TYPE_CHECKING:
|
||||
# Avoid circular imports.
|
||||
@@ -352,3 +353,38 @@ class Material(bonsai.core.tool.Material):
|
||||
elements.extend(tool.Model.get_occurrences_without_material_override(element))
|
||||
|
||||
tool.Model.apply_ifc_material_changes(elements, assigned_material=assigned_material)
|
||||
|
||||
@classmethod
|
||||
def ensure_new_material_set_is_valid(cls, material: ifcopenshell.entity_instance) -> None:
|
||||
material_type = material.is_a()
|
||||
|
||||
ifc_file = tool.Ifc.get()
|
||||
default_material = cls.get_default_material()
|
||||
|
||||
if material_type == "IfcMaterialConstituentSet":
|
||||
material_constituent = ifcopenshell.api.material.add_constituent(
|
||||
ifc_file,
|
||||
constituent_set=material,
|
||||
material=default_material,
|
||||
)
|
||||
material.MaterialConstituents = [material_constituent]
|
||||
elif material_type == "IfcMaterialLayerSet":
|
||||
material_layer = ifcopenshell.api.material.add_layer(
|
||||
ifc_file,
|
||||
layer_set=material,
|
||||
material=default_material,
|
||||
)
|
||||
material.MaterialLayers = [material_layer]
|
||||
elif material_type == "IfcMaterialProfileSet":
|
||||
profile = tool.Profile.get_default_profile()
|
||||
material_profile = ifcopenshell.api.material.add_profile(
|
||||
ifc_file,
|
||||
profile_set=material,
|
||||
profile=profile,
|
||||
material=None,
|
||||
)
|
||||
material.MaterialProfiles = [material_profile]
|
||||
elif material_type == "IfcMaterialList":
|
||||
material.Materials = [default_material]
|
||||
else:
|
||||
assert False, f"Invalid material type found: {material_type}."
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import ifcopenshell
|
||||
import ifcopenshell.api.profile
|
||||
import ifcopenshell.geom
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.unit
|
||||
@@ -78,6 +79,21 @@ class Profile(bonsai.core.tool.Profile):
|
||||
return profile
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def get_default_profile(cls) -> ifcopenshell.entity_instance:
|
||||
"""Return first found IfcProfileDef in IFC file or create a new default profile."""
|
||||
ifc_file = tool.Ifc.get()
|
||||
profile = next(iter(ifc_file.by_type("IfcProfileDef")), None)
|
||||
if profile:
|
||||
return profile
|
||||
profile = ifcopenshell.api.profile.add_parameterized_profile(ifc_file, ifc_class="IfcRectangleProfileDef")
|
||||
si_conversion = ifcopenshell.util.unit.calculate_unit_scale(ifc_file)
|
||||
profile.ProfileType = "AREA"
|
||||
profile.ProfileName = "Default Profile"
|
||||
profile.XDim = 0.1 / si_conversion
|
||||
profile.YDim = 0.1 / si_conversion
|
||||
return profile
|
||||
|
||||
@classmethod
|
||||
def get_model_profiles(cls) -> list[ifcopenshell.entity_instance]:
|
||||
return tool.Ifc.get().by_type("IfcProfileDef")
|
||||
|
||||
@@ -49,6 +49,7 @@ class TestAddMaterialSet:
|
||||
ifc.run("material.add_material_set", name="Unnamed", set_type="set_type").should_be_called().will_return(
|
||||
"material"
|
||||
)
|
||||
material.ensure_new_material_set_is_valid("material").should_be_called()
|
||||
material.is_editing_materials().should_be_called().will_return(False)
|
||||
assert subject.add_material_set(ifc, material, set_type="set_type") == "material"
|
||||
|
||||
@@ -56,6 +57,7 @@ class TestAddMaterialSet:
|
||||
ifc.run("material.add_material_set", name="Unnamed", set_type="set_type").should_be_called().will_return(
|
||||
"material"
|
||||
)
|
||||
material.ensure_new_material_set_is_valid("material").should_be_called()
|
||||
material.is_editing_materials().should_be_called().will_return(True)
|
||||
material.get_active_material_type().should_be_called().will_return("material_type")
|
||||
material.import_material_definitions("material_type").should_be_called()
|
||||
|
||||
@@ -150,3 +150,36 @@ class TestIsMaterialUsedInSets(NewFile):
|
||||
material_set.MaterialLayers = [material_set_item]
|
||||
material_set_item.Material = material
|
||||
assert subject.is_material_used_in_sets(material) is True
|
||||
|
||||
|
||||
class TestEnsureNewMaterialSetIsValid(NewFile):
|
||||
def test_material_constituent_set(self):
|
||||
ifc = ifcopenshell.file()
|
||||
tool.Ifc.set(ifc)
|
||||
material_set = ifc.create_entity("IfcMaterialConstituentSet")
|
||||
subject.ensure_new_material_set_is_valid(material_set)
|
||||
assert len(constituents := material_set.MaterialConstituents) == 1
|
||||
assert constituents[0].Material
|
||||
|
||||
def test_material_layer_set(self):
|
||||
ifc = ifcopenshell.file()
|
||||
tool.Ifc.set(ifc)
|
||||
material_set = ifc.create_entity("IfcMaterialLayerSet")
|
||||
subject.ensure_new_material_set_is_valid(material_set)
|
||||
assert len(layers := material_set.MaterialLayers) == 1
|
||||
assert layers[0].Material
|
||||
|
||||
def test_material_profile_set(self):
|
||||
ifc = ifcopenshell.file()
|
||||
tool.Ifc.set(ifc)
|
||||
material_set = ifc.create_entity("IfcMaterialProfileSet")
|
||||
subject.ensure_new_material_set_is_valid(material_set)
|
||||
assert len(profiles := material_set.MaterialProfiles) == 1
|
||||
assert profiles[0].Profile
|
||||
|
||||
def test_material_list(self):
|
||||
ifc = ifcopenshell.file()
|
||||
tool.Ifc.set(ifc)
|
||||
material_set = ifc.create_entity("IfcMaterialList")
|
||||
subject.ensure_new_material_set_is_valid(material_set)
|
||||
assert len(material_set.Materials) == 1
|
||||
|
||||
Reference in New Issue
Block a user