diff --git a/src/ifcopenshell-python/ifcopenshell/api/style/assign_material_style.py b/src/ifcopenshell-python/ifcopenshell/api/style/assign_material_style.py
index 921be2e1a3..6101bc4c9d 100644
--- a/src/ifcopenshell-python/ifcopenshell/api/style/assign_material_style.py
+++ b/src/ifcopenshell-python/ifcopenshell/api/style/assign_material_style.py
@@ -16,6 +16,8 @@
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see .
+import ifcopenshell
+
class Usecase:
def __init__(self, file, material=None, style=None, context=None, should_use_presentation_style_assignment=False):
@@ -112,6 +114,27 @@ class Usecase:
else:
self.create_new_definition_representation()
+ material_constituents_names = []
+ for inverse in self.file.get_inverse(self.settings["material"]):
+ if inverse.is_a("IfcMaterialConstituent") and inverse.Name:
+ material_constituents_names.append(inverse.Name)
+ if not material_constituents_names:
+ return
+
+ elements = ifcopenshell.util.element.get_elements_by_material(self.file, self.settings["material"])
+ shape_aspects = []
+ for element in elements:
+ shape_aspects += ifcopenshell.util.element.get_shape_aspects(element)
+
+ for shape_aspect in shape_aspects:
+ if shape_aspect.Name not in material_constituents_names:
+ continue
+
+ for rep in shape_aspect.ShapeRepresentations:
+ ifcopenshell.api.run(
+ "style.assign_representation_styles", self.file, shape_representation=rep, styles=[self.style]
+ )
+
def modify_existing_definition_representation(self):
definition_representation = self.settings["material"].HasRepresentation[0]
representation = self.get_styled_representation(definition_representation)
diff --git a/src/ifcopenshell-python/test/api/style/test_assign_material_style.py b/src/ifcopenshell-python/test/api/style/test_assign_material_style.py
new file mode 100644
index 0000000000..eab6dd73b4
--- /dev/null
+++ b/src/ifcopenshell-python/test/api/style/test_assign_material_style.py
@@ -0,0 +1,56 @@
+# IfcOpenShell - IFC toolkit and geometry engine
+# Copyright (C) 2022 Dion Moult
+#
+# This file is part of IfcOpenShell.
+#
+# IfcOpenShell is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# IfcOpenShell is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with IfcOpenShell. If not, see .
+
+import pytest
+import test.bootstrap
+import ifcopenshell
+import ifcopenshell.api
+
+
+# TODO: test assigning styles without material constituents
+class TestAssignMaterialStyle(test.bootstrap.IFC4):
+ def test_update_shape_aspect_representaitons_items_styles_if_material_is_part_of_matching_material_constituents(
+ self,
+ ):
+ element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
+ name = "Concrete"
+ product_shape = self.file.createIfcProductDefinitionShape()
+ element.Representation = product_shape
+ context = self.file.createIfcGeometricRepresentationContext()
+
+ representation = self.file.createIfcShapeRepresentation()
+ item = self.file.createIfcExtrudedAreaSolid()
+ representation.Items = [item]
+
+ shape_aspect = self.file.createIfcShapeAspect(ShapeRepresentations=(representation,), Name=name)
+ shape_aspect.PartOfProductDefinitionShape = product_shape
+
+ style = self.file.createIfcSurfaceStyle()
+ material = ifcopenshell.api.run("material.add_material", self.file)
+ material_set = ifcopenshell.api.run(
+ "material.add_material_set", self.file, set_type="IfcMaterialConstituentSet"
+ )
+ constituent = ifcopenshell.api.run(
+ "material.add_constituent", self.file, constituent_set=material_set, material=material
+ )
+ constituent.Name = name
+ ifcopenshell.api.run("material.assign_material", self.file, product=element, material=material_set)
+
+ ifcopenshell.api.run("style.assign_material_style", self.file, material=material, style=style, context=context)
+
+ assert item.StyledByItem[0].Styles == (style,)