From 281f4045ffd69efa7007dace7d41b3283b5179e2 Mon Sep 17 00:00:00 2001 From: Petru Conduraru Date: Thu, 16 Jul 2026 12:33:28 +0300 Subject: [PATCH] Bonsai: fix Activate Drawing crash for punctuated drawing names The sheets panel matched a sheet's DRAWING reference to its IfcAnnotation by stripping ".svg" from the reference's filename and comparing it against each annotation's Name after removing commas only. The on-disk filename is generated by sanitise_filename(), which strips every character outside [A-Za-z0-9._- ], not just commas, so any drawing Name containing other punctuation (parentheses, colons, quotes) never matches. The lookup then silently leaves op.drawing at 0, and clicking the button crashes at by_id(0) since IFC entity ids never include 0. Replace the name-based lookup with an exact Location match against get_drawing_document(), mirroring the same Location comparison AddDrawingToSheet already uses to detect an existing sheet reference, so no filesystem-sanitised name has to be reversed. Fixes #7167. Generated with the assistance of an AI coding tool. --- src/bonsai/bonsai/bim/module/drawing/ui.py | 18 ++++----------- src/bonsai/bonsai/core/tool.py | 1 + src/bonsai/bonsai/tool/drawing.py | 26 ++++++++++++++++++++++ 3 files changed, 31 insertions(+), 14 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/drawing/ui.py b/src/bonsai/bonsai/bim/module/drawing/ui.py index e0df93a4a6..bbc8650e4d 100644 --- a/src/bonsai/bonsai/bim/module/drawing/ui.py +++ b/src/bonsai/bonsai/bim/module/drawing/ui.py @@ -483,20 +483,10 @@ class BIM_PT_sheets(Panel): op = row3.operator("bim.activate_drawing_from_sheet", icon="OUTLINER_OB_CAMERA", text="") if active_sheet.reference_type == "DRAWING": - drawingnamesvg = active_sheet.name - drawingname = drawingnamesvg.split(".svg")[0] - ifc_file = tool.Ifc.get() - ifc_annotations = ifc_file.by_type("IfcAnnotation") - drawingid = None - for annotation in ifc_annotations: - if annotation.ObjectType != "DRAWING": - continue - Annotation_Name = annotation.Name.replace(",", "") # Remove commas - if Annotation_Name == drawingname: - drawingid = annotation.id() - break - if drawingid is not None: - op.drawing = drawingid + active_reference = tool.Ifc.get().by_id(active_sheet.ifc_definition_id) + drawing = tool.Drawing.get_drawing_for_sheet_reference(active_reference) + if drawing is not None: + op.drawing = drawing.id() row3.separator(factor=0.5, type="SPACE") diff --git a/src/bonsai/bonsai/core/tool.py b/src/bonsai/bonsai/core/tool.py index 90ddc006f0..c2c92d94b3 100644 --- a/src/bonsai/bonsai/core/tool.py +++ b/src/bonsai/bonsai/core/tool.py @@ -381,6 +381,7 @@ class Drawing: def get_document_uri(cls, document, description=None): pass def get_drawing_collection(cls, drawing): pass def get_drawing_document(cls, drawing): pass + def get_drawing_for_sheet_reference(cls, reference): pass def get_drawing_group(cls, drawing): pass def get_drawing_references(cls, drawing): pass def get_drawing_target_view(cls, drawing): pass diff --git a/src/bonsai/bonsai/tool/drawing.py b/src/bonsai/bonsai/tool/drawing.py index 7493b02d33..7d44f059ad 100644 --- a/src/bonsai/bonsai/tool/drawing.py +++ b/src/bonsai/bonsai/tool/drawing.py @@ -762,6 +762,32 @@ class Drawing(bonsai.core.tool.Drawing): if rel.is_a("IfcRelAssociatesDocument"): return rel.RelatingDocument + @classmethod + def get_drawing_for_sheet_reference( + cls, reference: ifcopenshell.entity_instance + ) -> Union[ifcopenshell.entity_instance, None]: + """Find the IfcAnnotation drawing that a sheet's "DRAWING" reference item represents. + + A sheet's document reference is a standalone copy created by + `bim.add_drawing_to_sheet` (see `AddDrawingToSheet`): it only shares + the drawing's `Location` (the on-disk SVG path) and has no direct IFC + relationship back to the originating `IfcAnnotation`. Match on that + `Location` instead of re-deriving the drawing's name from the + (filesystem-sanitised) filename, which silently fails to match + whenever the drawing's `Name` contains characters stripped by + `sanitise_filename()` (e.g. parentheses, colons, quotes). + """ + location = getattr(reference, "Location", None) + if not location: + return None + for drawing in tool.Ifc.get().by_type("IfcAnnotation"): + if drawing.ObjectType != "DRAWING": + continue + drawing_reference = cls.get_drawing_document(drawing) + if drawing_reference and drawing_reference.Location == location: + return drawing + return None + @classmethod def get_drawing_references(cls, drawing: ifcopenshell.entity_instance) -> set[ifcopenshell.entity_instance]: results: set[ifcopenshell.entity_instance] = set()