mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 17:31:45 +00:00
New API function to set shape aspect constituents
This commit is contained in:
@@ -55,6 +55,7 @@ from .remove_material import remove_material
|
||||
from .remove_material_set import remove_material_set
|
||||
from .remove_profile import remove_profile
|
||||
from .reorder_set_item import reorder_set_item
|
||||
from .set_shape_aspect_constituents import set_shape_aspect_constituents
|
||||
from .unassign_material import unassign_material
|
||||
|
||||
wrap_usecases(__path__, __name__)
|
||||
@@ -83,5 +84,6 @@ __all__ = [
|
||||
"remove_material_set",
|
||||
"remove_profile",
|
||||
"reorder_set_item",
|
||||
"set_shape_aspect_constituents",
|
||||
"unassign_material",
|
||||
]
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
# IfcOpenShell - IFC toolkit and geometry engine
|
||||
# Copyright (C) 2022 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
import ifcopenshell.api.style
|
||||
import ifcopenshell.api.material
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.representation
|
||||
|
||||
|
||||
def set_shape_aspect_constituents(
|
||||
file: ifcopenshell.file,
|
||||
*,
|
||||
element: ifcopenshell.entity_instance,
|
||||
context: ifcopenshell.entity_instance,
|
||||
materials: dict[str, ifcopenshell.entity_instance],
|
||||
) -> None:
|
||||
"""Assigns a material constituent set and sets styles based on shape aspects
|
||||
|
||||
An IFC element may be assigned to a set of material constituents. For
|
||||
example, a window may have a framing material and a glazing material. Each
|
||||
constituent may have a name, such as "Framing" (which may be assigned to an
|
||||
"Aluminium" material), and "Glazing" (assigned to a "Laminated Low-e Glass"
|
||||
material).
|
||||
|
||||
An IFC element's geometry may be composed of multiple geometric items.
|
||||
These geometric items may have names, known as "Shape Aspects". For
|
||||
example a solid extrusion for the framing named "Framing" and a solid
|
||||
extrusion for the glass panel named "Glazing".
|
||||
|
||||
A material may be associated with a style (i.e. colour). For example, a
|
||||
grey style for the "Aluminium" material and a transparent blue style for
|
||||
the "Laminated Low-e Glass" material.
|
||||
|
||||
These three concepts of material constituents, shape aspects, and
|
||||
associated styles are correlated. For example, if the name (e.g. "Framing")
|
||||
of a material constituent and a shape aspect correlate, that means that the
|
||||
geometric item inherits the style (i.e. grey).
|
||||
|
||||
This function lets you specify named material constituents, and it'll
|
||||
create a constituent set assigned to the element with those names. It'll
|
||||
then find any geometric representation items with shape aspects matching
|
||||
those names, and assign the correlating style.
|
||||
|
||||
If an assigned material constituent set already exists matching those
|
||||
values, it will be reused. If the values do not match, the existing
|
||||
material constituent set will be removed if it is not used by anything
|
||||
else.
|
||||
|
||||
:param element: The IfcProduct or IfcTypeProduct
|
||||
:param context: The IfcGeometricRepresentationContext, typically the body
|
||||
context. You can get this via
|
||||
:func:`ifcopenshell.util.representation.get_context`.
|
||||
:param materials: The key is the name of the constituent, and the value is
|
||||
the IfcMaterial.
|
||||
|
||||
Example:
|
||||
|
||||
.. code:: python
|
||||
|
||||
# Create two materials
|
||||
aluminium = ifcopenshell.api.material.add_material(model, name="AL01", category="aluminium")
|
||||
glass = ifcopenshell.api.material.add_material(model, name="GLZ01", category="glass")
|
||||
|
||||
# Auto assign material constituents and styles to items based on shape aspects
|
||||
ifcopenshell.api.material.set_shape_aspect_constituents(
|
||||
model, element=window, context=body, materials={
|
||||
"Framing": aluminium
|
||||
"Lining": aluminium
|
||||
"Glazing": glass
|
||||
})
|
||||
"""
|
||||
should_create_new_material_set = False
|
||||
if material := ifcopenshell.util.element.get_material(element):
|
||||
if (
|
||||
material.is_a("IfcMaterialConstituent")
|
||||
and len(names := [c.Name for c in material.MaterialConstituents]) == len(materials)
|
||||
and set(names) == set(materials.keys())
|
||||
):
|
||||
should_create_new_material_set = False
|
||||
else:
|
||||
should_create_new_material_set = True
|
||||
ifcopenshell.api.material.unassign_material(file, products=[element])
|
||||
if not material.is_a("IfcMaterial") and not file.get_total_inverses(material):
|
||||
ifcopenshell.api.material.remove_material_set(file, material=material)
|
||||
else:
|
||||
should_create_new_material_set = True
|
||||
if should_create_new_material_set:
|
||||
material_set = ifcopenshell.api.material.add_material_set(file, set_type="IfcMaterialConstituentSet")
|
||||
for name, material in materials.items():
|
||||
ifcopenshell.api.material.add_constituent(
|
||||
file, constituent_set=material_set, material=material, name=name
|
||||
)
|
||||
ifcopenshell.api.material.assign_material(file, products=[element], material=material_set)
|
||||
|
||||
styles = {n: ifcopenshell.util.representation.get_material_style(m, context) for n, m in materials.items()}
|
||||
print('styels are', styles)
|
||||
representation = ifcopenshell.util.representation.get_representation(element, context=context)
|
||||
print('rep is', representation)
|
||||
representation = ifcopenshell.util.representation.resolve_representation(representation)
|
||||
print('rrep is', representation)
|
||||
for item in representation.Items:
|
||||
print('checking item', item)
|
||||
if aspect := ifcopenshell.util.representation.get_item_shape_aspect(representation, item):
|
||||
print('found', aspect.Name)
|
||||
if style := styles.get(aspect.Name, None):
|
||||
print('... and correlating style', style)
|
||||
ifcopenshell.api.style.assign_item_style(file, item=item, style=style)
|
||||
Reference in New Issue
Block a user