Type manager can now browse to type classes that don't have any types yet

This commit is contained in:
Dion Moult
2022-10-11 17:34:17 +11:00
parent dff35c173d
commit 4279576d3c
3 changed files with 105 additions and 26 deletions
@@ -19,6 +19,7 @@
import bpy import bpy
import math import math
import functools import functools
import ifcopenshell
import blenderbim.tool as tool import blenderbim.tool as tool
from blenderbim.bim.ifc import IfcStore from blenderbim.bim.ifc import IfcStore
from blenderbim.bim.module.model.root import ConstrTypeEntityNotFound from blenderbim.bim.module.model.root import ConstrTypeEntityNotFound
@@ -41,6 +42,8 @@ class AuthoringData:
cls.load_ifc_classes() cls.load_ifc_classes()
cls.load_relating_types() cls.load_relating_types()
cls.load_relating_types_browser() cls.load_relating_types_browser()
cls.data["type_class"] = cls.type_class()
cls.data["type_predefined_type"] = cls.type_predefined_type()
cls.data["total_types"] = cls.total_types() cls.data["total_types"] = cls.total_types()
cls.data["total_pages"] = cls.total_pages() cls.data["total_pages"] = cls.total_pages()
cls.data["next_page"] = cls.next_page() cls.data["next_page"] = cls.next_page()
@@ -51,6 +54,24 @@ class AuthoringData:
cls.data["has_visible_openings"] = cls.has_visible_openings() cls.data["has_visible_openings"] = cls.has_visible_openings()
cls.data["active_class"] = cls.active_class() cls.data["active_class"] = cls.active_class()
@classmethod
def type_class(cls):
declaration = tool.Ifc.schema().declaration_by_name("IfcElementType")
declarations = ifcopenshell.util.schema.get_subtypes(declaration)
names = [d.name() for d in declarations]
names.extend(("IfcDoorStyle", "IfcWindowStyle"))
return [(c, c, "") for c in sorted(names)]
@classmethod
def type_predefined_type(cls):
results = []
declaration = tool.Ifc().schema().declaration_by_name(cls.props.type_class)
for attribute in declaration.attributes():
if attribute.name() == "PredefinedType":
results.extend([(e, e, "") for e in attribute.type_of_attribute().declared_type().enumeration_items()])
break
return results
@classmethod @classmethod
def type_thumbnail(cls): def type_thumbnail(cls):
if not cls.props.relating_type_id: if not cls.props.relating_type_id:
@@ -72,13 +93,13 @@ class AuthoringData:
@classmethod @classmethod
def total_types(cls): def total_types(cls):
ifc_class = cls.props.ifc_class type_class = cls.props.type_class
return len(tool.Ifc.get().by_type(ifc_class)) if ifc_class else 0 return len(tool.Ifc.get().by_type(type_class)) if type_class else 0
@classmethod @classmethod
def total_pages(cls): def total_pages(cls):
ifc_class = cls.props.ifc_class type_class = cls.props.type_class
total_types = len(tool.Ifc.get().by_type(ifc_class)) if ifc_class else 0 total_types = len(tool.Ifc.get().by_type(type_class)) if type_class else 0
return math.ceil(total_types / cls.types_per_page) return math.ceil(total_types / cls.types_per_page)
@classmethod @classmethod
@@ -93,20 +114,26 @@ class AuthoringData:
@classmethod @classmethod
def paginated_relating_types(cls): def paginated_relating_types(cls):
ifc_class = cls.props.ifc_class type_class = cls.props.type_class
if not ifc_class: if not type_class:
return [] return []
results = [] results = []
elements = sorted(tool.Ifc.get().by_type(ifc_class), key=lambda e: e.Name or "Unnamed") elements = sorted(tool.Ifc.get().by_type(type_class), key=lambda e: e.Name or "Unnamed")
elements = elements[(cls.props.type_page - 1) * cls.types_per_page:cls.props.type_page * cls.types_per_page] elements = elements[(cls.props.type_page - 1) * cls.types_per_page : cls.props.type_page * cls.types_per_page]
for element in elements: for element in elements:
results.append({ predefined_type = ifcopenshell.util.element.get_predefined_type(element)
"id": element.id(), if predefined_type == "NOTDEFINED":
"ifc_class": element.is_a(), predefined_type = None
"name": element.Name or "Unnamed", results.append(
"description": element.Description or "No Description", {
"icon_id": cls.type_thumbnails.get(element.id(), None) or 0, "id": element.id(),
}) "ifc_class": element.is_a(),
"name": element.Name or "Unnamed",
"description": element.Description or "No Description",
"predefined_type": predefined_type,
"icon_id": cls.type_thumbnails.get(element.id(), None) or 0,
}
)
return results return results
@classmethod @classmethod
@@ -29,6 +29,12 @@ def get_ifc_class(self, context):
return AuthoringData.data["ifc_classes"] return AuthoringData.data["ifc_classes"]
def get_type_class(self, context):
if not AuthoringData.is_loaded:
AuthoringData.load()
return AuthoringData.data["type_class"]
def get_relating_type(self, context): def get_relating_type(self, context):
if not AuthoringData.is_loaded: if not AuthoringData.is_loaded:
AuthoringData.load() AuthoringData.load()
@@ -41,6 +47,12 @@ def get_relating_type_browser(self, context):
return AuthoringData.data["relating_types_ids_browser"] return AuthoringData.data["relating_types_ids_browser"]
def get_type_predefined_type(self, context):
if not AuthoringData.is_loaded:
AuthoringData.load()
return AuthoringData.data["type_predefined_type"]
def store_cursor_position(context, event, cursor=True, window=True): def store_cursor_position(context, event, cursor=True, window=True):
browser_state = context.scene.BIMModelProperties.constr_browser_state browser_state = context.scene.BIMModelProperties.constr_browser_state
if cursor: if cursor:
@@ -62,8 +74,10 @@ def update_icon_id(self, context, browser=False):
return return
def set_icon(update_interval_seconds=1e-4): def set_icon(update_interval_seconds=1e-4):
if (ifc_class not in self.constr_classes if (
or relating_type_id not in self.constr_classes[ifc_class].constr_types): ifc_class not in self.constr_classes
or relating_type_id not in self.constr_classes[ifc_class].constr_types
):
return update_interval_seconds return update_interval_seconds
else: else:
self.icon_id = self.constr_classes[ifc_class].constr_types[relating_type_id].icon_id self.icon_id = self.constr_classes[ifc_class].constr_types[relating_type_id].icon_id
@@ -76,6 +90,15 @@ def update_ifc_class(self, context):
AuthoringData.data["type_thumbnail"] = AuthoringData.type_thumbnail() AuthoringData.data["type_thumbnail"] = AuthoringData.type_thumbnail()
def update_type_class(self, context):
AuthoringData.data["total_types"] = AuthoringData.total_types()
AuthoringData.data["total_pages"] = AuthoringData.total_pages()
AuthoringData.data["prev_page"] = AuthoringData.prev_page()
AuthoringData.data["next_page"] = AuthoringData.next_page()
AuthoringData.data["paginated_relating_types"] = AuthoringData.paginated_relating_types()
AuthoringData.data["type_predefined_type"] = AuthoringData.type_predefined_type()
def update_ifc_class_browser(self, context): def update_ifc_class_browser(self, context):
if context.region is not None and context.region.type != "TOOL_HEADER": if context.region is not None and context.region.type != "TOOL_HEADER":
AuthoringData.load_ifc_classes() AuthoringData.load_ifc_classes()
@@ -206,3 +229,16 @@ class BIMModelProperties(PropertyGroup):
z: bpy.props.FloatProperty(name="Z", default=0.5) z: bpy.props.FloatProperty(name="Z", default=0.5)
rl: bpy.props.FloatProperty(name="RL", default=1) rl: bpy.props.FloatProperty(name="RL", default=1)
type_page: bpy.props.IntProperty(name="Type Page", default=1, update=update_type_page) type_page: bpy.props.IntProperty(name="Type Page", default=1, update=update_type_page)
type_template: bpy.props.EnumProperty(
items=(
("1", "Custom Mesh", ""),
("2", "Vertical Layers", ""),
("2", "Horizontal Layers", ""),
("3", "Extruded Profile", ""),
("4", "Non-Geometric Type", ""),
),
name="Type Template",
default="1",
)
type_class: bpy.props.EnumProperty(items=get_type_class, name="IFC Class", update=update_type_class)
type_predefined_type: bpy.props.EnumProperty(items=get_type_predefined_type, name="Predefined Type", default=None)
@@ -35,6 +35,8 @@ class LaunchTypeManager(bpy.types.Operator):
def invoke(self, context, event): def invoke(self, context, event):
props = context.scene.BIMModelProperties props = context.scene.BIMModelProperties
props.type_page = 1 props.type_page = 1
if props.ifc_class:
props.type_class = props.ifc_class
bpy.ops.bim.load_type_thumbnails(ifc_class=props.ifc_class) bpy.ops.bim.load_type_thumbnails(ifc_class=props.ifc_class)
if not AuthoringData.is_loaded: if not AuthoringData.is_loaded:
AuthoringData.load() AuthoringData.load()
@@ -43,15 +45,24 @@ class LaunchTypeManager(bpy.types.Operator):
def draw(self, context): def draw(self, context):
props = context.scene.BIMModelProperties props = context.scene.BIMModelProperties
row = self.layout.row(align=True) row = self.layout.row()
row.prop(props, "type_class", text="")
columns = self.layout.column_flow(columns=3)
row = columns.row()
row.alignment = "LEFT"
row.label(text=f"{AuthoringData.data['total_types']} Types", icon="FILE_VOLUME")
row = columns.row(align=True)
row.alignment = "CENTER"
row.prop(props, "type_predefined_type", text="")
row.prop(props, "type_template", text="")
op = row.operator("bim.change_type_page", icon="ADD", text="")
row = columns.row(align=True)
row.alignment = "RIGHT" row.alignment = "RIGHT"
#row.label(text=f"", icon="FILE_VOLUME")
text = f"{AuthoringData.data['total_types']} types"
if AuthoringData.data["total_pages"] > 1: if AuthoringData.data["total_pages"] > 1:
text += f" ({props.type_page}/{AuthoringData.data['total_pages']}) " row.label(text=f"Page {props.type_page}/{AuthoringData.data['total_pages']} ")
row.label(text=text)
if AuthoringData.data["prev_page"]: if AuthoringData.data["prev_page"]:
op = row.operator("bim.change_type_page", icon="TRIA_LEFT", text="") op = row.operator("bim.change_type_page", icon="TRIA_LEFT", text="")
op.page = AuthoringData.data["prev_page"] op.page = AuthoringData.data["prev_page"]
@@ -74,11 +85,16 @@ class LaunchTypeManager(bpy.types.Operator):
row.label(text=relating_type["description"]) row.label(text=relating_type["description"])
row = box.row() row = box.row()
row.template_icon(icon_value=relating_type["icon_id"], scale=4) if relating_type["icon_id"]:
row.template_icon(icon_value=relating_type["icon_id"], scale=4)
else:
op = box.operator("bim.load_type_thumbnails", text="Load Thumbnails", icon="FILE_REFRESH")
op.ifc_class = props.type_class
row = box.row(align=True) row = box.row(align=True)
op = row.operator("bim.add_constr_type_instance", icon="ADD") text = f"Add {relating_type['predefined_type']}" if relating_type["predefined_type"] else "Add"
op = row.operator("bim.add_constr_type_instance", icon="ADD", text=text)
op.from_invoke = True op.from_invoke = True
op.ifc_class = relating_type["ifc_class"] op.ifc_class = relating_type["ifc_class"]
op.relating_type_id = relating_type["id"] op.relating_type_id = relating_type["id"]