def single_plate(cylinder_segments=100): top_wall = sl.cube([keyswitch_width + 3, 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, keyswitch_height + 3, 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 if plate_file is not None: socket = sl.import_(plate_file) socket = sl.translate([0, 0, plate_offset])(socket) plate = sl.union()(plate, socket) return plate
def turnout_cube(cube_size, paneling, left_hand=False): grooving = grooves(cube_size) diagonal_grooves = grooves(cube_size, diagonal=True, turnout=True) leds = turnout_led_holes(cube_size) button_holes = button_switch_holes(cube_size) if not left_hand: diagonal_grooves = mirror([1, 0, 0])(diagonal_grooves) leds = mirror([1, 0, 0])(leds) button_holes = mirror([1, 0, 0])(button_holes) holes = leds + grooving + diagonal_grooves + button_holes return plain_cube(cube_size, paneling) - holes
def switch_plate(): top_wall = forward((1.5 + keyswitch_length) / 2)( up(plate_thickness / 2)( cube((keyswitch_width + 3, 1.5, plate_thickness), center=True) - down(notch_plate_thickness)( # Notch for switch clips back(0.75)(cube((notch_width, notch_depth * 2, plate_thickness), center=True))))) left_wall = left((1.5 + keyswitch_width) / 2)(up(plate_thickness / 2)(cube( (1.5, keyswitch_length + 3, plate_thickness), center=True))) plate_half = top_wall + left_wall return plate_half + mirror((0, 1, 0))(mirror((1, 0, 0))(plate_half))
def cage_3_clips(z_length=10, inside=False): """3 clips arranged in proper distances for cage, aligned to optical axis at 0,0.""" third_rod_y = base.rods30_dist_third_rod - 25 # main pair of rods is at y=-25 clip_pair = base.base(z_length=z_length) single_clip = base.single_rod_clamp(z_length) if inside: clip_pair = translate((0, -50, 0))(mirror( (0, 1, 0))(clip_pair)) # clip at 25, needs to be moved back. single_clip = mirror((0, 1, 0))(single_clip) single_clip = translate((0, third_rod_y, 0))(rotate( (0, 0, 180))(single_clip)) return clip_pair + single_clip
def init_keyhole(self): top_wall = sl.cube([self.width + 3, 1.5, self.thickness], center=True) top_wall = sl.translate( (0, (1.5 / 2) + (self.height / 2), self.thickness / 2) )(top_wall) left_wall = sl.cube([1.5, self.height + 3, self.thickness], center=True) left_wall = sl.translate( ((1.5 / 2) + (self.width / 2), 0, self.thickness / 2) )(left_wall) side_nub = sl.cylinder(1, 2.75, segments=self.cylinder_segments, center=True) side_nub = sl.rotate(rad2deg(pi / 2), [1, 0, 0])(side_nub) side_nub = sl.translate((self.width / 2, 0, 1))(side_nub) nub_cube = sl.cube([1.5, 2.75, self.thickness], center=True) nub_cube = sl.translate( ((1.5 / 2) + (self.width / 2), 0, self.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 if self.hotswap_socket is not None: self.hotswap_socket = sl.translate([0, 0, self.thickness])( self.hotswap_socket) plate = sl.union()(plate, self.hotswap_socket) if self.cap_height is not None: cap = sl.cube([self.width, self.width, self.cap_height], center=True) self.cap = sl.translate([0, 0, ( self.thickness + self.switch_height + self.thickness)])( cap) if self.side == "left": plate = sl.mirror([-1, 0, 0])(plate) return plate
def platform(width, length, height): foot = end(width) head = translate((0, length, 0))(mirror((0, 1, 0))(foot)) slats = union()( [translate((0, y, 0))(slat(width)) for y in range(0, 70, 7)]) return (platform_color(head) + platform_color(foot) + platform_color(translate((0, 6.5, 0))(slats)))
def board_hook(clip_z=30, hook_opening=18, assemble=False): """ Hook for topmost end of cage - can be used to hang setup from a door, whiteboard, poster board, cabinet... 2019-05-13 - printed, works well. But: real-life poster board is one inch thick. """ assert base.__rods30, "this only makes sense for rod-mount" rod_clips = base.base_rods30(z_length=clip_z) rod_clips = translate((0, 0, clip_z / 2))(rod_clips) # start at z=0 hook_thick = 4 hook_width = 30 hook_z = 35 strut_height = 10 hook = translate((0, hook_opening - 20 + hook_thick / 2))(cube( (hook_width, hook_thick, hook_z), True)) hook = translate((0, 0, hook_z / 2))(hook) strut = cube((hook_thick, hook_opening + .1, strut_height), True) strut = translate((hook_width / 2 - hook_thick, (hook_opening - 40) / 2, strut_height / 2))(strut) strut += mirror((1, 0, 0))(strut) assembly = rod_clips + hook + strut if assemble: return translate((0, -50, 0))(rotate((0, 180, 180))(assembly)) else: return assembly
def double_plate(): plate_height = (sa_double_length - mount_height) / 3 # plate_height = (2*sa_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 sl.union()(top_plate, sl.mirror([0, 1, 0])(top_plate))
def slats(matress_width, matress_length, overhang): return color("peru")( translate((0, 0, 11 / 4))(slat_end(matress_width, overhang)) + translate((0, matress_length + 2 * overhang, 11 / 4))(mirror((0, 1, 0))(slat_end(matress_width, overhang))) + union()(*[ translate((0, overhang + y, 11 / 4))(slat_middle(matress_width, overhang)) for y in slat_displacements(matress_length) ]))
def end(width): body = cube((width, 1.5, 2.75)) tenon = cube((1.5, 1.5, 0.75)) return ( body + translate((width/3-0.75, 0, 2.75))(tenon) + translate((2*width/3-0.75, 0, 2.75))(tenon) - platformbed.joints.base_side_dovetail_joint() - translate((width, 0, 0))(mirror((1, 0, 0))(platformbed.joints.base_side_dovetail_joint())) - translate((width/2-0.75, 0, 1.375))(cube((1.5, 1.5, 1.375))) )
def base(width, length, height): left = side(length) right = translate((width, 0, 0))( mirror((1, 0, 0))(left) ) center = translate((width/2-0.75, 0, 0))( translate((0, 1.5, 0))(cube((1.5, length-3, 1.375))) + translate((0, 0, 1.375))(cube((1.5, length, 1.375))) ) foot = end(width) head = translate((0, length, 0))( mirror((0, 1, 0))(foot) ) return union()( end_color(head), end_color(foot), side_color(left), side_color(right), side_color(center), )
def box(width, height, depth, half=False, topbox=False): obj = sp.part() left = sp.cube([thickness, depth, height]) right = left.copy() right = spu.right(width - thickness)(right) obj += left + right top = sp.cube([width - 2 * thickness, depth, thickness]) top = spu.right(thickness)(top) if (half): ha = spu.up(height / 2 - thickness / 2)(top) obj += ha h = sp.cylinder(holes / 2, thickness + 10) top -= sp.translate([50, 50, 0])(h) top -= sp.translate([width - 50, 50, 0])(h) top -= sp.translate([width - 50, depth - 50, 0])(h) top -= sp.translate([50, depth - 50, 0])(h) bottom = top top = spu.up(height - thickness)(top) obj += top + bottom if (not topbox): sta = sp.cube([width * 3 / 4, thickness, 100]) sta = sp.rotate([0, -45, 0])(sta) cutout = sp.cube([width, depth, height]) cutout = spu.down(height / 4)(spu.left(width / 4)(cutout)) cutout -= spu.back(5)(sp.cube( [width / 2 - thickness, depth + 10, height / 2 - thickness])) sta -= spu.back(depth / 2)(cutout) sta = spu.right(thickness)(sta) sta += spu.right(width)(sp.mirror([1, 0, 0])(sta)) sta += sp.mirror([0, 0, 1])(sta) sta = spu.forward(depth - thickness)(sta) obj += (spu.up(height / 2)(sta) - ha) if (half and topbox): window = sp.cube( [width - 2 * thickness, thickness, height / 2 - 1.5 * thickness]) window = sp.translate([thickness, 0, thickness])(window) obj += spu.up(height / 2 - thickness / 2)(window) return obj
def circuit_board_for_turnout(cube_size, left_hand): led_lead_holes, led_pedastals = turnout_led_mount_holes(cube_size) button_holes = button_switch_mount_holes(cube_size) row_of_cable_holes = right(0.01 * inches)(union()(back(0.35 * inches)( cable_holes(cube_size)))) top_row = (row_of_cable_holes) bottom_row = back(0.1 * inches)(row_of_cable_holes) holes = resistor_holes( cube_size) + led_lead_holes + button_holes + top_row + bottom_row whole = (circuit_board() + led_pedastals - holes) * circuit_board_limit() if left_hand: whole = mirror([1, 0, 0])(whole) return whole
def base(matress_width, matress_length, overhang): end_to_end = zip( (base_side(matress_length, overhang), base_support(matress_length, overhang), base_support(matress_length, overhang), base_side(matress_length, overhang)), base_longitudinal_displacements(matress_width), ) end_to_end = union()( translate((0, overhang, 0))(base_end(matress_width, overhang)), translate((0, overhang + matress_length, 0))(mirror( (0, 1, 0))(base_end(matress_width, overhang))), *[translate((overhang + x, 0, 0))(part) for part, x in end_to_end]) return end_to_end
def front_wall(self): door_opening = left(self.door_opening_offset)(up( self.door_opening_threshold)(grounded_cube([ self.door_opening_width, 2 * self.wall_thickness, self.door_opening_height ]))) single_door = self.door() reverse_door = mirror([1, 0, 0])(single_door) single_offset = (self.door_width + self.door_crack) / 2 right_door = left(self.door_opening_offset - single_offset)(single_door) left_door = left(self.door_opening_offset + single_offset)(reverse_door) return forward(self.wall_y_offset)(self.main_wall() - door_opening + right_door + left_door)
def model_side(side="right"): shape = sl.union()(key_holes(side=side), connectors(), thumb(side=side), thumb_connectors(),) s2 = sl.union()(case_walls(), screw_insert_outers(), teensy_holder(), usb_holder(),) s2 = sl.difference()(s2, rj9_space(), usb_holder_hole(), screw_insert_holes()) shape = sl.union()(shape, s2, rj9_holder(), wire_posts(),) shape -= sl.translate([0, 0, -20])(sl.cube([350, 350, 40], center=True)) if side == "left": shape = sl.mirror([-1, 0, 0])(shape) return shape
def single_plate(cylinder_segments=100): top_wall = sl.cube([keyswitch_width + 3, 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, keyswitch_height + 3, 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 if hot_swap: hot_swap_socket = sl.import_( path.join(r"..", "geometry", r"hot_swap_plate.stl")) hot_swap_socket = sl.translate([0, 0, plate_thickness - 5.25 ])(hot_swap_socket) plate = sl.union()(plate, hot_swap_socket) return plate
def bard_brick(): double_thickness = 2 * THICKNESS base = basic_brick(WIDTH, LENGTH, HEIGHT) interior = down(THICKNESS)(basic_brick(WIDTH - double_thickness, LENGTH - double_thickness, HEIGHT)) handle = up(HEIGHT - HANDLE_HEIGHT)( forward((LENGTH + HANDLE_LENGTH) / 2 - THICKNESS)(grounded_cube( [HANDLE_WIDTH, THICKNESS + HANDLE_LENGTH, HANDLE_HEIGHT]))) chop = back(LENGTH / 2)(cube([CHOP_WIDTH, CHOP_LENGTH, 2 * CHOP_HEIGHT], center=True)) side_ridge = grounded_cube([SIDE_RIDGE_THICKNESS, LENGTH, HEIGHT]) side_ridges = union()([right(x)(side_ridge) for x in RIDGE_X]) end_ridge = forward(END_RIDGE_Y)(grounded_cube( [END_RIDGE_W + THICKNESS, END_RIDGE_DEPTH, HEIGHT])) brick = base - interior + handle - chop + side_ridges + end_ridge return mirror([0, 0, 1])(down(HEIGHT)(brick))
def groove_insert(cube_size, insert_sizing): assert insert_sizing in INSERT_SIZES is_diagonal = not insert_sizing in ['long', 'cross'] is_cross = insert_sizing == 'cross' is_turn_out = 'turnout' in insert_sizing is_short = insert_sizing == 'short' is_right_handed_turnout = is_turn_out and 'right' in insert_sizing if is_diagonal: spread = 2 * GROOVE_OFFSET if is_short or is_turn_out: spread = -spread insert_length = (cube_size + spread) * math.sqrt(0.5) + INSERT_THICKNESS limiting_length = insert_length * math.sqrt(0.5) limiter = rotate(45, [0, 1, 0])(cube( [limiting_length, limiting_length, limiting_length])) if is_turn_out: limiter *= up(INSERT_THICKNESS)(right(INSERT_THICKNESS)(limiter)) else: insert_length = cube_size limiter = None tab = right((insert_length - INSERT_TAB_HEIGHT) / 2)(cube( [INSERT_TAB_LENGTH, INSERT_TAB_HEIGHT, INSERT_THICKNESS])) if is_cross: insert_length = cube_size / 2 + GROOVE_OFFSET - GROOVE_DIAMETER / 2 insert = cube([insert_length, INSERT_HEIGHT, INSERT_THICKNESS]) if limiter: insert *= limiter if is_cross: pole_length = cube_size - insert_length pole_offset = cube_size / 2 - GROOVE_OFFSET - GROOVE_DIAMETER / 2 pole = right(pole_offset)(cube( [INSERT_THICKNESS, INSERT_HEIGHT, pole_length])) insert += pole result = insert + tab if is_turn_out: result = left(INSERT_THICKNESS)(result) if is_right_handed_turnout: result = right(insert_length - INSERT_THICKNESS)(mirror([1, 0, 0])(result)) return result
def left_right_symmetric(offset, target): left_target = left(offset)(mirror([1, 0, 0])(target)) right_target = right(offset)(target) return left_target + right_target
def y_symmetric(target): return mirror([0, 1, 0])(target)
def process_gerber( outline_file, solderpaste_file, stencil_thickness=0.2, include_ledge=True, ledge_height=1.2, ledge_gap=0.0, increase_hole_size_by=0.0, simplify_regions=False, flip_stencil=False, ): """Convert gerber outline and solderpaste files to an scad file.""" outline_shape = create_outline_shape(outline_file) cutout_polygon = create_cutouts( solderpaste_file, increase_hole_size_by=increase_hole_size_by, simplify_regions=simplify_regions, ) # debugging! # return scad_render(linear_extrude(height=stencil_thickness)(polygon(outline_shape))) if ledge_gap: # Add a gap between the ledge and the stencil outline_shape = offset_shape(outline_shape, ledge_gap) outline_polygon = polygon([v.as_tuple() for v in outline_shape]) if flip_stencil: mirror_normal = (-1, 0, 0) outline_bounds = geometry.bounding_box(outline_shape) outline_polygon = translate((outline_bounds[2][0], 0, 0))( mirror(mirror_normal)(outline_polygon) ) cutout_polygon = translate((outline_bounds[2][0], 0, 0))( mirror(mirror_normal)(cutout_polygon) ) stencil = linear_extrude(height=stencil_thickness)(outline_polygon - cutout_polygon) if include_ledge: ledge_shape = offset_shape(outline_shape, 1.2) ledge_polygon = polygon([v.as_tuple() for v in ledge_shape]) - outline_polygon # Cut the ledge in half by taking the bounding box of the outline, cutting it in half # and removing the resulting shape from the ledge shape # We always leave the longer side of the ledge intact so we don't end up with a tiny ledge. cutter = geometry.bounding_box(ledge_shape) height = abs(cutter[1][1] - cutter[0][1]) width = abs(cutter[0][0] - cutter[3][0]) if width > height: cutter[1].y -= height / 2 cutter[2].y -= height / 2 else: cutter[2].x -= width / 2 cutter[3].x -= width / 2 ledge_polygon = ledge_polygon - polygon([v.as_tuple() for v in cutter]) ledge = utils.down(ledge_height - stencil_thickness)( linear_extrude(height=ledge_height)(ledge_polygon) ) stencil = ledge + stencil # Rotate the stencil to make it printable stencil = rotate(a=180, v=(1, 0, 0))(stencil) # for debugging, output just the cutout polygon (extruded) # return scad_render(linear_extrude(height=stencil_thickness)(cutout_polygon)) return scad_render(stencil)
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", r"right_py.scad")) if symmetry == "asymmetric": mod_l = model_side(side="left") sl.scad_render_to_file( mod_l, path.join(r"..", "things", r"left_py.scad") ) else: sl.scad_render_to_file( sl.mirror([-1, 0, 0])(mod_r), path.join(r"..", "things", r"left_py.scad") ) def baseplate(): shape = sl.union()( case_walls(), teensy_holder(), # rj9_holder(), screw_insert_outers(), ) tool = sl.translate([0, 0, -10])(screw_insert_screw_holes()) shape = shape - tool
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(ROOT_DIR, "scad", r"right_py.scad")) if symmetry == "asymmetric": mod_l = model_side(side="left") sl.scad_render_to_file(mod_l, path.join(ROOT_DIR, "scad", r"left_py.scad")) else: sl.scad_render_to_file( sl.mirror([-1, 0, 0])(mod_r), path.join(ROOT_DIR, "scad", r"left_py.scad") ) def baseplate(): shape = sl.union()( case_walls(), teensy_holder(), # rj9_holder(), screw_insert_outers(), ) tool = sl.translate([0, 0, -10])(screw_insert_screw_holes()) shape = shape - tool
y, z, )(self) solid.OpenSCADObject.scale = solid.OpenSCADObject.s solid.OpenSCADObject.up = lambda self, d: solid.utils.up(d)(self) # along z solid.OpenSCADObject.down = lambda self, d: solid.utils.down(d)(self) solid.OpenSCADObject.left = lambda self, d: solid.utils.left(d)(self ) # along y solid.OpenSCADObject.right = lambda self, d: solid.utils.right(d)(self) solid.OpenSCADObject.forward = lambda self, d: solid.utils.forward(d)( self) # along x solid.OpenSCADObject.back = lambda self, d: solid.utils.back(d)(self) solid.OpenSCADObject.c = lambda self, c: solid.color(c)(self) solid.OpenSCADObject.color = solid.OpenSCADObject.c solid.OpenSCADObject.m = lambda self, a, b, c: solid.mirror([a, b, c])(self) solid.OpenSCADObject.mirror = solid.OpenSCADObject.m solid.OpenSCADObject.x = lambda self, d: solid.right(d)(self) # along z solid.OpenSCADObject.y = lambda self, d: solid.forward(d)(self) # along y solid.OpenSCADObject.z = lambda self, d: solid.up(d)(self) # along z solid.OpenSCADObject.e = lambda self, height, axis="z", center=True, **kwargs: ff_linear_extrude( self, height, axis, **kwargs) solid.OpenSCADObject.extrude = solid.OpenSCADObject.e solid.OpenSCADObject.linear_extrude = solid.OpenSCADObject.e solid.OpenSCADObject.dump = lambda self, fn, prefix="": dump(self, fn, prefix) def cy(r=None,
shape = sl.union()( shape, s2, rj9_holder(), wire_posts(), ) shape -= sl.translate([0, 0, -20])(sl.cube([350, 350, 40], center=True)) return shape sl.scad_render_to_file(model_right(), path.join(r"..", "things", r"right_py.scad")) sl.scad_render_to_file( sl.mirror([-1, 0, 0])(model_right()), path.join(r"..", "things", r"left_py.scad")) def baseplate(): shape = sl.union()( case_walls(), teensy_holder(), # rj9_holder(), screw_insert_outers(), ) tool = sl.translate([0, 0, -10])(screw_insert_screw_holes()) shape = shape - tool