Example #1
0
def basic_geometry():
    # SolidPython code can look a lot like OpenSCAD code.  It also has
    # some syntactic sugar built in that can make it look more pythonic.
    # Here are two identical pieces of geometry, one left and one right.

    # left_piece uses standard OpenSCAD grammar (note the commas between
    # block elements; OpenSCAD doesn't require this)
    left_piece = union()(translate((-15, 0, 0))(cube([10, 5, 3], center=True)),
                         translate(
                             (-10, 0, 0))(difference()(cylinder(r=5,
                                                                h=15,
                                                                center=True),
                                                       cylinder(r=4,
                                                                h=16,
                                                                center=True))))

    # Right piece uses a more Pythonic grammar.  + (plus) is equivalent to union(),
    # - (minus) is equivalent to difference() and * (star) is equivalent to intersection
    # solid.utils also defines up(), down(), left(), right(), forward(), and back()
    # for common transforms.
    right_piece = right(15)(cube([10, 5, 3], center=True))
    cyl = cylinder(r=5, h=15, center=True) - cylinder(r=4, h=16, center=True)
    right_piece += right(10)(cyl)

    return union()(left_piece, right_piece)
Example #2
0
def m3_12():
    bolt_height = 12
    m = union()(
            head(),
            translate((0, 0, -bolt_height))(
                    cylinder(r=m3_rad, h=bolt_height)
            )
    )
    return m
Example #3
0
def makestack(dia):
    stack = union()(cylinder(d=dia + WALL * 2, h=TRAY_H - FLOOR) -
                    up(FLOOR)(cylinder(d=dia, h=TRAY_H)))
    hole_pcg = 0.7
    stack -= hole()(down(1)(cylinder(d=dia * hole_pcg, h=TRAY_H)))
    stack -= hole()(translate([-dia / 2 - WALL, -dia / 2 * hole_pcg, -1])(cube(
        [dia / 2 + WALL, dia * hole_pcg, TRAY_H * 3])))

    return stack
Example #4
0
def assembly():
    return union()(
            doohickey(c='blue'),
            translate((-10, 0, doohickey_h / 2))(m3_12()),
            translate((0, 0, doohickey_h / 2))(m3_16()),
            translate((10, 0, doohickey_h / 2))(m3_12()),
            # Nuts
            translate((-10, 0, -nut_height - doohickey_h / 2))(m3_nut()),
            translate((0, 0, -nut_height - doohickey_h / 2))(m3_nut()),
            translate((10, 0, -nut_height - doohickey_h / 2))(m3_nut()),
    )
Example #5
0
def bottom_part():
    top = difference()
    u = union()
    u2 = union()
    top.add(u)
    d = difference()
    d.add(cylinder(r=innerR + wall + gap, h=toph))
    d.add(translate((0, 0, baseH)).add(cylinder(r=innerR + gap, h=toph)))
    u.add(d)
    top.add(u2)
    for i in range(0, 3):
        a = i * 2 * pi / 3
        r = innerR + gap + wall / 2
        u.add(
            translate(((r - 0.3) * cos(a), (r - 0.3) * sin(a),
                       toph - 6)).add(sphere(r=2.4)))
        u2.add(
            translate(((r + wall - 0.3) * cos(a), (r + wall - 0.3) * sin(a),
                       toph - 6)).add(sphere(r=2.4)))

    return top
def screws():
    """The screw holes that need to be applied to both halves"""
    threads = []
    for x in [0, IPAD_W + WALL * 1 + SLIP * 2 + INNER_WALL * 1 + WALL_PADDING]:
        for y in [
                30,
                IPAD_H + WALL * 2 + SLIP * 2 + INNER_WALL + WALL_PADDING - 30
        ]:
            threads.append(
                translate([x, y,
                           BACK + IPAD_D / 2])(rotate([0, 90,
                                                       0])(screwthread())))
    return union()(*threads)
Example #7
0
def main(out_dir):
    # Parameters
    height_ratio = 0.25
    left_loc = ONE_THIRD
    midpoint_loc = 0.5
    right_loc = 2 * ONE_THIRD
    gens = 5

    # Results
    all_polys = union()

    # setup
    ax, ay = 0, 0
    bx, by = 100, 0
    cx, cy = 50, 86.6
    base_seg1 = LineSegment2(Point2(ax, ay), Point2(cx, cy))
    base_seg2 = LineSegment2(Point2(cx, cy), Point2(bx, by))
    base_seg3 = LineSegment2(Point2(bx, by), Point2(ax, ay))
    generations = [[base_seg1, base_seg2, base_seg3]]

    # Recursively generate snowflake segments
    for g in range(1, gens):
        generations.append([])
        for seg in generations[g - 1]:
            generations[g].extend(
                kochify(seg, height_ratio, left_loc, midpoint_loc, right_loc))

    # # Put all generations into SCAD
    orig_length = abs(generations[0][0])
    for g, a_gen in enumerate(generations):
        points = [s.p1 for s in a_gen]

        # Just use arrays for points so SCAD understands
        points = [[p.x, p.y] for p in points]

        # Move each generation up in y so it doesn't overlap the others
        h = orig_length * 1.5 * g

        # Do the SCAD
        edges = [list(range(len(points)))]
        all_polys.add(forward(h)(polygon(points=points, paths=edges)))

    file_out = scad_render_to_file(all_polys,
                                   out_dir=out_dir,
                                   include_orig_code=True)
    print(f"{__file__}: SCAD file written to: {file_out}")
Example #8
0
def top_part():
    maze_path = os.path.join(os.path.dirname(__file__), 'maze7.png')

    depth_map = build_depth_map(maze_path)

    d = difference()
    u = union()
    u.add(bumpMapCylinder(depth_map, innerR, hn, 0, 255))
    u.add(cylinder(r=innerR + wall + gap, h=gripH))
    d.add(u)
    d.add(intersection().add(
        bumpMapCylinder(depth_map, innerR, hn + 2, wall,
                        0).set_modifier("")).add(
                            translate((0, 0, baseH)).add(
                                cylinder(r=innerR + 2 * wall,
                                         h=h * 1.1).set_modifier(""))))
    return d
def ipadminiholderfront():
    # Back (wall mount)
    # o = sizedipad(IPAD_W + WALL * 2 + SLIP * 2, IPAD_H + WALL * 2 + SLIP * 2, BACK)
    o = union()
    # Front supports
    o += sizedipad(
        TOTAL_W,
        IPAD_H + WALL * 2 + SLIP * 2 + INNER_WALL + WALL_PADDING,
        IPAD_D + WALL + SLIP + BACK,
    )

    sides = WALL + INNER_WALL + WALL_PADDING + SLIP

    # Cutouts for buttons, round curves around the button
    o -= translate([
        IPAD_W + WALL + SLIP * 2 + INNER_WALL + WALL_PADDING - BUTTON_D / 2 -
        BUTTON_TO_EDGE,
        (IPAD_H + WALL * 2 + SLIP * 2) / 2 + INNER_WALL + WALL_PADDING,
        BACK,
    ])(cylinder(d=BUTTON_D, h=50))
    o -= translate([
        sides + SCREEN_SIDE_EDGE - SCREEN_BORDER + IPAD_W -
        (SCREEN_SIDE_EDGE - SCREEN_BORDER) * 2 + BUTTON_D / 2,
        (IPAD_H + WALL * 2 + SLIP * 2) / 2 + INNER_WALL + WALL_PADDING +
        BUTTON_D,
        BACK,
    ])(difference()(
        translate([-BUTTON_D, -BUTTON_D, 0])(cube([BUTTON_D, BUTTON_D, 50])),
        cylinder(d=BUTTON_D, h=50),
    ))
    o -= translate([
        sides + SCREEN_SIDE_EDGE - SCREEN_BORDER + IPAD_W -
        (SCREEN_SIDE_EDGE - SCREEN_BORDER) * 2 + BUTTON_D / 2,
        (IPAD_H + WALL * 2 + SLIP * 2) / 2 + INNER_WALL + WALL_PADDING -
        BUTTON_D,
        BACK,
    ])(difference()(
        translate([-BUTTON_D, 0, 0])(cube([BUTTON_D, BUTTON_D, 50])),
        cylinder(d=BUTTON_D, h=50),
    ))
    # Camera
    o -= translate([
        sides + BUTTON_TO_EDGE + BUTTON_D / 2,
        (IPAD_H + WALL * 2 + SLIP * 2) / 2 + INNER_WALL + WALL_PADDING,
        BACK,
    ])(cylinder(d=BUTTON_D, h=50))
    o -= translate([
        sides + SCREEN_SIDE_EDGE - SCREEN_BORDER - BUTTON_D / 2,
        (IPAD_H + WALL * 2 + SLIP * 2) / 2 + INNER_WALL + WALL_PADDING +
        BUTTON_D,
        BACK,
    ])(difference()(
        translate([0, -BUTTON_D, 0])(cube([BUTTON_D, BUTTON_D, 50])),
        cylinder(d=BUTTON_D, h=50),
    ))
    o -= translate([
        sides + SCREEN_SIDE_EDGE - SCREEN_BORDER - BUTTON_D / 2,
        (IPAD_H + WALL * 2 + SLIP * 2) / 2 + INNER_WALL + WALL_PADDING -
        BUTTON_D,
        BACK,
    ])(difference()(
        translate([0, 0, 0])(cube([BUTTON_D, BUTTON_D, 50])),
        cylinder(d=BUTTON_D, h=50),
    ))

    # # Camera
    # o -= translate([WALL + SIDE_EDGE / 2, (IPAD_H + WALL * 2 + SLIP * 2) / 2, BACK])(
    #     cylinder(d=BUTTON_D, h=50)
    # )

    # Cutout for actual iPad, made very tall to allow sliding in/out
    if ALLOW_IPAD_SLIDE_IN:
        height = IPAD_H * 2 + INNER_WALL + WALL_PADDING
    else:
        height = IPAD_H + INNER_WALL * 2 + WALL_PADDING
    o -= translate([WALL, WALL, -1])(sizedipad(
        IPAD_W + SLIP * 2 + INNER_WALL * 2 + WALL_PADDING * 2,
        height,
        IPAD_D + SLIP + BACK + 1,
    ))
    # Cutout for remaining material around where the extra overhang is for the power
    # connector
    o -= translate([WALL, WALL, -1])(sizedipad(
        TOTAL_W - WALL * 2,
        IPAD_H + INNER_WALL * 2 + WALL_PADDING,
        IPAD_D + SLIP + BACK + 1,
    ))
    # Cutout for screen
    o -= translate([
        sides + SCREEN_SIDE_EDGE - SCREEN_BORDER,
        sides + SCREEN_BOTTOM_EDGE - SCREEN_BORDER,
        BACK,
    ])(cube([
        IPAD_W - (SCREEN_SIDE_EDGE - SCREEN_BORDER) * 2,
        IPAD_H - (SCREEN_BOTTOM_EDGE - SCREEN_BORDER) * 2,
        IPAD_D * 3,
    ]))
    # Side "hooks"
    o += translate([WALL, (IPAD_H - 15 * 2) + 15, 0])(rotate([90, 0, 0])(
        linear_extrude(IPAD_H - 15 * 2)(polygon([[0, 0], [1, 0], [0, 1]]))))
    o += translate([TOTAL_W - WALL * 2 + WALL, 15, 0])(rotate([-90, 180, 0])(
        linear_extrude(IPAD_H - 15 * 2)(polygon([[0, 0], [1, 0], [0, 1]]))))
    o += translate([
        (TOTAL_W - 15 * 2) + 15, WALL, 0
    ])(rotate([0, -90, 0])(linear_extrude(TOTAL_W - 15 * 2)(polygon([[0, 0],
                                                                     [1, 0],
                                                                     [0,
                                                                      1]]))))
    # o += translate([15, WALL, 0])(cube([IPAD_W - 15 * 2, WALL, WALL]))

    # Power connector
    if POWER_CONNECTOR_ACCESSIBLE:
        o -= translate([
            IPAD_W / 2,
            (IPAD_H + WALL * 2 + SLIP * 2) / 2 + INNER_WALL + WALL_PADDING -
            POWER_UNDERHANG - BUTTON_D / 2,
            -1,
        ])(cube([IPAD_W, BUTTON_D + POWER_UNDERHANG,
                 IPAD_D + SLIP + BACK + 1]))

    # Lock Button
    if ALLOW_IPAD_SLIDE_IN:
        extra = 100
    else:
        extra = 0
    o -= translate([
        -1,
        (IPAD_H + WALL * 2 + SLIP * 2) - LOCK_BUTTON_TO_EDGE -
        LOCK_BUTTON_LEN + INNER_WALL + WALL_PADDING,
        0,
    ])(cube([50, LOCK_BUTTON_LEN + extra, IPAD_D + SLIP + BACK]))

    # Screws
    o -= screws()

    if SHOW_IPAD:
        o += translate([
            WALL + INNER_WALL + SLIP + WALL_PADDING,
            WALL + INNER_WALL + SLIP + WALL_PADDING,
            BACK,
        ])(IPAD_STL).set_modifier("")

    return o
Example #10
0
def assembly():
    # Your code here!
    a = union()

    return a
Example #11
0
def main_3d(out_dir):
    gens = 4

    # Parameters
    ab_weight = 0.5
    bc_weight = 0.5
    ca_weight = 0.5
    pyr_a_weight = ONE_THIRD
    pyr_b_weight = ONE_THIRD
    pyr_c_weight = ONE_THIRD
    pyr_height_weight = ONE_THIRD

    all_polys = union()

    # setup
    ax, ay, az = 100, -100, 100
    bx, by, bz = 100, 100, -100
    cx, cy, cz = -100, 100, 100
    dx, dy, dz = -100, -100, -100
    generations = [[
        [Point3(ax, ay, az),
         Point3(bx, by, bz),
         Point3(cx, cy, cz)],
        [Point3(bx, by, bz),
         Point3(ax, ay, az),
         Point3(dx, dy, dz)],
        [Point3(ax, ay, az),
         Point3(cx, cy, cz),
         Point3(dx, dy, dz)],
        [Point3(cx, cy, cz),
         Point3(bx, by, bz),
         Point3(dx, dy, dz)],
    ]]

    # Recursively generate snowflake segments
    for g in range(1, gens):
        generations.append([])
        for a, b, c in generations[g - 1]:
            new_tris = kochify_3d(a, b, c, ab_weight, bc_weight, ca_weight,
                                  pyr_a_weight, pyr_b_weight, pyr_c_weight,
                                  pyr_height_weight)
            generations[g].extend(new_tris)

    # Put all generations into SCAD
    orig_length = abs(generations[0][0][1] - generations[0][0][0])
    for g, a_gen in enumerate(generations):
        # Move each generation up in y so it doesn't overlap the others
        h = orig_length * 1.5 * g

        # Build the points and triangles arrays that SCAD needs
        faces = []
        points = []
        for a, b, c in a_gen:
            points.extend([[a.x, a.y, a.z], [b.x, b.y, b.z], [c.x, c.y, c.z]])
            t = len(points)
            faces.append([t - 3, t - 2, t - 1])

        # Do the SCAD
        edges = [list(range(len(points)))]
        all_polys.add(up(h)(polyhedron(points=points, faces=faces)))

    file_out = Path(out_dir) / 'koch_3d.scad'
    file_out = scad_render_to_file(all_polys, file_out, include_orig_code=True)
    print(f"{__file__}: SCAD file written to: {file_out}")
Example #12
0
        all_tets = [subtet for tet in all_tets for subtet in tet.next_gen(midpoint_weight, jitter_range_vec)]

    if scale != 1:
        for tet in all_tets:
            tet.scale(scale)
    return all_tets


if __name__ == '__main__':
    out_dir = Path(sys.argv[1]) if len(sys.argv) > 1 else Path.cwd()

    generations = 3
    midpoint_weight = 0.5
    # jitter_range_vec adds some randomness to the generated shape,
    # making it more interesting.  Try:
    # jitter_range_vec = [0.5,0, 0]
    jitter_range_vec = None
    all_tets = sierpinski_3d(generations, scale=100, midpoint_weight=midpoint_weight, jitter_range_vec=jitter_range_vec)

    t = union()
    for tet in all_tets:
        # Create the scad code for all tetrahedra
        t.add(tet.scad_code())
        # Draw cubes at all intersections to make the shape manifold.
        for p in tet.points:
            t.add(translate(p).add(cube(5, center=True)))

    file_out = out_dir / f'gasket_{generations}_gen.scad'
    file_out = scad_render_to_file(t, file_out)
    print(f"{__file__}: SCAD file written to: \n{file_out}")
Example #13
0
def main(params: Params):
    # face
    face_profile = roundrect(
        [LGX_FACE_WIDTH, LGX_FACE_HEIGHT + params.lgx_face_extra_height],
        params.face_radius,
    )
    cutout_profile = roundrect([params.poe_face_width, params.poe_face_height],
                               params.poe_face_radius)
    cutout_x = LGX_FACE_WIDTH / 2 - params.poe_face_width / 2
    cutout_y = params.poe_face_lift + params.platform_thickness
    cutout = translate([cutout_x, cutout_y, 0])(cutout_profile)
    cutout_extrude = debug(
        down(params.lgx_rack_thickness)(
            linear_extrude(params.face_thickness +
                           params.lgx_rack_thickness)(cutout)))

    post = circle(d=params.face_post_d)
    posts = post + right(params.face_post_separation)(post)
    posts = translate([
        LGX_FACE_WIDTH / 2 - params.face_post_separation / 2,
        LGX_FACE_HEIGHT / 2, 0
    ])(posts)

    face = difference()(face_profile, posts)
    face_extrusion = linear_extrude(height=params.face_thickness)(face)

    tray_depth = (params.platform_thickness + params.poe_depth +
                  params.lgx_rack_thickness)

    # tray
    tray = linear_extrude(height=params.platform_thickness)(
        square(size=[LGX_PLATFORM_WIDTH, tray_depth]))

    poe_holder_outer_params = [
        params.poe_width + params.platform_thickness * 2,
        tray_depth,
    ]
    poe_holder_profile = difference()(
        square(poe_holder_outer_params),
        right(params.platform_thickness)(forward(params.lgx_rack_thickness)(
            square([
                params.poe_width,
                params.poe_depth,
            ]))),
    )
    poe_holder_extrude = linear_extrude(
        height=params.poe_retainer_height)(poe_holder_profile)
    poe_holder = translate([
        LGX_PLATFORM_WIDTH / 2 - poe_holder_outer_params[0] / 2,
        0,
        params.platform_thickness,
    ])(poe_holder_extrude)

    tray = union()(poe_holder, tray)
    tray = rotate([270, 0, 0])(translate(
        [LGX_FACE_WIDTH / 2 - LGX_PLATFORM_WIDTH / 2, 0, 0])(tray))

    # support
    support_start_inset = (params.platform_thickness + LGX_FACE_WIDTH / 2 -
                           LGX_PLATFORM_WIDTH / 2)
    point_extent = LGX_FACE_HEIGHT - params.platform_thickness
    support_profile = polygon([[0, 0], [0, point_extent], [point_extent, 0]])
    support = linear_extrude(height=params.platform_thickness)(support_profile)
    support = rotate([270, 0, 90])(support)
    support_left = translate([support_start_inset, 0, 0])(support)
    support_right = translate([
        support_start_inset + LGX_PLATFORM_WIDTH - params.platform_thickness,
        0, 0
    ])(support)

    return difference()(union()(face_extrusion, tray, support_left,
                                support_right), cutout_extrude)
Example #14
0
    top = difference()
    u = union()
    u2 = union()
    top.add(u)
    d = difference()
    d.add(cylinder(r=innerR + wall + gap, h=toph))
    d.add(translate((0, 0, baseH)).add(cylinder(r=innerR + gap, h=toph)))
    u.add(d)
    top.add(u2)
    for i in range(0, 3):
        a = i * 2 * pi / 3
        r = innerR + gap + wall / 2
        u.add(
            translate(((r - 0.3) * cos(a), (r - 0.3) * sin(a),
                       toph - 6)).add(sphere(r=2.4)))
        u2.add(
            translate(((r + wall - 0.3) * cos(a), (r + wall - 0.3) * sin(a),
                       toph - 6)).add(sphere(r=2.4)))

    return top


if __name__ == '__main__':
    out_dir = sys.argv[1] if len(sys.argv) > 1 else None
    file_out = os.path.join(out_dir, 'mazebox.scad')

    assm = union()(top_part(), translate((3 * innerR, 0, 0))(bottom_part()))

    print(f"{__file__}: SCAD file written to: \n{file_out}")
    scad_render_to_file(assm, file_out, file_header=f'$fn = {SEGMENTS};')