mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-06 07:51:47 +00:00
You can now load the active IFC file into a BIMTester audit. Rapid auditing go go go!
This commit is contained in:
@@ -18,56 +18,37 @@ def before_all(context):
|
||||
if context.config.lang:
|
||||
switch_locale(userdata.get("localedir"), context.config.lang)
|
||||
|
||||
context.ifc_path = userdata["ifc"]
|
||||
context.ifc_basename = os.path.basename(
|
||||
os.path.splitext(context.ifc_path)[0]
|
||||
)
|
||||
|
||||
continue_after_failed = userdata.getbool(
|
||||
"runner.continue_after_failed_step", True
|
||||
)
|
||||
continue_after_failed = userdata.getbool("runner.continue_after_failed_step", True)
|
||||
Scenario.continue_after_failed_step = continue_after_failed
|
||||
|
||||
# keep out path
|
||||
context.outpath = os.path.join(this_path, "..")
|
||||
# TODO: refactor smart view support into a decoupled module
|
||||
# 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
|
||||
# neither log file nor sm file does need to be explicit removed first
|
||||
# context.outpath = os.path.join(this_path, "..")
|
||||
|
||||
# set up log file
|
||||
context.thelogfile = os.path.join(
|
||||
context.outpath,
|
||||
context.ifc_basename + ".log"
|
||||
)
|
||||
create_logfile(
|
||||
context.thelogfile,
|
||||
context.ifc_basename,
|
||||
)
|
||||
# context.thelogfile = os.path.join(context.outpath, context.ifc_basename + ".log")
|
||||
# create_logfile(
|
||||
# context.thelogfile,
|
||||
# context.ifc_basename,
|
||||
# )
|
||||
|
||||
# set up smart view file
|
||||
context.smview_file = os.path.join(
|
||||
context.outpath,
|
||||
context.ifc_basename + ".bcsv"
|
||||
)
|
||||
create_zoom_smartview(
|
||||
context.smview_file,
|
||||
context.ifc_basename,
|
||||
)
|
||||
# # set up smart view file
|
||||
# context.smview_file = os.path.join(context.outpath, context.ifc_basename + ".bcsv")
|
||||
# create_zoom_smartview(
|
||||
# context.smview_file,
|
||||
# context.ifc_basename,
|
||||
# )
|
||||
|
||||
|
||||
def after_step(context, step):
|
||||
|
||||
if step.status == "failed":
|
||||
|
||||
# append log file
|
||||
append_logfile(context, step)
|
||||
|
||||
# extend smart view
|
||||
if hasattr(context, "falseguids"):
|
||||
# print(context.falseguids)
|
||||
|
||||
append_zoom_smartview(
|
||||
context.smview_file,
|
||||
step.name,
|
||||
context.falseguids
|
||||
)
|
||||
pass
|
||||
# TODO: refactor smart view support into a decoupled module
|
||||
#if step.status == "failed":
|
||||
# # append log file
|
||||
# append_logfile(context, step)
|
||||
# # extend smart view
|
||||
# if hasattr(context, "falseguids"):
|
||||
# append_zoom_smartview(context.smview_file, step.name, context.falseguids)
|
||||
|
||||
@@ -4,7 +4,8 @@ from . import ui, prop, operator
|
||||
classes = (
|
||||
operator.ExecuteBIMTester,
|
||||
operator.BIMTesterPurge,
|
||||
operator.SelectFeaturesDir,
|
||||
operator.SelectFeature,
|
||||
operator.SelectBIMTesterIfcFile,
|
||||
operator.RejectElement,
|
||||
operator.ApproveClass,
|
||||
operator.RejectClass,
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import os
|
||||
import bpy
|
||||
import tempfile
|
||||
import webbrowser
|
||||
import ifcopenshell
|
||||
import bimtester
|
||||
import bimtester.run
|
||||
import bimtester.reports
|
||||
import os
|
||||
import webbrowser
|
||||
from pathlib import Path
|
||||
from itertools import cycle
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
@@ -15,33 +16,26 @@ class ExecuteBIMTester(bpy.types.Operator):
|
||||
bl_label = "Execute BIMTester"
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BimTesterProperties
|
||||
|
||||
filename = os.path.join(
|
||||
bpy.context.scene.BimTesterProperties.features_dir,
|
||||
bpy.context.scene.BimTesterProperties.features_file + ".feature",
|
||||
)
|
||||
cwd = os.getcwd()
|
||||
os.chdir(bpy.context.scene.BimTesterProperties.features_dir)
|
||||
bimtester.run.run_tests({
|
||||
"advanced_arguments": "",
|
||||
"console": False,
|
||||
"featuresdir": "",
|
||||
"feature": filename,
|
||||
"gui": False,
|
||||
"ifcfile": "",
|
||||
"purge": False,
|
||||
"path": "",
|
||||
})
|
||||
bimtester.reports.generate_report()
|
||||
webbrowser.open(
|
||||
"file://"
|
||||
+ os.path.join(
|
||||
bpy.context.scene.BimTesterProperties.features_dir,
|
||||
"report",
|
||||
bpy.context.scene.BimTesterProperties.features_file + ".feature.html",
|
||||
)
|
||||
)
|
||||
os.chdir(cwd)
|
||||
with tempfile.TemporaryDirectory() as dirpath:
|
||||
report = os.path.join(dirpath, "{}.html".format(props.feature))
|
||||
args = {
|
||||
"action": "run",
|
||||
"advanced_arguments": "",
|
||||
"console": False,
|
||||
"feature": props.feature,
|
||||
"ifc": props.ifc_file,
|
||||
"path": "",
|
||||
"report": report,
|
||||
"schema": "",
|
||||
"lang": "en"
|
||||
}
|
||||
use_stored_ifc = props.should_load_from_memory and IfcStore.get_file()
|
||||
runner = bimtester.run.TestRunner(args["ifc"], ifc=IfcStore.get_file() if use_stored_ifc else None)
|
||||
report_json = runner.run(args)
|
||||
bimtester.reports.ReportGenerator().generate(report_json, args["report"])
|
||||
webbrowser.open("file://" + report)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -50,7 +44,6 @@ class BIMTesterPurge(bpy.types.Operator):
|
||||
bl_label = "Purge Tests"
|
||||
|
||||
def execute(self, context):
|
||||
|
||||
filename = os.path.join(
|
||||
bpy.context.scene.BimTesterProperties.features_dir,
|
||||
bpy.context.scene.BimTesterProperties.features_file + ".feature",
|
||||
@@ -62,15 +55,31 @@ class BIMTesterPurge(bpy.types.Operator):
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class SelectFeaturesDir(bpy.types.Operator):
|
||||
bl_idname = "bim.select_features_dir"
|
||||
bl_label = "Select Features Directory"
|
||||
class SelectFeature(bpy.types.Operator):
|
||||
bl_idname = "bim.select_feature"
|
||||
bl_label = "Select Feature"
|
||||
filename_ext = ".feature"
|
||||
filter_glob: bpy.props.StringProperty(default="*.feature", options={"HIDDEN"})
|
||||
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
|
||||
|
||||
def execute(self, context):
|
||||
bpy.context.scene.BimTesterProperties.features_dir = (
|
||||
os.path.dirname(os.path.abspath(self.filepath)) if "." in self.filepath else self.filepath
|
||||
)
|
||||
bpy.context.scene.BimTesterProperties.feature = 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"}
|
||||
|
||||
def invoke(self, context, event):
|
||||
|
||||
@@ -2,6 +2,7 @@ import os
|
||||
from pathlib import Path
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from blenderbim.bim.prop import StrProperty
|
||||
from blenderbim.bim.module.root.prop import getIfcClasses
|
||||
from bpy.types import PropertyGroup
|
||||
from bpy.props import (
|
||||
PointerProperty,
|
||||
@@ -15,53 +16,16 @@ from bpy.props import (
|
||||
)
|
||||
|
||||
scenarios_enum = []
|
||||
featuresfiles_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):
|
||||
global scenarios_enum
|
||||
if len(scenarios_enum) < 1:
|
||||
scenarios_enum.clear()
|
||||
|
||||
if context.scene.BimTesterProperties.features_file != '': # To handle the error when no .feature file exists in the folder
|
||||
filename = os.path.join(
|
||||
context.scene.BimTesterProperties.features_dir, context.scene.BimTesterProperties.features_file + ".feature"
|
||||
)
|
||||
with open(filename, "r") as feature_file:
|
||||
if context.scene.BimTesterProperties.feature != "":
|
||||
with open(context.scene.BimTesterProperties.feature, "r") as feature_file:
|
||||
lines = feature_file.readlines()
|
||||
for line in lines:
|
||||
if "Scenario:" in line:
|
||||
@@ -77,13 +41,9 @@ def refreshScenarios(self, context):
|
||||
|
||||
|
||||
class BimTesterProperties(PropertyGroup):
|
||||
features_dir: StringProperty(default="", name="Features Directory", update=refreshFeaturesFiles)
|
||||
features_file: EnumProperty(items=getFeaturesFiles, name="Features File", update=refreshScenarios)
|
||||
feature: StringProperty(default="", name="Feature File", update=refreshScenarios)
|
||||
ifc_file: StringProperty(default="", name="IFC File")
|
||||
audit_ifc_class: EnumProperty(items=getIfcClasses, name="Audit Class")
|
||||
qa_reject_element_reason: StringProperty(name="Element Rejection Reason")
|
||||
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 blenderbim.bim.ifc import IfcStore
|
||||
|
||||
|
||||
class BIM_PT_qa(Panel):
|
||||
@@ -11,47 +11,48 @@ class BIM_PT_qa(Panel):
|
||||
bl_context = "scene"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
self.layout.use_property_split = True
|
||||
|
||||
scene = context.scene
|
||||
bimtester_properties = bpy.context.scene.BimTesterProperties
|
||||
props = 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)
|
||||
row.prop(bimtester_properties, "features_dir")
|
||||
row.operator("bim.select_features_dir", icon="FILE_FOLDER", text="")
|
||||
if not IfcStore.get_file() or not props.should_load_from_memory:
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(props, "ifc_file")
|
||||
row.operator("bim.select_bimtester_ifc_file", icon="FILE_FOLDER", text="")
|
||||
|
||||
if bimtester_properties.features_dir:
|
||||
row = layout.row(align=True)
|
||||
row.prop(bimtester_properties, "features_file")
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(props, "feature")
|
||||
row.operator("bim.select_feature", icon="FILE_FOLDER", text="")
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.prop(bimtester_properties, "scenario")
|
||||
else:
|
||||
return
|
||||
has_ifc_file = (IfcStore.get_file() and props.should_load_from_memory) or (
|
||||
props.ifc_file and not props.should_load_from_memory
|
||||
)
|
||||
|
||||
if str(context.scene.BimTesterProperties.features_file) != '': # To handle the error when no .feature file exists in the folder
|
||||
row = layout.row()
|
||||
row.operator("bim.execute_bim_tester")
|
||||
row = self.layout.row(align=True)
|
||||
row.operator("bim.execute_bim_tester")
|
||||
row.operator("bim.bim_tester_purge")
|
||||
|
||||
row = layout.row()
|
||||
row.operator("bim.bim_tester_purge")
|
||||
if props.feature and has_ifc_file:
|
||||
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.prop(bimtester_properties, "qa_reject_element_reason")
|
||||
row = layout.row()
|
||||
row = self.layout.row()
|
||||
row.prop(props, "qa_reject_element_reason")
|
||||
row = self.layout.row()
|
||||
row.operator("bim.reject_element")
|
||||
|
||||
row = layout.row()
|
||||
row.prop(bimtester_properties, "audit_ifc_class")
|
||||
row = self.layout.row()
|
||||
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.reject_class")
|
||||
|
||||
row = layout.row()
|
||||
row = self.layout.row()
|
||||
row.operator("bim.select_audited")
|
||||
|
||||
Reference in New Issue
Block a user