#!/usr/bin/env python3 from argparse import ArgumentParser from json import loads from os.path import dirname, join, realpath from time import time SCRIPT_DIR = dirname(realpath(__file__)) def compute_dimensions(layout): max_x = 0 x = 0 y = 0 shape_override = {} for row in layout: # ignore metadata if isinstance(row, dict): continue for key in row: if isinstance(key, dict): x += key.get('x', 0) y += key.get('y', 0) shape_override = key continue x += shape_override.get('w', 1) shape_override = {} max_x = max(x, max_x) x = 0 y += 1 return (max_x, y) def make_rect(x, y, w, h): return [ (x, y ), (x+w, y ), (x+w, y+h), (x, y+h), ] def write(f, points, r): points = ' '.join(map(lambda p: f'(xy {p[0]} {p[1]})', points)) f.write(f' (fp_poly (pts {points}) (layer F.Cu) (width {2*r}))\n') f.write(f' (fp_poly (pts {points}) (layer F.Mask) (width {2*r-0.05}))\n') def plot_shape(f, shape, args, offset_x, offset_y): p = args.padding r = args.radius s = args.scale coord = lambda c: (c+p)*s+r dim = lambda d: (d-2*p)*s-2*r points = make_rect(coord(shape['x'])+offset_x, coord(shape['y'])+offset_y, dim(shape['w']), dim(shape['h'])) write(f, points, r) if shape['x'] != shape['x2'] or shape['y'] != shape['y2'] or shape['w'] != shape['w2'] or shape['h'] != shape['h2']: points = make_rect(coord(shape['x2'])+offset_x, coord(shape['y2'])+offset_y, dim(shape['w2']), dim(shape['h2'])) write(f, points, r) if __name__ == '__main__': parser = ArgumentParser() parser.add_argument('-p', '--padding', default=0.1, type=float) parser.add_argument('-r', '--radius', default=0.1, type=float) parser.add_argument('-s', '--scale', default=1.905, type=float) parser.add_argument('layout', help='path to layout file') parser.add_argument('name', help='name of generated footprint') args = parser.parse_args() with open(args.layout) as f: layout = loads(f.read()) w, h = compute_dimensions(layout) offset_x = -w*args.scale/2 offset_y = -h*args.scale/2 name = args.name out_path = join(SCRIPT_DIR, f'../kezboard-pcb.pretty/{name}.kicad_mod') with open(out_path, 'w') as f: f.write(f''' (module {name} (layer F.Cu) (tedit {hex(int(time()))[2:].upper()}) (descr "tiny kezboard is tiny") (attr virtual) (fp_text reference REF** (at 0 {offset_y-1}) (layer F.SilkS) hide (effects (font (size 1 1) (thickness 0.15))) ) (fp_text value {name} (at 0 {-(offset_y-1)}) (layer F.Fab) hide (effects (font (size 1 1) (thickness 0.15))) ) '''.lstrip()) x = 0 y = 0 shape_override = {} for row in layout: # ignore metadata if isinstance(row, dict): continue for key in row: if isinstance(key, dict): x += key.get('x', 0) y += key.get('y', 0) shape_override = key continue w = shape_override.get('w', 1) h = shape_override.get('h', 1) shape = { 'x': x, 'y': y, 'w': w, 'h': h, 'x2': x+shape_override.get('x2', 0), 'y2': y+shape_override.get('y2', 0), 'w2': shape_override.get('w2', w), 'h2': shape_override.get('h2', h), } plot_shape(f, shape, args, offset_x, offset_y) x += shape['w'] shape_override = {} x = 0 y += 1 f.write(')\n')