diff --git a/src/blenderbim/test/bim/feature/model.feature b/src/blenderbim/test/bim/feature/model.feature index 9b4930a543..f147ac25fe 100644 --- a/src/blenderbim/test/bim/feature/model.feature +++ b/src/blenderbim/test/bim/feature/model.feature @@ -73,3 +73,197 @@ Scenario: Pie update container When the object "IfcSlab/Slab" is placed in the collection "IfcBuildingStorey/Level 1" And I press "bim.pie_update_container" Then nothing happens + +Scenario: Add a wall + Given an empty IFC project + And I load the demo construction library + And I set "scene.BIMModelProperties.ifc_class" to "IfcWallType" + And the variable "element_type" is "[e for e in {ifc}.by_type('IfcWallType') if e.Name == 'WAL100'][0].id()" + And I set "scene.BIMModelProperties.relating_type_id" to "{element_type}" + When I press "bim.add_constr_type_instance" + Then the object "IfcWall/Wall" is an "IfcWall" + And the object "IfcWall/Wall" dimensions are "1,0.1,3" + And the object "IfcWall/Wall" bottom left corner is at "0,0,0" + +Scenario: Extend a wall to the cursor + Given an empty IFC project + And I load the demo construction library + And I set "scene.BIMModelProperties.ifc_class" to "IfcWallType" + And the variable "element_type" is "[e for e in {ifc}.by_type('IfcWallType') if e.Name == 'WAL100'][0].id()" + And I set "scene.BIMModelProperties.relating_type_id" to "{element_type}" + And I press "bim.hotkey(hotkey='S_A')" + And the object "IfcWall/Wall" is selected + And the cursor is at "2,0,0" + When I press "bim.hotkey(hotkey='S_E')" + Then the object "IfcWall/Wall" dimensions are "2,0.1,3" + And the object "IfcWall/Wall" bottom left corner is at "0,0,0" + +Scenario: Add a wall perpendicular to an existing wall + Given an empty IFC project + And I load the demo construction library + And I set "scene.BIMModelProperties.ifc_class" to "IfcWallType" + And the variable "element_type" is "[e for e in {ifc}.by_type('IfcWallType') if e.Name == 'WAL100'][0].id()" + And I set "scene.BIMModelProperties.relating_type_id" to "{element_type}" + And I press "bim.hotkey(hotkey='S_A')" + And the cursor is at "0.5,0,0" + When I press "bim.hotkey(hotkey='S_A')" + Then the object "IfcWall/Wall.001" dimensions are "1,0.1,3" + And the object "IfcWall/Wall.001" bottom left corner is at "0,0,0" + And the object "IfcWall/Wall" dimensions are "1,0.1,3" + And the object "IfcWall/Wall" bottom left corner is at "0.5,0,0" + And the object "IfcWall/Wall" top right corner is at "0.6,-1,3" + +Scenario: Extend one wall to another + Given an empty IFC project + And I load the demo construction library + And I set "scene.BIMModelProperties.ifc_class" to "IfcWallType" + And the variable "element_type" is "[e for e in {ifc}.by_type('IfcWallType') if e.Name == 'WAL100'][0].id()" + And I set "scene.BIMModelProperties.relating_type_id" to "{element_type}" + And I press "bim.hotkey(hotkey='S_A')" + And the cursor is at "0.5,0,0" + And I press "bim.hotkey(hotkey='S_A')" + And the object "IfcWall/Wall" is moved to "0.5,-1,0" + And the object "IfcWall/Wall" is selected + And additionally the object "IfcWall/Wall.001" is selected + When I press "bim.hotkey(hotkey='S_E')" + Then the object "IfcWall/Wall.001" dimensions are "1,0.1,3" + And the object "IfcWall/Wall.001" bottom left corner is at "0,0,0" + And the object "IfcWall/Wall" dimensions are "2,0.1,3" + And the object "IfcWall/Wall" bottom left corner is at "0.5,0,0" + And the object "IfcWall/Wall" top right corner is at "0.6,-2,3" + +Scenario: Join two walls with a butt joint - first wall has priority + Given an empty IFC project + And I load the demo construction library + And I set "scene.BIMModelProperties.ifc_class" to "IfcWallType" + And the variable "element_type" is "[e for e in {ifc}.by_type('IfcWallType') if e.Name == 'WAL100'][0].id()" + And I set "scene.BIMModelProperties.relating_type_id" to "{element_type}" + And I press "bim.hotkey(hotkey='S_A')" + And the cursor is at "0.5,0,0" + And I press "bim.hotkey(hotkey='S_A')" + And the object "IfcWall/Wall" is selected + And additionally the object "IfcWall/Wall.001" is selected + When I press "bim.hotkey(hotkey='S_T')" + Then the object "IfcWall/Wall.001" dimensions are "0.4,0.1,3" + And the object "IfcWall/Wall.001" bottom left corner is at "0.6,0,0" + And the object "IfcWall/Wall" dimensions are "1.1,0.1,3" + And the object "IfcWall/Wall" bottom left corner is at "0.5,0.1,0" + And the object "IfcWall/Wall" top right corner is at "0.6,-1,3" + +Scenario: Join two walls with a butt joint - second wall has priority + Given an empty IFC project + And I load the demo construction library + And I set "scene.BIMModelProperties.ifc_class" to "IfcWallType" + And the variable "element_type" is "[e for e in {ifc}.by_type('IfcWallType') if e.Name == 'WAL100'][0].id()" + And I set "scene.BIMModelProperties.relating_type_id" to "{element_type}" + And I press "bim.hotkey(hotkey='S_A')" + And the cursor is at "0.5,0,0" + And I press "bim.hotkey(hotkey='S_A')" + And the object "IfcWall/Wall.001" is selected + And additionally the object "IfcWall/Wall" is selected + When I press "bim.hotkey(hotkey='S_T')" + Then the object "IfcWall/Wall.001" dimensions are "0.5,0.1,3" + And the object "IfcWall/Wall.001" bottom left corner is at "0.5,0,0" + And the object "IfcWall/Wall" dimensions are "1,0.1,3" + And the object "IfcWall/Wall" bottom left corner is at "0.5,0,0" + And the object "IfcWall/Wall" top right corner is at "0.6,-1,3" + +Scenario: Join two walls with a mitre joint + Given an empty IFC project + And I load the demo construction library + And I set "scene.BIMModelProperties.ifc_class" to "IfcWallType" + And the variable "element_type" is "[e for e in {ifc}.by_type('IfcWallType') if e.Name == 'WAL100'][0].id()" + And I set "scene.BIMModelProperties.relating_type_id" to "{element_type}" + And I press "bim.hotkey(hotkey='S_A')" + And the cursor is at "0.5,0,0" + And I press "bim.hotkey(hotkey='S_A')" + And the object "IfcWall/Wall" is selected + And additionally the object "IfcWall/Wall.001" is selected + When I press "bim.hotkey(hotkey='S_Y')" + Then the object "IfcWall/Wall.001" dimensions are "0.5,0.1,3" + And the object "IfcWall/Wall.001" bottom left corner is at "0.5,0,0" + And the object "IfcWall/Wall" dimensions are "1.1,0.1,3" + And the object "IfcWall/Wall" bottom left corner is at "0.5,0.1,0" + And the object "IfcWall/Wall" top right corner is at "0.6,-1,3" + +Scenario: Change the height of a wall + Given an empty IFC project + And I load the demo construction library + And I set "scene.BIMModelProperties.ifc_class" to "IfcWallType" + And the variable "element_type" is "[e for e in {ifc}.by_type('IfcWallType') if e.Name == 'WAL100'][0].id()" + And I set "scene.BIMModelProperties.relating_type_id" to "{element_type}" + And I press "bim.hotkey(hotkey='S_A')" + And the object "IfcWall/Wall" is selected + And I set "scene.BIMModelProperties.extrusion_depth" to "2000.0" + When I press "bim.change_extrusion_depth(depth=2000.0)" + Then the object "IfcWall/Wall" dimensions are "1,0.1,2" + +Scenario: Change the length of a wall + Given an empty IFC project + And I load the demo construction library + And I set "scene.BIMModelProperties.ifc_class" to "IfcWallType" + And the variable "element_type" is "[e for e in {ifc}.by_type('IfcWallType') if e.Name == 'WAL100'][0].id()" + And I set "scene.BIMModelProperties.relating_type_id" to "{element_type}" + And I press "bim.hotkey(hotkey='S_A')" + And the object "IfcWall/Wall" is selected + And I set "scene.BIMModelProperties.length" to "2000.0" + When I press "bim.change_layer_length(length=2000.0)" + Then the object "IfcWall/Wall" dimensions are "2,0.1,3" + +Scenario: Flip a wall + Given an empty IFC project + And I load the demo construction library + And I set "scene.BIMModelProperties.ifc_class" to "IfcWallType" + And the variable "element_type" is "[e for e in {ifc}.by_type('IfcWallType') if e.Name == 'WAL100'][0].id()" + And I set "scene.BIMModelProperties.relating_type_id" to "{element_type}" + And I press "bim.hotkey(hotkey='S_A')" + And the object "IfcWall/Wall" is selected + When I press "bim.hotkey(hotkey='S_F')" + Then the object "IfcWall/Wall" dimensions are "1,0.1,3" + And the object "IfcWall/Wall" bottom left corner is at "1,0,0" + And the object "IfcWall/Wall" top right corner is at "0,-0.1,3" + +Scenario: Split a wall + Given an empty IFC project + And I load the demo construction library + And I set "scene.BIMModelProperties.ifc_class" to "IfcWallType" + And the variable "element_type" is "[e for e in {ifc}.by_type('IfcWallType') if e.Name == 'WAL100'][0].id()" + And I set "scene.BIMModelProperties.relating_type_id" to "{element_type}" + And I press "bim.hotkey(hotkey='S_A')" + And the object "IfcWall/Wall" is selected + And the cursor is at "0.5,0,0" + When I press "bim.hotkey(hotkey='S_K')" + Then the object "IfcWall/Wall" is an "IfcWall" + And the object "IfcWall/Wall.001" is an "IfcWall" + And the object "IfcWall/Wall" dimensions are "0.5,0.1,3" + And the object "IfcWall/Wall" bottom left corner is at "0,0,0" + And the object "IfcWall/Wall" top right corner is at "0.5,0.1,3" + And the object "IfcWall/Wall.001" dimensions are "0.5,0.1,3" + And the object "IfcWall/Wall.001" bottom left corner is at "0.5,0,0" + And the object "IfcWall/Wall.001" top right corner is at "1,0.1,3" + +Scenario: Rotate a wall by 90 degrees + Given an empty IFC project + And I load the demo construction library + And I set "scene.BIMModelProperties.ifc_class" to "IfcWallType" + And the variable "element_type" is "[e for e in {ifc}.by_type('IfcWallType') if e.Name == 'WAL100'][0].id()" + And I set "scene.BIMModelProperties.relating_type_id" to "{element_type}" + And I press "bim.hotkey(hotkey='S_A')" + And the object "IfcWall/Wall" is selected + When I press "bim.hotkey(hotkey='S_R')" + Then the object "IfcWall/Wall" dimensions are "1,0.1,3" + And the object "IfcWall/Wall" bottom left corner is at "0,0,0" + And the object "IfcWall/Wall" top right corner is at "-0.1,1,3" + +Scenario: Regenerate a wall - after doing nothing interesting + Given an empty IFC project + And I load the demo construction library + And I set "scene.BIMModelProperties.ifc_class" to "IfcWallType" + And the variable "element_type" is "[e for e in {ifc}.by_type('IfcWallType') if e.Name == 'WAL100'][0].id()" + And I set "scene.BIMModelProperties.relating_type_id" to "{element_type}" + And I press "bim.hotkey(hotkey='S_A')" + And the object "IfcWall/Wall" is selected + When I press "bim.hotkey(hotkey='S_G')" + Then the object "IfcWall/Wall" is an "IfcWall" + And the object "IfcWall/Wall" dimensions are "1,0.1,3" + And the object "IfcWall/Wall" bottom left corner is at "0,0,0" diff --git a/src/blenderbim/test/bim/test_feature.py b/src/blenderbim/test/bim/test_feature.py index 057f9ddbae..98b9e297bf 100644 --- a/src/blenderbim/test/bim/test_feature.py +++ b/src/blenderbim/test/bim/test_feature.py @@ -51,6 +51,7 @@ def replace_variables(value): def is_x(number, x): return abs(number - x) < 1e-6 + def vectors_are_equal(v1, v2): assert len(v1) == len(v2), f"Compared vectors are not equal length: {v1}, {v2}" return all(is_x(v1[i], v2[i]) for i in range(len(v1))) @@ -78,6 +79,8 @@ def an_empty_ifc_project(): if len(bpy.data.objects) > 0: bpy.data.batch_remove(bpy.data.objects) bpy.ops.outliner.orphans_purge(do_local_ids=True, do_linked_ids=True, do_recursive=True) + bpy.context.scene.unit_settings.system = "METRIC" + bpy.context.scene.unit_settings.length_unit = "MILLIMETERS" bpy.ops.bim.create_project() @@ -198,7 +201,10 @@ def then_the_object_name_is_selected(name): @given(parsers.parse('the object "{name}" is moved to "{location}"')) @when(parsers.parse('the object "{name}" is moved to "{location}"')) def the_object_name_is_moved_to_location(name, location): - the_object_name_exists(name).location += Vector([float(co) for co in location.split(",")]) + location = [float(co) for co in location.split(",")] + the_object_name_exists(name).matrix_world[0][3] = location[0] + the_object_name_exists(name).matrix_world[1][3] = location[1] + the_object_name_exists(name).matrix_world[2][3] = location[2] @given(parsers.parse('the object "{name}" is scaled to "{scale}"')) @@ -610,12 +616,22 @@ def the_object_name_dimensions_are_dimensions(name, dimensions): assert is_x(number, expected_dimensions[i]) -@then(parsers.parse('the object "{name}" bottom left corner is at "{location}"')) +@then(parsers.parse('the object "{name}" top right corner is at "{location}"')) def the_object_name_is_at_location(name, location): - obj_corner = Vector(the_object_name_exists(name).bound_box[0]) + obj = the_object_name_exists(name) + obj_corner = obj.matrix_world @ Vector(obj.bound_box[6]) assert ( obj_corner - Vector([float(co) for co in location.split(",")]) - ).length < 0.1, f"Object has corner {obj_corner}" + ).length < 0.1, f"Object has top right corner {obj_corner}" + + +@then(parsers.parse('the object "{name}" bottom left corner is at "{location}"')) +def the_object_name_is_at_location(name, location): + obj = the_object_name_exists(name) + obj_corner = obj.matrix_world @ Vector(obj.bound_box[0]) + assert ( + obj_corner - Vector([float(co) for co in location.split(",")]) + ).length < 0.1, f"Object has bottom left corner {obj_corner}" @then(parsers.parse('the object "{name}" is contained in "{container_name}"')) @@ -647,6 +663,11 @@ def i_add_a_construction_library(): bpy.ops.bim.select_library_file(filepath=lib_path, append_all=True) +@given(parsers.parse('the cursor is at "{location}"')) +def the_cursor_is_at_location(location): + bpy.context.scene.cursor.location = [float(co) for co in location.split(",")] + + @given("I display the construction type browser") @when("I display the construction type browser") def i_display_the_construction_type_browser(): @@ -672,12 +693,15 @@ def move_cursor_bottom_left(): bpy.context.window.cursor_warp(10, 10) +# These definitions are not to be used in tests but simply in debugging failing tests + + @given(parsers.parse("I save sample test files")) @when(parsers.parse("I save sample test files")) @then(parsers.parse("I save sample test files")) def saving_sample_test_files(and_open_in_blender=None): filepath = f"{variables['cwd']}/test/files/sample_test_file" - blend_filepath = f'{filepath}.blend' + blend_filepath = f"{filepath}.blend" bpy.ops.export_ifc.bim(filepath=f"{filepath}.ifc", should_save_as=True) bpy.ops.wm.save_as_mainfile(filepath=f"{filepath}.blend") @@ -690,11 +714,14 @@ def saving_sample_test_files_and_open_in_blender(): saving_sample_test_files() filepath = f"{variables['cwd']}/test/files/sample_test_file.blend" import subprocess - subprocess.Popen([bpy.app.binary_path, f'{filepath}']) + + subprocess.Popen([bpy.app.binary_path, f"{filepath}"]) @given(parsers.parse("I run pdb")) @when(parsers.parse("I run pdb")) @then(parsers.parse("I run pdb")) def run_pdb(): - import pdb; pdb.set_trace() \ No newline at end of file + import pdb + + pdb.set_trace()