Fix #5897. Fix #5488. Fix #5498. Bug where you couldn't edit newly added annotation.

The annotation adding code was a bit of a mess, spread around
create_annotation, create_annotation_occurrence, and
bpy.ops.bim.add_annotation. I've now consolidated it all into
core.add_annotation and updated it to work with the new item editing
mode (basically new objects need to reload their representation to
populate item_ids). Things are still messy, but a bit less now.
This commit is contained in:
Dion Moult
2025-01-17 20:53:29 +11:00
parent c163b260cf
commit 24b3cfc067
4 changed files with 87 additions and 43 deletions
@@ -1423,27 +1423,33 @@ class AddAnnotation(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.add_annotation" bl_idname = "bim.add_annotation"
bl_label = "Add Annotation" bl_label = "Add Annotation"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
object_type: bpy.props.StringProperty()
data_type: bpy.props.StringProperty()
description: bpy.props.StringProperty() description: bpy.props.StringProperty()
@classmethod @classmethod
def poll(cls, context): def poll(cls, context):
return IfcStore.get_file() and context.scene.camera return tool.Ifc.get() and context.scene.camera
@classmethod @classmethod
def description(cls, context, operator): def description(cls, context, operator):
return operator.description or "" return operator.description or ""
def _execute(self, context): def _execute(self, context):
drawing = tool.Ifc.get_entity(context.scene.camera) props = bpy.context.scene.BIMAnnotationProperties
if not drawing: if not (drawing := tool.Ifc.get_entity(context.scene.camera)):
self.report({"WARNING"}, "Not a BIM camera") self.report({"WARNING"}, "Not a BIM camera")
return return
r = core.add_annotation(tool.Ifc, tool.Collector, tool.Drawing, drawing=drawing, object_type=self.object_type) obj = core.add_annotation(
if isinstance(r, str): tool.Ifc,
self.report({"WARNING"}, r) tool.Collector,
tool.Drawing,
drawing=drawing,
object_type=props.object_type,
relating_type=tool.Ifc.get().by_id(int(props.relating_type_id)) if props.relating_type_id != "0" else None,
enable_editing=True,
)
if props.object_type == "IMAGE":
bpy.ops.bim.add_reference_image("INVOKE_DEFAULT", use_existing_object_by_name=obj.name)
class AddSheet(bpy.types.Operator, tool.Ifc.Operator): class AddSheet(bpy.types.Operator, tool.Ifc.Operator):
@@ -20,7 +20,9 @@
import os import os
import bpy import bpy
import bonsai.core.type import bonsai.core.type
import bonsai.core.drawing as core
import bonsai.tool as tool import bonsai.tool as tool
import ifcopenshell.util.representation
from bonsai.bim.module.drawing.data import DecoratorData, AnnotationData from bonsai.bim.module.drawing.data import DecoratorData, AnnotationData
from bonsai.bim.helper import prop_with_search from bonsai.bim.helper import prop_with_search
from bpy.types import WorkSpaceTool from bpy.types import WorkSpaceTool
@@ -161,12 +163,12 @@ def create_annotation_occurrence(context):
obj = tool.Drawing.create_annotation_object(drawing, object_type) obj = tool.Drawing.create_annotation_object(drawing, object_type)
obj.name = relating_type.Name obj.name = relating_type.Name
ifc_context = tool.Drawing.get_annotation_context(tool.Drawing.get_drawing_target_view(drawing), object_type) ifc_context = tool.Drawing.get_annotation_context(tool.Drawing.get_drawing_target_view(drawing), object_type)
relating_type_repr = tool.Drawing.get_annotation_representation(relating_type) relating_type_rep = tool.Drawing.get_annotation_representation(relating_type)
element = tool.Drawing.run_root_assign_class( element = tool.Drawing.run_root_assign_class(
obj=obj, obj=obj,
ifc_class="IfcAnnotation", ifc_class="IfcAnnotation",
predefined_type=object_type, predefined_type=object_type,
should_add_representation=not bool(relating_type_repr), should_add_representation=not relating_type_rep,
context=ifc_context, context=ifc_context,
ifc_representation_class=tool.Drawing.get_ifc_representation_class(object_type), ifc_representation_class=tool.Drawing.get_ifc_representation_class(object_type),
) )
@@ -175,27 +177,23 @@ def create_annotation_occurrence(context):
tool.Ifc.run("group.assign_group", group=tool.Drawing.get_drawing_group(drawing), products=[element]) tool.Ifc.run("group.assign_group", group=tool.Drawing.get_drawing_group(drawing), products=[element])
tool.Collector.assign(obj) tool.Collector.assign(obj)
tool.Blender.select_and_activate_single_object(context, obj)
if relating_type_repr is None and props.object_type == "IMAGE": if relating_type_rep is None and props.object_type == "IMAGE":
bpy.ops.bim.add_reference_image("INVOKE_DEFAULT", use_existing_object_by_name=obj.name) bpy.ops.bim.add_reference_image("INVOKE_DEFAULT", use_existing_object_by_name=obj.name)
if representation := ifcopenshell.util.representation.get_representation(element, ifc_context):
def create_annotation(): bonsai.core.geometry.switch_representation(
props = bpy.context.scene.BIMAnnotationProperties tool.Ifc,
if props.relating_type_id != "0": tool.Geometry,
create_annotation_occurrence(bpy.context) obj=obj,
else: representation=representation,
object_type = props.object_type should_reload=True,
if not bpy.ops.bim.add_annotation.poll(): is_global=True,
return should_sync_changes_first=False,
bpy.ops.bim.add_annotation(
object_type=object_type, data_type=tool.Drawing.ANNOTATION_TYPES_DATA[object_type][-1]
) )
if props.object_type == "IMAGE":
bpy.ops.bim.add_reference_image( if obj.data and not relating_type_rep:
"INVOKE_DEFAULT", use_existing_object_by_name=bpy.context.active_object.name tool.Drawing.enable_editing(obj)
)
class AnnotationToolUI: class AnnotationToolUI:
@@ -294,21 +292,28 @@ class Hotkey(bpy.types.Operator, tool.Ifc.Operator):
def hotkey_S_T(self): def hotkey_S_T(self):
props = bpy.context.scene.BIMAnnotationProperties props = bpy.context.scene.BIMAnnotationProperties
annotation_type = props.object_type object_type = props.object_type
if annotation_type not in tool.Drawing.ANNOTATION_TYPES_SUPPORT_SETUP: if object_type not in tool.Drawing.ANNOTATION_TYPES_SUPPORT_SETUP:
self.report({"ERROR"}, f"Annotation type {annotation_type} is not supported for tagging.") self.report({"ERROR"}, f"Annotation type {object_type} is not supported for tagging.")
return return
related_objects = bpy.context.selected_objects related_objects = bpy.context.selected_objects
for related_object in related_objects: for related_object in related_objects:
create_annotation() obj = core.add_annotation(
obj = bpy.context.active_object tool.Ifc,
bpy.ops.object.mode_set(mode="OBJECT") tool.Collector,
tool.Drawing.setup_annotation_object(obj, annotation_type, related_object) tool.Drawing,
drawing=tool.Ifc.get_entity(bpy.context.scene.camera),
object_type=object_type,
relating_type=tool.Ifc.get().by_id(int(props.relating_type_id)) if props.relating_type_id != "0" else None,
enable_editing=False,
)
tool.Drawing.setup_annotation_object(obj, object_type, related_object)
def hotkey_S_A(self): def hotkey_S_A(self):
create_annotation() if bpy.ops.bim.add_annotation.poll():
bpy.ops.bim.add_annotation()
def hotkey_S_E(self): def hotkey_S_E(self):
if not bpy.context.active_object: if not bpy.context.active_object:
+12 -3
View File
@@ -406,7 +406,9 @@ def add_annotation(
drawing_tool: tool.Drawing, drawing_tool: tool.Drawing,
drawing: ifcopenshell.entity_instance, drawing: ifcopenshell.entity_instance,
object_type: str, object_type: str,
) -> None: relating_type: ifcopenshell.entity_instance,
enable_editing: bool = False,
) -> bpy.types.Object:
target_view = drawing_tool.get_drawing_target_view(drawing) target_view = drawing_tool.get_drawing_target_view(drawing)
context = drawing_tool.get_annotation_context(target_view, object_type) context = drawing_tool.get_annotation_context(target_view, object_type)
if not context: if not context:
@@ -416,17 +418,24 @@ def add_annotation(
obj = drawing_tool.create_annotation_object(drawing, object_type) obj = drawing_tool.create_annotation_object(drawing, object_type)
element = ifc.get_entity(obj) element = ifc.get_entity(obj)
if not element: if not element:
relating_type_rep = drawing_tool.get_annotation_representation(relating_type) if relating_type else None
element = drawing_tool.run_root_assign_class( element = drawing_tool.run_root_assign_class(
obj=obj, obj=obj,
ifc_class="IfcAnnotation", ifc_class="IfcAnnotation",
predefined_type=object_type, predefined_type=object_type,
should_add_representation=True, should_add_representation=not relating_type_rep,
context=context, context=context,
ifc_representation_class=drawing_tool.get_ifc_representation_class(object_type), ifc_representation_class=drawing_tool.get_ifc_representation_class(object_type),
) )
if relating_type:
drawing_tool.run_type_assign_type(element=element, relating_type=relating_type)
ifc.run("group.assign_group", group=drawing_tool.get_drawing_group(drawing), products=[element]) ifc.run("group.assign_group", group=drawing_tool.get_drawing_group(drawing), products=[element])
if representation := drawing_tool.get_representation(element, context):
drawing_tool.reload_representation(obj=obj, representation=representation)
collector.assign(obj, should_clean_users_collection=True) collector.assign(obj, should_clean_users_collection=True)
drawing_tool.enable_editing(obj) if not relating_type_rep and object_type != "IMAGE" and enable_editing:
drawing_tool.enable_editing(obj)
return obj
def build_schedule(drawing: tool.Drawing, schedule: ifcopenshell.entity_instance) -> None: def build_schedule(drawing: tool.Drawing, schedule: ifcopenshell.entity_instance) -> None:
+29 -5
View File
@@ -348,11 +348,15 @@ class Drawing(bonsai.core.tool.Drawing):
@classmethod @classmethod
def enable_editing(cls, obj: bpy.types.Object) -> None: def enable_editing(cls, obj: bpy.types.Object) -> None:
bpy.ops.object.select_all(action="DESELECT") from bonsai.bim.module.geometry.data import ViewportData
bpy.context.view_layer.objects.active = obj
obj.select_set(True) tool.Blender.select_and_activate_single_object(bpy.context, obj)
if obj.data: if not obj.data:
bpy.ops.object.mode_set(mode="EDIT") return
ViewportData.load() # Reload valid modes
bpy.ops.bim.override_mode_set_edit() # Enter item mode
ViewportData.load() # Reload valid modes
bpy.ops.bim.override_mode_set_edit() # Enter edit mode
@classmethod @classmethod
def enable_editing_drawings(cls) -> None: def enable_editing_drawings(cls) -> None:
@@ -988,6 +992,26 @@ class Drawing(bonsai.core.tool.Drawing):
ifc_representation_class=ifc_representation_class, ifc_representation_class=ifc_representation_class,
) )
@classmethod
def run_type_assign_type(cls, element: ifcopenshell.entity_instance, relating_type: ifcopenshell.entity_instance):
return bonsai.core.type.assign_type(tool.Ifc, tool.Type, element=element, type=relating_type)
@classmethod
def reload_representation(cls, obj: bpy.types.Object, representation: ifcopenshell.entity_instance):
return bonsai.core.geometry.switch_representation(
tool.Ifc,
tool.Geometry,
obj=obj,
representation=representation,
should_reload=True,
is_global=True,
should_sync_changes_first=False,
)
@classmethod
def get_representation(cls, element, context):
return ifcopenshell.util.representation.get_representation(element, context)
@classmethod @classmethod
def set_drawing_collection_name( def set_drawing_collection_name(
cls, drawing: ifcopenshell.entity_instance, collection: bpy.types.Collection cls, drawing: ifcopenshell.entity_instance, collection: bpy.types.Collection