import numpy as np from numpy import pi import os.path as path import json import os from scipy.spatial import ConvexHull as sphull def deg2rad(degrees: float) -> float: return degrees * pi / 180 def rad2deg(rad: float) -> float: return rad * 180 / pi ############################################### # EXTREMELY UGLY BUT FUNCTIONAL BOOTSTRAP ############################################### ## IMPORT DEFAULT CONFIG IN CASE NEW PARAMETERS EXIST import generate_configuration as cfg for item in cfg.shape_config: locals()[item] = cfg.shape_config[item] ## LOAD RUN CONFIGURATION FILE AND WRITE TO ANY VARIABLES IN FILE. with open('run_config.json', mode='r') as fid: data = json.load(fid) for item in data: locals()[item] = data[item] # Really rough setup. Check for ENGINE, set it not present from configuration. try: print('Found Current Engine in Config = {}'.format(ENGINE)) except Exception: print('Engine Not Found in Config') ENGINE = 'solid' # ENGINE = 'cadquery' print('Setting Current Engine = {}'.format(ENGINE)) if save_dir in ['', None, '.']: save_path = os.path.join(r"..", "things") else: save_path = os.path.join(r"..", "things", save_dir) ############################################### # END EXTREMELY UGLY BOOTSTRAP ############################################### #################################################### # HELPER FUNCTIONS TO MERGE CADQUERY AND OPENSCAD #################################################### if ENGINE == 'cadquery': from helpers_cadquery import * else: from helpers_solid import * #################################################### # END HELPER FUNCTIONS #################################################### debug_exports = False debug_trace = False def debugprint(info): if debug_trace: print(info) if oled_mount_type is not None and oled_mount_type != "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', 'NOTCH', 'HS_NOTCH']: keyswitch_height = undercut_keyswitch_height keyswitch_width = undercut_keyswitch_width else: keyswitch_height = hole_keyswitch_height keyswitch_width = hole_keyswitch_width if 'HS_' in plate_style: symmetry = "asymmetric" plate_file = path.join("..", "src", r"hot_swap_plate") plate_offset = 0.0 mount_width = keyswitch_width + 2 * plate_rim mount_height = keyswitch_height + 2 * plate_rim mount_thickness = plate_thickness if default_1U_cluster: double_plate_height = (.7*sa_double_length - mount_height) / 3 else: double_plate_height = (.95*sa_double_length - mount_height) / 3 if oled_mount_type is not None and oled_mount_type != "NONE": left_wall_x_offset = oled_left_wall_x_offset_override left_wall_z_offset = oled_left_wall_z_offset_override left_wall_lower_y_offset = oled_left_wall_lower_y_offset left_wall_lower_z_offset = oled_left_wall_lower_z_offset 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) teensy_width = 20 teensy_height = 12 teensy_length = 33 teensy2_length = 53 teensy_pcb_thickness = 2 teensy_offset_height = 5 teensy_holder_top_length = 18 teensy_holder_width = 7 + teensy_pcb_thickness teensy_holder_height = 6 + teensy_width wire_post_height = 7 wire_post_overhang = 3.5 wire_post_diameter = 2.6 screw_insert_height = 3.8 screw_insert_bottom_radius = 5.31 / 2 screw_insert_top_radius = 5.1 / 2 # save_path = path.join("..", "things", save_dir) if not path.isdir(save_path): os.mkdir(save_path) def column_offset(column: int) -> list: return column_offsets[column] # column_style='fixed' def single_plate(cylinder_segments=100, side="right"): if plate_style in ['NUB', 'HS_NUB']: top_wall = box(mount_width, 1.5, plate_thickness) top_wall = translate(top_wall, (0, (1.5 / 2) + (keyswitch_height / 2), plate_thickness / 2)) left_wall = box(1.5, mount_height, plate_thickness) left_wall = translate(left_wall, ((1.5 / 2) + (keyswitch_width / 2), 0, plate_thickness / 2)) side_nub = cylinder(radius=1, height=2.75) side_nub = translate(side_nub, (0, 0, -2.75 / 2.0)) side_nub = rotate(side_nub, (90, 0, 0)) side_nub = translate(side_nub, (keyswitch_width / 2, 0, 1)) nub_cube = box(1.5, 2.75, plate_thickness) nub_cube = translate(nub_cube, ((1.5 / 2) + (keyswitch_width / 2), 0, plate_thickness / 2)) side_nub2 = tess_hull(shapes=(side_nub, nub_cube)) side_nub2 = union([side_nub2, side_nub, nub_cube]) plate_half1 = union([top_wall, left_wall, side_nub2]) plate_half2 = plate_half1 plate_half2 = mirror(plate_half2, 'XZ') plate_half2 = mirror(plate_half2, 'YZ') plate = union([plate_half1, plate_half2]) else: # 'HOLE' or default, square cutout for non-nub designs. plate = box(mount_width, mount_height, mount_thickness) plate = translate(plate, (0.0, 0.0, mount_thickness / 2.0)) shape_cut = box(keyswitch_width, keyswitch_height, mount_thickness * 2 +.02) shape_cut = translate(shape_cut, (0.0, 0.0, mount_thickness-.01)) plate = difference(plate, [shape_cut]) if plate_style in ['UNDERCUT', 'HS_UNDERCUT', 'NOTCH', 'HS_NOTCH']: if plate_style in ['UNDERCUT', 'HS_UNDERCUT']: undercut = box( keyswitch_width + 2 * clip_undercut, keyswitch_height + 2 * clip_undercut, mount_thickness ) if plate_style in ['NOTCH', 'HS_NOTCH']: undercut = box( notch_width, keyswitch_height + 2 * clip_undercut, mount_thickness ) undercut = union([undercut, box( keyswitch_width + 2 * clip_undercut, notch_width, mount_thickness ) ]) undercut = translate(undercut, (0.0, 0.0, -clip_thickness + mount_thickness / 2.0)) if ENGINE=='cadquery' and undercut_transition > 0: undercut = undercut.faces("+Z").chamfer(undercut_transition, clip_undercut) plate = difference(plate, [undercut]) if plate_file is not None: socket = import_file(plate_file) socket = translate(socket, [0, 0, plate_thickness + plate_offset]) plate = union([plate, socket]) if plate_holes: half_width = plate_holes_width/2. half_height = plate_holes_height/2. x_off = plate_holes_xy_offset[0] y_off = plate_holes_xy_offset[1] holes = [ translate( cylinder(radius=plate_holes_diameter/2, height=plate_holes_depth+.01), (x_off+half_width, y_off+half_height, plate_holes_depth/2-.01) ), translate( cylinder(radius=plate_holes_diameter / 2, height=plate_holes_depth+.01), (x_off-half_width, y_off+half_height, plate_holes_depth/2-.01) ), translate( cylinder(radius=plate_holes_diameter / 2, height=plate_holes_depth+.01), (x_off-half_width, y_off-half_height, plate_holes_depth/2-.01) ), translate( cylinder(radius=plate_holes_diameter / 2, height=plate_holes_depth+.01), (x_off+half_width, y_off-half_height, plate_holes_depth/2-.01) ), ] plate = difference(plate, holes) if side == "left": plate = mirror(plate, 'YZ') return plate ################ ## SA Keycaps ## ################ 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 = polyline([(bw2, bl2), (bw2, -bl2), (-bw2, -bl2), (-bw2, bl2), (bw2, bl2)]) k1 = extrude_poly(outer_poly=k1, height=0.1) k1 = translate(k1, (0, 0, 0.05)) k2 = polyline([(pw2, pl2), (pw2, -pl2), (-pw2, -pl2), (-pw2, pl2), (pw2, pl2)]) k2 = extrude_poly(outer_poly=k2, height=0.1) k2 = translate(k2, (0, 0, 12.0)) if m > 0: m1 = polyline([(m, m), (m, -m), (-m, -m), (-m, m), (m, m)]) # m1 = cq.Wire.assembleEdges(m1.edges().objects) m1 = extrude_poly(outer_poly=m1, height=0.1) m1 = translate(m1, (0, 0, 6.0)) key_cap = hull_from_shapes((k1, k2, m1)) else: key_cap = hull_from_shapes((k1, k2)) key_cap = translate(key_cap, (0, 0, 5 + plate_thickness)) # key_cap = key_cap.color((220 / 255, 163 / 255, 163 / 255, 1)) return key_cap ######################### ## Placement Functions ## ######################### def rotate_around_x(position, angle): # debugprint('rotate_around_x()') 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): # debugprint('rotate_around_y()') 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) def apply_key_geometry( shape, translate_fn, rotate_x_fn, rotate_y_fn, column, row, column_style=column_style, ): debugprint('apply_key_geometry()') 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, [0, 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 x_rot(shape, angle): # debugprint('x_rot()') return rotate(shape, [rad2deg(angle), 0, 0]) def y_rot(shape, angle): # debugprint('y_rot()') return rotate(shape, [0, rad2deg(angle), 0]) def key_place(shape, column, row): debugprint('key_place()') return apply_key_geometry(shape, translate, x_rot, y_rot, column, row) def add_translate(shape, xyz): debugprint('add_translate()') vals = [] for i in range(len(shape)): vals.append(shape[i] + xyz[i]) return vals def key_position(position, column, row): debugprint('key_position()') return apply_key_geometry( position, add_translate, rotate_around_x, rotate_around_y, column, row ) def key_holes(side="right"): debugprint('key_holes()') # hole = single_plate() holes = [] for column in range(ncols): for row in range(nrows): if (column in [2, 3]) or (not row == lastrow): holes.append(key_place(single_plate(side=side), column, row)) shape = union(holes) return shape def caps(): caps = None for column in range(ncols): for row in range(nrows): if (column in [2, 3]) or (not row == lastrow): if caps is None: caps = key_place(sa_cap(), column, row) else: caps = add([caps, key_place(sa_cap(), column, row)]) return caps #################### ## Web Connectors ## #################### def web_post(): debugprint('web_post()') post = box(post_size, post_size, web_thickness) post = translate(post, (0, 0, plate_thickness - (web_thickness / 2))) return post def web_post_tr(wide=False): if wide: w_divide = 1.2 else: w_divide = 2.0 return translate(web_post(), ((mount_width / w_divide) - post_adj, (mount_height / 2) - post_adj, 0)) def web_post_tl(wide=False): if wide: w_divide = 1.2 else: w_divide = 2.0 return translate(web_post(), (-(mount_width / w_divide) + post_adj, (mount_height / 2) - post_adj, 0)) def web_post_bl(wide=False): if wide: w_divide = 1.2 else: w_divide = 2.0 return translate(web_post(), (-(mount_width / w_divide) + post_adj, -(mount_height / 2) + post_adj, 0)) def web_post_br(wide=False): if wide: w_divide = 1.2 else: w_divide = 2.0 return translate(web_post(), ((mount_width / w_divide) - post_adj, -(mount_height / 2) + post_adj, 0)) def connectors(): debugprint('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 union(hulls) ############ ## Thumbs ## ############ def thumborigin(): # debugprint('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): debugprint('thumb_tr_place()') shape = rotate(shape, [10, -15, 10]) shape = translate(shape, thumborigin()) shape = translate(shape, [-12, -16, 3]) return shape def thumb_tl_place(shape): debugprint('thumb_tl_place()') shape = rotate(shape, [7.5, -18, 10]) shape = translate(shape, thumborigin()) shape = translate(shape, [-32.5, -14.5, -2.5]) return shape def thumb_mr_place(shape): debugprint('thumb_mr_place()') shape = rotate(shape, [-6, -34, 48]) shape = translate(shape, thumborigin()) shape = translate(shape, [-29, -40, -13]) return shape def thumb_ml_place(shape): debugprint('thumb_ml_place()') shape = rotate(shape, [6, -34, 40]) shape = translate(shape, thumborigin()) shape = translate(shape, [-51, -25, -12]) return shape def thumb_br_place(shape): debugprint('thumb_br_place()') shape = rotate(shape, [-16, -33, 54]) shape = translate(shape, thumborigin()) shape = translate(shape, [-37.8, -55.3, -25.3]) return shape def thumb_bl_place(shape): debugprint('thumb_bl_place()') shape = rotate(shape, [-4, -35, 52]) shape = translate(shape, thumborigin()) shape = translate(shape, [-56.3, -43.3, -23.5]) return shape def thumb_1x_layout(shape, cap=False): debugprint('thumb_1x_layout()') if cap: shape_list = [ thumb_mr_place(rotate(shape, [0, 0, thumb_plate_mr_rotation])), thumb_ml_place(rotate(shape, [0, 0, thumb_plate_ml_rotation])), thumb_br_place(rotate(shape, [0, 0, thumb_plate_br_rotation])), thumb_bl_place(rotate(shape, [0, 0, thumb_plate_bl_rotation])), ] if default_1U_cluster: shape_list.append(thumb_tr_place(rotate(rotate(shape, (0, 0, 90)), [0, 0, thumb_plate_tr_rotation]))) shape_list.append(thumb_tl_place(rotate(shape, [0, 0, thumb_plate_tl_rotation]))) shapes = add(shape_list) else: shape_list = [ thumb_mr_place(rotate(shape, [0, 0, thumb_plate_mr_rotation])), thumb_ml_place(rotate(shape, [0, 0, thumb_plate_ml_rotation])), thumb_br_place(rotate(shape, [0, 0, thumb_plate_br_rotation])), thumb_bl_place(rotate(shape, [0, 0, thumb_plate_bl_rotation])), ] if default_1U_cluster: shape_list.append(thumb_tr_place(rotate(rotate(shape, (0, 0, 90)), [0, 0, thumb_plate_tr_rotation]))) shapes = union(shape_list) return shapes def thumb_15x_layout(shape, cap=False, plate=True): debugprint('thumb_15x_layout()') if plate: if cap: shape = rotate(shape, (0, 0, 90)) cap_list = [thumb_tl_place(rotate(shape, [0, 0, thumb_plate_tl_rotation]))] cap_list.append(thumb_tr_place(rotate(shape, [0, 0, thumb_plate_tr_rotation]))) return add(cap_list) else: shape_list = [thumb_tl_place(rotate(shape, [0, 0, thumb_plate_tl_rotation]))] if not default_1U_cluster: shape_list.append(thumb_tr_place(rotate(shape, [0, 0, thumb_plate_tr_rotation]))) return union(shape_list) else: if cap: shape = rotate(shape, (0, 0, 90)) shape_list = [ thumb_tl_place(shape), ] shape_list.append(thumb_tr_place(shape)) return add(shape_list) else: shape_list = [ thumb_tl_place(shape), ] if not default_1U_cluster: shape_list.append(thumb_tr_place(shape)) return union(shape_list) def double_plate_half(): debugprint('double_plate()') top_plate = box(mount_width, double_plate_height, web_thickness) top_plate = translate(top_plate, [0, (double_plate_height + mount_height) / 2, plate_thickness - (web_thickness / 2)] ) return top_plate def double_plate(): debugprint('double_plate()') top_plate = double_plate_half() return union((top_plate, mirror(top_plate, 'XZ'))) 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), cap=True) if not default_1U_cluster: t1.add(thumb_15x_layout(sa_cap(1.5), cap=True)) return t1 def default_thumb(side="right"): print('thumb()') shape = thumb_1x_layout(rotate(single_plate(side=side), (0, 0, -90))) shape = union([shape, thumb_15x_layout(rotate(single_plate(side=side), (0, 0, -90)))]) shape = union([shape, thumb_15x_layout(double_plate(), plate=False)]) return shape def thumb_post_tr(): debugprint('thumb_post_tr()') return translate(web_post(), [(mount_width / 2) - post_adj, ((mount_height/2) + double_plate_height) - post_adj, 0] ) def thumb_post_tl(): debugprint('thumb_post_tl()') return translate(web_post(), [-(mount_width / 2) + post_adj, ((mount_height/2) + double_plate_height) - post_adj, 0] ) def thumb_post_bl(): debugprint('thumb_post_bl()') return translate(web_post(), [-(mount_width / 2) + post_adj, -((mount_height/2) + double_plate_height) + post_adj, 0] ) def thumb_post_br(): debugprint('thumb_post_br()') return translate(web_post(), [(mount_width / 2) - post_adj, -((mount_height/2) + double_plate_height) + post_adj, 0] ) def default_thumb_connectors(): print('thumb_connectors()') hulls = [] # Top two if default_1U_cluster: hulls.append( triangle_hulls( [ thumb_tl_place(thumb_post_tr()), thumb_tl_place(thumb_post_br()), thumb_tr_place(web_post_tl()), thumb_tr_place(web_post_bl()), ] ) ) else: 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()), ] ) ) if default_1U_cluster: 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(web_post_bl()), thumb_mr_place(web_post_br()), thumb_tr_place(web_post_br()), ] ) ) else: # 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()), ] ) ) if default_1U_cluster: 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(web_post_tl()), key_place(web_post_bl(), 1, cornerrow), thumb_tr_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), thumb_tr_place(web_post_tr()), key_place(web_post_bl(), 2, lastrow), thumb_tr_place(web_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), ] ) ) else: 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 union(hulls) ############################ # MINI THUMB CLUSTER ############################ def mini_thumb_tr_place(shape): shape = rotate(shape, [14, -15, 10]) shape = translate(shape, thumborigin()) shape = translate(shape, [-15, -10, 5]) return shape def mini_thumb_tl_place(shape): shape = rotate(shape, [10, -23, 25]) shape = translate(shape, thumborigin()) shape = translate(shape, [-35, -16, -2]) return shape def mini_thumb_mr_place(shape): shape = rotate(shape, [10, -23, 25]) shape = translate(shape, thumborigin()) shape = translate(shape, [-23, -34, -6]) return shape def mini_thumb_br_place(shape): shape = rotate(shape, [6, -34, 35]) shape = translate(shape, thumborigin()) shape = translate(shape, [-39, -43, -16]) return shape def mini_thumb_bl_place(shape): shape = rotate(shape, [6, -32, 35]) shape = translate(shape, thumborigin()) shape = translate(shape, [-51, -25, -11.5]) return shape def mini_thumb_1x_layout(shape): return union([ mini_thumb_mr_place(rotate(shape, [0, 0, thumb_plate_mr_rotation])), mini_thumb_br_place(rotate(shape, [0, 0, thumb_plate_br_rotation])), mini_thumb_tl_place(rotate(shape, [0, 0, thumb_plate_tl_rotation])), mini_thumb_bl_place(rotate(shape, [0, 0, thumb_plate_bl_rotation])), ]) def mini_thumb_15x_layout(shape): return union([mini_thumb_tr_place(rotate(shape, [0, 0, thumb_plate_tr_rotation]))]) def mini_thumbcaps(): t1 = mini_thumb_1x_layout(sa_cap(1)) t15 = mini_thumb_15x_layout(rotate(sa_cap(1), [0, 0, rad2deg(pi / 2)])) return t1.add(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 = union([shape, mini_thumb_15x_layout(single_plate(side=side))]) return shape def mini_thumb_post_tr(): return translate(web_post(), [(mount_width / 2) - post_adj, (mount_height / 2) - post_adj, 0] ) def mini_thumb_post_tl(): return translate(web_post(), [-(mount_width / 2) + post_adj, (mount_height / 2) - post_adj, 0] ) def mini_thumb_post_bl(): return translate(web_post(), [-(mount_width / 2) + post_adj, -(mount_height / 2) + post_adj, 0] ) def mini_thumb_post_br(): return translate(web_post(), [(mount_width / 2) - post_adj, -(mount_height / 2) + post_adj, 0] ) 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_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), ] ) ) 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), ] ) ) return union(hulls) ############################ # Carbonfet THUMB CLUSTER ############################ def carbonfet_thumb_tl_place(shape): shape = rotate(shape, [10, -24, 10]) shape = translate(shape, thumborigin()) shape = translate(shape, [-13, -9.8, 4]) return shape def carbonfet_thumb_tr_place(shape): shape = rotate(shape, [6, -25, 10]) shape = translate(shape, thumborigin()) shape = translate(shape, [-7.5, -29.5, 0]) return shape def carbonfet_thumb_ml_place(shape): shape = rotate(shape, [8, -31, 14]) shape = translate(shape, thumborigin()) shape = translate(shape, [-30.5, -17, -6]) return shape def carbonfet_thumb_mr_place(shape): shape = rotate(shape, [4, -31, 14]) shape = translate(shape, thumborigin()) shape = translate(shape, [-22.2, -41, -10.3]) return shape def carbonfet_thumb_br_place(shape): shape = rotate(shape, [2, -37, 18]) shape = translate(shape, thumborigin()) shape = translate(shape, [-37, -46.4, -22]) return shape def carbonfet_thumb_bl_place(shape): shape = rotate(shape, [6, -37, 18]) shape = translate(shape, thumborigin()) shape = translate(shape, [-47, -23, -19]) return shape def carbonfet_thumb_1x_layout(shape): return union([ carbonfet_thumb_tr_place(rotate(shape, [0, 0, thumb_plate_tr_rotation])), carbonfet_thumb_mr_place(rotate(shape, [0, 0, thumb_plate_mr_rotation])), carbonfet_thumb_br_place(rotate(shape, [0, 0, thumb_plate_br_rotation])), carbonfet_thumb_tl_place(rotate(shape, [0, 0, thumb_plate_tl_rotation])), ]) def carbonfet_thumb_15x_layout(shape, plate=True): if plate: return union([ carbonfet_thumb_bl_place(rotate(shape, [0, 0, thumb_plate_bl_rotation])), carbonfet_thumb_ml_place(rotate(shape, [0, 0, thumb_plate_ml_rotation])) ]) else: return 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(rotate(sa_cap(1.5), [0, 0, rad2deg(pi / 2)])) return t1.add(t15) def carbonfet_thumb(side="right"): shape = carbonfet_thumb_1x_layout(single_plate(side=side)) shape = union([shape, carbonfet_thumb_15x_layout(double_plate_half(), plate=False)]) shape = union([shape, carbonfet_thumb_15x_layout(single_plate(side=side))]) return shape def carbonfet_thumb_post_tr(): return translate(web_post(), [(mount_width / 2) - post_adj, (mount_height / 1.15) - post_adj, 0] ) def carbonfet_thumb_post_tl(): return translate(web_post(), [-(mount_width / 2) + post_adj, (mount_height / 1.15) - post_adj, 0] ) def carbonfet_thumb_post_bl(): return translate(web_post(), [-(mount_width / 2) + post_adj, -(mount_height / 1.15) + post_adj, 0] ) def carbonfet_thumb_post_br(): return translate(web_post(), [(mount_width / 2) - post_adj, -(mount_height / 2) + post_adj, 0] ) 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 union(hulls) ########## ## Case ## ########## def bottom_hull(p, height=0.001): debugprint("bottom_hull()") if ENGINE == 'cadquery': shape = None for item in p: # proj = sl.projection()(p) # t_shape = sl.linear_extrude(height=height, twist=0, convexity=0, center=True)( # proj # ) vertices = [] verts = item.faces('= lastrow) if screws_offset == 'INSIDE': # debugprint('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': debugprint('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: # debugprint('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, ) shape = screw_insert_shape(bottom_radius, top_radius, height) shape = translate(shape, [position[0], position[1], height / 2]) return shape def screw_insert_thumb(bottom_radius, top_radius, height): if thumb_style == 'MINI': position = thumborigin() position = list(np.array(position) + np.array([-29, -51, -16])) position[2] = 0 elif thumb_style == 'CARBONFET': position = thumborigin() position = list(np.array(position) + np.array([-48, -37, 0])) position[2] = 0 else: position = thumborigin() position = list(np.array(position) + np.array([-21, -58, 0])) position[2] = 0 shape = screw_insert_shape(bottom_radius, top_radius, height) shape = translate(shape, [position[0], position[1], height / 2]) return shape def screw_insert_all_shapes(bottom_radius, top_radius, height, offset=0): print('screw_insert_all_shapes()') shape = ( translate(screw_insert(0, 0, bottom_radius, top_radius, height), (0, 0, offset)), translate(screw_insert(0, lastrow-1, bottom_radius, top_radius, height), (0, left_wall_lower_y_offset, offset)), translate(screw_insert(3, lastrow, bottom_radius, top_radius, height), (0, 0, offset)), translate(screw_insert(3, 0, bottom_radius, top_radius, height), (0,0, offset)), translate(screw_insert(lastcol, 0, bottom_radius, top_radius, height), (0, 0, offset)), translate(screw_insert(lastcol, lastrow-1, bottom_radius, top_radius, height), (0, 0, offset)), translate(screw_insert_thumb(bottom_radius, top_radius, height), (0, 0, offset)), ) return shape def screw_insert_holes(): return screw_insert_all_shapes( screw_insert_bottom_radius, screw_insert_top_radius, screw_insert_height+.02, offset=-.01 ) def screw_insert_outers(): return screw_insert_all_shapes( screw_insert_bottom_radius + 1.6, screw_insert_top_radius + 1.6, screw_insert_height + 1.5, ) def screw_insert_screw_holes(): return screw_insert_all_shapes(1.7, 1.7, 350) def wire_post(direction, offset): debugprint('wire_post()') s1 = box( wire_post_diameter, wire_post_diameter, wire_post_height ) s1 = translate(s1, [0, -wire_post_diameter * 0.5 * direction, 0]) s2 = box( wire_post_diameter, wire_post_overhang, wire_post_diameter ) s2 = translate(s2, [0, -wire_post_overhang * 0.5 * direction, -wire_post_height / 2] ) shape = union((s1, s2)) shape = translate(shape, [0, -offset, (-wire_post_height / 2) + 3]) shape = rotate(shape, [-alpha / 2, 0, 0]) shape = translate(shape, (3, -mount_height / 2, 0)) return shape def wire_posts(): debugprint('wire_posts()') shape = thumb_ml_place(wire_post(1, 0).translate([-5, 0, -2])) shape = union([shape, thumb_ml_place(wire_post(-1, 6).translate([0, 0, -2.5]))]) shape = union([shape, thumb_ml_place(wire_post(1, 0).translate([5, 0, -2]))]) for column in range(lastcol): for row in range(lastrow - 1): shape = union([ shape, key_place(wire_post(1, 0).translate([-5, 0, 0]), column, row), key_place(wire_post(-1, 6).translate([0, 0, 0]), column, row), key_place(wire_post(1, 0).translate([5, 0, 0]), column, row), ]) return shape def model_side(side="right"): print('model_right()') shape = union([key_holes(side=side)]) if debug_exports: export_file(shape=shape, fname=path.join(r"..", "things", r"debug_key_plates")) connector_shape = connectors() shape = union([shape, connector_shape]) if debug_exports: export_file(shape=shape, fname=path.join(r"..", "things", r"debug_connector_shape")) thumb_shape = thumb(side=side) if debug_exports: export_file(shape=thumb_shape, fname=path.join(r"..", "things", r"debug_thumb_shape")) shape = union([shape, thumb_shape]) thumb_connector_shape = thumb_connectors() shape = union([shape, thumb_connector_shape]) if debug_exports: export_file(shape=shape, fname=path.join(r"..", "things", r"debug_thumb_connector_shape")) walls_shape = case_walls() if debug_exports: export_file(shape=walls_shape, fname=path.join(r"..", "things", r"debug_walls_shape")) s2 = union([walls_shape]) s2 = union([s2, *screw_insert_outers()]) if controller_mount_type in ['RJ9_USB_TEENSY', 'USB_TEENSY']: s2 = union([s2, teensy_holder()]) if controller_mount_type in ['RJ9_USB_TEENSY', 'RJ9_USB_WALL', 'USB_WALL', 'USB_TEENSY']: s2 = union([s2, usb_holder()]) s2 = difference(s2, [usb_holder_hole()]) if controller_mount_type in ['RJ9_USB_TEENSY', 'RJ9_USB_WALL']: s2 = difference(s2, [rj9_space()]) if controller_mount_type in ['EXTERNAL']: s2 = difference(s2, [external_mount_hole()]) if controller_mount_type in ['None']: 0 # do nothing, only here to expressly state inaction. s2 = difference(s2, [union(screw_insert_holes())]) shape = union([shape, s2]) if controller_mount_type in ['RJ9_USB_TEENSY', 'RJ9_USB_WALL']: shape = union([shape, rj9_holder()]) if oled_mount_type == "UNDERCUT": hole, frame = oled_undercut_mount_frame() shape = difference(shape, [hole]) shape = union([shape, frame]) elif oled_mount_type == "SLIDING": hole, frame = oled_sliding_mount_frame() shape = difference(shape, [hole]) shape = union([shape, frame]) elif oled_mount_type == "CLIP": hole, frame = oled_clip_mount_frame() shape = difference(shape, [hole]) shape = union([shape, frame]) block = box(350, 350, 40) block = translate(block, (0, 0, -20)) shape = difference(shape, [block]) if show_caps: shape = add([shape, thumbcaps()]) shape = add([shape, caps()]) if side == "left": shape = mirror(shape, 'YZ') return shape # NEEDS TO BE SPECIAL FOR CADQUERY def baseplate(wedge_angle=None): if ENGINE == 'cadquery': # shape = mod_r shape = union([case_walls(), *screw_insert_outers()]) # tool = translate(screw_insert_screw_holes(), [0, 0, -10]) tool = screw_insert_all_shapes(screw_hole_diameter/2., screw_hole_diameter/2., 350) for item in tool: item = translate(item, [0, 0, -10]) shape = difference(shape, [item]) shape = translate(shape, (0, 0, -0.01)) square = cq.Workplane('XY').rect(1000, 1000) for wire in square.wires().objects: plane = cq.Workplane('XY').add(cq.Face.makeFromWires(wire)) shape = intersect(shape, plane) outside = shape.vertices(cq.DirectionMinMaxSelector(cq.Vector(1, 0, 0), True)).objects[0] sizes = [] max_val = 0 inner_index = 0 base_wires = shape.wires().objects for i_wire, wire in enumerate(base_wires): is_outside = False for vert in wire.Vertices(): if vert.toTuple() == outside.toTuple(): outer_wire = wire outer_index = i_wire is_outside = True sizes.append(0) if not is_outside: sizes.append(len(wire.Vertices())) if sizes[-1]>max_val: inner_index = i_wire max_val = sizes[-1] debugprint(sizes) inner_wire = base_wires[inner_index] # inner_plate = cq.Workplane('XY').add(cq.Face.makeFromWires(inner_wire)) if wedge_angle is not None: cq.Workplane('XY').add(cq.Solid.revolve(outerWire, innerWires, angleDegrees, axisStart, axisEnd)) else: inner_shape = cq.Workplane('XY').add(cq.Solid.extrudeLinear(outerWire=inner_wire, innerWires=[], vecNormal=cq.Vector(0, 0, base_thickness))) inner_shape = translate(inner_shape, (0, 0, -base_rim_thickness)) holes = [] for i in range(len(base_wires)): if i not in [inner_index, outer_index]: holes.append(base_wires[i]) cutout = [*holes, inner_wire] shape = cq.Workplane('XY').add(cq.Solid.extrudeLinear(outer_wire, cutout, cq.Vector(0, 0, base_rim_thickness))) hole_shapes=[] for hole in holes: loc = hole.Center() hole_shapes.append( translate( cylinder(screw_cbore_diameter, screw_cbore_depth), (loc.x, loc.y, 0) # (loc.x, loc.y, screw_cbore_depth/2) ) ) shape = difference(shape, hole_shapes) shape = translate(shape, (0, 0, -base_rim_thickness)) shape = union([shape, inner_shape]) return shape else: shape = union([ case_walls(), *screw_insert_outers() ]) tool = translate(union(screw_insert_screw_holes()), [0, 0, -10]) shape = shape - tool shape = translate(shape, [0, 0, -0.01]) return sl.projection(cut=True)(shape) def run(): mod_r = model_side(side="right") export_file(shape=mod_r, fname=path.join(save_path, config_name + r"_right")) if symmetry == "asymmetric": mod_l = model_side(side="left") export_file(shape=mod_l, fname=path.join(save_path, config_name + r"_left")) else: export_file(shape=mirror(mod_r, 'YZ'), fname=path.join(save_path, config_name + r"_left")) base = baseplate() export_file(shape=base, fname=path.join(save_path, config_name + r"_right_plate")) export_dxf(shape=base, fname=path.join(save_path, config_name + r"_right_plate")) lbase = mirror(base, 'YZ') export_file(shape=lbase, fname=path.join(save_path, config_name + r"_left_plate")) export_dxf(shape=lbase, fname=path.join(save_path, config_name + r"_left_plate")) if oled_mount_type == 'UNDERCUT': export_file(shape=oled_undercut_mount_frame()[1], fname=path.join(save_path, config_name + r"_oled_undercut_test")) if oled_mount_type == 'SLIDING': export_file(shape=oled_sliding_mount_frame()[1], fname=path.join(save_path, config_name + r"_oled_sliding_test")) 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) export_file(shape=oled_clip(), fname=path.join(save_path, config_name + r"_oled_clip")) export_file(shape=oled_clip_mount_frame()[1], fname=path.join(save_path, config_name + r"_oled_clip_test")) export_file(shape=union((oled_clip_mount_frame()[1], oled_clip())), fname=path.join(save_path, config_name + r"_oled_clip_assy_test")) # base = baseplate() # export_file(shape=base, fname=path.join(save_path, config_name + r"_plate")) if __name__ == '__main__': run()