mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-18 22:33:33 +00:00
Improved version with optional cascading
This commit is contained in:
@@ -23,7 +23,8 @@ classes = (
|
|||||||
product.AddEmptyType,
|
product.AddEmptyType,
|
||||||
product.AddTypeInstance,
|
product.AddTypeInstance,
|
||||||
product.DisplayIFCTypes,
|
product.DisplayIFCTypes,
|
||||||
product.AddIFCTypeInstance,
|
product.SelectTypeInstance,
|
||||||
|
product.TypeInstanceHelp,
|
||||||
product.AlignProduct,
|
product.AlignProduct,
|
||||||
product.DynamicallyVoidProduct,
|
product.DynamicallyVoidProduct,
|
||||||
workspace.Hotkey,
|
workspace.Hotkey,
|
||||||
@@ -36,7 +37,6 @@ classes = (
|
|||||||
prop.BIMModelProperties,
|
prop.BIMModelProperties,
|
||||||
prop.IfcTypeInfo,
|
prop.IfcTypeInfo,
|
||||||
ui.BIM_PT_authoring,
|
ui.BIM_PT_authoring,
|
||||||
ui.BIM_PT_authoring_architectural,
|
|
||||||
grid.BIM_OT_add_object,
|
grid.BIM_OT_add_object,
|
||||||
stair.BIM_OT_add_object,
|
stair.BIM_OT_add_object,
|
||||||
opening.BIM_OT_add_object,
|
opening.BIM_OT_add_object,
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ def refresh():
|
|||||||
class AuthoringData:
|
class AuthoringData:
|
||||||
data = {}
|
data = {}
|
||||||
is_loaded = False
|
is_loaded = False
|
||||||
|
updating = False
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def load(cls):
|
def load(cls):
|
||||||
@@ -85,22 +86,33 @@ class AuthoringData:
|
|||||||
def relating_types(cls, ifc_class=None):
|
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)]
|
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
|
@classmethod
|
||||||
def assetize_relating_type_from_selection(cls):
|
def assetize_ifc_class(cls, ifc_class=None):
|
||||||
props = bpy.context.scene.BIMModelProperties
|
if ifc_class is None:
|
||||||
ifc_class = props.ifc_class
|
props = bpy.context.scene.BIMModelProperties
|
||||||
relating_type_id = props.relating_type
|
ifc_class = props.ifc_class
|
||||||
ifc_class_occurrences = cls.ifc_class_entities(ifc_class=ifc_class)
|
ifc_type_info = cls.ifc_type_info(ifc_class)
|
||||||
ifc_class_occurrences = [entity for entity in ifc_class_occurrences if entity.id() == int(relating_type_id)]
|
_ = cls.new_ifc_type_info(ifc_class) if ifc_type_info is None else ifc_type_info
|
||||||
if len(ifc_class_occurrences) == 0:
|
ifc_class_occurrences = cls.ifc_class_entities(ifc_class)
|
||||||
return
|
for ifc_class_entity in ifc_class_occurrences:
|
||||||
ifc_class_entity = ifc_class_occurrences[0]
|
obj = tool.Ifc.get_object(ifc_class_entity)
|
||||||
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
|
relating_type = ifc_class_entity.Name
|
||||||
to_be_deleted = False
|
to_be_deleted = False
|
||||||
if obj.type == 'EMPTY':
|
if obj.type == 'EMPTY':
|
||||||
bpy.ops.bim.add_type_instance()
|
kwargs = {} if from_selection else {'ifc_class': ifc_class, 'relating_type_id': ifc_class_entity.id()}
|
||||||
new_obj = bpy.context.selected_objects[-1]
|
new_obj = cls.new_ifc_type_instance(**kwargs)
|
||||||
if new_obj is not None:
|
if new_obj is not None:
|
||||||
to_be_deleted = True
|
to_be_deleted = True
|
||||||
obj = new_obj
|
obj = new_obj
|
||||||
@@ -114,17 +126,37 @@ class AuthoringData:
|
|||||||
for col in obj.users_collection:
|
for col in obj.users_collection:
|
||||||
col.objects.unlink(obj)
|
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
|
@staticmethod
|
||||||
def ifc_type_info(ifc_class):
|
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]
|
return None if len(ifc_type_infos) == 0 else ifc_type_infos[0]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def new_ifc_type_instance(cls, ifc_class, relating_type_id):
|
def new_ifc_type_instance(cls, ifc_class=None, relating_type_id=None):
|
||||||
props = bpy.context.scene.BIMModelProperties
|
if ifc_class is not None:
|
||||||
props.ifc_class = ifc_class
|
cls.updating = True
|
||||||
props.relating_type = str(relating_type_id)
|
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()
|
bpy.ops.bim.add_type_instance()
|
||||||
|
return bpy.context.selected_objects[-1]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def relating_type_name_by_id(ifc_class, relating_type_id):
|
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/>.
|
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
|
import math
|
||||||
import mathutils
|
import mathutils
|
||||||
import ifcopenshell
|
import ifcopenshell
|
||||||
import ifcopenshell.api
|
import ifcopenshell.api
|
||||||
@@ -30,9 +31,11 @@ import blenderbim.core.geometry
|
|||||||
from . import wall, slab, profile, mep
|
from . import wall, slab, profile, mep
|
||||||
from blenderbim.bim.ifc import IfcStore
|
from blenderbim.bim.ifc import IfcStore
|
||||||
from blenderbim.bim.module.model.data import AuthoringData
|
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 ifcopenshell.api.pset.data import Data as PsetData
|
||||||
from mathutils import Vector, Matrix
|
from mathutils import Vector, Matrix
|
||||||
from bpy_extras.object_utils import AddObjectHelper
|
from bpy_extras.object_utils import AddObjectHelper
|
||||||
|
from . import prop
|
||||||
|
|
||||||
|
|
||||||
class AddEmptyType(bpy.types.Operator, AddObjectHelper):
|
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")
|
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):
|
class AddTypeInstance(bpy.types.Operator):
|
||||||
bl_idname = "bim.add_type_instance"
|
bl_idname = "bim.add_type_instance"
|
||||||
bl_label = "Add Type Instance"
|
bl_label = "Add"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
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()
|
ifc_class: bpy.props.StringProperty()
|
||||||
relating_type: bpy.props.IntProperty()
|
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):
|
def execute(self, context):
|
||||||
return IfcStore.execute_ifc_operator(self, context)
|
return IfcStore.execute_ifc_operator(self, context)
|
||||||
@@ -176,7 +192,7 @@ class AddTypeInstance(bpy.types.Operator):
|
|||||||
|
|
||||||
class DisplayIFCTypes(bpy.types.Operator):
|
class DisplayIFCTypes(bpy.types.Operator):
|
||||||
bl_idname = "bim.display_ifc_types"
|
bl_idname = "bim.display_ifc_types"
|
||||||
bl_label = "Browse IFC Types"
|
bl_label = "Browse IFC Construction Types"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
bl_description = "Display all possible IFC types for new instances"
|
bl_description = "Display all possible IFC types for new instances"
|
||||||
|
|
||||||
@@ -188,67 +204,232 @@ class DisplayIFCTypes(bpy.types.Operator):
|
|||||||
if not AuthoringData.is_loaded:
|
if not AuthoringData.is_loaded:
|
||||||
AuthoringData.load()
|
AuthoringData.load()
|
||||||
props = context.scene.BIMModelProperties
|
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
|
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)
|
return context.window_manager.invoke_popup(self, width=width)
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
layout = self.layout
|
|
||||||
props = context.scene.BIMModelProperties
|
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)
|
split = layout.split(align=True, factor=0.6)
|
||||||
col = split.column(align=True)
|
col1 = split.column(align=True)
|
||||||
row = col.row()
|
row = col1.row()
|
||||||
row.label(text="Select IFC Type to add:")
|
row.prop(data=props, property="unfold_relating_type", text="Preview All Relating Types")
|
||||||
col.row().separator(factor=2)
|
col1.row().separator(factor=0.5)
|
||||||
|
row = col1.row()
|
||||||
|
row.label(text="Select IFC Construction Type:")
|
||||||
|
col1.row().separator(factor=2)
|
||||||
enabled = True
|
enabled = True
|
||||||
if AuthoringData.data["ifc_classes"]:
|
if AuthoringData.data["ifc_classes"]:
|
||||||
row = col.row()
|
row = col1.row()
|
||||||
row.prop(data=props, property="ifc_class", text="", icon="FILE_VOLUME")
|
row.label(text="", icon="FILE_VOLUME")
|
||||||
col.row().separator()
|
prop_with_search(row, props, "ifc_class", text="")
|
||||||
|
col1.row().separator()
|
||||||
else:
|
else:
|
||||||
enabled = False
|
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"]:
|
if AuthoringData.data["relating_types"]:
|
||||||
row = col.row()
|
row = col1.row()
|
||||||
row.prop(data=props, property="relating_type", text="", icon="FILE_3D")
|
row.label(text="", icon="FILE_3D")
|
||||||
col.row().separator()
|
prop_with_search(row, props, "relating_type", text="")
|
||||||
|
col1.row().separator()
|
||||||
else:
|
else:
|
||||||
enabled = False
|
enabled = False
|
||||||
col.row().separator(factor=4)
|
col1.row().separator(factor=4.75)
|
||||||
row = col.row()
|
row = col1.row()
|
||||||
op = row.operator("bim.add_ifc_type_instance", icon="ADD")
|
|
||||||
row.enabled = enabled
|
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
|
op.relating_type_id = props.relating_type
|
||||||
col = split.column()
|
op = row.operator("bim.add_type_instance", icon="ADD")
|
||||||
box = col.box()
|
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:
|
if enabled:
|
||||||
box.template_icon(icon_value=props.icon_id, scale=6.)
|
box.template_icon(icon_value=props.icon_id, scale=6.)
|
||||||
|
|
||||||
|
|
||||||
class AddIFCTypeInstance(bpy.types.Operator):
|
class SelectTypeInstance(bpy.types.Operator):
|
||||||
bl_idname = "bim.add_ifc_type_instance"
|
bl_idname = "bim.select_type_instance"
|
||||||
bl_label = "Add"
|
bl_label = "Select"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
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()
|
ifc_class: bpy.props.StringProperty()
|
||||||
relating_type_id: 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):
|
def invoke(self, context, event):
|
||||||
self.close_panel(event)
|
close_operator_panel(event)
|
||||||
return self.execute(context)
|
return self.execute(context)
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
props = context.scene.BIMModelProperties
|
props = context.scene.BIMModelProperties
|
||||||
props.ifc_class, props.relating_type = self.ifc_class, self.relating_type_id
|
if self.ifc_class != "":
|
||||||
bpy.ops.bim.add_type_instance()
|
props.ifc_class = self.ifc_class
|
||||||
return {'FINISHED'}
|
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):
|
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"]
|
if ((ifc_class not in AuthoringData.data["preview_ifc_types"]
|
||||||
or relating_type not in AuthoringData.data["preview_ifc_types"][ifc_class])
|
or relating_type not in AuthoringData.data["preview_ifc_types"][ifc_class])
|
||||||
and relating_type is not None):
|
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 = bpy.context.scene.BIMModelProperties
|
||||||
props.icon_id = AuthoringData.data["preview_ifc_types"][ifc_class][relating_type]["icon_id"]
|
props.icon_id = AuthoringData.data["preview_ifc_types"][ifc_class][relating_type]["icon_id"]
|
||||||
|
|
||||||
|
|
||||||
def update_ifc_class(self, context):
|
def update_ifc_class(self, context):
|
||||||
AuthoringData.load_ifc_classes()
|
if not AuthoringData.updating:
|
||||||
AuthoringData.load_relating_types()
|
AuthoringData.load_ifc_classes()
|
||||||
self.relating_type = AuthoringData.data["relating_types"][0][0]
|
AuthoringData.load_relating_types()
|
||||||
update_icon_id(self, context)
|
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):
|
def update_relating_type(self, context):
|
||||||
@@ -61,26 +70,45 @@ def update_relating_type(self, context):
|
|||||||
update_icon_id(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):
|
class BIMModelProperties(PropertyGroup):
|
||||||
ifc_class: bpy.props.EnumProperty(items=get_ifc_class, name="IFC Class", update=update_ifc_class)
|
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)
|
relating_type: bpy.props.EnumProperty(items=get_relating_type, name="Relating Type", update=update_relating_type)
|
||||||
icon_id: bpy.props.IntProperty()
|
icon_id: bpy.props.IntProperty()
|
||||||
|
unfold_relating_type: bpy.props.BoolProperty(update=update_unfold_relating_type)
|
||||||
occurrence_name_style: bpy.props.EnumProperty(
|
occurrence_name_style: bpy.props.EnumProperty(
|
||||||
items=[("CLASS", "By Class", ""), ("TYPE", "By Type", ""), ("CUSTOM", "Custom", "")],
|
items=[("CLASS", "By Class", ""), ("TYPE", "By Type", ""), ("CUSTOM", "Custom", "")],
|
||||||
name="Occurrence Name Style",
|
name="Occurrence Name Style",
|
||||||
)
|
)
|
||||||
occurrence_name_function: bpy.props.StringProperty(name="Occurrence Name Function")
|
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):
|
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)
|
return AuthoringData.relating_types(ifc_class=ifc_class)
|
||||||
|
|
||||||
|
|
||||||
class IfcTypeInfo(PropertyGroup):
|
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(
|
relating_type: bpy.props.EnumProperty(
|
||||||
name="Relating type", description="Relating type", items=get_ifc_type_info_relating_types
|
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
|
# 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/>.
|
# 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 bpy.types import Panel
|
||||||
from blenderbim.bim.ifc import IfcStore
|
|
||||||
from blenderbim.bim.module.model.data import AuthoringData
|
|
||||||
|
|
||||||
|
|
||||||
class BIM_PT_authoring(Panel):
|
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_label = "Architectural"
|
||||||
bl_idname = "BIM_PT_authoring_architectural"
|
bl_idname = "BIM_PT_authoring"
|
||||||
bl_options = {"DEFAULT_CLOSED"}
|
|
||||||
bl_space_type = "VIEW_3D"
|
bl_space_type = "VIEW_3D"
|
||||||
bl_region_type = "UI"
|
bl_region_type = "UI"
|
||||||
bl_category = "BlenderBIM"
|
bl_category = "BlenderBIM"
|
||||||
bl_parent_id = "BIM_PT_authoring"
|
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ class BimTool(WorkSpaceTool):
|
|||||||
bl_keymap = (
|
bl_keymap = (
|
||||||
# ("bim.wall_tool_op", {"type": 'MOUSEMOVE', "value": 'ANY'}, {"properties": []}),
|
# ("bim.wall_tool_op", {"type": 'MOUSEMOVE', "value": 'ANY'}, {"properties": []}),
|
||||||
# ("mesh.add_wall", {"type": 'LEFTMOUSE', "value": 'PRESS'}, {"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.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": "T", "value": "PRESS", "shift": True}, {"properties": [("join_type", "L")]}),
|
||||||
("bim.join_wall", {"type": "Y", "value": "PRESS", "shift": True}, {"properties": [("join_type", "V")]}),
|
("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():
|
if not AuthoringData.is_loaded and IfcStore.get_file():
|
||||||
AuthoringData.load()
|
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)
|
row = layout.row(align=True)
|
||||||
if not IfcStore.get_file():
|
if not IfcStore.get_file():
|
||||||
row.label(text="No IFC Project", icon="ERROR")
|
row.label(text="No IFC Project", icon="ERROR")
|
||||||
return
|
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 AuthoringData.data["ifc_classes"]:
|
||||||
if props.ifc_class == "IfcWallType":
|
if props.ifc_class == "IfcWallType":
|
||||||
@@ -148,6 +182,9 @@ class Hotkey(bpy.types.Operator):
|
|||||||
getattr(self, f"hotkey_{self.hotkey}")()
|
getattr(self, f"hotkey_{self.hotkey}")()
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
def hotkey_S_A(self):
|
||||||
|
bpy.ops.bim.add_type_instance()
|
||||||
|
|
||||||
def hotkey_S_C(self):
|
def hotkey_S_C(self):
|
||||||
if self.has_ifc_class and self.props.ifc_class == "IfcWallType":
|
if self.has_ifc_class and self.props.ifc_class == "IfcWallType":
|
||||||
bpy.ops.bim.align_wall(align_type="CENTERLINE")
|
bpy.ops.bim.align_wall(align_type="CENTERLINE")
|
||||||
|
|||||||
Reference in New Issue
Block a user