Files
IfcOpenShell/src/ifcblenderexport/blenderbim/bim/scheduler.py
T

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

103 lines
4.2 KiB
Python
Raw Normal View History

import svgwrite
from odf.opendocument import load
from odf.table import Table, TableRow, TableColumn, TableCell
from odf.text import P
from odf.style import Style
2020-11-01 20:08:48 +07:00
class Scheduler:
def schedule(self, infile, outfile):
self.svg = svgwrite.Drawing(outfile, debug=False, id="root",)
self.padding = 1
self.margin = 1
doc = load(infile)
styles = {}
for style in doc.getElementsByType(Style):
2020-11-01 20:08:48 +07:00
name = style.getAttribute("name")
if not style.firstChild:
continue
styles[name] = {key[1]: value for key, value in style.firstChild.attributes.items()}
table = doc.getElementsByType(Table)[0]
column_widths = []
for col in table.getElementsByType(TableColumn):
2020-11-01 20:08:48 +07:00
style_name = col.getAttribute("stylename")
repeat = col.getAttribute("numbercolumnsrepeated")
repeat = int(repeat) if repeat else 1
for i in range(0, repeat):
2020-11-01 20:08:48 +07:00
if not style_name or "column-width" not in styles[style_name]:
column_widths.append(50)
else:
2020-11-01 20:08:48 +07:00
column_widths.append(self.convert_to_mm(styles[style_name]["column-width"]))
y = self.margin
for tri, tr in enumerate(table.getElementsByType(TableRow)):
x = self.margin
height = 6
tdi = 0
for td in tr.getElementsByType(TableCell):
2020-11-01 20:08:48 +07:00
repeat = td.getAttribute("numbercolumnsrepeated")
repeat = int(repeat) if repeat else 1
for i in range(0, repeat):
width = column_widths[tdi]
2020-11-01 20:08:48 +07:00
self.svg.add(
self.svg.rect(
insert=(x, y),
size=(width, height),
style="fill: #ffffff; stroke-width:.125; stroke: #000000;",
)
)
value = td.getElementsByType(P)
if value:
2020-11-01 20:08:48 +07:00
self.add_text(value[0], x + self.padding, y + self.padding)
x += width
tdi += 1
y += height
total_width = sum(column_widths) + (self.margin * 2)
2020-11-01 20:08:48 +07:00
self.svg["width"] = "{}mm".format(total_width)
self.svg["height"] = "{}mm".format(y)
self.svg["viewBox"] = "0 0 {} {}".format(total_width, y)
self.svg.save(pretty=True)
def add_text(self, text, x, y):
2020-11-01 20:08:48 +07:00
self.svg.add(
self.svg.text(
str(text).upper(),
insert=tuple((x, y)),
**{
"font-size": 4.13,
"font-family": "OpenGost Type B TT",
"text-anchor": "start",
"alignment-baseline": "baseline",
"dominant-baseline": "hanging",
}
)
)
def convert_to_mm(self, value):
# XSL is what defines the units of measurements in ODF
# https://docs.oasis-open.org/office/v1.2/os/OpenDocument-v1.2-os-part1.html#datatype-positiveLength
# https://www.w3.org/TR/2001/REC-xsl-20011015/slice5.html#section-N8185-Definitions-of-Units-of-Measure
2020-11-01 20:08:48 +07:00
if "cm" in value:
return float(value[0:-2]) * 10
2020-11-01 20:08:48 +07:00
elif "mm" in value:
return float(value[0:-2])
2020-11-01 20:08:48 +07:00
elif "in" in value:
return float(value[0:-2]) * 25.4
2020-11-01 20:08:48 +07:00
elif "pt" in value:
return float(value[0:-2]) * (1 / 72) * 25.4
elif "pc" in value:
return float(value[0:-2]) * 12 * (1 / 72) * 25.4
elif "px" in value:
# implementors may instead simply pick a fixed conversion factor,
# treating 'px' as an absolute unit of measurement (such as 1/92" or
# 1/72"). <-- We're picking 1/96 to match SVG. Let me know if it
# breaks anything.
2020-11-01 20:08:48 +07:00
return float(value[0:-2]) * (1 / 96) * 2.54 * 10
elif "em" in value:
# This is a funny one. Since the scheduler at the moment enforces a
# font size of 2.5mm (vertically, FWIW), I'm writing this. Hopefully
# this code doesn't hurt anybody.
2020-11-01 20:08:48 +07:00
return float(value[0:-2]) * (1 / 96) * 2.54 * 10