Generate functions for all API usecases for better static code features. See #2693.

This commit is contained in:
Dion Moult
2024-05-06 14:35:39 +10:00
parent 10f894e2ea
commit d11ec67129
330 changed files with 13283 additions and 13751 deletions
@@ -23,133 +23,135 @@ import ifcopenshell.util.representation
from typing import Optional, Union
def assign_material(
file: ifcopenshell.file,
products: list[ifcopenshell.entity_instance],
type: str = "IfcMaterial",
material: Optional[ifcopenshell.entity_instance] = None,
) -> Union[ifcopenshell.entity_instance, list[ifcopenshell.entity_instance], None]:
"""Assigns a material to the list of products
Will unassign previously assigned material.
When a material is assigned to a product, it means that the product is
made out of that material. In its simplest form, a single material may
be assigned to a product, meaning that the entire product is made out of
that one material. Alternatively, a material set may be assigned to a
product, meaning that the product is made out of a set of materials.
There are three types of sets, including layered construction, profiled
materials, and arbitrary material constituents. See
ifcopenshell.api.material.add_material_set for details.
Materials are typically assigned to the element types rather than
individual occurrences of elements. Individual occurrences would then
inherit the material from the type.
If the type has a material set, then the geometry of the occurrences
must comply with the material set. For example, if the type has a
constituent set, then it is expected that all occurrences also inherit
the geometry of the type, which is made out of those constituents.
Alternatively, if the type has a layer set, then all occurrences must
have geometry that has a thickness equal to the sum of all layers. If a
type has a profile set, then all occurrences must has the same profile
extruded along its axis.
For layers and profiles assigned to types, the occurrences must be
assigned an IfcMaterialLayerSetUsage or an IfcMaterialProfileSetUsage.
This allows individual occurrences to override the layered or profiled
construction offset from a reference line.
:param products: The list of IfcProducts to assign the material or material set
to.
:type products: list[ifcopenshell.entity_instance]
:param type: Choose from "IfcMaterial", "IfcMaterialConstituentSet",
"IfcMaterialLayerSet", "IfcMaterialLayerSetUsage",
"IfcMaterialProfileSet", "IfcMaterialProfileSetUsage", or
"IfcMaterialList". Note that "Set Usages" may only be assigned to
occurrences, not types. Defaults to "IfcMaterial".
:type type: str
:param material: The IfcMaterial or material set you are assigning here.
If type is Usage then no need to provide `material`, it will be deduced
from the element type automatically.
:type material: ifcopenshell.entity_instance, optional
:return: IfcRelAssociatesMaterial entity
or a list of IfcRelAssociatesMaterial entities
(possible if `type` is Usage
and `products` require different Usages)
or `None` if `products` was empty list.
:rtype: Union[
ifcopenshell.entity_instance,
list[ifcopenshell.entity_instance], None]
Example:
.. code:: python
# Let's start with a simple concrete material
concrete = ifcopenshell.api.run("material.add_material", model, name="CON01", category="concrete")
# Let's imagine a concrete bench made out of a single concrete
# material. Let's assign it to the type.
bench_type = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcFurnitureType")
ifcopenshell.api.run("material.assign_material", model,
products=[bench_type], type="IfcMaterial", material=concrete)
# Let's imagine there are a two occurrences of this bench. It's not
# necessary to assign any material to these benches as they
# automatically inherit the material from the type.
bench1 = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcFurniture")
bench2 = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcFurniture")
ifcopenshell.api.run("type.assign_type", model, related_objects=[bench1], relating_type=bench_type)
ifcopenshell.api.run("type.assign_type", model, related_objects=[bench2], relating_type=bench_type)
# If we have a concrete wall, we should use a layer set. Again,
# let's start with a wall type, not occurrences.
wall_type = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcWallType", name="WAL01")
# Even though there is only one layer in our layer set, we still use
# a layer set because it makes it clear that this is a layered
# construction. Let's say it's a 200mm thick concrete layer.
material_set = ifcopenshell.api.run("material.add_material_set", model,
name="CON200", set_type="IfcMaterialLayerSet")
layer = ifcopenshell.api.run("material.add_layer", model, layer_set=material_set, material=steel)
ifcopenshell.api.run("material.edit_layer", model, layer=layer, attributes={"LayerThickness": 200})
# Our wall type now has the layer set assigned to it
ifcopenshell.api.run("material.assign_material", model,
products=[wall_type], type="IfcMaterialLayerSet", material=material_set)
# Let's imagine an occurrence of this wall type.
wall = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcWall")
ifcopenshell.api.run("type.assign_type", model, related_objects=[wall], relating_type=wall_type)
# Our wall occurrence needs to have a "set usage" which describes
# how the layers relate to a reference line (typically a 2D line
# representing the extents of the wall). Usages are special since
# they automatically detect the inherited material set from the
# type. You'd write similar code for a profile set.
ifcopenshell.api.run("material.assign_material", model,
products=[wall], type="IfcMaterialLayerSetUsage")
# To be complete, let's create the wall's axis and body
# representation. Notice how the axis guides the walls "reference
# line" which determines where layers are extruded from, and the
# body has a thickness of 200mm, same as our total layer set
# thickness.
axis = ifcopenshell.api.run("geometry.add_axis_representation", model,
context=axis_context, axis=[(0.0, 0.0), (5000.0, 0.0)])
body = ifcopenshell.api.run("geometry.add_wall_representation", model,
context=body_context, length=5000, height=3000, thickness=200)
ifcopenshell.api.run("geometry.assign_representation", model, product=wall, representation=axis)
ifcopenshell.api.run("geometry.assign_representation", model, product=wall, representation=body)
ifcopenshell.api.run("geometry.edit_object_placement", model, product=wall)
"""
usecase = Usecase()
usecase.file = file
usecase.settings = {"products": products, "type": type, "material": material}
return usecase.execute()
class Usecase:
def __init__(
self,
file: ifcopenshell.file,
products: list[ifcopenshell.entity_instance],
type: str = "IfcMaterial",
material: Optional[ifcopenshell.entity_instance] = None,
):
"""Assigns a material to the list of products
Will unassign previously assigned material.
When a material is assigned to a product, it means that the product is
made out of that material. In its simplest form, a single material may
be assigned to a product, meaning that the entire product is made out of
that one material. Alternatively, a material set may be assigned to a
product, meaning that the product is made out of a set of materials.
There are three types of sets, including layered construction, profiled
materials, and arbitrary material constituents. See
ifcopenshell.api.material.add_material_set for details.
Materials are typically assigned to the element types rather than
individual occurrences of elements. Individual occurrences would then
inherit the material from the type.
If the type has a material set, then the geometry of the occurrences
must comply with the material set. For example, if the type has a
constituent set, then it is expected that all occurrences also inherit
the geometry of the type, which is made out of those constituents.
Alternatively, if the type has a layer set, then all occurrences must
have geometry that has a thickness equal to the sum of all layers. If a
type has a profile set, then all occurrences must has the same profile
extruded along its axis.
For layers and profiles assigned to types, the occurrences must be
assigned an IfcMaterialLayerSetUsage or an IfcMaterialProfileSetUsage.
This allows individual occurrences to override the layered or profiled
construction offset from a reference line.
:param products: The list of IfcProducts to assign the material or material set
to.
:type products: list[ifcopenshell.entity_instance]
:param type: Choose from "IfcMaterial", "IfcMaterialConstituentSet",
"IfcMaterialLayerSet", "IfcMaterialLayerSetUsage",
"IfcMaterialProfileSet", "IfcMaterialProfileSetUsage", or
"IfcMaterialList". Note that "Set Usages" may only be assigned to
occurrences, not types. Defaults to "IfcMaterial".
:type type: str
:param material: The IfcMaterial or material set you are assigning here.
If type is Usage then no need to provide `material`, it will be deduced
from the element type automatically.
:type material: ifcopenshell.entity_instance, optional
:return: IfcRelAssociatesMaterial entity
or a list of IfcRelAssociatesMaterial entities
(possible if `type` is Usage
and `products` require different Usages)
or `None` if `products` was empty list.
:rtype: Union[
ifcopenshell.entity_instance,
list[ifcopenshell.entity_instance], None]
Example:
.. code:: python
# Let's start with a simple concrete material
concrete = ifcopenshell.api.run("material.add_material", model, name="CON01", category="concrete")
# Let's imagine a concrete bench made out of a single concrete
# material. Let's assign it to the type.
bench_type = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcFurnitureType")
ifcopenshell.api.run("material.assign_material", model,
products=[bench_type], type="IfcMaterial", material=concrete)
# Let's imagine there are a two occurrences of this bench. It's not
# necessary to assign any material to these benches as they
# automatically inherit the material from the type.
bench1 = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcFurniture")
bench2 = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcFurniture")
ifcopenshell.api.run("type.assign_type", model, related_objects=[bench1], relating_type=bench_type)
ifcopenshell.api.run("type.assign_type", model, related_objects=[bench2], relating_type=bench_type)
# If we have a concrete wall, we should use a layer set. Again,
# let's start with a wall type, not occurrences.
wall_type = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcWallType", name="WAL01")
# Even though there is only one layer in our layer set, we still use
# a layer set because it makes it clear that this is a layered
# construction. Let's say it's a 200mm thick concrete layer.
material_set = ifcopenshell.api.run("material.add_material_set", model,
name="CON200", set_type="IfcMaterialLayerSet")
layer = ifcopenshell.api.run("material.add_layer", model, layer_set=material_set, material=steel)
ifcopenshell.api.run("material.edit_layer", model, layer=layer, attributes={"LayerThickness": 200})
# Our wall type now has the layer set assigned to it
ifcopenshell.api.run("material.assign_material", model,
products=[wall_type], type="IfcMaterialLayerSet", material=material_set)
# Let's imagine an occurrence of this wall type.
wall = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcWall")
ifcopenshell.api.run("type.assign_type", model, related_objects=[wall], relating_type=wall_type)
# Our wall occurrence needs to have a "set usage" which describes
# how the layers relate to a reference line (typically a 2D line
# representing the extents of the wall). Usages are special since
# they automatically detect the inherited material set from the
# type. You'd write similar code for a profile set.
ifcopenshell.api.run("material.assign_material", model,
products=[wall], type="IfcMaterialLayerSetUsage")
# To be complete, let's create the wall's axis and body
# representation. Notice how the axis guides the walls "reference
# line" which determines where layers are extruded from, and the
# body has a thickness of 200mm, same as our total layer set
# thickness.
axis = ifcopenshell.api.run("geometry.add_axis_representation", model,
context=axis_context, axis=[(0.0, 0.0), (5000.0, 0.0)])
body = ifcopenshell.api.run("geometry.add_wall_representation", model,
context=body_context, length=5000, height=3000, thickness=200)
ifcopenshell.api.run("geometry.assign_representation", model, product=wall, representation=axis)
ifcopenshell.api.run("geometry.assign_representation", model, product=wall, representation=body)
ifcopenshell.api.run("geometry.edit_object_placement", model, product=wall)
"""
self.file = file
self.settings = {"products": products, "type": type, "material": material}
def execute(self) -> Union[ifcopenshell.entity_instance, list[ifcopenshell.entity_instance], None]:
def execute(self):
self.products: set[ifcopenshell.entity_instance] = set(self.settings["products"])
if not self.products:
return