diff --git a/src/blenderbim/blenderbim/bim/module/model/product.py b/src/blenderbim/blenderbim/bim/module/model/product.py index 6504201fbb..519fce60d6 100644 --- a/src/blenderbim/blenderbim/bim/module/model/product.py +++ b/src/blenderbim/blenderbim/bim/module/model/product.py @@ -23,6 +23,7 @@ import ifcopenshell.api import ifcopenshell.util.element import ifcopenshell.util.representation import blenderbim.tool as tool +import blenderbim.core.type import blenderbim.core.geometry from . import wall, slab, profile from blenderbim.bim.ifc import IfcStore @@ -119,7 +120,13 @@ class AddTypeInstance(bpy.types.Operator): collection.objects.link(obj) collection_obj = bpy.data.objects.get(collection.name) bpy.ops.bim.assign_class(obj=obj.name, ifc_class=instance_class) - bpy.ops.bim.assign_type(relating_type=int(tprops.relating_type), related_object=obj.name) + blenderbim.core.type.assign_type( + tool.Ifc, + tool.Geometry, + tool.Type, + element=tool.Ifc.get_entity(obj), + type=tool.Ifc.get().by_id(int(tprops.relating_type)), + ) if building_obj: if instance_class in ["IfcWindow", "IfcDoor"]: diff --git a/src/blenderbim/blenderbim/bim/module/model/profile.py b/src/blenderbim/blenderbim/bim/module/model/profile.py index c1d513e21b..a81a15174e 100644 --- a/src/blenderbim/blenderbim/bim/module/model/profile.py +++ b/src/blenderbim/blenderbim/bim/module/model/profile.py @@ -26,6 +26,7 @@ import ifcopenshell.util.element import mathutils.geometry import blenderbim.bim.handler import blenderbim.tool as tool +import blenderbim.core.type import blenderbim.core.geometry from blenderbim.bim.ifc import IfcStore from math import pi, degrees, inf @@ -169,7 +170,9 @@ class DumbProfileGenerator: obj.rotation_euler[2] = math.pi / 2 element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id) - bpy.ops.bim.assign_type(relating_type=self.relating_type.id(), related_object=obj.name) + blenderbim.core.type.assign_type( + tool.Ifc, tool.Geometry, tool.Type, element=tool.Ifc.get_entity(obj), type=self.relating_type + ) profile_set_usage = ifcopenshell.util.element.get_material(element) blenderbim.core.geometry.add_representation( tool.Ifc, diff --git a/src/blenderbim/blenderbim/bim/module/model/slab.py b/src/blenderbim/blenderbim/bim/module/model/slab.py index c9847d1a21..94b58b09a0 100644 --- a/src/blenderbim/blenderbim/bim/module/model/slab.py +++ b/src/blenderbim/blenderbim/bim/module/model/slab.py @@ -25,6 +25,8 @@ import ifcopenshell.util.unit import ifcopenshell.util.element import mathutils.geometry import blenderbim.bim.handler +import blenderbim.core.type +import blenderbim.tool as tool from blenderbim.bim.ifc import IfcStore from math import pi, degrees from mathutils import Vector, Matrix @@ -305,7 +307,9 @@ class DumbSlabGenerator: ifc_class=ifc_class, ifc_representation_class="IfcExtrudedAreaSolid/IfcArbitraryProfileDefWithVoids", ) - bpy.ops.bim.assign_type(relating_type=self.relating_type.id(), related_object=obj.name) + blenderbim.core.type.assign_type( + tool.Ifc, tool.Geometry, tool.Type, element=tool.Ifc.get_entity(obj), type=self.relating_type + ) element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id) pset = ifcopenshell.api.run("pset.add_pset", self.file, product=element, name="EPset_Parametric") ifcopenshell.api.run("pset.edit_pset", self.file, pset=pset, properties={"Engine": "BlenderBIM.DumbLayer3"}) diff --git a/src/blenderbim/blenderbim/bim/module/model/wall.py b/src/blenderbim/blenderbim/bim/module/model/wall.py index 9e3dc5c82d..d3185b680e 100644 --- a/src/blenderbim/blenderbim/bim/module/model/wall.py +++ b/src/blenderbim/blenderbim/bim/module/model/wall.py @@ -26,6 +26,8 @@ import ifcopenshell.util.element import ifcopenshell.util.representation import mathutils.geometry import blenderbim.bim.handler +import blenderbim.core.type +import blenderbim.tool as tool from blenderbim.bim.ifc import IfcStore from ifcopenshell.api.pset.data import Data as PsetData from ifcopenshell.api.material.data import Data as MaterialData @@ -792,7 +794,9 @@ class DumbWallGenerator: ifc_representation_class="IfcExtrudedAreaSolid/IfcArbitraryClosedProfileDef", ) - bpy.ops.bim.assign_type(relating_type=self.relating_type.id(), related_object=obj.name) + blenderbim.core.type.assign_type( + tool.Ifc, tool.Geometry, tool.Type, element=tool.Ifc.get_entity(obj), type=self.relating_type + ) element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id) pset = ifcopenshell.api.run("pset.add_pset", self.file, product=element, name="EPset_Parametric") ifcopenshell.api.run("pset.edit_pset", self.file, pset=pset, properties={"Engine": "BlenderBIM.DumbLayer2"}) diff --git a/src/blenderbim/blenderbim/bim/module/root/operator.py b/src/blenderbim/blenderbim/bim/module/root/operator.py index 95ad3c6bcf..252369dcc6 100644 --- a/src/blenderbim/blenderbim/bim/module/root/operator.py +++ b/src/blenderbim/blenderbim/bim/module/root/operator.py @@ -22,10 +22,11 @@ import ifcopenshell.api import ifcopenshell.util.schema import ifcopenshell.util.element import blenderbim.bim.handler -import blenderbim.core.spatial -import blenderbim.core.style import blenderbim.core.geometry import blenderbim.core.material +import blenderbim.core.spatial +import blenderbim.core.style +import blenderbim.core.type import blenderbim.tool as tool from ifcopenshell.api.void.data import Data as VoidData from blenderbim.bim.ifc import IfcStore @@ -360,7 +361,7 @@ class CopyClass(bpy.types.Operator): IfcStore.link_element(result, obj) relating_type = ifcopenshell.util.element.get_type(result) if relating_type and relating_type.RepresentationMaps: - bpy.ops.bim.assign_type(relating_type=relating_type.id(), related_object=obj.name) + blenderbim.core.type.assign_type(tool.Ifc, tool.Geometry, tool.Type, element=result, type=relating_type) else: blenderbim.core.geometry.add_representation( tool.Ifc, diff --git a/src/blenderbim/blenderbim/bim/module/type/operator.py b/src/blenderbim/blenderbim/bim/module/type/operator.py index 7fe9d35817..a2986d248a 100644 --- a/src/blenderbim/blenderbim/bim/module/type/operator.py +++ b/src/blenderbim/blenderbim/bim/module/type/operator.py @@ -22,72 +22,41 @@ import ifcopenshell.util.type import ifcopenshell.api import blenderbim.tool as tool import blenderbim.core.geometry +import blenderbim.core.type as core from blenderbim.bim.ifc import IfcStore from ifcopenshell.api.type.data import Data from ifcopenshell.api.geometry.data import Data as GeometryData from ifcopenshell.api.material.data import Data as MaterialData -class AssignType(bpy.types.Operator): +class Operator: + def execute(self, context): + IfcStore.execute_ifc_operator(self, context) + blenderbim.bim.handler.refresh_ui_data() + return {"FINISHED"} + + +class AssignType(bpy.types.Operator, Operator): bl_idname = "bim.assign_type" bl_label = "Assign Type" bl_options = {"REGISTER", "UNDO"} relating_type: bpy.props.IntProperty() related_object: bpy.props.StringProperty() - def execute(self, context): - return IfcStore.execute_ifc_operator(self, context) - def _execute(self, context): - self.file = IfcStore.get_file() - relating_type = self.relating_type or int(context.active_object.BIMTypeProperties.relating_type) + type = tool.Ifc.get().by_id(self.relating_type or int(context.active_object.BIMTypeProperties.relating_type)) related_objects = ( [bpy.data.objects.get(self.related_object)] if self.related_object else context.selected_objects or [context.active_object] ) - for related_object in related_objects: - oprops = related_object.BIMObjectProperties - ifcopenshell.api.run( - "type.assign_type", - self.file, - **{ - "related_object": self.file.by_id(oprops.ifc_definition_id), - "relating_type": self.file.by_id(relating_type), - }, - ) + for obj in related_objects: + core.assign_type(tool.Ifc, tool.Geometry, tool.Type, element=tool.Ifc.get_entity(obj), type=type) + oprops = obj.BIMObjectProperties Data.load(IfcStore.get_file(), oprops.ifc_definition_id) GeometryData.load(IfcStore.get_file(), oprops.ifc_definition_id) MaterialData.load(IfcStore.get_file(), oprops.ifc_definition_id) - representation_ids = GeometryData.products[oprops.ifc_definition_id] - if not representation_ids: - pass # TODO: clear geometry? Make void? Make none type? - has_switched = False - for representation_id in representation_ids: - representation = GeometryData.representations[representation_id] - if representation["ContextOfItems"]["ContextIdentifier"] == "Body": - blenderbim.core.geometry.switch_representation( - tool.Geometry, - obj=related_object, - representation=tool.Ifc.get().by_id(representation_id), - should_reload=False, - enable_dynamic_voids=False, - is_global=False, - ) - has_switched = True - if not has_switched and representation_ids: - blenderbim.core.geometry.switch_representation( - tool.Geometry, - obj=related_object, - representation=tool.Ifc.get().by_id(representation_id), - should_reload=False, - enable_dynamic_voids=False, - is_global=False, - ) - - bpy.ops.bim.disable_editing_type(obj=related_object.name) - MaterialData.load(self.file) - return {"FINISHED"} + MaterialData.load(IfcStore.get_file()) class UnassignType(bpy.types.Operator): diff --git a/src/blenderbim/blenderbim/core/tool.py b/src/blenderbim/blenderbim/core/tool.py index 49f8605377..09d753e976 100644 --- a/src/blenderbim/blenderbim/core/tool.py +++ b/src/blenderbim/blenderbim/core/tool.py @@ -90,6 +90,7 @@ class Geometry: class Ifc: def get(cls): pass def get_entity(cls, obj): pass + def get_object(cls, obj): pass def link(cls, element, obj): pass def run(cls, command, **kwargs): pass def unlink(cls, element=None, obj=None): pass @@ -169,6 +170,14 @@ class Surveyor: def get_absolute_matrix(cls, obj): pass +@interface +class Type: + def disable_editing(cls, obj): pass + def get_any_representation(cls, element): pass + def get_body_representation(cls, element): pass + def has_dynamic_voids(cls, obj): pass + + @interface class Unit: def clear_active_unit(cls): pass diff --git a/src/blenderbim/blenderbim/core/type.py b/src/blenderbim/blenderbim/core/type.py new file mode 100644 index 0000000000..7d88898d87 --- /dev/null +++ b/src/blenderbim/blenderbim/core/type.py @@ -0,0 +1,37 @@ +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + +import blenderbim.core.geometry + + +def assign_type(ifc, geometry, type_tool, element=None, type=None): + ifc.run("type.assign_type", related_object=element, relating_type=type) + representation = type_tool.get_body_representation(element) + if not representation: + representation = type_tool.get_any_representation(element) + obj = ifc.get_object(element) + if representation: + blenderbim.core.geometry.switch_representation( + geometry, + obj=obj, + representation=representation, + should_reload=False, + enable_dynamic_voids=type_tool.has_dynamic_voids(obj), + is_global=False, + ) + type_tool.disable_editing(obj) diff --git a/src/blenderbim/blenderbim/tool/__init__.py b/src/blenderbim/blenderbim/tool/__init__.py index 094198a394..0b40a66c56 100644 --- a/src/blenderbim/blenderbim/tool/__init__.py +++ b/src/blenderbim/blenderbim/tool/__init__.py @@ -28,4 +28,5 @@ from blenderbim.tool.misc import Misc from blenderbim.tool.owner import Owner from blenderbim.tool.style import Style from blenderbim.tool.surveyor import Surveyor +from blenderbim.tool.type import Type from blenderbim.tool.unit import Unit diff --git a/src/blenderbim/blenderbim/tool/type.py b/src/blenderbim/blenderbim/tool/type.py new file mode 100644 index 0000000000..d2bddd3486 --- /dev/null +++ b/src/blenderbim/blenderbim/tool/type.py @@ -0,0 +1,53 @@ +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + +import ifcopenshell +import blenderbim.core.tool +import blenderbim.tool as tool +import blenderbim.bim.helper + + +class Type(blenderbim.core.tool.Type): + @classmethod + def disable_editing(cls, obj): + obj.BIMTypeProperties.is_editing_type = False + + @classmethod + def get_any_representation(cls, element): + if element.is_a("IfcProduct") and element.Representation and element.Representation.Representations: + return element.Representation.Representations[0] + elif element.is_a("IfcTypeProduct") and element.RepresentationMaps: + return element.RepresentationMaps[0].MappedRepresentation + + @classmethod + def get_body_representation(cls, element): + if element.is_a("IfcProduct") and element.Representation and element.Representation.Representations: + for representation in element.Representation.Representations: + if representation.ContextOfItems.ContextIdentifier == "Body": + return representation + elif element.is_a("IfcTypeProduct") and element.RepresentationMaps: + for representation_map in element.RepresentationMaps: + if representation_map.MappedRepresentation.ContextOfItems.ContextIdentifier == "Body": + return representation_map.MappedRepresentation + + @classmethod + def has_dynamic_voids(cls, obj): + for modifier in obj.modifiers: + if modifier.name == "IfcOpeningElement" and modifier.type == "BOOLEAN": + return True + return False diff --git a/src/blenderbim/pytest.ini b/src/blenderbim/pytest.ini index d250114cb2..43af31a44d 100644 --- a/src/blenderbim/pytest.ini +++ b/src/blenderbim/pytest.ini @@ -11,5 +11,6 @@ markers = root spatial style + type unit void diff --git a/src/blenderbim/test/bim/feature/type.feature b/src/blenderbim/test/bim/feature/type.feature new file mode 100644 index 0000000000..0e60f58801 --- /dev/null +++ b/src/blenderbim/test/bim/feature/type.feature @@ -0,0 +1,17 @@ +@type +Feature: Type + +Scenario: Assign type + Given an empty IFC project + And I add a cube + And the object "Cube" is selected + And I set "scene.BIMRootProperties.ifc_class" to "IfcWall" + And I press "bim.assign_class" + And I add an empty + And the object "Empty" is selected + And I set "scene.BIMRootProperties.ifc_product" to "IfcElementType" + And I set "scene.BIMRootProperties.ifc_class" to "IfcWallType" + And I press "bim.assign_class" + When the variable "type" is "{ifc}.by_type('IfcWallType')[0].id()" + And I press "bim.assign_type(relating_type={type}, related_object="IfcWall/Cube")" + Then nothing happens diff --git a/src/blenderbim/test/core/bootstrap.py b/src/blenderbim/test/core/bootstrap.py index e392ad89e5..d1a36ddf36 100644 --- a/src/blenderbim/test/core/bootstrap.py +++ b/src/blenderbim/test/core/bootstrap.py @@ -77,6 +77,13 @@ def owner(): prophet.verify() +@pytest.fixture +def type(): + prophet = Prophecy(blenderbim.core.tool.Type) + yield prophet + prophet.verify() + + @pytest.fixture def voider(): prophet = Prophecy(blenderbim.core.tool.Voider) diff --git a/src/blenderbim/test/core/test_geometry.py b/src/blenderbim/test/core/test_geometry.py index 40189ec2e2..01652a46b3 100644 --- a/src/blenderbim/test/core/test_geometry.py +++ b/src/blenderbim/test/core/test_geometry.py @@ -179,7 +179,7 @@ class TestAddRepresentation: class TestSwitchRepresentation: - def test_run(self, ifc, geometry, style, surveyor): + def test_switching_to_a_freshly_reloaded_representation(self, geometry): geometry.resolve_mapped_representation("mapped_rep").should_be_called().will_return("representation") geometry.get_representation_data("representation").should_be_called().will_return("data") geometry.import_representation( @@ -199,3 +199,32 @@ class TestSwitchRepresentation: enable_dynamic_voids=True, is_global=True, ) + + def test_switching_to_an_existing_representation(self, geometry): + geometry.resolve_mapped_representation("mapped_rep").should_be_called().will_return("representation") + geometry.get_representation_data("representation").should_be_called().will_return("data") + geometry.change_object_data("obj", "data", is_global=True).should_be_called() + geometry.is_body_representation("representation").should_be_called().will_return(True) + geometry.create_dynamic_voids("obj").should_be_called() + subject.switch_representation( + geometry, + obj="obj", + representation="mapped_rep", + should_reload=False, + enable_dynamic_voids=True, + is_global=True, + ) + + def test_switching_to_non_dynamic_baked_voids(self, geometry): + geometry.resolve_mapped_representation("mapped_rep").should_be_called().will_return("representation") + geometry.get_representation_data("representation").should_be_called().will_return("data") + geometry.change_object_data("obj", "data", is_global=False).should_be_called() + geometry.clear_dynamic_voids("obj").should_be_called() + subject.switch_representation( + geometry, + obj="obj", + representation="mapped_rep", + should_reload=False, + enable_dynamic_voids=False, + is_global=False, + ) diff --git a/src/blenderbim/test/core/test_type.py b/src/blenderbim/test/core/test_type.py new file mode 100644 index 0000000000..79bce1b781 --- /dev/null +++ b/src/blenderbim/test/core/test_type.py @@ -0,0 +1,61 @@ +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + +import blenderbim.core.type as subject +from test.core.bootstrap import ifc, geometry, type + + +class TestAssignType: + def test_assigning_and_switching_preferably_to_a_body_representation(self, ifc, geometry, type): + ifc.run("type.assign_type", related_object="element", relating_type="type").should_be_called() + type.get_body_representation("element").should_be_called().will_return("mapped_rep") + ifc.get_object("element").should_be_called().will_return("obj") + type.has_dynamic_voids("obj").should_be_called().will_return(False) + + geometry.resolve_mapped_representation("mapped_rep").should_be_called().will_return("representation") + geometry.get_representation_data("representation").should_be_called().will_return("data") + geometry.change_object_data("obj", "data", is_global=False).should_be_called() + geometry.clear_dynamic_voids("obj").should_be_called() + + type.disable_editing("obj").should_be_called() + + subject.assign_type(ifc, geometry, type, element="element", type="type") + + def test_assigning_and_switching_to_any_representation_as_a_fallback(self, ifc, geometry, type): + ifc.run("type.assign_type", related_object="element", relating_type="type").should_be_called() + type.get_body_representation("element").should_be_called().will_return(None) + type.get_any_representation("element").should_be_called().will_return("mapped_rep") + ifc.get_object("element").should_be_called().will_return("obj") + type.has_dynamic_voids("obj").should_be_called().will_return(False) + + geometry.resolve_mapped_representation("mapped_rep").should_be_called().will_return("representation") + geometry.get_representation_data("representation").should_be_called().will_return("data") + geometry.change_object_data("obj", "data", is_global=False).should_be_called() + geometry.clear_dynamic_voids("obj").should_be_called() + + type.disable_editing("obj").should_be_called() + + subject.assign_type(ifc, geometry, type, element="element", type="type") + + def test_assigning_and_not_changing_representation_if_not_available(self, ifc, type): + ifc.run("type.assign_type", related_object="element", relating_type="type").should_be_called() + type.get_body_representation("element").should_be_called().will_return(None) + type.get_any_representation("element").should_be_called().will_return(None) + ifc.get_object("element").should_be_called().will_return("obj") + type.disable_editing("obj").should_be_called() + subject.assign_type(ifc, geometry, type, element="element", type="type") diff --git a/src/blenderbim/test/tool/test_type.py b/src/blenderbim/test/tool/test_type.py new file mode 100644 index 0000000000..7aeffd4f8c --- /dev/null +++ b/src/blenderbim/test/tool/test_type.py @@ -0,0 +1,89 @@ +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2021 Dion Moult +# +# This file is part of BlenderBIM Add-on. +# +# BlenderBIM Add-on is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BlenderBIM Add-on 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BlenderBIM Add-on. If not, see . + +import bpy +import ifcopenshell +import blenderbim.core.tool +import blenderbim.tool as tool +from test.bim.bootstrap import NewFile +from blenderbim.tool.type import Type as subject + + +class TestImplementsTool(NewFile): + def test_run(self): + assert isinstance(subject(), blenderbim.core.tool.Type) + + +class TestDisableEditing(NewFile): + def test_run(self): + obj = bpy.data.objects.new("Object", None) + obj.BIMTypeProperties.is_editing_type = True + subject.disable_editing(obj) + assert obj.BIMTypeProperties.is_editing_type is False + + +class TestGetAnyRepresentation(NewFile): + def test_get_product_representation(self): + ifc = ifcopenshell.file() + representation = ifc.createIfcShapeRepresentation() + element = ifc.createIfcWall(Representation=ifc.createIfcProductRepresentation(Representations=[representation])) + assert subject.get_any_representation(element) == representation + + def test_get_type_product_representation(self): + ifc = ifcopenshell.file() + representation = ifc.createIfcShapeRepresentation() + element = ifc.createIfcWallType( + RepresentationMaps=[ifc.createIfcRepresentationMap(MappedRepresentation=representation)] + ) + assert subject.get_any_representation(element) == representation + + +class TestGetBodyRepresentation(NewFile): + def test_get_product_representation(self): + ifc = ifcopenshell.file() + rep = ifc.createIfcShapeRepresentation(ContextOfItems=ifc.createIfcGeometricRepresentationSubContext()) + body_rep = ifc.createIfcShapeRepresentation( + ContextOfItems=ifc.createIfcGeometricRepresentationSubContext(ContextIdentifier="Body") + ) + element = ifc.createIfcWall(Representation=ifc.createIfcProductRepresentation(Representations=[rep, body_rep])) + assert subject.get_body_representation(element) == body_rep + + def test_get_type_product_representation(self): + ifc = ifcopenshell.file() + rep = ifc.createIfcShapeRepresentation(ContextOfItems=ifc.createIfcGeometricRepresentationSubContext()) + body_rep = ifc.createIfcShapeRepresentation( + ContextOfItems=ifc.createIfcGeometricRepresentationSubContext(ContextIdentifier="Body") + ) + element = ifc.createIfcWallType( + RepresentationMaps=[ + ifc.createIfcRepresentationMap(MappedRepresentation=rep), + ifc.createIfcRepresentationMap(MappedRepresentation=body_rep), + ] + ) + assert subject.get_body_representation(element) == body_rep + + +class TestHasDynamicVoids(NewFile): + def test_run(self): + obj = bpy.data.objects.new("Object", None) + assert subject.has_dynamic_voids(obj) is False + + def test_checking_modifiers(self): + obj = bpy.data.objects.new("Object", bpy.data.meshes.new("Mesh")) + obj.modifiers.new("IfcOpeningElement", "BOOLEAN") + assert subject.has_dynamic_voids(obj) is True