#!/usr/bin/env python3 import argparse import cv2 import pathlib import numpy import os from typing import MutableMapping MAP_ROOT = pathlib.Path(os.getcwd()) TILES_DIR = MAP_ROOT / 'tiles' SHOW_MAP = False def get_tile_path(tile: str) -> pathlib.Path: """Return the corresponding image file name for a tile""" return TILES_DIR / f'{tile.lower().replace(" ", "_")}.png' def read_map(map_path: pathlib.Path) -> MutableMapping: """Read and parse a map file""" map_definition = {'symbols': {}, 'rules': {}} with open(map_path, 'r') as map_file: lines = [l[:-1] for l in map_file.readlines()] # remove new lines # sections in map files are seperated by an empty line section_end = lines.index('') map_string = '\n'.join(lines[:section_end]) lines = lines [section_end+1:] # consume map string section_end = lines.index('') for symbol_def in lines[:section_end]: symbol, tile = symbol_def.split(':=') symbol = symbol.strip() tile = tile.strip() map_definition['symbols'][symbol] = tile lines = lines[section_end + 1:] # consume symbol definitions # build up tiles tiles = [] for line in map_string.splitlines(): row = [] for symbol in line: tile = "neutral" if symbol != ' ': if symbol not in map_definition['symbols']: print(f'WARNING unknown symbol "{symbol}"') else: tile = map_definition['symbols'][symbol] row.append(tile) tiles.append(row) map_definition['tiles'] = tiles for rule in lines: name, rule = symbol_def.split(':=') name = name.strip() rule = rule.strip() map_definition['rules'][name] = rule return map_definition def generate_img(map_path: pathlib.Path): """Generate a image from a map file""" map_definition = read_map(map_path) tiles = map_definition['tiles'] rows_imgs = [] for i, row in enumerate(tiles): tile_imgs = [] for j, tile in enumerate(row): # find the right street and rotation if tile == 'street': # check continuations left = j > 1 and row[j-1] == 'street' right = j < len(row) - 1 and row[j+1] == 'street' above = i > 1 and tiles[i-1][j] == 'street' below = i < len(tiles) - 1 and tiles[i+1][j] == 'street' connections = len([b for b in [left, right, above, below] if b == True]) # straight lines if connections == 1 or (connections == 2 and ((left and right) or (above and below))): tile_img = cv2.imread(str(get_tile_path('street'))) if above or below: tile_img = numpy.rot90(tile_img) # elbow elif connections == 2: # normal orientation above and right tile_img = cv2.imread(str(get_tile_path('street_2'))) if right and below: tile_img = numpy.rot90(tile_img, 3) elif left and below: tile_img = numpy.rot90(tile_img, 2) elif above and left: tile_img = numpy.rot90(tile_img) elif connections == 3: # normal orientation left above right tile_img = cv2.imread(str(get_tile_path('street_3'))) if above and right and below: tile_img = numpy.rot90(tile_img, 3) elif left and below and right: tile_img = numpy.rot90(tile_img, 2) elif below and left and above: tile_img = numpy.rot90(tile_img) elif connections == 4: tile_img = cv2.imread(str(get_tile_path('street_4'))) else: tile_img = cv2.imread(str(get_tile_path(tile))) tile_imgs.append(tile_img) row_img = cv2.hconcat(tile_imgs) rows_imgs.append(row_img) map_img = cv2.vconcat(rows_imgs) if SHOW_MAP: cv2.imshow(f'{map_path.stem}.png', map_img) cv2.waitKey(0) cv2.imwrite(f'{map_path.stem}.png', map_img) def main(): """Generate map images from map files""" parser = argparse.ArgumentParser(description='generate latex standalone cards') parser.add_argument('map_input', help='map file or directory containing map files') parser.add_argument('--map-root', help='path to the map root directory') parser.add_argument('--show-map', help='show the generated map', action='store_true') args = parser.parse_args() if args.map_root: global MAP_ROOT MAP_ROOT = pathlib.Path(args.latex_root) global TILES_DIR TILES_DIR = MAP_ROOT / 'tiles' if args.show_map: global SHOW_MAP SHOW_MAP = True map_path = pathlib.Path(args.map_input) map_files = [map_path] if map_path.is_dir(): map_files = map_path.glob('*.map') for m in map_files: generate_img(m) if __name__ == '__main__': main()