mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-16 13:46:54 +00:00
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:
@@ -16,6 +16,7 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# 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/>.
|
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from blenderbim.bim.module.drawing.svgwriter import SvgWriter
|
||||||
import svgwrite
|
import svgwrite
|
||||||
|
|
||||||
from odf.opendocument import load
|
from odf.opendocument import load
|
||||||
@@ -25,6 +26,7 @@ from odf.style import Style
|
|||||||
|
|
||||||
FONT_SIZE = 4.13
|
FONT_SIZE = 4.13
|
||||||
|
|
||||||
|
|
||||||
class Scheduler:
|
class Scheduler:
|
||||||
def schedule(self, infile, outfile):
|
def schedule(self, infile, outfile):
|
||||||
self.svg = svgwrite.Drawing(
|
self.svg = svgwrite.Drawing(
|
||||||
@@ -41,7 +43,16 @@ class Scheduler:
|
|||||||
# looking for table-column-properties or table-row-properties
|
# looking for table-column-properties or table-row-properties
|
||||||
if not style.firstChild:
|
if not style.firstChild:
|
||||||
continue
|
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]
|
table = doc.getElementsByType(Table)[0]
|
||||||
|
|
||||||
@@ -85,8 +96,35 @@ class Scheduler:
|
|||||||
repeat = td.getAttribute("numbercolumnsrepeated")
|
repeat = td.getAttribute("numbercolumnsrepeated")
|
||||||
repeat = int(repeat) if repeat else 1
|
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):
|
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.add(
|
||||||
self.svg.rect(
|
self.svg.rect(
|
||||||
insert=(x, y),
|
insert=(x, y),
|
||||||
@@ -96,7 +134,23 @@ class Scheduler:
|
|||||||
)
|
)
|
||||||
value = td.getElementsByType(P)
|
value = td.getElementsByType(P)
|
||||||
if value:
|
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
|
x += width
|
||||||
tdi += column_span
|
tdi += column_span
|
||||||
|
|
||||||
@@ -107,20 +161,15 @@ class Scheduler:
|
|||||||
self.svg["viewBox"] = "0 0 {} {}".format(total_width, y)
|
self.svg["viewBox"] = "0 0 {} {}".format(total_width, y)
|
||||||
self.svg.save(pretty=True)
|
self.svg.save(pretty=True)
|
||||||
|
|
||||||
def add_text(self, text, x, y):
|
def add_text(self, text, x, y, box_alignment="bottom-left"):
|
||||||
bottom_left_alignment = {
|
box_alignment_params = SvgWriter.get_box_alignment_parameters(box_alignment)
|
||||||
"alignment-baseline": "baseline",
|
text_params = {
|
||||||
"dominant-baseline": "baseline",
|
"font-size": FONT_SIZE,
|
||||||
|
"font-family": "OpenGost Type B TT",
|
||||||
|
"text-anchor": "start",
|
||||||
}
|
}
|
||||||
text_tag = self.svg.text(
|
text_params.update(box_alignment_params)
|
||||||
str(text).upper(),
|
text_tag = self.svg.text(str(text).upper(), insert=tuple((x, y)), **text_params)
|
||||||
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)
|
self.svg.add(text_tag)
|
||||||
|
|
||||||
def convert_to_mm(self, value):
|
def convert_to_mm(self, value):
|
||||||
|
|||||||
@@ -234,7 +234,7 @@ class SvgWriter:
|
|||||||
rl = ifcopenshell.util.geolocation.auto_z2e(tool.Ifc.get(), rl)
|
rl = ifcopenshell.util.geolocation.auto_z2e(tool.Ifc.get(), rl)
|
||||||
rl *= unit_scale
|
rl *= unit_scale
|
||||||
rl = "{:.3f}m".format(rl)
|
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))
|
self.svg.add(self.svg.text(f"RL +{rl}", insert=tuple(text_position), class_="SECTIONLEVEL", **text_style))
|
||||||
if tag:
|
if tag:
|
||||||
self.svg.add(self.svg.text(tag, insert=(text_position[0], text_position[1] - 5), **text_style))
|
self.svg.add(self.svg.text(tag, insert=(text_position[0], text_position[1] - 5), **text_style))
|
||||||
@@ -263,7 +263,7 @@ class SvgWriter:
|
|||||||
"UP",
|
"UP",
|
||||||
insert=tuple(text_position),
|
insert=tuple(text_position),
|
||||||
class_="STAIR",
|
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"
|
line["stroke-dasharray"] = "12.5, 3, 3, 3"
|
||||||
axis_tag = tool.Ifc.get_entity(obj).Name
|
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.add(
|
||||||
self.svg.text(
|
self.svg.text(
|
||||||
axis_tag,
|
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))
|
reference_id, sheet_id = self.get_reference_and_sheet_id_from_annotation(tool.Ifc.get_entity(obj))
|
||||||
text_position = symbol_position_svg
|
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.add(
|
||||||
self.svg.text(
|
self.svg.text(
|
||||||
reference_id,
|
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))
|
reference_id, sheet_id = self.get_reference_and_sheet_id_from_annotation(tool.Ifc.get_entity(obj))
|
||||||
text_position = symbol_position_svg
|
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.add(
|
||||||
self.svg.text(
|
self.svg.text(
|
||||||
reference_id, insert=(text_position[0], text_position[1] - 2.5), class_="ELEVATION", **text_style
|
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 (reference_id, sheet_id)
|
||||||
return ("-", "-")
|
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
|
"""Convenience method to get svg parameters for text alignment
|
||||||
in a readable way.
|
in a readable way.
|
||||||
|
|
||||||
@@ -721,7 +722,7 @@ class SvgWriter:
|
|||||||
text_tag = self.svg.text(
|
text_tag = self.svg.text(
|
||||||
"",
|
"",
|
||||||
**(attribs | {"filter": "url(#fill-background)"}) if add_fill_bg else attribs,
|
**(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)
|
self.svg.add(text_tag)
|
||||||
|
|
||||||
@@ -795,7 +796,7 @@ class SvgWriter:
|
|||||||
rl = "{:.3f}m".format(rl)
|
rl = "{:.3f}m".format(rl)
|
||||||
|
|
||||||
box_alignment = "bottom-left" if projected_points[0].x <= projected_points[-1].x else "bottom-right"
|
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.add(
|
||||||
self.svg.text(
|
self.svg.text(
|
||||||
"RL +{}".format(rl),
|
"RL +{}".format(rl),
|
||||||
@@ -917,7 +918,7 @@ class SvgWriter:
|
|||||||
text_offset = (text_position - center_position).xy.normalized() * 5
|
text_offset = (text_position - center_position).xy.normalized() * 5
|
||||||
text_position += text_offset
|
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))
|
angle_text = abs(round(math.degrees(angle), 3))
|
||||||
if is_reflex:
|
if is_reflex:
|
||||||
angle_text = 360 - angle_text
|
angle_text = 360 - angle_text
|
||||||
@@ -978,7 +979,7 @@ class SvgWriter:
|
|||||||
)
|
)
|
||||||
text_position += text_offset
|
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 = (points[-1].co - points[-2].co).length
|
||||||
radius = helper.format_distance(radius, precision=self.precision, decimal_places=self.decimal_places)
|
radius = helper.format_distance(radius, precision=self.precision, decimal_places=self.decimal_places)
|
||||||
tag = element.Description or f"R{radius}"
|
tag = element.Description or f"R{radius}"
|
||||||
@@ -1051,7 +1052,7 @@ class SvgWriter:
|
|||||||
)
|
)
|
||||||
text_position += text_offset
|
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))
|
self.svg.add(self.svg.text(tag, insert=tuple(text_position), class_="RADIUS", **text_style))
|
||||||
|
|
||||||
def draw_diameter_annotations(self, obj):
|
def draw_diameter_annotations(self, obj):
|
||||||
@@ -1151,7 +1152,7 @@ class SvgWriter:
|
|||||||
text_format(text),
|
text_format(text),
|
||||||
insert=text_position,
|
insert=text_position,
|
||||||
class_="DIMENSION",
|
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:
|
if not show_description_only:
|
||||||
|
|||||||
Reference in New Issue
Block a user