diff --git a/src/ifcblenderexport/blenderbim/operator.py b/src/ifcblenderexport/blenderbim/operator.py index d7dcd38736..61219b55eb 100644 --- a/src/ifcblenderexport/blenderbim/operator.py +++ b/src/ifcblenderexport/blenderbim/operator.py @@ -12,6 +12,7 @@ from . import schema from bpy_extras.io_utils import ImportHelper from itertools import cycle from mathutils import Vector +from pathlib import Path class ExportIFC(bpy.types.Operator): bl_idname = "export.ifc" @@ -204,56 +205,91 @@ class ResetObjectColours(bpy.types.Operator): object.color = (1, 1, 1, 1) return {'FINISHED'} + +class QAHelper(): + @classmethod + def append_to_scenario(cls, lines): + filename = os.path.join( + bpy.context.scene.BIMProperties.features_dir, + bpy.context.scene.BIMProperties.features_file + '.feature') + if os.path.exists(filename+'~'): + os.remove(filename+'~') + os.rename(filename, filename+'~') + with open(filename, 'w') as destination: + with open(filename+'~', 'r') as source: + is_in_scenario = False + for source_line in source: + if 'Scenario: 'in source_line \ + and bpy.context.scene.BIMProperties.scenario == source_line.strip()[len('Scenario: '):]: + is_in_scenario = True + if is_in_scenario and source_line.strip()[0:4] == 'Then': + for line in lines: + destination.write((' '*8) + line + '\n') + is_in_scenario = False + destination.write(source_line) + os.remove(filename+'~') + + class ApproveClass(bpy.types.Operator): bl_idname = 'bim.approve_class' bl_label = 'Approve Class' def execute(self, context): - with open(bpy.context.scene.BIMProperties.data_dir + 'audit.txt', 'a') as file: - for object in bpy.context.selected_objects: - index = object.BIMObjectProperties.attributes.find('GlobalId') - if index == -1: - continue - file.write('Then the element {} is an {}\n'.format( + lines = [] + for object in bpy.context.selected_objects: + index = object.BIMObjectProperties.attributes.find('GlobalId') + if index != -1: + lines.append('Then the element {} is an {}'.format( object.BIMObjectProperties.attributes[index].string_value, object.name.split('/')[0])) + QAHelper.append_to_scenario(lines) return {'FINISHED'} + class RejectClass(bpy.types.Operator): bl_idname = 'bim.reject_class' bl_label = 'Reject Class' def execute(self, context): - with open(bpy.context.scene.BIMProperties.data_dir + 'audit.txt', 'a') as file: - for object in bpy.context.selected_objects: - file.write('Then the element {} is an {}\n'.format( - object.BIMObjectProperties.attributes[ - object.BIMObjectProperties.attributes.find('GlobalId')].string_value, - bpy.context.scene.BIMProperties.audit_ifc_class)) + lines = [] + for object in bpy.context.selected_objects: + lines.append('Then the element {} is an {}'.format( + object.BIMObjectProperties.attributes[ + object.BIMObjectProperties.attributes.find('GlobalId')].string_value, + bpy.context.scene.BIMProperties.audit_ifc_class)) + QAHelper.append_to_scenario(lines) return {'FINISHED'} + class RejectElement(bpy.types.Operator): bl_idname = 'bim.reject_element' bl_label = 'Reject Element' def execute(self, context): - with open(bpy.context.scene.BIMProperties.data_dir + 'audit.txt', 'a') as file: - for object in bpy.context.selected_objects: - file.write('Then the element {} should not exist because {}\n'.format( - object.BIMObjectProperties.attributes[ - object.BIMObjectProperties.attributes.find('GlobalId')].string_value, - bpy.context.scene.BIMProperties.qa_reject_element_reason)) + lines = [] + for object in bpy.context.selected_objects: + lines.append('Then the element {} should not exist because {}'.format( + object.BIMObjectProperties.attributes[ + object.BIMObjectProperties.attributes.find('GlobalId')].string_value, + bpy.context.scene.BIMProperties.qa_reject_element_reason)) + QAHelper.append_to_scenario(lines) return {'FINISHED'} + class SelectAudited(bpy.types.Operator): bl_idname = 'bim.select_audited' bl_label = 'Select Audited' def execute(self, context): audited_global_ids = [] - with open(bpy.context.scene.BIMProperties.data_dir + 'audit.txt') as file: - for line in file: - audited_global_ids.append(line.split(' ')[3]) + for filename in Path(bpy.context.scene.BIMProperties.features_dir).glob('*.feature'): + with open(filename, 'r') as feature_file: + lines = feature_file.readlines() + for line in lines: + words = line.strip().split() + 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 \ @@ -261,6 +297,9 @@ class SelectAudited(bpy.types.Operator): object.select_set(True) return {'FINISHED'} + def is_a_global_id(self, word): + return word[0] in ['0', '1', '2', '3'] and len(word) == 22 + class QuickProjectSetup(bpy.types.Operator): bl_idname = 'bim.quick_project_setup' bl_label = 'Quick Project Setup' diff --git a/src/ifcblenderexport/blenderbim/prop.py b/src/ifcblenderexport/blenderbim/prop.py index 304f0238f2..66cd440494 100644 --- a/src/ifcblenderexport/blenderbim/prop.py +++ b/src/ifcblenderexport/blenderbim/prop.py @@ -25,6 +25,8 @@ profiledef_enum = [] classes_enum = [] types_enum = [] availablematerialpsets_enum = [] +featuresfiles_enum = [] +scenarios_enum = [] psetnames_enum = [] psetfiles_enum = [] classification_enum = [] @@ -159,6 +161,44 @@ def getAvailableMaterialPsets(self, context): return availablematerialpsets_enum +def getFeaturesFiles(self, context): + global featuresfiles_enum + if len(featuresfiles_enum) < 1: + featuresfiles_enum.clear() + for filename in Path(context.scene.BIMProperties.features_dir).glob('*.feature'): + f = str(filename.stem) + featuresfiles_enum.append((f, f, '')) + return featuresfiles_enum + + +def refreshFeaturesFiles(self, context): + global featuresfiles_enum + featuresfiles_enum.clear() + getFeaturesFiles(self, context) + + +def getScenarios(self, context): + global scenarios_enum + if len(scenarios_enum) < 1: + scenarios_enum.clear() + filename = os.path.join( + context.scene.BIMProperties.features_dir, + context.scene.BIMProperties.features_file + '.feature') + with open(filename, 'r') as feature_file: + lines = feature_file.readlines() + for line in lines: + if 'Scenario:' in line: + s = line.strip()[len('Scenario: '):] + scenarios_enum.append((s, s, '')) + return scenarios_enum + + +def refreshScenarios(self, context): + global scenarios_enum + scenarios_enum.clear() + getScenarios(self, context) + + def getPsetNames(self, context): global psetnames_enum if len(psetnames_enum) < 1: @@ -345,7 +385,9 @@ class BIMProperties(PropertyGroup): has_georeferencing: BoolProperty(name="Has Georeferencing", default=False) has_library: BoolProperty(name="Has Project Library", default=False) global_id: StringProperty(name="GlobalId") - features_dir: StringProperty(default='', name="Features Directory") + features_dir: StringProperty(default='', name="Features Directory", update=refreshFeaturesFiles) + features_file: EnumProperty(items=getFeaturesFiles, name="Features File", update=refreshScenarios) + scenario: EnumProperty(items=getScenarios, name="Scenario") diff_json_file: StringProperty(default='', name="Diff JSON File") diff_old_file: StringProperty(default='', name="Diff Old IFC File") diff_new_file: StringProperty(default='', name="Diff New IFC File") diff --git a/src/ifcblenderexport/blenderbim/ui.py b/src/ifcblenderexport/blenderbim/ui.py index 4b54c6d8e6..9b7e500e8c 100644 --- a/src/ifcblenderexport/blenderbim/ui.py +++ b/src/ifcblenderexport/blenderbim/ui.py @@ -484,6 +484,13 @@ class BIM_PT_qa(Panel): row.prop(bim_properties, "features_dir") row.operator("bim.select_features_dir", icon="FILE_FOLDER", text="") + if bim_properties.features_dir: + row = layout.row(align=True) + row.prop(bim_properties, "features_file") + + row = layout.row(align=True) + row.prop(bim_properties, "scenario") + layout.label(text="Quality Auditing:") row = layout.row()