diff --git a/src/bonsai/bonsai/bim/module/root/operator.py b/src/bonsai/bonsai/bim/module/root/operator.py index 8373b38750..959082a72c 100644 --- a/src/bonsai/bonsai/bim/module/root/operator.py +++ b/src/bonsai/bonsai/bim/module/root/operator.py @@ -211,31 +211,23 @@ class AssignClass(bpy.types.Operator, tool.Ifc.Operator): ) continue - should_add_representation = self.should_add_representation - export_mesh_to_tesselation = False if self.should_add_representation and isinstance(obj.data, bpy.types.Mesh) and obj.data.polygons: - should_add_representation = False - export_mesh_to_tesselation = True - + bpy.ops.object.transform_apply(location=False, rotation=False, scale=True, properties=False) if tool.Geometry.mesh_has_loose_geometry(obj.data): self.report( {"WARNING"}, f"Mesh '{obj.data.name}' has loose geometry, loose geometry will be ignored to save mesh to IFC as a tessellation.", ) - element = core.assign_class( - tool.Ifc, - tool.Collector, - tool.Root, - obj=obj, - ifc_class=ifc_class, - predefined_type=predefined_type, - should_add_representation=should_add_representation, - context=ifc_context, - ifc_representation_class=self.ifc_representation_class, - ) - - if export_mesh_to_tesselation: + element = core.assign_class( + tool.Ifc, + tool.Collector, + tool.Root, + obj=obj, + ifc_class=ifc_class, + predefined_type=predefined_type, + should_add_representation=False, + ) representation = tool.Geometry.export_mesh_to_tessellation(obj, ifc_context) ifcopenshell.api.geometry.assign_representation(tool.Ifc.get(), element, representation) bonsai.core.geometry.switch_representation( @@ -247,6 +239,18 @@ class AssignClass(bpy.types.Operator, tool.Ifc.Operator): is_global=True, should_sync_changes_first=False, ) + else: + element = core.assign_class( + tool.Ifc, + tool.Collector, + tool.Root, + obj=obj, + ifc_class=ifc_class, + predefined_type=predefined_type, + should_add_representation=self.should_add_representation, + context=ifc_context, + ifc_representation_class=self.ifc_representation_class, + ) context.view_layer.objects.active = active_object @@ -412,7 +416,8 @@ class AddElement(bpy.types.Operator, tool.Ifc.Operator): if representation_template == "EMTPY" or not ifc_context: pass elif representation_template == "OBJ" and props.representation_obj: - obj.matrix_world = props.representation_obj.matrix_world + obj.matrix_world = props.representation_obj.matrix_world.copy() + obj.scale = (1, 1, 1) representation = tool.Geometry.export_mesh_to_tessellation(props.representation_obj, ifc_context) ifcopenshell.api.geometry.assign_representation(tool.Ifc.get(), element, representation) bonsai.core.geometry.switch_representation( diff --git a/src/bonsai/bonsai/core/tool.py b/src/bonsai/bonsai/core/tool.py index 1acae9d15d..7c5745d093 100644 --- a/src/bonsai/bonsai/core/tool.py +++ b/src/bonsai/bonsai/core/tool.py @@ -417,12 +417,10 @@ class Geometry: def get_total_representation_items(cls, obj): pass def has_data_users(cls, data): pass def has_material_style_override(cls, obj): pass - def import_representation(cls, obj, representation, apply_openings=True): pass def import_representation_parameters(cls, data): pass def is_body_representation(cls, representation): pass def is_box_representation(cls, representation): pass def is_data_supported_for_adding_representation(cls, data): pass - def is_edited(cls, obj): pass def is_mapped_representation(cls, representation): pass def is_type_product(cls, element): pass def link(cls, element, obj): pass diff --git a/src/bonsai/bonsai/tool/geometry.py b/src/bonsai/bonsai/tool/geometry.py index 8499638841..2dd51ac641 100644 --- a/src/bonsai/bonsai/tool/geometry.py +++ b/src/bonsai/bonsai/tool/geometry.py @@ -1842,6 +1842,7 @@ class Geometry(bonsai.core.tool.Geometry): tool.Blender.select_and_activate_single_object(bpy.context, dup_obj) + bpy.ops.object.transform_apply(location=False, rotation=False, scale=True, properties=False) bpy.ops.object.mode_set(mode="EDIT") bpy.ops.mesh.select_all(action="SELECT") bpy.ops.mesh.separate(type="LOOSE") diff --git a/src/bonsai/test/tool/test_geometry.py b/src/bonsai/test/tool/test_geometry.py index 93bb6f17f7..d36ccf59eb 100644 --- a/src/bonsai/test/tool/test_geometry.py +++ b/src/bonsai/test/tool/test_geometry.py @@ -174,21 +174,21 @@ class TestGetCartesianPointCoordinateOffset(NewFile): props = bpy.context.scene.BIMGeoreferenceProperties props.has_blender_offset = True obj.BIMObjectProperties.cartesian_point_offset = "1,2,3" - assert subject.get_cartesian_point_coordinate_offset(obj) == Vector((1.0, 2.0, 3.0)) + assert np.allclose(subject.get_cartesian_point_offset(obj), np.array((1., 2., 3.))) def test_get_null_if_not_a_cartesian_point_offset_type(self): obj = bpy.data.objects.new("Object", None) props = bpy.context.scene.BIMGeoreferenceProperties props.has_blender_offset = True obj.BIMObjectProperties.cartesian_point_offset = "1,2,3" - assert subject.get_cartesian_point_coordinate_offset(obj) is None + assert subject.get_cartesian_point_offset(obj) is None def test_get_null_if_no_blender_offset(self): obj = bpy.data.objects.new("Object", None) obj.BIMObjectProperties.blender_offset_type = "CARTESIAN_POINT" props = bpy.context.scene.BIMGeoreferenceProperties props.has_blender_offset = False - assert subject.get_cartesian_point_coordinate_offset(obj) is None + assert subject.get_cartesian_point_offset(obj) is None class TestGetElementType(NewFile): @@ -229,33 +229,6 @@ class TestHasDataUsers(NewFile): assert subject.has_data_users(data) is True -class TestImportRepresentation(NewFile): - def test_importing_a_normal_shape(self): - ifc = ifcopenshell.open("test/files/basic.ifc") - tool.Ifc.set(ifc) - obj = bpy.data.objects.new("Object", bpy.data.meshes.new("Mesh")) - material = bpy.data.materials.new("Material") - material.BIMStyleProperties.ifc_definition_id = 101 - element = ifc.by_type("IfcWall")[0] - tool.Ifc.link(element, obj) - representation = element.Representation.Representations[1] - mesh = subject.import_representation(obj, representation) - assert isinstance(mesh, bpy.types.Mesh) - assert len(mesh.polygons) == 12 - assert mesh.materials[0] == material - - def test_importing_non_body_curves(self): - ifc = ifcopenshell.open("test/files/annotation.ifc") - tool.Ifc.set(ifc) - obj = bpy.data.objects.new("Object", bpy.data.meshes.new("Mesh")) - element = ifc.by_type("IfcWall")[0] - tool.Ifc.link(element, obj) - representation = element.Representation.Representations[0] - mesh = subject.import_representation(obj, representation) - assert len(mesh.polygons) == 0 - assert len(mesh.edges) == 4 - - class TestImportRepresentationParameters(NewFile): def test_run(self): ifc = ifcopenshell.file() diff --git a/src/bonsai/test/tool/test_system.py b/src/bonsai/test/tool/test_system.py index 4123376fa2..1f676ba320 100644 --- a/src/bonsai/test/tool/test_system.py +++ b/src/bonsai/test/tool/test_system.py @@ -52,7 +52,7 @@ class TestAddPorts(NewFile): for port, expected_matrix in zip(ports, expected_matrices, strict=True): port_matrix = tool.Model.get_element_matrix(port) port_matrix.translation *= si_conversion - assert np.allclose(port_matrix, expected_matrix, atol=1.0e-5) + assert np.allclose(port_matrix, expected_matrix, atol=1.0e-5), f"Matrix does not match:\n{port_matrix}\n{expected_matrix}" def test_run(self): # default use diff --git a/src/bonsai/test/tool/test_unit.py b/src/bonsai/test/tool/test_unit.py index bd508ce074..4a8512c360 100644 --- a/src/bonsai/test/tool/test_unit.py +++ b/src/bonsai/test/tool/test_unit.py @@ -237,7 +237,7 @@ class TestImportUnitAttributes(NewFile): class TestImportUnits(NewFile): def test_importing_multiple_units(self): - ifc = ifcopenshell.file() + ifc = ifcopenshell.api.project.create_file() tool.Ifc.set(ifc) unit1 = ifc.createIfcDerivedUnit(UnitType="ANGULARVELOCITYUNIT") unit2 = ifc.createIfcMonetaryUnit(Currency="Currency") @@ -245,7 +245,8 @@ class TestImportUnits(NewFile): unit4 = ifc.createIfcConversionBasedUnit(Name="Name", UnitType="ABSORBEDDOSEUNIT") unit5 = ifc.createIfcSIUnit(Name="AMPERE", Prefix="MILLI", UnitType="ABSORBEDDOSEUNIT") unit6 = ifc.createIfcSIUnit(Name="CUBIC_METRE", Prefix="CENTI", UnitType="ABSORBEDDOSEUNIT") - ifc.createIfcUnitAssignment(Units=[unit2]) + ifcopenshell.api.root.create_entity(ifc, ifc_class="IfcProject") + ifcopenshell.api.unit.assign_unit(ifc, units=[unit2]) subject.import_units() props = bpy.context.scene.BIMUnitProperties assert len(props.units) == 6