mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-18 06:21:40 +00:00
Convert ODS schedules into SVG schedules for inclusion in drawings
This commit is contained in:
@@ -189,6 +189,7 @@ if bpy is not None:
|
|||||||
operator.AddSchedule,
|
operator.AddSchedule,
|
||||||
operator.RemoveSchedule,
|
operator.RemoveSchedule,
|
||||||
operator.SelectScheduleFile,
|
operator.SelectScheduleFile,
|
||||||
|
operator.BuildSchedule,
|
||||||
prop.StrProperty,
|
prop.StrProperty,
|
||||||
prop.Variable,
|
prop.Variable,
|
||||||
prop.Role,
|
prop.Role,
|
||||||
|
|||||||
@@ -8,12 +8,14 @@ import webbrowser
|
|||||||
import ifcopenshell
|
import ifcopenshell
|
||||||
import ifcopenshell.util.selector
|
import ifcopenshell.util.selector
|
||||||
import tempfile
|
import tempfile
|
||||||
|
import ntpath
|
||||||
from . import export_ifc
|
from . import export_ifc
|
||||||
from . import import_ifc
|
from . import import_ifc
|
||||||
from . import qto
|
from . import qto
|
||||||
from . import cut_ifc
|
from . import cut_ifc
|
||||||
from . import svgwriter
|
from . import svgwriter
|
||||||
from . import sheeter
|
from . import sheeter
|
||||||
|
from . import scheduler
|
||||||
from . import schema
|
from . import schema
|
||||||
from . import bcf
|
from . import bcf
|
||||||
from . import ifc
|
from . import ifc
|
||||||
@@ -3664,3 +3666,19 @@ class SelectScheduleFile(bpy.types.Operator):
|
|||||||
def invoke(self, context, event):
|
def invoke(self, context, event):
|
||||||
context.window_manager.fileselect_add(self)
|
context.window_manager.fileselect_add(self)
|
||||||
return {'RUNNING_MODAL'}
|
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'}
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -766,6 +766,7 @@ class BIM_PT_schedules(Panel):
|
|||||||
row.operator('bim.add_schedule')
|
row.operator('bim.add_schedule')
|
||||||
|
|
||||||
if props.schedules:
|
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
|
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')
|
layout.template_list('BIM_UL_generic', '', props, 'schedules', props, 'active_schedule_index')
|
||||||
|
|||||||
Reference in New Issue
Block a user