Distinguish bt active and selected constr type + renaming ifc_class -> constr_type

This commit is contained in:
carlos
2022-07-14 13:40:57 +02:00
parent f9f9746a9a
commit 3f24d54e8f
5 changed files with 268 additions and 248 deletions
@@ -22,7 +22,7 @@ from . import handler, prop, ui, grid, product, wall, slab, stair, opening, pie,
classes = (
product.AddEmptyType,
product.AddTypeInstance,
product.DisplayIFCTypes,
product.DisplayConstrTypes,
product.SelectTypeInstance,
product.TypeInstanceHelp,
product.AlignProduct,
@@ -35,7 +35,7 @@ classes = (
opening.AddElementOpening,
profile.ExtendProfile,
prop.BIMModelProperties,
prop.IfcTypeInfo,
prop.ConstrTypeInfo,
ui.BIM_PT_authoring,
grid.BIM_OT_add_object,
stair.BIM_OT_add_object,
@@ -54,7 +54,7 @@ def register():
if not bpy.app.background:
bpy.utils.register_tool(workspace.BimTool, after={"builtin.scale_cage"}, separator=True, group=True)
bpy.types.Scene.BIMModelProperties = bpy.props.PointerProperty(type=prop.BIMModelProperties)
bpy.types.Scene.IfcTypeInfo = bpy.props.CollectionProperty(type=prop.IfcTypeInfo)
bpy.types.Scene.ConstrTypeInfo = bpy.props.CollectionProperty(type=prop.ConstrTypeInfo)
bpy.types.VIEW3D_MT_mesh_add.append(grid.add_object_button)
bpy.types.VIEW3D_MT_mesh_add.append(stair.add_object_button)
bpy.types.VIEW3D_MT_mesh_add.append(opening.add_object_button)
@@ -72,7 +72,7 @@ def unregister():
if not bpy.app.background:
bpy.utils.unregister_tool(workspace.BimTool)
del bpy.types.Scene.BIMModelProperties
del bpy.types.Scene.IfcTypeInfo
del bpy.types.Scene.ConstrTypeInfo
bpy.app.handlers.load_post.remove(handler.load_post)
bpy.types.VIEW3D_MT_mesh_add.remove(grid.add_object_button)
bpy.types.VIEW3D_MT_mesh_add.remove(stair.add_object_button)
@@ -31,31 +31,35 @@ def refresh():
class AuthoringData:
data = {}
is_loaded = False
updating = False
@classmethod
def load(cls):
cls.is_loaded = True
if not hasattr(cls, "data"):
cls.data = {}
cls.load_ifc_classes()
cls.load_relating_types()
cls.load_preview_ifc_types()
cls.load_constr_classes()
cls.load_constr_types()
cls.load_constr_types_browser()
cls.load_preview_constr_types()
@classmethod
def load_ifc_classes(cls):
cls.data["ifc_classes"] = cls.ifc_classes()
def load_constr_classes(cls):
cls.data["constr_classes"] = cls.constr_classes()
@classmethod
def load_relating_types(cls):
cls.data["relating_types"] = cls.relating_types()
def load_constr_types(cls):
cls.data["constr_types_ids"] = cls.constr_types()
@classmethod
def load_preview_ifc_types(cls):
cls.data["preview_ifc_types"] = preview_icon_ids
def load_constr_types_browser(cls):
cls.data["constr_types_ids_browser"] = cls.constr_types_browser()
@classmethod
def ifc_classes(cls):
def load_preview_constr_types(cls):
cls.data["preview_constr_types"] = preview_icon_ids
@classmethod
def constr_classes(cls):
results = []
classes = {
e.is_a()
@@ -67,102 +71,133 @@ class AuthoringData:
return results
@classmethod
def ifc_class_entities(cls, ifc_class=None):
ifc_classes = cls.data["ifc_classes"]
if not ifc_classes:
def constr_class_entities(cls, constr_class=None):
constr_classes = cls.data["constr_classes"]
if not constr_classes:
return []
results = []
if ifc_class is None:
ifc_class = bpy.context.scene.BIMModelProperties.ifc_class
if not ifc_class and ifc_classes:
ifc_class = ifc_classes[0][0]
if ifc_class:
elements = sorted(tool.Ifc.get().by_type(ifc_class), key=lambda s: s.Name)
if constr_class is None:
props = bpy.context.scene.BIMModelProperties
constr_class = props.constr_class
if not constr_class and constr_classes:
constr_class = constr_classes[0][0]
if constr_class:
elements = sorted(tool.Ifc.get().by_type(constr_class), key=lambda s: s.Name)
results.extend(elements)
return results
return []
@classmethod
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)]
def constr_types(cls, constr_class=None):
return [
(str(e.id()), e.Name, e.Description or "") for e in cls.constr_class_entities(constr_class=constr_class)
]
@classmethod
def constr_types_browser(cls):
props = bpy.context.scene.BIMModelProperties
return cls.constr_types(constr_class=props.constr_class_browser)
@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
def new_constr_type_info(constr_class):
constr_type_info = bpy.context.scene.ConstrTypeInfo.add()
constr_type_info.name = constr_class
return constr_type_info
@classmethod
def assetize_ifc_class(cls, ifc_class=None):
if ifc_class is None:
def assetize_constr_class(cls, constr_class=None):
if constr_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
constr_class = props.constr_class
constr_type_info = cls.constr_type_info(constr_class)
_ = cls.new_constr_type_info(constr_class) if constr_type_info is None else constr_type_info
constr_class_occurrences = cls.constr_class_entities(constr_class)
for constr_class_entity in constr_class_occurrences:
preview_constr_types = cls.data["preview_constr_types"]
### handle asset regeneration when library entity is updated ¿?
if (constr_class not in preview_constr_types
or str(constr_class_entity.id()) not in preview_constr_types[constr_class]):
obj = tool.Ifc.get_object(constr_class_entity)
cls.assetize_object(obj, constr_class, constr_class_entity)
constr_type_info = cls.constr_type_info(constr_class)
constr_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
def assetize_object(cls, obj, constr_class, constr_class_entity, from_selection=False):
constr_type_id = constr_class_entity.id()
to_be_deleted = False
if obj.type == 'EMPTY':
kwargs = {} if from_selection else {'ifc_class': ifc_class, 'relating_type_id': ifc_class_entity.id()}
new_obj = cls.new_ifc_type_instance(**kwargs)
kwargs = {}
if not from_selection:
kwargs.update({'constr_class': constr_class, 'constr_type_id': constr_type_id})
new_obj = cls.new_constr_type_instance(**kwargs)
if new_obj is not None:
to_be_deleted = True
obj = new_obj
obj.asset_mark()
obj.asset_generate_preview()
icon_id = obj.preview.icon_id
if ifc_class not in cls.data["preview_ifc_types"]:
cls.data["preview_ifc_types"][ifc_class] = {}
cls.data["preview_ifc_types"][ifc_class][relating_type] = {"icon_id": icon_id, "object": obj}
if constr_class not in cls.data["preview_constr_types"]:
cls.data["preview_constr_types"][constr_class] = {}
cls.data["preview_constr_types"][constr_class][str(constr_type_id)] = {"icon_id": icon_id, "object": obj}
if to_be_deleted:
for col in obj.users_collection:
col.objects.unlink(obj)
@classmethod
def assetize_relating_type_from_selection(cls):
def assetize_constr_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:
constr_class_browser = props.constr_class_browser
constr_type_id_browser = props.constr_type_id_browser
constr_class_occurrences = cls.constr_class_entities(constr_class=constr_class_browser)
constr_class_occurrences = [
entity for entity in constr_class_occurrences if entity.id() == int(constr_type_id_browser)
]
if len(constr_class_occurrences) == 0:
return False
ifc_class_entity = ifc_class_occurrences[0]
obj = tool.Ifc.get_object(ifc_class_entity)
constr_class_entity = constr_class_occurrences[0]
obj = tool.Ifc.get_object(constr_class_entity)
if obj is None:
return False
cls.assetize_object(obj, ifc_class, ifc_class_entity, from_selection=True)
cls.assetize_object(obj, constr_class_browser, constr_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.name == ifc_class]
return None if len(ifc_type_infos) == 0 else ifc_type_infos[0]
def constr_type_info(constr_class):
constr_type_infos = [element for element in bpy.context.scene.ConstrTypeInfo if element.name == constr_class]
return None if len(constr_type_infos) == 0 else constr_type_infos[0]
@classmethod
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()
def new_constr_type_instance(cls, constr_class=None, constr_type_id=None):
props = bpy.context.scene.BIMModelProperties
if constr_class is None:
bpy.ops.bim.add_type_instance(
constr_class=props.constr_class_browser, constr_type_id=int(props.constr_type_id_browser)
)
else:
props.constr_class = constr_class
props.constr_type_id = str(constr_type_id)
bpy.ops.bim.add_type_instance()
return bpy.context.selected_objects[-1]
@staticmethod
def relating_type_name_by_id(ifc_class, relating_type_id):
def constr_type_name_by_id(constr_class, constr_type_id):
file = IfcStore.get_file()
try:
ifc_class_entity = file.by_id(int(relating_type_id))
constr_class_entity = file.by_id(int(constr_type_id))
except (RuntimeError, ValueError):
return None
return ifc_class_entity.Name if ifc_class_entity.is_a() == ifc_class else None
return constr_class_entity.Name if constr_class_entity.is_a() == constr_class else None
@classmethod
def consolidate_constr_type(cls):
props = bpy.context.scene.BIMModelProperties
props.constr_class = props.constr_class_browser
props.constr_type_id = props.constr_type_id_browser
@classmethod
def setup_constr_type_browser(cls):
props = bpy.context.scene.BIMModelProperties
props.constr_class_browser = props.constr_class
props.constr_type_id_browser = props.constr_type_id
@@ -69,8 +69,8 @@ class AddTypeInstance(bpy.types.Operator):
bl_label = "Add"
bl_options = {"REGISTER", "UNDO"}
bl_description = "Add Type Instance to the model"
ifc_class: bpy.props.StringProperty()
relating_type: bpy.props.IntProperty()
constr_class: bpy.props.StringProperty()
constr_type_id: bpy.props.IntProperty()
from_invoke: bpy.props.BoolProperty(default=False)
def invoke(self, context, event):
@@ -83,25 +83,29 @@ class AddTypeInstance(bpy.types.Operator):
def _execute(self, context):
props = context.scene.BIMModelProperties
ifc_class = self.ifc_class or props.ifc_class
relating_type_id = self.relating_type or props.relating_type
constr_class = self.constr_class or props.constr_class
constr_type_id = self.constr_type_id or props.constr_type_id
if not ifc_class or not relating_type_id:
if not constr_class or not constr_type_id:
return {"FINISHED"}
if self.from_invoke:
props.constr_class = self.constr_class
props.constr_type_id = str(self.constr_type_id)
self.file = IfcStore.get_file()
instance_class = ifcopenshell.util.type.get_applicable_entities(ifc_class, self.file.schema)[0]
relating_type = self.file.by_id(int(relating_type_id))
material = ifcopenshell.util.element.get_material(relating_type)
instance_class = ifcopenshell.util.type.get_applicable_entities(constr_class, self.file.schema)[0]
constr_type = self.file.by_id(int(constr_type_id))
material = ifcopenshell.util.element.get_material(constr_type)
if material and material.is_a("IfcMaterialProfileSet"):
if profile.DumbProfileGenerator(relating_type).generate():
if profile.DumbProfileGenerator(constr_type).generate():
return {"FINISHED"}
elif material and material.is_a("IfcMaterialLayerSet"):
if self.generate_layered_element(ifc_class, relating_type):
if self.generate_layered_element(constr_class, constr_type):
return {"FINISHED"}
if relating_type.is_a("IfcFlowSegmentType") and not relating_type.RepresentationMaps:
if mep.MepGenerator(relating_type).generate():
if constr_type.is_a("IfcFlowSegmentType") and not constr_type.RepresentationMaps:
if mep.MepGenerator(constr_type).generate():
return {"FINISHED"}
building_obj = None
@@ -130,14 +134,14 @@ class AddTypeInstance(bpy.types.Operator):
]
mesh = bpy.data.meshes.new(name="Instance")
mesh.from_pydata(verts, edges, faces)
obj = bpy.data.objects.new(tool.Model.generate_occurrence_name(relating_type, instance_class), mesh)
obj = bpy.data.objects.new(tool.Model.generate_occurrence_name(constr_type, instance_class), mesh)
obj.location = context.scene.cursor.location
collection = context.view_layer.active_layer_collection.collection
collection.objects.link(obj)
collection_obj = bpy.data.objects.get(collection.name)
bpy.ops.bim.assign_class(obj=obj.name, ifc_class=instance_class)
element = tool.Ifc.get_entity(obj)
blenderbim.core.type.assign_type(tool.Ifc, tool.Type, element=element, type=relating_type)
blenderbim.core.type.assign_type(tool.Ifc, tool.Type, element=element, type=constr_type)
if building_obj:
if instance_class in ["IfcWindow", "IfcDoor"]:
@@ -152,7 +156,7 @@ class AddTypeInstance(bpy.types.Operator):
obj.location[2] = collection_obj.location[2] - min([v[2] for v in obj.bound_box])
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
for port in ifcopenshell.util.system.get_ports(relating_type):
for port in ifcopenshell.util.system.get_ports(constr_type):
mat = ifcopenshell.util.placement.get_local_placement(port.ObjectPlacement)
mat[0][3] *= unit_scale
mat[1][3] *= unit_scale
@@ -190,11 +194,11 @@ class AddTypeInstance(bpy.types.Operator):
pass # Dumb block generator? Eh? :)
class DisplayIFCTypes(bpy.types.Operator):
bl_idname = "bim.display_ifc_types"
bl_label = "Browse Element Types"
class DisplayConstrTypes(bpy.types.Operator):
bl_idname = "bim.display_constr_types"
bl_label = "Browse Construction Types"
bl_options = {"REGISTER", "UNDO"}
bl_description = "Display all possible IFC types for new instances"
bl_description = "Display all available Construction Types to add new instances"
def execute(self, context):
bpy.ops.object.mode_set(mode="OBJECT")
@@ -203,14 +207,15 @@ class DisplayIFCTypes(bpy.types.Operator):
def invoke(self, context, event):
if not AuthoringData.is_loaded:
AuthoringData.load()
AuthoringData.setup_constr_type_browser()
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)
constr_class = props.constr_class_browser
constr_type_info = AuthoringData.constr_type_info(constr_class)
if constr_type_info is None or not constr_type_info.fully_loaded:
AuthoringData.assetize_constr_class(constr_class)
else:
prop.update_relating_type(props, context)
prop.update_constr_type(props, context)
min_width = 250
width_scaling = 5 ** -1
width = max([min_width, int(width_scaling * context.region.width)])
@@ -219,9 +224,9 @@ class DisplayIFCTypes(bpy.types.Operator):
def draw(self, context):
props = context.scene.BIMModelProperties
if props.unfold_relating_type:
self.draw_by_class(props)
self.draw_by_constr_class(props)
else:
self.draw_by_class_and_relating_type(props)
self.draw_by_constr_class_and_type(props)
def draw_header(self, props):
layout = self.layout
@@ -230,16 +235,16 @@ class DisplayIFCTypes(bpy.types.Operator):
split = inner_layout.split(align=True, factor=2./3)
col1 = split.column(align=True)
row = col1.row()
row.prop(data=props, property="unfold_relating_type", text="Preview All Relating Types")
row.prop(data=props, property="unfold_relating_type", text="Preview All Construction Types")
col1.row().separator(factor=1)
row = col1.row()
row.label(text="Select Element Type:")
row.label(text="Select Construction Type:")
col1.row().separator(factor=1.5)
enabled = True
if AuthoringData.data["ifc_classes"]:
if AuthoringData.data["constr_classes"]:
subsplit = col1.split(factor=1./3)
subsplit.column().row().label(text="IfcElementType:", icon="FILE_VOLUME")
prop_with_search(subsplit.column(), props, "ifc_class", text="")
subsplit.column().row().label(text="Construction Class:", icon="FILE_VOLUME")
prop_with_search(subsplit.column(), props, "constr_class_browser", text="")
col1.row().separator()
else:
enabled = False
@@ -250,18 +255,18 @@ class DisplayIFCTypes(bpy.types.Operator):
col2.row().separator(factor=1)
return {"enabled": enabled, "layout": inner_layout, "col1": col1, "col2": col2}
def draw_by_class(self, props):
def draw_by_constr_class(self, props):
header_data = self.draw_header(props)
enabled, layout = [header_data[key] for key in ["enabled", "layout"]]
ifc_class = props.ifc_class
constr_class_browser = props.constr_class_browser
num_cols = 3
layout.row().separator(factor=0.25)
layout.row().label(text=f"Available {ifc_class}(s):", icon="FILE_3D")
layout.row().label(text="Construction Types:", icon="FILE_3D")
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):
constr_types_browser = AuthoringData.constr_types_browser()
num_types = len(constr_types_browser)
for idx, (constr_type_id_browser, name, desc) in enumerate(constr_types_browser):
outer_col = flow.column()
box = outer_col.box()
row = box.row()
@@ -269,26 +274,25 @@ class DisplayIFCTypes(bpy.types.Operator):
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"]
preview_constr_types = AuthoringData.data["preview_constr_types"]
if constr_class_browser in preview_constr_types:
preview_constr_class = preview_constr_types[constr_class_browser]
if constr_type_id_browser in preview_constr_class:
icon_id = preview_constr_class[constr_type_id_browser]["icon_id"]
row.template_icon(icon_value=icon_id, scale=6.)
box.row().separator(factor=0.25)
box.row().separator(factor=0.2)
row = box.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
op.constr_class = constr_class_browser
op.constr_type_id = constr_type_id_browser
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)
box.row().separator(factor=0.05)
op.constr_class = constr_class_browser
if constr_type_id_browser.isnumeric():
op.constr_type_id = int(constr_type_id_browser)
factor = 2 if idx + 1 < math.ceil(num_types / num_cols) else 1.5
outer_col.row().separator(factor=factor)
last_row_cols = num_types % num_cols
@@ -296,14 +300,15 @@ class DisplayIFCTypes(bpy.types.Operator):
for _ in range(num_cols - last_row_cols):
flow.column()
def draw_by_class_and_relating_type(self, props):
def draw_by_constr_class_and_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"]:
constr_class_browser = props.constr_class_browser
constr_type_id_browser = props.constr_type_id_browser
if AuthoringData.data["constr_types_ids_browser"]:
subsplit = col1.split(factor=1. / 3)
subsplit.column().row().label(text=f"{ifc_class}:", icon="FILE_3D")
prop_with_search(subsplit.column(), props, "relating_type", text="")
subsplit.column().row().label(text="Construction Type:", icon="FILE_3D")
prop_with_search(subsplit.column(), props, "constr_type_id_browser", text="")
col1.row().separator()
else:
enabled = False
@@ -311,14 +316,13 @@ class DisplayIFCTypes(bpy.types.Operator):
row = col1.row()
row.enabled = enabled
op = row.operator("bim.select_type_instance", icon="RIGHTARROW_THIN")
op.ifc_class = ifc_class
op.relating_type_id = props.relating_type
op.constr_class = constr_class_browser
op.constr_type_id = constr_type_id_browser
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)
op.constr_class = constr_class_browser
if constr_type_id_browser.isnumeric():
op.constr_type_id = int(constr_type_id_browser)
col2.row().separator(factor=1.25)
split = col2.split(factor=0.025)
col = [split.column() for _ in range(2)][-1]
@@ -333,8 +337,8 @@ class SelectTypeInstance(bpy.types.Operator):
bl_label = "Select"
bl_options = {"REGISTER", "UNDO"}
bl_description = "Pick Type Instance as selection for subsequent operations"
ifc_class: bpy.props.StringProperty()
relating_type_id: bpy.props.StringProperty()
constr_class: bpy.props.StringProperty()
constr_type_id: bpy.props.StringProperty()
def invoke(self, context, event):
close_operator_panel(event)
@@ -342,16 +346,17 @@ class SelectTypeInstance(bpy.types.Operator):
def execute(self, context):
props = context.scene.BIMModelProperties
if self.ifc_class != "":
props.ifc_class = self.ifc_class
if self.relating_type_id != "":
props.relating_type = self.relating_type_id
if self.constr_class != "":
props.constr_class = self.constr_class
AuthoringData.load_constr_types()
if self.constr_type_id != "":
props.constr_type_id = self.constr_type_id
return {"FINISHED"}
class TypeInstanceHelp(bpy.types.Operator):
bl_idname = "bim.type_instance_help"
bl_label = "Element Types Help"
bl_label = "Construction Types Help"
bl_options = {"REGISTER", "UNDO"}
bl_description = "Click to read some contextual help"
@@ -367,22 +372,13 @@ class TypeInstanceHelp(bpy.types.Operator):
row = layout.row()
row.alignment = "CENTER"
row.label(text="BlenderBIM Help", icon="BLENDER")
row = layout.row()
row.alignment = "CENTER"
row.label(text="[Element Type Browser]")
layout.row().separator(factor=0.5)
row = col_with_margins(layout.row()).row()
row.label(text="When to use:", icon="KEYTYPE_MOVING_HOLD_VEC")
self.draw_lines(layout, self.message_purpose)
row.label(text="Overview:", icon="KEYTYPE_MOVING_HOLD_VEC")
self.draw_lines(layout, self.message_summary)
layout.row().separator()
row = 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 = 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 = col_with_margins(layout.row()).row()
row.label(text="Further support:", icon="KEYTYPE_MOVING_HOLD_VEC")
layout.row().separator(factor=0.5)
@@ -404,32 +400,10 @@ class TypeInstanceHelp(bpy.types.Operator):
row.label(text=f" {line}")
@property
def message_purpose(self):
def message_summary(self):
return [
'Available Element Types can be previewed and added through the button "Browse',
'Element Types", which appears when an IfcProjectLibrary, containing in turn',
'IfcElementType entities, is loaded. In order to manage loaded libraries, navigate',
'to [Scene Properties] -> [IFC Project Setup] -> [IFC Project Library], under the',
'Properties panel.'
]
@property
def message_overall(self):
return [
'Choose a certain Element Type by determining:',
' 1) An existing subtype of IfcElementType.',
' 2) Its entity name, as stored within the IfcProjectLibrary.',
'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, previews for every existing entity of',
'the selected IFC class will be shown at once. Not advisable on large projects, with',
'dozens of entities for a given IfcElementType.'
'The Construction Type Browser allows to preview and add new instances to the model.',
'For further support, please click on the Documentation link below.'
]
@@ -17,97 +17,107 @@
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
import bpy
import ifcopenshell.util.type
from blenderbim.bim.module.model.data import AuthoringData
from blenderbim.bim.prop import StrProperty, Attribute
from blenderbim.bim.ifc import IfcStore
import blenderbim.tool as tool
from bpy.types import PropertyGroup
def get_ifc_class(self, context):
def get_constr_class(self, context):
if not AuthoringData.is_loaded:
AuthoringData.load()
return AuthoringData.data["ifc_classes"]
return AuthoringData.data["constr_classes"]
def get_relating_type(self, context):
def get_constr_type(self, context):
if not AuthoringData.is_loaded:
AuthoringData.load()
return AuthoringData.data["relating_types"]
return AuthoringData.data["constr_types_ids"]
def get_constr_type_browser(self, context):
if not AuthoringData.is_loaded:
AuthoringData.load()
return AuthoringData.data["constr_types_ids_browser"]
def update_icon_id(self, context):
ifc_class = self.ifc_class
relating_type_id = self.relating_type
relating_type = AuthoringData.relating_type_name_by_id(ifc_class, relating_type_id)
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):
if not AuthoringData.assetize_relating_type_from_selection():
constr_class_browser = self.constr_class_browser
constr_type_id_browser = self.constr_type_id_browser
constr_type_browser = AuthoringData.constr_type_name_by_id(constr_class_browser, constr_type_id_browser)
if ((constr_class_browser not in AuthoringData.data["preview_constr_types"]
or constr_type_id_browser not in AuthoringData.data["preview_constr_types"][constr_class_browser])
and constr_type_browser is not None):
if not AuthoringData.assetize_constr_type_from_selection():
return
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_constr_types"][constr_class_browser][constr_type_id_browser]["icon_id"]
def update_ifc_class(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_constr_class(self, context):
AuthoringData.load_constr_classes()
AuthoringData.load_constr_types()
self.constr_type_id = AuthoringData.data["constr_types_ids"][0][0]
def update_relating_type(self, context):
AuthoringData.load_relating_types()
def update_constr_class_browser(self, context):
AuthoringData.load_constr_classes()
AuthoringData.load_constr_types_browser()
props = context.scene.BIMModelProperties
if props.unfold_relating_type:
constr_class_browser = props.constr_class_browser
constr_type_info = AuthoringData.constr_type_info(constr_class_browser)
if constr_type_info is None or not constr_type_info.fully_loaded:
curr_selection = props.constr_class, props.constr_type_id
AuthoringData.assetize_constr_class(constr_class_browser)
props.constr_class, props.constr_type_id = curr_selection
else:
self.constr_type_id_browser = AuthoringData.data["constr_types_ids_browser"][0][0]
def update_constr_type(self, context):
AuthoringData.load_constr_types()
def update_constr_type_browser(self, context):
AuthoringData.load_constr_types_browser()
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)
def update_unfold_constr_type(self, context):
update_constr_class_browser(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)
constr_class: bpy.props.EnumProperty(items=get_constr_class, name="Construction Class", update=update_constr_class)
constr_class_browser: bpy.props.EnumProperty(
items=get_constr_class, name="Construction Class", update=update_constr_class_browser
)
constr_type_id: bpy.props.EnumProperty(
items=get_constr_type, name="Construction Type", update=update_constr_type
)
constr_type_id_browser: bpy.props.EnumProperty(
items=get_constr_type_browser, name="Construction Type", update=update_constr_type_browser
)
icon_id: bpy.props.IntProperty()
unfold_relating_type: bpy.props.BoolProperty(update=update_unfold_relating_type)
unfold_relating_type: bpy.props.BoolProperty(update=update_unfold_constr_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
"constr_class_browser": get_constr_class,
"constr_type_browser": get_constr_type_browser
}
def get_ifc_type_info_relating_types(self, context):
ifc_class = self.name
return AuthoringData.relating_types(ifc_class=ifc_class)
def get_constr_type_info(self, context):
return AuthoringData.relating_types(constr_class=self.name)
class IfcTypeInfo(PropertyGroup):
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
class ConstrTypeInfo(PropertyGroup):
name: bpy.props.StringProperty(name="Construction class")
constr_type: bpy.props.EnumProperty(
name="Construction type", items=get_constr_type_info
)
fully_loaded: bpy.props.BoolProperty(default=False)
@@ -57,53 +57,54 @@ class BimTool(WorkSpaceTool):
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
constr_classes = AuthoringData.data["constr_classes"]
constr_types_ids = AuthoringData.data["constr_types_ids"]
if is_tool_header:
row.operator("bim.type_instance_help", text="", icon="QUESTION")
if ifc_classes and is_tool_header:
if constr_classes and is_tool_header:
row.label(text="", icon="BLANK1")
row.operator("bim.display_ifc_types", icon="COLLAPSEMENU")
row.operator("bim.display_constr_types", icon="COLLAPSEMENU")
ifc_class = props.ifc_class
relating_type = AuthoringData.relating_type_name_by_id(ifc_class, props.relating_type)
constr_class = props.constr_class
constr_type_id = props.constr_type_id
constr_type = AuthoringData.constr_type_name_by_id(constr_class, constr_type_id)
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:
if constr_classes:
row.label(text=f" Add")
row.label(text="", icon="FILE_VOLUME")
row.label(text=ifc_class)
row.label(text=constr_class)
row.label(text="", icon="FILE_3D")
row.label(text=f"{relating_type} ")
row.label(text=f"{constr_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"
txt_constr_class = constr_class if constr_classes else "No Construction Class"
txt_constr_type = constr_type if constr_types_ids else "No Construction Type"
row = layout.row(align=True)
row.label(text="Selected IFC Type:")
row.label(text="Selected Construction Type:")
row = layout.row(align=True)
row.label(text=txt_ifc_class, icon="FILE_VOLUME")
row.label(text=txt_constr_class, icon="FILE_VOLUME")
row = layout.row(align=True)
row.label(text=txt_relating_type, icon="FILE_3D")
row.label(text=txt_constr_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":
if AuthoringData.data["constr_classes"]:
if constr_class == "IfcWallType":
row = layout.row()
row.label(text="Join")
row = layout.row(align=True)
@@ -125,7 +126,7 @@ class BimTool(WorkSpaceTool):
row.label(text="", icon="EVENT_SHIFT")
row.label(text="Split", icon="EVENT_S")
if props.ifc_class in ("IfcColumnType", "IfcBeamType", "IfcMemberType"):
if constr_class in ("IfcColumnType", "IfcBeamType", "IfcMemberType"):
row = layout.row()
row.label(text="Join")
row = layout.row(align=True)