diff --git a/src/ifcblenderexport/blenderbim/bim/__init__.py b/src/ifcblenderexport/blenderbim/bim/__init__.py index 6a82216a48..64de65dab9 100644 --- a/src/ifcblenderexport/blenderbim/bim/__init__.py +++ b/src/ifcblenderexport/blenderbim/bim/__init__.py @@ -189,6 +189,7 @@ if bpy is not None: operator.AddSchedule, operator.RemoveSchedule, operator.SelectScheduleFile, + operator.BuildSchedule, prop.StrProperty, prop.Variable, prop.Role, diff --git a/src/ifcblenderexport/blenderbim/bim/data/schedules/.gitkeep b/src/ifcblenderexport/blenderbim/bim/data/schedules/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/ifcblenderexport/blenderbim/bim/operator.py b/src/ifcblenderexport/blenderbim/bim/operator.py index 3e246cad0d..e50fbc9b9c 100644 --- a/src/ifcblenderexport/blenderbim/bim/operator.py +++ b/src/ifcblenderexport/blenderbim/bim/operator.py @@ -8,12 +8,14 @@ import webbrowser import ifcopenshell import ifcopenshell.util.selector import tempfile +import ntpath from . import export_ifc from . import import_ifc from . import qto from . import cut_ifc from . import svgwriter from . import sheeter +from . import scheduler from . import schema from . import bcf from . import ifc @@ -3664,3 +3666,19 @@ class SelectScheduleFile(bpy.types.Operator): def invoke(self, context, event): context.window_manager.fileselect_add(self) return {'RUNNING_MODAL'} + + +class BuildSchedule(bpy.types.Operator): + bl_idname = 'bim.build_schedule' + bl_label = 'Build Schedule' + + def execute(self, context): + props = bpy.context.scene.DocProperties + schedule = props.schedules[props.active_schedule_index] + schedule_creator = scheduler.Scheduler() + outfile = os.path.join( + bpy.context.scene.BIMProperties.data_dir, 'schedules', + ntpath.basename(schedule.file).replace('.ods', '.svg')) + schedule_creator.schedule(schedule.file, outfile) + webbrowser.open('file://' + outfile) + return {'FINISHED'} diff --git a/src/ifcblenderexport/blenderbim/bim/scheduler.py b/src/ifcblenderexport/blenderbim/bim/scheduler.py new file mode 100644 index 0000000000..f44f44f480 --- /dev/null +++ b/src/ifcblenderexport/blenderbim/bim/scheduler.py @@ -0,0 +1,72 @@ +import svgwrite +import xml.etree.ElementTree as ET + +from odf.opendocument import load +from odf.table import Table, TableRow, TableColumn, TableCell +from odf.text import P +from odf.style import Style + +class Scheduler(): + def schedule(self, infile, outfile): + self.svg = svgwrite.Drawing( + outfile, + debug=False, + id='root', + ) + self.padding = 1 + self.margin = 5 + doc = load(infile) + styles = {} + for style in doc.getElementsByType(Style): + 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): + style_name = col.getAttribute('stylename') + repeat = col.getAttribute('numbercolumnsrepeated') + repeat = int(repeat) if repeat else 1 + for i in range(0, repeat): + if not style_name or 'column-width' not in styles[style_name]: + column_widths.append(50) + else: + column_widths.append(self.convert_to_si(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): + repeat = td.getAttribute('numbercolumnsrepeated') + repeat = int(repeat) if repeat else 1 + for i in range(0, repeat): + width = column_widths[tdi] + self.svg.add(self.svg.rect(insert=(x, y), size=(width, height), style='fill:rgba(255,255,255,1); stroke-width:.125; stroke:rgb(0,0,0)')) + value = td.getElementsByType(P) + if value: + 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) + 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): + 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_si(self, value): + if 'in' in value: + return float(value[0:-2]) * 25.4 diff --git a/src/ifcblenderexport/blenderbim/bim/ui.py b/src/ifcblenderexport/blenderbim/bim/ui.py index 7cc49ece6e..29388cf162 100644 --- a/src/ifcblenderexport/blenderbim/bim/ui.py +++ b/src/ifcblenderexport/blenderbim/bim/ui.py @@ -766,6 +766,7 @@ class BIM_PT_schedules(Panel): row.operator('bim.add_schedule') if props.schedules: + row.operator('bim.build_schedule', icon='LINENUMBERS_ON', text='') row.operator('bim.remove_schedule', icon='X', text='').index = props.active_schedule_index layout.template_list('BIM_UL_generic', '', props, 'schedules', props, 'active_schedule_index')