mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-17 14:02:27 +00:00
Bonsai: allow a single IfcAnnotation to appear on multiple drawings (#9019)
A manual IfcAnnotation can now be shared across several drawings as one element: editing it once updates it everywhere, and it renders into each drawing's SVG. Assignment is native IFC - the annotation becomes a member of multiple drawing IfcGroups - so SVG generation picks it up per-drawing with no writer changes. Auto-generated annotations (grid/section/elevation/level tags, via is_auto_annotation) are excluded since they are regenerated per drawing; manual annotations, dimensions included, are shareable. - core.add_annotation_to_drawing / remove_annotation_from_drawing - tool.Drawing.get_annotation_drawings (plural) - collector links a shared annotation into every assigned drawing collection - import_annotations_in_group re-collects already-imported shared annotations - bim.add_annotation_to_drawing / bim.remove_annotation_from_drawing operators - BIM_PT_annotation_drawings panel (add/remove drawings on an annotation) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -29,8 +29,10 @@ classes = (
|
|||||||
operator.ActivateDrawingStyle,
|
operator.ActivateDrawingStyle,
|
||||||
operator.ActivateModel,
|
operator.ActivateModel,
|
||||||
operator.AddAnnotation,
|
operator.AddAnnotation,
|
||||||
|
operator.AddAnnotationToDrawing,
|
||||||
operator.AddAnnotationType,
|
operator.AddAnnotationType,
|
||||||
operator.AssignManualDrawingReference,
|
operator.AssignManualDrawingReference,
|
||||||
|
operator.RemoveAnnotationFromDrawing,
|
||||||
operator.AddDrawing,
|
operator.AddDrawing,
|
||||||
operator.AddDrawingStyle,
|
operator.AddDrawingStyle,
|
||||||
operator.AddDrawingToSheet,
|
operator.AddDrawingToSheet,
|
||||||
@@ -133,6 +135,7 @@ classes = (
|
|||||||
ui.BIM_PT_schedules,
|
ui.BIM_PT_schedules,
|
||||||
ui.BIM_PT_references,
|
ui.BIM_PT_references,
|
||||||
ui.BIM_PT_product_assignments,
|
ui.BIM_PT_product_assignments,
|
||||||
|
ui.BIM_PT_annotation_drawings,
|
||||||
ui.BIM_PT_text,
|
ui.BIM_PT_text,
|
||||||
ui.BIM_UL_drawinglist,
|
ui.BIM_UL_drawinglist,
|
||||||
ui.BIM_UL_sheets,
|
ui.BIM_UL_sheets,
|
||||||
|
|||||||
@@ -47,9 +47,28 @@ class ProductAssignmentsData:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def load(cls):
|
def load(cls):
|
||||||
cls.data = {"relating_product": cls.relating_product()}
|
cls.data = {
|
||||||
|
"relating_product": cls.relating_product(),
|
||||||
|
"annotation_drawings": cls.annotation_drawings(),
|
||||||
|
"is_auto_annotation": cls.is_auto_annotation(),
|
||||||
|
}
|
||||||
cls.is_loaded = True
|
cls.is_loaded = True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def is_auto_annotation(cls):
|
||||||
|
element = tool.Ifc.get_entity(bpy.context.active_object)
|
||||||
|
if not element or not element.is_a("IfcAnnotation"):
|
||||||
|
return False
|
||||||
|
return tool.Drawing.is_auto_annotation(element)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def annotation_drawings(cls):
|
||||||
|
"""List of (drawing_id, drawing_name) the active annotation is assigned to."""
|
||||||
|
element = tool.Ifc.get_entity(bpy.context.active_object)
|
||||||
|
if not element or not element.is_a("IfcAnnotation") or element.ObjectType == "DRAWING":
|
||||||
|
return []
|
||||||
|
return [(d.id(), d.Name or f"Drawing {d.id()}") for d in tool.Drawing.get_annotation_drawings(element)]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def relating_product(cls):
|
def relating_product(cls):
|
||||||
element = tool.Ifc.get_entity(bpy.context.active_object)
|
element = tool.Ifc.get_entity(bpy.context.active_object)
|
||||||
|
|||||||
@@ -1896,6 +1896,102 @@ class AssignManualDrawingReference(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
area.tag_redraw()
|
area.tag_redraw()
|
||||||
|
|
||||||
|
|
||||||
|
def _get_unassigned_drawing_enum_items(self, context):
|
||||||
|
"""Drawings the active annotation is NOT yet assigned to."""
|
||||||
|
items = []
|
||||||
|
if (ifc := tool.Ifc.get()) and context.active_object:
|
||||||
|
element = tool.Ifc.get_entity(context.active_object)
|
||||||
|
assigned = set(tool.Drawing.get_annotation_drawings(element)) if element else set()
|
||||||
|
for d in ifc.by_type("IfcAnnotation"):
|
||||||
|
if d.ObjectType == "DRAWING" and d not in assigned:
|
||||||
|
items.append((str(d.id()), d.Name or f"Drawing {d.id()}", ""))
|
||||||
|
if not items:
|
||||||
|
items.append(("0", "No available drawings", ""))
|
||||||
|
return items
|
||||||
|
|
||||||
|
|
||||||
|
class AddAnnotationToDrawing(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
|
bl_idname = "bim.add_annotation_to_drawing"
|
||||||
|
bl_label = "Add Annotation To Drawing"
|
||||||
|
bl_description = "Assign the selected annotation(s) to an additional drawing so they render on it too"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
drawing_id: bpy.props.EnumProperty(name="Drawing", items=_get_unassigned_drawing_enum_items)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
if not tool.Ifc.get() or not context.active_object:
|
||||||
|
return False
|
||||||
|
element = tool.Ifc.get_entity(context.active_object)
|
||||||
|
if not element or not element.is_a("IfcAnnotation") or element.ObjectType == "DRAWING":
|
||||||
|
cls.poll_message_set("Active object is not an annotation.")
|
||||||
|
return False
|
||||||
|
if tool.Drawing.is_auto_annotation(element):
|
||||||
|
cls.poll_message_set("Auto-generated annotations cannot be shared across drawings.")
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def invoke(self, context, event):
|
||||||
|
return context.window_manager.invoke_props_dialog(self)
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
prop_with_search(
|
||||||
|
self.layout, self, "drawing_id", should_click_ok=True, search_threshold=0,
|
||||||
|
original_operator_path=f"{__name__}.AddAnnotationToDrawing",
|
||||||
|
)
|
||||||
|
|
||||||
|
def _execute(self, context):
|
||||||
|
if self.drawing_id == "0":
|
||||||
|
self.report({"WARNING"}, "No drawing selected.")
|
||||||
|
return
|
||||||
|
drawing = tool.Ifc.get().by_id(int(self.drawing_id))
|
||||||
|
elements = [
|
||||||
|
element
|
||||||
|
for o in tool.Blender.get_selected_objects()
|
||||||
|
if (element := tool.Ifc.get_entity(o)) and element.is_a("IfcAnnotation") and element.ObjectType != "DRAWING"
|
||||||
|
]
|
||||||
|
assigned = 0
|
||||||
|
skipped = 0
|
||||||
|
for element in elements:
|
||||||
|
if core.add_annotation_to_drawing(tool.Ifc, tool.Collector, tool.Drawing, element=element, drawing=drawing):
|
||||||
|
assigned += 1
|
||||||
|
else:
|
||||||
|
skipped += 1
|
||||||
|
msg = f"Assigned {assigned} annotation(s) to {drawing.Name or 'drawing'}."
|
||||||
|
if skipped:
|
||||||
|
msg += f" Skipped {skipped} (auto-generated or already assigned)."
|
||||||
|
self.report({"INFO"}, msg)
|
||||||
|
for area in context.screen.areas:
|
||||||
|
if area.type == "PROPERTIES":
|
||||||
|
area.tag_redraw()
|
||||||
|
|
||||||
|
|
||||||
|
class RemoveAnnotationFromDrawing(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
|
bl_idname = "bim.remove_annotation_from_drawing"
|
||||||
|
bl_label = "Remove Annotation From Drawing"
|
||||||
|
bl_description = "Remove the active annotation from this drawing (it stays on its other drawings)"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
drawing_id: bpy.props.IntProperty(options={"SKIP_SAVE"})
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
if not tool.Ifc.get() or not context.active_object:
|
||||||
|
return False
|
||||||
|
element = tool.Ifc.get_entity(context.active_object)
|
||||||
|
return bool(element and element.is_a("IfcAnnotation") and element.ObjectType != "DRAWING")
|
||||||
|
|
||||||
|
def _execute(self, context):
|
||||||
|
element = tool.Ifc.get_entity(context.active_object)
|
||||||
|
drawing = tool.Ifc.get().by_id(self.drawing_id)
|
||||||
|
if not core.remove_annotation_from_drawing(
|
||||||
|
tool.Ifc, tool.Collector, tool.Drawing, element=element, drawing=drawing
|
||||||
|
):
|
||||||
|
self.report({"WARNING"}, "An annotation must remain on at least one drawing.")
|
||||||
|
return
|
||||||
|
for area in context.screen.areas:
|
||||||
|
if area.type == "PROPERTIES":
|
||||||
|
area.tag_redraw()
|
||||||
|
|
||||||
|
|
||||||
class AddSheet(bpy.types.Operator, tool.Ifc.Operator):
|
class AddSheet(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
bl_idname = "bim.add_sheet"
|
bl_idname = "bim.add_sheet"
|
||||||
bl_label = "Add Sheet"
|
bl_label = "Add Sheet"
|
||||||
|
|||||||
@@ -564,6 +564,51 @@ class BIM_PT_product_assignments(Panel):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class BIM_PT_annotation_drawings(Panel):
|
||||||
|
bl_label = "Drawings"
|
||||||
|
bl_idname = "BIM_PT_annotation_drawings"
|
||||||
|
bl_space_type = "PROPERTIES"
|
||||||
|
bl_region_type = "WINDOW"
|
||||||
|
bl_context = "object"
|
||||||
|
bl_order = 2
|
||||||
|
bl_parent_id = "BIM_PT_tab_object_metadata"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
if not tool.Ifc.get() or not context.active_object:
|
||||||
|
return False
|
||||||
|
element = tool.Ifc.get_entity(context.active_object)
|
||||||
|
if not element or not element.is_a("IfcAnnotation") or element.ObjectType == "DRAWING":
|
||||||
|
return False
|
||||||
|
# Manual drawing-reference tags point at a single target drawing via a
|
||||||
|
# different mechanism, so multi-drawing sharing doesn't apply to them.
|
||||||
|
return not tool.Drawing.is_manual_drawing_reference(element)
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
if not ProductAssignmentsData.is_loaded:
|
||||||
|
ProductAssignmentsData.load()
|
||||||
|
|
||||||
|
assert self.layout
|
||||||
|
|
||||||
|
if ProductAssignmentsData.data["is_auto_annotation"]:
|
||||||
|
self.layout.label(text="Auto-generated annotation (single drawing).", icon="INFO")
|
||||||
|
return
|
||||||
|
|
||||||
|
row = self.layout.row(align=True)
|
||||||
|
row.label(text="Shown on drawings:", icon="IMAGE_DATA")
|
||||||
|
row.operator("bim.add_annotation_to_drawing", icon="ADD", text="")
|
||||||
|
|
||||||
|
drawings = ProductAssignmentsData.data["annotation_drawings"]
|
||||||
|
allow_remove = len(drawings) > 1
|
||||||
|
for drawing_id, drawing_name in drawings:
|
||||||
|
row = self.layout.row(align=True)
|
||||||
|
row.label(text=drawing_name, icon="OUTLINER_OB_CAMERA")
|
||||||
|
sub = row.column()
|
||||||
|
sub.enabled = allow_remove
|
||||||
|
op = sub.operator("bim.remove_annotation_from_drawing", icon="X", text="")
|
||||||
|
op.drawing_id = drawing_id
|
||||||
|
|
||||||
|
|
||||||
def get_category_icon(category_name):
|
def get_category_icon(category_name):
|
||||||
"""Get appropriate icon for each category"""
|
"""Get appropriate icon for each category"""
|
||||||
icons = {
|
icons = {
|
||||||
|
|||||||
@@ -503,6 +503,55 @@ def add_annotation(
|
|||||||
return obj
|
return obj
|
||||||
|
|
||||||
|
|
||||||
|
def add_annotation_to_drawing(
|
||||||
|
ifc: type[tool.Ifc],
|
||||||
|
collector: type[tool.Collector],
|
||||||
|
drawing_tool: type[tool.Drawing],
|
||||||
|
element: ifcopenshell.entity_instance,
|
||||||
|
drawing: ifcopenshell.entity_instance,
|
||||||
|
) -> bool:
|
||||||
|
"""Assign a manual annotation to an additional drawing so it renders on it too.
|
||||||
|
|
||||||
|
Auto-generated annotations (grid/section/elevation tags, etc.) are tied to a
|
||||||
|
single drawing's regeneration cycle and cannot be shared - they are skipped.
|
||||||
|
Returns True if the annotation was assigned, False if it was skipped/already there.
|
||||||
|
"""
|
||||||
|
if drawing_tool.is_auto_annotation(element):
|
||||||
|
return False
|
||||||
|
group = drawing_tool.get_drawing_group(drawing)
|
||||||
|
if not group or drawing in drawing_tool.get_annotation_drawings(element):
|
||||||
|
return False
|
||||||
|
ifc.run("group.assign_group", group=group, products=[element])
|
||||||
|
# Relink the Blender object so it becomes visible in the newly-assigned
|
||||||
|
# drawing's collection as well.
|
||||||
|
if obj := ifc.get_object(element):
|
||||||
|
collector.assign(obj)
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def remove_annotation_from_drawing(
|
||||||
|
ifc: type[tool.Ifc],
|
||||||
|
collector: type[tool.Collector],
|
||||||
|
drawing_tool: type[tool.Drawing],
|
||||||
|
element: ifcopenshell.entity_instance,
|
||||||
|
drawing: ifcopenshell.entity_instance,
|
||||||
|
) -> bool:
|
||||||
|
"""Remove a manual annotation from a drawing's group.
|
||||||
|
|
||||||
|
An annotation must always belong to at least one drawing, so removal from its
|
||||||
|
last remaining drawing is refused. Returns True if removed, False otherwise.
|
||||||
|
"""
|
||||||
|
if len(drawing_tool.get_annotation_drawings(element)) <= 1:
|
||||||
|
return False
|
||||||
|
group = drawing_tool.get_drawing_group(drawing)
|
||||||
|
if not group:
|
||||||
|
return False
|
||||||
|
ifc.run("group.unassign_group", group=group, products=[element])
|
||||||
|
if obj := ifc.get_object(element):
|
||||||
|
collector.assign(obj)
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
def assign_manual_drawing_reference(
|
def assign_manual_drawing_reference(
|
||||||
ifc: type[tool.Ifc],
|
ifc: type[tool.Ifc],
|
||||||
drawing_tool: type[tool.Drawing],
|
drawing_tool: type[tool.Drawing],
|
||||||
|
|||||||
@@ -358,6 +358,8 @@ class Drawing:
|
|||||||
def generate_reference_attributes(cls, reference, **attributes): pass
|
def generate_reference_attributes(cls, reference, **attributes): pass
|
||||||
def generate_sheet_identification(cls): pass
|
def generate_sheet_identification(cls): pass
|
||||||
def get_annotation_context(cls, target_view, object_type=None): pass
|
def get_annotation_context(cls, target_view, object_type=None): pass
|
||||||
|
def get_annotation_drawing(cls, element): pass
|
||||||
|
def get_annotation_drawings(cls, element): pass
|
||||||
def get_annotation_representation(cls, element_type): pass
|
def get_annotation_representation(cls, element_type): pass
|
||||||
def get_assigned_product(cls, element): pass
|
def get_assigned_product(cls, element): pass
|
||||||
def get_assigned_product_workaround(cls, element): pass
|
def get_assigned_product_workaround(cls, element): pass
|
||||||
@@ -393,6 +395,7 @@ class Drawing:
|
|||||||
def import_text_attributes(cls, obj): pass
|
def import_text_attributes(cls, obj): pass
|
||||||
def is_active_drawing(cls, drawing): pass
|
def is_active_drawing(cls, drawing): pass
|
||||||
def is_annotation_object_type(cls, element, object_types): pass
|
def is_annotation_object_type(cls, element, object_types): pass
|
||||||
|
def is_auto_annotation(cls, element): pass
|
||||||
def is_camera_orthographic(cls): pass
|
def is_camera_orthographic(cls): pass
|
||||||
def is_drawing_active(cls): pass
|
def is_drawing_active(cls): pass
|
||||||
def is_editing_sheets(cls): pass
|
def is_editing_sheets(cls): pass
|
||||||
|
|||||||
@@ -119,8 +119,12 @@ class Collector(bonsai.core.tool.Collector):
|
|||||||
cls.link_collection_object_safe(collection, obj)
|
cls.link_collection_object_safe(collection, obj)
|
||||||
project_obj = tool.Ifc.get_object(tool.Ifc.get().by_type("IfcProject")[0])
|
project_obj = tool.Ifc.get_object(tool.Ifc.get().by_type("IfcProject")[0])
|
||||||
cls.link_collection_child_safe(tool.Blender.get_object_bim_props(project_obj).collection, collection)
|
cls.link_collection_child_safe(tool.Blender.get_object_bim_props(project_obj).collection, collection)
|
||||||
elif element.is_a("IfcAnnotation") and (drawing_obj := cls.get_annotation_drawing_obj(element)):
|
elif element.is_a("IfcAnnotation") and (drawing_objs := cls.get_annotation_drawing_objs(element)):
|
||||||
cls.link_collection_object_safe(tool.Blender.get_object_bim_props(drawing_obj).collection, obj)
|
# An annotation may be shared across several drawings; link it into
|
||||||
|
# each drawing's collection so it is visible/editable from all of them.
|
||||||
|
for drawing_obj in drawing_objs:
|
||||||
|
if target_collection := tool.Blender.get_object_bim_props(drawing_obj).collection:
|
||||||
|
cls.link_collection_object_safe(target_collection, obj)
|
||||||
elif container := ifcopenshell.util.element.get_container(element):
|
elif container := ifcopenshell.util.element.get_container(element):
|
||||||
while container.is_a("IfcSpace"):
|
while container.is_a("IfcSpace"):
|
||||||
container = ifcopenshell.util.element.get_aggregate(container)
|
container = ifcopenshell.util.element.get_aggregate(container)
|
||||||
@@ -169,6 +173,18 @@ class Collector(bonsai.core.tool.Collector):
|
|||||||
if related_object.is_a("IfcAnnotation") and related_object.ObjectType == "DRAWING":
|
if related_object.is_a("IfcAnnotation") and related_object.ObjectType == "DRAWING":
|
||||||
return tool.Ifc.get_object(related_object)
|
return tool.Ifc.get_object(related_object)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_annotation_drawing_objs(cls, element: ifcopenshell.entity_instance) -> list[bpy.types.Object]:
|
||||||
|
"""Every drawing camera object this annotation is assigned to (may be several)."""
|
||||||
|
objs = []
|
||||||
|
for rel in element.HasAssignments or []:
|
||||||
|
if rel.is_a("IfcRelAssignsToGroup") and rel.RelatingGroup.ObjectType == "DRAWING":
|
||||||
|
for related_object in rel.RelatedObjects:
|
||||||
|
if related_object.is_a("IfcAnnotation") and related_object.ObjectType == "DRAWING":
|
||||||
|
if (drawing_obj := tool.Ifc.get_object(related_object)) and drawing_obj not in objs:
|
||||||
|
objs.append(drawing_obj)
|
||||||
|
return objs
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def link_collection_object_safe(cls, collection: bpy.types.Collection, obj: bpy.types.Object) -> None:
|
def link_collection_object_safe(cls, collection: bpy.types.Collection, obj: bpy.types.Object) -> None:
|
||||||
# Catching an exception is 10x faster than doing collection.objects.find
|
# Catching an exception is 10x faster than doing collection.objects.find
|
||||||
|
|||||||
@@ -233,6 +233,21 @@ class Drawing(bonsai.core.tool.Drawing):
|
|||||||
if e.ObjectType == "DRAWING":
|
if e.ObjectType == "DRAWING":
|
||||||
return e
|
return e
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_annotation_drawings(cls, element: ifcopenshell.entity_instance) -> list[ifcopenshell.entity_instance]:
|
||||||
|
"""Return every drawing (camera) this annotation is assigned to.
|
||||||
|
|
||||||
|
An annotation may belong to multiple drawing groups (it renders on each);
|
||||||
|
the singular get_annotation_drawing returns only the first/home drawing.
|
||||||
|
"""
|
||||||
|
drawings = []
|
||||||
|
for rel in element.HasAssignments or []:
|
||||||
|
if rel.is_a("IfcRelAssignsToGroup") and rel.RelatingGroup.ObjectType == "DRAWING":
|
||||||
|
for e in rel.RelatedObjects:
|
||||||
|
if e.ObjectType == "DRAWING" and e not in drawings:
|
||||||
|
drawings.append(e)
|
||||||
|
return drawings
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def exclude_annotation_from_drawing(
|
def exclude_annotation_from_drawing(
|
||||||
cls, element: ifcopenshell.entity_instance, drawing: ifcopenshell.entity_instance
|
cls, element: ifcopenshell.entity_instance, drawing: ifcopenshell.entity_instance
|
||||||
@@ -936,13 +951,10 @@ class Drawing(bonsai.core.tool.Drawing):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def import_annotations_in_group(cls, group: ifcopenshell.entity_instance) -> None:
|
def import_annotations_in_group(cls, group: ifcopenshell.entity_instance) -> None:
|
||||||
elements = set(
|
group_annotations = [
|
||||||
[
|
e for e in cls.get_group_elements(group) if e.is_a("IfcAnnotation") and e.ObjectType != "DRAWING"
|
||||||
e
|
]
|
||||||
for e in cls.get_group_elements(group)
|
elements = set(e for e in group_annotations if not tool.Ifc.get_object(e))
|
||||||
if e.is_a("IfcAnnotation") and e.ObjectType != "DRAWING" and not tool.Ifc.get_object(e)
|
|
||||||
]
|
|
||||||
)
|
|
||||||
logger = logging.getLogger("ImportIFC")
|
logger = logging.getLogger("ImportIFC")
|
||||||
ifc_import_settings = bonsai.bim.import_ifc.IfcImportSettings.factory(bpy.context, None, logger)
|
ifc_import_settings = bonsai.bim.import_ifc.IfcImportSettings.factory(bpy.context, None, logger)
|
||||||
ifc_importer = bonsai.bim.import_ifc.IfcImporter(ifc_import_settings)
|
ifc_importer = bonsai.bim.import_ifc.IfcImporter(ifc_import_settings)
|
||||||
@@ -955,6 +967,13 @@ class Drawing(bonsai.core.tool.Drawing):
|
|||||||
ifc_importer.setup_arrays(annotations_to_import=elements)
|
ifc_importer.setup_arrays(annotations_to_import=elements)
|
||||||
for obj in ifc_importer.added_data.values():
|
for obj in ifc_importer.added_data.values():
|
||||||
tool.Collector.assign(obj)
|
tool.Collector.assign(obj)
|
||||||
|
# Annotations shared from another drawing may already have a Blender object
|
||||||
|
# (so they were skipped above); re-collect them so they are also linked into
|
||||||
|
# this drawing's collection.
|
||||||
|
added_objs = set(ifc_importer.added_data.values())
|
||||||
|
for e in group_annotations:
|
||||||
|
if (obj := tool.Ifc.get_object(e)) and obj not in added_objs:
|
||||||
|
tool.Collector.assign(obj)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_camera_shape_matrix(
|
def get_camera_shape_matrix(
|
||||||
|
|||||||
Reference in New Issue
Block a user