Bonsai: add "Share Annotations" option to Duplicate Drawing

When duplicating a drawing with "Should Duplicate Annotations" enabled, a
new "Share Annotations" toggle lets the manual annotations be shared with
the new drawing (multi-group membership - editing one updates both) instead
of being copied into independent entities. Auto-generated tags
(grid/section/storey) are always copied, since they are regenerated per
drawing and cannot be shared.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Ryan Schultz
2026-08-20 10:34:49 -05:00
parent d911f18449
commit 8285e62365
2 changed files with 38 additions and 12 deletions
@@ -202,6 +202,14 @@ class DuplicateDrawing(bpy.types.Operator, tool.Ifc.Operator):
bl_options = {"REGISTER", "UNDO"}
drawing: bpy.props.IntProperty()
should_duplicate_annotations: bpy.props.BoolProperty(name="Should Duplicate Annotations", default=False)
share_annotations: bpy.props.BoolProperty(
name="Share Annotations",
description=(
"Assign the same annotations to the new drawing (shared - editing one updates both) "
"instead of creating independent copies. Auto-generated tags are always copied"
),
default=False,
)
@classmethod
def poll(cls, context):
@@ -216,8 +224,11 @@ class DuplicateDrawing(bpy.types.Operator, tool.Ifc.Operator):
def draw(self, context):
assert self.layout
row = self.layout
row.prop(self, "should_duplicate_annotations")
layout = self.layout
layout.prop(self, "should_duplicate_annotations")
row = layout.row()
row.enabled = self.should_duplicate_annotations
row.prop(self, "share_annotations")
def _execute(self, context):
props = tool.Drawing.get_document_props()
@@ -228,6 +239,7 @@ class DuplicateDrawing(bpy.types.Operator, tool.Ifc.Operator):
tool.Geometry,
drawing=tool.Ifc.get().by_id(self.drawing),
should_duplicate_annotations=self.should_duplicate_annotations,
share_annotations=self.share_annotations,
)
+24 -10
View File
@@ -355,6 +355,7 @@ def duplicate_drawing(
geometry: type[tool.Geometry],
drawing: ifcopenshell.entity_instance,
should_duplicate_annotations: bool = False,
share_annotations: bool = False,
) -> ifcopenshell.entity_instance:
drawing_name = drawing_tool.ensure_unique_drawing_name(drawing_tool.get_name(drawing))
new_drawing = ifc.run("root.copy_class", product=drawing)
@@ -367,16 +368,29 @@ def duplicate_drawing(
ifc.run("group.edit_group", group=new_group, attributes={"Name": drawing_name, "ObjectType": "DRAWING"})
ifc.run("group.assign_group", group=new_group, products=[new_drawing])
if should_duplicate_annotations:
new_annotations: list[ifcopenshell.entity_instance] = []
annotation_objs = [ifc.get_object(a) for a in drawing_tool.get_group_elements(group) if a != drawing]
old_to_new, _ = geometry.duplicate_ifc_objects(annotation_objs)
for new_elements in old_to_new.values():
# Remove the Blender object, since we haven't actually activated the duplicated drawing
for new_element in new_elements:
blender.remove_object(ifc.get_object(new_element))
new_annotations.extend(new_elements)
ifc.run("group.unassign_group", group=group, products=new_annotations)
ifc.run("group.assign_group", group=new_group, products=new_annotations)
source_annotations = [a for a in drawing_tool.get_group_elements(group) if a != drawing]
if share_annotations:
# Share manual annotations with the new drawing (multi-group membership):
# the same entity now belongs to both drawings' groups, so edits propagate.
# Auto-generated tags (grid/section/storey) can't be shared - they are
# regenerated per drawing - so they are still duplicated.
to_share = [a for a in source_annotations if not drawing_tool.is_auto_annotation(a)]
to_duplicate = [a for a in source_annotations if drawing_tool.is_auto_annotation(a)]
if to_share:
ifc.run("group.assign_group", group=new_group, products=to_share)
else:
to_duplicate = source_annotations
if to_duplicate:
new_annotations: list[ifcopenshell.entity_instance] = []
annotation_objs = [ifc.get_object(a) for a in to_duplicate]
old_to_new, _ = geometry.duplicate_ifc_objects(annotation_objs)
for new_elements in old_to_new.values():
# Remove the Blender object, since we haven't actually activated the duplicated drawing
for new_element in new_elements:
blender.remove_object(ifc.get_object(new_element))
new_annotations.extend(new_elements)
ifc.run("group.unassign_group", group=group, products=new_annotations)
ifc.run("group.assign_group", group=new_group, products=new_annotations)
old_reference = drawing_tool.get_drawing_document(new_drawing)
ifc.run("document.unassign_document", products=[new_drawing], document=old_reference)