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 math
import functools
import ifcopenshell
import blenderbim.tool as tool
from blenderbim.bim.ifc import IfcStore
from blenderbim.bim.module.model.root import ConstrTypeEntityNotFound
@@ -41,6 +42,8 @@ class AuthoringData:
cls.load_ifc_classes()
cls.load_relating_types()
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_pages"] = cls.total_pages()
cls.data["next_page"] = cls.next_page()
@@ -51,6 +54,24 @@ class AuthoringData:
cls.data["has_visible_openings"] = cls.has_visible_openings()
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
def type_thumbnail(cls):
if not cls.props.relating_type_id:
@@ -72,13 +93,13 @@ class AuthoringData:
@classmethod
def total_types(cls):
ifc_class = cls.props.ifc_class
return len(tool.Ifc.get().by_type(ifc_class)) if ifc_class else 0
type_class = cls.props.type_class
return len(tool.Ifc.get().by_type(type_class)) if type_class else 0
@classmethod
def total_pages(cls):
ifc_class = cls.props.ifc_class
total_types = len(tool.Ifc.get().by_type(ifc_class)) if ifc_class else 0
type_class = cls.props.type_class
total_types = len(tool.Ifc.get().by_type(type_class)) if type_class else 0
return math.ceil(total_types / cls.types_per_page)
@classmethod
@@ -93,20 +114,26 @@ class AuthoringData:
@classmethod
def paginated_relating_types(cls):
ifc_class = cls.props.ifc_class
if not ifc_class:
type_class = cls.props.type_class
if not type_class:
return []
results = []
elements = sorted(tool.Ifc.get().by_type(ifc_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 = 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]
for element in elements:
results.append({
"id": element.id(),
"ifc_class": element.is_a(),
"name": element.Name or "Unnamed",
"description": element.Description or "No Description",
"icon_id": cls.type_thumbnails.get(element.id(), None) or 0,
})
predefined_type = ifcopenshell.util.element.get_predefined_type(element)
if predefined_type == "NOTDEFINED":
predefined_type = None
results.append(
{
"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
@classmethod
@@ -29,6 +29,12 @@ def get_ifc_class(self, context):
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):
if not AuthoringData.is_loaded:
AuthoringData.load()
@@ -41,6 +47,12 @@ def get_relating_type_browser(self, context):
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):
browser_state = context.scene.BIMModelProperties.constr_browser_state
if cursor:
@@ -62,8 +74,10 @@ def update_icon_id(self, context, browser=False):
return
def set_icon(update_interval_seconds=1e-4):
if (ifc_class not in self.constr_classes
or relating_type_id not in self.constr_classes[ifc_class].constr_types):
if (
ifc_class not in self.constr_classes
or relating_type_id not in self.constr_classes[ifc_class].constr_types
):
return update_interval_seconds
else:
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()
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):
if context.region is not None and context.region.type != "TOOL_HEADER":
AuthoringData.load_ifc_classes()
@@ -206,3 +229,16 @@ class BIMModelProperties(PropertyGroup):
z: bpy.props.FloatProperty(name="Z", default=0.5)
rl: bpy.props.FloatProperty(name="RL", default=1)
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):
props = context.scene.BIMModelProperties
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)
if not AuthoringData.is_loaded:
AuthoringData.load()
@@ -43,15 +45,24 @@ class LaunchTypeManager(bpy.types.Operator):
def draw(self, context):
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.label(text=f"", icon="FILE_VOLUME")
text = f"{AuthoringData.data['total_types']} types"
if AuthoringData.data["total_pages"] > 1:
text += f" ({props.type_page}/{AuthoringData.data['total_pages']}) "
row.label(text=text)
row.label(text=f"Page {props.type_page}/{AuthoringData.data['total_pages']} ")
if AuthoringData.data["prev_page"]:
op = row.operator("bim.change_type_page", icon="TRIA_LEFT", text="")
op.page = AuthoringData.data["prev_page"]
@@ -74,11 +85,16 @@ class LaunchTypeManager(bpy.types.Operator):
row.label(text=relating_type["description"])
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)
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.ifc_class = relating_type["ifc_class"]
op.relating_type_id = relating_type["id"]