def spaced_hole_punch(offsets, spacings, diameter, thickness): x_offset, y_offset, z_offset = offsets x_spacings, z_spacings = spacings hole = back(y_offset)(up(z_offset)(right(x_offset)(punch_hole( diameter, thickness)))) return union()( [up(z)(right(x)(hole)) for z in z_spacings for x in x_spacings])
def grid_plane(grid_unit=12, count=10, line_weight=0.1, plane='xz'): # Draws a grid of thin lines in the specified plane. Helpful for # reference during debugging. elle = count * grid_unit t = union() t.set_modifier('background') for i in range(-count // 2, count // 2 + 1): if 'xz' in plane: # xz-plane h = up(i * grid_unit)(cube([elle, line_weight, line_weight], center=True)) v = right(i * grid_unit)(cube([line_weight, line_weight, elle], center=True)) t.add([h, v]) # xy plane if 'xy' in plane: h = forward(i * grid_unit)(cube([elle, line_weight, line_weight], center=True)) v = right(i * grid_unit)(cube([line_weight, elle, line_weight], center=True)) t.add([h, v]) # yz plane if 'yz' in plane: h = up(i * grid_unit)(cube([line_weight, elle, line_weight], center=True)) v = forward(i * grid_unit)(cube([line_weight, line_weight, elle], center=True)) t.add([h, v]) return t
def control_box(wall_length, wall_width, wall_height): max_board_thickness = max(pro_micro.board_thickness, distribution_board.board_thickness) board_surface_pos = max(20 + wall_thickness - wall_length, 5) case_length = (board_surface_pos + max_board_thickness + 3 + wall_thickness) case_width = (pro_micro.board_length + distribution_board.board_length + 3 * wall_thickness) board_offset_forward = (board_surface_pos + max_board_thickness - case_length / 2) def position_control_box(part): """Position the control box on the final model.""" #return left(case_width / 2)( return left(wall_width / 4 - case_width / 2)(forward( (wall_length + case_length) / 2)(up(wall_height / 2)(part))) def position_controller(part): """Position the controller board within the control box.""" return forward(board_offset_forward)( left(case_width / 2 - wall_thickness + wall_thickness / 4)(rotate( (90, -90, 0))(part))) def position_distribution_board(part): """Position the distribution board within the control box.""" return forward(board_offset_forward)( right(case_width / 2 - wall_thickness + wall_thickness / 4)(rotate( (90, 90, 0))(part))) center_post_length = max_board_thickness + 3 center_post_offset_right = (case_width / 2 - wall_thickness * 1.5 - distribution_board.board_length) inner = (down(wall_thickness / 2 + 1)(back(wall_thickness + 1)(cube( ( case_width - 2 * wall_thickness, case_length + 2, wall_height - wall_thickness + 1, ), center=True, ))) + rotate( (90, 0, 0))(right(center_post_offset_right)(cylinder_outer(4.5, 100)))) case = position_control_box( cube((case_width, case_length, wall_height), center=True) - inner # Center post (between the two boards): + forward(board_surface_pos - case_length / 2 + center_post_length / 2) (right(center_post_offset_right) (cube((wall_thickness * 2, center_post_length, wall_height), center=True) - rotate((90, 0, 0)) (cylinder_outer(m2_shaft_radius, center_post_length)))) - position_controller(pro_micro.board_profile(0)) - position_distribution_board(distribution_board.board_profile(0))) cutout = position_control_box(inner) return (case, cutout)
def catmull_rom_spline_variants(): points = [ Point2(0,0), Point2(1,1), Point2(2,1), Point2(2,-1), ] controls = control_points(points) # By default, catmull_rom_points() will return a closed smooth shape curve_points_closed = catmull_rom_points(points, close_loop=True) # If `close_loop` is False, it will return only points between the start and # end control points, and make a best guess about tangents for the first and last segments curve_points_open = catmull_rom_points(points, close_loop=False) # By specifying start_tangent and end_tangent, you can change a shape # significantly. This is similar to what you might do with Illustrator's Pen Tool. # Try changing these vectors to see the effects this has on the rightmost curve in the example start_tangent = Vector2(-2, 0) end_tangent = Vector2(3, 0) tangent_pts = [points[0] + start_tangent, *points, points[-1] + end_tangent] tangent_controls = control_points(tangent_pts) curve_points_tangents = catmull_rom_points(points, close_loop=False, start_tangent=start_tangent, end_tangent=end_tangent) closed = polygon(curve_points_closed) + controls opened = polygon(curve_points_open) + controls tangents = polygon(curve_points_tangents) + tangent_controls a = closed + right(3)(opened) + right(10)(tangents) return a
def extrude_example_xy_scaling() -> OpenSCADObject: num_points = SEGMENTS path_rad = PATH_RAD circle = circle_points(15) path = circle_points(rad=path_rad) # If scales aren't included, they'll default to # no scaling at each step along path. no_scale_obj = make_label('No Scale') no_scale_obj += extrude_along_path(circle, path) # angles: from 0 to 6*Pi angles = list((frange(0, 3 * tau, num_steps=len(path)))) # With a 1-D scale factor, an extrusion grows and shrinks uniformly x_scales = [(1 + cos(a) / 2) for a in angles] x_obj = make_label('1D Scale') x_obj += extrude_along_path(circle, path, scales=x_scales) # With a 2D scale factor, a shape's X & Y dimensions can scale # independently, leading to more interesting shapes # X & Y scales vary between 0.5 & 1.5 xy_scales = [Point2(1 + cos(a) / 2, 1 + sin(a) / 2) for a in angles] xy_obj = make_label('2D Scale') xy_obj += extrude_along_path(circle, path, scales=xy_scales) obj = no_scale_obj + right(3 * path_rad)(x_obj) + right( 6 * path_rad)(xy_obj) return obj
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)
def assembly(): return sp.union()( sp.color('red')(spu.right(100.)(wheel.volume())), sp.color('green')(right_stub_axle.volume()), sp.color('blue')(spu.right(58.)(sp.rotate( (0., 90., 0.))(wheel_bushing.volume()))), )
def slot(r_head, h_head, r_shaft, width, height): """slot openscad styled vertically oriented printable slot origin formed by the center of left circle :param r_head: the radius of the top of the screw, [mm] :param h_head: the height of the top of the screw, [mm] :param r_shaft: the radius of the shaft of the screw, [mm] :param width: the width of the slot, [mm] :param height: the height of the slot, [mm] """ h_shaft = height - h_head - (r_head - r_shaft) head = cylinder(h=h_head, r=r_head, segments=30) # 45 degrees cone for printability cone = up(h_head)(cylinder(h=r_head - r_shaft, r1=r_head, r2=r_shaft, segments=30)) shaft = up(h_head + (r_head - r_shaft))(cylinder(h=h_shaft, r=r_shaft, segments=30)) cyl = head + cone + shaft inner = hull()(cyl, right(width)(cyl)) cyl = cylinder(h=height, r=r_head + THICK_WALL) outer = hull()(cyl, right(width)(cyl)) slot = outer - hole()(inner) return slot
def final(): return down(1)(block()) \ - left(y / 2)( \ right(21)(down(5.5)(usbconn())) \ + right(4)(down(2)(button())) \ + right(14)(arduino()) \ )
def add_keystones(face, jack_placements, height): jack = keystone() keyhole = keystone_hole() for x, h in jack_placements: y = h - height / 2 face -= forward(y)(right(x)(keyhole)) face += forward(y)(right(x)(jack)) return face
def boxmount(): base = cube([30, 50, 2]) circ = cylinder(h=10, r=1.6, segments=30) circs = right(5)(circ) + right(25)(circ) base -= forward(5)(circs) base -= forward(25)(circs) base -= forward(45)(circs) base = rotate([90, 0, 90])(base) return base
def assembly(): left_wall = draw_side_wall() right_wall = utils.right(dimensions.drawer_x)(draw_side_wall()) bottom = draw_bottom() front_wall = draw_front_back() back_wall = utils.forward(dimensions.drawer_y - 1)(draw_front_back()) knob = utils.back(0.4)(draw_knob()) knob = utils.right(dimensions.drawer_y)(knob) knob = utils.up(dimensions.drawer_z / 2)(knob) drawer = left_wall + right_wall + bottom + front_wall + back_wall + knob return drawer
def assembly(): box = big_box.assembly() box = utils.color('blue')(box) bottom_drawer = utils.up(1)(utils.right(1)(drawers.assembly())) bottom_drawer = utils.color('red')(bottom_drawer) top_drawer = utils.right(1)(utils.up((dimensions.box_x / 4) - 1)( drawers.assembly())) top_drawer = utils.color('green')(top_drawer) middle_spacer = solid.cube([dimensions.box_x, 1, 1.5]) middle_spacer = utils.up((dimensions.box_z / 2) - 0.5)(middle_spacer) middle_spacer = utils.right(0.5)(middle_spacer) middle_spacer = utils.color('blue')(middle_spacer) monitor_stand = box + bottom_drawer + top_drawer + middle_spacer return monitor_stand
def __init__(self, retainer_diameter, height, depth, threads_per_inch, cap_diameter, hole_diameter, cap_thickness,**kwargs): r_r = to_mm(retainer_diameter/2.) height = to_mm(height) h_r = to_mm(hole_diameter/2.) c_r = to_mm(cap_diameter/2.) c_t = to_mm(cap_thickness) threads_per_inch = threads_per_inch o_d = kwargs.get('outer_diameter') i_d = kwargs.get('inner_diameter') if 'bodytube' in kwargs: o_d = kwargs['bodytube'].outer_diameter i_d = kwargs['bodytube'].inner_diameter print i_d i_r = to_mm(i_d/2.) o_r = to_mm(o_d/2.) print retainer_diameter flange_d = to_mm(kwargs.get('flange_diameter'), safe=True) flange_t = to_mm(kwargs.get('flange_thickness'), safe=True) spine_diameter = to_mm(kwargs.get('spine_diameter'), safe=True) round_radius = to_mm(kwargs.get('round_radius',0)) if flange_d and flange_t: flange = cylinder(h=flange_t, r=flange_d/2.) else: flange = cylinder(h=height, r=o_r/2.) # HACK because this will be removed self.retainer = difference() (self.threaded_male_column(height, to_mm(retainer_diameter), threads_per_inch) + flange, cylinder(h=height, r=o_r), up(height-depth), cylinder(h=depth, r=i_r)) self.cap = difference()(cylinder(h=height,r=c_r), self.threaded_female_column(height-c_t, to_mm(retainer_diameter), threads_per_inch), cylinder(h=height, r=h_r)) if spine_diameter: no_spines = kwargs.get('spines',0) spines = [] for idx in xrange(0, no_spines): spines.append(rotate([0,0,360/no_spines*idx])(right(c_r)(cylinder(h=height-c_t-spine_diameter/2, r=spine_diameter/2)+ up(height-c_t-spine_diameter/2)(sphere(r=spine_diameter/2.))))) self.cap+=union()(*spines) self.round = rotate_extrude()(right(c_r-round_radius)(square([round_radius,round_radius])*circle(round_radius))) self.cap -= up(height-round_radius)(rotate_extrude()(right(c_r-round_radius)(square([round_radius,round_radius])))) self.cap += up(height-round_radius)(self.round)
def laserbase(laserheight): """laserabase creates the basis for the laser with ventilation wall The laserbase is in the XY plane at quadrant 1. One corner is at the origin. The width is parallel to the x-axis. The laser was provided by Odic Force, productid OFL510-1. The padheight is laser height- 16.5 The laserbundle travels in the +x direction and departs from the center, that is 15 mm. param: laserheight: the desired height of the laser """ # The laser tube is at 8 mm from bottom. # The laser tube has a diameter of 17 mm # The laser is at 8 + 17 * 0.5 - 1 = 16.5 mm (shim of 1 mm needed) # The laser base is 30x60 mm, which was made # 30x75 mm to make room for the ventilator # PARAMETERS height = laserheight - 15.5 # [mm], xdisp = 48.5 # [mm], x-displacement screws ydisp = 16 # [mm], y-displacement screws r_shaft = 2 # [mm], shaft radius screws h_head = 5 # [mm], height shaft head r_head = 3.5 # [mm], top radius screws tspile = 4 # [mm], y-thickness ventilation spile hspile = 25 # [mm], height ventilation spile length = 75 # [mm], x-direction length laser width = 30 # [mm], y-direction width laser screw_offst = 7 # [mm], screw offset +x-edge # MINIMAL MATERIAL BASE screws = screw(r_head, h_head, r_shaft, height) + right(xdisp)(screw( r_head, h_head, r_shaft, height)) spiegel = forward(ydisp / 2)(mirror([0, 1, 0])(back(ydisp / 2)(screws))) screws += spiegel base = translate([length - xdisp - screw_offst, (width - ydisp) / 2, 0])(screws) # ventilation wall # spile spile = up(height)(cube([THICK_WALL, tspile, hspile])) nofspiles = ceil((width) / (tspile * 2)) # shift base base = right(THICK_WALL)(base) # add wall base += cube([THICK_WALL, width, HEIGHT_WALL]) # create pockets for i in range(0, nofspiles): base -= hole()(forward(i * 2 * tspile + THICK_WALL)(spile)) return base
def button_switch_mount_holes(cube_size, add_cleat=True): single_lead_cylinder = cylinder(r=SWITCH_LEAD_DIAMETER / 2, h=cube_size, center=True, segments=16) hole_displacement = 0.075 * inches lead_hole_pair = left(hole_displacement)(single_lead_cylinder) + right( hole_displacement)(single_lead_cylinder) lead_hole_pair = rotate(-45)(lead_hole_pair) button_holes = [ right(BUTTON_HOLE_X_OFFSETS[index])(forward( BUTTON_HOLE_Y_OFFSETS[index])(lead_hole_pair)) for index in range(len(BUTTON_HOLE_Y_OFFSETS)) ] return union()(button_holes)
def slots(): slot = single_slot() return left(SLOT_OFFSET_X)(back(SLOT_OFFSET_Y)(union()([ right(ix * SLOT_SPACING_X)(forward(iy * SLOT_SPACING_Y)(slot)) for ix in range(SLOT_COUNT_X) for iy in range(SLOT_COUNT_Y) ])))
def key_grid_tester( length_units, width_units, wall_height=default_wall_height, margin_length=0, margin_width=0, ): x_grid_size = mount_width + switch_spacing y_grid_size = mount_length + switch_spacing case = key_grid_tester_walls( length_units, width_units, wall_height, margin_length, margin_width ) + up(wall_height - plate_thickness)( right(x_grid_size * (width_units - 1) / 2)( back(y_grid_size * (length_units - 1) / 2)( *[ left(x_grid_size * x_units)( forward(y_grid_size * y_units)(spaced_switch_plate()) ) for y_units in range(length_units) for x_units in range(width_units) ] ) ) ) return case
def slot_peg_with_catch( diameter=DEFAULT_PEG_DIAMETER, thickness=DEFAULT_HOLDER_THICKNESS, clearance=DEFAULT_CLEARANCE, overreach=None, slot_width=None, slot_clearance=DEFAULT_CONTAINER_CLEARANCE ): if overreach is None: overreach = diameter peg = solid_peg(diameter=diameter, thickness=thickness, clearance=clearance, overreach=overreach) if slot_width is None: slot_width = 0.35 * min(diameter, overreach) hole_height = clearance + overreach hole_displacement = slot_clearance + thickness + 0.5 * hole_height round_hole_bottom = back(0.5 * hole_height)( cylinder(r=0.5 * slot_width, h=2 * diameter, center=True, segments=16)) hole_cutout = cube([slot_width, hole_height, 2 * diameter], center=True) hole = up(hole_displacement)( rotate([90.0, 0.0, 0.0])( hole_cutout + round_hole_bottom)) catch_height = clearance + thickness + 0.5 * diameter catch_offset = 0.5 * diameter unscaled_catch = up(catch_height)( rotate([90, 0, 0])( cylinder(r=0.5 * diameter, h=0.5 * slot_width, center=True, segments=4))) catch = scale([0.4, 1.0, 1.0])(unscaled_catch) return peg \ + left(catch_offset)(catch) \ + right(catch_offset)(catch) \ - hole
def multipart_hole(): # It's good to be able to keep holes empty, but often we want to put # things (bolts, etc.) in them. The way to do this is to declare the # object containing the hole a "part". Then, the hole will remain # empty no matter what you add to the 'part'. But if you put an object # that is NOT part of the 'part' into the hole, it will still appear. # On the left (not_part), here's what happens if we try to put an object # into an explicit hole: the object gets erased by the hole. # On the right (is_part), we mark the cube-with-hole as a "part", # and then insert the same 'bolt' cylinder into it. The entire # bolt rematins. b = cube(10, center=True) c = cylinder(r=2, h=12, center=True) # A cube with an explicit hole not_part = b - hole()(c) # Mark this cube-with-hole as a separate part from the cylinder is_part = part()(not_part.copy()) # This fits in the holes bolt = cylinder(r=1.5, h=14, center=True) + up(8)(cylinder( r=2.5, h=2.5, center=True)) # The section of the bolt inside not_part disappears. The section # of the bolt inside is_part is still there. return not_part + bolt + right(45)(is_part + bolt)
def lasershim(height): """lasershim This is a shim which can be used to pad. The base of the shim is in the XY plane at quadrant 1. One corner is at the origin. The width is parallel to the x-axis. The shim can be used if the laserbase is not correctly alligned. The laser was provided by Odic Force, productid OFL510-1. param: height: defines height shim [mm] """ # PARAMETER xdisp = 48.5 # [mm], x-displacement screw ydisp = 16 # [mm], y-displacement screws r_shaft = 2 + 0.5 # [mm], shaft radius screws length = 75 # [mm], x-direction length laser width = 30 # [mm], y-direction width laser screw_offst = 7 # [mm], screw offset +x-edge # MAXIMAL MATERIAL BASE base = cube([length, width, height]) # screw holes screws = cylinder(h=height, r=r_shaft) + right(xdisp)(cylinder(h=height, r=r_shaft)) spiegel = forward(ydisp / 2)(mirror([0, 1, 0])(back(ydisp / 2)(screws))) screws += spiegel # create holes base -= translate([length - xdisp - screw_offst, (width - ydisp) / 2, 0])(screws) return base
def cable_holes(cube_size): single_cable_hole = cylinder(r=LED_LEAD_DIAMETER / 2, h=2 * cube_size, center=True, segments=16) return left(0.4 * inches)( [right(index * 0.2 * inches)(single_cable_hole) for index in range(5)])
def grooves(cube_size, diagonal=False, doubled=False, turnout=False): groove = groove_cylinder(cube_size) if diagonal: groove = rotate(-45)(groove) short_offset = 0.5 * (cube_size / 2 - GROOVE_OFFSET) long_offset = 0.5 * (cube_size / 2 + GROOVE_OFFSET) if turnout: x_offsets = [2 * short_offset - long_offset, long_offset] y_offsets = [long_offset, long_offset] else: x_offsets = y_offsets = [short_offset, long_offset] else: x_offsets = [0, 0] y_offsets = [-GROOVE_OFFSET, GROOVE_OFFSET] groove_pair = union()([ right(x_offset)(forward(y_offset)(groove)) for x_offset, y_offset in zip(x_offsets, y_offsets) ]) if turnout: limiting_block = forward(cube_size + GROOVE_OFFSET)(cube( [2 * cube_size, 2 * cube_size, 2 * cube_size], center=True)) groove_pair *= limiting_block if doubled: groove_pair += rotate(180, [0, 0, 1])(groove_pair) return groove_pair
def assembly(): left_wall = lateral_wall() right_wall = utils.right(dimensions.box_x)(lateral_wall()) bottom = bottom_top_wall() top = utils.up(dimensions.box_z)(bottom_top_wall()) back = utils.forward(dimensions.box_y - 1)(back_wall()) return left_wall + right_wall + bottom + top + back
def panelmountmini(): """panelmount panel mount for panel Mount cable -B to Mini-B cable http://adafru.it/936 """ base = cube([40, 20, THICK_WALL], center=True) # screw hole screw_hole = cylinder(r=1.75, h=THICK_WALL * 2, center=True, segments=30) # create two holes + hole usb cube base -= hole()(left(14)(screw_hole) + right(14)(screw_hole) + cube([17.5, 12, THICK_WALL * 2], center=True)) # change orientation base = right(0.5 * THICK_WALL)(rotate([0, 90, 0])(rotate([0, 0, 90])(base))) return base
def tool_holes(self): offset = TOOL_HOLE_DISPLACEMENT / 2 hole = cylinder(r=TOOL_HOLE_DIAMETER / 2 + self.inflation, h=2 * PLATE_THICKNESS, center=True, segments=32) return left(offset)(hole) + right(offset)(hole)
def mounting_slots(): slot = grounded_cube([MOUNT_SLOT_WIDTH, MOUNT_SLOT_THICKNESS, HOLE_HEIGHT]) return union()([ right(x)(forward(y)(slot)) for x in [-MOUNT_SLOT_X_OFFSET, MOUNT_SLOT_X_OFFSET] for y in [-MOUNT_SLOT_Y_OFFSET, 0, MOUNT_SLOT_Y_OFFSET] ])
def __init__(self): # stretched oval body = hull()(circle(radius) + right(phone_width)(circle(radius))) # used to hold the layers together body = body - self.screw_holes() # set self self.body = body # proper X-axis alignment self.body = right(radius)(body) # cut possible hole if self.hole: self.body -= self.hole.make_hole()
def xulaconnector(): screw_xuout = 2.5 screw_xuin = 1.5 screw_toph = 1 offset = 5 length = offset + THICK_WALL # XULA2 is attached to the top with two screws screw_xula = hscrew(screw_xuout, screw_toph, screw_xuin, length) screws_xula = screw_xula + right(58)(screw_xula) screws_xula += up(48.8)(screws_xula) xula_base = screws_xula # Raspberry connector xula2 rsp_cnctr = cube([58 - 2 * (screw_xuin + THICK_WALL * 0.5), length, 6]) xula_base += translate([screw_xuin + THICK_WALL * 0.5, -length, -3 + 48.8])(hole()(rsp_cnctr)) # add stickit connector top_height = 4 # top height screw in mm top_r = 3.5 # top r screw in mm shaft_r = 2 screw_stick = hscrew(top_r, top_height, shaft_r, length) screws_stick = screw_stick + up(15)(screw_stick) # stickit length 49.6-1.28-2-2 # 15.5+1.5+1.2-1.5 xula_base += translate( [-(49.6 - 1.28 - 2 - 2) - 8, 0, 15.5 + 1.5 + 1.2 - 1.5 - 2.7])(screws_stick) xula_base += translate([-60, -2, -8])(cube([123, 2, 61])) xula_base = up(THICK_WALL + 11)(xula_base) # add down connector base_exit = cube([58 + 2 * screw_xuin + THICK_WALL, 16, THICK_WALL]) base_exit += hole()(translate( [screw_xuin + THICK_WALL * 0.5, THICK_WALL, 0])(cube([58 - 2 * (screw_xuin + THICK_WALL * 0.5), 12, THICK_WALL]))) xula_base += back(16)(base_exit) return xula_base
def flat(): body = square(size=[length, height]) holes = [] num_cutouts = int(ceil(length / step)) for i in xrange(num_cutouts + 1): holes.append(right((i + 1) * step)(slit())) body -= union()(holes) return body
def fibcubes(): g = translate([0, 0, 0]) for x in range(2): g += right(x * m.fibcube_side)(fibcube()) h = translate([0, 0, 0]) for x in range(2): for y in range(2): h += forward(y * m.fibcube_side)(right(x * m.fibcube_side)(fibcube())) h = right(28)(h) i = translate([0, 0, 0]) for x in range(2): i += right(x * (m.fibcube_side + 3))(fibcube()) i = forward(13)(i) return g + h + i
def box(): floor = down(BIG)(grounded_cube([BIG, BIG, BIG])) side = forward(HALF_LENGTH)(grounded_cube([THICKNESS, LENGTH, HEIGHT])) left_side = left(SIDE_OFFSET)(side) right_side = right(SIDE_OFFSET)(side) rear = forward(THICKNESS / 2)(grounded_cube([WIDTH, THICKNESS, HEIGHT])) door = bottom() + left_side + right_side + rear return tilt_back(door) - floor
def flat(): def offset(i, break_after=5): x = 0 if i < break_after else phone_width + layer_y_gap + radius y = i * (radius + layer_y_gap) y = y - break_after * (radius + layer_y_gap) if x > 0 else y return x, y layers = [] for i, l in enumerate(ls): x, y = offset(i) l_inst = l() layer = l_inst.body layer = color(l_inst.color)(layer) layers.append(right(x)(forward(y)(layer))) return union()(layers)
v.screw_length = s.var(10, comment='Length of thread to be inside spacer.', end_comment='[3:45]') v.head_hole_height = s.var('spacer_height - screw_length') body = s.cube(size=[spacer_depth, spacer_width, v.spacer_height]) slot = u.up(3)(s.cube(size=[spacer_depth, 10, 2])) slot_round = u.back(1)(u.up(2)( s.rotate(a=v.spacer_height, v=[1, 0, 0])( s.cube(size=[spacer_depth, 4, 4]) ) )) screw_hole = u.forward(5)( s.cylinder(r=v.screw_head_radius, h=v.head_hole_height, segments=32) + u.up(v.head_hole_height)( s.cylinder(r=v.screw_radius, h=v.screw_length, segments=32) ) ) screw_hole_1 = u.right(screw_offset)(screw_hole) screw_hole_2 = u.right(screw_offset_2)(screw_hole) wire_run = u.up(20)(s.cube(size=[spacer_depth, 4, 9])) final = body - slot - slot_round - screw_hole_1 - screw_hole_2 - wire_run s.scad_render_to_file(final, __file__.replace('.py', '.scad'), variables=v)
# inner to subtract from the body for the body inner = s.cube( size=[depth - wall_width, square_width, height - walls_width] ) inner += u.up(inner_rad)(s.rotate(a=[0, 90, 0])( s.cylinder(r=inner_rad, h=depth - wall_width, segments=segments) )) inner += u.forward(square_width)(u.up(inner_rad)( s.rotate(a=[0, 90, 0])( s.cylinder(r=inner_rad, h=depth - wall_width, segments=segments) ) )) # subtract inner from body body -= u.right(wall_width)(u.up(wall_width)(inner)) # subtract sensor hole body -= u.forward(sensor_y - sensor_width / 2.0)( u.right(depth - top_hole_depth + half_wall_width)(u.up( height - wall_width)( s.cube(size=[depth - top_hole_depth, sensor_width, wall_width]) )) ) # bolt base 1 body += u.up(bolt_z)(u.forward(bolt_base1_y)(u.right(depth - half_wall_width)( s.rotate(a=[90 - bolt_base_angle, -90, 0])( s.cylinder( d1=bolt_base_dia, d2=0.0, h=bolt_base_depth, segments=segments) )
def make_hole(self): body = square([self.width, self.height]) layer_width = (phone_width + 2 * radius) moved_right = right(layer_width / 2 - self.width / 2)(body) moved_down = back(self.height / 2 + self.y_adjust)(moved_right) return moved_down
def screw_holes(self): return [ left(screw_hole_shift)(circle(screw_hole_radius)), right(screw_hole_shift + phone_width)(circle(screw_hole_radius)) ]
screw_head_radius = 4 screw_rad = 2 screw_length = 10 head_hole_height = spacer_height - screw_length body = s.cube(size=[spacer_depth, spacer_width, spacer_height]) slot = u.up(3)(s.cube(size=[spacer_depth, 10, 2])) slot_round = u.back(1)(u.up(2)( s.rotate(a=spacer_height, v=[1, 0, 0])( s.cube(size=[spacer_depth, 4, 4]) ) )) screw_hole = u.forward(5)( s.cylinder(r=screw_head_radius, h=head_hole_height, segments=32) + u.up(head_hole_height)( s.cylinder(r=screw_rad, h=screw_length, segments=32) ) ) screw_hole_1 = u.right(screw_offset)(screw_hole) screw_hole_2 = u.right(spacer_depth - screw_offset)(screw_hole) wire_run = u.up(20)(s.cube(size=[spacer_depth, 4, 9])) final = body - slot - slot_round - screw_hole_1 - screw_hole_2 - wire_run s.scad_render_to_file(final, __file__.replace('.py', '.scad'))