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 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(): outer_bars = sp.rotate([-90, 0, 0])([ spu.left(d)(box_section.volume(length=outer_length, center=False, color='red')) for d in [-outer, outer] ]) inner_bars = sp.rotate([-90, 0, 0])([ spu.left(d)(box_section.volume(length=inner_length, center=False, color='green')) for d in [-inner, inner] ]) front_bumper = spu.forward(inner_length + (box_section.default_size[0] / 2.))(sp.rotate( [0, 90, 0])(box_section.volume( length=inner * 2. + box_section.default_size[0], center=True, color='blue'))) mid_bars = spu.forward(outer_length + box_section.default_size[0] / 2.)( sp.rotate([0, 90, 0])( box_section.volume(length=inner * 2. - box_section.default_size[0], center=True, color='cyan'), [ sp.rotate([0, a, 0])( spu.up(inner + box_section.default_size[0] / 2.)( box_section.volume( length=outer - inner, center=False, color='cyan'))) for a in [0, 180] ], ), ) rear_bar = spu.back(box_section.default_size[0] / 2.)(sp.rotate([ 0, 90, 0 ])(box_section.volume(length=outer * 2. + box_section.default_size[0], center=True, color='magenta'))) bearings = spu.forward(rear_axle_position)(sp.rotate([180, 0, 0])([ sp.translate([x, 0, box_section.default_size[0] / 2. ])(sp.color('orange')(rear_axle_bearing.volume())) for x in [-outer, outer] ])) front_axle_and_wheels = sp.color('gray')(sp.translate( (0, 1150, -box_section.default_size[0]))(front_axle.assembly())) return sp.union()( outer_bars, inner_bars, front_bumper, mid_bars, rear_bar, bearings, front_axle_and_wheels, )
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 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(): # Catmull-Rom Splines a = basic_catmull_rom() a += forward(4)(catmull_rom_spline_variants()) a += forward(6)(bottle_shape(width=2, height=6)) # Bezier Splines a += forward(12)(basic_bezier()) a += forward(18)(bezier_points_variants()) return a
def position_mounting_points(part): x_offset = wall_width / 2 - wall_thickness y_offset = wall_length / 2 - wall_thickness return (left(x_offset)(forward(y_offset)(part)) + right(x_offset)(forward(y_offset)(part)) + left(x_offset)(back(y_offset)(part)) + right(x_offset)(back(y_offset)(part)) + right(split_offset - wall_thickness)(forward(y_offset)(part)) + right(split_offset + wall_thickness)(forward(y_offset)(part)) + right(split_offset - wall_thickness)(back(y_offset)(part)) + right(split_offset + wall_thickness)(back(y_offset)(part)))
def makeRail(self): length = self.RailLen cap = cube([length, self.CapWide, self.CapThik]) leg = up(self.CapThik)(cube( [length, self.LegThik, self.ChanHi + self.eps])) asm = cap + forward( self.ChanHang1)(leg) + forward(self.CapWide - self.ChanHang2 - self.LegThik)(leg) px = self.Pillar1 while px < length: asm += self.makePillar(px) px += self.PillarSep return asm
def ueyeholder(): """ueyeholder creates a holder for an ueye camera A holder for an uEye camera to view upward. The uEye camera cannot look upward due its connector on the back. This design solves this problem via a cubical enclosure. """ #### UEYE cubical dimension margin = 0.3 size_x = 34 # mm size_y = 32 # mm size_z = 34.6 # mm ### UEYE screw screw_d = 3 # mm screw_z = 30.4 # sep z-direction screw_z -= screw_d screw_ytop = 19.8 # mm screw_ytop -= screw_d screw_ybottom = 21.8 screw_ybottom -= screw_d screw_zoff = 1.3 + screw_d / 2 connector_z = 18 # mm connector_x = 16.2 # mm #### # box # camera is pushed in from bottom holder = cube([ size_x + 2 * THCKW + margin, size_y + 2 * THCKW + margin, size_z + THCKW + connector_z + margin ]) holder -= translate([THCKW, THCKW, THCKW])(cube([ size_x + margin, size_y + margin, size_z + THCKW + connector_z + margin ])) # 4 screw holes socket = cylinder(h=size_x + 2 * THCKW, r=screw_d / 2, segments=SGM) socket = rotate([0, 90, 0])(socket) sockets = socket + forward(screw_ybottom)(socket) temp = (screw_ytop - screw_ybottom) * 0.5 sockets += up(screw_z)(back(temp)(socket) + forward(screw_ytop - temp)(socket)) # substraction prep sockets holder -= translate([ 0, (size_y - screw_ybottom) * 0.5 + THCKW + 0.5 * margin, screw_zoff + THCKW + connector_z + 0.5 * margin ])(sockets) # space connector holder -= translate([THCKW + 0.5 * (size_x - connector_x), 0, THCKW])(cube( [connector_x, THCKW, size_z + THCKW + connector_z])) return holder
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 arduino(): usbhole = up(2.5)(cube([2.5, 7.5, 9], True)) board = up(3.75)(cube([2, x, 7.5], True)) smds = up(1.25)(cube([1.5, 5, 2.5], True)) dupont = up(2.5)(cube([2.5, 2.5, 5], True)) pinhole = cube([39, 1, 1], True) return (usbhole) \ + up(1)(left(3.75)(smds)) \ + up(1)(left(2)(board)) \ + left(4.25)(up(3.5)(forward((x/2)-1.25)(dupont))) \ + left(4.25)(up(3.5)(back((x/2)-1.25)(dupont))) \ + left(5)(up(2.25)(forward((x/2)-1.25)(pinhole))) \ + left(5)(up(2.25)(back((x/2)-1.25)(pinhole)))
def projection(): d = (height / 2.) - magic_1 panel = spu.forward(d)(plate.projection(size=(width, height), radius=10, center=True)) mounting_holes = place_at_centres([mounting_hole_centres, 0], drilled_hole.projection(8)) rear_light_holes = spu.forward(light_y_offset)([ place_at_centres([x, 0], lights.small.holes()) for x in light_centres ]) return panel - mounting_holes - rear_light_holes
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 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 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 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 makeChannels(railModel, chanNames): asm = None for cname in chanNames: crail = ChannelRail(railModel, channelSpecs[cname]) c = crail.makeRail() asm = (c + forward(railModel.CapWide + .1)(asm)) if asm else c return asm
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 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 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 switch_hole(): base_shape = [SWITCH_HOLE_WIDTH, SWITCH_HOLE_LENGTH, SWITCH_HOLE_HEIGHT * 2] base_elevation = SWITCH_HOLE_ELEVATION base = forward(SWITCH_HOLE_Y_OFFSET)(up(base_elevation)( grounded_cube(base_shape)) ) return base
def assembly(): small_lights = spu.forward(small_light_y_offset)( place_at_centres([small_light_centres, 0], lights.small.volume()) ) large_lights = spu.forward(large_light_y_offset)( place_at_centres([large_light_centres, 0], lights.large.assembly()) ) return sp.union()( sp.color('red')(bumper.volume()), spu.up(bumper.thickness)( sp.color('green')(small_lights), sp.color('blue')(large_lights), ), )
def key_shaft(): trunk_length = SHAFT_LENGTH - 0.5 * THICKNESS trunk = back(trunk_length / 2)(cube([THICKNESS, trunk_length, KEY_HEIGHT], center=True)) slot = back(SLOT_LENGTH / 2)(cube( [SLOT_WIDTH, SLOT_LENGTH, 2 * KEY_HEIGHT], center=True)) tip = cylinder(r=THICKNESS / 2, h=KEY_HEIGHT, center=True, segments=16) return forward(trunk_length)(trunk + tip - slot)
def topbox(down, logo): """topbox constructs the top part of the box :param down: if true downward ray box created :param logo: if true logo is generated, logo slows rendering """ top = cube([LENGTH_TOP, WIDTH_TOP, THICK_WALL]) # 4 screws used, 2 was insufficient screw_fixout = 3.5 # mm (radius) screw_fixin = 2 # TODO: connect to holesize threaded inserti screw_toph = 5 cyl = screw(screw_fixout, screw_toph, screw_fixin, HEIGHT_TOP) top += translate([SCREW_FIXOFFST, SCREW_FIXOFFST, 0])(cyl) top += translate([LENGTH_TOP - SCREW_FIXOFFST, SCREW_FIXOFFST, 0])(cyl) top += translate( [LENGTH_TOP - SCREW_FIXOFFST, WIDTH_TOP - SCREW_FIXOFFST, 0])(cyl) top += translate([SCREW_FIXOFFST, WIDTH_TOP - SCREW_FIXOFFST, 0])(cyl) # sliding should be prevented with 4 protrusion, # 1 is logo and 3 other are knobs x_knob = cube([THICK_WALL, THICK_WALL * 3, HEIGHT_TOP - THICK_WALL]) x_knobs = translate( [THICK_WALL, WIDTH_TOP / 2 - 1, THICK_WALL])(x_knob) + translate([ LENGTH_TOP - 2 * THICK_WALL, WIDTH_TOP / 2 - 1, THICK_WALL ])(x_knob) y_knob = cube([THICK_WALL * 3, THICK_WALL, HEIGHT_TOP - THICK_WALL]) y_knobs = translate([LENGTH_TOP * 0.25, 0, THICK_WALL ])(forward(THICK_WALL)(y_knob) + forward(WIDTH_TOP - 2 * THICK_WALL)(y_knob)) top += y_knobs + x_knobs # LOGO slows down render, should be turned off when developing if logo: top += translate([ 0.5 * (LENGTH_TOP - (120 + THICK_WALL * 2)), WIDTH_TOP - THICK_WALL - (13 + THICK_WALL * 2), 0 ])(createlogo()) if not down: laser_y = 24 + 2 * THICK_WALL top -= translate( [75 + 10 + 48 + THICK_WALL + 10, laser_y - 0.5 * 8, 0])(cube([20, 8, THICK_WALL])) # FIX FOR BOX orientation top = rotate([0, 0, 180])(mirror([0, 1, 0])(rotate([0, 180, 0])(top))) return top
def turnout_led_holes(cube_size): single_led_hole = led_hole(cube_size) leds = [ right(BUTTON_LED_X_OFFSETS[index])(forward( BUTTON_LED_Y_OFFSETS[index])(single_led_hole)) for index in range(len(BUTTON_LED_Y_OFFSETS)) ] return union()(leds)
def side_pegs(single_peg, shape, margin): peg_set = up(shape[2] / 2)(rotate([90, 0, 0])(grid_pegs( single_peg, centered_grid(width=shape[0], length=shape[2], margin=margin)))) half_length = shape[1] / 2 left_pegs = back(half_length)(peg_set) right_pegs = forward(half_length)(peg_set) return left_pegs + right_pegs
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 keystone_clasps(): clasp = up(KEYSTONE_THICKNESS + KEYSTONE_REACH + KEYSTONE_THICKNESS)( grounded_cube([ KEYSTONE_WIDTH + 2 * KEYSTONE_THICKNESS, KEYSTONE_CLASP_LENGTH + KEYSTONE_THICKNESS, KEYSTONE_CLASP_DEPTH ])) offset = (KEYSTONE_LENGTH - KEYSTONE_CLASP_LENGTH) / 2 return back(offset)(clasp) + forward(offset)(clasp)
def resistor_holes(cube_size): one_hole = cylinder(r=LED_LEAD_DIAMETER / 2, h=cube_size, center=True, segments=16) resistor_holes = [ right(x)(forward(y)(one_hole)) for (x, y) in RESISTOR_HOLE_OFFSETS ] return union()(resistor_holes)
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)
bolt_base2_y = square_width + outer_rad - (bolt_base_dia / 2.0) bolt_base_depth = depth * 0.66 # rotation of bolt base to merge into the side bolt_base_angle = math.degrees(math.atan2( bolt_base_depth, bolt_base_dia / 2.0)) hnt = nt / 2.0 # half nested tolerance # body centre body = s.cube(size=[depth, square_width, height]) # body round edge 1 body += u.up(outer_rad)(s.rotate(a=[0, 90, 0])( s.cylinder(r=outer_rad, h=depth, segments=segments) )) # body round edge 2 body += u.forward(square_width)(u.up(outer_rad)(s.rotate(a=[0, 90, 0])( s.cylinder(r=outer_rad, h=depth, segments=segments) ))) # 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) ) ))
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)
def slit(): return rotate(a=back_bend_degrees)( forward(y_offset)( union()(hull()( circle(r=radius) + forward(height)(circle(r=radius))))))