Add script to generate KiCad footprints from keyboard layouts

This commit is contained in:
Luca 2021-07-18 22:51:14 +02:00
parent 83bb4ad6aa
commit 4d1d7b6257
2 changed files with 134 additions and 0 deletions

2
.gitignore vendored
View File

@ -26,3 +26,5 @@ fp-info-cache
# Exported BOM files # Exported BOM files
*.xml *.xml
*.csv *.csv
*.old

132
scripts/layout2footprint.py Executable file
View File

@ -0,0 +1,132 @@
#!/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')