Purge old code from timer-based type browser system

This commit is contained in:
Dion Moult
2023-04-13 21:39:26 +10:00
parent f2c25f430a
commit e5c9f0e38f
7 changed files with 18 additions and 333 deletions
@@ -18,7 +18,6 @@
import bpy
from blenderbim.bim.module.model.data import AuthoringData
from blenderbim.bim.module.model.root import ConstrTypeEntityNotFound
from bpy.types import PropertyGroup
from math import pi
@@ -96,9 +96,6 @@ classes = (
slab.ResetVertex,
slab.SetArcIndex,
space.GenerateSpace,
prop.ConstrTypeInfo,
prop.ConstrClassInfo,
prop.ConstrBrowserState,
prop.BIMModelProperties,
prop.BIMArrayProperties,
prop.BIMStairProperties,
@@ -116,7 +113,6 @@ classes = (
ui.BIM_PT_railing,
ui.BIM_PT_roof,
ui.LaunchTypeManager,
ui.HelpConstrTypes,
ui.BIM_MT_model,
grid.BIM_OT_add_object,
stair.BIM_OT_add_object,
@@ -24,8 +24,6 @@ import ifcopenshell
import ifcopenshell.util.element
from ifcopenshell.util.doc import get_entity_doc, get_predefined_type_doc
import blenderbim.tool as tool
from blenderbim.bim.ifc import IfcStore
from blenderbim.bim.module.model.root import ConstrTypeEntityNotFound
def refresh():
@@ -49,9 +47,8 @@ class AuthoringData:
def load(cls):
cls.is_loaded = True
cls.props = bpy.context.scene.BIMModelProperties
cls.load_ifc_classes()
cls.load_relating_types()
cls.load_relating_types_browser()
cls.data["ifc_classes"] = cls.ifc_classes()
cls.data["relating_type_id"] = cls.relating_type_id()
cls.data["type_class"] = cls.type_class()
cls.data["type_predefined_type"] = cls.type_predefined_type()
cls.data["total_types"] = cls.total_types()
@@ -100,23 +97,11 @@ class AuthoringData:
@classmethod
def type_thumbnail(cls):
if not cls.data["relating_types_ids"]:
if not cls.data["relating_type_id"]:
return 0
element = tool.Ifc.get().by_id(int(cls.props.relating_type_id))
return cls.type_thumbnails.get(element.id(), None) or 0
@classmethod
def load_ifc_classes(cls):
cls.data["ifc_classes"] = cls.ifc_classes()
@classmethod
def load_relating_types(cls):
cls.data["relating_types_ids"] = cls.relating_types()
@classmethod
def load_relating_types_browser(cls):
cls.data["relating_types_ids_browser"] = cls.relating_types_browser()
@classmethod
def total_types(cls):
type_class = cls.props.type_class
@@ -210,155 +195,23 @@ class AuthoringData:
return results
@classmethod
def constr_class_entities(cls, ifc_class=None):
def relating_type_id(cls):
ifc_classes = cls.data["ifc_classes"]
if not ifc_classes:
return []
results = []
if ifc_class is None:
ifc_class = cls.props.ifc_class
ifc_class = cls.props.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 or "Unnamed")
results.extend(elements)
return results
return [
(str(e.id()), e.Name or "Unnamed", e.Description or "")
for e in results
]
return []
@classmethod
def relating_types(cls, ifc_class=None):
return [
(str(e.id()), e.Name or "Unnamed", e.Description or "")
for e in cls.constr_class_entities(ifc_class=ifc_class)
]
@classmethod
def relating_types_browser(cls):
if cls.data["ifc_classes"]:
return cls.relating_types(ifc_class=cls.props.ifc_class_browser)
@classmethod
def new_constr_class_info(cls, ifc_class):
if ifc_class not in cls.props.constr_classes:
cls.props.constr_classes.add().name = ifc_class
return cls.props.constr_classes[ifc_class]
@classmethod
def assetize_constr_class(cls, ifc_class=None):
selected_ifc_class = cls.props.ifc_class
selected_relating_type_id = cls.props.relating_type_id
if ifc_class is None:
ifc_class = cls.props.ifc_class_browser
if cls.constr_class_info(ifc_class) is None:
cls.new_constr_class_info(ifc_class)
constr_class_occurrences = cls.constr_class_entities(ifc_class)
constr_classes = cls.props.constr_classes
for constr_class_entity in constr_class_occurrences:
if (
ifc_class not in constr_classes
or constr_class_entity.Name not in constr_classes[ifc_class].constr_types
):
obj = tool.Ifc.get_object(constr_class_entity)
cls.assetize_object(obj, ifc_class, constr_class_entity)
cls.constr_class_info(ifc_class).fully_loaded = True
cls.props.updating = True
cls.props.ifc_class = selected_ifc_class
cls.props.relating_type_id = selected_relating_type_id
cls.props.updating = False
@classmethod
def assetize_object(cls, obj, ifc_class, ifc_class_entity, from_selection=False):
relating_type_id = ifc_class_entity.id()
to_be_deleted = False
if obj.type == "EMPTY":
kwargs = {}
if not from_selection:
kwargs.update({"ifc_class": ifc_class, "relating_type_id": relating_type_id})
new_obj = cls.new_relating_type(**kwargs)
if new_obj is not None:
to_be_deleted = True
obj = new_obj
obj.hide_set(True)
obj.asset_mark()
obj.asset_generate_preview()
blender33_or_above = bpy.app.version >= (3, 3, 0)
interval = 1e-4
def wait_for_asset_previews_generation(check_interval_seconds=interval):
if blender33_or_above and bpy.app.is_job_running("RENDER_PREVIEW"):
return check_interval_seconds
else:
if ifc_class not in cls.props.constr_classes:
cls.props.constr_classes.add().name = ifc_class
constr_class_info = cls.props.constr_classes[ifc_class]
# relating_type = cls.relating_type_name_by_id(ifc_class, relating_type_id)
if str(relating_type_id) not in constr_class_info.constr_types:
constr_class_info.constr_types.add().name = str(relating_type_id)
relating_type_info = constr_class_info.constr_types[str(relating_type_id)]
relating_type_info.object = obj
relating_type_info.icon_id = obj.preview.icon_id
if to_be_deleted:
element = tool.Ifc.get_entity(obj)
if element:
tool.Ifc.delete(element)
tool.Ifc.unlink(obj=obj)
for collection in obj.users_collection:
collection.objects.unlink(obj)
return None
first_interval = 0 if blender33_or_above else interval
bpy.app.timers.register(wait_for_asset_previews_generation, first_interval=first_interval)
@classmethod
def assetize_relating_type_from_selection(cls, browser=False):
ifc_class = cls.props.ifc_class_browser if browser else cls.props.ifc_class
relating_type_id = cls.props.relating_type_id_browser if browser else cls.props.relating_type_id
constr_class_occurrences = cls.constr_class_entities(ifc_class=ifc_class)
constr_class_occurrences = [
entity for entity in constr_class_occurrences if entity.id() == int(relating_type_id)
]
if len(constr_class_occurrences) == 0:
raise ConstrTypeEntityNotFound()
constr_class_entity = constr_class_occurrences[0]
if (obj := tool.Ifc.get_object(constr_class_entity)) is None:
raise ConstrTypeEntityNotFound()
cls.assetize_object(obj, ifc_class, constr_class_entity, from_selection=True)
@staticmethod
def constr_class_info(ifc_class):
props = bpy.context.scene.BIMModelProperties
return props.constr_classes[ifc_class] if ifc_class in props.constr_classes else None
@classmethod
def new_relating_type(cls, ifc_class=None, relating_type_id=None):
if ifc_class is None:
bpy.ops.bim.add_constr_type_instance(
ifc_class=cls.props.ifc_class, relating_type_id=int(cls.props.relating_type_id)
)
else:
cls.props.updating = True
cls.props.ifc_class = ifc_class
cls.props.relating_type_id = str(relating_type_id)
cls.props.updating = False
bpy.ops.bim.add_constr_type_instance()
return bpy.context.selected_objects[-1]
@staticmethod
def relating_type_name_by_id(ifc_class, relating_type_id):
file = IfcStore.get_file()
try:
constr_class_entity = file.by_id(int(relating_type_id))
except (RuntimeError, ValueError):
return None
return constr_class_entity.Name if constr_class_entity.is_a() == ifc_class else None
@classmethod
def relating_type_id_by_name(cls, ifc_class, relating_type):
relating_types = [ct[0] for ct in cls.relating_types(ifc_class=ifc_class) if ct[1] == relating_type]
return None if len(relating_types) == 0 else relating_types[0]
class ArrayData:
data = {}
@@ -21,7 +21,6 @@ import ifcopenshell
import blenderbim.tool as tool
from blenderbim.bim.prop import ObjProperty
from blenderbim.bim.module.model.data import AuthoringData
from blenderbim.bim.module.model.root import ConstrTypeEntityNotFound
from bpy.types import PropertyGroup, NodeTree
from math import pi
@@ -38,16 +37,10 @@ def get_type_class(self, context):
return AuthoringData.data["type_class"]
def get_relating_type(self, context):
def get_relating_type_id(self, context):
if not AuthoringData.is_loaded:
AuthoringData.load()
return AuthoringData.data["relating_types_ids"]
def get_relating_type_browser(self, context):
if not AuthoringData.is_loaded:
AuthoringData.load()
return AuthoringData.data["relating_types_ids_browser"]
return AuthoringData.data["relating_type_id"]
def get_type_predefined_type(self, context):
@@ -56,33 +49,9 @@ def get_type_predefined_type(self, context):
return AuthoringData.data["type_predefined_type"]
def update_icon_id(self, context, browser=False):
if context == "lost_context" or (context.region is not None and context.region.type != "TOOL_HEADER"):
ifc_class = self.ifc_class_browser if browser else self.ifc_class
relating_type_id = self.relating_type_id_browser if browser else self.relating_type_id
# relating_type = AuthoringData.relating_type_name_by_id(ifc_class, relating_type_id)
if ifc_class not in self.constr_classes or relating_type_id not in self.constr_classes[ifc_class].constr_types:
try:
AuthoringData.assetize_relating_type_from_selection(browser=browser)
except ConstrTypeEntityNotFound:
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
):
return update_interval_seconds
else:
self.icon_id = self.constr_classes[ifc_class].constr_types[relating_type_id].icon_id
bpy.app.timers.register(set_icon)
def update_ifc_class(self, context):
bpy.ops.bim.load_type_thumbnails(ifc_class=self.ifc_class)
AuthoringData.data["relating_types_ids"] = AuthoringData.relating_types()
AuthoringData.data["relating_type_id"] = AuthoringData.relating_types()
AuthoringData.data["type_thumbnail"] = AuthoringData.type_thumbnail()
@@ -95,21 +64,8 @@ def update_type_class(self, context):
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()
AuthoringData.load_relating_types_browser()
if self.updating:
return
ifc_class = self.ifc_class_browser
constr_class_info = AuthoringData.constr_class_info(ifc_class)
if constr_class_info is None or not constr_class_info.fully_loaded:
AuthoringData.assetize_constr_class(ifc_class)
def update_relating_type(self, context):
AuthoringData.load_relating_types()
def update_relating_type_id(self, context):
AuthoringData.data["relating_type_id"] = AuthoringData.relating_type_id()
AuthoringData.data["type_thumbnail"] = AuthoringData.type_thumbnail()
@@ -117,80 +73,19 @@ def update_type_page(self, context):
AuthoringData.data["paginated_relating_types"] = AuthoringData.paginated_relating_types()
def update_relating_type_browser(self, context):
AuthoringData.load_relating_types_browser()
if not self.updating:
update_icon_id(self, context, browser=True)
def update_relating_type_by_name(self, context):
AuthoringData.load_relating_types()
relating_type_id = AuthoringData.relating_type_id_by_name(self.ifc_class, self.relating_type)
if relating_type_id is not None:
self.relating_type_id = relating_type_id
def get_constr_class_info(props, ifc_class):
return props.constr_classes[ifc_class] if ifc_class in props.constr_classes else None
def update_preview_multiple(self, context):
if context.region is not None and context.region.type != "TOOL_HEADER":
if self.preview_multiple_constr_types:
ifc_class = self.ifc_class
constr_class_info = get_constr_class_info(self, ifc_class)
if constr_class_info is None or not constr_class_info.fully_loaded:
AuthoringData.assetize_constr_class(ifc_class)
else:
update_relating_type(self, context)
class ConstrTypeInfo(PropertyGroup):
name: bpy.props.StringProperty(name="Construction type ID")
icon_id: bpy.props.IntProperty(name="Icon ID")
object: bpy.props.PointerProperty(name="Object", type=bpy.types.Object)
class ConstrClassInfo(PropertyGroup):
name: bpy.props.StringProperty(name="Construction class")
constr_types: bpy.props.CollectionProperty(type=ConstrTypeInfo)
fully_loaded: bpy.props.BoolProperty(default=False)
class ConstrBrowserState(PropertyGroup):
cursor_x: bpy.props.IntProperty()
cursor_y: bpy.props.IntProperty()
window_x: bpy.props.IntProperty()
window_y: bpy.props.IntProperty()
far_away_x: bpy.props.IntProperty(default=10) # lower left corner to temporarily warp the mouse
far_away_y: bpy.props.IntProperty(default=10) # useful to close popup operators
updating: bpy.props.BoolProperty()
update_delay: bpy.props.FloatProperty(default=3e-2)
class BIMModelProperties(PropertyGroup):
ifc_class: bpy.props.EnumProperty(items=get_ifc_class, name="Construction Class", update=update_ifc_class)
ifc_class_browser: bpy.props.EnumProperty(
items=get_ifc_class, name="Construction Class", update=update_ifc_class_browser
)
relating_type: bpy.props.StringProperty(update=update_relating_type_by_name)
relating_type_id: bpy.props.EnumProperty(
items=get_relating_type, name="Construction Type", update=update_relating_type
)
relating_type_id_browser: bpy.props.EnumProperty(
items=get_relating_type_browser, name="Construction Type", update=update_relating_type_browser
items=get_relating_type_id, name="Construction Type", update=update_relating_type_id
)
icon_id: bpy.props.IntProperty()
preview_multiple_constr_types: bpy.props.BoolProperty(default=False, update=update_preview_multiple)
updating: bpy.props.BoolProperty(default=False)
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_classes: bpy.props.CollectionProperty(type=ConstrClassInfo)
constr_browser_state: bpy.props.PointerProperty(type=ConstrBrowserState)
getter_enum = {"ifc_class": get_ifc_class, "relating_type": get_relating_type_id}
extrusion_depth: bpy.props.FloatProperty(default=42.0)
cardinal_point: bpy.props.EnumProperty(
items=(
@@ -48,8 +48,3 @@ def sync_name(usecase_path, ifc_file, settings):
collection.name = new_name
obj.name = new_name
blenderbim.bim.handler.refresh_ui_data()
class ConstrTypeEntityNotFound(Exception):
pass
@@ -137,59 +137,6 @@ class BIM_PT_authoring(Panel):
row.operator("bim.align_wall", icon="ANCHOR_BOTTOM", text="Int.").align_type = "INTERIOR"
class HelpConstrTypes(Operator):
bl_idname = "bim.help_relating_types"
bl_label = "Construction Types Help"
bl_options = {"REGISTER", "UNDO"}
bl_description = "Click to read some contextual help"
def execute(self, context):
return {"FINISHED"}
def invoke(self, context, event):
return context.window_manager.invoke_popup(self, width=510)
def draw(self, context):
layout = self.layout
layout.row().separator(factor=0.5)
row = layout.row()
row.alignment = "CENTER"
row.label(text="BlenderBIM Help", icon="BLENDER")
layout.row().separator(factor=0.5)
row = layout.row().row()
row.label(text="Overview:", icon="KEYTYPE_MOVING_HOLD_VEC")
self.draw_lines(layout, self.message_summary)
layout.row().separator()
row = layout.row().row()
row.label(text="Further support:", icon="KEYTYPE_MOVING_HOLD_VEC")
layout.row().separator(factor=0.5)
row = layout.row()
op = row.operator("bim.open_upstream", text="Homepage", icon="HOME")
op.page = "home"
op = row.operator("bim.open_upstream", text="Docs", icon="DOCUMENTS")
op.page = "docs"
op = row.operator("bim.open_upstream", text="Wiki", icon="CURRENT_FILE")
op.page = "wiki"
op = row.operator("bim.open_upstream", text="Community", icon="COMMUNITY")
op.page = "community"
layout.row().separator()
def draw_lines(self, layout, lines):
box = layout.box()
for line in lines:
row = box.row()
row.label(text=f" {line}")
@property
def message_summary(self):
return [
"The Construction Type Browser allows to preview and add new instances to the model.",
"For further support, please click on the Documentation link below.",
]
class BIM_PT_array(bpy.types.Panel):
bl_label = "IFC Array"
bl_idname = "BIM_PT_array"
@@ -111,7 +111,7 @@ class BimToolUI:
@classmethod
def draw_create_object_interface(cls):
if not AuthoringData.data["relating_types_ids"]:
if not AuthoringData.data["relating_type_id"]:
return
if cls.props.ifc_class == "IfcWallType":
row = cls.layout.row(align=True)
@@ -301,7 +301,7 @@ class BimToolUI:
prop_with_search(row, cls.props, "ifc_class", text="")
row = cls.layout.row(align=True)
if AuthoringData.data["relating_types_ids"]:
if AuthoringData.data["relating_type_id"]:
row.label(text="", icon="FILE_3D")
prop_with_search(row, cls.props, "relating_type_id", text="")
else: