def scaledipad(x, y, height):
    """Returns an instance of the iPad scaled to have x, y mm extra size, at height"""
    xscale = (IPAD_W + x) / IPAD_W
    yscale = (IPAD_H + y) / IPAD_H
    print(xscale, yscale)
    o = linear_extrude(height)(polygon(IPAD_POINTS))
    return scale([xscale, yscale, 1])(o)
Example #2
0
 def test_fillet_2d_add(self):
     pts = [[0, 5], [5, 5], [5, 0], [10, 0], [10, 10], [0, 10], ]
     p = polygon(pts)
     three_points = [euclidify(pts[0:3], Point2)]
     actual = fillet_2d(three_points, orig_poly=p, fillet_rad=2, remove_material=False)
     expected = 'union(){polygon(points=[[0,5],[5,5],[5,0],[10,0],[10,10],[0,10]]);translate(v=[3.0000000000,3.0000000000]){difference(){intersection(){rotate(a=359.9000000000){translate(v=[-998,0,0]){square(center=false,size=[1000,1000]);}}rotate(a=450.1000000000){translate(v=[-998,-1000,0]){square(center=false,size=[1000,1000]);}}}circle(r=2);}}}'
     self.assertEqualOpenScadObject(expected, actual)
Example #3
0
    def test_fillet_2d_remove(self):
        pts = list((project_to_2D(p) for p in tri))
        poly = polygon(euc_to_arr(pts))
        newp = fillet_2d([pts], orig_poly=poly, fillet_rad=2, remove_material=True)
        expected = 'difference(){polygon(paths=[[0,1,2]],points=[[0,0],[10,0],[0,10]]);translate(v=[5.1715728753,2.0000000000]){difference(){intersection(){rotate(a=-90.1000000000){translate(v=[-998,0,0]){square(center=false,size=[1000,1000]);}}rotate(a=45.1000000000){translate(v=[-998,-1000,0]){square(center=false,size=[1000,1000]);}}}circle(r=2);}}}'
        actual = scad_render(newp)

        self.assertEqualNoWhitespace(expected, actual)
Example #4
0
 def test_imported_scad_arguments(self):
     include_file = self.expand_scad_path("examples/scad_to_include.scad")
     mod = import_scad(include_file)
     points = mod.scad_points();
     poly = polygon(points);
     actual = scad_render(poly);
     abs_path = points._get_include_path(include_file)
     expected = f'use <{abs_path}>\n\n\npolygon(points = scad_points());'
     self.assertEqual(expected, actual)
Example #5
0
    def test_fillet_2d_remove(self):
        pts = tri
        poly = polygon(euc_to_arr(tri))

        newp = fillet_2d(tri,
                         orig_poly=poly,
                         fillet_rad=2,
                         remove_material=True)
        expected = '\n\ndifference() {\n\tpolygon(paths = [[0, 1, 2]], points = [[0, 0, 0], [10, 0, 0], [0, 10, 0]]);\n\ttranslate(v = [5.1715728753, 2.0000000000, 0.0000000000]) {\n\t\tdifference() {\n\t\t\tintersection() {\n\t\t\t\trotate(a = 268.0000000000) {\n\t\t\t\t\ttranslate(v = [-998, 0, 0]) {\n\t\t\t\t\t\tsquare(center = false, size = [1000, 1000]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\trotate(a = 407.0000000000) {\n\t\t\t\t\ttranslate(v = [-998, -1000, 0]) {\n\t\t\t\t\t\tsquare(center = false, size = [1000, 1000]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tcircle(r = 2);\n\t\t}\n\t}\n}'
        actual = scad_render(newp)
        if expected != actual:
            print(''.join(difflib.unified_diff(expected, actual)))
        self.assertEqual(expected, actual)
Example #6
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 #7
0
 def test_fillet_2d_add(self):
     pts = [
         [0, 5],
         [5, 5],
         [5, 0],
         [10, 0],
         [10, 10],
         [0, 10],
     ]
     p = polygon(pts)
     newp = fillet_2d(euclidify(pts[0:3], Point3),
                      orig_poly=p,
                      fillet_rad=2,
                      remove_material=False)
     expected = '\n\nunion() {\n\tpolygon(paths = [[0, 1, 2, 3, 4, 5]], points = [[0, 5], [5, 5], [5, 0], [10, 0], [10, 10], [0, 10]]);\n\ttranslate(v = [3.0000000000, 3.0000000000, 0.0000000000]) {\n\t\tdifference() {\n\t\t\tintersection() {\n\t\t\t\trotate(a = 358.0000000000) {\n\t\t\t\t\ttranslate(v = [-998, 0, 0]) {\n\t\t\t\t\t\tsquare(center = false, size = [1000, 1000]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\trotate(a = 452.0000000000) {\n\t\t\t\t\ttranslate(v = [-998, -1000, 0]) {\n\t\t\t\t\t\tsquare(center = false, size = [1000, 1000]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tcircle(r = 2);\n\t\t}\n\t}\n}'
     actual = scad_render(newp)
     self.assertEqual(expected, actual)
Example #8
0
def threadedinsert(flip_x, thick, holesize, length):
    """insert
    heatpress insert

    Heatpress can be inserted from the top. The screw should also be inserted
    from the top. The screw is centered at the origin.
    The wall thickness are specified by;
    http://uk.farnell.com/tr-fastenings-brass-inserts-for-plastics
    The length and hole size should be obtained from the sheet.
    this threaded is supported by a triangle and can be mirrored in the
    x-direction
    :param flip_x: flip insert in, origin shifted back
    :param length: length of the insert
    :param holesize: diameter of the hole
    """
    # NOTE: other options
    # -sliding ; this results in a cable collision
    # -press insert; more recommended for photopolymer parts, less permanent
    # -bolt printed inside; requires print pause, not useful in production
    # -magnet; magnets are dangerous for electronics
    x_extent = holesize + 2 * thick
    y_extent = holesize / 2 + thick + SCREW_FIXOFFST
    base = cube([x_extent, y_extent, length])
    triangle = polygon([[0, 0], [y_extent, y_extent], [0, y_extent]])
    prism = linear_extrude(x_extent)(triangle)
    support = translate([x_extent, y_extent, 0])(rotate([90, 0, -90])(prism))
    base = support + up(y_extent)(base)
    base -= translate([holesize / 2 + thick, holesize / 2 + thick,
                       0])(cylinder(h=length + y_extent,
                                    r=holesize / 2,
                                    segments=30))
    # changed orientation to simplify placement
    base = down(y_extent + length)(base)
    # center origin at Z-axis
    base = translate(
        [-x_extent / 2, -SCREW_FIXOFFST + thick + holesize / 2, 0])(base)
    if flip_x:
        base = rotate([0, 0, 180])(base)
    return base
def ipadcorner(height=7.2):
    """Returns a 15x15mm corner of the ipad at mm height"""
    o = linear_extrude(height)(polygon(IPAD_CORNER))
    return o
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 #11
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)