mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-19 06:39:13 +00:00
IFC text - box alignment in viewport
This commit is contained in:
@@ -193,7 +193,7 @@ class DecoratorData:
|
|||||||
return display_data
|
return display_data
|
||||||
|
|
||||||
@classmethod
|
@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"""
|
"""returns font size in mm for current ifc text object"""
|
||||||
result = cls.data.get(obj.name, None)
|
result = cls.data.get(obj.name, None)
|
||||||
if result is not None:
|
if result is not None:
|
||||||
@@ -203,21 +203,25 @@ class DecoratorData:
|
|||||||
if not element:
|
if not element:
|
||||||
return
|
return
|
||||||
|
|
||||||
if obj.BIMTextProperties.is_editing:
|
props = obj.BIMTextProperties
|
||||||
font_size = float(obj.BIMTextProperties.font_size)
|
# 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:
|
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
|
# other attributes
|
||||||
if classes:
|
literal = tool.Drawing.get_text_literal(obj)
|
||||||
classes_split = classes.split()
|
box_alignment = literal.BoxAlignment
|
||||||
# prioritize smaller font sizes just like in svg
|
text = props.value
|
||||||
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"
|
|
||||||
|
|
||||||
font_size = FONT_SIZES[font_size_type]
|
text_data = {"text": text, "font_size": font_size, "box_alignment": box_alignment}
|
||||||
cls.data[obj.name] = font_size
|
cls.data[obj.name] = text_data
|
||||||
return font_size
|
return text_data
|
||||||
|
|||||||
@@ -379,7 +379,19 @@ class BaseDecorator:
|
|||||||
|
|
||||||
batch.draw(self.shader)
|
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
|
"""Draw text label
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -409,26 +421,42 @@ class BaseDecorator:
|
|||||||
# In particular it works only for the OpenGOST font and produces a 2.5mm font size.
|
# 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.
|
# It probably should be dynamically calculated using system.dpi or something.
|
||||||
# font_size = 16 <-- this is a good default
|
# font_size = 16 <-- this is a good default
|
||||||
font_size = int(0.004118616 * mm_to_px) * font_size / 2.5
|
# TODO: need to synchronize it better with svg
|
||||||
pos = pos - Vector((0, line_no * font_size))
|
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 box_alignment or center or vcenter:
|
||||||
if center or vcenter:
|
|
||||||
w, h = blf.dimensions(font_id, text)
|
w, h = blf.dimensions(font_id, text)
|
||||||
|
|
||||||
if center:
|
if box_alignment:
|
||||||
# horizontal centering
|
# TODO: need to work out the rotation too
|
||||||
pos -= Vector((cos, sin)) * w * 0.5
|
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:
|
if "left" in box_alignment:
|
||||||
# vertical centering
|
pass
|
||||||
pos -= Vector((-sin, cos)) * h * 0.5
|
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:
|
if vcenter:
|
||||||
# side-shifting
|
# vertical centering
|
||||||
pos += Vector((-sin, cos)) * gap
|
pos -= Vector((-sin, cos)) * h * 0.5
|
||||||
|
|
||||||
|
if gap:
|
||||||
|
# side-shifting
|
||||||
|
pos += Vector((-sin, cos)) * gap
|
||||||
|
|
||||||
blf.enable(font_id, blf.ROTATION)
|
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)
|
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
|
# TODO: support text rotation
|
||||||
dir = Vector((1, 0))
|
dir = Vector((1, 0))
|
||||||
pos = location_3d_to_region_2d(region, region3d, obj.matrix_world.translation)
|
pos = location_3d_to_region_2d(region, region3d, obj.matrix_world.translation)
|
||||||
font_size = DecoratorData.get_ifc_text_font_size(obj)
|
|
||||||
props = obj.BIMTextProperties
|
props = obj.BIMTextProperties
|
||||||
text = props.get_text() if props.is_editing else props.value
|
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.split("\\n")):
|
for line_i, line in enumerate(text_data["text"].split("\\n")):
|
||||||
self.draw_label(
|
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,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -416,10 +416,6 @@ class BIMTextProperties(PropertyGroup):
|
|||||||
def get_box_alignment(self):
|
def get_box_alignment(self):
|
||||||
return self.get("box_alignment", DEFAULT_BOX_ALIGNMENT)
|
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)
|
is_editing: BoolProperty(name="Is Editing", default=False)
|
||||||
attributes: CollectionProperty(name="Attributes", type=Attribute)
|
attributes: CollectionProperty(name="Attributes", type=Attribute)
|
||||||
test_prop: StringProperty(name="test_prop", default="TEXT")
|
test_prop: StringProperty(name="test_prop", default="TEXT")
|
||||||
@@ -436,16 +432,23 @@ class BIMTextProperties(PropertyGroup):
|
|||||||
("7.0", "7.0 - Title", ""),
|
("7.0", "7.0 - Title", ""),
|
||||||
],
|
],
|
||||||
default="2.5",
|
default="2.5",
|
||||||
update=refresh_font_size,
|
|
||||||
name="Font Size",
|
name="Font Size",
|
||||||
)
|
)
|
||||||
box_alignment: BoolVectorProperty(
|
box_alignment: BoolVectorProperty(
|
||||||
name="Box alignment", size=9, set=set_box_alignment, get=get_box_alignment, default=DEFAULT_BOX_ALIGNMENT
|
name="Box alignment", size=9, set=set_box_alignment, get=get_box_alignment, default=DEFAULT_BOX_ALIGNMENT
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_text(self):
|
def get_text_edited_data(self):
|
||||||
text_attribute = self.attributes.get("Literal", None)
|
"""should be called only if `is_editing`
|
||||||
return text_attribute.string_value if text_attribute else self.text
|
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):
|
class BIMAssignedProductProperties(PropertyGroup):
|
||||||
|
|||||||
@@ -465,8 +465,8 @@ class Drawing(blenderbim.core.tool.Drawing):
|
|||||||
box_alignment_mask[BOX_ALIGNMENT_POSITIONS.index(position_string)] = True
|
box_alignment_mask[BOX_ALIGNMENT_POSITIONS.index(position_string)] = True
|
||||||
props.box_alignment = box_alignment_mask
|
props.box_alignment = box_alignment_mask
|
||||||
|
|
||||||
font_size = DecoratorData.get_ifc_text_font_size(obj)
|
text_data = DecoratorData.get_ifc_text_data(obj)
|
||||||
props.font_size = str(font_size)
|
props.font_size = str(text_data["font_size"])
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def import_assigned_product(cls, obj):
|
def import_assigned_product(cls, obj):
|
||||||
|
|||||||
Reference in New Issue
Block a user