You can now load the active IFC file into a BIMTester audit. Rapid auditing go go go!

This commit is contained in:
Dion Moult
2021-02-02 20:45:56 +11:00
parent c3f7410f76
commit 5a722a792a
5 changed files with 108 additions and 156 deletions
@@ -18,56 +18,37 @@ def before_all(context):
if context.config.lang: if context.config.lang:
switch_locale(userdata.get("localedir"), context.config.lang) switch_locale(userdata.get("localedir"), context.config.lang)
context.ifc_path = userdata["ifc"] continue_after_failed = userdata.getbool("runner.continue_after_failed_step", True)
context.ifc_basename = os.path.basename(
os.path.splitext(context.ifc_path)[0]
)
continue_after_failed = userdata.getbool(
"runner.continue_after_failed_step", True
)
Scenario.continue_after_failed_step = continue_after_failed Scenario.continue_after_failed_step = continue_after_failed
# keep out path # TODO: refactor smart view support into a decoupled module
context.outpath = os.path.join(this_path, "..") # context.ifc_path = userdata.get("ifc", "")
# context.ifc_basename = os.path.basename(
# os.path.splitext(context.ifc_path)[0]
# )
# since bimtesterfc directory in tmp is removed on every run # context.outpath = os.path.join(this_path, "..")
# neither log file nor sm file does need to be explicit removed first
# set up log file # context.thelogfile = os.path.join(context.outpath, context.ifc_basename + ".log")
context.thelogfile = os.path.join( # create_logfile(
context.outpath, # context.thelogfile,
context.ifc_basename + ".log" # context.ifc_basename,
) # )
create_logfile(
context.thelogfile,
context.ifc_basename,
)
# set up smart view file # # set up smart view file
context.smview_file = os.path.join( # context.smview_file = os.path.join(context.outpath, context.ifc_basename + ".bcsv")
context.outpath, # create_zoom_smartview(
context.ifc_basename + ".bcsv" # context.smview_file,
) # context.ifc_basename,
create_zoom_smartview( # )
context.smview_file,
context.ifc_basename,
)
def after_step(context, step): def after_step(context, step):
pass
if step.status == "failed": # TODO: refactor smart view support into a decoupled module
#if step.status == "failed":
# append log file # # append log file
append_logfile(context, step) # append_logfile(context, step)
# # extend smart view
# extend smart view # if hasattr(context, "falseguids"):
if hasattr(context, "falseguids"): # append_zoom_smartview(context.smview_file, step.name, context.falseguids)
# print(context.falseguids)
append_zoom_smartview(
context.smview_file,
step.name,
context.falseguids
)
@@ -4,7 +4,8 @@ from . import ui, prop, operator
classes = ( classes = (
operator.ExecuteBIMTester, operator.ExecuteBIMTester,
operator.BIMTesterPurge, operator.BIMTesterPurge,
operator.SelectFeaturesDir, operator.SelectFeature,
operator.SelectBIMTesterIfcFile,
operator.RejectElement, operator.RejectElement,
operator.ApproveClass, operator.ApproveClass,
operator.RejectClass, operator.RejectClass,
@@ -1,10 +1,11 @@
import os
import bpy import bpy
import tempfile
import webbrowser
import ifcopenshell import ifcopenshell
import bimtester import bimtester
import bimtester.run import bimtester.run
import bimtester.reports import bimtester.reports
import os
import webbrowser
from pathlib import Path from pathlib import Path
from itertools import cycle from itertools import cycle
from blenderbim.bim.ifc import IfcStore from blenderbim.bim.ifc import IfcStore
@@ -15,33 +16,26 @@ class ExecuteBIMTester(bpy.types.Operator):
bl_label = "Execute BIMTester" bl_label = "Execute BIMTester"
def execute(self, context): def execute(self, context):
props = context.scene.BimTesterProperties
filename = os.path.join( with tempfile.TemporaryDirectory() as dirpath:
bpy.context.scene.BimTesterProperties.features_dir, report = os.path.join(dirpath, "{}.html".format(props.feature))
bpy.context.scene.BimTesterProperties.features_file + ".feature", args = {
) "action": "run",
cwd = os.getcwd() "advanced_arguments": "",
os.chdir(bpy.context.scene.BimTesterProperties.features_dir) "console": False,
bimtester.run.run_tests({ "feature": props.feature,
"advanced_arguments": "", "ifc": props.ifc_file,
"console": False, "path": "",
"featuresdir": "", "report": report,
"feature": filename, "schema": "",
"gui": False, "lang": "en"
"ifcfile": "", }
"purge": False, use_stored_ifc = props.should_load_from_memory and IfcStore.get_file()
"path": "", runner = bimtester.run.TestRunner(args["ifc"], ifc=IfcStore.get_file() if use_stored_ifc else None)
}) report_json = runner.run(args)
bimtester.reports.generate_report() bimtester.reports.ReportGenerator().generate(report_json, args["report"])
webbrowser.open( webbrowser.open("file://" + report)
"file://"
+ os.path.join(
bpy.context.scene.BimTesterProperties.features_dir,
"report",
bpy.context.scene.BimTesterProperties.features_file + ".feature.html",
)
)
os.chdir(cwd)
return {"FINISHED"} return {"FINISHED"}
@@ -50,7 +44,6 @@ class BIMTesterPurge(bpy.types.Operator):
bl_label = "Purge Tests" bl_label = "Purge Tests"
def execute(self, context): def execute(self, context):
filename = os.path.join( filename = os.path.join(
bpy.context.scene.BimTesterProperties.features_dir, bpy.context.scene.BimTesterProperties.features_dir,
bpy.context.scene.BimTesterProperties.features_file + ".feature", bpy.context.scene.BimTesterProperties.features_file + ".feature",
@@ -62,15 +55,31 @@ class BIMTesterPurge(bpy.types.Operator):
return {"FINISHED"} return {"FINISHED"}
class SelectFeaturesDir(bpy.types.Operator): class SelectFeature(bpy.types.Operator):
bl_idname = "bim.select_features_dir" bl_idname = "bim.select_feature"
bl_label = "Select Features Directory" bl_label = "Select Feature"
filename_ext = ".feature"
filter_glob: bpy.props.StringProperty(default="*.feature", options={"HIDDEN"})
filepath: bpy.props.StringProperty(subtype="FILE_PATH") filepath: bpy.props.StringProperty(subtype="FILE_PATH")
def execute(self, context): def execute(self, context):
bpy.context.scene.BimTesterProperties.features_dir = ( bpy.context.scene.BimTesterProperties.feature = self.filepath
os.path.dirname(os.path.abspath(self.filepath)) if "." in self.filepath else self.filepath return {"FINISHED"}
)
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class SelectBIMTesterIfcFile(bpy.types.Operator):
bl_idname = "bim.select_bimtester_ifc_file"
bl_label = "Select BIMTester IFC File"
filename_ext = ".ifc"
filter_glob: bpy.props.StringProperty(default="*.ifc;*.ifczip;*.ifcxml", options={"HIDDEN"})
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
def execute(self, context):
context.scene.BimTesterProperties.ifc_file = self.filepath
return {"FINISHED"} return {"FINISHED"}
def invoke(self, context, event): def invoke(self, context, event):
@@ -2,6 +2,7 @@ import os
from pathlib import Path from pathlib import Path
from blenderbim.bim.ifc import IfcStore from blenderbim.bim.ifc import IfcStore
from blenderbim.bim.prop import StrProperty from blenderbim.bim.prop import StrProperty
from blenderbim.bim.module.root.prop import getIfcClasses
from bpy.types import PropertyGroup from bpy.types import PropertyGroup
from bpy.props import ( from bpy.props import (
PointerProperty, PointerProperty,
@@ -15,53 +16,16 @@ from bpy.props import (
) )
scenarios_enum = [] scenarios_enum = []
featuresfiles_enum = []
classes_enum = [] classes_enum = []
def getIfcClasses(self, context): # This is a copy of the one in bim.prop (as it is used in other modules, can be refactored later)
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 getFeaturesFiles(self, context):
global featuresfiles_enum
if len(featuresfiles_enum) < 1:
featuresfiles_enum.clear()
for filename in Path(context.scene.BimTesterProperties.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): def getScenarios(self, context):
global scenarios_enum global scenarios_enum
if len(scenarios_enum) < 1: if len(scenarios_enum) < 1:
scenarios_enum.clear() scenarios_enum.clear()
if context.scene.BimTesterProperties.features_file != '': # To handle the error when no .feature file exists in the folder if context.scene.BimTesterProperties.feature != "":
filename = os.path.join( with open(context.scene.BimTesterProperties.feature, "r") as feature_file:
context.scene.BimTesterProperties.features_dir, context.scene.BimTesterProperties.features_file + ".feature"
)
with open(filename, "r") as feature_file:
lines = feature_file.readlines() lines = feature_file.readlines()
for line in lines: for line in lines:
if "Scenario:" in line: if "Scenario:" in line:
@@ -77,13 +41,9 @@ def refreshScenarios(self, context):
class BimTesterProperties(PropertyGroup): class BimTesterProperties(PropertyGroup):
features_dir: StringProperty(default="", name="Features Directory", update=refreshFeaturesFiles) feature: StringProperty(default="", name="Feature File", update=refreshScenarios)
features_file: EnumProperty(items=getFeaturesFiles, name="Features File", update=refreshScenarios) ifc_file: StringProperty(default="", name="IFC File")
audit_ifc_class: EnumProperty(items=getIfcClasses, name="Audit Class") audit_ifc_class: EnumProperty(items=getIfcClasses, name="Audit Class")
qa_reject_element_reason: StringProperty(name="Element Rejection Reason") qa_reject_element_reason: StringProperty(name="Element Rejection Reason")
scenario: EnumProperty(items=getScenarios, name="Scenario") scenario: EnumProperty(items=getScenarios, name="Scenario")
# should_load_from_memory: BoolProperty(default=False, name="Load from Memory") # can be added later to mimic the functionality in the CSV Module should_load_from_memory: BoolProperty(default=False, name="Load from Memory")
@@ -1,5 +1,5 @@
import bpy
from bpy.types import Panel from bpy.types import Panel
from blenderbim.bim.ifc import IfcStore
class BIM_PT_qa(Panel): class BIM_PT_qa(Panel):
@@ -11,47 +11,48 @@ class BIM_PT_qa(Panel):
bl_context = "scene" bl_context = "scene"
def draw(self, context): def draw(self, context):
layout = self.layout self.layout.use_property_split = True
layout.use_property_split = True
scene = context.scene props = context.scene.BimTesterProperties
bimtester_properties = bpy.context.scene.BimTesterProperties
layout.label(text="Gherkin Setup:") if IfcStore.get_file():
row = self.layout.row()
row.prop(props, "should_load_from_memory")
row = layout.row(align=True) if not IfcStore.get_file() or not props.should_load_from_memory:
row.prop(bimtester_properties, "features_dir") row = self.layout.row(align=True)
row.operator("bim.select_features_dir", icon="FILE_FOLDER", text="") row.prop(props, "ifc_file")
row.operator("bim.select_bimtester_ifc_file", icon="FILE_FOLDER", text="")
if bimtester_properties.features_dir: row = self.layout.row(align=True)
row = layout.row(align=True) row.prop(props, "feature")
row.prop(bimtester_properties, "features_file") row.operator("bim.select_feature", icon="FILE_FOLDER", text="")
row = layout.row(align=True) has_ifc_file = (IfcStore.get_file() and props.should_load_from_memory) or (
row.prop(bimtester_properties, "scenario") props.ifc_file and not props.should_load_from_memory
else: )
return
if str(context.scene.BimTesterProperties.features_file) != '': # To handle the error when no .feature file exists in the folder row = self.layout.row(align=True)
row = layout.row() row.operator("bim.execute_bim_tester")
row.operator("bim.execute_bim_tester") row.operator("bim.bim_tester_purge")
row = layout.row() if props.feature and has_ifc_file:
row.operator("bim.bim_tester_purge") self.layout.label(text="Scenario Authoring:")
layout.label(text="Quality Auditing:") row = self.layout.row(align=True)
row.prop(props, "scenario")
row = layout.row() row = self.layout.row()
row.prop(bimtester_properties, "qa_reject_element_reason") row.prop(props, "qa_reject_element_reason")
row = layout.row() row = self.layout.row()
row.operator("bim.reject_element") row.operator("bim.reject_element")
row = layout.row() row = self.layout.row()
row.prop(bimtester_properties, "audit_ifc_class") row.prop(props, "audit_ifc_class")
row = layout.row(align=True) row = self.layout.row(align=True)
row.operator("bim.approve_class") row.operator("bim.approve_class")
row.operator("bim.reject_class") row.operator("bim.reject_class")
row = layout.row() row = self.layout.row()
row.operator("bim.select_audited") row.operator("bim.select_audited")