Fix #7273. See #7253. Auto annotation references now cannot be deleted, but can be excluded.

This commit is contained in:
Dion Moult
2025-10-22 18:03:05 +11:00
parent 1f47aadc94
commit f48b5b9d92
7 changed files with 52 additions and 12 deletions
@@ -61,6 +61,7 @@ classes = (
operator.EnableEditingAssignedProduct,
operator.EnableEditingElementFilter,
operator.EnableEditingText,
operator.ExcludeAnnotation,
operator.ExpandSheet,
operator.LoadDrawings,
operator.LoadReferences,
@@ -3757,3 +3757,19 @@ class OpenDocumentationWebUi(bpy.types.Operator):
else:
bpy.ops.bim.open_web_browser(page="documentation")
return {"FINISHED"}
class ExcludeAnnotation(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.exclude_annotation"
bl_label = "Exclude Annotation"
bl_description = "Excludes the automatic annotation reference from the drawing"
bl_options = {"REGISTER", "UNDO"}
def _execute(self, context):
if not (obj := bpy.context.scene.camera) or not (drawing := tool.Ifc.get_entity(obj)):
return
for obj in tool.Blender.get_selected_objects(include_active=False):
if (element := tool.Ifc.get_entity(obj)) and tool.Drawing.is_auto_annotation(element):
if (referenced_element := tool.Drawing.get_annotation_element(element)):
tool.Drawing.exclude_annotation_from_drawing(referenced_element, drawing)
core.sync_references(tool.Ifc, tool.Collector, tool.Drawing, drawing=drawing)
@@ -194,6 +194,7 @@ class BIM_PT_element_filters(Panel):
text = "Exclude Filter" if ElementFiltersData.data["has_exclude_filter"] else "No Exclude Filter Found"
icon = "GREASEPENCIL" if ElementFiltersData.data["has_exclude_filter"] else "ADD"
row.label(text=text, icon="FILTER")
row.operator("bim.exclude_annotation", icon="REMOVE", text="")
row.operator("bim.enable_editing_element_filter", icon=icon, text="").filter_mode = "EXCLUDE"
@@ -787,6 +787,7 @@ def calc_delete_is_batch(ifc_file: ifcopenshell.file, context: bpy.types.Context
is_batch = total_elements > 500000 and total_polygons > 2000
return is_batch
class OverrideDelete(bpy.types.Operator):
bl_idname = "bim.override_object_delete"
bl_label = "IFC Delete"
@@ -857,10 +858,10 @@ class OverrideDelete(bpy.types.Operator):
objects_to_remove = context.selected_objects
self.process_arrays(context)
# Track aggregates before deleting their parts
aggregates_to_check = self.track_aggregates(objects_to_remove)
clear_active_object = True
for i, obj in enumerate(objects_to_remove, 1):
@@ -895,6 +896,9 @@ class OverrideDelete(bpy.types.Operator):
{"INFO"}, "The last grid axis of a grid cannot be deleted. Delete the grid instead."
)
continue
if tool.Drawing.is_auto_annotation(element):
self.report({"INFO"}, "References cannot be deleted. Exclude the referenced element instead.")
continue
tool.Geometry.delete_ifc_object(obj)
elif tool.Geometry.is_representation_item(obj):
tool.Geometry.delete_ifc_item(obj)
@@ -959,23 +963,25 @@ class OverrideDelete(bpy.types.Operator):
aggregate.id()
except:
continue
related_objects = ifcopenshell.util.element.get_parts(aggregate)
if len(related_objects) == 0:
aggregate_name = aggregate.Name or f"{aggregate.is_a()} #{aggregate.id()}"
deleted_aggregates.append(aggregate_name)
aggregate_obj = tool.Ifc.get_object(aggregate)
if aggregate_obj and tool.Blender.is_valid_data_block(aggregate_obj):
tool.Geometry.delete_ifc_object(aggregate_obj)
# Show info message if aggregates were deleted
if deleted_aggregates:
if len(deleted_aggregates) == 1:
self.report({'INFO'}, f"Aggregate '{deleted_aggregates[0]}' was deleted because it had no remaining parts")
self.report(
{"INFO"}, f"Aggregate '{deleted_aggregates[0]}' was deleted because it had no remaining parts"
)
else:
aggregate_list = ", ".join(f"'{name}'" for name in deleted_aggregates)
self.report({'INFO'}, f"Aggregates {aggregate_list} were deleted because they had no remaining parts")
self.report({"INFO"}, f"Aggregates {aggregate_list} were deleted because they had no remaining parts")
def process_arrays(self, context: bpy.types.Context) -> None:
ifc_file = tool.Ifc.get()
@@ -1002,6 +1008,7 @@ class OverrideDelete(bpy.types.Operator):
else:
break # allows to remove only n last layers of an array
class SelectedIdsData(NamedTuple):
objects: set[bpy.types.Object]
collections: set[bpy.types.Collection]
+11 -1
View File
@@ -476,7 +476,17 @@ def sync_references(
return
group = drawing_tool.get_drawing_group(drawing)
for reference_element in drawing_tool.get_potential_reference_elements(drawing):
potential_reference_elements = drawing_tool.get_potential_reference_elements(drawing)
for element in drawing_tool.get_group_elements(group):
if (
drawing_tool.is_auto_annotation(element)
and drawing_tool.get_assigned_product(element) not in potential_reference_elements
):
if obj := ifc.get_object(element):
drawing_tool.delete_object(obj)
ifc.run("root.remove_product", product=element)
for reference_element in potential_reference_elements:
reference_obj = ifc.get_object(reference_element)
annotation = drawing_tool.get_drawing_reference_annotation(drawing, reference_element)
+7 -2
View File
@@ -1488,13 +1488,19 @@ class Drawing(bonsai.core.tool.Drawing):
for axis in element.UAxes + element.VAxes + (element.WAxes or tuple()):
if axis in existing_references:
continue
elements.append(element)
elements.append(axis)
target_view = tool.Drawing.get_drawing_target_view(drawing)
if target_view in ("SECTION_VIEW", "ELEVATION_VIEW"):
for element in tool.Ifc.get().by_type("IfcBuildingStorey"):
if element in existing_references:
continue
elements.append(element)
return elements
@classmethod
def is_auto_annotation(cls, element: ifcopenshell.entity_instance):
return element.is_a("IfcAnnotation") and element.ObjectType in ("GRID", "SECTION", "ELEVATION", "SECTION_LEVEL")
@classmethod
def get_drawing_reference_annotation(
cls, drawing: ifcopenshell.entity_instance, reference_element: ifcopenshell.entity_instance
@@ -2649,5 +2655,4 @@ class Drawing(bonsai.core.tool.Drawing):
def hide_all_drawing_collections(cls) -> None:
for element in tool.Ifc.get().by_type("IfcAnnotation"):
if element.ObjectType == "DRAWING" and (obj := tool.Ifc.get_object(element)):
print('found element', element)
tool.Blender.get_layer_collection(obj.users_collection[0]).hide_viewport = True
+2 -2
View File
@@ -236,8 +236,8 @@ class Geometry(bonsai.core.tool.Geometry):
elif element.is_a("IfcAnnotation"):
if element.ObjectType == "DRAWING":
return bonsai.core.drawing.remove_drawing(tool.Ifc, tool.Drawing, drawing=element)
elif (referenced_element := tool.Drawing.get_annotation_element(element)) and (drawing := tool.Drawing.get_annotation_drawing(element)):
tool.Drawing.exclude_annotation_from_drawing(referenced_element, drawing)
elif tool.Drawing.is_auto_annotation(element):
return # For now, these are special referenced objects and cannot be deleted. Exclude instead.
elif element.is_a("IfcRelSpaceBoundary"):
ifcopenshell.api.boundary.remove_boundary(ifc_file, boundary=element)
tool.Boundary.undecorate_boundary(obj)