You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
openstreetmap-carto/scripts/generate_shields.py

133 lines
5.2 KiB
Python

#!/usr/bin/env python3
# Generate highway shields as SVG files in symbols/shields.
from __future__ import print_function
import copy, lxml.etree, math, os
from generate_road_colours import load_settings, generate_colours
def main():
settings = load_settings()
colours = generate_colours(settings, 'shield')
namespace = 'http://www.w3.org/2000/svg'
svgns = '{' + namespace + '}'
svgnsmap = {None: namespace}
config = {}
config['base'] = {}
# font_height and font_width are determined by trial and error
config['base']['rounded_corners'] = 2
config['base']['font_height'] = 12.1
config['base']['font_width'] = 6.2
config['base']['padding_x'] = 4
config['base']['padding_y'] = 2
config['base']['stroke_width'] = 1
# Fall back colours used if no colours are defined in road-colours.yaml for a road type.
config['base']['fill'] = '#f1f1f1'
config['base']['stroke_fill'] = '#c6c6c6'
config['global'] = {}
config['global']['types'] = ['motorway', 'trunk', 'primary', 'secondary', 'tertiary']
config['global']['max_width'] = 11
config['global']['max_height'] = 4
config['global']['output_dir'] = '../symbols/shields/' # specified relative to the script location
config['global']['additional_sizes'] = ['base', 'z16', 'z18']
# specific values overwrite config['base'] ones
config['motorway'] = {}
config['trunk'] = {}
config['primary'] = {}
config['secondary'] = {}
config['tertiary'] = {}
# Colour values generated by generate_road_colours.py.
for line_name, line_colours in colours.items():
for name, colour in line_colours.items():
config[name][line_name] = colour.rgb()
# changes for different size versions
config['z16'] = {}
config['z18'] = {}
config['z16']['font_width'] = 6.1
config['z16']['font_height'] = 14.1
config['z18']['font_width'] = 6.9
config['z18']['font_height'] = 15.1
if not os.path.exists(os.path.dirname(config['global']['output_dir'])):
os.makedirs(os.path.dirname(config['global']['output_dir']))
for height in range(1, config['global']['max_height'] + 1):
for width in range(1, config['global']['max_width'] + 1):
for shield_type in config['global']['types']:
# merge base config and specific styles
vars = copy.deepcopy(config['base'])
if shield_type in config:
for option in config[shield_type]:
vars[option] = config[shield_type][option]
for shield_size in config['global']['additional_sizes']:
if shield_size != 'base':
if shield_size in config:
for option in config[shield_size]:
vars[option] = config[shield_size][option]
shield_width = 2 * vars['padding_x'] + math.ceil(vars['font_width'] * width)
shield_height = 2 * vars['padding_y'] + math.ceil(vars['font_height'] * height)
svg = lxml.etree.Element('svg', nsmap=svgnsmap)
svg.set('width', str(shield_width + vars['stroke_width']))
svg.set('height', str(shield_height + vars['stroke_width']))
svg.set('viewBox', '0 0 ' + str(shield_width + vars['stroke_width']) + ' ' + str(shield_height + vars['stroke_width']))
if vars['stroke_width'] > 0:
offset_x = vars['stroke_width'] / 2.0
offset_y = vars['stroke_width'] / 2.0
else:
offset_x = 0
offset_y = 0
shield = lxml.etree.Element(svgns + 'rect')
shield.set('x', str(offset_x))
shield.set('y', str(offset_y))
shield.set('width', str(shield_width))
shield.set('height', str(shield_height))
if vars['rounded_corners'] > 0:
shield.set('rx', str(vars['rounded_corners']))
shield.set('ry', str(vars['rounded_corners']))
shield.set('fill', vars['fill'])
stroke = ''
if vars['stroke_width'] > 0:
shield.set('stroke', vars['stroke_fill'])
shield.set('stroke-width', str(vars['stroke_width']))
svg.append(shield)
filename = shield_type + '_' + str(width) + 'x' + str(height)
if shield_size != 'base':
filename = filename + '_' + shield_size
filename = filename + '.svg'
# save file
try:
shieldfile = open(os.path.join(os.path.dirname(__file__), config['global']['output_dir'] + filename), 'wb')
shieldfile.write(lxml.etree.tostring(svg, encoding='utf-8', xml_declaration=True, pretty_print=True))
shieldfile.close()
except IOError:
print('Could not save file ' + filename + '.')
continue
if __name__ == "__main__":
main()