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

220 lines
8.4 KiB
Python
Raw Normal View History

import xml.etree.ElementTree as ET
import urllib.parse
import pystache
import ntpath
import os
from shutil import copy
from xml.dom import minidom
class SheetBuilder:
def __init__(self):
self.data_dir = None
self.scale = 'NTS'
def create(self, name):
sheet_path = '{}sheets/{}.svg'.format(self.data_dir, name)
root = ET.Element('svg')
root.attrib['xmlns'] = 'http://www.w3.org/2000/svg'
root.attrib['xmlns:xlink'] = 'http://www.w3.org/1999/xlink'
root.attrib['id'] = 'root'
root.attrib['version'] = '1.1'
root.attrib['width'] = '841mm'
root.attrib['height'] = '594mm'
2020-08-18 10:04:19 +10:00
view = ET.SubElement(root, 'g')
view.attrib['data-type'] = 'titleblock'
titleblock = ET.SubElement(view, 'image')
titleblock.attrib['xlink:href'] = '../templates/titleblock.svg'
titleblock.attrib['x'] = '0'
titleblock.attrib['y'] = '0'
titleblock.attrib['width'] = '841mm'
titleblock.attrib['height'] = '594mm'
with open(sheet_path, 'w') as f:
f.write(minidom.parseString(ET.tostring(root)).toprettyxml(indent=' '))
2020-08-18 10:04:19 +10:00
def add_drawing(self, view_name, sheet_name):
sheet_path = os.path.join(self.data_dir, 'sheets', sheet_name + '.svg')
view_path = os.path.join(self.data_dir, 'diagrams', view_name + '.svg')
ET.register_namespace('', 'http://www.w3.org/2000/svg')
ET.register_namespace('xlink', 'http://www.w3.org/1999/xlink')
sheet_tree = ET.parse(sheet_path)
sheet_root = sheet_tree.getroot()
view_tree = ET.parse(view_path)
view_root = view_tree.getroot()
# The view is placed into a group with a background image element.
# Although the foreground SVG already has a background, it is duplicated
# here to accommodate browsers which do not nest images.
view = ET.SubElement(sheet_root, 'g')
2020-08-18 10:04:19 +10:00
view.attrib['data-type'] = 'drawing'
background = ET.SubElement(view, 'image')
background.attrib['xlink:href'] = '../diagrams/{}.png'.format(view_name)
background.attrib['x'] = '0'
background.attrib['y'] = '0'
background.attrib['width'] = view_root.attrib.get('width')
background.attrib['height'] = view_root.attrib.get('height')
foreground = ET.SubElement(view, 'image')
foreground.attrib['xlink:href'] = '../diagrams/{}.svg'.format(view_name)
foreground.attrib['x'] = '0'
foreground.attrib['y'] = '0'
foreground.attrib['width'] = view_root.attrib.get('width')
foreground.attrib['height'] = view_root.attrib.get('height')
title = ET.SubElement(view, 'image')
title.attrib['xlink:href'] = '../templates/view-title.svg'
title.attrib['x'] = '0'
title.attrib['y'] = view_root.attrib.get('height')
sheet_tree.write(sheet_path)
2020-08-18 10:04:19 +10:00
def add_schedule(self, schedule_name, sheet_name):
sheet_path = os.path.join(self.data_dir, 'sheets', sheet_name + '.svg')
view_path = os.path.join(self.data_dir, 'schedules', schedule_name + '.svg')
ET.register_namespace('', 'http://www.w3.org/2000/svg')
ET.register_namespace('xlink', 'http://www.w3.org/1999/xlink')
sheet_tree = ET.parse(sheet_path)
sheet_root = sheet_tree.getroot()
view_tree = ET.parse(view_path)
view_root = view_tree.getroot()
group = ET.SubElement(sheet_root, 'g')
group.attrib['data-type'] = 'schedule'
foreground = ET.SubElement(group, 'image')
foreground.attrib['xlink:href'] = '../schedules/{}.svg'.format(schedule_name)
foreground.attrib['x'] = '0'
foreground.attrib['y'] = '0'
foreground.attrib['width'] = view_root.attrib.get('width')
foreground.attrib['height'] = view_root.attrib.get('height')
title = ET.SubElement(group, 'image')
title.attrib['xlink:href'] = '../templates/view-title.svg'
title.attrib['x'] = '0'
title.attrib['y'] = view_root.attrib.get('height')
sheet_tree.write(sheet_path)
def build(self, sheet_name):
os.makedirs('{}build/{}/'.format(self.data_dir, sheet_name), exist_ok=True)
sheet_path = '{}sheets/{}.svg'.format(self.data_dir, sheet_name)
ET.register_namespace('', 'http://www.w3.org/2000/svg')
ET.register_namespace('xlink', 'http://www.w3.org/1999/xlink')
tree = ET.parse(sheet_path)
root = tree.getroot()
2020-08-18 10:04:19 +10:00
titleblock = root.findall('{http://www.w3.org/2000/svg}g[@data-type="titleblock"]')[0]
image = titleblock.findall('{http://www.w3.org/2000/svg}image')[0]
titleblock.append(self.parse_embedded_svg(image, {
'number': sheet_name,
'revision': 'A'
}))
2020-08-18 10:04:19 +10:00
titleblock.remove(image)
2020-08-18 10:04:19 +10:00
self.group_number = 1
self.build_drawings(root.findall('{http://www.w3.org/2000/svg}g[@data-type="drawing"]'), sheet_name)
self.build_schedules(root.findall('{http://www.w3.org/2000/svg}g[@data-type="schedule"]'))
2020-08-18 10:04:19 +10:00
with open('{}build/{}/{}.svg'.format(self.data_dir, sheet_name, sheet_name), 'wb') as output:
tree.write(output)
def build_drawings(self, drawings, sheet_name):
for view in drawings:
images = view.findall('{http://www.w3.org/2000/svg}image')
background = images[0]
foreground = images[1]
view_title = images[2]
self.scale = 'NTS'
# Add foreground
view.append(self.parse_embedded_svg(foreground, {}))
# Add background
background_path = '{}sheets/{}'.format(self.data_dir, self.get_href(background))
copy(background_path, '{}build/{}/'.format(self.data_dir, sheet_name))
# Add view title
foreground_path = self.get_href(foreground)
view.append(self.parse_embedded_svg(view_title, {
2020-08-18 10:04:19 +10:00
'no' : self.group_number,
'name': ntpath.basename(foreground_path)[0:-4],
'scale': self.scale
}))
for image in images:
view.remove(image)
2020-08-18 10:04:19 +10:00
self.group_number += 1
2020-08-18 10:04:19 +10:00
def build_schedules(self, schedules):
for group in schedules:
images = group.findall('{http://www.w3.org/2000/svg}image')
schedule = images[0]
group_title = images[1]
self.scale = 'NTS'
group.append(self.parse_embedded_svg(schedule, {}))
path = self.get_href(schedule)
group.append(self.parse_embedded_svg(group_title, {
'no' : self.group_number,
'name': ntpath.basename(path)[0:-4],
'scale': self.scale
}))
for image in images:
group.remove(image)
self.group_number += 1
def get_href(self, element):
return urllib.parse.unquote(element.attrib.get('{http://www.w3.org/1999/xlink}href'))
def parse_embedded_svg(self, image, data):
group = ET.Element('g')
group.attrib['transform'] = 'translate({},{})'.format(
self.mm_to_px(self.convert_to_mm(image.attrib.get('x'))),
self.mm_to_px(self.convert_to_mm(image.attrib.get('y'))))
svg_path = self.get_href(image)
with open('{}sheets/{}'.format(self.data_dir, svg_path), 'r') as template:
embedded = ET.fromstring(pystache.render(template.read(), data))
self.scale = embedded.attrib.get('data-scale')
images = embedded.findall('{http://www.w3.org/2000/svg}image')
for image in images:
new_href = ntpath.basename(image.attrib.get('{http://www.w3.org/1999/xlink}href'))
image.attrib['{http://www.w3.org/1999/xlink}href'] = new_href
group.append(embedded)
return group
def convert_to_mm(self, value):
if value.isnumeric():
return float(value)
if 'cm' in value:
return float(value[0:-2]) * 10
elif 'mm' in value:
return float(value[0:-2])
elif 'Q' in value:
return float(value[0:-1]) * (1/40) * 10
elif 'in' in value:
return float(value[0:-2]) * 2.54 * 10
elif 'pc' in value:
return float(value[0:-2]) * (1/6) * 2.54 * 10
elif 'pt' in value:
return float(value[0:-2]) * (1/72) * 2.54 * 10
elif 'px' in value:
return float(value[0:-2]) * (1/96) * 2.54 * 10
def mm_to_px(self, value):
return (value / 25.4) * 96