diff --git a/src/blenderbim/blenderbim/bim/import_ifc.py b/src/blenderbim/blenderbim/bim/import_ifc.py index 90018d3f79..f857df0486 100644 --- a/src/blenderbim/blenderbim/bim/import_ifc.py +++ b/src/blenderbim/blenderbim/bim/import_ifc.py @@ -32,7 +32,7 @@ import ifcopenshell.util.element import ifcopenshell.util.selector import ifcopenshell.util.geolocation from blenderbim.bim.ifc import IfcStore -from blenderbim.bim.module.drawing.prop import getDiagramScales +from blenderbim.bim.module.drawing.prop import get_diagram_scales class FileCopy(threading.Thread): @@ -241,9 +241,7 @@ class IfcImporter: elif self.ifc_import_settings.should_merge_by_material: self.merge_by_material() self.profile_code("Merging by material") - if self.ifc_import_settings.should_merge_materials_by_colour or ( - self.ifc_import_settings.should_auto_set_workarounds and len(self.material_creator.materials) > 300 - ): + if self.ifc_import_settings.should_merge_materials_by_colour or len(self.material_creator.materials) > 300: self.merge_materials_by_colour() self.profile_code("Merging by colour") self.add_project_to_scene() @@ -1314,7 +1312,7 @@ class IfcImporter: if "TargetView" in pset: camera.BIMCameraProperties.target_view = pset["TargetView"] if "Scale" in pset: - valid_scales = [i[0] for i in getDiagramScales(None, None) if pset["Scale"] == i[0].split("|")[-1]] + valid_scales = [i[0] for i in get_diagram_scales(None, bpy.context) if pset["Scale"] == i[0].split("|")[-1]] if valid_scales: camera.BIMCameraProperties.diagram_scale = valid_scales[0] else: @@ -1436,7 +1434,6 @@ class IfcImportSettings: self.logger = None self.input_file = None self.diff_file = None - self.should_auto_set_workarounds = True self.should_use_cpu_multiprocessing = True self.should_merge_by_class = False self.should_merge_by_material = False diff --git a/src/blenderbim/blenderbim/bim/module/drawing/prop.py b/src/blenderbim/blenderbim/bim/module/drawing/prop.py index 5a07c570a1..f87e4e6ee1 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/prop.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/prop.py @@ -53,7 +53,7 @@ def purge(): vector_styles_enum = [] -def getDiagramScales(self, context): +def get_diagram_scales(self, context): global diagram_scales_enum if ( len(diagram_scales_enum) < 1 @@ -294,7 +294,7 @@ class BIMCameraProperties(PropertyGroup): name="Target View", default="PLAN_VIEW", ) - diagram_scale: EnumProperty(items=getDiagramScales, name="Drawing Scale") + diagram_scale: EnumProperty(items=get_diagram_scales, name="Drawing Scale") custom_diagram_scale: StringProperty(name="Custom Scale") raster_x: IntProperty(name="Raster X", default=1000) raster_y: IntProperty(name="Raster Y", default=1000) diff --git a/src/blenderbim/blenderbim/bim/module/project/operator.py b/src/blenderbim/blenderbim/bim/module/project/operator.py index 12fdfb2ff3..f08226a7a6 100644 --- a/src/blenderbim/blenderbim/bim/module/project/operator.py +++ b/src/blenderbim/blenderbim/bim/module/project/operator.py @@ -23,6 +23,7 @@ import logging import tempfile import ifcopenshell import ifcopenshell.api +import ifcopenshell.util.selector import ifcopenshell.util.representation import blenderbim.bim.handler from blenderbim.bim.ifc import IfcStore @@ -512,12 +513,15 @@ class LoadProject(bpy.types.Operator): bl_options = {"REGISTER", "UNDO"} filepath: bpy.props.StringProperty(subtype="FILE_PATH") filter_glob: bpy.props.StringProperty(default="*.ifc;*.ifczip;*.ifcxml", options={"HIDDEN"}) + is_advanced: bpy.props.BoolProperty(name="Enable Advanced Mode", default=False) def execute(self, context): if not os.path.exists(self.filepath) or "ifc" not in os.path.splitext(self.filepath)[1].lower(): return {"FINISHED"} context.scene.BIMProperties.ifc_file = self.filepath context.scene.BIMProjectProperties.is_loading = True + if not self.is_advanced: + bpy.ops.bim.load_project_elements() return {"FINISHED"} def invoke(self, context, event): @@ -561,6 +565,23 @@ class LoadProjectElements(bpy.types.Operator): settings.elements = self.get_decomposition_elements() elif self.props.filter_mode == "IFC_CLASS": settings.elements = self.get_ifc_class_elements() + elif self.props.filter_mode == "WHITELIST": + settings.elements = self.get_whitelist_elements() + elif self.props.filter_mode == "BLACKLIST": + settings.elements = self.get_blacklist_elements() + settings.should_use_cpu_multiprocessing = self.props.should_use_cpu_multiprocessing + settings.should_merge_by_class = self.props.should_merge_by_class + settings.should_merge_by_material = self.props.should_merge_by_material + settings.should_merge_materials_by_colour = self.props.should_merge_materials_by_colour + settings.should_clean_mesh = self.props.should_clean_mesh + settings.deflection_tolerance = self.props.deflection_tolerance + settings.angular_tolerance = self.props.angular_tolerance + settings.should_offset_model = self.props.should_offset_model + settings.model_offset_coordinates = ( + [float(o) for o in self.props.model_offset_coordinates.split(",")] + if self.props.model_offset_coordinates + else (0, 0, 0) + ) settings.logger.info("Starting import") ifc_importer = import_ifc.IfcImporter(settings) ifc_importer.execute() @@ -604,3 +625,11 @@ class LoadProjectElements(bpy.types.Operator): continue elements.update(self.file.by_type(filter_category.name, include_subtypes=False)) return elements + + def get_whitelist_elements(self): + selector = ifcopenshell.util.selector.Selector() + return set(selector.parse(self.file, self.props.filter_query)) + + def get_blacklist_elements(self): + selector = ifcopenshell.util.selector.Selector() + return set(self.file.by_type("IfcElement")) - set(selector.parse(self.file, self.props.filter_query)) diff --git a/src/blenderbim/blenderbim/bim/module/project/prop.py b/src/blenderbim/blenderbim/bim/module/project/prop.py index 6acb2ce4f4..476e180250 100644 --- a/src/blenderbim/blenderbim/bim/module/project/prop.py +++ b/src/blenderbim/blenderbim/bim/module/project/prop.py @@ -23,6 +23,7 @@ from bpy.types import PropertyGroup from bpy.props import ( StringProperty, BoolProperty, + FloatProperty, IntProperty, CollectionProperty, ) @@ -92,12 +93,24 @@ class BIMProjectProperties(PropertyGroup): ("NONE", "None", "No filtering is performed"), ("DECOMPOSITION", "Decomposition", "Filter objects by decomposition"), ("IFC_CLASS", "IFC Class", "Filter objects by class"), + ("WHITELIST", "Whitelist", "Filter objects using a custom whitelist query"), + ("BLACKLIST", "Blacklist", "Filter objects using a custom blacklist query"), ], name="Filter Mode", update=update_filter_mode ) filter_categories: CollectionProperty(name="Filter Categories", type=FilterCategory) active_filter_category_index: IntProperty(name="Active Filter Category Index") + filter_query: StringProperty(name="Filter Query") + should_use_cpu_multiprocessing: BoolProperty(name="Import with CPU Multiprocessing", default=True) + should_merge_by_class: BoolProperty(name="Import and Merge by Class", default=False) + should_merge_by_material: BoolProperty(name="Import and Merge by Material", default=False) + should_merge_materials_by_colour: BoolProperty(name="Import and Merge Materials by Colour", default=False) + should_clean_mesh: BoolProperty(name="Import and Clean Mesh", default=True) + deflection_tolerance: FloatProperty(name="Import Deflection Tolerance", default=0.001) + angular_tolerance: FloatProperty(name="Import Angular Tolerance", default=0.5) + should_offset_model: BoolProperty(name="Import and Offset Model", default=False) + model_offset_coordinates: StringProperty(name="Model Offset Coordinates", default="0,0,0") def get_library_element_index(self, lib_element): diff --git a/src/blenderbim/blenderbim/bim/module/project/ui.py b/src/blenderbim/blenderbim/bim/module/project/ui.py index 4bb0105c83..bf204cb4ba 100644 --- a/src/blenderbim/blenderbim/bim/module/project/ui.py +++ b/src/blenderbim/blenderbim/bim/module/project/ui.py @@ -47,7 +47,7 @@ class BIM_PT_project(Panel): row.prop(pprops, "collection_mode") row = self.layout.row() row.prop(pprops, "filter_mode") - if pprops.filter_mode != "NONE": + if pprops.filter_mode in ["DECOMPOSITION", "IFC_CLASS"]: self.layout.template_list( "BIM_UL_filter_categories", "", @@ -56,6 +56,28 @@ class BIM_PT_project(Panel): pprops, "active_filter_category_index", ) + elif pprops.filter_mode in ["WHITELIST", "BLACKLIST"]: + row = self.layout.row() + row.prop(pprops, "filter_query") + row = self.layout.row() + row.prop(pprops, "should_use_cpu_multiprocessing") + row = self.layout.row() + row.prop(pprops, "should_merge_by_class") + row = self.layout.row() + row.prop(pprops, "should_merge_by_material") + row = self.layout.row() + row.prop(pprops, "should_merge_materials_by_colour") + row = self.layout.row() + row.prop(pprops, "should_clean_mesh") + row = self.layout.row() + row.prop(pprops, "deflection_tolerance") + row = self.layout.row() + row.prop(pprops, "angular_tolerance") + row = self.layout.row() + row.prop(pprops, "should_offset_model") + row = self.layout.row() + row.prop(pprops, "model_offset_coordinates") + row = self.layout.row(align=True) row.operator("bim.load_project_elements") row.operator("bim.unload_project", text="", icon="CANCEL") diff --git a/src/blenderbim/blenderbim/bim/operator.py b/src/blenderbim/blenderbim/bim/operator.py index 66e27bc6e7..150bc5a461 100644 --- a/src/blenderbim/blenderbim/bim/operator.py +++ b/src/blenderbim/blenderbim/bim/operator.py @@ -100,66 +100,13 @@ class ExportIFC(bpy.types.Operator): return {"FINISHED"} -class ImportIFC(bpy.types.Operator, ImportHelper): +class ImportIFC(bpy.types.Operator): bl_idname = "import_ifc.bim" bl_label = "Import IFC" bl_options = {"REGISTER", "UNDO"} - filename_ext = ".ifc" - filter_glob: bpy.props.StringProperty(default="*.ifc;*.ifczip;*.ifcxml", options={"HIDDEN"}) - - should_auto_set_workarounds: bpy.props.BoolProperty(name="Automatically Set Vendor Workarounds", default=True) - should_use_cpu_multiprocessing: bpy.props.BoolProperty(name="Import with CPU Multiprocessing", default=True) - should_merge_by_class: bpy.props.BoolProperty(name="Import and Merge by Class", default=False) - should_merge_by_material: bpy.props.BoolProperty(name="Import and Merge by Material", default=False) - should_merge_materials_by_colour: bpy.props.BoolProperty(name="Import and Merge Materials by Colour", default=False) - should_clean_mesh: bpy.props.BoolProperty(name="Import and Clean Mesh", default=True) - deflection_tolerance: bpy.props.FloatProperty(name="Import Deflection Tolerance", default=0.001) - angular_tolerance: bpy.props.FloatProperty(name="Import Angular Tolerance", default=0.5) - should_offset_model: bpy.props.BoolProperty(name="Import and Offset Model", default=False) - model_offset_coordinates: bpy.props.StringProperty(name="Model Offset Coordinates", default="0,0,0") - ifc_import_filter: bpy.props.EnumProperty( - items=[ - ("NONE", "None", ""), - ("WHITELIST", "Whitelist", ""), - ("BLACKLIST", "Blacklist", ""), - ], - name="Import Filter", - ) - ifc_selector: bpy.props.StringProperty(default="", name="IFC Selector") def execute(self, context): - start = time.time() - logger = logging.getLogger("ImportIFC") - path_log = os.path.join(context.scene.BIMProperties.data_dir, "process.log") - if not os.access(context.scene.BIMProperties.data_dir, os.W_OK): - path_log = os.path.join(tempfile.mkdtemp(), "process.log") - logging.basicConfig( - filename=path_log, - filemode="a", - level=logging.DEBUG, - ) - - settings = import_ifc.IfcImportSettings.factory(context, self.filepath, logger) - settings.should_auto_set_workarounds = self.should_auto_set_workarounds - settings.should_use_cpu_multiprocessing = self.should_use_cpu_multiprocessing - settings.should_merge_by_class = self.should_merge_by_class - settings.should_merge_by_material = self.should_merge_by_material - settings.should_merge_materials_by_colour = self.should_merge_materials_by_colour - settings.should_clean_mesh = self.should_clean_mesh - settings.deflection_tolerance = self.deflection_tolerance - settings.angular_tolerance = self.angular_tolerance - settings.should_offset_model = self.should_offset_model - settings.model_offset_coordinates = ( - [float(o) for o in self.model_offset_coordinates.split(",")] if self.model_offset_coordinates else (0, 0, 0) - ) - settings.ifc_import_filter = self.ifc_import_filter - settings.ifc_selector = self.ifc_selector - - settings.logger.info("Starting import") - ifc_importer = import_ifc.IfcImporter(settings) - ifc_importer.execute() - settings.logger.info("Import finished in {:.2f} seconds".format(time.time() - start)) - print("Import finished in {:.2f} seconds".format(time.time() - start)) + bpy.ops.bim.load_project('INVOKE_DEFAULT') return {"FINISHED"} diff --git a/src/blenderbim/test/bim/bootstrap.py b/src/blenderbim/test/bim/bootstrap.py index 2177bbd9dc..4b18fef692 100644 --- a/src/blenderbim/test/bim/bootstrap.py +++ b/src/blenderbim/test/bim/bootstrap.py @@ -26,6 +26,7 @@ import blenderbim import ifcopenshell import ifcopenshell.util.representation from blenderbim.bim.ifc import IfcStore +from mathutils import Vector # Monkey-patch webbrowser opening since we want to test headlessly webbrowser.open = lambda x: True @@ -245,6 +246,11 @@ def the_object_name_has_number_vertices(name, number): assert total == int(number), f"We found {total} vertices" +def the_object_name_is_at_location(name, location): + obj_location = the_object_name_exists(name).location + assert (obj_location - Vector([float(co) for co in location.split(",")])).length < 0.1, f"Object is at {obj_location}" + + definitions = { "an empty IFC project": an_empty_ifc_project, "I add a cube": i_add_a_cube, @@ -275,6 +281,7 @@ definitions = { 'the object "(.*)" is not voided by "(.*)"': the_object_name_is_not_voided_by_void, 'the object "(.*)" should display as "(.*)"': the_object_name_should_display_as_mode, 'the object "(.*)" has "([0-9]+)" vertices': the_object_name_has_number_vertices, + 'the object "(.*)" is at "(.*)"': the_object_name_is_at_location, } diff --git a/src/blenderbim/test/bim/module/project/test_operator.py b/src/blenderbim/test/bim/module/project/test_operator.py index 08fffc6f07..8230049470 100644 --- a/src/blenderbim/test/bim/module/project/test_operator.py +++ b/src/blenderbim/test/bim/module/project/test_operator.py @@ -42,7 +42,33 @@ class TestLoadProject(test.bim.bootstrap.NewFile): return """ When I press "bim.load_project(filepath='{cwd}/test/files/basic.ifc')" Then an IFC file exists + And the object "IfcProject/My Project" is an "IfcProject" + And the object "IfcSite/My Site" is an "IfcSite" + And the object "IfcBuilding/My Building" is an "IfcBuilding" + And the object "IfcBuildingStorey/Ground Floor" is an "IfcBuildingStorey" + And the object "IfcBuildingStorey/Level 1" is an "IfcBuildingStorey" + And the object "IfcSlab/Slab" is an "IfcSlab" + And the object "IfcWall/Wall" is an "IfcWall" + And the object "IfcElementAssembly/Empty" is an "IfcElementAssembly" + And the object "IfcBeam/Beam" is an "IfcBeam" + And the object "IfcSite/My Site" is in the collection "IfcSite/My Site" + And the object "IfcBuilding/My Building" is in the collection "IfcBuilding/My Building" + And the object "IfcBuildingStorey/Ground Floor" is in the collection "IfcBuildingStorey/Ground Floor" + And the object "IfcBuildingStorey/Level 1" is in the collection "IfcBuildingStorey/Level 1" + And the object "IfcElementAssembly/Empty" is in the collection "IfcElementAssembly/Empty" + And the object "IfcBeam/Beam" is in the collection "IfcElementAssembly/Empty" + And the object "IfcSlab/Slab" is in the collection "IfcBuildingStorey/Ground Floor" + And the object "IfcWall/Wall" is in the collection "IfcBuildingStorey/Level 1" + And "scene.BIMProjectProperties.is_loading" is "False" + """ + + @test.bim.bootstrap.scenario + def test_loading_a_project_in_advanced_mode(self): + return """ + When I press "bim.load_project(filepath='{cwd}/test/files/basic.ifc', is_advanced=True)" + Then an IFC file exists And "scene.BIMProjectProperties.is_loading" is "True" + And the object "IfcProject/My Project" does not exist """ @@ -50,7 +76,7 @@ class TestLoadProjectElements(test.bim.bootstrap.NewFile): @test.bim.bootstrap.scenario def test_loading_all_project_elements(self): return """ - Given I press "bim.load_project(filepath='{cwd}/test/files/basic.ifc')" + Given I press "bim.load_project(filepath='{cwd}/test/files/basic.ifc', is_advanced=True)" When I set "scene.BIMProjectProperties.collection_mode" to "DECOMPOSITION" And I set "scene.BIMProjectProperties.filter_mode" to "NONE" And I press "bim.load_project_elements" @@ -77,7 +103,7 @@ class TestLoadProjectElements(test.bim.bootstrap.NewFile): @test.bim.bootstrap.scenario def test_loading_objects_filtered_by_decomposition(self): return """ - Given I press "bim.load_project(filepath='{cwd}/test/files/basic.ifc')" + Given I press "bim.load_project(filepath='{cwd}/test/files/basic.ifc', is_advanced=True)" When I set "scene.BIMProjectProperties.collection_mode" to "DECOMPOSITION" And I set "scene.BIMProjectProperties.filter_mode" to "DECOMPOSITION" Then "scene.BIMProjectProperties.filter_categories['IfcSite/My Site'].total_elements" is "0" @@ -106,7 +132,7 @@ class TestLoadProjectElements(test.bim.bootstrap.NewFile): @test.bim.bootstrap.scenario def test_loading_objects_filtered_by_ifc_class(self): return """ - Given I press "bim.load_project(filepath='{cwd}/test/files/basic.ifc')" + Given I press "bim.load_project(filepath='{cwd}/test/files/basic.ifc', is_advanced=True)" When I set "scene.BIMProjectProperties.collection_mode" to "DECOMPOSITION" And I set "scene.BIMProjectProperties.filter_mode" to "IFC_CLASS" Then "scene.BIMProjectProperties.filter_categories['IfcWall'].total_elements" is "1" @@ -126,10 +152,56 @@ class TestLoadProjectElements(test.bim.bootstrap.NewFile): And the object "IfcWall/Wall" does not exist """ + @test.bim.bootstrap.scenario + def test_loading_objects_filtered_by_whitelist(self): + return """ + Given I press "bim.load_project(filepath='{cwd}/test/files/basic.ifc', is_advanced=True)" + When I set "scene.BIMProjectProperties.collection_mode" to "DECOMPOSITION" + And I set "scene.BIMProjectProperties.filter_mode" to "WHITELIST" + And I set "scene.BIMProjectProperties.filter_query" to ".IfcSlab" + And I press "bim.load_project_elements" + Then the object "IfcProject/My Project" is an "IfcProject" + And the object "IfcSite/My Site" is an "IfcSite" + And the object "IfcBuilding/My Building" is an "IfcBuilding" + And the object "IfcBuildingStorey/Ground Floor" is an "IfcBuildingStorey" + And the object "IfcSlab/Slab" is an "IfcSlab" + And the object "IfcSite/My Site" is in the collection "IfcSite/My Site" + And the object "IfcBuilding/My Building" is in the collection "IfcBuilding/My Building" + And the object "IfcBuildingStorey/Ground Floor" is in the collection "IfcBuildingStorey/Ground Floor" + And the object "IfcSlab/Slab" is in the collection "IfcBuildingStorey/Ground Floor" + And the object "IfcBuildingStorey/Level 1" does not exist + And the object "IfcWall/Wall" does not exist + """ + + @test.bim.bootstrap.scenario + def test_loading_objects_filtered_by_blacklist(self): + return """ + Given I press "bim.load_project(filepath='{cwd}/test/files/basic.ifc', is_advanced=True)" + When I set "scene.BIMProjectProperties.collection_mode" to "DECOMPOSITION" + And I set "scene.BIMProjectProperties.filter_mode" to "BLACKLIST" + And I set "scene.BIMProjectProperties.filter_query" to ".IfcSlab" + And I press "bim.load_project_elements" + Then the object "IfcProject/My Project" is an "IfcProject" + And the object "IfcSite/My Site" is an "IfcSite" + And the object "IfcBuilding/My Building" is an "IfcBuilding" + And the object "IfcBuildingStorey/Level 1" is an "IfcBuildingStorey" + And the object "IfcWall/Wall" is an "IfcWall" + And the object "IfcElementAssembly/Empty" is an "IfcElementAssembly" + And the object "IfcBeam/Beam" is an "IfcBeam" + And the object "IfcSite/My Site" is in the collection "IfcSite/My Site" + And the object "IfcBuilding/My Building" is in the collection "IfcBuilding/My Building" + And the object "IfcBuildingStorey/Level 1" is in the collection "IfcBuildingStorey/Level 1" + And the object "IfcWall/Wall" is in the collection "IfcBuildingStorey/Level 1" + And the object "IfcElementAssembly/Empty" is in the collection "IfcElementAssembly/Empty" + And the object "IfcBeam/Beam" is in the collection "IfcElementAssembly/Empty" + And the object "IfcBuildingStorey/Ground Floor" does not exist + And the object "IfcSlab/Slab" does not exist + """ + @test.bim.bootstrap.scenario def test_loading_no_objects_due_to_filter(self): return """ - Given I press "bim.load_project(filepath='{cwd}/test/files/basic.ifc')" + Given I press "bim.load_project(filepath='{cwd}/test/files/basic.ifc', is_advanced=True)" When I set "scene.BIMProjectProperties.collection_mode" to "DECOMPOSITION" And I set "scene.BIMProjectProperties.filter_mode" to "IFC_CLASS" And I press "bim.load_project_elements" @@ -142,12 +214,22 @@ class TestLoadProjectElements(test.bim.bootstrap.NewFile): And the object "IfcWall/Wall" does not exist """ + @test.bim.bootstrap.scenario + def test_manual_offset_of_object_placements(self): + return """ + Given I press "bim.load_project(filepath='{cwd}/test/files/manual-geolocation.ifc', is_advanced=True)" + When I set "scene.BIMProjectProperties.should_offset_model" to "True" + And I set "scene.BIMProjectProperties.model_offset_coordinates" to "-268388.5, -5774506.0, -21.899999618530273" + And I press "bim.load_project_elements" + Then the object "IfcPlate/1780 x 270 PRECAST WALL" is at "0,0,0" + """ + class TestUnloadProject(test.bim.bootstrap.NewFile): @test.bim.bootstrap.scenario def test_unloading_a_project(self): return """ - When I press "bim.load_project(filepath='{cwd}/test/files/basic.ifc')" + When I press "bim.load_project(filepath='{cwd}/test/files/basic.ifc', is_advanced=True)" And I press "bim.unload_project" Then an IFC file does not exist And "scene.BIMProjectProperties.is_loading" is "False" diff --git a/src/blenderbim/test/bim/test_operator.py b/src/blenderbim/test/bim/test_operator.py deleted file mode 100644 index 608be4185d..0000000000 --- a/src/blenderbim/test/bim/test_operator.py +++ /dev/null @@ -1,31 +0,0 @@ -# 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 test.bim.bootstrap -from blenderbim.bim.ifc import IfcStore - - -class TestImportIFC(test.bim.bootstrap.NewFile): - def test_manual_offset_of_object_placements(self): - bpy.ops.import_ifc.bim( - filepath="./test/files/manual-geolocation.ifc", - should_offset_model=True, - model_offset_coordinates="-268388.5, -5774506.0, -21.899999618530273", - ) - assert IfcStore.id_map[63].location.length < 1