133 lines
3.8 KiB
Python
Executable File
133 lines
3.8 KiB
Python
Executable File
#!/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')
|