Improved version with optional cascading

This commit is contained in:
carlos
2022-07-10 07:46:30 +02:00
parent 8c9115c0ff
commit 618bed3889
6 changed files with 349 additions and 110 deletions
@@ -23,7 +23,8 @@ classes = (
product.AddEmptyType,
product.AddTypeInstance,
product.DisplayIFCTypes,
product.AddIFCTypeInstance,
product.SelectTypeInstance,
product.TypeInstanceHelp,
product.AlignProduct,
product.DynamicallyVoidProduct,
workspace.Hotkey,
@@ -36,7 +37,6 @@ classes = (
prop.BIMModelProperties,
prop.IfcTypeInfo,
ui.BIM_PT_authoring,
ui.BIM_PT_authoring_architectural,
grid.BIM_OT_add_object,
stair.BIM_OT_add_object,
opening.BIM_OT_add_object,
@@ -31,6 +31,7 @@ def refresh():
class AuthoringData:
data = {}
is_loaded = False
updating = False
@classmethod
def load(cls):
@@ -85,22 +86,33 @@ class AuthoringData:
def relating_types(cls, ifc_class=None):
return [(str(e.id()), e.Name, e.Description or "") for e in cls.ifc_class_entities(ifc_class=ifc_class)]
@staticmethod
def new_ifc_type_info(ifc_class):
ifc_type_info = bpy.context.scene.IfcTypeInfo.add()
ifc_type_info.name = ifc_class
return ifc_type_info
@classmethod
def assetize_relating_type_from_selection(cls):
props = bpy.context.scene.BIMModelProperties
ifc_class = props.ifc_class
relating_type_id = props.relating_type
ifc_class_occurrences = cls.ifc_class_entities(ifc_class=ifc_class)
ifc_class_occurrences = [entity for entity in ifc_class_occurrences if entity.id() == int(relating_type_id)]
if len(ifc_class_occurrences) == 0:
return
ifc_class_entity = ifc_class_occurrences[0]
obj = tool.Ifc.get_object(ifc_class_entity)
def assetize_ifc_class(cls, ifc_class=None):
if ifc_class is None:
props = bpy.context.scene.BIMModelProperties
ifc_class = props.ifc_class
ifc_type_info = cls.ifc_type_info(ifc_class)
_ = cls.new_ifc_type_info(ifc_class) if ifc_type_info is None else ifc_type_info
ifc_class_occurrences = cls.ifc_class_entities(ifc_class)
for ifc_class_entity in ifc_class_occurrences:
obj = tool.Ifc.get_object(ifc_class_entity)
cls.assetize_object(obj, ifc_class, ifc_class_entity)
ifc_type_info = cls.ifc_type_info(ifc_class)
ifc_type_info.fully_loaded = True
@classmethod
def assetize_object(cls, obj, ifc_class, ifc_class_entity, from_selection=False):
relating_type = ifc_class_entity.Name
to_be_deleted = False
if obj.type == 'EMPTY':
bpy.ops.bim.add_type_instance()
new_obj = bpy.context.selected_objects[-1]
kwargs = {} if from_selection else {'ifc_class': ifc_class, 'relating_type_id': ifc_class_entity.id()}
new_obj = cls.new_ifc_type_instance(**kwargs)
if new_obj is not None:
to_be_deleted = True
obj = new_obj
@@ -114,17 +126,37 @@ class AuthoringData:
for col in obj.users_collection:
col.objects.unlink(obj)
@classmethod
def assetize_relating_type_from_selection(cls):
props = bpy.context.scene.BIMModelProperties
ifc_class = props.ifc_class
relating_type_id = props.relating_type
ifc_class_occurrences = cls.ifc_class_entities(ifc_class=ifc_class)
ifc_class_occurrences = [entity for entity in ifc_class_occurrences if entity.id() == int(relating_type_id)]
if len(ifc_class_occurrences) == 0:
return False
ifc_class_entity = ifc_class_occurrences[0]
obj = tool.Ifc.get_object(ifc_class_entity)
if obj is None:
return False
cls.assetize_object(obj, ifc_class, ifc_class_entity, from_selection=True)
return True
@staticmethod
def ifc_type_info(ifc_class):
ifc_type_infos = [element for element in bpy.context.scene.IfcTypeInfo if element.ifc_class == ifc_class]
ifc_type_infos = [element for element in bpy.context.scene.IfcTypeInfo if element.name == ifc_class]
return None if len(ifc_type_infos) == 0 else ifc_type_infos[0]
@classmethod
def new_ifc_type_instance(cls, ifc_class, relating_type_id):
props = bpy.context.scene.BIMModelProperties
props.ifc_class = ifc_class
props.relating_type = str(relating_type_id)
def new_ifc_type_instance(cls, ifc_class=None, relating_type_id=None):
if ifc_class is not None:
cls.updating = True
props = bpy.context.scene.BIMModelProperties
props.ifc_class = ifc_class
props.relating_type = str(relating_type_id)
cls.updating = False
bpy.ops.bim.add_type_instance()
return bpy.context.selected_objects[-1]
@staticmethod
def relating_type_name_by_id(ifc_class, relating_type_id):
@@ -17,6 +17,7 @@
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
import bpy
import math
import mathutils
import ifcopenshell
import ifcopenshell.api
@@ -30,9 +31,11 @@ import blenderbim.core.geometry
from . import wall, slab, profile, mep
from blenderbim.bim.ifc import IfcStore
from blenderbim.bim.module.model.data import AuthoringData
from blenderbim.bim.helper import prop_with_search
from ifcopenshell.api.pset.data import Data as PsetData
from mathutils import Vector, Matrix
from bpy_extras.object_utils import AddObjectHelper
from . import prop
class AddEmptyType(bpy.types.Operator, AddObjectHelper):
@@ -54,13 +57,26 @@ def add_empty_type_button(self, context):
self.layout.operator(AddEmptyType.bl_idname, icon="FILE_3D")
def close_operator_panel(event):
x, y = event.mouse_x, event.mouse_y
bpy.context.window.cursor_warp(10, 10)
move_back = lambda: bpy.context.window.cursor_warp(x, y)
bpy.app.timers.register(move_back, first_interval=0.001)
class AddTypeInstance(bpy.types.Operator):
bl_idname = "bim.add_type_instance"
bl_label = "Add Type Instance"
bl_label = "Add"
bl_options = {"REGISTER", "UNDO"}
bl_description = "Add the selected Type Instance to the model"
bl_description = "Add Type Instance to the model"
ifc_class: bpy.props.StringProperty()
relating_type: bpy.props.IntProperty()
from_invoke: bpy.props.BoolProperty(default=False)
def invoke(self, context, event):
if self.from_invoke:
close_operator_panel(event)
return self.execute(context)
def execute(self, context):
return IfcStore.execute_ifc_operator(self, context)
@@ -176,7 +192,7 @@ class AddTypeInstance(bpy.types.Operator):
class DisplayIFCTypes(bpy.types.Operator):
bl_idname = "bim.display_ifc_types"
bl_label = "Browse IFC Types"
bl_label = "Browse IFC Construction Types"
bl_options = {"REGISTER", "UNDO"}
bl_description = "Display all possible IFC types for new instances"
@@ -188,67 +204,232 @@ class DisplayIFCTypes(bpy.types.Operator):
if not AuthoringData.is_loaded:
AuthoringData.load()
props = context.scene.BIMModelProperties
props.relating_type = props.relating_type
if props.unfold_relating_type:
ifc_class = props.ifc_class
ifc_type_info = AuthoringData.ifc_type_info(ifc_class)
if ifc_type_info is None or not ifc_type_info.fully_loaded:
AuthoringData.assetize_ifc_class(ifc_class)
else:
prop.update_relating_type(props, context)
min_width = 250
width = max([min_width, int(context.region.width / 7)])
width_scaling = 6. ** -1
width = max([min_width, int(width_scaling * context.region.width)])
return context.window_manager.invoke_popup(self, width=width)
def draw(self, context):
layout = self.layout
props = context.scene.BIMModelProperties
if props.unfold_relating_type:
self.draw_by_class(props)
else:
self.draw_by_class_and_relating_type(props)
def draw_header(self, props):
layout = self.layout
split = layout.split(align=True, factor=0.6)
col = split.column(align=True)
row = col.row()
row.label(text="Select IFC Type to add:")
col.row().separator(factor=2)
col1 = split.column(align=True)
row = col1.row()
row.prop(data=props, property="unfold_relating_type", text="Preview All Relating Types")
col1.row().separator(factor=0.5)
row = col1.row()
row.label(text="Select IFC Construction Type:")
col1.row().separator(factor=2)
enabled = True
if AuthoringData.data["ifc_classes"]:
row = col.row()
row.prop(data=props, property="ifc_class", text="", icon="FILE_VOLUME")
col.row().separator()
row = col1.row()
row.label(text="", icon="FILE_VOLUME")
prop_with_search(row, props, "ifc_class", text="")
col1.row().separator()
else:
enabled = False
col2 = split.column(align=True)
subsplit = col2.split(factor=0.9)
subcol = [subsplit.column() for _ in range(2)][-1]
subcol.operator("bim.type_instance_help", text="", icon="QUESTION")
col2.row().separator(factor=1)
return {"enabled": enabled, "layout": layout, "col1": col1, "col2": col2}
def draw_by_class(self, props):
header_data = self.draw_header(props)
enabled, layout = [header_data[key] for key in ["enabled", "layout"]]
ifc_class = props.ifc_class
num_cols = 3
layout.row().separator(factor=0.25)
flow = layout.grid_flow(row_major=True, columns=num_cols, even_columns=True, even_rows=True, align=True)
relating_types = AuthoringData.relating_types()
num_types = len(relating_types)
for idx, (rt_id, name, desc) in enumerate(relating_types):
outer_col = flow.column()
box = outer_col.box()
row = box.row()
row.label(text=name, icon="FILE_3D")
row.alignment = "CENTER"
row = box.row()
if enabled:
preview_ifc_types = AuthoringData.data["preview_ifc_types"]
if ifc_class in preview_ifc_types:
preview_ifc_class = preview_ifc_types[ifc_class]
if name in preview_ifc_class:
icon_id = preview_ifc_class[name]["icon_id"]
row.template_icon(icon_value=icon_id, scale=6.)
outer_col.row().separator(factor=0.5)
row = outer_col.row()
split = row.split(factor=0.5)
col = split.column()
op = col.operator("bim.select_type_instance", icon="RIGHTARROW_THIN")
op.ifc_class = ifc_class
op.relating_type_id = rt_id
col = split.column()
op = col.operator("bim.add_type_instance", icon="ADD")
op.from_invoke = True
op.ifc_class = ifc_class
if rt_id.isnumeric():
op.relating_type = int(rt_id)
factor = 2 if idx + 1 < math.ceil(num_types / num_cols) else 0.5
outer_col.row().separator(factor=factor)
last_row_cols = num_types % num_cols
if last_row_cols != 0:
for _ in range(num_cols - last_row_cols):
flow.column()
def draw_by_class_and_relating_type(self, props):
header_data = self.draw_header(props)
enabled, col1, col2 = [header_data[key] for key in ["enabled", "col1", "col2"]]
ifc_class = props.ifc_class
if AuthoringData.data["relating_types"]:
row = col.row()
row.prop(data=props, property="relating_type", text="", icon="FILE_3D")
col.row().separator()
row = col1.row()
row.label(text="", icon="FILE_3D")
prop_with_search(row, props, "relating_type", text="")
col1.row().separator()
else:
enabled = False
col.row().separator(factor=4)
row = col.row()
op = row.operator("bim.add_ifc_type_instance", icon="ADD")
col1.row().separator(factor=4.75)
row = col1.row()
row.enabled = enabled
op.ifc_class = props.ifc_class
op = row.operator("bim.select_type_instance", icon="RIGHTARROW_THIN")
op.ifc_class = ifc_class
op.relating_type_id = props.relating_type
col = split.column()
box = col.box()
op = row.operator("bim.add_type_instance", icon="ADD")
op.from_invoke = True
op.ifc_class = ifc_class
relating_type = props.relating_type
if relating_type.isnumeric():
op.relating_type = int(relating_type)
box = col2.box()
if enabled:
box.template_icon(icon_value=props.icon_id, scale=6.)
class AddIFCTypeInstance(bpy.types.Operator):
bl_idname = "bim.add_ifc_type_instance"
bl_label = "Add"
class SelectTypeInstance(bpy.types.Operator):
bl_idname = "bim.select_type_instance"
bl_label = "Select"
bl_options = {"REGISTER", "UNDO"}
bl_description = "Add an instance of this IFC type"
bl_description = "Pick Type Instance as selection for subsequent operations"
ifc_class: bpy.props.StringProperty()
relating_type_id: bpy.props.StringProperty()
def close_panel(self, event):
x, y = event.mouse_x, event.mouse_y
bpy.context.window.cursor_warp(10, 10)
move_back = lambda: bpy.context.window.cursor_warp(x, y)
bpy.app.timers.register(move_back, first_interval=0.001)
def invoke(self, context, event):
self.close_panel(event)
close_operator_panel(event)
return self.execute(context)
def execute(self, context):
props = context.scene.BIMModelProperties
props.ifc_class, props.relating_type = self.ifc_class, self.relating_type_id
bpy.ops.bim.add_type_instance()
return {'FINISHED'}
if self.ifc_class != "":
props.ifc_class = self.ifc_class
if self.relating_type_id != "":
props.relating_type = self.relating_type_id
return {"FINISHED"}
class TypeInstanceHelp(bpy.types.Operator):
bl_idname = "bim.type_instance_help"
bl_label = "IFC Construction Type Help"
bl_options = {"REGISTER", "UNDO"}
bl_description = "Click to read some contextual help"
def execute(self, context):
return {"FINISHED"}
def invoke(self, context, event):
return context.window_manager.invoke_popup(self, width=525)
def draw(self, context):
layout = self.layout
layout.row().separator(factor=0.5)
row = layout.row()
row.alignment = "CENTER"
row.label(text="BlenderBIM Help", icon="BLENDER")
row = layout.row()
row.alignment = "CENTER"
row.label(text="[IFC Construction Type Browser]")
layout.row().separator(factor=0.5)
row = self.col_with_margins(layout.row()).row()
row.label(text="When to use:", icon="KEYTYPE_MOVING_HOLD_VEC")
self.draw_lines(layout, self.message_purpose)
layout.row().separator()
row = self.col_with_margins(layout.row()).row()
row.label(text="Overall workflow:", icon="KEYTYPE_MOVING_HOLD_VEC")
self.draw_lines(layout, self.message_overall)
layout.row().separator()
row = self.col_with_margins(layout.row()).row()
row.label(text="UI panel hints:", icon="KEYTYPE_MOVING_HOLD_VEC")
self.draw_lines(layout, self.message_ui)
layout.row().separator(factor=1.5)
row = self.col_with_margins(layout.row()).row()
row.label(text="Further help:", icon="KEYTYPE_MOVING_HOLD_VEC")
layout.row().separator(factor=0.5)
row = self.col_with_margins(layout).row()
op = row.operator("bim.open_upstream", text="Homepage", icon="HOME")
op.page = "home"
op = row.operator("bim.open_upstream", text="Docs", icon="DOCUMENTS")
op.page = "docs"
op = row.operator("bim.open_upstream", text="Wiki", icon="CURRENT_FILE")
op.page = "wiki"
op = row.operator("bim.open_upstream", text="Community", icon="COMMUNITY")
op.page = "community"
layout.row().separator()
@staticmethod
def col_with_margins(layout, margin_left=0.025, margin_right=None):
margin_right = margin_left if margin_right is None else margin_right
split = layout.split(factor=margin_left, align=True)
col = [split.column() for _ in range(2)][-1]
subsplit = col.split(factor=(1. - margin_right), align=True)
subcol = subsplit.column()
subsplit.column().label(text="")
return subcol
def draw_lines(self, layout, lines):
box = self.col_with_margins(layout).box()
for line in lines:
row = box.row()
row.label(text="", icon="RIGHTARROW_THIN")
row.label(text=line)
@property
def message_purpose(self):
return [
'Available IFC Construction Types can be previewed and added through the button',
'"Browse IFC Construction Types", which appears when an IFC Project Library,',
'containing in turn definitions of construction types, is loaded. In order to ',
'manage loaded IFC Project Libraries, navigate to [Scene Properties] -> [IFC',
'Project Setup] -> [IFC Project Library] under the Properties panel.'
]
@property
def message_overall(self):
return [
'Choose an IFC Construction Type by picking 1) an IFC Class and 2) a Relating Type. ',
'Then, click on the "Add" button to directly add one instance of the chosen type to',
'the model, or alternatively click on the "Select" button to be able to later add ',
'several instances with SHIFT + A.'
]
@property
def message_ui(self):
return [
'If "Preview All Relating Types" is marked, a preview for every Relating Type will',
'be shown at once. Not advisable on large projects with dozens of types per class.'
]
class AlignProduct(bpy.types.Operator):
@@ -44,16 +44,25 @@ def update_icon_id(self, context):
if ((ifc_class not in AuthoringData.data["preview_ifc_types"]
or relating_type not in AuthoringData.data["preview_ifc_types"][ifc_class])
and relating_type is not None):
AuthoringData.assetize_relating_type_from_selection()
if not AuthoringData.assetize_relating_type_from_selection():
return
props = bpy.context.scene.BIMModelProperties
props.icon_id = AuthoringData.data["preview_ifc_types"][ifc_class][relating_type]["icon_id"]
def update_ifc_class(self, context):
AuthoringData.load_ifc_classes()
AuthoringData.load_relating_types()
self.relating_type = AuthoringData.data["relating_types"][0][0]
update_icon_id(self, context)
if not AuthoringData.updating:
AuthoringData.load_ifc_classes()
AuthoringData.load_relating_types()
props = context.scene.BIMModelProperties
if props.unfold_relating_type:
ifc_class = props.ifc_class
ifc_type_info = AuthoringData.ifc_type_info(ifc_class)
if ifc_type_info is None or not ifc_type_info.fully_loaded:
AuthoringData.assetize_ifc_class(ifc_class)
else:
self.relating_type = AuthoringData.data["relating_types"][0][0]
update_icon_id(self, context)
def update_relating_type(self, context):
@@ -61,26 +70,45 @@ def update_relating_type(self, context):
update_icon_id(self, context)
def update_unfold_relating_type(self, context):
update_ifc_class(self, context)
# if self.unfold_relating_type:
# props = context.scene.BIMModelProperties
# ifc_class = props.ifc_class
# ifc_type_info = AuthoringData.ifc_type_info(ifc_class)
# if ifc_type_info is None or not ifc_type_info.fully_loaded:
# AuthoringData.assetize_ifc_class(ifc_class)
# else:
# update_ifc_class(self, context)
class BIMModelProperties(PropertyGroup):
ifc_class: bpy.props.EnumProperty(items=get_ifc_class, name="IFC Class", update=update_ifc_class)
relating_type: bpy.props.EnumProperty(items=get_relating_type, name="Relating Type", update=update_relating_type)
icon_id: bpy.props.IntProperty()
unfold_relating_type: bpy.props.BoolProperty(update=update_unfold_relating_type)
occurrence_name_style: bpy.props.EnumProperty(
items=[("CLASS", "By Class", ""), ("TYPE", "By Type", ""), ("CUSTOM", "Custom", "")],
name="Occurrence Name Style",
)
occurrence_name_function: bpy.props.StringProperty(name="Occurrence Name Function")
getter_enum = {
"ifc_class": get_ifc_class,
"relating_type": get_relating_type
}
def get_ifc_type_info_relating_types(self, context):
ifc_class = self.ifc_class
ifc_class = self.name
return AuthoringData.relating_types(ifc_class=ifc_class)
class IfcTypeInfo(PropertyGroup):
ifc_class: bpy.props.StringProperty(name="IFC class", description="IFC class")
name: bpy.props.StringProperty(name="IFC class", description="IFC class")
relating_type: bpy.props.EnumProperty(
name="Relating type", description="Relating type", items=get_ifc_type_info_relating_types
)
fully_loaded: bpy.props.BoolProperty(default=False)
@@ -16,54 +16,15 @@
# You should have received a copy of the GNU General Public License
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
import blenderbim.bim.module.type.prop as type_prop
from bpy.types import Panel
from blenderbim.bim.ifc import IfcStore
from blenderbim.bim.module.model.data import AuthoringData
class BIM_PT_authoring(Panel):
bl_idname = "BIM_PT_authoring"
bl_label = "Authoring"
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
bl_category = "BlenderBIM"
@classmethod
def poll(cls, context):
return IfcStore.get_file()
def draw(self, context):
if not AuthoringData.is_loaded:
AuthoringData.load()
props = context.scene.BIMModelProperties
col = self.layout.column(align=True)
enabled = True
if AuthoringData.data["ifc_classes"]:
col.prop(props, "ifc_class", text="", icon="FILE_VOLUME")
else:
col.label(text="No IFC Class", icon="FILE_VOLUME")
enabled = False
if AuthoringData.data["relating_types"]:
col.prop(props, "relating_type", text="", icon="FILE_3D")
else:
col.label(text="No Relating Type", icon="FILE_3D")
enabled = False
row = col.row()
row.operator("bim.add_type_instance", icon="ADD")
row.enabled = enabled
class BIM_PT_authoring_architectural(Panel):
bl_label = "Architectural"
bl_idname = "BIM_PT_authoring_architectural"
bl_options = {"DEFAULT_CLOSED"}
bl_idname = "BIM_PT_authoring"
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
bl_category = "BlenderBIM"
bl_parent_id = "BIM_PT_authoring"
def draw(self, context):
row = self.layout.row(align=True)
@@ -37,6 +37,7 @@ class BimTool(WorkSpaceTool):
bl_keymap = (
# ("bim.wall_tool_op", {"type": 'MOUSEMOVE', "value": 'ANY'}, {"properties": []}),
# ("mesh.add_wall", {"type": 'LEFTMOUSE', "value": 'PRESS'}, {"properties": []}),
("bim.hotkey", {"type": "A", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_A")]}),
("bim.hotkey", {"type": "E", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_E")]}),
("bim.join_wall", {"type": "T", "value": "PRESS", "shift": True}, {"properties": [("join_type", "L")]}),
("bim.join_wall", {"type": "Y", "value": "PRESS", "shift": True}, {"properties": [("join_type", "V")]}),
@@ -54,19 +55,52 @@ class BimTool(WorkSpaceTool):
if not AuthoringData.is_loaded and IfcStore.get_file():
AuthoringData.load()
props = context.scene.BIMModelProperties
is_tool_header = context.region.type == "TOOL_HEADER"
ifc_classes = AuthoringData.data["ifc_classes"]
relating_types = AuthoringData.data["relating_types"]
row = layout.row(align=True)
if not IfcStore.get_file():
row.label(text="No IFC Project", icon="ERROR")
return
props = context.scene.BIMModelProperties
if AuthoringData.data["ifc_classes"]:
row.operator("bim.display_ifc_types", icon="COLLAPSEMENU")
else:
row.label(text="No IFC Class")
if not AuthoringData.data["relating_types"]:
row.label(text="No Relating Type")
row.label(text="", icon="BLANK1")
if is_tool_header:
row.operator("bim.type_instance_help", text="", icon="QUESTION")
if ifc_classes and is_tool_header:
row.label(text="", icon="BLANK1")
row.operator("bim.display_ifc_types", icon="COLLAPSEMENU")
ifc_class = props.ifc_class
relating_type = AuthoringData.relating_type_name_by_id(ifc_class, props.relating_type)
if is_tool_header:
row.label(text="", icon="BLANK1")
row = layout.row(align=True)
row.label(text="", icon="EVENT_SHIFT")
row.label(text="", icon="EVENT_A")
if ifc_classes:
row.label(text=f" Add")
row.label(text="", icon="FILE_VOLUME")
row.label(text=ifc_class)
row.label(text="", icon="FILE_3D")
row.label(text=f"{relating_type} ")
else:
row.label(text=f" Add instance")
else:
txt_ifc_class = ifc_class if ifc_classes else "No IFC Class"
txt_relating_type = relating_type if relating_types else "No Relating Type"
row = layout.row(align=True)
row.label(text="Selected IFC Type:")
row = layout.row(align=True)
row.label(text=txt_ifc_class, icon="FILE_VOLUME")
row = layout.row(align=True)
row.label(text=txt_relating_type, icon="FILE_3D")
row = layout.row(align=True)
row.label(text="", icon="EVENT_SHIFT")
row.label(text="", icon="EVENT_A")
row.label(text=f" Add Type Instance")
if AuthoringData.data["ifc_classes"]:
if props.ifc_class == "IfcWallType":
@@ -148,6 +182,9 @@ class Hotkey(bpy.types.Operator):
getattr(self, f"hotkey_{self.hotkey}")()
return {"FINISHED"}
def hotkey_S_A(self):
bpy.ops.bim.add_type_instance()
def hotkey_S_C(self):
if self.has_ifc_class and self.props.ifc_class == "IfcWallType":
bpy.ops.bim.align_wall(align_type="CENTERLINE")