diff --git a/src/blenderbim/blenderbim/bim/module/model/opening.py b/src/blenderbim/blenderbim/bim/module/model/opening.py index 6795a02147..1d55fb305d 100644 --- a/src/blenderbim/blenderbim/bim/module/model/opening.py +++ b/src/blenderbim/blenderbim/bim/module/model/opening.py @@ -111,7 +111,7 @@ class FilledOpeningGenerator: # Equivalent to "side Z" for a wall axis, so that stuff like skylights appear on the top. local_position_on_voided_obj.z = layers["offset"] + layers["thickness"] new_matrix.translation.xyz = voided_obj.matrix_world @ local_position_on_voided_obj - rotation_matrix = Matrix.Rotation(radians(-90), 4, 'X') + rotation_matrix = Matrix.Rotation(radians(-90), 4, "X") new_matrix @= rotation_matrix filling_obj.matrix_world = new_matrix @@ -188,7 +188,13 @@ class FilledOpeningGenerator: ) def regenerate_from_type(self, usecase_path, ifc_file, settings): - filling = settings["related_object"] + relating_type = settings["relating_type"] + + for related_object in settings["related_objects"]: + self._regenerate_from_type(related_object) + + def _regenerate_from_type(self, related_object: ifcopenshell.entity_instance) -> None: + filling = related_object if not getattr(filling, "FillsVoids", None): return diff --git a/src/blenderbim/blenderbim/bim/module/model/profile.py b/src/blenderbim/blenderbim/bim/module/model/profile.py index 8a4bde560d..2fed398cbe 100644 --- a/src/blenderbim/blenderbim/bim/module/model/profile.py +++ b/src/blenderbim/blenderbim/bim/module/model/profile.py @@ -96,7 +96,7 @@ class DumbProfileGenerator: should_add_representation=False, context=self.body_context, ) - ifcopenshell.api.run("type.assign_type", self.file, related_object=element, relating_type=self.relating_type) + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element], relating_type=self.relating_type) material = ifcopenshell.util.element.get_material(element) material.CardinalPoint = self.cardinal_point @@ -211,11 +211,18 @@ class DumbProfileRegenerator: return results def regenerate_from_type(self, usecase_path, ifc_file, settings): - obj = tool.Ifc.get_object(settings["related_object"]) - if not obj or not obj.data or not obj.data.BIMMeshProperties.ifc_definition_id: + relating_type = settings["relating_type"] + + new_material = ifcopenshell.util.element.get_material(relating_type) + if not new_material or not new_material.is_a("IfcMaterialLayerSet"): return - new_material = ifcopenshell.util.element.get_material(settings["relating_type"]) - if not new_material or not new_material.is_a("IfcMaterialProfileSet"): + + for related_object in settings["related_objects"]: + self._regenerate_from_type(related_object) + + def _regenerate_from_type(self, related_object: ifcopenshell.entity_instance) -> None: + obj = tool.Ifc.get_object(related_object) + if not obj or not obj.data or not obj.data.BIMMeshProperties.ifc_definition_id: return DumbProfileRecalculator().recalculate([obj]) diff --git a/src/blenderbim/blenderbim/bim/module/model/slab.py b/src/blenderbim/blenderbim/bim/module/model/slab.py index de1d44715b..ec23ca101f 100644 --- a/src/blenderbim/blenderbim/bim/module/model/slab.py +++ b/src/blenderbim/blenderbim/bim/module/model/slab.py @@ -35,6 +35,7 @@ from math import radians from mathutils import Vector, Matrix from blenderbim.bim.module.geometry.helper import Helper from blenderbim.bim.module.model.decorator import ProfileDecorator +from typing import Optional def calculate_quantities(usecase_path, ifc_file, settings): @@ -177,7 +178,7 @@ class DumbSlabGenerator: should_add_representation=False, context=self.body_context, ) - ifcopenshell.api.run("type.assign_type", self.file, related_object=element, relating_type=self.relating_type) + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element], relating_type=self.relating_type) blenderbim.core.geometry.edit_object_placement(tool.Ifc, tool.Geometry, tool.Surveyor, obj=obj) representation = ifcopenshell.api.run( @@ -250,27 +251,38 @@ class DumbSlabPlaner: self.change_thickness(element, total_thickness) def regenerate_from_type(self, usecase_path, ifc_file, settings): - obj = tool.Ifc.get_object(settings["related_object"]) - if not obj or not obj.data or not obj.data.BIMMeshProperties.ifc_definition_id: - return - self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(ifc_file) - new_material = ifcopenshell.util.element.get_material(settings["relating_type"]) + relating_type = settings["relating_type"] + + new_material = ifcopenshell.util.element.get_material(relating_type) if not new_material or not new_material.is_a("IfcMaterialLayerSet"): return + parametric = ifcopenshell.util.element.get_psets(settings["relating_type"]).get("EPset_Parametric") layer_set_direction = None if parametric: layer_set_direction = parametric.get("LayerSetDirection", layer_set_direction) new_thickness = sum([l.LayerThickness for l in new_material.MaterialLayers]) - material = ifcopenshell.util.element.get_material(settings["related_object"]) + + self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(ifc_file) + for related_object in settings["related_objects"]: + self._regenerate_from_type(related_object, layer_set_direction, new_thickness) + + def _regenerate_from_type( + self, related_object: ifcopenshell.entity_instance, layer_set_direction: Optional[str], new_thickness: float + ) -> None: + obj = tool.Ifc.get_object(related_object) + if not obj or not obj.data or not obj.data.BIMMeshProperties.ifc_definition_id: + return + + material = ifcopenshell.util.element.get_material(related_object) if not material or not material.is_a("IfcMaterialLayerSetUsage"): return if layer_set_direction: material.LayerSetDirection = layer_set_direction if material.LayerSetDirection == "AXIS3": - self.change_thickness(settings["related_object"], new_thickness) + self.change_thickness(related_object, new_thickness) - def change_thickness(self, element, thickness): + def change_thickness(self, element: ifcopenshell.entity_instance, thickness: float) -> None: body_context = ifcopenshell.util.representation.get_context(tool.Ifc.get(), "Model", "Body", "MODEL_VIEW") obj = tool.Ifc.get_object(element) if not obj: diff --git a/src/blenderbim/blenderbim/bim/module/model/wall.py b/src/blenderbim/blenderbim/bim/module/model/wall.py index 3463cb5f78..78e8b4c579 100644 --- a/src/blenderbim/blenderbim/bim/module/model/wall.py +++ b/src/blenderbim/blenderbim/bim/module/model/wall.py @@ -37,6 +37,7 @@ from blenderbim.bim.ifc import IfcStore from math import pi, sin, cos, degrees, radians from mathutils import Vector, Matrix from blenderbim.bim.module.model.opening import FilledOpeningGenerator +from typing import Optional class JoinWall(bpy.types.Operator, tool.Ifc.Operator): @@ -608,7 +609,7 @@ class DumbWallGenerator: should_add_representation=False, context=self.body_context, ) - ifcopenshell.api.run("type.assign_type", self.file, related_object=element, relating_type=self.relating_type) + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element], relating_type=self.relating_type) if self.axis_context: representation = ifcopenshell.api.run( "geometry.add_axis_representation", @@ -729,18 +730,29 @@ class DumbWallPlaner: DumbWallRecalculator().recalculate([w for w in set(walls) if w]) def regenerate_from_type(self, usecase_path, ifc_file, settings): - obj = tool.Ifc.get_object(settings["related_object"]) - if not obj or not obj.data or not obj.data.BIMMeshProperties.ifc_definition_id: - return - self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(ifc_file) - new_material = ifcopenshell.util.element.get_material(settings["relating_type"]) + relating_type = settings["relating_type"] + + new_material = ifcopenshell.util.element.get_material(relating_type) if not new_material or not new_material.is_a("IfcMaterialLayerSet"): return - parametric = ifcopenshell.util.element.get_psets(settings["relating_type"]).get("EPset_Parametric") + + parametric = ifcopenshell.util.element.get_psets(relating_type).get("EPset_Parametric") layer_set_direction = None if parametric: layer_set_direction = parametric.get("LayerSetDirection", layer_set_direction) - material = ifcopenshell.util.element.get_material(settings["related_object"]) + + self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(ifc_file) + for related_object in settings["related_objects"]: + self._regenerate_from_type(related_object, layer_set_direction) + + def _regenerate_from_type( + self, related_object: ifcopenshell.entity_instance, layer_set_direction: Optional[str] + ) -> None: + obj = tool.Ifc.get_object(related_object) + if not obj or not obj.data or not obj.data.BIMMeshProperties.ifc_definition_id: + return + + material = ifcopenshell.util.element.get_material(related_object) if not material or not material.is_a("IfcMaterialLayerSetUsage"): return if layer_set_direction: diff --git a/src/blenderbim/blenderbim/core/type.py b/src/blenderbim/blenderbim/core/type.py index ec36ad5ffe..969dc3c125 100644 --- a/src/blenderbim/blenderbim/core/type.py +++ b/src/blenderbim/blenderbim/core/type.py @@ -20,7 +20,7 @@ import blenderbim.core.geometry def assign_type(ifc, type_tool, element=None, type=None): - ifc.run("type.assign_type", related_object=element, relating_type=type) + ifc.run("type.assign_type", related_objects=[element], relating_type=type) obj = ifc.get_object(element) if type_tool.has_material_usage(element): pass # for now, representation regeneration handled by API listeners diff --git a/src/blenderbim/blenderbim/tool/spatial.py b/src/blenderbim/blenderbim/tool/spatial.py index 4e5afa9682..48d2b54274 100644 --- a/src/blenderbim/blenderbim/tool/spatial.py +++ b/src/blenderbim/blenderbim/tool/spatial.py @@ -690,7 +690,7 @@ class Spatial(blenderbim.core.tool.Spatial): instance_class = ifcopenshell.util.type.get_applicable_entities(ifc_class, tool.Ifc.get().schema)[0] bpy.ops.bim.assign_class(obj=obj.name, ifc_class=instance_class) element = tool.Ifc.get_entity(obj) - tool.Ifc.run("type.assign_type", related_object=element, relating_type=relating_type) + tool.Ifc.run("type.assign_type", related_objects=[element], relating_type=relating_type) @classmethod def assign_relating_type_to_element(cls, ifc, Type, element, relating_type): diff --git a/src/blenderbim/test/core/test_type.py b/src/blenderbim/test/core/test_type.py index 0a084f8438..5800f04ea4 100644 --- a/src/blenderbim/test/core/test_type.py +++ b/src/blenderbim/test/core/test_type.py @@ -22,7 +22,7 @@ from test.core.bootstrap import ifc, type class TestAssignType: def test_assigning_and_switching_to_an_existing_type_data(self, ifc, type): - ifc.run("type.assign_type", related_object="element", relating_type="type").should_be_called() + ifc.run("type.assign_type", related_objects=["element"], relating_type="type").should_be_called() type.has_material_usage("element").should_be_called().will_return(False) ifc.get_object("type").should_be_called().will_return("type_obj") type.get_object_data("type_obj").should_be_called().will_return("type_obj_data") @@ -32,7 +32,7 @@ class TestAssignType: subject.assign_type(ifc, type, element="element", type="type") def test_assigning_and_not_changing_data_if_the_type_has_no_data(self, ifc, type): - ifc.run("type.assign_type", related_object="element", relating_type="type").should_be_called() + ifc.run("type.assign_type", related_objects=["element"], relating_type="type").should_be_called() type.has_material_usage("element").should_be_called().will_return(False) ifc.get_object("type").should_be_called().will_return("type_obj") type.get_object_data("type_obj").should_be_called().will_return(None) diff --git a/src/blenderbim/test/tool/test_geometry.py b/src/blenderbim/test/tool/test_geometry.py index 48f443ad19..0837fe50a3 100644 --- a/src/blenderbim/test/tool/test_geometry.py +++ b/src/blenderbim/test/tool/test_geometry.py @@ -199,7 +199,7 @@ class TestGetElementType(NewFile): ifc = tool.Ifc.get() element = ifc.createIfcWall() type = ifc.createIfcWallType() - ifcopenshell.api.run("type.assign_type", ifc, related_object=element, relating_type=type) + ifcopenshell.api.run("type.assign_type", ifc, related_objects=[element], relating_type=type) assert subject.get_element_type(element) == type @@ -209,7 +209,7 @@ class TestGetElementsOfType(NewFile): ifc = tool.Ifc.get() element = ifc.createIfcWall() type = ifc.createIfcWallType() - ifcopenshell.api.run("type.assign_type", ifc, related_object=element, relating_type=type) + ifcopenshell.api.run("type.assign_type", ifc, related_objects=[element], relating_type=type) assert subject.get_elements_of_type(type) == (element,) diff --git a/src/blenderbim/test/tool/test_root.py b/src/blenderbim/test/tool/test_root.py index 099880df3f..7e0e40fed4 100644 --- a/src/blenderbim/test/tool/test_root.py +++ b/src/blenderbim/test/tool/test_root.py @@ -98,7 +98,7 @@ class TestGetElementType(NewFile): ifc = tool.Ifc.get() element = ifc.createIfcWall() type = ifc.createIfcWallType() - ifcopenshell.api.run("type.assign_type", ifc, related_object=element, relating_type=type) + ifcopenshell.api.run("type.assign_type", ifc, related_objects=[element], relating_type=type) assert subject.get_element_type(element) == type diff --git a/src/blenderbim/test/tool/test_type.py b/src/blenderbim/test/tool/test_type.py index 4e3a7342f5..bf497e021c 100644 --- a/src/blenderbim/test/tool/test_type.py +++ b/src/blenderbim/test/tool/test_type.py @@ -154,7 +154,7 @@ class TestGetTypeOccurrences(NewFile): tool.Ifc.set(ifc) wall_type = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWallType") wall = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall") - ifcopenshell.api.run("type.assign_type", ifc, related_object=wall, relating_type=wall_type) + ifcopenshell.api.run("type.assign_type", ifc, related_objects=[wall], relating_type=wall_type) assert subject.get_type_occurrences(wall_type) == (wall,) diff --git a/src/ifcopenshell-python/docs/ifcopenshell-python/geometry_creation.rst b/src/ifcopenshell-python/docs/ifcopenshell-python/geometry_creation.rst index f79b7c8d80..408329c078 100644 --- a/src/ifcopenshell-python/docs/ifcopenshell-python/geometry_creation.rst +++ b/src/ifcopenshell-python/docs/ifcopenshell-python/geometry_creation.rst @@ -648,7 +648,7 @@ efficient and implies that the type is interchangable (e.g. for maintenance). # Assign our furniture occurrence to the type. # That's it! The representation will automatically be mapped! - run("type.assign_type", model, related_object=element, relating_type=element_type) + run("type.assign_type", model, related_objects=[element], relating_type=element_type) Material layer sets ------------------- @@ -693,7 +693,7 @@ responsibility to make sure the geometry is correct. ifcopenshell.api.run("geometry.edit_object_placement", model, product=wall) # The wall is a WAL01 wall type. The material layer set is inherited. - ifcopenshell.api.run("type.assign_type", model, related_object=wall, relating_type=wall_type) + ifcopenshell.api.run("type.assign_type", model, related_objects=[wall], relating_type=wall_type) # It's now our responsibility to create a compatible representation. # Notice how our thickness of 0.118 must equal .013 + .092 + .013 from our type @@ -749,7 +749,7 @@ responsibility to make sure the geometry is correct. ifcopenshell.api.run("geometry.edit_object_placement", model, product=beam) # The beam is a B1 beam type. The material profile set is inherited. - ifcopenshell.api.run("type.assign_type", model, related_object=beam, relating_type=beam_type) + ifcopenshell.api.run("type.assign_type", model, related_objects=[beam], relating_type=beam_type) # It's now our responsibility to create a compatible representation. # Notice how we reuse our profile instead of creating a new profile. diff --git a/src/ifcopenshell-python/ifcopenshell/api/__init__.py b/src/ifcopenshell-python/ifcopenshell/api/__init__.py index fea3e6a225..ccea070c98 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/__init__.py +++ b/src/ifcopenshell-python/ifcopenshell/api/__init__.py @@ -73,6 +73,9 @@ ARGUMENTS_DEPRECATION = { "nest.unassign_object": partial( batching_argument_deprecation, prev_argument="related_object", new_argument="related_objects" ), + "type.assign_type": partial( + batching_argument_deprecation, prev_argument="related_object", new_argument="related_objects" + ), } diff --git a/src/ifcopenshell-python/ifcopenshell/api/material/assign_material.py b/src/ifcopenshell-python/ifcopenshell/api/material/assign_material.py index 0c27e4ea46..b1a97faaac 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/material/assign_material.py +++ b/src/ifcopenshell-python/ifcopenshell/api/material/assign_material.py @@ -85,8 +85,8 @@ class Usecase: # 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_object=bench1, relating_type=bench_type) - ifcopenshell.api.run("type.assign_type", model, related_object=bench2, relating_type=bench_type) + 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. @@ -106,7 +106,7 @@ class Usecase: # 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_object=wall, relating_type=wall_type) + 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 diff --git a/src/ifcopenshell-python/ifcopenshell/api/material/edit_layer_usage.py b/src/ifcopenshell-python/ifcopenshell/api/material/edit_layer_usage.py index d6900314ab..63aa2adda1 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/material/edit_layer_usage.py +++ b/src/ifcopenshell-python/ifcopenshell/api/material/edit_layer_usage.py @@ -59,7 +59,7 @@ class Usecase: # 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_object=wall, relating_type=wall_type) + 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 diff --git a/src/ifcopenshell-python/ifcopenshell/api/project/append_asset.py b/src/ifcopenshell-python/ifcopenshell/api/project/append_asset.py index 7ac21e07f3..991824859b 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/project/append_asset.py +++ b/src/ifcopenshell-python/ifcopenshell/api/project/append_asset.py @@ -204,7 +204,7 @@ class Usecase: "type.assign_type", self.file, should_run_listeners=False, - related_object=element, + related_objects=[element], relating_type=new_type, should_map_representations=False, ) diff --git a/src/ifcopenshell-python/ifcopenshell/api/type/assign_type.py b/src/ifcopenshell-python/ifcopenshell/api/type/assign_type.py index 622f034b79..260b068e7e 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/type/assign_type.py +++ b/src/ifcopenshell-python/ifcopenshell/api/type/assign_type.py @@ -19,11 +19,18 @@ import ifcopenshell import ifcopenshell.api import ifcopenshell.util.element +from typing import Union class Usecase: - def __init__(self, file, related_object=None, relating_type=None, should_map_representations=True): - """Assigns a type to an occurrence of an object + def __init__( + self, + file: ifcopenshell.file, + related_objects: list[ifcopenshell.entity_instance], + relating_type: ifcopenshell.entity_instance, + should_map_representations=True, + ): + """Assigns a type to occurrences of an object IFC supports the concept of occurrences and types. An occurrence is an actual physical product in the real world: like a wall, a chair, a door, @@ -83,8 +90,8 @@ class Usecase: as-built or dilapidation models, where existing conditions are ambiguous, unknown or are so bespoke as to have no logical type. - :param related_object: The IfcElement occurrence. - :type related_object: ifcopenshell.entity_instance.entity_instance + :param related_objects: The IfcElement occurrences. + :type related_objects: list[ifcopenshell.entity_instance.entity_instance] :param relating_type: The IfcElementType type. :type relating_type: ifcopenshell.entity_instance.entity_instance :param should_map_representations: If a type has a representation map, @@ -93,7 +100,8 @@ class Usecase: yourself. In this scenario, you may set this to False. :type should_map_representations: bool :return: The IfcRelDefinesByType relationship - :rtype: ifcopenshell.entity_instance.entity_instance + or `None` if `related_objects` was empty list. + :rtype: Union[ifcopenshell.entity_instance.entity_instance, None] Example: @@ -111,7 +119,7 @@ class Usecase: # had a representation, the furniture occurrence will also now have # the exact same representation. This is highly efficient as you # don't need to define the representation for every occurrence. - ifcopenshell.api.run("type.assign_type", model, related_object=furniture, relating_type=furniture_type) + ifcopenshell.api.run("type.assign_type", model, related_objects=[furniture], relating_type=furniture_type) # Let's imagine a parametric material layer set wall_type = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcWallType", name="WAL01") @@ -146,7 +154,7 @@ class Usecase: wall = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcWall") # The wall is a WAL01 wall type. - ifcopenshell.api.run("type.assign_type", model, related_object=wall, relating_type=wall_type) + ifcopenshell.api.run("type.assign_type", model, related_objects=[wall], relating_type=wall_type) # A bit of preparation, let's create some geometric contexts since # we want to create some geometry for our wall. @@ -167,81 +175,101 @@ class Usecase: """ self.file = file self.settings = { - "related_object": related_object, + "related_objects": related_objects, "relating_type": relating_type, "should_map_representations": should_map_representations, } - def execute(self): - if self.file.schema == "IFC2X3": - is_typed_by = None - is_defined_by = self.settings["related_object"].IsDefinedBy - for rel in is_defined_by: - if rel.is_a("IfcRelDefinesByType"): - is_typed_by = [rel] - break - types = self.settings["relating_type"].ObjectTypeOf - else: - is_typed_by = self.settings["related_object"].IsTypedBy - types = self.settings["relating_type"].Types - - if types and is_typed_by == types: + def execute(self) -> Union[ifcopenshell.entity_instance, None]: + if not self.settings["related_objects"]: return - if is_typed_by: - related_objects = list(is_typed_by[0].RelatedObjects) - related_objects.remove(self.settings["related_object"]) - if related_objects: - is_typed_by[0].RelatedObjects = related_objects - ifcopenshell.api.run("owner.update_owner_history", self.file, **{"element": is_typed_by[0]}) + related_objects = set(self.settings["related_objects"]) + relating_type = self.settings["relating_type"] + + ifc2x3 = self.file.schema == "IFC2X3" + + related_objects = set(self.settings["related_objects"]) + relating_type = self.settings["relating_type"] + if ifc2x3: + types = next(iter(relating_type.ObjectTypeOf), None) + else: + types = next(iter(relating_type.Types), None) + + previous_types_rels: set[ifcopenshell.entity_instance] = set() + objects_without_types: list[ifcopenshell.entity_instance] = [] + objects_with_types: list[ifcopenshell.entity_instance] = [] + + # check if there is anything to change + for object in related_objects: + if ifc2x3: + object_rel = next((i for i in object.IsDefinedBy if i.is_a("IfcRelDefinesByType")), None) else: - history = is_typed_by[0].OwnerHistory - self.file.remove(is_typed_by[0]) + object_rel = next(iter(object.IsTypedBy), None) + + if object_rel is None: + objects_without_types.append(object) + continue + + # either is_nested_by is None or product is part of different rel + if object_rel != types: + previous_types_rels.add(object_rel) + objects_with_types.append(object) + + objects_to_change = objects_without_types + objects_with_types + # nothing to change + if not objects_to_change: + return types + + # unassign from previous types + for is_typed_by in previous_types_rels: + cur_related_objects = set(is_typed_by.RelatedObjects) - related_objects + if cur_related_objects: + is_typed_by.RelatedObjects = list(cur_related_objects) + ifcopenshell.api.run("owner.update_owner_history", self.file, **{"element": is_typed_by}) + else: + history = is_typed_by.OwnerHistory + self.file.remove(is_typed_by) if history: ifcopenshell.util.element.remove_deep2(self.file, history) + # assign objects to a new type if types: - related_objects = list(types[0].RelatedObjects) - related_objects.append(self.settings["related_object"]) - types[0].RelatedObjects = related_objects - ifcopenshell.api.run("owner.update_owner_history", self.file, **{"element": types[0]}) + types.RelatedObjects = list(set(types.RelatedObjects) | related_objects) + ifcopenshell.api.run("owner.update_owner_history", self.file, **{"element": types}) else: types = self.file.create_entity( "IfcRelDefinesByType", **{ "GlobalId": ifcopenshell.guid.new(), "OwnerHistory": ifcopenshell.api.run("owner.create_owner_history", self.file), - "RelatedObjects": [self.settings["related_object"]], - "RelatingType": self.settings["relating_type"], - } + "RelatedObjects": list(related_objects), + "RelatingType": relating_type, + }, ) if self.settings["should_map_representations"]: - if getattr(self.settings["relating_type"], "RepresentationMaps", None): - ifcopenshell.api.run( - "type.map_type_representations", - self.file, - related_object=self.settings["related_object"], - relating_type=self.settings["relating_type"], - ) - self.map_material_usages() + if getattr(relating_type, "RepresentationMaps", None): + for related_object in related_objects: + ifcopenshell.api.run( + "type.map_type_representations", + self.file, + related_object=related_object, + relating_type=relating_type, + ) + self.map_material_usages(related_objects) return types - def map_material_usages(self): + def map_material_usages(self, related_objects: set[ifcopenshell.entity_instance]) -> None: type_material = ifcopenshell.util.element.get_material(self.settings["relating_type"]) if not type_material: return - if type_material.is_a("IfcMaterialLayerSet"): - ifcopenshell.api.run( - "material.assign_material", - self.file, - product=self.settings["related_object"], - type="IfcMaterialLayerSetUsage", - ) - elif type_material.is_a("IfcMaterialProfileSet"): - ifcopenshell.api.run( - "material.assign_material", - self.file, - product=self.settings["related_object"], - type="IfcMaterialProfileSetUsage", - ) + ifc_class = type_material.is_a() + if ifc_class in ("IfcMaterialLayerSet", "IfcMaterialProfileSet"): + for related_object in related_objects: + ifcopenshell.api.run( + "material.assign_material", + self.file, + product=related_object, + type=f"{ifc_class}Usage", + ) diff --git a/src/ifcopenshell-python/ifcopenshell/api/type/map_type_representations.py b/src/ifcopenshell-python/ifcopenshell/api/type/map_type_representations.py index 940fd25902..180e163477 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/type/map_type_representations.py +++ b/src/ifcopenshell-python/ifcopenshell/api/type/map_type_representations.py @@ -60,7 +60,7 @@ class Usecase: # furniture type has no representation, so the furniture may also # have no representation, or any arbitrary representation that may # vary from occurrence to occurrence. - ifcopenshell.api.run("type.assign_type", model, related_object=furniture, relating_type=furniture_type) + ifcopenshell.api.run("type.assign_type", model, related_objects=[furniture], relating_type=furniture_type) # A bit of preparation, let's create some geometric contexts since # we want to create some geometry for our furniture type. diff --git a/src/ifcopenshell-python/ifcopenshell/api/type/unassign_type.py b/src/ifcopenshell-python/ifcopenshell/api/type/unassign_type.py index 843121f967..dbafade861 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/type/unassign_type.py +++ b/src/ifcopenshell-python/ifcopenshell/api/type/unassign_type.py @@ -42,7 +42,7 @@ class Usecase: furniture = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcFurniture") # Assign the furniture to the furniture type. - ifcopenshell.api.run("type.assign_type", model, related_object=furniture, relating_type=furniture_type) + ifcopenshell.api.run("type.assign_type", model, related_objects=[furniture], relating_type=furniture_type) # Change our mind. Maybe it's a different type? ifcopenshell.api.run("type.unassign_type", model, related_object=furniture) diff --git a/src/ifcopenshell-python/test/api/geometry/test_assign_representation.py b/src/ifcopenshell-python/test/api/geometry/test_assign_representation.py index 1bdd7f1ce8..654e4d383a 100644 --- a/src/ifcopenshell-python/test/api/geometry/test_assign_representation.py +++ b/src/ifcopenshell-python/test/api/geometry/test_assign_representation.py @@ -47,7 +47,7 @@ class TestAssignRepresentation(test.bootstrap.IFC4): def test_assigning_to_a_type_will_map_representations_to_instances(self): wall = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") walltype = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") - ifcopenshell.api.run("type.assign_type", self.file, related_object=wall, relating_type=walltype) + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[wall], relating_type=walltype) context = self.file.createIfcGeometricRepresentationContext() rep = self.file.createIfcShapeRepresentation(ContextOfItems=context) rep2 = self.file.createIfcShapeRepresentation(ContextOfItems=context) @@ -69,7 +69,7 @@ class TestAssignRepresentation(test.bootstrap.IFC4): ifcopenshell.api.run("geometry.assign_representation", self.file, product=walltype, representation=rep) wall = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") - ifcopenshell.api.run("type.assign_type", self.file, related_object=wall, relating_type=walltype) + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[wall], relating_type=walltype) ifcopenshell.api.run("geometry.assign_representation", self.file, product=wall, representation=rep2) assert wall.Representation.Representations[0].RepresentationType == "MappedRepresentation" @@ -84,7 +84,7 @@ class TestAssignRepresentation(test.bootstrap.IFC4): rep = self.file.createIfcShapeRepresentation(ContextOfItems=context) walltype = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") wall = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") - ifcopenshell.api.run("type.assign_type", self.file, related_object=wall, relating_type=walltype) + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[wall], relating_type=walltype) ifcopenshell.api.run("geometry.assign_representation", self.file, product=wall, representation=rep) assert wall.Representation.Representations[0].RepresentationType != "MappedRepresentation" assert wall.Representation.Representations[0] == rep diff --git a/src/ifcopenshell-python/test/api/material/test_assign_material.py b/src/ifcopenshell-python/test/api/material/test_assign_material.py index 9e616cbb95..dabcdb811c 100644 --- a/src/ifcopenshell-python/test/api/material/test_assign_material.py +++ b/src/ifcopenshell-python/test/api/material/test_assign_material.py @@ -48,7 +48,7 @@ class TestAssignMaterial(test.bootstrap.IFC4): def test_assign_type_material_layer_set_and_element_layer_set_usage(self): element_type = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") - ifcopenshell.api.run("type.assign_type", self.file, related_object=element, relating_type=element_type) + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element], relating_type=element_type) material = ifcopenshell.api.run("material.add_material", self.file, name="CON01") ifcopenshell.api.run("material.assign_material", self.file, product=element_type, type="IfcMaterialLayerSet") ifcopenshell.api.run("material.assign_material", self.file, product=element, type="IfcMaterialLayerSetUsage") @@ -69,7 +69,7 @@ class TestAssignMaterial(test.bootstrap.IFC4): def test_assign_type_material_profile_set_and_element_profile_set_usage(self): element_type = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") - ifcopenshell.api.run("type.assign_type", self.file, related_object=element, relating_type=element_type) + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element], relating_type=element_type) material = ifcopenshell.api.run("material.add_material", self.file, name="CON01") ifcopenshell.api.run("material.assign_material", self.file, product=element_type, type="IfcMaterialProfileSet") ifcopenshell.api.run("material.assign_material", self.file, product=element, type="IfcMaterialProfileSetUsage") diff --git a/src/ifcopenshell-python/test/api/material/test_unassign_material.py b/src/ifcopenshell-python/test/api/material/test_unassign_material.py index aea9e78ddf..9634941d21 100644 --- a/src/ifcopenshell-python/test/api/material/test_unassign_material.py +++ b/src/ifcopenshell-python/test/api/material/test_unassign_material.py @@ -62,7 +62,7 @@ class TestUnassignMaterial(test.bootstrap.IFC4): def test_unassign_material_layer_set_usage_from_element(self): element_type = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") - ifcopenshell.api.run("type.assign_type", self.file, related_object=element, relating_type=element_type) + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element], relating_type=element_type) material = ifcopenshell.api.run("material.add_material", self.file, name="CON01") ifcopenshell.api.run("material.assign_material", self.file, product=element_type, type="IfcMaterialLayerSet") ifcopenshell.api.run("material.assign_material", self.file, product=element, type="IfcMaterialLayerSetUsage") @@ -78,8 +78,8 @@ class TestUnassignMaterial(test.bootstrap.IFC4): element_type = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") - ifcopenshell.api.run("type.assign_type", self.file, related_object=element, relating_type=element_type) - ifcopenshell.api.run("type.assign_type", self.file, related_object=element2, relating_type=element_type) + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element], relating_type=element_type) + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element2], relating_type=element_type) material = ifcopenshell.api.run("material.add_material", self.file, name="CON01") ifcopenshell.api.run("material.assign_material", self.file, product=element_type, type="IfcMaterialLayerSet") rel = ifcopenshell.api.run( @@ -114,7 +114,7 @@ class TestUnassignMaterial(test.bootstrap.IFC4): def test_unassign_material_profile_set_usage_from_element(self): element_type = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") - ifcopenshell.api.run("type.assign_type", self.file, related_object=element, relating_type=element_type) + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element], relating_type=element_type) material = ifcopenshell.api.run("material.add_material", self.file, name="CON01") ifcopenshell.api.run("material.assign_material", self.file, product=element_type, type="IfcMaterialProfileSet") ifcopenshell.api.run("material.assign_material", self.file, product=element, type="IfcMaterialProfileSetUsage") diff --git a/src/ifcopenshell-python/test/api/project/test_append_asset.py b/src/ifcopenshell-python/test/api/project/test_append_asset.py index bca7a1580d..7c8ed8943a 100644 --- a/src/ifcopenshell-python/test/api/project/test_append_asset.py +++ b/src/ifcopenshell-python/test/api/project/test_append_asset.py @@ -88,7 +88,7 @@ class TestAppendAsset(test.bootstrap.IFC4): element = ifcopenshell.api.run("root.create_entity", library, ifc_class="IfcWall") element_type = ifcopenshell.api.run("root.create_entity", library, ifc_class="IfcWallType") element_type2 = ifcopenshell.api.run("root.create_entity", library, ifc_class="IfcWallType") - ifcopenshell.api.run("type.assign_type", library, related_object=element, relating_type=element_type) + ifcopenshell.api.run("type.assign_type", library, related_objects=[element], relating_type=element_type) material = ifcopenshell.api.run("material.add_material", library, name="Material") ifcopenshell.api.run("material.assign_material", library, product=element, material=material) ifcopenshell.api.run("material.assign_material", library, product=element_type, material=material) @@ -186,7 +186,7 @@ class TestAppendAsset(test.bootstrap.IFC4): element_type.RepresentationMaps = [library.createIfcRepresentationMap(MappedRepresentation=mapped_rep)] element = ifcopenshell.api.run("root.create_entity", library, ifc_class="IfcWall") - ifcopenshell.api.run("type.assign_type", library, related_object=element, relating_type=element_type) + ifcopenshell.api.run("type.assign_type", library, related_objects=[element], relating_type=element_type) ifcopenshell.api.run("project.append_asset", self.file, library=library, element=element) assert len(self.file.by_type("IfcStyledItem")) == 1 @@ -356,7 +356,7 @@ class TestAppendAsset(test.bootstrap.IFC4): library = ifcopenshell.api.run("project.create_file") element = ifcopenshell.api.run("root.create_entity", library, ifc_class="IfcWall") element_type = ifcopenshell.api.run("root.create_entity", library, ifc_class="IfcWallType") - ifcopenshell.api.run("type.assign_type", library, related_object=element, relating_type=element_type) + ifcopenshell.api.run("type.assign_type", library, related_objects=[element], relating_type=element_type) ifcopenshell.api.run("project.append_asset", self.file, library=library, element=element) assert ifcopenshell.util.element.get_type(self.file.by_type("IfcWall")[0]).is_a("IfcWallType") @@ -366,9 +366,9 @@ class TestAppendAsset(test.bootstrap.IFC4): element2 = ifcopenshell.api.run("root.create_entity", library, ifc_class="IfcWall") element3 = ifcopenshell.api.run("root.create_entity", library, ifc_class="IfcWall") element_type = ifcopenshell.api.run("root.create_entity", library, ifc_class="IfcWallType") - ifcopenshell.api.run("type.assign_type", library, related_object=element, relating_type=element_type) - ifcopenshell.api.run("type.assign_type", library, related_object=element2, relating_type=element_type) - ifcopenshell.api.run("type.assign_type", library, related_object=element3, relating_type=element_type) + ifcopenshell.api.run("type.assign_type", library, related_objects=[element], relating_type=element_type) + ifcopenshell.api.run("type.assign_type", library, related_objects=[element2], relating_type=element_type) + ifcopenshell.api.run("type.assign_type", library, related_objects=[element3], relating_type=element_type) ifcopenshell.api.run("project.append_asset", self.file, library=library, element=element) ifcopenshell.api.run("project.append_asset", self.file, library=library, element=element2) assert len(ifcopenshell.util.element.get_types(self.file.by_type("IfcWallType")[0])) == 2 @@ -387,7 +387,7 @@ class TestAppendAsset(test.bootstrap.IFC4): element = ifcopenshell.api.run("root.create_entity", library, ifc_class="IfcWall") element_type = ifcopenshell.api.run("root.create_entity", library, ifc_class="IfcWallType") element_type2 = ifcopenshell.api.run("root.create_entity", library, ifc_class="IfcWallType") - ifcopenshell.api.run("type.assign_type", library, related_object=element, relating_type=element_type) + ifcopenshell.api.run("type.assign_type", library, related_objects=[element], relating_type=element_type) material = ifcopenshell.api.run("material.add_material", library, name="Material") ifcopenshell.api.run("material.assign_material", library, product=element, material=material) ifcopenshell.api.run("material.assign_material", library, product=element_type, material=material) @@ -419,7 +419,7 @@ class TestAppendAssetIFC2X3(test.bootstrap.IFC2X3): library = ifcopenshell.api.run("project.create_file", version="IFC2X3") element = ifcopenshell.api.run("root.create_entity", library, ifc_class="IfcWall") element_type = ifcopenshell.api.run("root.create_entity", library, ifc_class="IfcWallType") - ifcopenshell.api.run("type.assign_type", library, related_object=element, relating_type=element_type) + ifcopenshell.api.run("type.assign_type", library, related_objects=[element], relating_type=element_type) ifcopenshell.api.run("project.append_asset", self.file, library=library, element=element) assert ifcopenshell.util.element.get_type(self.file.by_type("IfcWall")[0]).is_a("IfcWallType") @@ -429,9 +429,9 @@ class TestAppendAssetIFC2X3(test.bootstrap.IFC2X3): element2 = ifcopenshell.api.run("root.create_entity", library, ifc_class="IfcWall") element3 = ifcopenshell.api.run("root.create_entity", library, ifc_class="IfcWall") element_type = ifcopenshell.api.run("root.create_entity", library, ifc_class="IfcWallType") - ifcopenshell.api.run("type.assign_type", library, related_object=element, relating_type=element_type) - ifcopenshell.api.run("type.assign_type", library, related_object=element2, relating_type=element_type) - ifcopenshell.api.run("type.assign_type", library, related_object=element3, relating_type=element_type) + ifcopenshell.api.run("type.assign_type", library, related_objects=[element], relating_type=element_type) + ifcopenshell.api.run("type.assign_type", library, related_objects=[element2], relating_type=element_type) + ifcopenshell.api.run("type.assign_type", library, related_objects=[element3], relating_type=element_type) ifcopenshell.api.run("project.append_asset", self.file, library=library, element=element) ifcopenshell.api.run("project.append_asset", self.file, library=library, element=element2) assert len(ifcopenshell.util.element.get_types(self.file.by_type("IfcWallType")[0])) == 2 diff --git a/src/ifcopenshell-python/test/api/root/test_copy_class.py b/src/ifcopenshell-python/test/api/root/test_copy_class.py index a4177150fa..25e2b06345 100644 --- a/src/ifcopenshell-python/test/api/root/test_copy_class.py +++ b/src/ifcopenshell-python/test/api/root/test_copy_class.py @@ -210,7 +210,7 @@ class TestCopyClass(test.bootstrap.IFC4): def test_copying_a_type_and_purging_type_relationships(self): type = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") - ifcopenshell.api.run("type.assign_type", self.file, related_object=element, relating_type=type) + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element], relating_type=type) new = ifcopenshell.api.run("root.copy_class", self.file, product=type) assert not new.Types diff --git a/src/ifcopenshell-python/test/api/root/test_reassign_class.py b/src/ifcopenshell-python/test/api/root/test_reassign_class.py index fc9a7f4b2b..17b3fd1801 100644 --- a/src/ifcopenshell-python/test/api/root/test_reassign_class.py +++ b/src/ifcopenshell-python/test/api/root/test_reassign_class.py @@ -54,9 +54,9 @@ class TestReassignClass(test.bootstrap.IFC4): def test_reassign_class_for_type_occurrences(self): element_type = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") element1 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") - ifcopenshell.api.run("type.assign_type", self.file, related_object=element1, relating_type=element_type) + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element1], relating_type=element_type) element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") - ifcopenshell.api.run("type.assign_type", self.file, related_object=element2, relating_type=element_type) + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element2], relating_type=element_type) element_type = ifcopenshell.api.run( "root.reassign_class", self.file, product=element_type, ifc_class="IfcSlabType" @@ -74,9 +74,9 @@ class TestReassignClass(test.bootstrap.IFC4): def test_reassigning_type_class_and_its_occurrences_classes_if_entity_was_typed(self): element_type = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") element1 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") - ifcopenshell.api.run("type.assign_type", self.file, related_object=element1, relating_type=element_type) + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element1], relating_type=element_type) element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") - ifcopenshell.api.run("type.assign_type", self.file, related_object=element2, relating_type=element_type) + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element2], relating_type=element_type) element1 = ifcopenshell.api.run("root.reassign_class", self.file, product=element1, ifc_class="IfcSlab") diff --git a/src/ifcopenshell-python/test/api/root/test_remove_product.py b/src/ifcopenshell-python/test/api/root/test_remove_product.py index 34756288bd..821e9cb3dc 100644 --- a/src/ifcopenshell-python/test/api/root/test_remove_product.py +++ b/src/ifcopenshell-python/test/api/root/test_remove_product.py @@ -98,7 +98,7 @@ class TestRemoveProduct(test.bootstrap.IFC4): context = ifcopenshell.api.run("context.add_context", self.file, context_type="Model") element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") element_type = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") - ifcopenshell.api.run("type.assign_type", self.file, related_object=element, relating_type=element_type) + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element], relating_type=element_type) rep_map = self.file.createIfcRepresentationMap( MappingOrigin=self.file.createIfcAxis2Placement3D(), MappedRepresentation=self.file.createIfcShapeRepresentation( @@ -377,7 +377,7 @@ class TestRemoveProduct(test.bootstrap.IFC4): def test_removing_all_type_relationships_of_an_element(self): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") element_type = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") - ifcopenshell.api.run("type.assign_type", self.file, related_object=element, relating_type=element_type) + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element], relating_type=element_type) ifcopenshell.api.run("root.remove_product", self.file, product=element) assert not self.file.by_type("IfcRelDefinesByType") assert self.file.by_type("IfcWallType") @@ -386,8 +386,8 @@ class TestRemoveProduct(test.bootstrap.IFC4): element1 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") element_type = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") - ifcopenshell.api.run("type.assign_type", self.file, related_object=element1, relating_type=element_type) - ifcopenshell.api.run("type.assign_type", self.file, related_object=element2, relating_type=element_type) + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element1], relating_type=element_type) + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element2], relating_type=element_type) ifcopenshell.api.run("root.remove_product", self.file, product=element_type) assert not self.file.by_type("IfcRelDefinesByType") assert self.file.by_type("IfcWall") diff --git a/src/ifcopenshell-python/test/api/test_api.py b/src/ifcopenshell-python/test/api/test_api.py index 15e81b03ba..c19c378427 100644 --- a/src/ifcopenshell-python/test/api/test_api.py +++ b/src/ifcopenshell-python/test/api/test_api.py @@ -123,3 +123,11 @@ class TestTemporarySupportForDeprecatedAPIArguments(test.bootstrap.IFC4): ifcopenshell.api.run("nest.assign_object", self.file, related_objects=[subelement1], relating_object=element) ifcopenshell.api.run("nest.unassign_object", self.file, related_object=subelement1) assert ifcopenshell.util.element.get_nest(subelement1) is None + + @deprecation_check + def test_assigning_a_type(self): + element1 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + element_type = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") + rel = ifcopenshell.api.run("type.assign_type", self.file, related_object=element1, relating_type=element_type) + assert ifcopenshell.util.element.get_type(element1) == element_type + assert rel.is_a("IfcRelDefinesByType") diff --git a/src/ifcopenshell-python/test/api/type/test_assign_type.py b/src/ifcopenshell-python/test/api/type/test_assign_type.py new file mode 100644 index 0000000000..484cceb260 --- /dev/null +++ b/src/ifcopenshell-python/test/api/type/test_assign_type.py @@ -0,0 +1,70 @@ +# IfcOpenShell - IFC toolkit and geometry engine +# Copyright (C) 2021 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 test.bootstrap +import ifcopenshell.api +import ifcopenshell.util.element +import pytest + + +class TestAssignType(test.bootstrap.IFC4): + def test_assigning_a_type(self): + element1 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + element_type = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") + rel = ifcopenshell.api.run( + "type.assign_type", self.file, related_objects=[element1, element2], relating_type=element_type + ) + assert ifcopenshell.util.element.get_type(element1) == element_type + assert ifcopenshell.util.element.get_type(element2) == element_type + assert rel.is_a("IfcRelDefinesByType") + + def test_doing_nothing_if_type_is_already_assigned(self): + element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + element_type = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element], relating_type=element_type) + total_elements = len([e for e in self.file]) + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element], relating_type=element_type) + assert len([e for e in self.file]) == total_elements + + def test_that_old_typing_relationships_are_updated_if_they_still_have_elements(self): + element_type1 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") + element_type2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") + element1 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + ifcopenshell.api.run( + "type.assign_type", self.file, related_objects=[element1, element2], relating_type=element_type1 + ) + rel = element1.IsDefinedBy[0] if self.file.schema == "IFC2X3" else element1.IsTypedBy[0] + assert len(rel.RelatedObjects) == 2 + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element1], relating_type=element_type2) + assert len(rel.RelatedObjects) == 1 + + def test_that_old_typing_relationships_are_purged_if_no_more_elements_are_nested(self): + element_type1 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") + element_type2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") + element1 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element1], relating_type=element_type1) + rel_id = (element1.IsDefinedBy[0] if self.file.schema == "IFC2X3" else element1.IsTypedBy[0]).id() + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element1], relating_type=element_type2) + with pytest.raises(RuntimeError): + self.file.by_id(rel_id) + + +class TestAssignTypeIFC2X3(test.bootstrap.IFC2X3, TestAssignType): + pass diff --git a/src/ifcopenshell-python/test/api/type/test_map_type_representation.py b/src/ifcopenshell-python/test/api/type/test_map_type_representation.py index 50e63cb90d..a43430a040 100644 --- a/src/ifcopenshell-python/test/api/type/test_map_type_representation.py +++ b/src/ifcopenshell-python/test/api/type/test_map_type_representation.py @@ -24,7 +24,7 @@ class TestMapTypeRepresentations(test.bootstrap.IFC4): def test_doing_nothing_if_the_type_has_no_representation_maps(self): element = self.file.createIfcWall() type = self.file.createIfcWallType() - ifcopenshell.api.run("type.assign_type", self.file, related_object=element, relating_type=type) + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element], relating_type=type) total_elements = len([e for e in self.file]) ifcopenshell.api.run("type.map_type_representations", self.file, related_object=element, relating_type=type) assert len([e for e in self.file]) == total_elements diff --git a/src/ifcopenshell-python/test/util/test_brick.py b/src/ifcopenshell-python/test/util/test_brick.py index 52a99b1a1a..78b7771d57 100644 --- a/src/ifcopenshell-python/test/util/test_brick.py +++ b/src/ifcopenshell-python/test/util/test_brick.py @@ -36,5 +36,5 @@ class TestGetBrickTypeIFC2X3(test.bootstrap.IFC2X3): def test_run(self): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcFlowController") type_element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcAirTerminalBoxType") - ifcopenshell.api.run("type.assign_type", self.file, related_object=element, relating_type=type_element) + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element], relating_type=type_element) assert subject.get_brick_type(element) == "https://brickschema.org/schema/Brick#TerminalUnit" diff --git a/src/ifcopenshell-python/test/util/test_classification.py b/src/ifcopenshell-python/test/util/test_classification.py index 58a5e47de2..d394f8056b 100644 --- a/src/ifcopenshell-python/test/util/test_classification.py +++ b/src/ifcopenshell-python/test/util/test_classification.py @@ -69,7 +69,7 @@ class TestGetReferences(test.bootstrap.IFC4): project = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcProject") element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") element_type = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") - ifcopenshell.api.run("type.assign_type", self.file, related_object=element, relating_type=element_type) + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element], relating_type=element_type) ifcopenshell.api.run("classification.add_classification", self.file, classification=classification) ifcopenshell.api.run( "classification.add_reference", @@ -98,7 +98,7 @@ class TestGetReferences(test.bootstrap.IFC4): project = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcProject") element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") element_type = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") - ifcopenshell.api.run("type.assign_type", self.file, related_object=element, relating_type=element_type) + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element], relating_type=element_type) ifcopenshell.api.run("classification.add_classification", self.file, classification=classification) ifcopenshell.api.run( "classification.add_reference", diff --git a/src/ifcopenshell-python/test/util/test_element.py b/src/ifcopenshell-python/test/util/test_element.py index ec5e686d60..1af3ac2434 100644 --- a/src/ifcopenshell-python/test/util/test_element.py +++ b/src/ifcopenshell-python/test/util/test_element.py @@ -55,7 +55,7 @@ class TestGetPsetIFC4(test.bootstrap.IFC4): def test_getting_inherited_psets(self): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") type_element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") - ifcopenshell.api.run("type.assign_type", self.file, related_object=element, relating_type=type_element) + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element], relating_type=type_element) pset = ifcopenshell.api.run("pset.add_pset", self.file, product=type_element, name="name") ifcopenshell.api.run("pset.edit_pset", self.file, pset=pset, properties={"a": 1, "x": 1}) pset = ifcopenshell.api.run("pset.add_pset", self.file, product=element, name="name") @@ -79,7 +79,7 @@ class TestGetPsetIFC4(test.bootstrap.IFC4): def test_excluding_inherited_psets(self): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") type_element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") - ifcopenshell.api.run("type.assign_type", self.file, related_object=element, relating_type=type_element) + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element], relating_type=type_element) pset = ifcopenshell.api.run("pset.add_pset", self.file, product=type_element, name="name") ifcopenshell.api.run("pset.edit_pset", self.file, pset=pset, properties={"a": 1, "x": 1}) pset = ifcopenshell.api.run("pset.add_pset", self.file, product=element, name="name") @@ -133,7 +133,7 @@ class TestGetPsetsIFC4(test.bootstrap.IFC4): def test_getting_inherited_psets(self): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") type_element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") - ifcopenshell.api.run("type.assign_type", self.file, related_object=element, relating_type=type_element) + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element], relating_type=type_element) pset = ifcopenshell.api.run("pset.add_pset", self.file, product=type_element, name="name") ifcopenshell.api.run("pset.edit_pset", self.file, pset=pset, properties={"a": 1, "x": 1}) pset = ifcopenshell.api.run("pset.add_pset", self.file, product=element, name="name") @@ -263,14 +263,14 @@ class TestGetPredefinedTypeIFC4(test.bootstrap.IFC4): def test_getting_an_inherited_predefined_type(self): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") element_type = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") - ifcopenshell.api.run("type.assign_type", self.file, related_object=element, relating_type=element_type) + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element], relating_type=element_type) element_type.PredefinedType = "PARTITIONING" assert subject.get_predefined_type(element) == "PARTITIONING" def test_getting_an_inherited_userdefined_type_for_an_element_type(self): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") element_type = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") - ifcopenshell.api.run("type.assign_type", self.file, related_object=element, relating_type=element_type) + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element], relating_type=element_type) element_type.PredefinedType = "USERDEFINED" element_type.ElementType = "FOOBAR" assert subject.get_predefined_type(element) == "FOOBAR" @@ -278,7 +278,7 @@ class TestGetPredefinedTypeIFC4(test.bootstrap.IFC4): def test_getting_an_overriden_predefined_type(self): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") element_type = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") - ifcopenshell.api.run("type.assign_type", self.file, related_object=element, relating_type=element_type) + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element], relating_type=element_type) element_type.PredefinedType = "NOTDEFINED" element.PredefinedType = "PARTITIONING" assert subject.get_predefined_type(element) == "PARTITIONING" @@ -286,7 +286,7 @@ class TestGetPredefinedTypeIFC4(test.bootstrap.IFC4): def test_getting_an_inherited_userdefined_type_for_a_process_type(self): element = ifcopenshell.api.run("sequence.add_task", self.file) element_type = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcTaskType") - ifcopenshell.api.run("type.assign_type", self.file, related_object=element, relating_type=element_type) + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element], relating_type=element_type) element_type.PredefinedType = "USERDEFINED" element_type.ProcessType = "FOOBAR" assert subject.get_predefined_type(element) == "FOOBAR" @@ -296,7 +296,7 @@ class TestGetTypeIFC4(test.bootstrap.IFC4): def test_getting_the_type_of_a_product(self): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") element_type = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") - ifcopenshell.api.run("type.assign_type", self.file, related_object=element, relating_type=element_type) + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element], relating_type=element_type) assert subject.get_type(element) == element_type assert subject.get_type(element_type) == element_type @@ -309,7 +309,7 @@ class TestGetTypes(test.bootstrap.IFC4): def test_getting_the_type_of_a_product(self): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") element_type = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") - ifcopenshell.api.run("type.assign_type", self.file, related_object=element, relating_type=element_type) + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element], relating_type=element_type) assert subject.get_types(element_type) == (element,) @@ -391,7 +391,7 @@ class TestGetMaterial(test.bootstrap.IFC4): def test_getting_an_inherited_material_from_the_elements_type(self): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") element_type = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") - ifcopenshell.api.run("type.assign_type", self.file, related_object=element, relating_type=element_type) + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element], relating_type=element_type) material = ifcopenshell.api.run("material.add_material", self.file) ifcopenshell.api.run("material.assign_material", self.file, product=element_type, material=material) assert subject.get_material(element) == material @@ -399,7 +399,7 @@ class TestGetMaterial(test.bootstrap.IFC4): def test_getting_an_overridden_material_from_the_elements_occurrence(self): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") element_type = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") - ifcopenshell.api.run("type.assign_type", self.file, related_object=element, relating_type=element_type) + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element], relating_type=element_type) material = ifcopenshell.api.run("material.add_material", self.file) ifcopenshell.api.run("material.assign_material", self.file, product=element_type, material=material) material = ifcopenshell.api.run("material.add_material", self.file) @@ -409,7 +409,7 @@ class TestGetMaterial(test.bootstrap.IFC4): def test_getting_direct_materials_without_checking_inheritance(self): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") element_type = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") - ifcopenshell.api.run("type.assign_type", self.file, related_object=element, relating_type=element_type) + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element], relating_type=element_type) material = ifcopenshell.api.run("material.add_material", self.file) ifcopenshell.api.run("material.assign_material", self.file, product=element_type, material=material) assert subject.get_material(element, should_inherit=False) is None @@ -493,7 +493,7 @@ class TestGetElementsByMaterial(test.bootstrap.IFC4): def test_getting_elements_of_a_material_layer_set(self): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") element_type = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") - ifcopenshell.api.run("type.assign_type", self.file, related_object=element, relating_type=element_type) + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element], relating_type=element_type) material = ifcopenshell.api.run("material.add_material", self.file) material_set = ifcopenshell.api.run("material.add_material_set", self.file, set_type="IfcMaterialLayerSet") ifcopenshell.api.run("material.add_layer", self.file, layer_set=material_set, material=material) @@ -507,7 +507,7 @@ class TestGetElementsByMaterial(test.bootstrap.IFC4): def test_getting_elements_of_a_material_profile_set(self): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") element_type = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") - ifcopenshell.api.run("type.assign_type", self.file, related_object=element, relating_type=element_type) + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element], relating_type=element_type) material = ifcopenshell.api.run("material.add_material", self.file) material_set = ifcopenshell.api.run("material.add_material_set", self.file, set_type="IfcMaterialProfileSet") ifcopenshell.api.run("material.add_profile", self.file, profile_set=material_set, material=material) diff --git a/src/ifcopenshell-python/test/util/test_selector.py b/src/ifcopenshell-python/test/util/test_selector.py index 703558969c..6565142429 100644 --- a/src/ifcopenshell-python/test/util/test_selector.py +++ b/src/ifcopenshell-python/test/util/test_selector.py @@ -168,7 +168,7 @@ class TestFilterElements(test.bootstrap.IFC4): def test_selecting_by_type(self): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") element_type = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") - ifcopenshell.api.run("type.assign_type", self.file, related_object=element, relating_type=element_type) + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element], relating_type=element_type) assert subject.filter_elements(self.file, "IfcWall, type=Foo") == set() element_type.Name = "Foo" assert subject.filter_elements(self.file, "IfcWall, type=Foo") == {element} @@ -465,10 +465,10 @@ class TestSelector(test.bootstrap.IFC4): def test_getting_occurrences_of_a_filtered_type(self): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") element_type = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") - ifcopenshell.api.run("type.assign_type", self.file, related_object=element, relating_type=element_type) + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element], relating_type=element_type) element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") element_type2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") - ifcopenshell.api.run("type.assign_type", self.file, related_object=element2, relating_type=element_type2) + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element2], relating_type=element_type2) assert set(subject.Selector.parse(self.file, "* .IfcWallType")) == {element, element2} def test_getting_decomposition_of_a_filtered_type(self): @@ -505,7 +505,7 @@ class TestSelector(test.bootstrap.IFC4): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") element_type = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") element_type.Name = "Foo" - ifcopenshell.api.run("type.assign_type", self.file, related_object=element, relating_type=element_type) + ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element], relating_type=element_type) assert set(subject.Selector.parse(self.file, '.IfcWall[type.Name="Foo"]')) == {element} def test_selecting_via_a_material(self): diff --git a/src/ifctester/test/ids_doc_generator.py b/src/ifctester/test/ids_doc_generator.py index 3290104cfa..2543daec23 100644 --- a/src/ifctester/test/ids_doc_generator.py +++ b/src/ifctester/test/ids_doc_generator.py @@ -328,7 +328,7 @@ wall_types = [] for i in range(0, 4): wall_type = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcWallType", name=f"DEMO{i + 1}") wall = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcWall", name=f"WALL {i + 1}") - ifcopenshell.api.run("type.assign_type", model, related_object=wall, relating_type=wall_type) + ifcopenshell.api.run("type.assign_type", model, related_objects=[wall], relating_type=wall_type) representation = ifcopenshell.api.run( "geometry.add_wall_representation", model, context=body, length=5, height=3, thickness=(i + 1) * 0.05 ) diff --git a/src/ifctester/test/test_facet.py b/src/ifctester/test/test_facet.py index 65c6cfc8d2..d34e9426f7 100644 --- a/src/ifctester/test/test_facet.py +++ b/src/ifctester/test/test_facet.py @@ -168,7 +168,7 @@ class TestEntity: ifc = ifcopenshell.file() wall = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall") wall_type = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWallType", predefined_type="X") - ifcopenshell.api.run("type.assign_type", ifc, related_object=wall, relating_type=wall_type) + ifcopenshell.api.run("type.assign_type", ifc, related_objects=[wall], relating_type=wall_type) facet = Entity(name="IFCWALL", predefinedType="X") run("Inherited predefined types should pass", facet=facet, inst=wall, expected=True) @@ -177,7 +177,7 @@ class TestEntity: wall_type = ifcopenshell.api.run( "root.create_entity", ifc, ifc_class="IfcWallType", predefined_type="NOTDEFINED" ) - ifcopenshell.api.run("type.assign_type", ifc, related_object=wall, relating_type=wall_type) + ifcopenshell.api.run("type.assign_type", ifc, related_objects=[wall], relating_type=wall_type) facet = Entity(name="IFCWALL", predefinedType="X") run("Overridden predefined types should pass", facet=facet, inst=wall, expected=True) @@ -637,7 +637,7 @@ class TestAttribute: ifc = ifcopenshell.file() wall = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall") wall_type = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWallType") - ifcopenshell.api.run("type.assign_type", ifc, related_object=wall, relating_type=wall_type) + ifcopenshell.api.run("type.assign_type", ifc, related_objects=[wall], relating_type=wall_type) wall_type.Description = "Foobar" facet = Attribute(name="Description", value="Foobar") run("Attributes are not inherited by the occurrence", facet=facet, inst=wall, expected=False) @@ -808,7 +808,7 @@ class TestClassification: # https://github.com/buildingSMART/IFC4.3.x-development/issues/475 wall = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall") wall_type = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWallType") - ifcopenshell.api.run("type.assign_type", ifc, related_object=wall, relating_type=wall_type) + ifcopenshell.api.run("type.assign_type", ifc, related_objects=[wall], relating_type=wall_type) ifcopenshell.api.run( "classification.add_reference", ifc, product=wall, reference=ref11, classification=system_a ) @@ -1209,7 +1209,7 @@ class TestProperty: ifc = self.setup_ifc() wall = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall") wall_type = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWallType") - ifcopenshell.api.run("type.assign_type", ifc, related_object=wall, relating_type=wall_type) + ifcopenshell.api.run("type.assign_type", ifc, related_objects=[wall], relating_type=wall_type) pset = ifcopenshell.api.run("pset.add_pset", ifc, product=wall_type, name="Foo_Bar") ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": "Bar"}) facet = Property(propertySet="Foo_Bar", baseName="Foo", dataType="IFCLABEL") @@ -1219,7 +1219,7 @@ class TestProperty: ifc = self.setup_ifc() wall = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall") wall_type = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWallType") - ifcopenshell.api.run("type.assign_type", ifc, related_object=wall, relating_type=wall_type) + ifcopenshell.api.run("type.assign_type", ifc, related_objects=[wall], relating_type=wall_type) pset = ifcopenshell.api.run("pset.add_pset", ifc, product=wall_type, name="Foo_Bar") ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": "Baz"}) pset = ifcopenshell.api.run("pset.add_pset", ifc, product=wall, name="Foo_Bar") @@ -1374,7 +1374,7 @@ class TestMaterial: ifc = ifcopenshell.file() element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall") element_type = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWallType") - ifcopenshell.api.run("type.assign_type", ifc, related_object=element, relating_type=element_type) + ifcopenshell.api.run("type.assign_type", ifc, related_objects=[element], relating_type=element_type) material = ifcopenshell.api.run("material.add_material", ifc) ifcopenshell.api.run("material.assign_material", ifc, product=element_type, material=material) material.Name = "Foo" @@ -1384,7 +1384,7 @@ class TestMaterial: ifc = ifcopenshell.file() element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall") element_type = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWallType") - ifcopenshell.api.run("type.assign_type", ifc, related_object=element, relating_type=element_type) + ifcopenshell.api.run("type.assign_type", ifc, related_objects=[element], relating_type=element_type) material = ifcopenshell.api.run("material.add_material", ifc) ifcopenshell.api.run("material.assign_material", ifc, product=element_type, material=material) material.Name = "Bar"