Support cells text alignment building schedule from ods #2885

Before - https://i.imgur.com/9QZ2YW2.png
After - https://i.imgur.com/M7ZHSJq.png
This commit is contained in:
Andrej730
2023-05-02 16:59:26 +05:00
parent f858dd14d9
commit 9f19b33764
2 changed files with 80 additions and 30 deletions
@@ -16,6 +16,7 @@
# You should have received a copy of the GNU General Public License
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
from blenderbim.bim.module.drawing.svgwriter import SvgWriter
import svgwrite
from odf.opendocument import load
@@ -25,6 +26,7 @@ from odf.style import Style
FONT_SIZE = 4.13
class Scheduler:
def schedule(self, infile, outfile):
self.svg = svgwrite.Drawing(
@@ -41,7 +43,16 @@ class Scheduler:
# looking for table-column-properties or table-row-properties
if not style.firstChild:
continue
styles[name] = {key[1]: value for key, value in style.firstChild.attributes.items()}
if style.firstChild.tagName in ["style:table-column-properties", "style:table-row-properties"]:
style_children = [style.firstChild]
else:
# for style:table-cell-properties we need to collect also text and paragraph properties
style_children = style.childNodes
styles[name] = {}
for child in style_children:
child_params = {key[1]: value for key, value in child.attributes.items()}
styles[name].update(child_params)
table = doc.getElementsByType(Table)[0]
@@ -77,7 +88,7 @@ class Scheduler:
x = self.margin
height = row_heights[tri]
tdi = 0
for td in tr.getElementsByType(TableCell):
column_span = td.getAttribute("numbercolumnsspanned")
column_span = int(column_span) if column_span else 1
@@ -85,8 +96,35 @@ class Scheduler:
repeat = td.getAttribute("numbercolumnsrepeated")
repeat = int(repeat) if repeat else 1
# figuring text alignment
style_name = td.getAttribute("stylename")
if (
style_name
and "vertical-align" in styles[style_name]
and styles[style_name]["vertical-align"] != "automatic"
):
vertical_align = styles[style_name]["vertical-align"]
else:
vertical_align = "bottom"
if (
style_name
and "text-align" in styles[style_name]
and styles[style_name]["text-align"] != "automatic"
):
horizontal_align = styles[style_name]["text-align"]
horizontal_align = "middle" if horizontal_align == "center" else horizontal_align
else:
horizontal_align = "left"
if vertical_align == "middle" and horizontal_align == "middle":
box_alignment = "center"
else:
box_alignment = f"{vertical_align}-{horizontal_align}"
# drawing cells and text
for i in range(0, repeat):
width = sum(column_widths[tdi:tdi + int(column_span)])
width = sum(column_widths[tdi : tdi + int(column_span)])
self.svg.add(
self.svg.rect(
insert=(x, y),
@@ -96,7 +134,23 @@ class Scheduler:
)
value = td.getElementsByType(P)
if value:
self.add_text(value[0], x + self.padding, y + height - self.padding)
# figuring text position based on alignment
text_position = [0, 0]
if box_alignment.endswith("left"):
text_position[0] = x + self.padding
elif box_alignment.endswith("middle") or box_alignment == "center":
text_position[0] = x + width / 2
elif box_alignment.endswith("right"):
text_position[0] = x + width - self.padding
if box_alignment.startswith("top"):
text_position[1] = y + self.padding
elif box_alignment == "center":
text_position[1] = y + height / 2
elif box_alignment.startswith("bottom"):
text_position[1] = y + height - self.padding
self.add_text(value[0], *text_position, box_alignment=box_alignment)
x += width
tdi += column_span
@@ -107,21 +161,16 @@ class Scheduler:
self.svg["viewBox"] = "0 0 {} {}".format(total_width, y)
self.svg.save(pretty=True)
def add_text(self, text, x, y):
bottom_left_alignment = {
"alignment-baseline": "baseline",
"dominant-baseline": "baseline",
def add_text(self, text, x, y, box_alignment="bottom-left"):
box_alignment_params = SvgWriter.get_box_alignment_parameters(box_alignment)
text_params = {
"font-size": FONT_SIZE,
"font-family": "OpenGost Type B TT",
"text-anchor": "start",
}
text_tag = self.svg.text(
str(text).upper(),
insert=tuple((x, y)),
**({
"font-size": FONT_SIZE,
"font-family": "OpenGost Type B TT",
"text-anchor": "start",
} | bottom_left_alignment)
)
self.svg.add(text_tag)
text_params.update(box_alignment_params)
text_tag = self.svg.text(str(text).upper(), insert=tuple((x, y)), **text_params)
self.svg.add(text_tag)
def convert_to_mm(self, value):
# XSL is what defines the units of measurements in ODF
@@ -234,7 +234,7 @@ class SvgWriter:
rl = ifcopenshell.util.geolocation.auto_z2e(tool.Ifc.get(), rl)
rl *= unit_scale
rl = "{:.3f}m".format(rl)
text_style = self.get_box_alignment_parameters("bottom-left")
text_style = SvgWriter.get_box_alignment_parameters("bottom-left")
self.svg.add(self.svg.text(f"RL +{rl}", insert=tuple(text_position), class_="SECTIONLEVEL", **text_style))
if tag:
self.svg.add(self.svg.text(tag, insert=(text_position[0], text_position[1] - 5), **text_style))
@@ -263,7 +263,7 @@ class SvgWriter:
"UP",
insert=tuple(text_position),
class_="STAIR",
**self.get_box_alignment_parameters("center"),
**SvgWriter.get_box_alignment_parameters("center"),
)
)
@@ -287,7 +287,7 @@ class SvgWriter:
)
line["stroke-dasharray"] = "12.5, 3, 3, 3"
axis_tag = tool.Ifc.get_entity(obj).Name
text_style = self.get_box_alignment_parameters("center")
text_style = SvgWriter.get_box_alignment_parameters("center")
self.svg.add(
self.svg.text(
axis_tag,
@@ -557,7 +557,7 @@ class SvgWriter:
reference_id, sheet_id = self.get_reference_and_sheet_id_from_annotation(tool.Ifc.get_entity(obj))
text_position = symbol_position_svg
text_style = self.get_box_alignment_parameters("center")
text_style = SvgWriter.get_box_alignment_parameters("center")
self.svg.add(
self.svg.text(
reference_id,
@@ -590,7 +590,7 @@ class SvgWriter:
reference_id, sheet_id = self.get_reference_and_sheet_id_from_annotation(tool.Ifc.get_entity(obj))
text_position = symbol_position_svg
text_style = self.get_box_alignment_parameters("center")
text_style = SvgWriter.get_box_alignment_parameters("center")
self.svg.add(
self.svg.text(
reference_id, insert=(text_position[0], text_position[1] - 2.5), class_="ELEVATION", **text_style
@@ -617,7 +617,8 @@ class SvgWriter:
return (reference_id, sheet_id)
return ("-", "-")
def get_box_alignment_parameters(self, box_alignment):
@staticmethod
def get_box_alignment_parameters(box_alignment):
"""Convenience method to get svg parameters for text alignment
in a readable way.
@@ -721,7 +722,7 @@ class SvgWriter:
text_tag = self.svg.text(
"",
**(attribs | {"filter": "url(#fill-background)"}) if add_fill_bg else attribs,
**self.get_box_alignment_parameters(text_literal.BoxAlignment),
**SvgWriter.get_box_alignment_parameters(text_literal.BoxAlignment),
)
self.svg.add(text_tag)
@@ -795,7 +796,7 @@ class SvgWriter:
rl = "{:.3f}m".format(rl)
box_alignment = "bottom-left" if projected_points[0].x <= projected_points[-1].x else "bottom-right"
text_style = self.get_box_alignment_parameters(box_alignment)
text_style = SvgWriter.get_box_alignment_parameters(box_alignment)
self.svg.add(
self.svg.text(
"RL +{}".format(rl),
@@ -917,7 +918,7 @@ class SvgWriter:
text_offset = (text_position - center_position).xy.normalized() * 5
text_position += text_offset
text_style = self.get_box_alignment_parameters("center")
text_style = SvgWriter.get_box_alignment_parameters("center")
angle_text = abs(round(math.degrees(angle), 3))
if is_reflex:
angle_text = 360 - angle_text
@@ -978,7 +979,7 @@ class SvgWriter:
)
text_position += text_offset
text_style = self.get_box_alignment_parameters("center")
text_style = SvgWriter.get_box_alignment_parameters("center")
radius = (points[-1].co - points[-2].co).length
radius = helper.format_distance(radius, precision=self.precision, decimal_places=self.decimal_places)
tag = element.Description or f"R{radius}"
@@ -1051,7 +1052,7 @@ class SvgWriter:
)
text_position += text_offset
text_style = self.get_box_alignment_parameters("center")
text_style = SvgWriter.get_box_alignment_parameters("center")
self.svg.add(self.svg.text(tag, insert=tuple(text_position), class_="RADIUS", **text_style))
def draw_diameter_annotations(self, obj):
@@ -1151,7 +1152,7 @@ class SvgWriter:
text_format(text),
insert=text_position,
class_="DIMENSION",
**(text_kwargs | self.get_box_alignment_parameters(box_alignment)),
**(text_kwargs | SvgWriter.get_box_alignment_parameters(box_alignment)),
)
if not show_description_only: