From 38f563d4f4297b6437461b7b7f9749b1ac10e65b Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Tue, 11 Oct 2022 13:49:46 +1100 Subject: [PATCH] New timerless thumbnailed type manager. --- .../blenderbim/bim/module/model/__init__.py | 9 ++- .../blenderbim/bim/module/model/data.py | 56 ++++++++++++++-- .../blenderbim/bim/module/model/product.py | 19 ++++-- .../blenderbim/bim/module/model/prop.py | 5 ++ .../blenderbim/bim/module/model/ui.py | 64 ++++++++++++++++++- .../blenderbim/bim/module/model/wall.py | 2 +- .../blenderbim/bim/module/model/workspace.py | 4 +- 7 files changed, 139 insertions(+), 20 deletions(-) diff --git a/src/blenderbim/blenderbim/bim/module/model/__init__.py b/src/blenderbim/blenderbim/bim/module/model/__init__.py index cfaf0353c7..5d4a2009e6 100644 --- a/src/blenderbim/blenderbim/bim/module/model/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/model/__init__.py @@ -20,12 +20,14 @@ import bpy from . import handler, prop, ui, grid, product, wall, slab, stair, opening, pie, workspace, profile classes = ( - product.AddEmptyType, product.AddConstrTypeInstance, - product.DisplayConstrTypes, - product.ReinvokeOperator, + product.AddEmptyType, product.AlignProduct, + product.ChangeTypePage, + product.DisplayConstrTypes, product.DynamicallyVoidProduct, + product.LoadTypeThumbnails, + product.ReinvokeOperator, workspace.Hotkey, wall.AlignWall, wall.ChangeExtrusionDepth, @@ -65,6 +67,7 @@ classes = ( prop.BIMModelProperties, ui.BIM_PT_authoring, ui.DisplayConstrTypesUI, + ui.LaunchTypeManager, ui.HelpConstrTypes, ui.BIM_MT_model, grid.BIM_OT_add_object, diff --git a/src/blenderbim/blenderbim/bim/module/model/data.py b/src/blenderbim/blenderbim/bim/module/model/data.py index b7ee343f83..ec7012adfc 100644 --- a/src/blenderbim/blenderbim/bim/module/model/data.py +++ b/src/blenderbim/blenderbim/bim/module/model/data.py @@ -16,8 +16,9 @@ # You should have received a copy of the GNU General Public License # along with BlenderBIM Add-on. If not, see . -import functools import bpy +import math +import functools import blenderbim.tool as tool from blenderbim.bim.ifc import IfcStore from blenderbim.bim.module.model.root import ConstrTypeEntityNotFound @@ -30,6 +31,7 @@ def refresh(): class AuthoringData: data = {} type_thumbnails = {} + types_per_page = 9 is_loaded = False @classmethod @@ -39,6 +41,11 @@ class AuthoringData: cls.load_ifc_classes() cls.load_relating_types() cls.load_relating_types_browser() + cls.data["total_types"] = cls.total_types() + cls.data["total_pages"] = cls.total_pages() + cls.data["next_page"] = cls.next_page() + cls.data["prev_page"] = cls.prev_page() + cls.data["paginated_relating_types"] = cls.paginated_relating_types() cls.data["type_thumbnail"] = cls.type_thumbnail() cls.data["is_voidable_element"] = cls.is_voidable_element() cls.data["has_visible_openings"] = cls.has_visible_openings() @@ -46,13 +53,9 @@ class AuthoringData: @classmethod def type_thumbnail(cls): - props = bpy.context.scene.BIMModelProperties - if not props.relating_type_id: - return 0 - element = tool.Ifc.get().by_id(int(props.relating_type_id)) - obj = tool.Ifc.get_object(element) - if not obj: + if not cls.props.relating_type_id: return 0 + element = tool.Ifc.get().by_id(int(cls.props.relating_type_id)) return cls.type_thumbnails.get(element.id(), None) or 0 @classmethod @@ -67,6 +70,45 @@ class AuthoringData: def load_relating_types_browser(cls): cls.data["relating_types_ids_browser"] = cls.relating_types_browser() + @classmethod + def total_types(cls): + ifc_class = cls.props.ifc_class + return len(tool.Ifc.get().by_type(ifc_class)) if ifc_class else 0 + + @classmethod + def total_pages(cls): + ifc_class = cls.props.ifc_class + total_types = len(tool.Ifc.get().by_type(ifc_class)) if ifc_class else 0 + return math.ceil(total_types / cls.types_per_page) + + @classmethod + def next_page(cls): + if cls.props.type_page < cls.total_pages(): + return cls.props.type_page + 1 + + @classmethod + def prev_page(cls): + if cls.props.type_page > 1: + return cls.props.type_page - 1 + + @classmethod + def paginated_relating_types(cls): + ifc_class = cls.props.ifc_class + if not ifc_class: + return [] + results = [] + elements = sorted(tool.Ifc.get().by_type(ifc_class), key=lambda e: e.Name or "Unnamed") + elements = elements[(cls.props.type_page - 1) * cls.types_per_page:cls.props.type_page * cls.types_per_page] + for element in elements: + results.append({ + "id": element.id(), + "ifc_class": element.is_a(), + "name": element.Name or "Unnamed", + "description": element.Description or "No Description", + "icon_id": cls.type_thumbnails.get(element.id(), None) or 0, + }) + return results + @classmethod def is_voidable_element(cls): element = tool.Ifc.get_entity(bpy.context.active_object) diff --git a/src/blenderbim/blenderbim/bim/module/model/product.py b/src/blenderbim/blenderbim/bim/module/model/product.py index eabbbbbad8..011fdeedb5 100644 --- a/src/blenderbim/blenderbim/bim/module/model/product.py +++ b/src/blenderbim/blenderbim/bim/module/model/product.py @@ -194,6 +194,17 @@ class AddConstrTypeInstance(bpy.types.Operator): pass # Dumb block generator? Eh? :) +class ChangeTypePage(bpy.types.Operator, tool.Ifc.Operator): + bl_idname = "bim.change_type_page" + bl_label = "Change Type Page" + bl_options = {"REGISTER"} + page: bpy.props.IntProperty() + + def _execute(self, context): + context.scene.BIMModelProperties.type_page = self.page + return {"FINISHED"} + + class DisplayConstrTypes(bpy.types.Operator): bl_idname = "bim.display_constr_types" bl_label = "Browse Construction Types" @@ -408,13 +419,13 @@ class LoadTypeThumbnails(bpy.types.Operator, tool.Ifc.Operator): thicknesses = [l.LayerThickness for l in material.MaterialLayers] total_thickness = sum(thicknesses) si_total_thickness = total_thickness * unit_scale - if si_total_thickness < 0.05: + if si_total_thickness <= 0.051: width = 10 - elif si_total_thickness < 0.1: + elif si_total_thickness <= 0.11: width = 20 - elif si_total_thickness < 0.2: + elif si_total_thickness <= 0.21: width = 30 - elif si_total_thickness < 0.3: + elif si_total_thickness <= 0.31: width = 40 else: width = 50 diff --git a/src/blenderbim/blenderbim/bim/module/model/prop.py b/src/blenderbim/blenderbim/bim/module/model/prop.py index 9fd1963c41..6a71b4bf1a 100644 --- a/src/blenderbim/blenderbim/bim/module/model/prop.py +++ b/src/blenderbim/blenderbim/bim/module/model/prop.py @@ -94,6 +94,10 @@ def update_relating_type(self, context): AuthoringData.data["type_thumbnail"] = AuthoringData.type_thumbnail() +def update_type_page(self, context): + AuthoringData.data["paginated_relating_types"] = AuthoringData.paginated_relating_types() + + def update_relating_type_browser(self, context): AuthoringData.load_relating_types_browser() if not self.updating: @@ -201,3 +205,4 @@ class BIMModelProperties(PropertyGroup): y: bpy.props.FloatProperty(name="Y", default=0.5) z: bpy.props.FloatProperty(name="Z", default=0.5) rl: bpy.props.FloatProperty(name="RL", default=1) + type_page: bpy.props.IntProperty(name="Type Page", default=1, update=update_type_page) diff --git a/src/blenderbim/blenderbim/bim/module/model/ui.py b/src/blenderbim/blenderbim/bim/module/model/ui.py index 4605acc844..979a0150be 100644 --- a/src/blenderbim/blenderbim/bim/module/model/ui.py +++ b/src/blenderbim/blenderbim/bim/module/model/ui.py @@ -23,6 +23,66 @@ from blenderbim.bim.module.model.prop import store_cursor_position from blenderbim.bim.helper import prop_with_search, close_operator_panel +class LaunchTypeManager(bpy.types.Operator): + bl_idname = "bim.launch_type_manager" + bl_label = "Launch Type Manager" + bl_options = {"REGISTER"} + bl_description = "Display all available Construction Types to add new instances" + + def execute(self, context): + return {"FINISHED"} + + def invoke(self, context, event): + props = context.scene.BIMModelProperties + props.type_page = 1 + bpy.ops.bim.load_type_thumbnails(ifc_class=props.ifc_class) + if not AuthoringData.is_loaded: + AuthoringData.load() + return context.window_manager.invoke_popup(self, width=550) + + def draw(self, context): + props = context.scene.BIMModelProperties + + row = self.layout.row(align=True) + row.alignment = "RIGHT" + #row.label(text=f"", icon="FILE_VOLUME") + + text = f"{AuthoringData.data['total_types']} types" + if AuthoringData.data["total_pages"] > 1: + text += f" ({props.type_page}/{AuthoringData.data['total_pages']}) " + row.label(text=text) + + if AuthoringData.data["prev_page"]: + op = row.operator("bim.change_type_page", icon="TRIA_LEFT", text="") + op.page = AuthoringData.data["prev_page"] + if AuthoringData.data["next_page"]: + op = row.operator("bim.change_type_page", icon="TRIA_RIGHT", text="") + op.page = AuthoringData.data["next_page"] + + flow = self.layout.grid_flow(row_major=True, columns=3, even_columns=True, even_rows=True, align=True) + + for relating_type in AuthoringData.data["paginated_relating_types"]: + outer_col = flow.column() + box = outer_col.box() + + row = box.row() + row.alignment = "CENTER" + row.label(text=relating_type["name"], icon="FILE_3D") + + row = box.row() + row.alignment = "CENTER" + row.label(text=relating_type["description"]) + + row = box.row() + row.template_icon(icon_value=relating_type["icon_id"], scale=4) + + row = box.row() + op = row.operator("bim.add_constr_type_instance", icon="ADD") + op.from_invoke = True + op.ifc_class = relating_type["ifc_class"] + op.relating_type_id = relating_type["id"] + + class BIM_PT_authoring(Panel): bl_label = "Architectural" bl_idname = "BIM_PT_authoring" @@ -58,9 +118,7 @@ class DisplayConstrTypesUI(Operator): browser_state.updating = True def run_operator(): - bpy.ops.bim.reinvoke_operator( - "INVOKE_DEFAULT", operator="bim.display_constr_types_ui" - ) + bpy.ops.bim.reinvoke_operator("INVOKE_DEFAULT", operator="bim.display_constr_types_ui") browser_state.updating = False if not browser_state.updating: diff --git a/src/blenderbim/blenderbim/bim/module/model/wall.py b/src/blenderbim/blenderbim/bim/module/model/wall.py index f9093893ca..78e8bcc746 100644 --- a/src/blenderbim/blenderbim/bim/module/model/wall.py +++ b/src/blenderbim/blenderbim/bim/module/model/wall.py @@ -757,7 +757,7 @@ class DumbWallJoiner: axis1["reference"][0], axis1["reference"][1] = axis1["reference"][1], axis1["reference"][0] flip_matrix = Matrix.Rotation(pi, 4, "Z") - wall1.rotation_euler.rotate(flip_matrix) + wall1.matrix_world = wall1.matrix_world @ flip_matrix bpy.context.view_layer.update() self.recreate_wall(element1, wall1, axis1["reference"], axis1["reference"]) diff --git a/src/blenderbim/blenderbim/bim/module/model/workspace.py b/src/blenderbim/blenderbim/bim/module/model/workspace.py index 6c20a3a320..15e3ba0fd8 100644 --- a/src/blenderbim/blenderbim/bim/module/model/workspace.py +++ b/src/blenderbim/blenderbim/bim/module/model/workspace.py @@ -93,6 +93,7 @@ class BimTool(WorkSpaceTool): 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: @@ -121,11 +122,10 @@ class BimTool(WorkSpaceTool): else: row.label(text="No Construction Type", icon="FILE_3D") + box = layout.box() if AuthoringData.data["type_thumbnail"]: - box = layout.box() box.template_icon(icon_value=AuthoringData.data["type_thumbnail"], scale=5) else: - box = layout.box() op = box.operator("bim.load_type_thumbnails", text="Load Thumbnails", icon="FILE_REFRESH") op.ifc_class = props.ifc_class