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 import bpy
from blenderbim.bim.module.model.data import AuthoringData from blenderbim.bim.module.model.data import AuthoringData
from blenderbim.bim.module.model.root import ConstrTypeEntityNotFound
from bpy.types import PropertyGroup from bpy.types import PropertyGroup
from math import pi from math import pi
@@ -96,9 +96,6 @@ classes = (
slab.ResetVertex, slab.ResetVertex,
slab.SetArcIndex, slab.SetArcIndex,
space.GenerateSpace, space.GenerateSpace,
prop.ConstrTypeInfo,
prop.ConstrClassInfo,
prop.ConstrBrowserState,
prop.BIMModelProperties, prop.BIMModelProperties,
prop.BIMArrayProperties, prop.BIMArrayProperties,
prop.BIMStairProperties, prop.BIMStairProperties,
@@ -116,7 +113,6 @@ classes = (
ui.BIM_PT_railing, ui.BIM_PT_railing,
ui.BIM_PT_roof, ui.BIM_PT_roof,
ui.LaunchTypeManager, ui.LaunchTypeManager,
ui.HelpConstrTypes,
ui.BIM_MT_model, ui.BIM_MT_model,
grid.BIM_OT_add_object, grid.BIM_OT_add_object,
stair.BIM_OT_add_object, stair.BIM_OT_add_object,
@@ -24,8 +24,6 @@ import ifcopenshell
import ifcopenshell.util.element import ifcopenshell.util.element
from ifcopenshell.util.doc import get_entity_doc, get_predefined_type_doc from ifcopenshell.util.doc import get_entity_doc, get_predefined_type_doc
import blenderbim.tool as tool import blenderbim.tool as tool
from blenderbim.bim.ifc import IfcStore
from blenderbim.bim.module.model.root import ConstrTypeEntityNotFound
def refresh(): def refresh():
@@ -49,9 +47,8 @@ class AuthoringData:
def load(cls): def load(cls):
cls.is_loaded = True cls.is_loaded = True
cls.props = bpy.context.scene.BIMModelProperties cls.props = bpy.context.scene.BIMModelProperties
cls.load_ifc_classes() cls.data["ifc_classes"] = cls.ifc_classes()
cls.load_relating_types() cls.data["relating_type_id"] = cls.relating_type_id()
cls.load_relating_types_browser()
cls.data["type_class"] = cls.type_class() cls.data["type_class"] = cls.type_class()
cls.data["type_predefined_type"] = cls.type_predefined_type() cls.data["type_predefined_type"] = cls.type_predefined_type()
cls.data["total_types"] = cls.total_types() cls.data["total_types"] = cls.total_types()
@@ -100,23 +97,11 @@ class AuthoringData:
@classmethod @classmethod
def type_thumbnail(cls): def type_thumbnail(cls):
if not cls.data["relating_types_ids"]: if not cls.data["relating_type_id"]:
return 0 return 0
element = tool.Ifc.get().by_id(int(cls.props.relating_type_id)) element = tool.Ifc.get().by_id(int(cls.props.relating_type_id))
return cls.type_thumbnails.get(element.id(), None) or 0 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 @classmethod
def total_types(cls): def total_types(cls):
type_class = cls.props.type_class type_class = cls.props.type_class
@@ -210,155 +195,23 @@ class AuthoringData:
return results return results
@classmethod @classmethod
def constr_class_entities(cls, ifc_class=None): def relating_type_id(cls):
ifc_classes = cls.data["ifc_classes"] ifc_classes = cls.data["ifc_classes"]
if not ifc_classes: if not ifc_classes:
return [] return []
results = [] 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: if not ifc_class and ifc_classes:
ifc_class = ifc_classes[0][0] ifc_class = ifc_classes[0][0]
if ifc_class: if ifc_class:
elements = sorted(tool.Ifc.get().by_type(ifc_class), key=lambda s: s.Name or "Unnamed") elements = sorted(tool.Ifc.get().by_type(ifc_class), key=lambda s: s.Name or "Unnamed")
results.extend(elements) results.extend(elements)
return results return [
(str(e.id()), e.Name or "Unnamed", e.Description or "")
for e in results
]
return [] 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: class ArrayData:
data = {} data = {}
@@ -21,7 +21,6 @@ import ifcopenshell
import blenderbim.tool as tool import blenderbim.tool as tool
from blenderbim.bim.prop import ObjProperty from blenderbim.bim.prop import ObjProperty
from blenderbim.bim.module.model.data import AuthoringData from blenderbim.bim.module.model.data import AuthoringData
from blenderbim.bim.module.model.root import ConstrTypeEntityNotFound
from bpy.types import PropertyGroup, NodeTree from bpy.types import PropertyGroup, NodeTree
from math import pi from math import pi
@@ -38,16 +37,10 @@ def get_type_class(self, context):
return AuthoringData.data["type_class"] return AuthoringData.data["type_class"]
def get_relating_type(self, context): def get_relating_type_id(self, context):
if not AuthoringData.is_loaded: if not AuthoringData.is_loaded:
AuthoringData.load() AuthoringData.load()
return AuthoringData.data["relating_types_ids"] return AuthoringData.data["relating_type_id"]
def get_relating_type_browser(self, context):
if not AuthoringData.is_loaded:
AuthoringData.load()
return AuthoringData.data["relating_types_ids_browser"]
def get_type_predefined_type(self, context): def get_type_predefined_type(self, context):
@@ -56,33 +49,9 @@ def get_type_predefined_type(self, context):
return AuthoringData.data["type_predefined_type"] 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): def update_ifc_class(self, context):
bpy.ops.bim.load_type_thumbnails(ifc_class=self.ifc_class) 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() 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() AuthoringData.data["type_predefined_type"] = AuthoringData.type_predefined_type()
def update_ifc_class_browser(self, context): def update_relating_type_id(self, context):
if context.region is not None and context.region.type != "TOOL_HEADER": AuthoringData.data["relating_type_id"] = AuthoringData.relating_type_id()
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()
AuthoringData.data["type_thumbnail"] = AuthoringData.type_thumbnail() 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() 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): class BIMModelProperties(PropertyGroup):
ifc_class: bpy.props.EnumProperty(items=get_ifc_class, name="Construction Class", update=update_ifc_class) 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( relating_type_id: bpy.props.EnumProperty(
items=get_relating_type, name="Construction Type", update=update_relating_type items=get_relating_type_id, name="Construction Type", update=update_relating_type_id
)
relating_type_id_browser: bpy.props.EnumProperty(
items=get_relating_type_browser, name="Construction Type", update=update_relating_type_browser
) )
icon_id: bpy.props.IntProperty() icon_id: bpy.props.IntProperty()
preview_multiple_constr_types: bpy.props.BoolProperty(default=False, update=update_preview_multiple)
updating: bpy.props.BoolProperty(default=False) updating: bpy.props.BoolProperty(default=False)
occurrence_name_style: bpy.props.EnumProperty( occurrence_name_style: bpy.props.EnumProperty(
items=[("CLASS", "By Class", ""), ("TYPE", "By Type", ""), ("CUSTOM", "Custom", "")], items=[("CLASS", "By Class", ""), ("TYPE", "By Type", ""), ("CUSTOM", "Custom", "")],
name="Occurrence Name Style", name="Occurrence Name Style",
) )
occurrence_name_function: bpy.props.StringProperty(name="Occurrence Name Function") occurrence_name_function: bpy.props.StringProperty(name="Occurrence Name Function")
getter_enum = {"ifc_class": get_ifc_class, "relating_type": get_relating_type} getter_enum = {"ifc_class": get_ifc_class, "relating_type": get_relating_type_id}
constr_classes: bpy.props.CollectionProperty(type=ConstrClassInfo)
constr_browser_state: bpy.props.PointerProperty(type=ConstrBrowserState)
extrusion_depth: bpy.props.FloatProperty(default=42.0) extrusion_depth: bpy.props.FloatProperty(default=42.0)
cardinal_point: bpy.props.EnumProperty( cardinal_point: bpy.props.EnumProperty(
items=( items=(
@@ -48,8 +48,3 @@ def sync_name(usecase_path, ifc_file, settings):
collection.name = new_name collection.name = new_name
obj.name = new_name obj.name = new_name
blenderbim.bim.handler.refresh_ui_data() 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" 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): class BIM_PT_array(bpy.types.Panel):
bl_label = "IFC Array" bl_label = "IFC Array"
bl_idname = "BIM_PT_array" bl_idname = "BIM_PT_array"
@@ -111,7 +111,7 @@ class BimToolUI:
@classmethod @classmethod
def draw_create_object_interface(cls): def draw_create_object_interface(cls):
if not AuthoringData.data["relating_types_ids"]: if not AuthoringData.data["relating_type_id"]:
return return
if cls.props.ifc_class == "IfcWallType": if cls.props.ifc_class == "IfcWallType":
row = cls.layout.row(align=True) row = cls.layout.row(align=True)
@@ -301,7 +301,7 @@ class BimToolUI:
prop_with_search(row, cls.props, "ifc_class", text="") prop_with_search(row, cls.props, "ifc_class", text="")
row = cls.layout.row(align=True) row = cls.layout.row(align=True)
if AuthoringData.data["relating_types_ids"]: if AuthoringData.data["relating_type_id"]:
row.label(text="", icon="FILE_3D") row.label(text="", icon="FILE_3D")
prop_with_search(row, cls.props, "relating_type_id", text="") prop_with_search(row, cls.props, "relating_type_id", text="")
else: else: