mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 09:48:32 +00:00
Multiline in dimension description / suffix / prefix #3005
Also added some offset for dimension text in viewport to make it more similar to svg
This commit is contained in:
@@ -377,17 +377,42 @@ class BaseDecorator:
|
||||
font_size_mm=2.5,
|
||||
line_no=0,
|
||||
box_alignment=None,
|
||||
multiline=False,
|
||||
multiline_to_bottom=True,
|
||||
):
|
||||
"""Draw text label
|
||||
|
||||
Args:
|
||||
pos: bottom-center
|
||||
multiline: \n characters will be interpreted as line breaks
|
||||
|
||||
aligned and centered at segment middle
|
||||
|
||||
NOTE: `blf.draw` seems to ignore the \n character, so we have to split the text ourselves
|
||||
and use the `line_no` argument of `draw_label`
|
||||
|
||||
"""
|
||||
|
||||
if multiline:
|
||||
line_no = 0
|
||||
lines = text.split("\\n")
|
||||
lines = lines if multiline_to_bottom else lines[::-1]
|
||||
for line in lines:
|
||||
self.draw_label(
|
||||
context,
|
||||
line,
|
||||
pos,
|
||||
text_dir,
|
||||
gap=gap,
|
||||
center=center,
|
||||
vcenter=vcenter,
|
||||
font_size_mm=font_size_mm,
|
||||
line_no=line_no,
|
||||
box_alignment=box_alignment,
|
||||
)
|
||||
line_no += 1 if multiline_to_bottom else -1
|
||||
return
|
||||
|
||||
# 0 is the default font, but we're fancier than that
|
||||
font_id = self.font_id
|
||||
|
||||
@@ -492,7 +517,7 @@ class BaseDecorator:
|
||||
start_i = add_verts_sequence(add_offsets(v0, segment), start_i, **out_kwargs)
|
||||
self.draw_lines(context, obj, output_verts, output_edges)
|
||||
|
||||
def draw_text(self, context, obj, text_world_position=None):
|
||||
def draw_text(self, context, obj, text_world_position=None, reverse_lines_order=False):
|
||||
"""if `text_world_position` is not provided, the object's location will be used"""
|
||||
if not text_world_position:
|
||||
text_world_position = obj.location
|
||||
@@ -522,6 +547,7 @@ class BaseDecorator:
|
||||
text_scale = obj.scale.x
|
||||
|
||||
line_i = 0
|
||||
font_size_mm = text_data["FontSize"] * text_scale
|
||||
for literal_data in literals_data:
|
||||
box_alignment = literal_data["BoxAlignment"]
|
||||
|
||||
@@ -534,11 +560,11 @@ class BaseDecorator:
|
||||
gap=0,
|
||||
center=False,
|
||||
vcenter=False,
|
||||
font_size_mm=text_data["FontSize"] * text_scale,
|
||||
font_size_mm=font_size_mm,
|
||||
line_no=line_i,
|
||||
box_alignment=box_alignment,
|
||||
)
|
||||
line_i += 1
|
||||
line_i += 1 if not reverse_lines_order else -1
|
||||
|
||||
|
||||
class DimensionDecorator(BaseDecorator):
|
||||
@@ -624,6 +650,8 @@ class DimensionDecorator(BaseDecorator):
|
||||
show_description_only = dimension_data["show_description_only"]
|
||||
text_prefix = dimension_data["text_prefix"]
|
||||
text_suffix = dimension_data["text_suffix"]
|
||||
viewportDrawingScale = self.get_viewport_drawing_scale(context)
|
||||
text_offset_value = viewportDrawingScale * 3
|
||||
|
||||
for i0, i1 in indices:
|
||||
v0 = Vector(vertices[i0])
|
||||
@@ -633,6 +661,8 @@ class DimensionDecorator(BaseDecorator):
|
||||
text_dir = p1 - p0
|
||||
if text_dir.length < 1:
|
||||
continue
|
||||
perpendicular = Vector((-text_dir.y, text_dir.x)).normalized()
|
||||
text_offset = perpendicular * text_offset_value
|
||||
|
||||
if not show_description_only:
|
||||
length = (v1 - v0).length
|
||||
@@ -641,12 +671,35 @@ class DimensionDecorator(BaseDecorator):
|
||||
text = self.format_value(context, length)
|
||||
text = text_prefix + text + text_suffix
|
||||
|
||||
self.draw_label(context, text, p0 + text_dir * 0.5, text_dir, box_alignment="bottom-middle")
|
||||
self.draw_label(
|
||||
context,
|
||||
text,
|
||||
p0 + text_dir * 0.5 + text_offset,
|
||||
text_dir,
|
||||
box_alignment="bottom-middle",
|
||||
multiline=True,
|
||||
multiline_to_bottom=False,
|
||||
)
|
||||
if description:
|
||||
self.draw_label(context, description, p0 + text_dir * 0.5, text_dir, box_alignment="top-middle")
|
||||
self.draw_label(
|
||||
context,
|
||||
description,
|
||||
p0 + text_dir * 0.5 - text_offset,
|
||||
text_dir,
|
||||
box_alignment="top-middle",
|
||||
multiline=True,
|
||||
)
|
||||
|
||||
elif show_description_only and description:
|
||||
self.draw_label(context, description, p0 + text_dir * 0.5, text_dir, box_alignment="bottom-middle")
|
||||
self.draw_label(
|
||||
context,
|
||||
description,
|
||||
p0 + text_dir * 0.5 + text_offset,
|
||||
text_dir,
|
||||
box_alignment="bottom-middle",
|
||||
multiline=True,
|
||||
multiline_to_bottom=False,
|
||||
)
|
||||
|
||||
|
||||
class AngleDecorator(BaseDecorator):
|
||||
|
||||
@@ -1149,28 +1149,86 @@ class SvgWriter:
|
||||
|
||||
# if annotation can't fit offset text to the right of marker
|
||||
text_position = mid if sheet_dimension > 5 else (end + (3 * vector.normalized()))
|
||||
rotation = math.degrees(vector.angle_signed(Vector((1, 0))))
|
||||
angle = math.degrees(vector.angle_signed(Vector((1, 0))))
|
||||
|
||||
line = self.svg.line(start=start, end=end, class_=" ".join(classes))
|
||||
self.svg.add(line)
|
||||
|
||||
def create_text_tag(text, text_position, box_alignment):
|
||||
text_kwargs = {"transform": "rotate({} {} {})".format(rotation, text_position.x, text_position.y)}
|
||||
if not show_description_only:
|
||||
text = f"{text_prefix}{str(dimension)}{text_suffix}"
|
||||
text_tag = self.create_text_tag(
|
||||
text,
|
||||
text_position + perpendicular,
|
||||
angle,
|
||||
"bottom-middle",
|
||||
"DIMENSION",
|
||||
text_format=text_format,
|
||||
multiline=True,
|
||||
multiline_to_bottom=False,
|
||||
)
|
||||
self.svg.add(text_tag)
|
||||
if dimension_text:
|
||||
text_tag = self.create_text_tag(
|
||||
dimension_text,
|
||||
text_position - perpendicular,
|
||||
angle,
|
||||
"top-middle",
|
||||
"DIMENSION",
|
||||
text_format=text_format,
|
||||
multiline=True,
|
||||
multiline_to_bottom=True,
|
||||
)
|
||||
self.svg.add(text_tag)
|
||||
|
||||
elif show_description_only and dimension_text:
|
||||
text_tag = self.create_text_tag(
|
||||
dimension_text,
|
||||
text_position + perpendicular,
|
||||
angle,
|
||||
"bottom-middle",
|
||||
"DIMENSION",
|
||||
text_format=text_format,
|
||||
multiline=True,
|
||||
multiline_to_bottom=False,
|
||||
)
|
||||
self.svg.add(text_tag)
|
||||
|
||||
def create_text_tag(
|
||||
self,
|
||||
text,
|
||||
text_position,
|
||||
angle,
|
||||
box_alignment,
|
||||
class_str,
|
||||
text_format=lambda x: x,
|
||||
multiline=False,
|
||||
multiline_to_bottom=False,
|
||||
):
|
||||
if not multiline:
|
||||
text_kwargs = {"transform": "rotate({} {} {})".format(angle, text_position.x, text_position.y)}
|
||||
return self.svg.text(
|
||||
text_format(text),
|
||||
insert=text_position,
|
||||
class_="DIMENSION",
|
||||
class_=class_str,
|
||||
**(text_kwargs | SvgWriter.get_box_alignment_parameters(box_alignment)),
|
||||
)
|
||||
|
||||
if not show_description_only:
|
||||
text = f"{text_prefix}{str(dimension)}{text_suffix}"
|
||||
self.svg.add(create_text_tag(text, text_position + perpendicular, "bottom-middle"))
|
||||
if dimension_text:
|
||||
self.svg.add(create_text_tag(dimension_text, text_position - perpendicular, "top-middle"))
|
||||
text_position_svg_str = ", ".join(map(str, text_position))
|
||||
text_transform = f"translate({text_position_svg_str}) rotate({angle})"
|
||||
text_kwargs = {
|
||||
"transform": text_transform,
|
||||
"style": "font-size: 0;",
|
||||
}
|
||||
|
||||
elif show_description_only and dimension_text:
|
||||
self.svg.add(create_text_tag(dimension_text, text_position + perpendicular, "bottom-middle"))
|
||||
text_tag = self.svg.text("", **text_kwargs, **SvgWriter.get_box_alignment_parameters(box_alignment))
|
||||
text_lines = text.replace("\\n", "\n").split("\n")
|
||||
text_lines = text_lines if multiline_to_bottom else text_lines[::-1]
|
||||
|
||||
for line_number, text_line in enumerate(text_lines):
|
||||
tspan = self.svg.tspan(text_format(text_line), class_=class_str, insert=(0, 0))
|
||||
tspan.update({"dy": f"{line_number if multiline_to_bottom else -line_number}em"})
|
||||
text_tag.add(tspan)
|
||||
return text_tag
|
||||
|
||||
def project_point_onto_camera(self, point):
|
||||
# TODO is this needlessly complex?
|
||||
|
||||
Reference in New Issue
Block a user