Summary
bim.remove_drawing_from_sheet removes the IfcDocumentReference from the model but leaves the drawing in the sheet's layout SVG, whenever the layout's data-id no longer matches the reference's current STEP id. It fails silently — no error, and the layout file is still rewritten, so it looks like something happened.
The result is a model and a layout that disagree. Bonsai's own Sheets UI shows the drawing gone (it reads the IFC), while the layout SVG still places it — and so does anything built from that layout.
Cause
SheetBuilder.remove_drawing matches on the STEP entity id:
|
for g in layout_root.findall(f"{SVG}g"): |
|
if g.attrib.get("data-id") == str(reference.id()): |
|
layout_root.remove(g) |
|
break |
|
|
|
layout_tree.write(layout_path) |
for g in layout_root.findall(f"{SVG}g"):
if g.attrib.get("data-id") == str(reference.id()):
layout_root.remove(g)
break
layout_tree.write(layout_path)
STEP ids are not stable across a re-serialisation of the file — merging projects, or any round trip through a tool that renumbers entities, changes them. The layout keeps whatever ids were current when each drawing was added, so after a renumbering data-id points at nothing. The loop matches nothing, break is never reached, and layout_tree.write() runs regardless: the file's mtime changes and it gets reformatted, while its content is unchanged.
The same <g> element already carries a stable key, written two functions above:
view.attrib["data-id"] = str(reference.id())
view.attrib["data-drawing"] = drawing.GlobalId
And update_drawing_sizes in the same file already prefers it:
drawing = ifc_file.by_guid(drawing_view.attrib.get("data-drawing"))
So remove_drawing is the outlier — it is the one place keyed on the unstable half of the pair.
What I observed
On a project that had been through a merge:
- Sheet had 9 drawings placed in its layout. I removed 5 of them via the Sheets UI.
- The model afterwards referenced 4 — correct, and Bonsai's UI showed 4.
- The layout SVG still contained all 9, with its mtime updated to the moment of the removal.
- Every
data-id in that layout (3672697, 3729889 … 3729896) matched no entity in the file; the live IfcDocumentReferences were #1373231 … #1380359.
Two other sheets in the same project had likewise-renumbered ids. Their counts still matched only because nothing had been removed from them since — the next removal on either would fail the same way.
Reproducing it
The minimal isolation, which needs no particular file and takes a minute:
- Create a sheet and add a drawing to it.
- Open the sheet's layout in
layouts/ and change that drawing's <g data-id="..."> to any number not in the file (this stands in for the renumbering, which is otherwise incidental).
- Remove that drawing from the sheet in the Sheets panel.
- The
IfcDocumentReference is gone from the model and the drawing is gone from the UI, but the <g> is still in the layout. No error is raised.
To hit it the way it happens in practice, merge a project (or otherwise round-trip the IFC through something that renumbers entities) after sheets have been laid out, then remove a drawing from one of those sheets.
Suggested fix
Match on the drawing's GlobalId, keeping data-id as a fallback for layouts written before the change. Either resolve the drawing from the reference and compare against data-drawing, or — self-contained, no lookup needed — compare the group's foreground xlink:href against reference.Location, remembering that layout hrefs are URL-encoded.
It would also be worth logging rather than passing silently when nothing matches: a removal that quietly does nothing to the layout is the part that makes this expensive to notice. In my case the divergence went unnoticed until a downstream tool that reads layouts reported a different drawing count than the model did.
Happy to put up a PR if the GlobalId-with-fallback direction sounds right.
Version
- Bonsai 0.8.6-alpha260708, Blender 5.2, Windows
- Confirmed unchanged on the default branch
v0.9.0 as of today (e1be433)
Summary
bim.remove_drawing_from_sheetremoves theIfcDocumentReferencefrom the model but leaves the drawing in the sheet's layout SVG, whenever the layout'sdata-idno longer matches the reference's current STEP id. It fails silently — no error, and the layout file is still rewritten, so it looks like something happened.The result is a model and a layout that disagree. Bonsai's own Sheets UI shows the drawing gone (it reads the IFC), while the layout SVG still places it — and so does anything built from that layout.
Cause
SheetBuilder.remove_drawingmatches on the STEP entity id:IfcOpenShell/src/bonsai/bonsai/bim/module/drawing/sheeter.py
Lines 224 to 229 in e1be433
STEP ids are not stable across a re-serialisation of the file — merging projects, or any round trip through a tool that renumbers entities, changes them. The layout keeps whatever ids were current when each drawing was added, so after a renumbering
data-idpoints at nothing. The loop matches nothing,breakis never reached, andlayout_tree.write()runs regardless: the file's mtime changes and it gets reformatted, while its content is unchanged.The same
<g>element already carries a stable key, written two functions above:And
update_drawing_sizesin the same file already prefers it:So
remove_drawingis the outlier — it is the one place keyed on the unstable half of the pair.What I observed
On a project that had been through a merge:
data-idin that layout (3672697,3729889…3729896) matched no entity in the file; the liveIfcDocumentReferences were#1373231…#1380359.Two other sheets in the same project had likewise-renumbered ids. Their counts still matched only because nothing had been removed from them since — the next removal on either would fail the same way.
Reproducing it
The minimal isolation, which needs no particular file and takes a minute:
layouts/and change that drawing's<g data-id="...">to any number not in the file (this stands in for the renumbering, which is otherwise incidental).IfcDocumentReferenceis gone from the model and the drawing is gone from the UI, but the<g>is still in the layout. No error is raised.To hit it the way it happens in practice, merge a project (or otherwise round-trip the IFC through something that renumbers entities) after sheets have been laid out, then remove a drawing from one of those sheets.
Suggested fix
Match on the drawing's GlobalId, keeping
data-idas a fallback for layouts written before the change. Either resolve the drawing from the reference and compare againstdata-drawing, or — self-contained, no lookup needed — compare the group's foregroundxlink:hrefagainstreference.Location, remembering that layout hrefs are URL-encoded.It would also be worth logging rather than passing silently when nothing matches: a removal that quietly does nothing to the layout is the part that makes this expensive to notice. In my case the divergence went unnoticed until a downstream tool that reads layouts reported a different drawing count than the model did.
Happy to put up a PR if the GlobalId-with-fallback direction sounds right.
Version
v0.9.0as of today (e1be433)