cad/mkbd65.py
2022-03-02 20:26:05 +01:00

138 lines
6.6 KiB
Python
Executable file

#!/usr/bin/env python3
import sys
from subprocess import run
from configparser import ConfigParser
import click
from solid import scad_render_to_file, translate
from mkbd65.key_mat import key_mat, key
from mkbd65.pcb import pcb
from mkbd65.phone import phone
from mkbd65.lower_case import lower_case
from mkbd65.util import PCB_WIDTH
@click.command()
@click.option("-l", "--layout", "layout", default="ansi", show_default=True, help="Keyboard layout", type=click.Choice(["ansi", "ansi_big_enter", "iso"], case_sensitive=False))
@click.option("-v", "--variant", "variant", default="en", show_default=True, help="Keyboard layout variant", type=click.Choice(["en", "de"], case_sensitive=False))
@click.option("-s", "--stl", "stl", is_flag=True, help="Generate STL files")
@click.option("-3", "--3mf", "emf", is_flag=True, help="Generate 3MF files")
@click.option("-a", "--amf", "amf", is_flag=True, help="Generate AMF files")
@click.option("-d", "--detail", "detail", default=64, show_default=True, help="OpenSCAD detail level", type=click.INT)
@click.argument("config_file")
def cli(layout, variant, stl, emf, amf, detail, config_file):
if layout == "ansi" and variant == "de":
click.echo("There is no german ansi variant. German keyboards need one more key and therefore use the ISO layout.")
sys.exit()
config = ConfigParser()
config.read(config_file)
components = {
"phone": phone(
width=config.getfloat("phone", "width"),
height=config.getfloat("phone", "height"),
thickness=config.getfloat("phone", "thickness"),
corner_radius=config.getfloat("phone", "corner_radius"),
side_radius=config.getfloat("phone", "side_radius")
),
"key": key(
width=config.getfloat("key_mat", "key_width", fallback=9),
height=config.getfloat("key_mat", "key_height", fallback=6),
thickness=config.getfloat("key_mat", "key_thickness", fallback=2),
corner_radius=config.getfloat("key_mat", "key_corner_radius", fallback=1),
label="❤️",
font=config.get("key_mat", "font", fallback="DejaVu Sans:style=Bold")
),
"key_mat": key_mat(
margin=config.getfloat("key_mat", "margin", fallback=1),
padding=config.getfloat("key_mat", "padding", fallback=1),
thickness=config.getfloat("key_mat", "thickness", fallback=0.5),
key_width=config.getfloat("key_mat", "key_width", fallback=9),
key_height=config.getfloat("key_mat", "key_height", fallback=6),
key_radius=config.getfloat("key_mat", "key_corner_radius", fallback=1),
key_thickness=config.getfloat("key_mat", "key_thickness", fallback=2),
layout=layout,
variant=variant,
font=config.get("key_mat", "font", fallback="DejaVu Sans:style=Bold")
),
"pcb": pcb(
key_width=config.getfloat("key_mat", "key_width", fallback=9),
key_height=config.getfloat("key_mat", "key_height", fallback=6),
key_padding=config.getfloat("key_mat", "padding", fallback=1)
),
"lower_case": lower_case(
phone_width=config.getfloat("phone", "width"),
phone_height=config.getfloat("phone", "height"),
phone_radius=config.getfloat("phone", "corner_radius")
),
"test_key_mat": key_mat(
margin=config.getfloat("key_mat", "margin", fallback=1),
padding=config.getfloat("key_mat", "padding", fallback=1),
thickness=config.getfloat("key_mat", "thickness", fallback=0.5),
key_width=config.getfloat("key_mat", "key_width", fallback=9),
key_height=config.getfloat("key_mat", "key_height", fallback=6),
key_radius=config.getfloat("key_mat", "key_corner_radius", fallback=1),
key_thickness=config.getfloat("key_mat", "key_thickness", fallback=2),
layout=layout,
variant=variant,
font=config.get("key_mat", "font", fallback="DejaVu Sans:style=Bold"),
keys_h=5,
keys_v=3
)
}
columns = 13
alps_thickness = 0.78
alps_height = 4
alps_width = 6
pcb_thickness = 1
bottom_cover_thickness = 0.5
pcb_margin_y = 3
pcb_margin_x = (PCB_WIDTH - (columns * config.getfloat("key_mat", "key_width", fallback=9) + (columns - 1) * config.getfloat("key_mat", "padding", fallback=1))) / 2 + (config.getfloat("key_mat", "key_width", fallback=9) - 6) / 2
key_mat_width = 13 * config.getfloat("key_mat", "key_width", fallback=9) + 12 * config.getfloat("key_mat", "padding", fallback=1) + 2 * config.getfloat("key_mat", "margin", fallback=1)
# TODO: fix x of pcb
full_model = components["lower_case"] + translate(v=((config.getfloat("phone", "width") - PCB_WIDTH) / 2, config.getfloat("phone", "corner_radius") / 2, bottom_cover_thickness))(
components["pcb"]
) + translate(v=(
pcb_margin_x + config.getfloat("phone", "corner_radius", fallback=10) / 2 - config.getfloat("key_mat", "margin", fallback=1) - (config.getfloat("key_mat", "key_width", fallback=9) - alps_width) / 2,
pcb_margin_y + config.getfloat("phone", "corner_radius", fallback=10) / 2 - config.getfloat("key_mat", "margin", fallback=1) - (config.getfloat("key_mat", "key_height", fallback=6) - alps_height) / 2,
alps_thickness + pcb_thickness + bottom_cover_thickness))(
components["key_mat"]
)
# config.getfloat("phone", "width") - key_mat_width) / 2,
# 3 + config.getfloat("key_mat", "margin", fallback=1) + (config.getfloat("key_mat", "key_height", fallback=6) - 4) / 2 ,
# 1.78
scad_render_to_file(
full_model,
filepath=f"mkbd65.scad",
file_header=f'$fn = {detail};',
include_orig_code=False
)
for component in components.keys():
print(f"Rendering component {component}...")
scad_render_to_file(
components[component],
filepath=f"mkbd65_{component}.scad",
file_header=f'$fn = {detail};',
include_orig_code=False
)
if stl:
print(f"Generate STL for component {component}...")
run(["openscad", "-o", f"mkbd65_{component}.stl", f"mkbd65_{component}.scad"])
if emf:
print(f"Generate 3MF for component {component}...")
run(["openscad", "-o", f"mkbd65_{component}.3mf", f"mkbd65_{component}.scad"])
if amf:
print(f"Generate AMF for component {component}...")
run(["openscad", "-o", f"mkbd65_{component}.amf", f"mkbd65_{component}.scad"])
if __name__ == "__main__":
cli()