mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-28 19:27:10 +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:
|
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")
|
||||||
|
|||||||
Reference in New Issue
Block a user