From 7f9e6386a5b7c0c30cacb1c963fdd676645f0637 Mon Sep 17 00:00:00 2001 From: Joshua Shreve Date: Wed, 7 Jul 2021 21:11:14 -0400 Subject: Temporary version as the cadquery and solid python versions are merged by use of helper functions. Added a screw to the thumb cluster. Cadquery baseplate now has counterbores and actual solid geometry that is autogenerated, which is not possible in solid/OpenSCAD by the current methodology as it requires finding and extruding edges. --- src/dactyl_manuform_solid.py | 2373 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2373 insertions(+) create mode 100644 src/dactyl_manuform_solid.py (limited to 'src/dactyl_manuform_solid.py') diff --git a/src/dactyl_manuform_solid.py b/src/dactyl_manuform_solid.py new file mode 100644 index 0000000..07e2450 --- /dev/null +++ b/src/dactyl_manuform_solid.py @@ -0,0 +1,2373 @@ +import solid as sl +import numpy as np +from numpy import pi +import os.path as path +import os +import json + +def deg2rad(degrees: float) -> float: + return degrees * pi / 180 + + +def rad2deg(rad: float) -> float: + return rad * 180 / pi + + + +## IMPORT DEFAULT CONFIG IN CASE NEW PARAMETERS EXIST +import src.generate_configuration as cfg +for item in cfg.shape_config: + locals()[item] = cfg.shape_config[item] + +## LOAD RUN CONFIGURATION FILE +with open('run_config.json', mode='r') as fid: + data = json.load(fid) +for item in data: + locals()[item] = data[item] + +if oled_mount_type is not None: + for item in oled_configurations[oled_mount_type]: + locals()[item] = oled_configurations[oled_mount_type][item] + +if nrows > 5: + column_style = column_style_gt5 + +centerrow = nrows - centerrow_offset + +lastrow = nrows - 1 +cornerrow = lastrow - 1 +lastcol = ncols - 1 + +# Derived values +if plate_style in ['NUB', 'HS_NUB']: + keyswitch_height = nub_keyswitch_height + keyswitch_width = nub_keyswitch_width +elif plate_style in ['UNDERCUT', 'HS_UNDERCUT']: + keyswitch_height = undercut_keyswitch_height + keyswitch_width = undercut_keyswitch_width +else: + keyswitch_height = hole_keyswitch_height + keyswitch_width = hole_keyswitch_width + +if plate_style in ['HS_UNDERCUT', 'HS_NUB', 'HS_HOLE']: + symmetry = "asymmetric" + plate_file = path.join("..", "src", r"hot_swap_plate.stl") + plate_offset = 0.0 + +mount_width = keyswitch_width + 3 +mount_height = keyswitch_height + 3 +mount_thickness = plate_thickness + +if oled_mount_type is not None: + left_wall_x_offset = oled_left_wall_x_offset_override + left_wall_z_offset = oled_left_wall_z_offset_override + + +spath = path.join("..", "things", save_dir) +if not path.isdir(spath): + os.mkdir(spath) + +def column_offset(column: int) -> list: + return column_offsets[column] + + +def single_plate(cylinder_segments=100, side="right"): + if plate_style in ['NUB', 'HS_NUB']: + top_wall = sl.cube([mount_width, 1.5, plate_thickness], center=True) + top_wall = sl.translate( + (0, (1.5 / 2) + (keyswitch_height / 2), plate_thickness / 2) + )(top_wall) + + left_wall = sl.cube([1.5, mount_height, plate_thickness], center=True) + left_wall = sl.translate( + ((1.5 / 2) + (keyswitch_width / 2), 0, plate_thickness / 2) + )(left_wall) + + side_nub = sl.cylinder(1, 2.75, segments=cylinder_segments, center=True) + side_nub = sl.rotate(rad2deg(pi / 2), [1, 0, 0])(side_nub) + side_nub = sl.translate((keyswitch_width / 2, 0, 1))(side_nub) + nub_cube = sl.cube([1.5, 2.75, plate_thickness], center=True) + nub_cube = sl.translate( + ((1.5 / 2) + (keyswitch_width / 2), 0, plate_thickness / 2) + )(nub_cube) + + side_nub = sl.hull()(side_nub, nub_cube) + + plate_half1 = top_wall + left_wall + side_nub + plate_half2 = plate_half1 + plate_half2 = sl.mirror([0, 1, 0])(plate_half2) + plate_half2 = sl.mirror([1, 0, 0])(plate_half2) + + plate = plate_half1 + plate_half2 + + + else: # 'HOLE' or default, square cutout for non-nub designs. + plate = sl.cube([mount_width, mount_height, mount_thickness], center=True) + plate = sl.translate((0.0, 0.0, mount_thickness / 2.0))(plate) + shape_cut = sl.cube([keyswitch_width, keyswitch_height, mount_thickness * 2], center=True) + shape_cut = sl.translate((0.0, 0.0, mount_thickness))(shape_cut) + plate = sl.difference()(plate, shape_cut) + + if plate_style in ['UNDERCUT', 'HS_UNDERCUT']: + undercut = sl.cube([ + keyswitch_width + 2 * clip_undercut, + keyswitch_height + 2 * clip_undercut, + mount_thickness + ], center=True) + + undercut = sl.translate((0.0, 0.0, -clip_thickness + mount_thickness / 2.0))(undercut) + + plate = sl.difference()(plate, undercut) + + if plate_file is not None: + socket = sl.import_(plate_file) + socket = sl.translate([0.0, 0.0, plate_thickness + plate_offset])(socket) + + plate = sl.union()(plate, socket) + + if side == "left": + plate = sl.mirror([-1, 0, 0])(plate) + + return plate + + +################ +## SA Keycaps ## +################ + +sa_length = 18.25 +sa_double_length = 37.5 + + +def sa_cap(Usize=1): + # MODIFIED TO NOT HAVE THE ROTATION. NEEDS ROTATION DURING ASSEMBLY + sa_length = 18.25 + + if Usize == 1: + bl2 = 18.5/2 + bw2 = 18.5/2 + m = 17 / 2 + pl2 = 6 + pw2 = 6 + + elif Usize == 2: + bl2 = sa_length + bw2 = sa_length / 2 + m = 0 + pl2 = 16 + pw2 = 6 + + elif Usize == 1.5: + bl2 = sa_length / 2 + bw2 = 27.94 / 2 + m = 0 + pl2 = 6 + pw2 = 11 + + + k1 = sl.polygon([[bw2, bl2], [bw2, -bl2], [-bw2, -bl2], [-bw2, bl2]]) + k1 = sl.linear_extrude(height=0.1, twist=0, convexity=0, center=True)(k1) + k1 = sl.translate([0, 0, 0.05])(k1) + k2 = sl.polygon([[pw2, pl2], [pw2, -pl2], [-pw2, -pl2], [-pw2, pl2]]) + k2 = sl.linear_extrude(height=0.1, twist=0, convexity=0, center=True)(k2) + k2 = sl.translate([0, 0, 12.0])(k2) + if m > 0: + m1 = sl.polygon([[m, m], [m, -m], [-m, -m], [-m, m]]) + m1 = sl.linear_extrude(height=0.1, twist=0, convexity=0, center=True)(m1) + m1 = sl.translate([0, 0, 6.0])(m1) + key_cap = sl.hull()(k1, k2, m1) + else: + key_cap = sl.hull()(k1, k2) + + # key_cap = sl.translate([0, 0, 5 + plate_thickness])(key_cap) + key_cap = sl.color([220 / 255, 163 / 255, 163 / 255, 1])(key_cap) + + return key_cap + + +######################### +## Placement Functions ## +######################### + + +def rotate_around_x(position, angle): + # print((position, angle)) + t_matrix = np.array( + [ + [1, 0, 0], + [0, np.cos(angle), -np.sin(angle)], + [0, np.sin(angle), np.cos(angle)], + ] + ) + return np.matmul(t_matrix, position) + + +def rotate_around_y(position, angle): + # print((position, angle)) + t_matrix = np.array( + [ + [np.cos(angle), 0, np.sin(angle)], + [0, 1, 0], + [-np.sin(angle), 0, np.cos(angle)], + ] + ) + return np.matmul(t_matrix, position) + + +cap_top_height = plate_thickness + sa_profile_key_height +row_radius = ((mount_height + extra_height) / 2) / (np.sin(alpha / 2)) + cap_top_height +column_radius = ( + ((mount_width + extra_width) / 2) / (np.sin(beta / 2)) + ) + cap_top_height +column_x_delta = -1 - column_radius * np.sin(beta) +column_base_angle = beta * (centercol - 2) + +def offset_for_column(col, row): + if pinky_1_5U and ( + col == lastcol and row <= last_1_5U and row >= first_1_5U + ): + return 4.7625 + else: + return 0 + +def apply_key_geometry( + shape, + translate_fn, + rotate_x_fn, + rotate_y_fn, + column, + row, + column_style=column_style, +): + column_angle = beta * (centercol - column) + + if column_style == "orthographic": + column_z_delta = column_radius * (1 - np.cos(column_angle)) + shape = translate_fn(shape, [0, 0, -row_radius]) + shape = rotate_x_fn(shape, alpha * (centerrow - row)) + shape = translate_fn(shape, [0, 0, row_radius]) + shape = rotate_y_fn(shape, column_angle) + shape = translate_fn( + shape, [-(column - centercol) * column_x_delta, 0, column_z_delta] + ) + shape = translate_fn(shape, column_offset(column)) + + elif column_style == "fixed": + shape = rotate_y_fn(shape, fixed_angles[column]) + shape = translate_fn(shape, [fixed_x[column], 0, fixed_z[column]]) + shape = translate_fn(shape, [0, 0, -(row_radius + fixed_z[column])]) + shape = rotate_x_fn(shape, alpha * (centerrow - row)) + shape = translate_fn(shape, [0, 0, row_radius + fixed_z[column]]) + shape = rotate_y_fn(shape, fixed_tenting) + shape = translate_fn(shape, [0, column_offset(column)[1], 0]) + + else: + shape = translate_fn(shape, [offset_for_column(column, row), 0, -row_radius]) + shape = rotate_x_fn(shape, alpha * (centerrow - row)) + shape = translate_fn(shape, [0, 0, row_radius]) + shape = translate_fn(shape, [0, 0, -column_radius]) + shape = rotate_y_fn(shape, column_angle) + shape = translate_fn(shape, [0, 0, column_radius]) + shape = translate_fn(shape, column_offset(column)) + + shape = rotate_y_fn(shape, tenting_angle) + shape = translate_fn(shape, [0, 0, keyboard_z_offset]) + + return shape + + +def translate(shape, xyz): + return sl.translate(xyz)(shape) + + +def x_rot(shape, angle): + return sl.rotate(rad2deg(angle), [1, 0, 0])(shape) + + +def y_rot(shape, angle): + return sl.rotate(rad2deg(angle), [0, 1, 0])(shape) + + +def key_place(shape, column, row): + return apply_key_geometry(shape, translate, x_rot, y_rot, column, row) + + +def add_translate(shape, xyz): + vals = [] + for i in range(len(shape)): + vals.append(shape[i] + xyz[i]) + return vals + + +def key_position(position, column, row): + return apply_key_geometry( + position, add_translate, rotate_around_x, rotate_around_y, column, row + ) + + +def key_holes(side="right"): + hole = single_plate(side=side) + holes = [] + for column in range(ncols): + for row in range(nrows): + if (column in [2, 3]) or (not row == lastrow): + holes.append(key_place(hole, column, row)) + + return sl.union()(*holes) + + +def caps(): + caps = [] + for column in range(ncols): + for row in range(nrows): + if (column in [2, 3]) or (not row == lastrow): + caps.append(key_place(sa_cap(), column, row)) + + return sl.union()(*caps) + + +#################### +## Web Connectors ## +#################### + + +def web_post(): + post = sl.cube([post_size, post_size, web_thickness], center=True) + post = sl.translate([0, 0, plate_thickness - (web_thickness / 2)])(post) + return post + + +post_adj = post_size / 2 + + +def web_post_tr(wide=False): + if wide: + w_divide = 1.2 + else: + w_divide = 2.0 + return sl.translate( + [(mount_width / w_divide) - post_adj, (mount_height / 2) - post_adj, 0] + )(web_post()) + +def web_post_tl(wide=False): + if wide: + w_divide = 1.2 + else: + w_divide = 2.0 + return sl.translate( + [-(mount_width / w_divide) + post_adj, (mount_height / 2) - post_adj, 0] + )(web_post()) + + +def web_post_bl(wide=False): + if wide: + w_divide = 1.2 + else: + w_divide = 2.0 + return sl.translate( + [-(mount_width / w_divide) + post_adj, -(mount_height / 2) + post_adj, 0] + )(web_post()) + + +def web_post_br(wide=False): + if wide: + w_divide = 1.2 + else: + w_divide = 2.0 + return sl.translate( + [(mount_width / w_divide) - post_adj, -(mount_height / 2) + post_adj, 0] + )(web_post()) + + + + +def triangle_hulls(shapes): + hulls = [] + for i in range(len(shapes) - 2): + hulls.append(sl.hull()(*shapes[i: (i + 3)])) + + return sl.union()(*hulls) + + +def connectors(): + hulls = [] + for column in range(ncols - 1): + for row in range(lastrow): # need to consider last_row? + # for row in range(nrows): # need to consider last_row? + places = [] + places.append(key_place(web_post_tl(), column + 1, row)) + places.append(key_place(web_post_tr(), column, row)) + places.append(key_place(web_post_bl(), column + 1, row)) + places.append(key_place(web_post_br(), column, row)) + hulls.append(triangle_hulls(places)) + + for column in range(ncols): + # for row in range(nrows-1): + for row in range(cornerrow): + places = [] + places.append(key_place(web_post_bl(), column, row)) + places.append(key_place(web_post_br(), column, row)) + places.append(key_place(web_post_tl(), column, row + 1)) + places.append(key_place(web_post_tr(), column, row + 1)) + hulls.append(triangle_hulls(places)) + + for column in range(ncols - 1): + # for row in range(nrows-1): # need to consider last_row? + for row in range(cornerrow): # need to consider last_row? + places = [] + places.append(key_place(web_post_br(), column, row)) + places.append(key_place(web_post_tr(), column, row + 1)) + places.append(key_place(web_post_bl(), column + 1, row)) + places.append(key_place(web_post_tl(), column + 1, row + 1)) + hulls.append(triangle_hulls(places)) + + return sl.union()(*hulls) + + +############ +## Thumbs ## +############ + + +def thumborigin(): + origin = key_position([mount_width / 2, -(mount_height / 2), 0], 1, cornerrow) + for i in range(len(origin)): + origin[i] = origin[i] + thumb_offsets[i] + return origin + + +def thumb_tr_place(shape): + shape = sl.rotate(10, [1, 0, 0])(shape) + shape = sl.rotate(-23, [0, 1, 0])(shape) + shape = sl.rotate(10, [0, 0, 1])(shape) + shape = sl.translate(thumborigin())(shape) + shape = sl.translate([-12, -16, 3])(shape) + return shape + + +def thumb_tl_place(shape): + shape = sl.rotate(10, [1, 0, 0])(shape) + shape = sl.rotate(-23, [0, 1, 0])(shape) + shape = sl.rotate(10, [0, 0, 1])(shape) + shape = sl.translate(thumborigin())(shape) + shape = sl.translate([-32, -15, -2])(shape) + return shape + + +def thumb_mr_place(shape): + shape = sl.rotate(-6, [1, 0, 0])(shape) + shape = sl.rotate(-34, [0, 1, 0])(shape) + shape = sl.rotate(48, [0, 0, 1])(shape) + shape = sl.translate(thumborigin())(shape) + shape = sl.translate([-29, -40, -13])(shape) + return shape + + +def thumb_ml_place(shape): + shape = sl.rotate(6, [1, 0, 0])(shape) + shape = sl.rotate(-34, [0, 1, 0])(shape) + shape = sl.rotate(40, [0, 0, 1])(shape) + shape = sl.translate(thumborigin())(shape) + shape = sl.translate([-51, -25, -12])(shape) + return shape + + +def thumb_br_place(shape): + shape = sl.rotate(-16, [1, 0, 0])(shape) + shape = sl.rotate(-33, [0, 1, 0])(shape) + shape = sl.rotate(54, [0, 0, 1])(shape) + shape = sl.translate(thumborigin())(shape) + shape = sl.translate([-37.8, -55.3, -25.3])(shape) + return shape + + +def thumb_bl_place(shape): + shape = sl.rotate(-4, [1, 0, 0])(shape) + shape = sl.rotate(-35, [0, 1, 0])(shape) + shape = sl.rotate(52, [0, 0, 1])(shape) + shape = sl.translate(thumborigin())(shape) + shape = sl.translate([-56.3, -43.3, -23.5])(shape) + return shape + + +def thumb_1x_layout(shape): + return sl.union()( + thumb_mr_place(shape), + thumb_ml_place(shape), + thumb_br_place(shape), + thumb_bl_place(shape), + ) + + +def thumb_15x_layout(shape): + return sl.union()(thumb_tr_place(shape), thumb_tl_place(shape)) + + +def double_plate_half(): + plate_height = (sa_double_length - mount_height) / 3 + top_plate = sl.cube([mount_width, plate_height, web_thickness], center=True) + top_plate = sl.translate( + [0, (plate_height + mount_height) / 2, plate_thickness - (web_thickness / 2)] + )(top_plate) + return top_plate + + +def double_plate(): + top_plate = double_plate_half() + return sl.union()(top_plate, sl.mirror([0, 1, 0])(top_plate)) + +def thumbcaps(): + if thumb_style == "MINI": + return mini_thumbcaps() + elif thumb_style == "CARBONFET": + return carbonfet_thumbcaps() + else: + return default_thumbcaps() + +def thumb(side="right"): + if thumb_style == "MINI": + return mini_thumb(side) + elif thumb_style == "CARBONFET": + return carbonfet_thumb(side) + else: + return default_thumb(side) + +def thumb_connectors(): + if thumb_style == "MINI": + return mini_thumb_connectors() + elif thumb_style == "CARBONFET": + return carbonfet_thumb_connectors() + else: + return default_thumb_connectors() + + +def default_thumbcaps(): + t1 = thumb_1x_layout(sa_cap(1)) + t15 = thumb_15x_layout(sl.rotate(pi / 2, [0, 0, 1])(sa_cap(1.5))) + return t1 + t15 + + + +def default_thumb(side="right"): + + shape = thumb_1x_layout(sl.rotate([0.0, 0.0, -90])(single_plate(side=side))) + shape += thumb_15x_layout(sl.rotate([0.0, 0.0, -90])(single_plate(side=side))) + shape += thumb_15x_layout(double_plate()) + + return shape + + +def thumb_post_tr(): + return sl.translate( + [(mount_width / 2) - post_adj, (mount_height / 1.15) - post_adj, 0] + )(web_post()) + + +def thumb_post_tl(): + return sl.translate( + [-(mount_width / 2) + post_adj, (mount_height / 1.15) - post_adj, 0] + )(web_post()) + + +def thumb_post_bl(): + return sl.translate( + [-(mount_width / 2) + post_adj, -(mount_height / 1.15) + post_adj, 0] + )(web_post()) + + +def thumb_post_br(): + return sl.translate( + [(mount_width / 2) - post_adj, -(mount_height / 1.15) + post_adj, 0] + )(web_post()) + + +def default_thumb_connectors(): + hulls = [] + + # Top two + hulls.append( + triangle_hulls( + [ + thumb_tl_place(thumb_post_tr()), + thumb_tl_place(thumb_post_br()), + thumb_tr_place(thumb_post_tl()), + thumb_tr_place(thumb_post_bl()), + ] + ) + ) + + # bottom two on the right + hulls.append( + triangle_hulls( + [ + thumb_br_place(web_post_tr()), + thumb_br_place(web_post_br()), + thumb_mr_place(web_post_tl()), + thumb_mr_place(web_post_bl()), + ] + ) + ) + + # bottom two on the left + hulls.append( + triangle_hulls( + [ + thumb_br_place(web_post_tr()), + thumb_br_place(web_post_br()), + thumb_mr_place(web_post_tl()), + thumb_mr_place(web_post_bl()), + ] + ) + ) + # centers of the bottom four + hulls.append( + triangle_hulls( + [ + thumb_bl_place(web_post_tr()), + thumb_bl_place(web_post_br()), + thumb_ml_place(web_post_tl()), + thumb_ml_place(web_post_bl()), + ] + ) + ) + + # top two to the middle two, starting on the left + hulls.append( + triangle_hulls( + [ + thumb_br_place(web_post_tl()), + thumb_bl_place(web_post_bl()), + thumb_br_place(web_post_tr()), + thumb_bl_place(web_post_br()), + thumb_mr_place(web_post_tl()), + thumb_ml_place(web_post_bl()), + thumb_mr_place(web_post_tr()), + thumb_ml_place(web_post_br()), + ] + ) + ) + + # top two to the main keyboard, starting on the left + hulls.append( + triangle_hulls( + [ + thumb_tl_place(thumb_post_tl()), + thumb_ml_place(web_post_tr()), + thumb_tl_place(thumb_post_bl()), + thumb_ml_place(web_post_br()), + thumb_tl_place(thumb_post_br()), + thumb_mr_place(web_post_tr()), + thumb_tr_place(thumb_post_bl()), + thumb_mr_place(web_post_br()), + thumb_tr_place(thumb_post_br()), + ] + ) + ) + + hulls.append( + triangle_hulls( + [ + thumb_tl_place(thumb_post_tl()), + key_place(web_post_bl(), 0, cornerrow), + thumb_tl_place(thumb_post_tr()), + key_place(web_post_br(), 0, cornerrow), + thumb_tr_place(thumb_post_tl()), + key_place(web_post_bl(), 1, cornerrow), + thumb_tr_place(thumb_post_tr()), + key_place(web_post_br(), 1, cornerrow), + key_place(web_post_tl(), 2, lastrow), + key_place(web_post_bl(), 2, lastrow), + thumb_tr_place(thumb_post_tr()), + key_place(web_post_bl(), 2, lastrow), + thumb_tr_place(thumb_post_br()), + key_place(web_post_br(), 2, lastrow), + key_place(web_post_bl(), 3, lastrow), + key_place(web_post_tr(), 2, lastrow), + key_place(web_post_tl(), 3, lastrow), + key_place(web_post_bl(), 3, cornerrow), + key_place(web_post_tr(), 3, lastrow), + key_place(web_post_br(), 3, cornerrow), + key_place(web_post_bl(), 4, cornerrow), + ] + ) + ) + + hulls.append( + triangle_hulls( + [ + key_place(web_post_br(), 1, cornerrow), + key_place(web_post_tl(), 2, lastrow), + key_place(web_post_bl(), 2, cornerrow), + key_place(web_post_tr(), 2, lastrow), + key_place(web_post_br(), 2, cornerrow), + key_place(web_post_bl(), 3, cornerrow), + ] + ) + ) + + hulls.append( + triangle_hulls( + [ + key_place(web_post_tr(), 3, lastrow), + key_place(web_post_br(), 3, lastrow), + key_place(web_post_tr(), 3, lastrow), + key_place(web_post_bl(), 4, cornerrow), + ] + ) + ) + + return sl.union()(*hulls) + + +############################ +# MINI THUMB CLUSTER +############################ + + +def mini_thumb_tr_place(shape): + shape = sl.rotate(14, [1, 0, 0])(shape) + shape = sl.rotate(-15, [0, 1, 0])(shape) + shape = sl.rotate(10, [0, 0, 1])(shape) + shape = sl.translate(thumborigin())(shape) + shape = sl.translate([-15, -10, 5])(shape) + return shape + + +def mini_thumb_tl_place(shape): + shape = sl.rotate(10, [1, 0, 0])(shape) + shape = sl.rotate(-23, [0, 1, 0])(shape) + shape = sl.rotate(25, [0, 0, 1])(shape) + shape = sl.translate(thumborigin())(shape) + shape = sl.translate([-35, -16, -2])(shape) + return shape + + +def mini_thumb_mr_place(shape): + shape = sl.rotate(10, [1, 0, 0])(shape) + shape = sl.rotate(-23, [0, 1, 0])(shape) + shape = sl.rotate(25, [0, 0, 1])(shape) + shape = sl.translate(thumborigin())(shape) + shape = sl.translate([-23, -34, -6])(shape) + return shape + + +def mini_thumb_br_place(shape): + shape = sl.rotate(6, [1, 0, 0])(shape) + shape = sl.rotate(-34, [0, 1, 0])(shape) + shape = sl.rotate(35, [0, 0, 1])(shape) + shape = sl.translate(thumborigin())(shape) + shape = sl.translate([-39, -43, -16])(shape) + return shape + + +def mini_thumb_bl_place(shape): + shape = sl.rotate(6, [1, 0, 0])(shape) + shape = sl.rotate(-32, [0, 1, 0])(shape) + shape = sl.rotate(35, [0, 0, 1])(shape) + shape = sl.translate(thumborigin())(shape) + shape = sl.translate([-51, -25, -11.5])(shape) + return shape + + +def mini_thumb_1x_layout(shape): + return sl.union()( + mini_thumb_mr_place(shape), + mini_thumb_br_place(shape), + mini_thumb_tl_place(shape), + mini_thumb_bl_place(shape), + ) + + +def mini_thumb_15x_layout(shape): + return sl.union()(mini_thumb_tr_place(shape)) + + +def mini_thumbcaps(): + t1 = mini_thumb_1x_layout(sa_cap(1)) + t15 = mini_thumb_15x_layout(sl.rotate(pi / 2, [0, 0, 1])(sa_cap(1))) + return t1 + t15 + + +def mini_thumb(side="right"): + + # shape = thumb_1x_layout(sl.rotate([0.0, 0.0, -90])(single_plate(side=side))) + # shape += thumb_15x_layout(sl.rotate([0.0, 0.0, -90])(single_plate(side=side))) + shape = mini_thumb_1x_layout(single_plate(side=side)) + shape += mini_thumb_15x_layout(single_plate(side=side)) + + return shape + + +def mini_thumb_post_tr(): + return sl.translate( + [(mount_width / 2) - post_adj, (mount_height / 2) - post_adj, 0] + )(web_post()) + + +def mini_thumb_post_tl(): + return sl.translate( + [-(mount_width / 2) + post_adj, (mount_height / 2) - post_adj, 0] + )(web_post()) + + +def mini_thumb_post_bl(): + return sl.translate( + [-(mount_width / 2) + post_adj, -(mount_height / 2) + post_adj, 0] + )(web_post()) + + +def mini_thumb_post_br(): + return sl.translate( + [(mount_width / 2) - post_adj, -(mount_height / 2) + post_adj, 0] + )(web_post()) + + +def mini_thumb_connectors(): + hulls = [] + + # Top two + hulls.append( + triangle_hulls( + [ + mini_thumb_tl_place(web_post_tr()), + mini_thumb_tl_place(web_post_br()), + mini_thumb_tr_place(mini_thumb_post_tl()), + mini_thumb_tr_place(mini_thumb_post_bl()), + ] + ) + ) + + # bottom two on the right + hulls.append( + triangle_hulls( + [ + mini_thumb_br_place(web_post_tr()), + mini_thumb_br_place(web_post_br()), + mini_thumb_mr_place(web_post_tl()), + mini_thumb_mr_place(web_post_bl()), + ] + ) + ) + + # bottom two on the left + hulls.append( + triangle_hulls( + [ + mini_thumb_mr_place(web_post_tr()), + mini_thumb_mr_place(web_post_br()), + mini_thumb_tr_place(mini_thumb_post_br()), + ] + ) + ) + + # between top and bottom row + hulls.append( + triangle_hulls( + [ + mini_thumb_br_place(web_post_tl()), + mini_thumb_bl_place(web_post_bl()), + mini_thumb_br_place(web_post_tr()), + mini_thumb_bl_place(web_post_br()), + mini_thumb_mr_place(web_post_tl()), + mini_thumb_tl_place(web_post_bl()), + mini_thumb_mr_place(web_post_tr()), + mini_thumb_tl_place(web_post_br()), + mini_thumb_tr_place(web_post_bl()), + mini_thumb_mr_place(web_post_tr()), + mini_thumb_tr_place(web_post_br()), + ] + ) + ) + # top two to the main keyboard, starting on the left + hulls.append( + triangle_hulls( + [ + mini_thumb_tl_place(web_post_tl()), + mini_thumb_bl_place(web_post_tr()), + mini_thumb_tl_place(web_post_bl()), + mini_thumb_bl_place(web_post_br()), + mini_thumb_mr_place(web_post_tr()), + mini_thumb_tl_place(web_post_bl()), + mini_thumb_tl_place(web_post_br()), + mini_thumb_mr_place(web_post_tr()), + ] + ) + ) + # top two to the main keyboard, starting on the left + hulls.append( + triangle_hulls( + [ + mini_thumb_tl_place(web_post_tl()), + key_place(web_post_bl(), 0, cornerrow), + mini_thumb_tl_place(web_post_tr()), + key_place(web_post_br(), 0, cornerrow), + mini_thumb_tr_place(mini_thumb_post_tl()), + key_place(web_post_bl(), 1, cornerrow), + mini_thumb_tr_place(mini_thumb_post_tr()), + key_place(web_post_br(), 1, cornerrow), + key_place(web_post_tl(), 2, lastrow), + key_place(web_post_bl(), 2, lastrow), + mini_thumb_tr_place(mini_thumb_post_tr()), + key_place(web_post_bl(), 2, lastrow), + mini_thumb_tr_place(mini_thumb_post_br()), + key_place(web_post_br(), 2, lastrow), + key_place(web_post_bl(), 3, lastrow), + key_place(web_post_tr(), 2, lastrow), + key_place(web_post_tl(), 3, lastrow), + key_place(web_post_bl(), 3, cornerrow), + key_place(web_post_tr(), 3, lastrow), + key_place(web_post_br(), 3, cornerrow), + ] + ) + ) + + hulls.append( + triangle_hulls( + [ + key_place(web_post_br(), 1, cornerrow), + key_place(web_post_tl(), 2, lastrow), + key_place(web_post_bl(), 2, cornerrow), + key_place(web_post_tr(), 2, lastrow), + key_place(web_post_br(), 2, cornerrow), + key_place(web_post_bl(), 3, cornerrow), + ] + ) + ) + + # hulls.append( + # triangle_hulls( + # [ + # key_place(web_post_tr(), 3, lastrow), + # key_place(web_post_br(), 3, lastrow), + # key_place(web_post_tr(), 3, lastrow), + # key_place(web_post_bl(), 4, cornerrow), + # ] + # ) + # ) + + return sl.union()(*hulls) + + +############################ +# Carbonfet THUMB CLUSTER +############################ + + +def carbonfet_thumb_tl_place(shape): + shape = sl.rotate(10, [1, 0, 0])(shape) + shape = sl.rotate(-24, [0, 1, 0])(shape) + shape = sl.rotate(10, [0, 0, 1])(shape) + shape = sl.translate(thumborigin())(shape) + shape = sl.translate([-13, -9.8, 4])(shape) + + return shape + +def carbonfet_thumb_tr_place(shape): + shape = sl.rotate(6, [1, 0, 0])(shape) + shape = sl.rotate(-24, [0, 1, 0])(shape) + shape = sl.rotate(10, [0, 0, 1])(shape) + shape = sl.translate(thumborigin())(shape) + shape = sl.translate([-7.5, -29.5, 0])(shape) + return shape + +def carbonfet_thumb_ml_place(shape): + shape = sl.rotate(8, [1, 0, 0])(shape) + shape = sl.rotate(-31, [0, 1, 0])(shape) + shape = sl.rotate(14, [0, 0, 1])(shape) + shape = sl.translate(thumborigin())(shape) + shape = sl.translate([-30.5, -17, -6])(shape) + return shape + +def carbonfet_thumb_mr_place(shape): + shape = sl.rotate(4, [1, 0, 0])(shape) + shape = sl.rotate(-31, [0, 1, 0])(shape) + shape = sl.rotate(14, [0, 0, 1])(shape) + shape = sl.translate(thumborigin())(shape) + shape = sl.translate([-22.2, -41, -10.3])(shape) + return shape + +def carbonfet_thumb_br_place(shape): + shape = sl.rotate(2, [1, 0, 0])(shape) + shape = sl.rotate(-37, [0, 1, 0])(shape) + shape = sl.rotate(18, [0, 0, 1])(shape) + shape = sl.translate(thumborigin())(shape) + shape = sl.translate([-37, -46.4, -22])(shape) + return shape + +def carbonfet_thumb_bl_place(shape): + shape = sl.rotate(6, [1, 0, 0])(shape) + shape = sl.rotate(-37, [0, 1, 0])(shape) + shape = sl.rotate(18, [0, 0, 1])(shape) + shape = sl.translate(thumborigin())(shape) + shape = sl.translate([-47, -23, -19])(shape) + return shape + + +def carbonfet_thumb_1x_layout(shape): + return sl.union()( + # carbonfet_thumb_tr_place(sl.rotate(pi / 2, [0, 0, 1])(shape)), + carbonfet_thumb_tr_place(shape), + carbonfet_thumb_mr_place(shape), + carbonfet_thumb_br_place(shape), + # carbonfet_thumb_tl_place(sl.rotate(pi / 2, [0, 0, 1])(shape)), + carbonfet_thumb_tl_place(shape), + ) + + +def carbonfet_thumb_15x_layout(shape): + return sl.union()( + carbonfet_thumb_bl_place(shape), + carbonfet_thumb_ml_place(shape) + ) + + +def carbonfet_thumbcaps(): + t1 = carbonfet_thumb_1x_layout(sa_cap(1)) + t15 = carbonfet_thumb_15x_layout(sl.rotate(pi / 2, [0, 0, 1])(sa_cap(1.5))) + return t1 + t15 + + +def carbonfet_thumb(side="right"): + # shape = thumb_1x_layout(sl.rotate([0.0, 0.0, -90])(single_plate(side=side))) + # shape += thumb_15x_layout(sl.rotate([0.0, 0.0, -90])(single_plate(side=side))) + shape = carbonfet_thumb_1x_layout(single_plate(side=side)) + shape += carbonfet_thumb_15x_layout(double_plate_half()) + shape += carbonfet_thumb_15x_layout(single_plate(side=side)) + + return shape + +def carbonfet_thumb_post_tr(): + return sl.translate( + [(mount_width / 2) - post_adj, (mount_height / 1.15) - post_adj, 0] + )(web_post()) + + +def carbonfet_thumb_post_tl(): + return sl.translate( + [-(mount_width / 2) + post_adj, (mount_height / 1.15) - post_adj, 0] + )(web_post()) + + +def carbonfet_thumb_post_bl(): + return sl.translate( + [-(mount_width / 2) + post_adj, -(mount_height / 1.15) + post_adj, 0] + )(web_post()) + + +def carbonfet_thumb_post_br(): + return sl.translate( + [(mount_width / 2) - post_adj, -(mount_height / 2) + post_adj, 0] + )(web_post()) + +def carbonfet_thumb_connectors(): + hulls = [] + + # Top two + hulls.append( + triangle_hulls( + [ + carbonfet_thumb_tl_place(web_post_tl()), + carbonfet_thumb_tl_place(web_post_bl()), + carbonfet_thumb_ml_place(carbonfet_thumb_post_tr()), + carbonfet_thumb_ml_place(web_post_br()), + ] + ) + ) + + hulls.append( + triangle_hulls( + [ + carbonfet_thumb_ml_place(carbonfet_thumb_post_tl()), + carbonfet_thumb_ml_place(web_post_bl()), + carbonfet_thumb_bl_place(carbonfet_thumb_post_tr()), + carbonfet_thumb_bl_place(web_post_br()), + ] + ) + ) + + # bottom two on the right + hulls.append( + triangle_hulls( + [ + carbonfet_thumb_br_place(web_post_tr()), + carbonfet_thumb_br_place(web_post_br()), + carbonfet_thumb_mr_place(web_post_tl()), + carbonfet_thumb_mr_place(web_post_bl()), + ] + ) + ) + + # bottom two on the left + hulls.append( + triangle_hulls( + [ + carbonfet_thumb_mr_place(web_post_tr()), + carbonfet_thumb_mr_place(web_post_br()), + carbonfet_thumb_tr_place(web_post_tl()), + carbonfet_thumb_tr_place(web_post_bl()), + ] + ) + ) + hulls.append( + triangle_hulls( + [ + carbonfet_thumb_tr_place(web_post_br()), + carbonfet_thumb_tr_place(web_post_bl()), + carbonfet_thumb_mr_place(web_post_br()), + ] + ) + ) + + # between top and bottom row + hulls.append( + triangle_hulls( + [ + carbonfet_thumb_br_place(web_post_tl()), + carbonfet_thumb_bl_place(web_post_bl()), + carbonfet_thumb_br_place(web_post_tr()), + carbonfet_thumb_bl_place(web_post_br()), + carbonfet_thumb_mr_place(web_post_tl()), + carbonfet_thumb_ml_place(web_post_bl()), + carbonfet_thumb_mr_place(web_post_tr()), + carbonfet_thumb_ml_place(web_post_br()), + carbonfet_thumb_tr_place(web_post_tl()), + carbonfet_thumb_tl_place(web_post_bl()), + carbonfet_thumb_tr_place(web_post_tr()), + carbonfet_thumb_tl_place(web_post_br()), + ] + ) + ) + # top two to the main keyboard, starting on the left + hulls.append( + triangle_hulls( + [ + carbonfet_thumb_ml_place(carbonfet_thumb_post_tl()), + key_place(web_post_bl(), 0, cornerrow), + carbonfet_thumb_ml_place(carbonfet_thumb_post_tr()), + key_place(web_post_br(), 0, cornerrow), + carbonfet_thumb_tl_place(web_post_tl()), + key_place(web_post_bl(), 1, cornerrow), + carbonfet_thumb_tl_place(web_post_tr()), + key_place(web_post_br(), 1, cornerrow), + key_place(web_post_tl(), 2, lastrow), + key_place(web_post_bl(), 2, lastrow), + carbonfet_thumb_tl_place(web_post_tr()), + key_place(web_post_bl(), 2, lastrow), + carbonfet_thumb_tl_place(web_post_br()), + key_place(web_post_br(), 2, lastrow), + key_place(web_post_bl(), 3, lastrow), + carbonfet_thumb_tl_place(web_post_br()), + carbonfet_thumb_tr_place(web_post_tr()), + ] + ) + ) + + hulls.append( + triangle_hulls( + [ + key_place(web_post_tr(), 3, lastrow), + key_place(web_post_br(), 3, cornerrow), + key_place(web_post_tl(), 3, lastrow), + key_place(web_post_bl(), 3, cornerrow), + ] + ) + ) + + hulls.append( + triangle_hulls( + [ + key_place(web_post_tr(), 2, lastrow), + key_place(web_post_br(), 2, lastrow), + key_place(web_post_tl(), 3, lastrow), + key_place(web_post_bl(), 3, lastrow), + ] + ) + ) + + hulls.append( + triangle_hulls( + [ + carbonfet_thumb_tr_place(web_post_br()), + carbonfet_thumb_tr_place(web_post_tr()), + key_place(web_post_bl(), 3, lastrow), + ] + ) + ) + + hulls.append( + triangle_hulls( + [ + key_place(web_post_br(), 1, cornerrow), + key_place(web_post_tl(), 2, lastrow), + key_place(web_post_bl(), 2, cornerrow), + key_place(web_post_tr(), 2, lastrow), + key_place(web_post_br(), 2, cornerrow), + key_place(web_post_tl(), 3, lastrow), + key_place(web_post_bl(), 3, cornerrow), + ] + ) + ) + + hulls.append( + triangle_hulls( + [ + key_place(web_post_tr(), 3, lastrow), + key_place(web_post_br(), 3, lastrow), + key_place(web_post_bl(), 4, cornerrow), + ] + ) + ) + + hulls.append( + triangle_hulls( + [ + key_place(web_post_tr(), 3, lastrow), + key_place(web_post_br(), 3, cornerrow), + key_place(web_post_bl(), 4, cornerrow), + ] + ) + ) + + + return sl.union()(*hulls) + +########## +## Case ## +########## + + +def bottom_hull(p, height=0.001): + shape = None + for item in p: + proj = sl.projection()(p) + t_shape = sl.linear_extrude(height=height, twist=0, convexity=0, center=True)( + proj + ) + t_shape = sl.translate([0, 0, height / 2 - 10])(t_shape) + if shape is None: + shape = t_shape + shape = sl.hull()(p, shape, t_shape) + return shape + + +def left_key_position(row, direction): + pos = np.array( + key_position([-mount_width * 0.5, direction * mount_height * 0.5, 0], 0, row) + ) + return list(pos - np.array([left_wall_x_offset, 0, left_wall_z_offset])) + + +def left_key_place(shape, row, direction): + pos = left_key_position(row, direction) + return sl.translate(pos)(shape) + + +def wall_locate1(dx, dy): + return [dx * wall_thickness, dy * wall_thickness, -1] + + +def wall_locate2(dx, dy): + return [dx * wall_x_offset, dy * wall_y_offset, -wall_z_offset] + + +def wall_locate3(dx, dy, back=False): + if back: + return [ + dx * (wall_x_offset + wall_base_x_thickness), + dy * (wall_y_offset + wall_base_back_thickness), + -wall_z_offset, + ] + else: + return [ + dx * (wall_x_offset + wall_base_x_thickness), + dy * (wall_y_offset + wall_base_y_thickness), + -wall_z_offset, + ] + + +def wall_brace(place1, dx1, dy1, post1, place2, dx2, dy2, post2, back=False): + hulls = [] + + hulls.append(place1(post1)) + hulls.append(place1(sl.translate(wall_locate1(dx1, dy1))(post1))) + hulls.append(place1(sl.translate(wall_locate2(dx1, dy1))(post1))) + hulls.append(place1(sl.translate(wall_locate3(dx1, dy1, back))(post1))) + + hulls.append(place2(post2)) + hulls.append(place2(sl.translate(wall_locate1(dx2, dy2))(post2))) + hulls.append(place2(sl.translate(wall_locate2(dx2, dy2))(post2))) + hulls.append(place2(sl.translate(wall_locate3(dx2, dy2, back))(post2))) + shape1 = sl.hull()(*hulls) + + hulls = [] + hulls.append(place1(sl.translate(wall_locate2(dx1, dy1))(post1))) + hulls.append(place1(sl.translate(wall_locate3(dx1, dy1, back))(post1))) + hulls.append(place2(sl.translate(wall_locate2(dx2, dy2))(post2))) + hulls.append(place2(sl.translate(wall_locate3(dx2, dy2, back))(post2))) + shape2 = bottom_hull(hulls) + + return shape1 + shape2 + + +def key_wall_brace(x1, y1, dx1, dy1, post1, x2, y2, dx2, dy2, post2, back=False): + return wall_brace( + (lambda shape: key_place(shape, x1, y1)), + dx1, + dy1, + post1, + (lambda shape: key_place(shape, x2, y2)), + dx2, + dy2, + post2, + back + ) + + +def back_wall(): + x = 0 + shape = key_wall_brace(x, 0, 0, 1, web_post_tl(), x, 0, 0, 1, web_post_tr(), back=True) + for i in range(ncols - 1): + x = i + 1 + shape += key_wall_brace(x, 0, 0, 1, web_post_tl(), x, 0, 0, 1, web_post_tr(), back=True) + shape += key_wall_brace( + x, 0, 0, 1, web_post_tl(), x - 1, 0, 0, 1, web_post_tr(), back=True + ) + shape += key_wall_brace( + lastcol, 0, 0, 1, web_post_tr(), lastcol, 0, 1, 0, web_post_tr(), back=True + ) + return shape + + +def right_wall(): + if pinky_1_5U: + if first_1_5U_row > 0: + shape = key_wall_brace( + lastcol, 0, 0, 1, web_post_tr(), lastcol, 0, 1, 0, web_post_tr()) + else: + shape = key_wall_brace( + lastcol, 0, 0, 1, web_post_tr(), lastcol, 0, 0, 1, web_post_tr(wide=True)) + shape += key_wall_brace( + lastcol, 0, 0, 1, web_post_tr(), lastcol, 0, 1, 0, web_post_tr(wide=True)) + + shape += key_wall_brace( + lastcol, 0, 0, -1, web_post_br(), lastcol, 0, 1, 0, web_post_br()) + + if first_1_5U_row >= 2: + for y in range(first_1_5U_row - 1): + shape += key_wall_brace( + lastcol, y, 1, 0, web_post_tr(), lastcol, y, 1, 0, web_post_br()) + shape += key_wall_brace( + lastcol, y, 1, 0, web_post_br(), lastcol, y-1, 1, 0, web_post_tr()) + + if first_1_5U_row >= 1: + for i in range(2): + y = first_1_5U_row - 1 + i + shape += key_wall_brace( + lastcol, y, 1, 0, web_post_tr(), lastcol, y-1, 1, 0, web_post_tr(wide=True)) + + for i in range(2): + y = first_1_5U_row + i + shape += key_wall_brace( + lastcol, y, 1, 0, web_post_tr(wide=True), lastcol, y, 1, 0, web_post_br(wide=True)) + + for i in range(first_1_5U_row - last_1_5U_row): + y = first_1_5U_row + i + shape += key_wall_brace( + lastcol, y+1, 1, 0, web_post_tr(wide=True), lastcol, y, 1, 0, web_post_br(wide=True)) + + if first_1_5U_row >= 1: + for i in range(2): + y = first_1_5U_row - 1 + i + shape += key_wall_brace( + lastcol, y, 1, 0, web_post_tr(), lastcol, y-1, 1, 0, web_post_tr(wide=True)) + + else: + y = 0 + shape = key_wall_brace( + lastcol, y, 1, 0, web_post_tr(), lastcol, y, 1, 0, web_post_br() + ) + for i in range(lastrow - 1): + y = i + 1 + shape += key_wall_brace( + lastcol, y - 1, 1, 0, web_post_br(), lastcol, y, 1, 0, web_post_tr()) + + shape += key_wall_brace( + lastcol, y, 1, 0, web_post_tr(), lastcol, y, 1, 0, web_post_br()) + + shape += key_wall_brace( + lastcol, cornerrow, 0, -1, web_post_br(), lastcol, cornerrow, 1, 0, web_post_br()) + + return shape + + +def left_wall(): + shape = wall_brace( + (lambda sh: key_place(sh, 0, 0)), + 0, + 1, + web_post_tl(), + (lambda sh: left_key_place(sh, 0, 1)), + 0, + 1, + web_post(), + ) + + shape += wall_brace( + (lambda sh: left_key_place(sh, 0, 1)), + 0, + 1, + web_post(), + (lambda sh: left_key_place(sh, 0, 1)), + -1, + 0, + web_post(), + ) + + for i in range(lastrow): + y = i + temp_shape1 = wall_brace( + (lambda sh: left_key_place(sh, y, 1)), + -1, + 0, + web_post(), + (lambda sh: left_key_place(sh, y, -1)), + -1, + 0, + web_post(), + ) + temp_shape2 = sl.hull()( + key_place(web_post_tl(), 0, y), + key_place(web_post_bl(), 0, y), + left_key_place(web_post(), y, 1), + left_key_place(web_post(), y, -1), + ) + shape += temp_shape1 + temp_shape2 + + for i in range(lastrow - 1): + y = i + 1 + temp_shape1 = wall_brace( + (lambda sh: left_key_place(sh, y - 1, -1)), + -1, + 0, + web_post(), + (lambda sh: left_key_place(sh, y, 1)), + -1, + 0, + web_post(), + ) + temp_shape2 = sl.hull()( + key_place(web_post_tl(), 0, y), + key_place(web_post_bl(), 0, y - 1), + left_key_place(web_post(), y, 1), + left_key_place(web_post(), y - 1, -1), + ) + shape += temp_shape1 + temp_shape2 + + return shape + + +def front_wall(): + shape = key_wall_brace( + lastcol, 0, 0, 1, web_post_tr(), lastcol, 0, 1, 0, web_post_tr() + ) + shape += key_wall_brace( + 3, lastrow, 0, -1, web_post_bl(), 3, lastrow, 0.5, -1, web_post_br() + ) + shape += key_wall_brace( + 3, lastrow, 0.5, -1, web_post_br(), 4, cornerrow, 1, -1, web_post_bl() + ) + for i in range(ncols - 4): + x = i + 4 + shape += key_wall_brace( + x, cornerrow, 0, -1, web_post_bl(), x, cornerrow, 0, -1, web_post_br() + ) + for i in range(ncols - 5): + x = i + 5 + shape += key_wall_brace( + x, cornerrow, 0, -1, web_post_bl(), x - 1, cornerrow, 0, -1, web_post_br() + ) + + return shape + +def thumb_walls(): + if thumb_style == "MINI": + return mini_thumb_walls() + elif thumb_style == "CARBONFET": + return carbonfet_thumb_walls() + else: + return default_thumb_walls() + +def thumb_connection(): + if thumb_style == "MINI": + return mini_thumb_connection() + elif thumb_style == "CARBONFET": + return carbonfet_thumb_connection() + else: + return default_thumb_connection() + +def default_thumb_walls(): + # thumb, walls + shape = wall_brace(thumb_mr_place, 0, -1, web_post_br(), thumb_tr_place, 0, -1, thumb_post_br()) + shape += wall_brace(thumb_mr_place, 0, -1, web_post_br(), thumb_mr_place, 0, -1, web_post_bl()) + shape += wall_brace(thumb_br_place, 0, -1, web_post_br(), thumb_br_place, 0, -1, web_post_bl()) + shape += wall_brace(thumb_ml_place, -0.3, 1, web_post_tr(), thumb_ml_place, 0, 1, web_post_tl()) + shape += wall_brace(thumb_bl_place, 0, 1, web_post_tr(), thumb_bl_place, 0, 1, web_post_tl()) + shape += wall_brace(thumb_br_place, -1, 0, web_post_tl(), thumb_br_place, -1, 0, web_post_bl()) + shape += wall_brace(thumb_bl_place, -1, 0, web_post_tl(), thumb_bl_place, -1, 0, web_post_bl()) + # thumb, corners + shape += wall_brace(thumb_br_place, -1, 0, web_post_bl(), thumb_br_place, 0, -1, web_post_bl()) + shape += wall_brace(thumb_bl_place, -1, 0, web_post_tl(), thumb_bl_place, 0, 1, web_post_tl()) + # thumb, tweeners + shape += wall_brace(thumb_mr_place, 0, -1, web_post_bl(), thumb_br_place, 0, -1, web_post_br()) + shape += wall_brace(thumb_ml_place, 0, 1, web_post_tl(), thumb_bl_place, 0, 1, web_post_tr()) + shape += wall_brace(thumb_bl_place, -1, 0, web_post_bl(), thumb_br_place, -1, 0, web_post_tl()) + shape += wall_brace(thumb_tr_place, 0, -1, thumb_post_br(), (lambda sh: key_place(sh, 3, lastrow)), 0, -1, web_post_bl()) + + return shape + +def default_thumb_connection(): + # clunky bit on the top left thumb connection (normal connectors don't work well) + shape = bottom_hull( + [ + left_key_place(sl.translate(wall_locate2(-1, 0))(web_post()), cornerrow, -1), + left_key_place(sl.translate(wall_locate3(-1, 0))(web_post()), cornerrow, -1), + thumb_ml_place(sl.translate(wall_locate2(-0.3, 1))(web_post_tr())), + thumb_ml_place(sl.translate(wall_locate3(-0.3, 1))(web_post_tr())), + ] + ) + + shape += sl.hull()( + [ + left_key_place(sl.translate(wall_locate2(-1, 0))(web_post()), cornerrow, -1), + left_key_place(sl.translate(wall_locate3(-1, 0))(web_post()), cornerrow, -1), + thumb_ml_place(sl.translate(wall_locate2(-0.3, 1))(web_post_tr())), + thumb_ml_place(sl.translate(wall_locate3(-0.3, 1))(web_post_tr())), + thumb_tl_place(thumb_post_tl()), + ] + ) + + shape += sl.hull()( + [ + left_key_place(web_post(), cornerrow, -1), + left_key_place(sl.translate(wall_locate1(-1, 0))(web_post()), cornerrow, -1), + left_key_place(sl.translate(wall_locate2(-1, 0))(web_post()), cornerrow, -1), + left_key_place(sl.translate(wall_locate3(-1, 0))(web_post()), cornerrow, -1), + thumb_tl_place(thumb_post_tl()), + ] + ) + + shape += sl.hull()( + [ + left_key_place(web_post(), cornerrow, -1), + left_key_place(sl.translate(wall_locate1(-1, 0))(web_post()), cornerrow, -1), + key_place(web_post_bl(), 0, cornerrow), + # key_place(sl.translate(wall_locate1(-1, 0))(web_post_bl()), 0, cornerrow), + key_place(sl.translate(wall_locate1(0, 0))(web_post_bl()), 0, cornerrow), + thumb_tl_place(thumb_post_tl()), + ] + ) + + shape += sl.hull()( + [ + thumb_ml_place(web_post_tr()), + thumb_ml_place(sl.translate(wall_locate1(-0.3, 1))(web_post_tr())), + thumb_ml_place(sl.translate(wall_locate2(-0.3, 1))(web_post_tr())), + thumb_ml_place(sl.translate(wall_locate3(-0.3, 1))(web_post_tr())), + thumb_tl_place(thumb_post_tl()), + ] + ) + + return shape + + +def mini_thumb_walls(): + # thumb, walls + shape = wall_brace(mini_thumb_mr_place, 0, -1, web_post_br(), mini_thumb_tr_place, 0, -1, mini_thumb_post_br()) + shape += wall_brace(mini_thumb_mr_place, 0, -1, web_post_br(), mini_thumb_mr_place, 0, -1, web_post_bl()) + shape += wall_brace(mini_thumb_br_place, 0, -1, web_post_br(), mini_thumb_br_place, 0, -1, web_post_bl()) + shape += wall_brace(mini_thumb_bl_place, 0, 1, web_post_tr(), mini_thumb_bl_place, 0, 1, web_post_tl()) + shape += wall_brace(mini_thumb_br_place, -1, 0, web_post_tl(), mini_thumb_br_place, -1, 0, web_post_bl()) + shape += wall_brace(mini_thumb_bl_place, -1, 0, web_post_tl(), mini_thumb_bl_place, -1, 0, web_post_bl()) + # thumb, corners + shape += wall_brace(mini_thumb_br_place, -1, 0, web_post_bl(), mini_thumb_br_place, 0, -1, web_post_bl()) + shape += wall_brace(mini_thumb_bl_place, -1, 0, web_post_tl(), mini_thumb_bl_place, 0, 1, web_post_tl()) + # thumb, tweeners + shape += wall_brace(mini_thumb_mr_place, 0, -1, web_post_bl(), mini_thumb_br_place, 0, -1, web_post_br()) + shape += wall_brace(mini_thumb_bl_place, -1, 0, web_post_bl(), mini_thumb_br_place, -1, 0, web_post_tl()) + shape += wall_brace(mini_thumb_tr_place, 0, -1, mini_thumb_post_br(), (lambda sh: key_place(sh, 3, lastrow)), 0, -1, web_post_bl()) + + return shape + +def mini_thumb_connection(): + # clunky bit on the top left thumb connection (normal connectors don't work well) + shape = bottom_hull( + [ + left_key_place(sl.translate(wall_locate2(-1, 0))(web_post()), cornerrow, -1), + left_key_place(sl.translate(wall_locate3(-1, 0))(web_post()), cornerrow, -1), + mini_thumb_bl_place(sl.translate(wall_locate2(-0.3, 1))(web_post_tr())), + mini_thumb_bl_place(sl.translate(wall_locate3(-0.3, 1))(web_post_tr())), + ] + ) + + shape += sl.hull()( + [ + left_key_place(sl.translate(wall_locate2(-1, 0))(web_post()), cornerrow, -1), + left_key_place(sl.translate(wall_locate3(-1, 0))(web_post()), cornerrow, -1), + mini_thumb_bl_place(sl.translate(wall_locate2(-0.3, 1))(web_post_tr())), + mini_thumb_bl_place(sl.translate(wall_locate3(-0.3, 1))(web_post_tr())), + mini_thumb_tl_place(web_post_tl()), + ] + ) + + shape += sl.hull()( + [ + left_key_place(web_post(), cornerrow, -1), + left_key_place(sl.translate(wall_locate1(-1, 0))(web_post()), cornerrow, -1), + left_key_place(sl.translate(wall_locate2(-1, 0))(web_post()), cornerrow, -1), + left_key_place(sl.translate(wall_locate3(-1, 0))(web_post()), cornerrow, -1), + mini_thumb_tl_place(web_post_tl()), + ] + ) + + shape += sl.hull()( + [ + left_key_place(web_post(), cornerrow, -1), + left_key_place(sl.translate(wall_locate1(-1, 0))(web_post()), cornerrow, -1), + key_place(web_post_bl(), 0, cornerrow), + # key_place(sl.translate(wall_locate1(-1, 0))(web_post_bl()), 0, cornerrow), + mini_thumb_tl_place(web_post_tl()), + ] + ) + + shape += sl.hull()( + [ + mini_thumb_bl_place(web_post_tr()), + mini_thumb_bl_place(sl.translate(wall_locate1(-0.3, 1))(web_post_tr())), + mini_thumb_bl_place(sl.translate(wall_locate2(-0.3, 1))(web_post_tr())), + mini_thumb_bl_place(sl.translate(wall_locate3(-0.3, 1))(web_post_tr())), + mini_thumb_tl_place(web_post_tl()), + ] + ) + + return shape + + + +def carbonfet_thumb_walls(): + # thumb, walls + shape = wall_brace(carbonfet_thumb_mr_place, 0, -1, web_post_br(), carbonfet_thumb_tr_place, 0, -1, web_post_br()) + shape += wall_brace(carbonfet_thumb_mr_place, 0, -1, web_post_br(), carbonfet_thumb_mr_place, 0, -1.15, web_post_bl()) + shape += wall_brace(carbonfet_thumb_br_place, 0, -1, web_post_br(), carbonfet_thumb_br_place, 0, -1, web_post_bl()) + shape += wall_brace(carbonfet_thumb_bl_place, -.3, 1, thumb_post_tr(), carbonfet_thumb_bl_place, 0, 1, thumb_post_tl()) + shape += wall_brace(carbonfet_thumb_br_place, -1, 0, web_post_tl(), carbonfet_thumb_br_place, -1, 0, web_post_bl()) + shape += wall_brace(carbonfet_thumb_bl_place, -1, 0, thumb_post_tl(), carbonfet_thumb_bl_place, -1, 0, web_post_bl()) + # thumb, corners + shape += wall_brace(carbonfet_thumb_br_place, -1, 0, web_post_bl(), carbonfet_thumb_br_place, 0, -1, web_post_bl()) + shape += wall_brace(carbonfet_thumb_bl_place, -1, 0, thumb_post_tl(), carbonfet_thumb_bl_place, 0, 1, thumb_post_tl()) + # thumb, tweeners + shape += wall_brace(carbonfet_thumb_mr_place, 0, -1.15, web_post_bl(), carbonfet_thumb_br_place, 0, -1, web_post_br()) + # shape += wall_brace(thumb_ml_place, 0, 1, web_post_tl(), carbonfet_thumb_bl_place, 0, 1, web_post_tr()) + shape += wall_brace(carbonfet_thumb_bl_place, -1, 0, web_post_bl(), carbonfet_thumb_br_place, -1, 0, web_post_tl()) + shape += wall_brace(carbonfet_thumb_tr_place, 0, -1, web_post_br(), (lambda sh: key_place(sh, 3, lastrow)), 0, -1, web_post_bl()) + return shape + +def carbonfet_thumb_connection(): + # clunky bit on the top left thumb connection (normal connectors don't work well) + shape = bottom_hull( + [ + left_key_place(sl.translate(wall_locate2(-1, 0))(web_post()), cornerrow, -1), + left_key_place(sl.translate(wall_locate3(-1, 0))(web_post()), cornerrow, -1), + carbonfet_thumb_bl_place(sl.translate(wall_locate2(-0.3, 1))(thumb_post_tr())), + carbonfet_thumb_bl_place(sl.translate(wall_locate3(-0.3, 1))(thumb_post_tr())), + ] + ) + + shape += sl.hull()( + [ + left_key_place(sl.translate(wall_locate2(-1, 0))(web_post()), cornerrow, -1), + left_key_place(sl.translate(wall_locate3(-1, 0))(web_post()), cornerrow, -1), + carbonfet_thumb_bl_place(sl.translate(wall_locate2(-0.3, 1))(thumb_post_tr())), + carbonfet_thumb_bl_place(sl.translate(wall_locate3(-0.3, 1))(thumb_post_tr())), + carbonfet_thumb_ml_place(thumb_post_tl()), + ] + ) + + shape += sl.hull()( + [ + left_key_place(web_post(), cornerrow, -1), + left_key_place(sl.translate(wall_locate1(-1, 0))(web_post()), cornerrow, -1), + left_key_place(sl.translate(wall_locate2(-1, 0))(web_post()), cornerrow, -1), + left_key_place(sl.translate(wall_locate3(-1, 0))(web_post()), cornerrow, -1), + carbonfet_thumb_ml_place(thumb_post_tl()), + ] + ) + + shape += sl.hull()( + [ + left_key_place(web_post(), cornerrow, -1), + left_key_place(sl.translate(wall_locate1(-1, 0))(web_post()), cornerrow, -1), + key_place(web_post_bl(), 0, cornerrow), + # key_place(sl.translate(wall_locate1(-1, 0))(web_post_bl()), 0, cornerrow), + carbonfet_thumb_ml_place(thumb_post_tl()), + ] + ) + + shape += sl.hull()( + [ + carbonfet_thumb_bl_place(thumb_post_tr()), + carbonfet_thumb_bl_place(sl.translate(wall_locate1(-0.3, 1))(thumb_post_tr())), + carbonfet_thumb_bl_place(sl.translate(wall_locate2(-0.3, 1))(thumb_post_tr())), + carbonfet_thumb_bl_place(sl.translate(wall_locate3(-0.3, 1))(thumb_post_tr())), + carbonfet_thumb_ml_place(thumb_post_tl()), + ] + ) + + return shape + + + +def case_walls(): + return ( + back_wall() + + left_wall() + + right_wall() + + front_wall() + + thumb_walls() + + thumb_connection() + ) + + +rj9_start = list( + np.array([0, -3, 0]) + + np.array( + key_position( + list(np.array(wall_locate3(0, 1)) + np.array([0, (mount_height / 2), 0])), + 0, + 0, + ) + ) +) + +rj9_position = [rj9_start[0], rj9_start[1], 11] + + +def rj9_cube(): + return sl.cube([14.78, 13, 22.38], center=True) + + +def rj9_space(): + return sl.translate(rj9_position)(rj9_cube()) + + +def rj9_holder(): + shape = sl.union()( + sl.translate([0, 2, 0])(sl.cube([10.78, 9, 18.38], center=True)), + sl.translate([0, 0, 5])(sl.cube([10.78, 13, 5], center=True)), + ) + shape = sl.difference()(rj9_cube(), shape) + shape = sl.translate(rj9_position)(shape) + return shape + + +usb_holder_position = key_position( + list(np.array(wall_locate2(0, 1)) + np.array([0, (mount_height / 2), 0])), 1, 0 +) +usb_holder_size = [6.5, 10.0, 13.6] +usb_holder_thickness = 4 + + +def usb_holder(): + shape = sl.cube( + [ + usb_holder_size[0] + usb_holder_thickness, + usb_holder_size[1], + usb_holder_size[2] + usb_holder_thickness, + ], + center=True, + ) + shape = sl.translate( + [ + usb_holder_position[0], + usb_holder_position[1], + (usb_holder_size[2] + usb_holder_thickness) / 2, + ] + )(shape) + return shape + + +def usb_holder_hole(): + shape = sl.cube(usb_holder_size, center=True) + shape = sl.translate( + [ + usb_holder_position[0], + usb_holder_position[1], + (usb_holder_size[2] + usb_holder_thickness) / 2, + ] + )(shape) + return shape + + +external_start = list( + np.array([external_holder_width / 2, 0, 0]) + + np.array( + key_position( + list(np.array(wall_locate3(0, 1)) + np.array([0, (mount_height / 2), 0])), + 0, + 0, + ) + ) +) + + +def external_mount_hole(): + print('external_mount_hole()') + shape = sl.cube((external_holder_width, 20.0, external_holder_height), center=True) + shape = sl.translate( + ( + external_start[0] + external_holder_xoffset, + external_start[1], + external_holder_height / 2 + ) + )(shape) + return shape + + +def oled_sliding_mount_frame(): + mount_ext_width = oled_mount_width + 2 * oled_mount_rim + mount_ext_height = ( + oled_mount_height + 2 * oled_edge_overlap_end + + oled_edge_overlap_connector + oled_edge_overlap_clearance + + 2 * oled_mount_rim + ) + mount_ext_up_height = oled_mount_height + 2 * oled_mount_rim + top_hole_start = -mount_ext_height / 2.0 + oled_mount_rim + oled_edge_overlap_end + oled_edge_overlap_connector + top_hole_length = oled_mount_height + hole = sl.cube([mount_ext_width, mount_ext_up_height, oled_mount_cut_depth + .01], center=True) + hole = sl.translate([0., top_hole_start + top_hole_length / 2, 0.])(hole) + hole_down = sl.cube([mount_ext_width, mount_ext_height, oled_mount_depth + oled_mount_cut_depth / 2], + center=True) + hole_down = sl.translate([0., 0., -oled_mount_cut_depth / 4])(hole_down) + hole += hole_down + + shape = sl.cube([mount_ext_width, mount_ext_height, oled_mount_depth], center=True) + + conn_hole_start = -mount_ext_height / 2.0 + oled_mount_rim + conn_hole_length = ( + oled_edge_overlap_end + oled_edge_overlap_connector + + oled_edge_overlap_clearance + oled_thickness + ) + conn_hole = sl.cube([oled_mount_width, conn_hole_length + .01, oled_mount_depth], center=True) + conn_hole = sl.translate([ + 0, + conn_hole_start + conn_hole_length / 2, + -oled_edge_overlap_thickness + ])(conn_hole) + + end_hole_length = ( + oled_edge_overlap_end + oled_edge_overlap_clearance + ) + end_hole_start = mount_ext_height / 2.0 - oled_mount_rim - end_hole_length + end_hole = sl.cube([oled_mount_width, end_hole_length + .01, oled_mount_depth], center=True) + end_hole = sl.translate([ + 0, + end_hole_start + end_hole_length / 2, + -oled_edge_overlap_thickness + ])(end_hole) + + top_hole_start = -mount_ext_height / 2.0 + oled_mount_rim + oled_edge_overlap_end + oled_edge_overlap_connector + top_hole_length = oled_mount_height + top_hole = sl.cube( + [oled_mount_width, top_hole_length, oled_edge_overlap_thickness + oled_thickness - oled_edge_chamfer], + center=True) + top_hole = sl.translate([ + 0, + top_hole_start + top_hole_length / 2, + (oled_mount_depth - oled_edge_overlap_thickness - oled_thickness - oled_edge_chamfer) / 2.0 + ])(top_hole) + + top_chamfer_1 = sl.cube([ + oled_mount_width, + top_hole_length, + 0.01 + ], center=True) + top_chamfer_2 = sl.cube([ + oled_mount_width + 2 * oled_edge_chamfer, + top_hole_length + 2 * oled_edge_chamfer, + 0.01 + ], center=True) + top_chamfer_1 = sl.translate([ + 0, + 0, + -oled_edge_chamfer - .05 + ])(top_chamfer_1) + top_chamfer_1 = sl.hull()(top_chamfer_1, top_chamfer_2) + + top_chamfer_1 = sl.translate([ + 0, + top_hole_start + top_hole_length / 2, + oled_mount_depth / 2.0 + .05 + ])(top_chamfer_1) + top_hole += top_chamfer_1 + + shape = sl.difference()(shape, conn_hole, top_hole, end_hole) + + shape = sl.rotate(oled_mount_rotation_xyz)(shape) + shape = sl.translate( + ( + oled_mount_location_xyz[0], + oled_mount_location_xyz[1], + oled_mount_location_xyz[2], + ) + )(shape) + + hole = sl.rotate(oled_mount_rotation_xyz)(hole) + hole = sl.translate( + ( + oled_mount_location_xyz[0], + oled_mount_location_xyz[1], + oled_mount_location_xyz[2], + ) + )(hole) + return hole, shape + + +def oled_clip_mount_frame(): + mount_ext_width = oled_mount_width + 2 * oled_mount_rim + mount_ext_height = ( + oled_mount_height + 2 * oled_clip_thickness + + 2 * oled_clip_undercut + 2 * oled_clip_overhang + 2 * oled_mount_rim + ) + hole = sl.cube([mount_ext_width, mount_ext_height, oled_mount_cut_depth + .01], center=True) + + shape = sl.cube([mount_ext_width, mount_ext_height, oled_mount_depth], center=True) + shape -= sl.cube([oled_mount_width, oled_mount_height, oled_mount_depth + .1], center=True) + + clip_slot = sl.cube([ + oled_clip_width + 2 * oled_clip_width_clearance, + oled_mount_height + 2 * oled_clip_thickness + 2 * oled_clip_overhang, + oled_mount_depth + .1], center=True) + + shape -= clip_slot + + clip_undercut = sl.cube([ + oled_clip_width + 2 * oled_clip_width_clearance, + oled_mount_height + 2 * oled_clip_thickness + 2 * oled_clip_overhang + 2 * oled_clip_undercut, + oled_mount_depth + .1], center=True) + + clip_undercut = sl.translate((0., 0., oled_clip_undercut_thickness))(clip_undercut) + shape -= clip_undercut + + plate = sl.cube([ + oled_mount_width + .1, + oled_mount_height - 2 * oled_mount_connector_hole, + oled_mount_depth - oled_thickness], center=True) + plate = sl.translate((0., 0., -oled_thickness / 2.0))(plate) + shape += plate + + shape = sl.rotate(oled_mount_rotation_xyz)(shape) + shape = sl.translate( + ( + oled_mount_location_xyz[0], + oled_mount_location_xyz[1], + oled_mount_location_xyz[2], + ) + )(shape) + + hole = sl.rotate(oled_mount_rotation_xyz)(hole) + hole = sl.translate( + ( + oled_mount_location_xyz[0], + oled_mount_location_xyz[1], + oled_mount_location_xyz[2], + ) + )(hole) + + return hole, shape + + +def oled_clip(): + mount_ext_width = oled_mount_width + 2 * oled_mount_rim + mount_ext_height = ( + oled_mount_height + 2 * oled_clip_thickness + 2 * oled_clip_overhang + + 2 * oled_clip_undercut + 2 * oled_mount_rim + ) + + oled_leg_depth = oled_mount_depth + oled_clip_z_gap + + shape = sl.cube([mount_ext_width - .1, mount_ext_height - .1, oled_mount_bezel_thickness], center=True) + shape = sl.translate((0., 0., oled_mount_bezel_thickness / 2.))(shape) + + hole_1 = sl.cube([ + oled_screen_width + 2 * oled_mount_bezel_chamfer, + oled_screen_length + 2 * oled_mount_bezel_chamfer, + .01 + ], center=True) + hole_2 = sl.cube([oled_screen_width, oled_screen_length, 2.05 * oled_mount_bezel_thickness], center=True) + hole = sl.hull()(hole_1, hole_2) + + shape -= sl.translate((0., 0., oled_mount_bezel_thickness))(hole) + + clip_leg = sl.cube([oled_clip_width, oled_clip_thickness, oled_leg_depth], center=True) + clip_leg = sl.translate(( + 0., + 0., + # (oled_mount_height+2*oled_clip_overhang+oled_clip_thickness)/2, + -oled_leg_depth / 2. + ))(clip_leg) + + latch_1 = sl.cube([ + oled_clip_width, + oled_clip_overhang + oled_clip_thickness, + .01 + ], center=True) + latch_2 = sl.cube([ + oled_clip_width, + oled_clip_thickness / 2, + oled_clip_extension + ], center=True) + latch_2 = sl.translate(( + 0., + -(-oled_clip_thickness / 2 + oled_clip_thickness + oled_clip_overhang) / 2, + -oled_clip_extension / 2 + ))(latch_2) + latch = sl.hull()(latch_1, latch_2) + latch = sl.translate(( + 0., + oled_clip_overhang / 2, + -oled_leg_depth + ))(latch) + + clip_leg += latch + + clip_leg = sl.translate(( + 0., + (oled_mount_height + 2 * oled_clip_overhang + oled_clip_thickness) / 2 - oled_clip_y_gap, + 0. + ))(clip_leg) + + shape += clip_leg + shape += sl.mirror((0., 1., 0.))(clip_leg) + + return shape + + +def oled_undercut_mount_frame(): + mount_ext_width = oled_mount_width + 2 * oled_mount_rim + mount_ext_height = oled_mount_height + 2 * oled_mount_rim + hole = sl.cube([mount_ext_width, mount_ext_height, oled_mount_cut_depth + .01], center=True) + + shape = sl.cube([mount_ext_width, mount_ext_height, oled_mount_depth], center=True) + shape = sl.difference()( + shape, + sl.cube([oled_mount_width, oled_mount_height, oled_mount_depth + .1], center=True) + ) + undercut = sl.cube([ + oled_mount_width + 2 * oled_mount_undercut, + oled_mount_height + 2 * oled_mount_undercut, + oled_mount_depth], center=True) + undercut = sl.translate((0., 0., -oled_mount_undercut_thickness))(undercut) + shape = sl.difference()(shape, undercut) + + shape = sl.rotate(oled_mount_rotation_xyz)(shape) + shape = sl.translate( + ( + oled_mount_location_xyz[0], + oled_mount_location_xyz[1], + oled_mount_location_xyz[2], + ) + )(shape) + + hole = sl.rotate(oled_mount_rotation_xyz)(hole) + hole = sl.translate( + ( + oled_mount_location_xyz[0], + oled_mount_location_xyz[1], + oled_mount_location_xyz[2], + ) + )(hole) + + return hole, shape + + +teensy_width = 20 +teensy_height = 12 +teensy_length = 33 +teensy2_length = 53 +teensy_pcb_thickness = 2 +teensy_holder_width = 7 + teensy_pcb_thickness +teensy_holder_height = 6 + teensy_width +teensy_offset_height = 5 +teensy_holder_top_length = 18 +teensy_top_xy = key_position(wall_locate3(-1, 0), 0, centerrow - 1) +teensy_bot_xy = key_position(wall_locate3(-1, 0), 0, centerrow + 1) +teensy_holder_length = teensy_top_xy[1] - teensy_bot_xy[1] +teensy_holder_offset = -teensy_holder_length / 2 +teensy_holder_top_offset = (teensy_holder_top_length / 2) - teensy_holder_length + + +def teensy_holder(): + s1 = sl.cube([3, teensy_holder_length, 6 + teensy_width], center=True) + s1 = sl.translate([1.5, teensy_holder_offset, 0])(s1) + + s2 = sl.cube([teensy_pcb_thickness, teensy_holder_length, 3], center=True) + s2 = sl.translate( + [ + (teensy_pcb_thickness / 2) + 3, + teensy_holder_offset, + -1.5 - (teensy_width / 2), + ] + )(s2) + + s3 = sl.cube([teensy_pcb_thickness, teensy_holder_top_length, 3], center=True) + s3 = sl.translate( + [ + (teensy_pcb_thickness / 2) + 3, + teensy_holder_top_offset, + 1.5 + (teensy_width / 2), + ] + )(s3) + + s4 = sl.cube([4, teensy_holder_top_length, 4], center=True) + s4 = sl.translate( + [teensy_pcb_thickness + 5, teensy_holder_top_offset, 1 + (teensy_width / 2)] + )(s4) + + shape = sl.union()(s1, s2, s3, s4) + + shape = sl.translate([-teensy_holder_width, 0, 0])(shape) + shape = sl.translate([-1.4, 0, 0])(shape) + shape = sl.translate( + [teensy_top_xy[0], teensy_top_xy[1] - 1, (6 + teensy_width) / 2] + )(shape) + + return shape + + +def screw_insert_shape(bottom_radius, top_radius, height): + shape = sl.union()( + sl.cylinder(r1=bottom_radius, r2=top_radius, h=height, center=True), + sl.translate([0, 0, (height / 2)])(sl.sphere(top_radius)), + ) + return shape + + +def screw_insert(column, row, bottom_radius, top_radius, height): + shift_right = column == lastcol + shift_left = column == 0 + shift_up = (not (shift_right or shift_left)) and (row == 0) + shift_down = (not (shift_right or shift_left)) and (row >= lastrow) + + if screws_offset == 'INSIDE': + # print('Shift Inside') + shift_left_adjust = wall_base_x_thickness + shift_right_adjust = -wall_base_x_thickness/2 + shift_down_adjust = -wall_base_y_thickness/2 + shift_up_adjust = -wall_base_y_thickness/3 + + elif screws_offset == 'OUTSIDE': + print('Shift Outside') + shift_left_adjust = 0 + shift_right_adjust = wall_base_x_thickness/2 + shift_down_adjust = wall_base_y_thickness*2/3 + shift_up_adjust = wall_base_y_thickness*2/3 + + else: + # print('Shift Origin') + shift_left_adjust = 0 + shift_right_adjust = 0 + shift_down_adjust = 0 + shift_up_adjust = 0 + + if shift_up: + position = key_position( + list(np.array(wall_locate2(0, 1)) + np.array([0, (mount_height / 2) + shift_up_adjust, 0])), + column, + row, + ) + elif shift_down: + position = key_position( + list(np.array(wall_locate2(0, -1)) - np.array([0, (mount_height / 2) + shift_down_adjust, 0])), + column, + row, + ) + elif shift_left: + position = list( + np.array(left_key_position(row, 0)) + np.array(wall_locate3(-1, 0)) + np.array((shift_left_adjust,0,0)) + ) + else: + position = key_position( + list(np.array(wall_locate2(1, 0)) + np.array([(mount_height / 2), 0, 0]) + np.array((shift_right_adjust,0,0)) + ), + column, + row, + ) + + # add z height below 0 due to 0 thickness skin covering the hole. + shape = screw_insert_shape(bottom_radius, top_radius, height + 5) + shape = sl.translate((position[0], position[1], height / 2 - 2.5))(shape) + + return shape + + +def screw_insert_all_shapes(bottom_radius, top_radius, height): + shape = sl.union()( + screw_insert(0, 0, bottom_radius, top_radius, height), + screw_insert(0, lastrow - 1, bottom_radius, top_radius, height), + screw_insert(3, lastrow, bottom_radius, top_radius, height), + screw_insert(3, 0, bottom_radius, top_radius, height), + screw_insert(lastcol, 0, bottom_radius, top_radius, height), + screw_insert(lastcol, lastrow - 1, bottom_radius, top_radius, height), + ) + + return shape + + +screw_insert_height = 3.8 +screw_insert_bottom_radius = 5.31 / 2 +screw_insert_top_radius = 5.1 / 2 +screw_insert_holes = screw_insert_all_shapes( + screw_insert_bottom_radius, screw_insert_top_radius, screw_insert_height +) +screw_insert_outers = screw_insert_all_shapes( + screw_insert_bottom_radius + 1.6, + screw_insert_top_radius + 1.6, + screw_insert_height + 1.5, +) +screw_insert_screw_holes = screw_insert_all_shapes(1.7, 1.7, 350) + +wire_post_height = 7 +wire_post_overhang = 3.5 +wire_post_diameter = 2.6 + + +def wire_post(direction, offset): + s1 = sl.cube( + [wire_post_diameter, wire_post_diameter, wire_post_height], center=True + ) + s1 = sl.translate([0, -wire_post_diameter * 0.5 * direction, 0])(s1) + + s2 = sl.cube( + [wire_post_diameter, wire_post_overhang, wire_post_diameter], center=True + ) + s2 = sl.translate( + [0, -wire_post_overhang * 0.5 * direction, -wire_post_height / 2] + )(s2) + + shape = sl.union()(s1, s2) + shape = sl.translate([0, -offset, (-wire_post_height / 2) + 3])(shape) + shape = sl.rotate(-alpha / 2, [1, 0, 0])(shape) + shape = sl.translate([3, -mount_height / 2, 0])(shape) + + return shape + + +def wire_posts(): + shape = thumb_ml_place(sl.translate([-5, 0, -2])(wire_post(1, 0))) + shape += thumb_ml_place(sl.translate([0, 0, -2.5])(wire_post(-1, 6))) + shape += thumb_ml_place(sl.translate([5, 0, -2])(wire_post(1, 0))) + + for column in range(lastcol): + for row in range(lastrow - 1): + shape += sl.union()( + key_place(sl.translate([-5, 0, 0])(wire_post(1, 0)), column, row), + key_place(sl.translate([0, 0, 0])(wire_post(-1, 6)), column, row), + key_place(sl.translate([5, 0, 0])(wire_post(1, 0)), column, row), + ) + return shape + + +def model_side(side="right"): + shape = sl.union()(key_holes(side=side), connectors(), thumb(side=side), thumb_connectors(), ) + pre_sub = [] + adders = [] + post_sub = [screw_insert_holes()] + + if controller_mount_type in ['RJ9_USB_TEENSY']: + adders.append(teensy_holder()) + + if controller_mount_type in ['RJ9_USB_TEENSY', 'RJ9_USB_WALL']: + adders.append(usb_holder()) + post_sub.append(usb_holder_hole()) + + if controller_mount_type in ['RJ9_USB_TEENSY', 'RJ9_USB_WALL']: + pre_sub.append(rj9_space()) + adders.append(rj9_holder()) + + if controller_mount_type in ['EXTERNAL']: + post_sub.append(external_mount_hole()) + + s2 = sl.union()(case_walls(), screw_insert_outers()) + s2 = sl.difference()(s2, *pre_sub) + s2 = sl.union()(s2, *adders) + shape = sl.union()(shape, s2) + + shape -= sl.translate([0, 0, -20])(sl.cube([350, 350, 40], center=True)) + + shape = sl.difference()(shape, *post_sub) + + if oled_mount_type == "UNDERCUT": + hole, frame = oled_undercut_mount_frame() + shape -= hole + shape += frame + + elif oled_mount_type == "SLIDING": + hole, frame = oled_sliding_mount_frame() + shape -= hole + shape += frame + + elif oled_mount_type == "CLIP": + hole, frame = oled_clip_mount_frame() + shape -= hole + shape += frame + + if side == "left": + shape = sl.mirror([-1, 0, 0])(shape) + + return shape + + +mod_r = model_side(side="right") + +sl.scad_render_to_file(mod_r, path.join(r"..", "things", save_dir, config_name + r"_right.scad")) + +if symmetry == "asymmetric": + mod_l = model_side(side="left") + sl.scad_render_to_file( + mod_l, path.join(r"..", "things", save_dir, config_name + r"_left.scad") + ) +else: + sl.scad_render_to_file( + sl.mirror([-1, 0, 0])(mod_r), path.join(r"..", "things", save_dir, config_name + r"_left.scad") + ) + + +def baseplate(): + shape = sl.union()( + case_walls(), + screw_insert_outers(), + ) + + tool = sl.translate([0, 0, -10])(screw_insert_screw_holes()) + + shape = shape - tool + + shape = sl.translate([0, 0, -0.01])(shape) + + return sl.projection(cut=True)(shape) + + +sl.scad_render_to_file(baseplate(), path.join(r"..", "things", save_dir, config_name + r"_plate.scad")) + +if oled_mount_type == 'UNDERCUT': + sl.scad_render_to_file(oled_undercut_mount_frame()[1], path.join(r"..", "things", save_dir, config_name + r"_oled_undercut_test.scad")) + +if oled_mount_type == 'SLIDING': + sl.scad_render_to_file(oled_sliding_mount_frame()[1], path.join(r"..", "things", save_dir, config_name + r"_oled_sliding_test.scad")) + +if oled_mount_type == 'CLIP': + oled_mount_location_xyz = (0.0, 0.0, -oled_mount_depth / 2) + oled_mount_rotation_xyz = (0.0, 0.0, 0.0) + sl.scad_render_to_file(oled_clip(), path.join(r"..", "things", save_dir, config_name + r"_oled_clip.scad")) + sl.scad_render_to_file(oled_clip_mount_frame()[1], path.join(r"..", "things", save_dir, config_name + r"_oled_clip_test.scad")) + sl.scad_render_to_file(oled_clip_mount_frame()[1] + oled_clip(), + path.join(r"..", "things", save_dir, config_name + r"_oled_clip_assy_test.scad")) -- cgit v1.2.3