def assembly(): return sp.union()( sp.color('red')(spu.left(100.)(wheel.volume())), sp.color('green')(left_stub_axle.volume()), sp.color('blue')(spu.left(58.)(sp.rotate( (0., -90., 0.))(wheel_bushing.volume()))), )
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 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 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)
def final(): return down(1)(block()) \ - left(y / 2)( \ right(21)(down(5.5)(usbconn())) \ + right(4)(down(2)(button())) \ + right(14)(arduino()) \ )
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 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 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 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 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 assembly(): axle = sp.color('red')( round_bar.volume( diameter=axle_diameter, length=axle_length, center=True ) ) sprocket_assy = spu.up(sprocket_pos)( sp.color('green')(sp.rotate((180, 0, 0))(drive_sprocket.assembly())) ) brake_disc_assy = spu.down(brake_disc_pos)( sp.color('blue')(brake_disc.assembly()) ) wheels = [ sp.rotate([0, a, 0])( spu.left(wheel_centre_distance / 2.)( sp.color('cyan')(wheel.assembly()) ) ) for a in [0, 180] ] return sp.union()( sp.rotate([0, 90, 0])(sp.union()( axle, sprocket_assy, brake_disc_assy, )), 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 led_mount_holes(cube_size): one_hole = cylinder(r=LED_LEAD_DIAMETER / 2, h=cube_size, center=True, segments=16) hole_displacement = 0.05 * inches return left(hole_displacement)(one_hole) + right(hole_displacement)( one_hole)
def assembly(): x_bars = sp.rotate([0, 90, 0])( [ spu.back(d)( box_section.volume( length=outer * 2. + box_section.default_size[0], center=True ) ) for d in split_centers(seat_depth) ] ) y_bars = sp.rotate([90, 0, 0])( [ spu.left(d)( box_section.volume( length=seat_depth - box_section.default_size[0], center=True ) ) for d in [-outer, outer] ] ) _mount_bar_centres = (mount_bar_centres - box_section.default_size[0]) / 2. mount_bars = spu.up(box_section.default_size[0])( sp.rotate([90, 0, 0])( [ spu.left(d)( box_section.volume( length=seat_depth + box_section.default_size[0], center=True ) ) for d in [-_mount_bar_centres, _mount_bar_centres] ] ) ) frame = sp.union()( sp.color('red')(x_bars), sp.color('green')(y_bars), sp.color('blue')(mount_bars), ) return frame
def single_groove_cut(self, ratio): angle = -math.degrees(TAB_ANGLE) * ratio side = TAB_DIAMETER + 2 * self.inflation offset = TAB_DIAMETER - ratio * GROOVE_THICKNESS vertical_offset = TOP_PLATE_THICKNESS single = grounded_cube( [side, side, GROOVE_THICKNESS + 2 * self.inflation]) grooves = left(offset)(single) + right(offset)(single) + forward( offset)(single) + back(offset)(single) return up(vertical_offset)(rotate(angle, v=[0, 0, 1])(grooves))
def support(self): thickness = self.plank_size / 2 base_pad = down(thickness)( grounded_cube([self.seat_width, self.table_length, thickness]) ) center_bench_pad = up(self.seat_height - self.beam_size)( grounded_cube([thickness , self.table_length, self.beam_size]) ) center_offset = (self.bench_beam_width - self.beam_size)/2 bench_pad = up(self.seat_height - self.beam_size)( grounded_cube([thickness , self.table_length, self.beam_size]) ) return ( left(self.seat_offset_x)(base_pad) + right(self.seat_offset_x)(base_pad) + left(self.bench_beam_width/2)(center_bench_pad) + right(center_offset)(center_bench_pad) + bench_pad + up(self.beam_size) )
def connector(self, distance_from_surface): return optional(self.has_connector)( up(distance_from_surface - 1.25)( forward(self.plug_offset)( rotate((90, 0, 0))( hull()( left(4 - 1.25)(cylinder_outer(2.5 / 2, 6)), right(4 - 1.25)(cylinder_outer(2.5 / 2, 6)), ) ) ) + forward(self.plug_offset + self.plug_length)( rotate((90, 0, 0))( hull()( left(4 - 1.25)(cylinder_outer(8.5 / 2, self.plug_length)), right(4 - 1.25)(cylinder_outer(8.5 / 2, self.plug_length)), ) ) ) ) )
def board_cylinder(): group = cube() # FIXME: look into empties/children for x in [-m.rpi_hole_x_dist / 2, m.rpi_hole_x_dist / 2]: for y in [-m.rpi_hole_y_dist / 2, m.rpi_hole_y_dist / 2]: c = cylinder(r=m.rpi_cylinder / 2, h=5) c2 = up(m.rpi_board_height)( cylinder(r=m.rpi_hole / 2 - m.diameter_margin, h=m.rpi_board_height) ) c = c + c2 group += forward(y)(left(x)(c)) return group
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 mounting_posts(self, distance_from_surface): positioning_post_height = distance_from_surface + self.board_thickness + 3 positioning_post = forward(1)( up(positioning_post_height / 2)( cube((4, 4, positioning_post_height), center=True) ) ) return ( back(self.board_length + m2_shaft_radius + FUDGE)( mount_post_m2(distance_from_surface) ) + left(7)(positioning_post) + right(7)(positioning_post) )
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))
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 key_grid_tester_walls( length_units, width_units, wall_height, margin_length, margin_width ): wall_length, wall_width = key_grid_tester_wall_dimensions( length_units, width_units, wall_height, margin_length, margin_width ) top_wall = forward((wall_length - wall_thickness) / 2)( cube((wall_width, wall_thickness, wall_height), center=True) ) left_wall = left((wall_width - wall_thickness) / 2)( cube((wall_thickness, wall_length, wall_height), center=True) ) return up(wall_height / 2)( top_wall + left_wall + rotate(180)(top_wall) + rotate(180)(left_wall) )
def panel_set(): front = back(NARROW_WIDTH)(rotate(180, [0, 0, 1])(rotate(90, [1, 0, 0])( forward(PANEL_HEIGHT / 2 + PANEL_THICKNESS)(front_panel())))) back_piece = forward(NARROW_WIDTH)(rotate(0, [0, 0, 1])(rotate( 90, [1, 0, 0])(forward(PANEL_HEIGHT / 2 + PANEL_THICKNESS)(back_panel())))) side = up(1.5 * PANEL_THICKNESS)(left(WIDE_WIDTH / 2)(rotate( 90, [0, 0, 1])(rotate(90, [1, 0, 0])(forward(PANEL_HEIGHT / 2)( side_panel()))))) mount = down(PANEL_THICKNESS)(right(1.5 * inches + PANEL_THICKNESS)(rotate( [90, 0, -90])(mount_panel()))) # return mount return front + \ back_piece + \ mount + \ forward((NARROW_WIDTH - PANEL_THICKNESS) / 2)(side) + \ back((NARROW_WIDTH - PANEL_THICKNESS) / 2)(side)
def makeCrossbar(railModel, chanNames, barThik, barWidth, nBars): eps = railModel.eps capW = railModel.CapWide holeD = railModel.PillarID specs = [channelSpecs[cname] for cname in chanNames] skips = [spec.ChanWide - spec.ChanHang1 - spec.ChanHang2 for spec in specs] barLen = sum([capW + skip for skip in skips]) bar = cube([barWidth, barLen, barThik]) holeAt = capW / 2 for skip in skips: bar += hole()(translate([barWidth / 2, holeAt, -eps])(cylinder(d=holeD, h=barThik + 2 * eps))) holeAt += capW + skip asm = None for line in range(nBars): asm = left(barWidth + .1)(bar + asm if asm else bar) return asm
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 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
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
def mount(): padding_bars = sp.color('green')( sp.translate((0, 0, -d))( sp.rotate((0, 90, 0))( box_section.volume(length=mount_overlap, center=False) ) ) ) yoke_bars = sp.color('blue')( [ sp.translate((-mount_overhang, 0, z))( sp.rotate((0, 90, 0))( box_section.volume( length=mount_overhang + mount_overlap, center=False ) ) ) for z in [d, -d * 2.] ] ) mount_bar = sp.color('cyan')( sp.rotate((0, 90, 0))(box_section.volume(length=magic_1, center=False)) ) return spu.left(bar_length / 2.)( sp.rotate((0, camber, 0))( sp.translate((-magic_1, 0, 0.5 * d))( sp.union()( padding_bars, yoke_bars, mount_bar, ) ) ) )
def door(self): forward_offset = self.door_thickness / 2 - 0.5 * nscale_inches # slight merge into frame main_panel = grounded_cube( [self.door_width, self.door_thickness, self.door_height]) horizontal_beam = grounded_cube( [self.door_width, self.door_beam_thickness, self.door_beam_width]) vertical_beam = grounded_cube( [self.door_beam_width, self.door_beam_thickness, self.door_height]) horizontal_offset = (self.door_width - self.door_beam_thickness) / 2 vertical_offset = self.door_height - self.door_beam_thickness / 2 diagonal_offset = (self.door_width - self.door_beam_width) / 2 diagonal_skew = 2 * diagonal_offset / self.door_height diagonal_beam = multmatrix([ [1, 0, diagonal_skew, -diagonal_offset], [0, 1, 0, 0], [0, 0, 1, 0], ])(vertical_beam) beams = horizontal_beam + up(vertical_offset)(horizontal_beam) beams += left(horizontal_offset)(vertical_beam) beams += right(horizontal_offset)(vertical_beam) beams += diagonal_beam return up(self.door_opening_threshold - 0.5 * self.door_oversize)( forward(forward_offset)(main_panel + forward( (self.door_beam_thickness - self.door_thickness) / 2)(beams)))
def screw_holes(self): return [ left(screw_hole_shift)(circle(screw_hole_radius)), right(screw_hole_shift + phone_width)(circle(screw_hole_radius)) ]