Update BBIM tester module UI to be compatible with new IfcTester upgrades

This commit is contained in:
Dion Moult
2023-09-01 16:47:55 +10:00
parent 283961fc72
commit 2ea3704d96
5 changed files with 89 additions and 52 deletions
@@ -0,0 +1,45 @@
# BlenderBIM Add-on - OpenBIM Blender Add-on
# Copyright (C) 2023 Dion Moult <dion@thinkmoult.com>
#
# This file is part of BlenderBIM Add-on.
#
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# BlenderBIM Add-on is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
import bpy
import blenderbim.tool as tool
def refresh():
TesterData.is_loaded = False
class TesterData:
data = {}
is_loaded = False
@classmethod
def load(cls):
cls.data = {"has_report": cls.has_report(), "specification": cls.specification()}
cls.is_loaded = True
@classmethod
def has_report(cls):
return tool.Tester.report
@classmethod
def specification(cls):
if not tool.Tester.report:
return {}
props = bpy.context.scene.IfcTesterProperties
return tool.Tester.report[props.active_specification_index]
@@ -21,15 +21,16 @@ import bpy
import time import time
import tempfile import tempfile
import webbrowser import webbrowser
import json
import ifctester import ifctester
import ifctester.ids import ifctester.ids
import ifctester.reporter import ifctester.reporter
import ifcopenshell import ifcopenshell
import blenderbim.tool as tool import blenderbim.tool as tool
import blenderbim.bim.handler
from blenderbim.bim.module.tester.data import TesterData
class ExecuteIfcTester(bpy.types.Operator): class ExecuteIfcTester(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.execute_ifc_tester" bl_idname = "bim.execute_ifc_tester"
bl_label = "Execute IfcTester" bl_label = "Execute IfcTester"
@@ -54,28 +55,27 @@ class ExecuteIfcTester(bpy.types.Operator):
print("Finished loading:", time.time() - start) print("Finished loading:", time.time() - start)
start = time.time() start = time.time()
specs.validate(ifc) specs.validate(ifc)
print("Finished validating:", time.time() - start) print("Finished validating:", time.time() - start)
start = time.time() start = time.time()
if props.generate_html_report: if props.generate_html_report:
engine = ifctester.reporter.Html(specs) engine = ifctester.reporter.Html(specs)
engine.report() engine.report()
engine.to_file(output) engine.to_file(output)
webbrowser.open("file://" + output) webbrowser.open("file://" + output)
report = None report = None
report = ifctester.reporter.Json(specs).report()['specifications'] report = ifctester.reporter.Json(specs).report()["specifications"]
if report: if report:
props.has_report = True tool.Tester.report = report
props.report = json.dumps(report)
props.specifications.clear() props.specifications.clear()
c=0
for spec in report: for spec in report:
new_spec = props.specifications.add() new_spec = props.specifications.add()
new_spec.name = spec['name'] new_spec.name = spec["name"]
new_spec.status = spec['status'] new_spec.status = spec["status"]
blenderbim.bim.handler.refresh_ui_data()
return {"FINISHED"} return {"FINISHED"}
@@ -118,23 +118,24 @@ class SelectRequirement(bpy.types.Operator):
bl_label = "Select Specification" bl_label = "Select Specification"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
spec_index: bpy.props.IntProperty() spec_index: bpy.props.IntProperty()
req_index: bpy.props.IntProperty() req_index: bpy.props.IntProperty()
def execute(self, context): def execute(self, context):
props = context.scene.IfcTesterProperties props = context.scene.IfcTesterProperties
report = json.loads(props.report) report = tool.Tester.report
props.old_index = self.spec_index props.old_index = self.spec_index
failed_entities = report[self.spec_index]['requirements'] [self.req_index]['failed_entities'] failed_entities = report[self.spec_index]["requirements"][self.req_index]["failed_entities"]
props.n_entities = len(failed_entities) props.n_entities = len(failed_entities)
props.has_entities = True if props.n_entities > 0 else False props.has_entities = True if props.n_entities > 0 else False
props.failed_entities.clear() props.failed_entities.clear()
for e in failed_entities: for e in failed_entities:
new_entity = props.failed_entities.add() new_entity = props.failed_entities.add()
new_entity.element = e['element'] new_entity.element = e["element"]
new_entity.reason = e['reason'] new_entity.reason = e["reason"]
return {"FINISHED"} return {"FINISHED"}
class SelectEntity(bpy.types.Operator): class SelectEntity(bpy.types.Operator):
bl_idname = "bim.select_entity" bl_idname = "bim.select_entity"
bl_label = "Select Entity" bl_label = "Select Entity"
@@ -142,13 +143,14 @@ class SelectEntity(bpy.types.Operator):
ifc_id: bpy.props.IntProperty() ifc_id: bpy.props.IntProperty()
def execute(self, context): def execute(self, context):
bpy.ops.object.select_all(action='DESELECT') bpy.ops.object.select_all(action="DESELECT")
for obj in context.scene.objects: for obj in context.scene.objects:
if obj.BIMObjectProperties.ifc_definition_id == self.ifc_id: if obj.BIMObjectProperties.ifc_definition_id == self.ifc_id:
obj.select_set(True) obj.select_set(True)
bpy.context.view_layer.objects.active = obj bpy.context.view_layer.objects.active = obj
return {"FINISHED"} return {"FINISHED"}
class ExportBcf(bpy.types.Operator): class ExportBcf(bpy.types.Operator):
bl_idname = "bim.export_bcf" bl_idname = "bim.export_bcf"
bl_label = "Export BCF" bl_label = "Export BCF"
@@ -168,7 +170,6 @@ class ExportBcf(bpy.types.Operator):
bcf_reporter.report() bcf_reporter.report()
bcf_reporter.to_file(output) bcf_reporter.to_file(output)
print("Finished exporting!") print("Finished exporting!")
self.report({"INFO"}, 'Finished exporting!') self.report({"INFO"}, "Finished exporting!")
return {"FINISHED"} return {"FINISHED"}
@@ -16,6 +16,7 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>. # along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
from blenderbim.bim.module.tester.data import TesterData
from blenderbim.bim.prop import StrProperty from blenderbim.bim.prop import StrProperty
from bpy.types import PropertyGroup from bpy.types import PropertyGroup
from bpy.props import ( from bpy.props import (
@@ -34,8 +35,8 @@ def purge():
pass pass
def get_failure_entities(): def update_active_specification_index(self, context):
return TesterData.load()
class Specification(PropertyGroup): class Specification(PropertyGroup):
@@ -53,13 +54,10 @@ class IfcTesterProperties(PropertyGroup):
ifc_file: StringProperty(default="", name="IFC File") ifc_file: StringProperty(default="", name="IFC File")
should_load_from_memory: BoolProperty(default=False, name="Load from Memory") should_load_from_memory: BoolProperty(default=False, name="Load from Memory")
generate_html_report: BoolProperty(default=False, name="Generate HTML report") generate_html_report: BoolProperty(default=False, name="Generate HTML report")
active_specification_index: IntProperty(name="Active Specification Index") active_specification_index: IntProperty(name="Active Specification Index", update=update_active_specification_index)
active_requirement_index: IntProperty(name="Active Requirement Index")
old_index: IntProperty(name="", default=0) old_index: IntProperty(name="", default=0)
active_failed_entity_index: IntProperty(name="Active Failed Entity Index") active_failed_entity_index: IntProperty(name="Active Failed Entity Index")
report: StringProperty(default="", name="JSON report")
specifications: CollectionProperty(name="Specifications", type=Specification) specifications: CollectionProperty(name="Specifications", type=Specification)
failed_entities: CollectionProperty(name="FailedEntities", type=FailedEntities) failed_entities: CollectionProperty(name="FailedEntities", type=FailedEntities)
has_report: BoolProperty(default=False, name="")
has_entities: BoolProperty(default=False, name="") has_entities: BoolProperty(default=False, name="")
n_entities: IntProperty(name="", default=0) n_entities: IntProperty(name="", default=0)
@@ -18,7 +18,7 @@
import blenderbim.tool as tool import blenderbim.tool as tool
from bpy.types import Panel, UIList from bpy.types import Panel, UIList
import json from blenderbim.bim.module.tester.data import TesterData
class BIM_PT_tester(Panel): class BIM_PT_tester(Panel):
@@ -31,6 +31,9 @@ class BIM_PT_tester(Panel):
bl_parent_id = "BIM_PT_tab_quality_control" bl_parent_id = "BIM_PT_tab_quality_control"
def draw(self, context): def draw(self, context):
if not TesterData.is_loaded:
TesterData.load()
self.layout.use_property_split = True self.layout.use_property_split = True
props = context.scene.IfcTesterProperties props = context.scene.IfcTesterProperties
@@ -53,7 +56,7 @@ class BIM_PT_tester(Panel):
row = self.layout.row() row = self.layout.row()
row.operator("bim.execute_ifc_tester") row.operator("bim.execute_ifc_tester")
if props.has_report: if TesterData.data["has_report"]:
self.layout.template_list( self.layout.template_list(
"BIM_UL_tester_specifications", "BIM_UL_tester_specifications",
"", "",
@@ -69,33 +72,26 @@ class BIM_PT_tester(Panel):
def draw_editable_ui(self, context): def draw_editable_ui(self, context):
props = context.scene.IfcTesterProperties props = context.scene.IfcTesterProperties
i = props.active_specification_index specification = TesterData.data["specification"]
dic_report = json.loads(props.report)
total_successes = dic_report[i]["total_successes"] n_requirements = len(specification["requirements"])
total = dic_report[i]["total"]
percentage = dic_report[i]["percentage"]
n_requirements = len(dic_report[i]["requirements"])
row = self.layout.row() row = self.layout.row()
row.label(text=f"Passed: {total_successes}/{total} ({percentage}%)") row.label(
text=f'Passed: {specification["total_checks_pass"]}/{specification["total_checks"]} ({specification["percent_checks_pass"]}%)'
)
row = self.layout.row() row = self.layout.row()
row.label(text=f"Requirements ({n_requirements}):") row.label(text=f"Requirements ({n_requirements}):")
c = 0
box = self.layout.box() box = self.layout.box()
for req in dic_report[i]["requirements"]: for i, requirement in enumerate(specification["requirements"]):
row = box.row(align=True) row = box.row(align=True)
row.label(text=f" {c+1}. {req['description']}") row.label(text=requirement["description"], icon="CHECKMARK" if requirement["status"] else "CANCEL")
if req["status"]: if not requirement["status"]:
row.label(text="PASS", icon="CHECKMARK")
else:
row.label(text="FAIL", icon="CANCEL")
op = row.operator("bim.select_requirement", text="", icon="LONGDISPLAY") op = row.operator("bim.select_requirement", text="", icon="LONGDISPLAY")
op.spec_index = i op.spec_index = props.active_specification_index
op.req_index = c op.req_index = i
c += 1
if props.old_index == i and props.n_entities > 0: if props.old_index == props.active_specification_index and props.n_entities > 0:
row = self.layout.row() row = self.layout.row()
row.label(text=f"Failed entities [{props.n_entities}]:") row.label(text=f"Failed entities [{props.n_entities}]:")
self.layout.template_list( self.layout.template_list(
@@ -112,11 +108,7 @@ class BIM_UL_tester_specifications(UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname): def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
if item: if item:
row = layout.row(align=True) row = layout.row(align=True)
row.label(text=item.name, icon="WORDWRAP_ON") row.label(text=item.name, icon="CHECKMARK" if item.status else "CANCEL")
if item.status:
row.label(text="PASS")
else:
row.label(text="FAIL")
class BIM_UL_tester_failed_entities(UIList): class BIM_UL_tester_failed_entities(UIList):
@@ -51,6 +51,7 @@ from blenderbim.tool.structural import Structural
from blenderbim.tool.style import Style from blenderbim.tool.style import Style
from blenderbim.tool.surveyor import Surveyor from blenderbim.tool.surveyor import Surveyor
from blenderbim.tool.system import System from blenderbim.tool.system import System
from blenderbim.tool.tester import Tester
from blenderbim.tool.type import Type from blenderbim.tool.type import Type
from blenderbim.tool.unit import Unit from blenderbim.tool.unit import Unit
from blenderbim.tool.search import Search from blenderbim.tool.search import Search