Annotation Tool

Added Annotation Tool that allows you create annotation types and their occurences. It will also allow us to get rid of "Annotation" panel in N-panel.

I've recorded bunch of short videos to demonstrate the features:

- bulk tagging - currently works only for "Text" and "Stair arrow" type of annotations, adds annotations to all selected objects, automatically assigns products to the annotations
https://user-images.githubusercontent.com/9417531/231968358-28cbb762-3349-470a-beef-d1ab21882769.mp4

- creating annotation type with representation - all occurences will share the same representation which makes bulk tagging really powerful if you use variables like {{PredefinedType}}, {{GlobalId}}, {{Name}}, {{Description}}, {{ObjectType}}, {{Tag}}

https://user-images.githubusercontent.com/9417531/231970500-333514c6-6406-4ef5-a9e7-fddfcc9a2436.mp4

- creating annotation type without representation - it allows occurences to have unique text or line geometry but still share the same classes from inherited property set

Examples:
  creating text type without representation to create title case annotations
  https://user-images.githubusercontent.com/9417531/231969361-bda5f924-a8c8-4f5a-ba61-461aa7101f73.mp4

  creating type for oblique dimension annotations
  https://user-images.githubusercontent.com/9417531/231969902-38e8c3f4-45a6-4c98-bba4-2956288ce10a.mp4

- readjusting - if you created some annotations using bulk tagging but the products were changed / moved afterwards now you can select those annotations and "readjust" them according to new product's position / measurements
https://user-images.githubusercontent.com/9417531/231968975-ee8d6589-60ee-4575-9be2-b0ce68d43ffa.mp4

PS In this commit I've also moved all icons to 1 .blend file and added instructions how to regenerate them.
This commit is contained in:
Andrej730
2023-04-10 14:02:50 +05:00
parent 01a4d64419
commit fcdfa5dd23
16 changed files with 501 additions and 45 deletions
+81 -23
View File
@@ -40,6 +40,7 @@ from blenderbim.bim.module.drawing.data import FONT_SIZES, DecoratorData
from blenderbim.bim.module.drawing.prop import get_diagram_scales, BOX_ALIGNMENT_POSITIONS
from mathutils import Vector
import collections
class Drawing(blenderbim.core.tool.Drawing):
@@ -80,8 +81,28 @@ class Drawing(blenderbim.core.tool.Drawing):
return obj
# TODO: add a way for users to run this method to readjust the annotations
# based on non-modifier stairs
@classmethod
def ensure_annotation_in_drawing_plane(cls, obj, camera=None):
"""Make sure annotation object is going to be visible in the camera view"""
def get_camera_from_annotation_object(obj):
entity = tool.Ifc.get_entity(obj)
if not entity:
return
for rel in entity.HasAssignments:
if rel.is_a("IfcRelAssignsToGroup"):
for e in rel.RelatedObjects:
if e.ObjectType == "DRAWING":
return tool.Ifc.get_object(e)
if not camera:
camera = get_camera_from_annotation_object(obj) or bpy.context.scene.camera
current_pos = camera.matrix_world.inverted() @ obj.location
current_pos.z = -camera.data.clip_start
current_pos = camera.matrix_world @ current_pos
obj.location = current_pos
@classmethod
def setup_annotation_object(cls, obj, object_type, related_object=None):
"""Finish object's adjustments after both object and entity are created"""
@@ -89,27 +110,70 @@ class Drawing(blenderbim.core.tool.Drawing):
if not related_object:
related_object = bpy.context.active_object
related_entity = tool.Ifc.get_entity(related_object)
if not related_entity:
return
obj_entity = tool.Ifc.get_entity(obj)
assign_product = False
if object_type == "STAIR_ARROW":
if related_entity and related_entity.is_a("IfcStairFlight"):
stair, stair_entity = related_object, related_entity
arrow = obj
arrow_element = tool.Ifc.get_entity(arrow)
arrow.parent = stair
if related_entity.is_a("IfcStairFlight"):
stair, arrow = related_object, obj
# place the arrow
# NOTE: may not work correctly in EDIT mode
bbox = tool.Blender.get_object_bounding_box(stair)
float_is_zero = lambda f: 0.0001 >= f >= -0.0001
arrow.location = Vector((bbox["min_x"], (bbox["max_y"] - bbox["min_y"]) / 2, bbox["max_z"]))
arrow.location = stair.matrix_world @ Vector(
(bbox["min_x"], (bbox["max_y"] - bbox["min_y"]) / 2, bbox["max_z"])
)
last_step_x = max(v.co.x for v in stair.data.vertices if float_is_zero(v.co.z - bbox["max_z"]))
arrow.data.splines[0].points[0].co = Vector((0, 0, 0, 1))
arrow.data.splines[0].points[1].co = Vector((last_step_x, 0, 0, 1))
if not cls.get_assigned_product(arrow_element):
tool.Ifc.run("drawing.assign_product", relating_product=stair_entity, related_object=arrow_element)
pass
cls.ensure_annotation_in_drawing_plane(obj)
assign_product = True
elif object_type == "TEXT":
bbox = tool.Blender.get_object_bounding_box(related_object)
obj.location = related_object.matrix_world @ bbox["center"]
cls.ensure_annotation_in_drawing_plane(obj)
assign_product = True
if assign_product and not cls.get_assigned_product(obj_entity):
tool.Ifc.run("drawing.assign_product", relating_product=related_entity, related_object=obj_entity)
if object_type == "TEXT":
tool.Drawing.update_text_value(obj)
@classmethod
def is_annotation_object_type(cls, element, object_types):
if not isinstance(object_types, collections.abc.Iterable):
object_types = [object_types]
element_type = element.is_a()
if element_type == "IfcAnnotation" and element.ObjectType in object_types:
return True
if element_type == "IfcTypeProduct" and element.ApplicableOccurrence.startswith("IfcAnnotation/"):
applicable_object_type = element.ApplicableOccurrence.split("/")[1]
if applicable_object_type in object_types:
return True
return False
@classmethod
def get_annotation_representation(cls, element):
rep = ifcopenshell.util.representation.get_representation(
element, "Plan", "Annotation"
) or ifcopenshell.util.representation.get_representation(element, "Model", "Annotation")
if not rep:
return None
rep = tool.Geometry.resolve_mapped_representation(rep)
return rep
@classmethod
def create_camera(cls, name, matrix):
@@ -376,13 +440,11 @@ class Drawing(blenderbim.core.tool.Drawing):
element = tool.Ifc.get_entity(obj)
if not element:
return
rep = ifcopenshell.util.representation.get_representation(
element, "Plan", "Annotation"
) or ifcopenshell.util.representation.get_representation(element, "Model", "Annotation")
rep = cls.get_annotation_representation(element)
if not rep:
return
items = [i for i in rep.Items if i.is_a("IfcTextLiteral")]
return [] if return_list else None
items = [i for i in rep.Items if i.is_a("IfcTextLiteral")]
if not items:
return [] if return_list else None
if return_list:
@@ -395,9 +457,7 @@ class Drawing(blenderbim.core.tool.Drawing):
if not element:
return
rep = ifcopenshell.util.representation.get_representation(
element, "Plan", "Annotation"
) or ifcopenshell.util.representation.get_representation(element, "Model", "Annotation")
rep = cls.get_annotation_representation(element)
if not rep:
return
@@ -435,9 +495,7 @@ class Drawing(blenderbim.core.tool.Drawing):
if not element:
return
rep = ifcopenshell.util.representation.get_representation(
element, "Plan", "Annotation"
) or ifcopenshell.util.representation.get_representation(element, "Model", "Annotation")
rep = cls.get_annotation_representation(element)
if not rep:
return