diff --git a/src/bonsai/bonsai/bim/module/drawing/sheeter.py b/src/bonsai/bonsai/bim/module/drawing/sheeter.py index df57b6efb5..84344b6c66 100644 --- a/src/bonsai/bonsai/bim/module/drawing/sheeter.py +++ b/src/bonsai/bonsai/bim/module/drawing/sheeter.py @@ -132,9 +132,22 @@ class SheetBuilder: self.add_view_title(x, view_height + y + VIEW_TITLE_OFFSET_Y, view, layout_dir) layout_tree.write(layout_path) + @staticmethod + def _ifc_entity_exists(ifc: ifcopenshell.file, entity_id: int) -> bool: + try: + ifc.by_id(entity_id) + return True + except RuntimeError: + return False + def next_drawing_location(self, layout_root: ET.Element, next_width: float) -> list: titleblocks = layout_root.findall(f'{SVG}g[@data-type="titleblock"]') - drawings = layout_root.findall(f'{SVG}g[@data-type="drawing"]') + ifc = tool.Ifc.get() + drawings = [ + g + for g in layout_root.findall(f'{SVG}g[@data-type="drawing"]') + if self._ifc_entity_exists(ifc, int(g.attrib.get("data-id", "0"))) + ] # how wide is the title block frame try: @@ -403,14 +416,20 @@ class SheetBuilder: return svg - def build_drawings(self, root: ET.Element, sheet: ifcopenshell.entity_instance): + def build_drawings(self, root: ET.Element, sheet: ifcopenshell.entity_instance) -> None: for view in root.findall(f'{SVG}g[@data-type="drawing"]'): drawing_id = int(view.attrib["data-id"]) try: reference = tool.Ifc.get().by_id(int(view.attrib["data-id"])) drawing = tool.Ifc.get().by_guid(view.attrib["data-drawing"]) except RuntimeError: - # Perhaps the SVG has outdated content or is edited externally which we cannot control. + # The layout SVG has a drawing group whose IFC reference no longer + # exists. This is intentional: remove_drawing_from_sheet deliberately + # leaves the group in the layout SVG so that Blender's undo can restore + # the IFC reference and the group is still there to build from. Remove + # it only from the in-memory tree so it doesn't appear in the output + # sheet; the layout SVG file on disk is left untouched. + root.remove(view) continue images = view.findall(f"{SVG}image") diff --git a/src/bonsai/bonsai/tool/drawing.py b/src/bonsai/bonsai/tool/drawing.py index a78fd67ed2..14ee8509d3 100644 --- a/src/bonsai/bonsai/tool/drawing.py +++ b/src/bonsai/bonsai/tool/drawing.py @@ -2838,13 +2838,12 @@ class Drawing(bonsai.core.tool.Drawing): @classmethod def remove_drawing_from_sheet(cls, reference: ifcopenshell.entity_instance) -> None: - import bonsai.bim.module.drawing.sheeter as sheeter - - sheet = tool.Drawing.get_reference_document(reference) - - sheet_builder = sheeter.SheetBuilder() - sheet_builder.remove_drawing(reference, sheet) - + # NOTE: The layout SVG is intentionally NOT modified here. Removing the + # drawing group from the SVG file would make the change non-undoable + # (Blender's undo restores IFC state but not files on disk). Instead, + # build_drawings() detects and removes stale groups (those whose IFC + # reference no longer exists) the next time the sheet is built, and also + # writes the cleaned layout SVG back to disk at that point. ifcopenshell.api.document.remove_reference(tool.Ifc.get(), reference=reference) tool.Drawing.import_sheets()