diff --git a/.gitignore b/.gitignore index a5319ed122..4da5ad5869 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,7 @@ data/ *.xml node_modules/ localconfig.json + +# Generated at runtime by Python. +*.pyc +**/*.pyc diff --git a/road-colors.yaml b/road-colors.yaml index 3dc57d4a55..78d3188ac0 100644 --- a/road-colors.yaml +++ b/road-colors.yaml @@ -16,18 +16,28 @@ hue: [10, 106] # Lightness ranges from 0 to 100; dark to bright. # Chroma ranges from 0 to 100 too; unsaturated to fully saturated. classes: - fill: - lightness: [70, 97] - chroma: [35, 29] - casing: - lightness: [50, 50] - chroma: [70, 55] - low-zoom: - lightness: [62, 92] - chroma: [50, 40] - low-zoom-casing: - lightness: [50, 70] - chroma: [50, 65] + # Colours for output into the MSS file + mss: + fill: + lightness: [70, 97] + chroma: [35, 29] + casing: + lightness: [50, 50] + chroma: [70, 55] + low-zoom: + lightness: [62, 92] + chroma: [50, 40] + low-zoom-casing: + lightness: [50, 70] + chroma: [50, 65] + shield: + lightness: [20, 25] + chroma: [40, 42] + # Colours used by the road shields script shield: - lightness: [20, 25] - chroma: [40, 42] + fill: + lightness: [85, 95] + chroma: [12, 14] + stroke_fill: + lightness: [70, 80] + chroma: [22, 24] diff --git a/scripts/generate_road_colours.py b/scripts/generate_road_colours.py index 57c3b2a0cc..6217b244d4 100755 --- a/scripts/generate_road_colours.py +++ b/scripts/generate_road_colours.py @@ -28,14 +28,18 @@ def rgb_error(self): return delta_e_cie2000(convert_color(self.m_lch, LabColor), convert_color(sRGBColor.new_from_rgb_hex(self.rgb()), LabColor)) - -def main(): - parser = argparse.ArgumentParser(description='Generates road colours') - parser.add_argument('-v', '--verbose', dest='verbose', help='Generates information about colour differences', action='store_true', default=False) - args = parser.parse_args() - - settings = yaml.load(open('road-colors.yaml', 'r')) - +def load_settings(): + """Read the settings from YAML.""" + return yaml.load(open('road-colors.yaml', 'r')) + +def generate_colours(settings, section): + """Generate colour ranges. + + Arguments: + settings -- The settings loaded by load_settings. + section -- Which section of the settings under 'classes' to use. Typically + 'mss' or 'shields'. + """ road_classes = settings['roads'] colour_divisions = len(road_classes) - 1 hues = OrderedDict() @@ -62,7 +66,7 @@ def main(): # The higher the road classification, the higher its saturation. Conversely, # the roads get brighter towards the lower end of the classification. - classes = settings['classes'] + classes = settings['classes'][section] for cls, params in classes.iteritems(): l = params['lightness'] c = params['chroma'] @@ -83,6 +87,18 @@ def main(): c += delta_c l += delta_l + return colours + +def main(): + parser = argparse.ArgumentParser(description='Generates road colours') + parser.add_argument('-v', '--verbose', dest='verbose', help='Generates information about colour differences', action='store_true', default=False) + args = parser.parse_args() + + settings = load_settings() + road_classes = settings['roads'] + colour_divisions = len(road_classes) - 1 + colours = generate_colours(settings, 'mss') + # Print a warning about the nature of these definitions. print "/* This is generated code, do not change this file manually. */" print "/* */" @@ -91,7 +107,6 @@ def main(): print "/* ./scripts/generate_road_colours.py > road-colors-generated.mss */" print "/* */" - for line_name, line_colours in colours.iteritems(): for name, colour in line_colours.iteritems(): if args.verbose: diff --git a/scripts/generate_shields.py b/scripts/generate_shields.py index 32c780c24e..4faa207e3b 100755 --- a/scripts/generate_shields.py +++ b/scripts/generate_shields.py @@ -1,132 +1,131 @@ #!/usr/bin/env python -# generate highway shields +# 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(): - namespace = 'http://www.w3.org/2000/svg' - svgns = '{' + namespace + '}' - svgnsmap = {None: namespace} - - config = {} - config['base'] = {} - - config['base']['rounded_corners'] = 2 - config['base']['font_height'] = 9.1 - config['base']['font_width'] = 5.9 - config['base']['padding_x'] = 4 - config['base']['padding_y'] = 2 - config['base']['fill'] = '#ddd' - config['base']['stroke_width'] = 1 - config['base']['stroke_fill'] = '#000' - - 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 are generated by generate_road_colours.py - - config['motorway']['fill'] = '#eccdd1' # Lch(85,12,10), error 0.3 - config['motorway']['stroke_fill'] = '#d39da5' # Lch(70,22,10), error 0.2 - config['trunk']['fill'] = '#f2d7ce' # Lch(88,12,42), error 1.0 - config['trunk']['stroke_fill'] = '#d7a899' # Lch(73,22,42), error 0.9 - config['primary']['fill'] = '#f3e3cf' # Lch(91,12,74), error 1.4 - config['primary']['stroke_fill'] = '#d1b795' # Lch(76,22,74), error 1.8 - config['secondary']['fill'] = '#eeefd7' # Lch(94,12,106), error 1.3 - config['secondary']['stroke_fill'] = '#c4c69c' # Lch(79,22,106), error 1.5 - config['tertiary']['fill'] = '#f1f1f1' # Lch(95,0,0), error 0.1 - config['tertiary']['stroke_fill'] = '#c6c6c6' # Lch(80,0,0), error 0.1 - - # changes for different size versions - config['z16'] = {} - config['z18'] = {} - - config['z16']['font_width'] = 6.5 - config['z16']['font_height'] = 10.1 - config['z18']['font_width'] = 7.2 - config['z18']['font_height'] = 11.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', '100%') - svg.set('height', '100%') - 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('id', 'shield') - - stroke = '' - if vars['stroke_width'] > 0: - stroke = 'stroke:' + vars['stroke_fill'] + ';stroke-width:' + str(vars['stroke_width']) + ';' - - shield.set('style', 'fill:' + vars['fill'] + ';' + stroke) - - 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), 'w') - 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() + settings = load_settings() + colours = generate_colours(settings, 'shield') + + namespace = 'http://www.w3.org/2000/svg' + svgns = '{' + namespace + '}' + svgnsmap = {None: namespace} + + config = {} + config['base'] = {} + + config['base']['rounded_corners'] = 2 + config['base']['font_height'] = 9.1 + config['base']['font_width'] = 5.9 + 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.iteritems(): + for name, colour in line_colours.iteritems(): + config[name][line_name] = colour.rgb() + + # changes for different size versions + config['z16'] = {} + config['z18'] = {} + + config['z16']['font_width'] = 6.5 + config['z16']['font_height'] = 10.1 + config['z18']['font_width'] = 7.2 + config['z18']['font_height'] = 11.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', '100%') + svg.set('height', '100%') + 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('id', 'shield') + + stroke = '' + if vars['stroke_width'] > 0: + stroke = 'stroke:' + vars['stroke_fill'] + ';stroke-width:' + str(vars['stroke_width']) + ';' + + shield.set('style', 'fill:' + vars['fill'] + ';' + stroke) + + 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), 'w') + 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()