예제 #1
0
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
예제 #2
0
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))
예제 #4
0
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
예제 #5
0
    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
예제 #6
0
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)))
예제 #7
0
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
예제 #8
0
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))
예제 #9
0
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)
        ]))
예제 #10
0
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)))
    )
예제 #11
0
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),
    )
예제 #12
0
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
예제 #13
0
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
예제 #14
0
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
예제 #15
0
 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)
예제 #16
0
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
예제 #17
0
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
예제 #18
0
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))
예제 #19
0
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
예제 #20
0
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
예제 #21
0
def y_symmetric(target):
    return mirror([0, 1, 0])(target)
예제 #22
0
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)
예제 #23
0
        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
예제 #24
0
    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
예제 #25
0
    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,
예제 #26
0
    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