Add script to generate KiCad footprints from keyboard layouts
This commit is contained in:
parent
83bb4ad6aa
commit
4d1d7b6257
|
@ -26,3 +26,5 @@ fp-info-cache
|
|||
# Exported BOM files
|
||||
*.xml
|
||||
*.csv
|
||||
|
||||
*.old
|
||||
|
|
|
@ -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')
|
Loading…
Reference in New Issue