From 32e47d03d48656eb84773b1d29bc2784b09ae8d8 Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Fri, 17 Mar 2023 19:00:53 +0500 Subject: [PATCH] IFC text - box alignment in viewport --- .../blenderbim/bim/module/drawing/data.py | 36 +++++---- .../bim/module/drawing/decoration.py | 76 ++++++++++++++----- .../blenderbim/bim/module/drawing/prop.py | 19 +++-- src/blenderbim/blenderbim/tool/drawing.py | 4 +- 4 files changed, 89 insertions(+), 46 deletions(-) diff --git a/src/blenderbim/blenderbim/bim/module/drawing/data.py b/src/blenderbim/blenderbim/bim/module/drawing/data.py index b43fb96bba..9d0dad02ff 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/data.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/data.py @@ -193,7 +193,7 @@ class DecoratorData: return display_data @classmethod - def get_ifc_text_font_size(cls, obj): + def get_ifc_text_data(cls, obj): """returns font size in mm for current ifc text object""" result = cls.data.get(obj.name, None) if result is not None: @@ -203,21 +203,25 @@ class DecoratorData: if not element: return - if obj.BIMTextProperties.is_editing: - font_size = float(obj.BIMTextProperties.font_size) + props = obj.BIMTextProperties + # getting font size + classes = ifcopenshell.util.element.get_pset(element, "EPset_Annotation", "Classes") + # use `regular` as default + if classes: + classes_split = classes.split() + # prioritize smaller font sizes just like in svg + font_size_type = next( + (font_size_type for font_size_type in FONT_SIZES if font_size_type in classes_split), "regular" + ) else: - classes = ifcopenshell.util.element.get_pset(element, "EPset_Annotation", "Classes") + font_size_type = "regular" + font_size = FONT_SIZES[font_size_type] - # use `regular` as default - if classes: - classes_split = classes.split() - # prioritize smaller font sizes just like in svg - font_size_type = next( - (font_size_type for font_size_type in FONT_SIZES if font_size_type in classes_split), "regular" - ) - else: - font_size_type = "regular" + # other attributes + literal = tool.Drawing.get_text_literal(obj) + box_alignment = literal.BoxAlignment + text = props.value - font_size = FONT_SIZES[font_size_type] - cls.data[obj.name] = font_size - return font_size + text_data = {"text": text, "font_size": font_size, "box_alignment": box_alignment} + cls.data[obj.name] = text_data + return text_data diff --git a/src/blenderbim/blenderbim/bim/module/drawing/decoration.py b/src/blenderbim/blenderbim/bim/module/drawing/decoration.py index 059beb22fe..feb43be55c 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/decoration.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/decoration.py @@ -379,7 +379,19 @@ class BaseDecorator: batch.draw(self.shader) - def draw_label(self, context, text, pos, dir, gap=4, center=True, vcenter=False, font_size=2.5, line_no=0): + def draw_label( + self, + context, + text, + pos, + dir, + gap=4, + center=True, + vcenter=False, + font_size_mm=2.5, + line_no=0, + box_alignment=None, + ): """Draw text label Args: @@ -409,26 +421,42 @@ class BaseDecorator: # In particular it works only for the OpenGOST font and produces a 2.5mm font size. # It probably should be dynamically calculated using system.dpi or something. # font_size = 16 <-- this is a good default - font_size = int(0.004118616 * mm_to_px) * font_size / 2.5 - pos = pos - Vector((0, line_no * font_size)) + # TODO: need to synchronize it better with svg + font_size_px = int(0.004118616 * mm_to_px) * font_size_mm / 2.5 + pos = pos - Vector((0, line_no * font_size_px)) - blf.size(font_id, font_size, dpi) + blf.size(font_id, font_size_px, dpi) - w, h = 0, 0 - if center or vcenter: + if box_alignment or center or vcenter: w, h = blf.dimensions(font_id, text) - if center: - # horizontal centering - pos -= Vector((cos, sin)) * w * 0.5 + if box_alignment: + # TODO: need to work out the rotation too + if "bottom" in box_alignment: + pass + elif "top" in box_alignment: + pos -= Vector((0, h)) + else: + pos -= Vector((0, h / 2)) # middle / center - if vcenter: - # vertical centering - pos -= Vector((-sin, cos)) * h * 0.5 + if "left" in box_alignment: + pass + elif "right" in box_alignment: + pos -= Vector((w, 0)) + else: + pos -= Vector((w / 2, 0)) + else: + if center: + # horizontal centering + pos -= Vector((cos, sin)) * w * 0.5 - if gap: - # side-shifting - pos += Vector((-sin, cos)) * gap + if vcenter: + # vertical centering + pos -= Vector((-sin, cos)) * h * 0.5 + + if gap: + # side-shifting + pos += Vector((-sin, cos)) * gap blf.enable(font_id, blf.ROTATION) blf.position(font_id, pos.x, pos.y, 0) if hasattr(pos, "x") else blf.position(font_id, 0, 0, 0) @@ -2072,13 +2100,21 @@ class TextDecorator(BaseDecorator): # TODO: support text rotation dir = Vector((1, 0)) pos = location_3d_to_region_2d(region, region3d, obj.matrix_world.translation) - font_size = DecoratorData.get_ifc_text_font_size(obj) props = obj.BIMTextProperties - text = props.get_text() if props.is_editing else props.value - - for line_i, line in enumerate(text.split("\\n")): + text_data = props.get_text_edited_data() if props.is_editing else DecoratorData.get_ifc_text_data(obj) + box_alignment = text_data["box_alignment"] + for line_i, line in enumerate(text_data["text"].split("\\n")): self.draw_label( - context, line, pos, dir, gap=0, center=False, vcenter=False, font_size=font_size, line_no=line_i + context, + line, + pos, + dir, + gap=0, + center=False, + vcenter=False, + font_size_mm=text_data["font_size"], + line_no=line_i, + box_alignment=box_alignment, ) diff --git a/src/blenderbim/blenderbim/bim/module/drawing/prop.py b/src/blenderbim/blenderbim/bim/module/drawing/prop.py index 7eb077c5aa..d336053656 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/prop.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/prop.py @@ -416,10 +416,6 @@ class BIMTextProperties(PropertyGroup): def get_box_alignment(self): return self.get("box_alignment", DEFAULT_BOX_ALIGNMENT) - def refresh_font_size(self, context): - # force update this object's font size for viewport display - DecoratorData.data.pop(context.object.name, None) - is_editing: BoolProperty(name="Is Editing", default=False) attributes: CollectionProperty(name="Attributes", type=Attribute) test_prop: StringProperty(name="test_prop", default="TEXT") @@ -436,16 +432,23 @@ class BIMTextProperties(PropertyGroup): ("7.0", "7.0 - Title", ""), ], default="2.5", - update=refresh_font_size, name="Font Size", ) box_alignment: BoolVectorProperty( name="Box alignment", size=9, set=set_box_alignment, get=get_box_alignment, default=DEFAULT_BOX_ALIGNMENT ) - def get_text(self): - text_attribute = self.attributes.get("Literal", None) - return text_attribute.string_value if text_attribute else self.text + def get_text_edited_data(self): + """should be called only if `is_editing` + etherwise should use `DecoratorData.get_ifc_text_data(obj)` instead + because this data could be out of date + """ + text_data = { + "text": self.attributes["Literal"].string_value, + "font_size": float(self.font_size), + "box_alignment": self.attributes["BoxAlignment"].string_value, + } + return text_data class BIMAssignedProductProperties(PropertyGroup): diff --git a/src/blenderbim/blenderbim/tool/drawing.py b/src/blenderbim/blenderbim/tool/drawing.py index 9cd08fa05d..3475e32023 100644 --- a/src/blenderbim/blenderbim/tool/drawing.py +++ b/src/blenderbim/blenderbim/tool/drawing.py @@ -465,8 +465,8 @@ class Drawing(blenderbim.core.tool.Drawing): box_alignment_mask[BOX_ALIGNMENT_POSITIONS.index(position_string)] = True props.box_alignment = box_alignment_mask - font_size = DecoratorData.get_ifc_text_font_size(obj) - props.font_size = str(font_size) + text_data = DecoratorData.get_ifc_text_data(obj) + props.font_size = str(text_data["font_size"]) @classmethod def import_assigned_product(cls, obj):