From 6bc4e003b4b8cb8faa97996a0b1195b63391ce73 Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Thu, 4 Apr 2024 16:27:10 +0500 Subject: [PATCH] bim.debug_active_drawing debug operator #4500 Operator can help narrow down failing elements when drawing is failing with "RuntimeError: An unknown error occurred". it's located in debug section - https://i.imgur.com/b03jmkZ.png The output is noisy but the results are highlighted: https://i.imgur.com/0ZA0u60.png https://i.imgur.com/oXzqIXU.png https://i.imgur.com/Y0nMRMz.png --- .../blenderbim/bim/module/debug/__init__.py | 1 + .../blenderbim/bim/module/debug/operator.py | 94 +++++++++++++++++++ .../blenderbim/bim/module/debug/ui.py | 3 + 3 files changed, 98 insertions(+) diff --git a/src/blenderbim/blenderbim/bim/module/debug/__init__.py b/src/blenderbim/blenderbim/bim/module/debug/__init__.py index 93f3713205..271950ea61 100644 --- a/src/blenderbim/blenderbim/bim/module/debug/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/debug/__init__.py @@ -24,6 +24,7 @@ classes = ( operator.CopyDebugInformation, operator.CreateAllShapes, operator.CreateShapeFromStepId, + operator.DebugActiveDrawing, operator.InspectFromObject, operator.InspectFromStepId, operator.OverrideDisplayType, diff --git a/src/blenderbim/blenderbim/bim/module/debug/operator.py b/src/blenderbim/blenderbim/bim/module/debug/operator.py index 1a1f80f123..08b3527cc8 100644 --- a/src/blenderbim/blenderbim/bim/module/debug/operator.py +++ b/src/blenderbim/blenderbim/bim/module/debug/operator.py @@ -20,11 +20,14 @@ import os import sys import bpy import time +import random import logging import platform import subprocess import addon_utils import ifcopenshell +import ifcopenshell.api +import ifcopenshell.util.element import ifcopenshell.util.placement import ifcopenshell.util.representation import blenderbim.tool as tool @@ -660,3 +663,94 @@ class PipInstall(bpy.types.Operator): ] ) return {"FINISHED"} + + +class DebugActiveDrawing(bpy.types.Operator): + bl_idname = "bim.debug_active_drawing" + bl_label = "Search Active Drawing For Failing Elements" + bl_description = ( + "Will iterate over all visible drawing's objects, trying to narrow down the list of possible failing objects" + ) + + def execute(self, context: bpy.types.Context): + props = context.scene.DocProperties + drawing_item = props.drawings[props.active_drawing_index] + drawing = tool.Ifc.get().by_id(drawing_item.ifc_definition_id) + + GREEN = "\033[92m" + CYAN = "\033[96m" + END = "\033[0m" + ATTEMPS = 10 + + # run create drawing with sync for once + # to make sure everything is actually in sync + try: + bpy.ops.bim.create_drawing(sync=True) + except: + pass + else: + self.report({"INFO"}, "No errors creating drawing, nothing to investigate.") + return + + all_elements = [e for obj in context.visible_objects if (e := tool.Ifc.get_entity(obj))] + all_elements = set(all_elements) + + original_exclude = ifcopenshell.util.element.get_pset(drawing, "EPset_Drawing", "Exclude") + pset = tool.Pset.get_element_pset(drawing, "EPset_Drawing") + + def drawing_fails_to_load(chunk_to_include: set) -> bool: + current_elements = all_elements - chunk_to_include + excluded_guids = ", ".join([e.GlobalId for e in current_elements if hasattr(e, "GlobalId")]) + tool.Ifc.run("pset.edit_pset", pset=pset, properties={"Exclude": f"{original_exclude}, {excluded_guids}"}) + + try: + bpy.ops.bim.create_drawing(sync=False) + result = False + except Exception as e: + # print(e) + result = True + + tool.Ifc.run("pset.edit_pset", pset=pset, properties={"Exclude": original_exclude}) + return result + + def test_elements(elements: list[ifcopenshell.entity_instance], attempts: int = ATTEMPS) -> None: + print(f"{CYAN}processing {len(elements)} elements{END}") + n_elements = len(elements) + middle = int(n_elements / 2) + chunk1, chunk2 = elements[:middle], elements[middle:] + test_chunk_1 = drawing_fails_to_load(set(chunk1)) + test_chunk_2 = drawing_fails_to_load(set(chunk2)) + + if not test_chunk_1 and not test_chunk_2: + if attempts == 0 or n_elements == 2: + print(f"{GREEN}Couldn't narrow it down any further.{END}") + print(f"It's some of the {n_elements} elements:") + print(elements) + + print("Let's test excluding them...") + for element in elements: + test = drawing_fails_to_load(all_elements - {element}) + if test: + print(f"{GREEN}Excluding element fixed the drawing: {END}") + print(element) + else: + print(f"{CYAN}Excluding element didn't fixed the drawing: {END}") + print(element) + else: + print(f"{CYAN}Will try to reshuffle elements and try again, attempt {ATTEMPS-attempts+1}/{ATTEMPS}") + attempts -= 1 + random.shuffle(elements) + test_elements(elements, attempts) + + return + + if test_chunk_1: + test_elements(chunk1) + + if test_chunk_2: + test_elements(chunk2) + + test_elements(list(all_elements)) + + self.report({"INFO"}, "See system console for the results") + return {"FINISHED"} diff --git a/src/blenderbim/blenderbim/bim/module/debug/ui.py b/src/blenderbim/blenderbim/bim/module/debug/ui.py index 21a6e11f80..2fd503cf6f 100644 --- a/src/blenderbim/blenderbim/bim/module/debug/ui.py +++ b/src/blenderbim/blenderbim/bim/module/debug/ui.py @@ -75,6 +75,9 @@ class BIM_PT_debug(Panel): row = layout.row() row.operator("bim.profile_import_ifc") + row = layout.row() + row.operator("bim.debug_active_drawing") + row = layout.split(factor=0.5, align=True) row.operator("bim.create_shape_from_step_id").should_include_curves = False row.operator("bim.create_shape_from_step_id", text="", icon="IPO_ELASTIC").should_include_curves = True