From b90ab706583e618591e75064873c300ccdb01d3f Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Sat, 15 Oct 2022 11:06:09 +1100 Subject: [PATCH] Modeling dimensions now have sensible defaults depending on units and show prior to element creation --- .../blenderbim/bim/module/model/prop.py | 2 +- .../blenderbim/bim/module/model/workspace.py | 258 ++++++++++-------- .../blenderbim/bim/module/project/operator.py | 11 +- src/blenderbim/blenderbim/core/project.py | 4 + src/blenderbim/blenderbim/core/tool.py | 3 + src/blenderbim/blenderbim/tool/project.py | 25 ++ src/blenderbim/test/core/test_project.py | 12 + src/blenderbim/test/tool/test_project.py | 32 +++ .../ifcopenshell/util/unit.py | 2 + 9 files changed, 227 insertions(+), 122 deletions(-) diff --git a/src/blenderbim/blenderbim/bim/module/model/prop.py b/src/blenderbim/blenderbim/bim/module/model/prop.py index eb510ff2a0..fd8c4a9165 100644 --- a/src/blenderbim/blenderbim/bim/module/model/prop.py +++ b/src/blenderbim/blenderbim/bim/module/model/prop.py @@ -1,5 +1,5 @@ # BlenderBIM Add-on - OpenBIM Blender Add-on -# Copyright (C) 2020, 2021 Dion Moult +# Copyright (C) 2020, 2021, 2022 Dion Moult # # This file is part of BlenderBIM Add-on. # diff --git a/src/blenderbim/blenderbim/bim/module/model/workspace.py b/src/blenderbim/blenderbim/bim/module/model/workspace.py index 15e3ba0fd8..624614848f 100644 --- a/src/blenderbim/blenderbim/bim/module/model/workspace.py +++ b/src/blenderbim/blenderbim/bim/module/model/workspace.py @@ -1,5 +1,5 @@ # BlenderBIM Add-on - OpenBIM Blender Add-on -# Copyright (C) 2020, 2021 Dion Moult +# Copyright (C) 2020, 2021, 2022 Dion Moult # # This file is part of BlenderBIM Add-on. # @@ -39,6 +39,7 @@ class BimTool(WorkSpaceTool): bl_keymap = ( # ("bim.wall_tool_op", {"type": 'MOUSEMOVE', "value": 'ANY'}, {"properties": []}), # ("mesh.add_wall", {"type": 'LEFTMOUSE', "value": 'PRESS'}, {"properties": []}), + #("bim.sync_modeling", {"type": 'MOUSEMOVE', "value": 'ANY'}, {"properties": []}), ("bim.hotkey", {"type": "A", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_A")]}), ("bim.hotkey", {"type": "C", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_C")]}), ("bim.hotkey", {"type": "E", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_E")]}), @@ -56,12 +57,18 @@ class BimTool(WorkSpaceTool): ("bim.hotkey", {"type": "O", "value": "PRESS", "alt": True}, {"properties": [("hotkey", "A_O")]}), ) - def draw_settings(context, layout, something): - props = context.scene.BIMModelProperties - is_tool_header = context.region.type == "TOOL_HEADER" - is_sidebar = context.region.type == "UI" + def draw_settings(context, layout, ws_tool): + # Unlike operators, Blender doesn't treat workspace tools as a class, so we'll create our own. + BimToolUI.draw(context, layout) - row = layout.row(align=True) + +class BimToolUI: + @classmethod + def draw(cls, context, layout): + cls.layout = layout + cls.props = context.scene.BIMModelProperties + + row = cls.layout.row(align=True) if not tool.Ifc.get(): row.label(text="No IFC Project", icon="ERROR") return @@ -69,121 +76,87 @@ class BimTool(WorkSpaceTool): if not AuthoringData.is_loaded: AuthoringData.load() - ifc_classes = AuthoringData.data["ifc_classes"] if "ifc_classes" in AuthoringData.data else False - relating_types_ids = ( - AuthoringData.data["relating_types_ids"] if "relating_types_ids" in AuthoringData.data else False - ) - - #if ifc_classes and relating_types_ids and not props.icon_id and not is_tool_header: + #if ifc_classes and relating_types_ids and not cls.props.icon_id and not is_tool_header: # # hack Dion won't like to show a preview also on the first time the sidebar is shown - # bpy.app.timers.register(lambda: prop.update_ifc_class(props, "lost_context")) - # bpy.app.timers.register(lambda: prop.update_relating_type(props, "lost_context")) + # bpy.app.timers.register(lambda: prop.update_ifc_class(cls.props, "lost_context")) + # bpy.app.timers.register(lambda: prop.update_relating_type(cls.props, "lost_context")) - ifc_class = props.ifc_class - relating_type_id = props.relating_type_id + if context.region.type == "TOOL_HEADER": + cls.draw_header_interface() + elif context.region.type == "UI": + cls.draw_sidebar_interface() - if is_tool_header: - row = layout.row(align=True) - if ifc_classes: - row.label(text="", icon="FILE_VOLUME") - row.prop(data=props, property="ifc_class", text="") - else: - row.label(text="No Construction Class", icon="FILE_VOLUME") - row = layout.row(align=True) - if relating_types_ids: - row.label(text="", icon="FILE_3D") - prop_with_search(row, props, "relating_type_id", text="") - row.operator("bim.launch_type_manager", icon="LIGHTPROBE_GRID", text="") - else: - row.label(text="No Construction Type", icon="FILE_3D") - if ifc_classes: - #row = layout.row() - #row.operator("bim.display_constr_types", icon="TRIA_DOWN", text="") + if context.active_object: + cls.draw_edit_object_interface(context) + elif not context.selected_objects: + cls.draw_create_object_interface() - row = layout.row(align=True) - row.label(text="", icon="EVENT_SHIFT") - row.label(text="", icon="EVENT_A") - op = row.operator("bim.add_constr_type_instance", text="Add") - op.from_invoke = True - op.ifc_class = ifc_class - if relating_type_id.isnumeric(): - op.relating_type_id = int(relating_type_id) - elif is_sidebar: - row = layout.row(align=True) - if ifc_classes: - row.label(text="", icon="FILE_VOLUME") - prop_with_search(row, props, "ifc_class", text="") - else: - row.label(text="No Construction Class", icon="FILE_VOLUME") - row = layout.row(align=True) - if relating_types_ids: - row.label(text="", icon="FILE_3D") - prop_with_search(row, props, "relating_type_id", text="") - else: - row.label(text="No Construction Type", icon="FILE_3D") + @classmethod + def draw_create_object_interface(cls): + if not AuthoringData.data["relating_types_ids"]: + return + if cls.props.ifc_class == "IfcWallType": + row = cls.layout.row(align=True) + row.prop(data=cls.props, property="extrusion_depth", text="Height") - box = layout.box() - if AuthoringData.data["type_thumbnail"]: - box.template_icon(icon_value=AuthoringData.data["type_thumbnail"], scale=5) - else: - op = box.operator("bim.load_type_thumbnails", text="Load Thumbnails", icon="FILE_REFRESH") - op.ifc_class = props.ifc_class + row = cls.layout.row(align=True) + row.prop(data=cls.props, property="length", text="Length") + elif cls.props.ifc_class in ("IfcColumnType", "IfcBeamType", "IfcMemberType"): + row = cls.layout.row(align=True) + row.prop(data=cls.props, property="cardinal_point", text="Axis") - if ifc_classes: - row = layout.row(align=True) - row.label(text="", icon="EVENT_SHIFT") - row.label(text="", icon="EVENT_A") - op = row.operator("bim.add_constr_type_instance", text="Add") - op.from_invoke = True - op.ifc_class = ifc_class - if relating_type_id.isnumeric(): - op.relating_type_id = int(relating_type_id) + row = cls.layout.row(align=True) + label = "Height" if cls.props.ifc_class == "IfcColumn" else "Length" + row.prop(data=cls.props, property="extrusion_depth", text=label) + elif cls.props.ifc_class in ("IfcWindowType", "IfcWindowStyle", "IfcDoorType", "IfcDoorStyle"): + row = cls.layout.row(align=True) + row.prop(data=cls.props, property="rl", text="RL") + @classmethod + def draw_edit_object_interface(cls, context): if AuthoringData.data["active_class"] in ("IfcWall", "IfcWallStandardCase"): - row = layout.row(align=True) - row.prop(data=props, property="extrusion_depth", text="Height") + row = cls.layout.row(align=True) + row.prop(data=cls.props, property="extrusion_depth", text="Height") op = row.operator("bim.change_extrusion_depth", icon="FILE_REFRESH", text="") - op.depth = props.extrusion_depth + op.depth = cls.props.extrusion_depth - row = layout.row(align=True) - row.prop(data=props, property="length", text="Length") + row = cls.layout.row(align=True) + row.prop(data=cls.props, property="length", text="Length") op = row.operator("bim.change_layer_length", icon="FILE_REFRESH", text="") - op.length = props.length + op.length = cls.props.length - row = layout.row(align=True) + row = cls.layout.row(align=True) row.label(text="", icon="EVENT_SHIFT") row.label(text="", icon="EVENT_E") row.operator("bim.hotkey", text="Extend").hotkey = "S_E" - row = layout.row(align=True) + row = cls.layout.row(align=True) row.label(text="", icon="EVENT_SHIFT") row.label(text="", icon="EVENT_T") row.operator("bim.hotkey", text="Butt").hotkey = "S_T" - row = layout.row(align=True) + row = cls.layout.row(align=True) row.label(text="", icon="EVENT_SHIFT") row.label(text="", icon="EVENT_Y") row.operator("bim.hotkey", text="Mitre").hotkey = "S_Y" - row = layout.row(align=True) + row = cls.layout.row(align=True) row.label(text="", icon="EVENT_SHIFT") row.label(text="", icon="EVENT_M") row.operator("bim.hotkey", text="Merge").hotkey = "S_M" - row = layout.row(align=True) + row = cls.layout.row(align=True) row.label(text="", icon="EVENT_SHIFT") row.label(text="", icon="EVENT_F") row.operator("bim.hotkey", text="Flip").hotkey = "S_F" - row = layout.row(align=True) + row = cls.layout.row(align=True) row.label(text="", icon="EVENT_SHIFT") row.label(text="", icon="EVENT_S") row.operator("bim.hotkey", text="Split").hotkey = "S_S" - row = layout.row(align=True) + row = cls.layout.row(align=True) row.label(text="", icon="EVENT_SHIFT") row.label(text="", icon="EVENT_G") row.operator("bim.hotkey", text="Regen").hotkey = "S_G" row.operator("bim.join_wall", icon="X", text="").join_type = "" elif AuthoringData.data["active_class"] in ("IfcSlab", "IfcSlabStandardCase"): - if not context.active_object: - pass - elif context.active_object.mode == "OBJECT": - row = layout.row(align=True) + if context.active_object.mode == "OBJECT": + row = cls.layout.row(align=True) row.label(text="", icon="EVENT_SHIFT") row.label(text="", icon="EVENT_E") row.operator("bim.hotkey", text="Edit Profile").hotkey = "S_E" @@ -195,34 +168,34 @@ class BimTool(WorkSpaceTool): "IfcMember", "IfcMemberStandardCase", ): - row = layout.row(align=True) - row.prop(data=props, property="cardinal_point", text="Axis") + row = cls.layout.row(align=True) + row.prop(data=cls.props, property="cardinal_point", text="Axis") op = row.operator("bim.change_cardinal_point", icon="FILE_REFRESH", text="") - op.cardinal_point = int(props.cardinal_point) + op.cardinal_point = int(cls.props.cardinal_point) - row = layout.row(align=True) - label = "Height" if ifc_class == "IfcColumnType" else "Length" - row.prop(data=props, property="extrusion_depth", text=label) + row = cls.layout.row(align=True) + label = "Height" if AuthoringData.data["active_class"] in ("IfcColumn", "IfcColumnStandardCase") else "Length" + row.prop(data=cls.props, property="extrusion_depth", text=label) op = row.operator("bim.change_profile_depth", icon="FILE_REFRESH", text="") - op.depth = props.extrusion_depth + op.depth = cls.props.extrusion_depth - row = layout.row(align=True) + row = cls.layout.row(align=True) row.label(text="", icon="EVENT_SHIFT") row.label(text="", icon="EVENT_E") row.operator("bim.hotkey", text="Extend").hotkey = "S_E" - row = layout.row(align=True) + row = cls.layout.row(align=True) row.label(text="", icon="EVENT_SHIFT") row.label(text="", icon="EVENT_T") row.operator("bim.hotkey", text="Butt").hotkey = "S_T" - row = layout.row(align=True) + row = cls.layout.row(align=True) row.label(text="", icon="EVENT_SHIFT") row.label(text="", icon="EVENT_Y") row.operator("bim.hotkey", text="Mitre").hotkey = "S_Y" - row = layout.row(align=True) + row = cls.layout.row(align=True) row.label(text="", icon="EVENT_SHIFT") row.label(text="", icon="EVENT_R") row.operator("bim.hotkey", text="Rotate 90").hotkey = "S_R" - row = layout.row(align=True) + row = cls.layout.row(align=True) row.label(text="", icon="EVENT_SHIFT") row.label(text="", icon="EVENT_G") row.operator("bim.hotkey", text="Regen").hotkey = "S_G" @@ -233,25 +206,24 @@ class BimTool(WorkSpaceTool): "IfcDoor", "IfcDoorStandardCase", ): - row = layout.row(align=True) - row.prop(data=props, property="rl", text="RL") + row = cls.layout.row(align=True) + row.prop(data=cls.props, property="rl", text="RL") - row = layout.row(align=True) + row = cls.layout.row(align=True) row.label(text="", icon="EVENT_SHIFT") row.label(text="", icon="EVENT_G") row.operator("bim.hotkey", text="Regen").hotkey = "S_G" - - if props.ifc_class in ( + elif AuthoringData.data["active_class"] in ( "IfcCableCarrierSegmentType", "IfcCableSegmentType", "IfcDuctSegmentType", "IfcPipeSegmentType", ): - row = layout.row(align=True) + row = cls.layout.row(align=True) row.label(text="", icon="EVENT_SHIFT") row.label(text="Extend", icon="EVENT_E") - row = layout.row(align=True) + row = cls.layout.row(align=True) row.label(text="", icon="EVENT_SHIFT") row.label(text="", icon="EVENT_O") if len(context.selected_objects) == 2: @@ -265,30 +237,90 @@ class BimTool(WorkSpaceTool): else: row.operator("bim.show_openings", icon="HIDE_OFF", text="") - row = layout.row(align=True) + row = cls.layout.row(align=True) row.label(text="Align") - row = layout.row(align=True) + row = cls.layout.row(align=True) row.label(text="", icon="EVENT_SHIFT") row.label(text="Align Exterior", icon="EVENT_X") - row = layout.row(align=True) + row = cls.layout.row(align=True) row.label(text="", icon="EVENT_SHIFT") row.label(text="Align Centerline", icon="EVENT_C") - row = layout.row(align=True) + row = cls.layout.row(align=True) row.label(text="", icon="EVENT_SHIFT") row.label(text="Align Interior", icon="EVENT_V") - row = layout.row(align=True) + row = cls.layout.row(align=True) - row = layout.row(align=True) + row = cls.layout.row(align=True) row.label(text="Mode") - row = layout.row(align=True) + row = cls.layout.row(align=True) row.label(text="", icon="EVENT_ALT") row.label(text="", icon="EVENT_O") row.operator("bim.hotkey", text="Void").hotkey = "A_O" - row = layout.row(align=True) + row = cls.layout.row(align=True) row.label(text="", icon="EVENT_ALT") row.label(text="", icon="EVENT_D") row.operator("bim.hotkey", text="Decomposition").hotkey = "A_D" + @classmethod + def draw_header_interface(cls): + row = cls.layout.row(align=True) + if AuthoringData.data["ifc_classes"]: + row.label(text="", icon="FILE_VOLUME") + row.prop(data=cls.props, property="ifc_class", text="") + else: + row.label(text="No Construction Class", icon="FILE_VOLUME") + row = cls.layout.row(align=True) + if AuthoringData.data["relating_types_ids"]: + row.label(text="", icon="FILE_3D") + prop_with_search(row, cls.props, "relating_type_id", text="") + row.operator("bim.launch_type_manager", icon="LIGHTPROBE_GRID", text="") + else: + row.label(text="No Construction Type", icon="FILE_3D") + if AuthoringData.data["ifc_classes"]: + #row = cls.layout.row() + #row.operator("bim.display_constr_types", icon="TRIA_DOWN", text="") + + row = cls.layout.row(align=True) + row.label(text="", icon="EVENT_SHIFT") + row.label(text="", icon="EVENT_A") + op = row.operator("bim.add_constr_type_instance", text="Add") + op.from_invoke = True + op.ifc_class = cls.props.ifc_class + if cls.props.relating_type_id.isnumeric(): + op.relating_type_id = int(cls.props.relating_type_id) + + @classmethod + def draw_sidebar_interface(cls): + row = cls.layout.row(align=True) + if AuthoringData.data["ifc_classes"]: + row.label(text="", icon="FILE_VOLUME") + prop_with_search(row, cls.props, "ifc_class", text="") + else: + row.label(text="No Construction Class", icon="FILE_VOLUME") + row = cls.layout.row(align=True) + if AuthoringData.data["relating_types_ids"]: + row.label(text="", icon="FILE_3D") + prop_with_search(row, cls.props, "relating_type_id", text="") + else: + row.label(text="No Construction Type", icon="FILE_3D") + + box = cls.layout.box() + if AuthoringData.data["type_thumbnail"]: + box.template_icon(icon_value=AuthoringData.data["type_thumbnail"], scale=5) + else: + op = box.operator("bim.load_type_thumbnails", text="Load Thumbnails", icon="FILE_REFRESH") + op.ifc_class = cls.props.ifc_class + + if AuthoringData.data["ifc_classes"]: + row = cls.layout.row(align=True) + row.label(text="", icon="EVENT_SHIFT") + row.label(text="", icon="EVENT_A") + op = row.operator("bim.add_constr_type_instance", text="Add") + op.from_invoke = True + op.ifc_class = cls.props.ifc_class + if cls.props.relating_type_id.isnumeric(): + op.relating_type_id = int(cls.props.relating_type_id) + class Hotkey(bpy.types.Operator, tool.Ifc.Operator): bl_idname = "bim.hotkey" diff --git a/src/blenderbim/blenderbim/bim/module/project/operator.py b/src/blenderbim/blenderbim/bim/module/project/operator.py index b547556f10..71cd8a2416 100644 --- a/src/blenderbim/blenderbim/bim/module/project/operator.py +++ b/src/blenderbim/blenderbim/bim/module/project/operator.py @@ -56,10 +56,6 @@ class CreateProject(bpy.types.Operator): props = context.scene.BIMProjectProperties template = None if props.template_file == "0" else props.template_file core.create_project(tool.Ifc, tool.Project, schema=props.export_schema, template=template) - # Load thumbnails for the first time - if tool.Ifc.get().by_type("IfcElementType"): - ifc_class = sorted(tool.Ifc.get().by_type("IfcElementType"), key=lambda e: e.is_a())[0].is_a() - bpy.ops.bim.load_type_thumbnails(ifc_class=ifc_class) def rollback(self, data): IfcStore.file = None @@ -596,10 +592,9 @@ class LoadProjectElements(bpy.types.Operator): print("Import finished in {:.2f} seconds".format(time.time() - start)) context.scene.BIMProjectProperties.is_loading = False - # Load thumbnails for the first time - if tool.Ifc.get().by_type("IfcElementType"): - ifc_class = sorted(tool.Ifc.get().by_type("IfcElementType"), key=lambda e: e.is_a())[0].is_a() - bpy.ops.bim.load_type_thumbnails(ifc_class=ifc_class) + tool.Project.load_default_thumbnails() + tool.Project.set_default_context() + tool.Project.set_default_modeling_dimensions() return {"FINISHED"} def get_decomposition_elements(self): diff --git a/src/blenderbim/blenderbim/core/project.py b/src/blenderbim/blenderbim/core/project.py index 7ef7766146..56a20731f9 100644 --- a/src/blenderbim/blenderbim/core/project.py +++ b/src/blenderbim/blenderbim/core/project.py @@ -74,3 +74,7 @@ def create_project(ifc, project, schema=None, template=None): if template: project.append_all_types_from_template(template) + + project.load_default_thumbnails() + project.set_default_context() + project.set_default_modeling_dimensions() diff --git a/src/blenderbim/blenderbim/core/tool.py b/src/blenderbim/blenderbim/core/tool.py index 6dd74b103e..edd7e4c01d 100644 --- a/src/blenderbim/blenderbim/core/tool.py +++ b/src/blenderbim/blenderbim/core/tool.py @@ -379,6 +379,7 @@ class Owner: class Project: def append_all_types_from_template(cls, template): pass def create_empty(cls, name): pass + def load_default_thumbnails(cls): pass def run_aggregate_assign_object(cls, relating_obj=None, related_obj=None): pass def run_context_add_context(cls, context_type=None, context_identifier=None, target_view=None, parent=None): pass def run_owner_add_organisation(cls): pass @@ -389,6 +390,8 @@ class Project: def run_unit_assign_scene_units(cls): pass def set_active_spatial_element(cls, obj): pass def set_context(cls, context): pass + def set_default_context(cls): pass + def set_default_modeling_dimensions(cls): pass @interface diff --git a/src/blenderbim/blenderbim/tool/project.py b/src/blenderbim/blenderbim/tool/project.py index 850c7aab24..f0418d58e3 100644 --- a/src/blenderbim/blenderbim/tool/project.py +++ b/src/blenderbim/blenderbim/tool/project.py @@ -18,6 +18,8 @@ import os import bpy +import ifcopenshell +import ifcopenshell.util.unit import blenderbim.core.tool import blenderbim.tool as tool from blenderbim.bim.ifc import IfcStore @@ -36,6 +38,12 @@ class Project(blenderbim.core.tool.Project): def create_empty(cls, name): return bpy.data.objects.new(name, None) + @classmethod + def load_default_thumbnails(cls): + if tool.Ifc.get().by_type("IfcElementType"): + ifc_class = sorted(tool.Ifc.get().by_type("IfcElementType"), key=lambda e: e.is_a())[0].is_a() + bpy.ops.bim.load_type_thumbnails(ifc_class=ifc_class) + @classmethod def run_aggregate_assign_object(cls, relating_obj=None, related_obj=None): return blenderbim.core.aggregate.assign_object( @@ -114,3 +122,20 @@ class Project(blenderbim.core.tool.Project): def set_context(cls, context): blenderbim.bim.handler.refresh_ui_data() bpy.context.scene.BIMRootProperties.contexts = str(context.id()) + + @classmethod + def set_default_context(cls): + context = ifcopenshell.util.representation.get_context(tool.Ifc.get(), "Model", "Body", "MODEL_VIEW") + if context: + bpy.context.scene.BIMRootProperties.contexts = str(context.id()) + + @classmethod + def set_default_modeling_dimensions(cls): + props = bpy.context.scene.BIMModelProperties + unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get()) + props.extrusion_depth = 3 / unit_scale + props.length = 1 / unit_scale + props.rl = 1 / unit_scale + props.x = 0.5 / unit_scale + props.y = 0.5 / unit_scale + props.z = 0.5 / unit_scale diff --git a/src/blenderbim/test/core/test_project.py b/src/blenderbim/test/core/test_project.py index 301b012466..3d899ccb83 100644 --- a/src/blenderbim/test/core/test_project.py +++ b/src/blenderbim/test/core/test_project.py @@ -77,6 +77,10 @@ class TestCreateProject: project.set_context("body").should_be_called() project.set_active_spatial_element("storey").should_be_called() + project.load_default_thumbnails().should_be_called() + project.set_default_context().should_be_called() + project.set_default_modeling_dimensions().should_be_called() + subject.create_project(ifc, project, schema="IFC4", template=None) def test_appending_project_template_types_if_specified(self, ifc, project): @@ -132,6 +136,10 @@ class TestCreateProject: project.append_all_types_from_template("template").should_be_called() + project.load_default_thumbnails().should_be_called() + project.set_default_context().should_be_called() + project.set_default_modeling_dimensions().should_be_called() + subject.create_project(ifc, project, schema="IFC4", template="template") def test_create_an_ifc2x3_project_with_owner_defaults(self, ifc, project): @@ -192,4 +200,8 @@ class TestCreateProject: project.set_context("body").should_be_called() project.set_active_spatial_element("storey").should_be_called() + project.load_default_thumbnails().should_be_called() + project.set_default_context().should_be_called() + project.set_default_modeling_dimensions().should_be_called() + subject.create_project(ifc, project, schema="IFC2X3", template=None) diff --git a/src/blenderbim/test/tool/test_project.py b/src/blenderbim/test/tool/test_project.py index a6fea4ef42..8398693364 100644 --- a/src/blenderbim/test/tool/test_project.py +++ b/src/blenderbim/test/tool/test_project.py @@ -42,6 +42,11 @@ class TestCreateEmpty(NewFile): assert not bpy.data.objects.get("Foobar").data +class TestLoadDefaultThumbnails(NewFile): + def test_nothing(self): + pass # Not possible to test this headlessly + + class TestRunAggregateAssignObject(NewFile): def test_nothing(self): pass @@ -101,3 +106,30 @@ class TestSetContext(NewFile): context = ifc.createIfcGeometricRepresentationContext() subject.set_context(context) assert bpy.context.scene.BIMRootProperties.contexts == str(context.id()) + + +class TestSetDefaultContext(NewFile): + def test_run(self): + ifc = ifcopenshell.file() + tool.Ifc.set(ifc) + ifc.createIfcProject() + model = ifcopenshell.api.run("context.add_context", ifc, context_type="Model") + body = ifcopenshell.api.run("context.add_context", ifc, parent=model, context_type="Model", context_identifier="Body", target_view="MODEL_VIEW") + subject.set_default_context() + assert bpy.context.scene.BIMRootProperties.contexts == str(body.id()) + + +class TestSetDefaultModelingDimensions(NewFile): + def test_run(self): + ifc = ifcopenshell.file() + tool.Ifc.set(ifc) + ifc.createIfcProject() + ifcopenshell.api.run("unit.assign_unit", ifc) + subject.set_default_modeling_dimensions() + props = bpy.context.scene.BIMModelProperties + assert props.extrusion_depth == 3000 + assert props.length == 1000 + assert props.rl == 1000 + assert props.x == 500 + assert props.y == 500 + assert props.z == 500 diff --git a/src/ifcopenshell-python/ifcopenshell/util/unit.py b/src/ifcopenshell-python/ifcopenshell/util/unit.py index 4ca430056d..59928a7412 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/unit.py +++ b/src/ifcopenshell-python/ifcopenshell/util/unit.py @@ -477,6 +477,8 @@ def calculate_unit_scale(file): :returns: The scale factor :rtype: float """ + if not file.by_type("IfcUnitAssignment"): + return 1 units = file.by_type("IfcUnitAssignment")[0] unit_scale = 1 for unit in units.Units: