mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-12 10:33:20 +00:00
Distinguish bt active and selected constr type + renaming ifc_class -> constr_type
This commit is contained in:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user