mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 09:48:32 +00:00
Type manager can now browse to type classes that don't have any types yet
This commit is contained in:
@@ -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"]
|
||||
|
||||
Reference in New Issue
Block a user