From 86e3d1e5480ffa170d24744d14015d9d7a365df8 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Sat, 23 Jan 2021 12:54:27 +1100 Subject: [PATCH] WIP refactor root module properties. See #1222. --- .../bim/module/bimtester/operator.py | 43 +++++---- .../blenderbim/bim/module/csv/operator.py | 5 +- .../blenderbim/bim/module/diff/operator.py | 1 - .../blenderbim/bim/module/root/__init__.py | 7 +- .../blenderbim/bim/module/root/operator.py | 17 ++-- .../blenderbim/bim/module/root/prop.py | 94 +++++++++++++++++++ .../blenderbim/bim/module/root/ui.py | 8 +- src/ifcblenderexport/blenderbim/bim/prop.py | 74 --------------- 8 files changed, 138 insertions(+), 111 deletions(-) create mode 100644 src/ifcblenderexport/blenderbim/bim/module/root/prop.py diff --git a/src/ifcblenderexport/blenderbim/bim/module/bimtester/operator.py b/src/ifcblenderexport/blenderbim/bim/module/bimtester/operator.py index 41df7fa30e..78aa34b24f 100644 --- a/src/ifcblenderexport/blenderbim/bim/module/bimtester/operator.py +++ b/src/ifcblenderexport/blenderbim/bim/module/bimtester/operator.py @@ -5,6 +5,7 @@ import os import webbrowser from pathlib import Path from itertools import cycle +from blenderbim.bim.ifc import IfcStore class ExecuteBIMTester(bpy.types.Operator): @@ -67,12 +68,11 @@ class RejectElement(bpy.types.Operator): def execute(self, context): lines = [] - for object in bpy.context.selected_objects: + self.file = IfcStore.get_file() + for obj in bpy.context.selected_objects: lines.append( " * The element {} should not exist because {}".format( - object.BIMObjectProperties.attributes[ - object.BIMObjectProperties.attributes.find("GlobalId") - ].string_value, + self.file.by_id(obj.BIMObjectProperties.ifc_definition_id).GlobalId, bpy.context.scene.BimTesterProperties.qa_reject_element_reason, ) ) @@ -112,14 +112,16 @@ class ApproveClass(bpy.types.Operator): def execute(self, context): lines = [] - for object in bpy.context.selected_objects: - index = object.BIMObjectProperties.attributes.find("GlobalId") - if index != -1: - lines.append( - " * The element {} is an {}".format( - object.BIMObjectProperties.attributes[index].string_value, object.name.split("/")[0] - ) + self.file = IfcStore.get_file() + for obj in bpy.context.selected_objects: + if not obj.BIMObjectProperties.ifc_definition_id: + continue + element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id) + lines.append( + " * The element {} is an {}".format( + element.GlobalId, element.is_a() ) + ) QAHelper.append_to_scenario(lines) return {"FINISHED"} @@ -129,12 +131,13 @@ class RejectClass(bpy.types.Operator): def execute(self, context): lines = [] - for object in bpy.context.selected_objects: + self.file = IfcStore.get_file() + for obj in bpy.context.selected_objects: + if not obj.BIMObjectProperties.ifc_definition_id: + continue lines.append( " * The element {} is an {}".format( - object.BIMObjectProperties.attributes[ - object.BIMObjectProperties.attributes.find("GlobalId") - ].string_value, + self.file.by_id(obj.BIMObjectProperties.ifc_definition_id).GlobalId, bpy.context.scene.BimTesterProperties.audit_ifc_class, ) ) @@ -147,6 +150,7 @@ class SelectAudited(bpy.types.Operator): def execute(self, context): audited_global_ids = [] + self.file = IfcStore.get_file() for filename in Path(bpy.context.scene.BimTesterProperties.features_dir).glob("*.feature"): with open(filename, "r") as feature_file: lines = feature_file.readlines() @@ -155,10 +159,11 @@ class SelectAudited(bpy.types.Operator): for word in words: if self.is_a_global_id(word): audited_global_ids.append(word) - for object in bpy.context.visible_objects: - index = object.BIMObjectProperties.attributes.find("GlobalId") - if index != -1 and object.BIMObjectProperties.attributes[index].string_value in audited_global_ids: - object.select_set(True) + for obj in bpy.context.visible_objects: + if not obj.BIMObjectProperties.ifc_definition_id: + continue + if self.file.by_id(obj.BIMObjectProperties.ifc_definition_id).GlobalId in audited_global_ids: + obj.select_set(True) return {"FINISHED"} def is_a_global_id(self, word): diff --git a/src/ifcblenderexport/blenderbim/bim/module/csv/operator.py b/src/ifcblenderexport/blenderbim/bim/module/csv/operator.py index 1a54a1855e..cc9fdee81a 100644 --- a/src/ifcblenderexport/blenderbim/bim/module/csv/operator.py +++ b/src/ifcblenderexport/blenderbim/bim/module/csv/operator.py @@ -90,9 +90,10 @@ class EyedropIfcCsv(bpy.types.Operator): def execute(self, context): global_ids = [] + self.file = IfcStore.get_file() for obj in context.selected_objects: - if hasattr(obj, "BIMObjectProperties") and obj.BIMObjectProperties.attributes.get("GlobalId"): - global_ids.append("#" + obj.BIMObjectProperties.attributes.get("GlobalId").string_value) + if hasattr(obj, "BIMObjectProperties") and obj.BIMObjectProperties.ifc_definition_id: + global_ids.append("#" + self.file.by_id(obj.BIMObjectProperties.ifc_definition_id).GlobalId) context.scene.CsvProperties.ifc_selector = "|".join(global_ids) return {"FINISHED"} diff --git a/src/ifcblenderexport/blenderbim/bim/module/diff/operator.py b/src/ifcblenderexport/blenderbim/bim/module/diff/operator.py index 7b34cc4bbf..5ca9dfefc8 100644 --- a/src/ifcblenderexport/blenderbim/bim/module/diff/operator.py +++ b/src/ifcblenderexport/blenderbim/bim/module/diff/operator.py @@ -32,7 +32,6 @@ class VisualiseDiff(bpy.types.Operator): for obj in bpy.context.visible_objects: obj.color = (1.0, 1.0, 1.0, 0.2) global_id = ifc_file.by_id(obj.BIMObjectProperties.ifc_definition_id).GlobalId - #global_id = obj.BIMObjectProperties.attributes.get("GlobalId") if not global_id: continue if global_id.string_value in diff["deleted"]: diff --git a/src/ifcblenderexport/blenderbim/bim/module/root/__init__.py b/src/ifcblenderexport/blenderbim/bim/module/root/__init__.py index 32d3c5e695..a4938ddf68 100644 --- a/src/ifcblenderexport/blenderbim/bim/module/root/__init__.py +++ b/src/ifcblenderexport/blenderbim/bim/module/root/__init__.py @@ -1,5 +1,5 @@ import bpy -from . import ui, operator +from . import ui, prop, operator classes = ( operator.EnableReassignClass, @@ -7,13 +7,14 @@ classes = ( operator.ReassignClass, operator.AssignClass, operator.UnassignClass, + prop.BIMRootProperties, ui.BIM_PT_class, ) def register(): - pass + bpy.types.Scene.BIMRootProperties = bpy.props.PointerProperty(type=prop.BIMRootProperties) def unregister(): - pass + del bpy.types.Scene.BIMRootProperties diff --git a/src/ifcblenderexport/blenderbim/bim/module/root/operator.py b/src/ifcblenderexport/blenderbim/bim/module/root/operator.py index 3d71a7778c..279af04897 100644 --- a/src/ifcblenderexport/blenderbim/bim/module/root/operator.py +++ b/src/ifcblenderexport/blenderbim/bim/module/root/operator.py @@ -14,6 +14,7 @@ class EnableReassignClass(bpy.types.Operator): def execute(self, context): obj = bpy.context.active_object + self.file = IfcStore.get_file() ifc_class = obj.name.split("/")[0] bpy.context.active_object.BIMObjectProperties.is_reassigning_class = True ifc_products = [ @@ -28,11 +29,11 @@ class EnableReassignClass(bpy.types.Operator): ] for ifc_product in ifc_products: if ifcopenshell.util.schema.is_a(IfcStore.get_schema().declaration_by_name(ifc_class), ifc_product): - bpy.context.scene.BIMProperties.ifc_product = ifc_product - bpy.context.scene.BIMProperties.ifc_class = obj.name.split("/")[0] - predefined_type = obj.BIMObjectProperties.attributes.get("PredefinedType") - if predefined_type: - bpy.context.scene.BIMProperties.ifc_predefined_type = predefined_type.string_value + bpy.context.scene.BIMRootProperties.ifc_product = ifc_product + element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id) + bpy.context.scene.BIMRootProperties.ifc_class = element.is_a() + if hasattr(element, "PredefinedType") and element.PredefinedType: + bpy.context.scene.BIMRootProperties.ifc_predefined_type = element.PredefinedType return {"FINISHED"} @@ -52,14 +53,14 @@ class ReassignClass(bpy.types.Operator): def execute(self, context): obj = bpy.context.active_object self.file = IfcStore.get_file() - predefined_type = bpy.context.scene.BIMProperties.ifc_predefined_type + predefined_type = bpy.context.scene.BIMRootProperties.ifc_predefined_type if predefined_type == "USERDEFINED": - predefined_type = bpy.context.scene.BIMProperties.ifc_userdefined_type + predefined_type = bpy.context.scene.BIMRootProperties.ifc_userdefined_type product = reassign_class.Usecase( self.file, { "product": self.file.by_id(obj.BIMObjectProperties.ifc_definition_id), - "ifc_class": bpy.context.scene.BIMProperties.ifc_class, + "ifc_class": bpy.context.scene.BIMRootProperties.ifc_class, "predefined_type": predefined_type, }, ).execute() diff --git a/src/ifcblenderexport/blenderbim/bim/module/root/prop.py b/src/ifcblenderexport/blenderbim/bim/module/root/prop.py new file mode 100644 index 0000000000..ea8c6ded28 --- /dev/null +++ b/src/ifcblenderexport/blenderbim/bim/module/root/prop.py @@ -0,0 +1,94 @@ +import bpy +from blenderbim.bim.ifc import IfcStore +from bpy.types import PropertyGroup +from bpy.props import ( + PointerProperty, + StringProperty, + EnumProperty, + BoolProperty, + IntProperty, + FloatProperty, + FloatVectorProperty, + CollectionProperty, +) + +products_enum = [] +classes_enum = [] +types_enum = [] + + +def getIfcPredefinedTypes(self, context): + global types_enum + file = IfcStore.get_file() + if len(types_enum) < 1 and file: + declaration = IfcStore.get_schema().declaration_by_name(self.ifc_class) + for attribute in declaration.attributes(): + if attribute.name() == "PredefinedType": + types_enum.extend( + [(e, e, "") for e in attribute.type_of_attribute().declared_type().enumeration_items()] + ) + break + return types_enum + + +def refreshClasses(self, context): + global classes_enum + classes_enum.clear() + enum = getIfcClasses(self, context) + context.scene.BIMRootProperties.ifc_class = enum[0][0] + + +def refreshPredefinedTypes(self, context): + global types_enum + types_enum.clear() + enum = getIfcPredefinedTypes(self, context) + context.scene.BIMRootProperties.ifc_predefined_type = enum[0][0] + + +def getIfcProducts(self, context): + global products_enum + file = IfcStore.get_file() + if len(products_enum) < 1: + products_enum.extend( + [ + (e, e, "") + for e in [ + "IfcElement", + "IfcElementType", + "IfcSpatialElement", + "IfcGroup", + "IfcStructuralItem", + "IfcContext", + "IfcAnnotation", + ] + ] + ) + if file.schema == "IFC2X3": + products_enum[2] = ("IfcSpatialStructureElement", "IfcSpatialStructureElement", "") + return products_enum + + +def getIfcClasses(self, context): + global classes_enum + file = IfcStore.get_file() + if len(classes_enum) < 1 and file: + declaration = IfcStore.get_schema().declaration_by_name(self.ifc_product) + + def get_classes(declaration): + results = [] + if not declaration.is_abstract(): + results.append(declaration.name()) + for subtype in declaration.subtypes(): + results.extend(get_classes(subtype)) + return results + + classes = get_classes(declaration) + classes_enum.extend([(c, c, "") for c in sorted(classes)]) + return classes_enum + + +class BIMRootProperties(PropertyGroup): + ifc_product: EnumProperty(items=getIfcProducts, name="Products", update=refreshClasses) + ifc_class: EnumProperty(items=getIfcClasses, name="Class", update=refreshPredefinedTypes) + ifc_predefined_type: EnumProperty(items=getIfcPredefinedTypes, name="Predefined Type", default=None) + ifc_userdefined_type: StringProperty(name="Userdefined Type") diff --git a/src/ifcblenderexport/blenderbim/bim/module/root/ui.py b/src/ifcblenderexport/blenderbim/bim/module/root/ui.py index 1d3e6180bd..2ba234081b 100644 --- a/src/ifcblenderexport/blenderbim/bim/module/root/ui.py +++ b/src/ifcblenderexport/blenderbim/bim/module/root/ui.py @@ -41,12 +41,12 @@ class BIM_PT_class(Panel): row = self.layout.row(align=True) op = row.operator("bim.assign_class") op.obj = context.active_object.name - op.ifc_class = bpy.context.scene.BIMProperties.ifc_class - op.predefined_type = bpy.context.scene.BIMProperties.ifc_predefined_type - op.userdefined_type = bpy.context.scene.BIMProperties.ifc_userdefined_type + op.ifc_class = bpy.context.scene.BIMRootProperties.ifc_class + op.predefined_type = bpy.context.scene.BIMRootProperties.ifc_predefined_type + op.userdefined_type = bpy.context.scene.BIMRootProperties.ifc_userdefined_type def draw_class_dropdowns(self): - props = bpy.context.scene.BIMProperties + props = bpy.context.scene.BIMRootProperties row = self.layout.row() row.prop(props, "ifc_product") row = self.layout.row() diff --git a/src/ifcblenderexport/blenderbim/bim/prop.py b/src/ifcblenderexport/blenderbim/bim/prop.py index a024ef7ae5..504f5beef4 100644 --- a/src/ifcblenderexport/blenderbim/bim/prop.py +++ b/src/ifcblenderexport/blenderbim/bim/prop.py @@ -26,10 +26,7 @@ from bpy.props import ( cwd = os.path.dirname(os.path.realpath(__file__)) diagram_scales_enum = [] -products_enum = [] profiledef_enum = [] -classes_enum = [] -types_enum = [] availablematerialpsets_enum = [] ifcpatchrecipes_enum = [] titleblocks_enum = [] @@ -117,32 +114,6 @@ def setDefaultProperties(scene): bpy.ops.bim.save_drawing_style(index="2") -def getIfcPredefinedTypes(self, context): - global types_enum - file = IfcStore.get_file() - if len(types_enum) < 1 and file: - declaration = IfcStore.get_schema().declaration_by_name(self.ifc_class) - for attribute in declaration.attributes(): - if attribute.name() == "PredefinedType": - types_enum.extend([(e, e, "") for e in attribute.type_of_attribute().declared_type().enumeration_items()]) - break - return types_enum - - -def refreshClasses(self, context): - global classes_enum - classes_enum.clear() - enum = getIfcClasses(self, context) - context.scene.BIMProperties.ifc_class = enum[0][0] - - -def refreshPredefinedTypes(self, context): - global types_enum - types_enum.clear() - enum = getIfcPredefinedTypes(self, context) - context.scene.BIMProperties.ifc_predefined_type = enum[0][0] - - def getDiagramScales(self, context): global diagram_scales_enum if ( @@ -239,46 +210,6 @@ def refreshActiveDrawingIndex(self, context): bpy.ops.bim.activate_view(drawing_index=context.scene.DocProperties.active_drawing_index) -def getIfcProducts(self, context): - global products_enum - file = IfcStore.get_file() - if len(products_enum) < 1: - products_enum.extend( - [ - (e, e, "") - for e in [ - "IfcElement", - "IfcElementType", - "IfcSpatialElement", - "IfcGroup", - "IfcStructuralItem", - "IfcContext", - "IfcAnnotation", - ] - ] - ) - if file.schema == "IFC2X3": - products_enum[2] = ("IfcSpatialStructureElement", "IfcSpatialStructureElement", "") - return products_enum - - -def getIfcClasses(self, context): - global classes_enum - file = IfcStore.get_file() - if len(classes_enum) < 1 and file: - declaration = IfcStore.get_schema().declaration_by_name(self.ifc_product) - def get_classes(declaration): - results = [] - if not declaration.is_abstract(): - results.append(declaration.name()) - for subtype in declaration.subtypes(): - results.extend(get_classes(subtype)) - return results - classes = get_classes(declaration) - classes_enum.extend([(c, c, "") for c in sorted(classes)]) - return classes_enum - - def getAttributeEnumValues(self, context): return [(e, e, "") for e in json.loads(self.enum_items)] @@ -859,10 +790,6 @@ class BIMProperties(PropertyGroup): schema_dir: StringProperty(default=os.path.join(cwd, "schema") + os.path.sep, name="Schema Directory") data_dir: StringProperty(default=os.path.join(cwd, "data") + os.path.sep, name="Data Directory") ifc_file: StringProperty(name="IFC File") - ifc_product: EnumProperty(items=getIfcProducts, name="Products", update=refreshClasses) - ifc_class: EnumProperty(items=getIfcClasses, name="Class", update=refreshPredefinedTypes) - ifc_predefined_type: EnumProperty(items=getIfcPredefinedTypes, name="Predefined Type", default=None) - ifc_userdefined_type: StringProperty(name="Userdefined Type") export_schema: EnumProperty(items=[("IFC4", "IFC4", ""), ("IFC2X3", "IFC2X3", "")], name="IFC Schema") export_json_version: EnumProperty(items=[("4", "4", ""), ("5a", "5a", "")], name="IFC JSON Version") export_json_compact: BoolProperty(name="Export Compact IFCJSON", default=False) @@ -884,7 +811,6 @@ class BIMProperties(PropertyGroup): import_should_use_cpu_multiprocessing: BoolProperty(name="Import with CPU Multiprocessing", default=True) import_should_import_with_profiling: BoolProperty(name="Import with Profiling", default=True) import_should_import_aggregates: BoolProperty(name="Import Aggregates", default=True) - import_should_merge_aggregates: BoolProperty(name="Import and Merge Aggregates", default=False) import_should_merge_by_class: BoolProperty(name="Import and Merge by Class", default=False) import_should_merge_by_material: BoolProperty(name="Import and Merge by Material", default=False) import_should_merge_materials_by_colour: BoolProperty(name="Import and Merge Materials by Colour", default=False)