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 model_right(): shape = sl.union()( key_holes(), connectors(), thumb(), thumb_connectors(), ) s2 = sl.union()( case_walls(), screw_insert_outers(), teensy_holder(), usb_holder(), ) s2 = sl.difference()(s2, rj9_space(), usb_holder_hole(), screw_insert_holes()) shape = sl.union()( shape, s2, rj9_holder(), wire_posts(), ) shape -= sl.translate([0, 0, -20])(sl.cube([350, 350, 40], center=True)) return shape
def get_shape(self, with_verts=False): if with_verts: shape = sl.union()(self.shape, self.vertices_shape(), self.unrotated_verts_shape(), self.origin_marker(), self.unrotated_origin_marker()) if self.cap is not None: return sl.union()(shape, self.cap) return shape return self.shape
def plane_make_part3D(self, thepart, pconfig): self.generate_part3D(thepart, pconfig) # for cutout in thepart.cutouts3D: # for c in cutout: # thepart.border3D = thepart.border3D - c subparts = [] for sp in thepart.parts: if hasattr(sp, 'subpart') and sp.subpart: self.make_part3D(sp, pconfig) if hasattr(sp, 'border3D'): subparts.append(sp.border3D) if len(subparts): if hasattr(thepart, 'border3D'): thepart.border3D=solid.union()(thepart.border3D,*subparts) else: thepart.border3D=solid.union()(*subparts) if not hasattr(thepart, 'border3D'): return False cutouts = [thepart.border3D] for cutout in thepart.cutouts3D: for c in cutout: cutouts.append(c) thepart.border3D = solid.difference()(*cutouts) # 3D transformations can only be applied to parts, so we can just go up the tree p = thepart c=0 print p while(p and type(p) is not Plane):# and (c==0 or not p.renderable() )): p.rotations_to_3D() if hasattr(p, 'transform') and p.transform is not None and p.transform is not False: print p.transform if 'matrix3D' in p.transform: if type(p.transform['matrix3D'][0]) is list or type(p.transform['matrix3D'][0]) is Vec: thepart.border3D=solid.translate([-p.transform['matrix3D'][0][0], -p.transform['matrix3D'][0][1],-p.transform['matrix3D'][0][2]])(thepart.border3D) thepart.border3D=solid.multmatrix(m=p.transform['matrix3D'][1])(thepart.border3D) thepart.border3D=solid.translate([p.transform['matrix3D'][0][0], p.transform['matrix3D'][0][1],p.transform['matrix3D'][0][2]])(thepart.border3D) else: thepart.border3D=solid.multmatrix(m=p.transform['matrix3D'])(thepart.border3D) if 'rotate3D' in p.transform: if type(p.transform['rotate3D'][0]) is list or type(p.transform['rotate3D'][0]) is Vec: thepart.border3D=solid.translate([-p.transform['rotate3D'][0][0], -p.transform['rotate3D'][0][1],-p.transform['rotate3D'][0][2]])(thepart.border3D) thepart.border3D=solid.rotate([p.transform['rotate3D'][1][0], p.transform['rotate3D'][1][1],p.transform['rotate3D'][1][2] ])(thepart.border3D) thepart.border3D=solid.translate([p.transform['rotate3D'][0][0], p.transform['rotate3D'][0][1],p.transform['rotate3D'][0][2]])(thepart.border3D) else: thepart.border3D=solid.rotate([p.transform['rotate3D'][0], p.transform['rotate3D'][1],p.transform['rotate3D'][2] ])(thepart.border3D) if 'translate3D' in p.transform: thepart.border3D=solid.translate([p.transform['translate3D'][0], p.transform['translate3D'][1],p.transform['translate3D'][2] ])(thepart.border3D) c+=1 p=p.parent
def plane_make_part3D(self, thepart, pconfig): self.generate_part3D(thepart, pconfig) # for cutout in thepart.cutouts3D: # for c in cutout: # thepart.border3D = thepart.border3D - c subparts = [] for sp in thepart.parts: if hasattr(sp, 'subpart') and sp.subpart: self.make_part3D(sp, pconfig) if hasattr(sp, 'border3D'): subparts.append(sp.border3D) if len(subparts): if hasattr(thepart, 'border3D'): thepart.border3D=solid.union()(thepart.border3D,*subparts) else: thepart.border3D=solid.union()(*subparts) if not hasattr(thepart, 'border3D'): return False cutouts = [thepart.border3D] for cutout in thepart.cutouts3D: for c in cutout: cutouts.append(c) thepart.border3D = solid.difference()(*cutouts) # 3D transformations can only be applied to parts, so we can just go up the tree p = thepart c=0 while(p and type(p) is not Plane):# and (c==0 or not p.renderable() )): p.rotations_to_3D() if hasattr(p, 'transform') and p.transform is not None and p.transform is not False: if 'matrix3D' in p.transform: if type(p.transform['matrix3D'][0]) is list or type(p.transform['matrix3D'][0]) is Vec: thepart.border3D=solid.translate([-p.transform['matrix3D'][0][0], -p.transform['matrix3D'][0][1],-p.transform['matrix3D'][0][2]])(thepart.border3D) thepart.border3D=solid.multmatrix(m=p.transform['matrix3D'][1])(thepart.border3D) thepart.border3D=solid.translate([p.transform['matrix3D'][0][0], p.transform['matrix3D'][0][1],p.transform['matrix3D'][0][2]])(thepart.border3D) else: thepart.border3D=solid.multmatrix(m=p.transform['matrix3D'])(thepart.border3D) if 'rotate3D' in p.transform: if type(p.transform['rotate3D'][0]) is list or type(p.transform['rotate3D'][0]) is Vec: thepart.border3D=solid.translate([-p.transform['rotate3D'][0][0], -p.transform['rotate3D'][0][1],-p.transform['rotate3D'][0][2]])(thepart.border3D) thepart.border3D=solid.rotate([p.transform['rotate3D'][1][0], p.transform['rotate3D'][1][1],p.transform['rotate3D'][1][2] ])(thepart.border3D) thepart.border3D=solid.translate([p.transform['rotate3D'][0][0], p.transform['rotate3D'][0][1],p.transform['rotate3D'][0][2]])(thepart.border3D) else: thepart.border3D=solid.rotate([p.transform['rotate3D'][0], p.transform['rotate3D'][1],p.transform['rotate3D'][2] ])(thepart.border3D) if 'translate3D' in p.transform: thepart.border3D=solid.translate([p.transform['translate3D'][0], p.transform['translate3D'][1],p.transform['translate3D'][2] ])(thepart.border3D) c+=1 p=p.parent
def create_model(data, rows, columns): hexes = to_base(int.from_bytes(data, 'big'), 720) assert len(hexes) == rows * columns sts = [] for row in range(rows): for col in range(columns): order = permute.permute([1, 2, 3, 4, 5, 6], hexes[row * 9 + col]) heights = [1 + 1.5 * i / len(order) for i in order] st = stump(heights) xdiff = 1.5 * col xdiff *= 1.2 ydiff = (-3**0.5) * row - (3**0.5 / 2) * col ydiff *= 1.2 st = solid.translate([xdiff, ydiff, 0])(st) sts.append(st) base = solid.translate([-3.4, -3.2, 0])(solid.rotate([0, 0, -30])( solid.scale([22, 6.5, 0.3])(solid.cube(1)))) x, y = 0.5, (3**0.5 / 2) / 2 marker = solid.translate([-1.5, -2.5, 0])( solid.polyhedron( points=[ # bottom (-x, -y, 0), (x, -y, 0), (0, y, 0), # top (-x, -y, 1), (x, -y, 1), (0, y, 1) ], faces=[ # bottom (0, 1, 2), # top (5, 4, 3), # sides (0, 3, 4, 1), (1, 4, 5, 2), (2, 5, 3, 0) ])) return solid.union()([base, solid.union()(sts), marker])
def create_cutouts(solder_paste, increase_hole_size_by=0.0): solder_paste.to_metric() cutout_shapes = [] cutout_lines = [] apertures = {} current_aperture = None current_x = None current_y = None for statement in solder_paste.statements: if statement.type == 'PARAM' and statement.param == 'AD': # define aperture apertures[statement.d] = { 'shape': statement.shape, 'modifiers': statement.modifiers } elif statement.type == 'APERTURE': current_aperture = statement.d elif statement.type == 'COORD' and statement.op == 'D3': # flash object coordinates if not current_aperture: raise Exception("No aperture set on flash object coordinates!") aperture = apertures[current_aperture] current_x = statement.x if statement.x is not None else current_x current_y = statement.y if statement.y is not None else current_y if aperture['shape'] == 'C': # circle cutout_shapes.append( primitive_to_shape( primitives.Circle(diameter=aperture['modifiers'][0][0], position=[current_x, current_y]))) elif aperture['shape'] == 'R': # rectangle width, height = aperture['modifiers'][0] cutout_shapes.append( primitive_to_shape( primitives.Rectangle( position=[current_x, current_y], width=width, height=height, ))) else: raise NotImplementedError( "Only circular and rectangular flash objects are supported!" ) for p in solder_paste.primitives: shape = primitive_to_shape(p) if len(shape) > 2: cutout_shapes.append(shape) else: cutout_lines.append(shape) # If the cutouts contain lines we try to first join them together into shapes cutout_shapes += lines_to_shapes(cutout_lines) polygons = [] for shape in cutout_shapes: if increase_hole_size_by and len(shape) > 2: shape = offset_shape(shape, increase_hole_size_by) polygons.append(polygon([[x, y] for x, y in shape])) return union()(*polygons)
def connectors(): hulls = [] for column in range(ncols - 1): for row in range(lastrow): # need to consider last_row? # for row in range(nrows): # need to consider last_row? places = [] places.append(key_place(web_post_tl(), column + 1, row)) places.append(key_place(web_post_tr(), column, row)) places.append(key_place(web_post_bl(), column + 1, row)) places.append(key_place(web_post_br(), column, row)) hulls.append(triangle_hulls(places)) for column in range(ncols): # for row in range(nrows-1): for row in range(cornerrow): places = [] places.append(key_place(web_post_bl(), column, row)) places.append(key_place(web_post_br(), column, row)) places.append(key_place(web_post_tl(), column, row + 1)) places.append(key_place(web_post_tr(), column, row + 1)) hulls.append(triangle_hulls(places)) for column in range(ncols - 1): # for row in range(nrows-1): # need to consider last_row? for row in range(cornerrow): # need to consider last_row? places = [] places.append(key_place(web_post_br(), column, row)) places.append(key_place(web_post_tr(), column, row + 1)) places.append(key_place(web_post_bl(), column + 1, row)) places.append(key_place(web_post_tl(), column + 1, row + 1)) hulls.append(triangle_hulls(places)) return sl.union()(*hulls)
def thumb_1x_layout(shape): return sl.union()( thumb_mr_place(shape), thumb_ml_place(shape), thumb_br_place(shape), thumb_bl_place(shape), )
def teensy_holder(): s1 = sl.cube([3, teensy_holder_length, 6 + teensy_width], center=True) s1 = sl.translate([1.5, teensy_holder_offset, 0])(s1) s2 = sl.cube([teensy_pcb_thickness, teensy_holder_length, 3], center=True) s2 = sl.translate([ (teensy_pcb_thickness / 2) + 3, teensy_holder_offset, -1.5 - (teensy_width / 2), ])(s2) s3 = sl.cube([teensy_pcb_thickness, teensy_holder_top_length, 3], center=True) s3 = sl.translate([ (teensy_pcb_thickness / 2) + 3, teensy_holder_top_offset, 1.5 + (teensy_width / 2), ])(s3) s4 = sl.cube([4, teensy_holder_top_length, 4], center=True) s4 = sl.translate([ teensy_pcb_thickness + 5, teensy_holder_top_offset, 1 + (teensy_width / 2) ])(s4) shape = sl.union()(s1, s2, s3, s4) shape = sl.translate([-teensy_holder_width, 0, 0])(shape) shape = sl.translate([-1.4, 0, 0])(shape) shape = sl.translate( [teensy_top_xy[0], teensy_top_xy[1] - 1, (6 + teensy_width) / 2])(shape) return shape
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 flat_cap(x, y, z, r, recess=0): """flat_cap x, y, z cap dimensions r (int): radius for rounded edges recess: decimal, percent of cap to remove """ cap = rounded_cube(x, y, z, r) if recess > 0: if recess < 1: insert = rounded_cube(x * recess, y * recess, (z * recess) - 0.5, r, center=True) cap = s.difference()(cap, s.translate([0, 0, z - (z * recess) + 0.5])(insert)) else: raise ValueError(f"recess should be a decimal between 0 and 1") out = s.union()(cap, mx_post(6, z / 2)) return out
def tetrahedron(): """ Creates a ball-and-stick model of a geodesic sphere based off of an tetrahedron, highlighting vertices of valence 3 """ (vs, es, fs) = geo.sphere(v=3, base=geo.tetrahedron_vertices) vms = geo.vertex_matrices(vs) ems = geo.edge_matrices(es, vs) els = geo.edge_lengths(es, vs) ves = geo.vertex_edges(es) highlight_valence = 3 def shape_at_vertex(m, ve): shape = solid.sphere(r=0.05) if len(ve) == highlight_valence: shape = solid.color("red")(shape) return solid.multmatrix(m)(shape) def shape_at_edge(m, el, e): shape = solid.cylinder(r1=0.03, r2=0.03, h=el, center=True) if any(len(ves[i]) == highlight_valence for i in e): shape = solid.color("red")(shape) return solid.multmatrix(m)(solid.utils.rot_z_to_right(shape)) shape = solid.union()( *[shape_at_vertex(m, ve) for m, ve in zip(vms, ves)], *[shape_at_edge(m, el, e) for m, el, e in zip(ems, els, es)]) return shape
def spaceship_earth(): """ Creates a model of EPCOT's spaceship earth """ (vs, es, fs) = geo.sphere(v=8) fms = geo.face_matrices(fs, vs) fts = geo.face_triangles_2d(fs, vs, fms) def shape_at_face(m, ft): center = np.array([0, 0]) panel1 = np.vstack((ft[0], ft[1], center)) panel2 = np.vstack((ft[1], ft[2], center)) panel3 = np.vstack((ft[2], ft[0], center)) panel_angle = 20 def panel_shape(panel_tri): edge_midpoint = 0.5 * (panel_tri[0] + panel_tri[1]) rotation_vector = panel_tri[1] - panel_tri[0] transform = lambda x: solid.translate( edge_midpoint)(solid.rotate(a=panel_angle, v=rotation_vector) (solid.translate(-edge_midpoint)(x))) return transform( solid.linear_extrude(0.01)(solid.polygon(panel_tri * 0.9))) return solid.multmatrix(m)( solid.union()(*[panel_shape(p) for p in (panel1, panel2, panel3)])) inner_radius = np.mean(np.linalg.norm(np.array(fms)[:, 0:3, 3], axis=1)) return solid.union()(solid.sphere(r=inner_radius, segments=FN * 4), *[shape_at_face(m, ft) for m, ft in zip(fms, fts)])
def assembly(): column = tube.volume(diameter=column_diameter, wall_thickness=2., length=column_length) return sp.union()( spu.up(column_length)( spu.up(wheel.plate_thickness / 2.)( sp.color('red')(wheel.volume()), spu.up(wheel.plate_thickness / 2.)( sp.color('green')(instrument_panel.assembly()) ), sp.translate((150, 80))( sp.rotate((0., 60., 0.))( sp.color('blue')(throttle.assembly()) ) ), ), sp.rotate((0, 180, 0))(sp.color('cyan')(wheel_mount.volume())), ), sp.color('magenta')(column), spu.up(440.)(sp.color('purple')(column_mount.upper.assembly())), spu.up(60.)(sp.color('grey')(column_mount.lower.assembly())), sp.rotate((0, 0, 0))( sp.color('orange')(arm_mount.volume()), sp.color('pink')(spu.down(arm.thickness)(arm.volume())), ), )
def volume(): base = spu.up(base_height / 2.)( sp.cube([width, base_length, base_height], center=True) ) mounting_holes = spu.down(1)( place_at_centres( [0, mounting_hole_centres], sp.cylinder(d=mounting_hole_diameter, h=base_height + 2) ) ) base -= mounting_holes bearing = spu.up(shaft_height)( sp.rotate([0, 90, 0])( sp.cylinder(d=60, h=width, center=True) - sp.cylinder(d=shaft_diameter, h=width + 1, center=True) ) ) return sp.union()( base, bearing, )
def single_plate(cylinder_segments=100): top_wall = sl.cube([keyswitch_width + 3, 1.5, plate_thickness], center=True) top_wall = sl.translate( (0, (1.5 / 2) + (keyswitch_height / 2), plate_thickness / 2))(top_wall) left_wall = sl.cube([1.5, keyswitch_height + 3, plate_thickness], center=True) left_wall = sl.translate( ((1.5 / 2) + (keyswitch_width / 2), 0, plate_thickness / 2))(left_wall) side_nub = sl.cylinder(1, 2.75, segments=cylinder_segments, center=True) side_nub = sl.rotate(rad2deg(pi / 2), [1, 0, 0])(side_nub) side_nub = sl.translate((keyswitch_width / 2, 0, 1))(side_nub) nub_cube = sl.cube([1.5, 2.75, plate_thickness], center=True) nub_cube = sl.translate( ((1.5 / 2) + (keyswitch_width / 2), 0, plate_thickness / 2))(nub_cube) side_nub = sl.hull()(side_nub, nub_cube) plate_half1 = top_wall + left_wall + side_nub plate_half2 = plate_half1 plate_half2 = sl.mirror([0, 1, 0])(plate_half2) plate_half2 = sl.mirror([1, 0, 0])(plate_half2) plate = plate_half1 + plate_half2 if plate_file is not None: socket = sl.import_(plate_file) socket = sl.translate([0, 0, plate_offset])(socket) plate = sl.union()(plate, socket) return plate
def platform(width, length, height): foot = end(width) head = translate((0, length, 0))(mirror((0, 1, 0))(foot)) slats = union()( [translate((0, y, 0))(slat(width)) for y in range(0, 70, 7)]) return (platform_color(head) + platform_color(foot) + platform_color(translate((0, 6.5, 0))(slats)))
def single_slice(index): for slice_num, (lower, upper) in enumerate(slice_parameters()): if slice_num == index: return solid.translate([0, 0, upper - lower])( solid.rotate([0, 180, 0])( solid.union()(*produce_slice(lower, upper)) )) raise Exception("Non-existent slice %i, max: %i!" % (index, slice_num))
def full_cone(): cylinders = [] for slice_num, (lower, upper) in enumerate(slice_parameters()): cylinders.extend(produce_slice(lower, upper, mdf_strength * slice_num)) return solid.translate([0, 0, cone_length])( solid.rotate([0, 180, 0])( solid.union()(*cylinders) ) )
def slice_sim(slices, t_m=3.0): """ Returns simulation of assembled slice-formed solid. Args: slices ([PolyLine]): list of PolyLines to simulate. t_m (float): material thickness Returns: A PolyMesh representing the assembled slices. """ # assume stacked in the z dimension axis = np.array([0, 0, 1]) slice_solids = [] for (i, slice) in enumerate(slices): translation = list(t_m * axis * i) slice_solid = sl.linear_extrude(t_m)(slice.get_generator()) positioned_solid = sl.translate(translation)(slice_solid) slice_solids.append(positioned_solid) return PolyMesh(generator=sl.union()(slice_solids))
def create_cutouts(solder_paste, increase_hole_size_by=0.0): solder_paste.to_metric() cutout_shapes = [] cutout_lines = [] for p in solder_paste.primitives: shape = primitive_to_shape(p) if len(shape) > 2: cutout_shapes.append(shape) else: cutout_lines.append(shape) # If the cutouts contain lines we try to first join them together into shapes cutout_shapes += lines_to_shapes(cutout_lines) polygons = [] for shape in cutout_shapes: if increase_hole_size_by and len(shape) > 2: shape = offset_shape(shape, increase_hole_size_by) polygons.append(polygon([[x, y] for x, y in shape])) return union()(*polygons)
def __init__(self, **kwargs): if 'name' not in kwargs.keys(): kwargs['name'] = 'klann' if 'elts' not in kwargs.keys(): #create O, A,B, C, D, E, F,M, b1,b2,b3,b4,conn = create_klann_geometry() pos_A, neg_A = joint_from_point(A,"A",1) pos_B, neg_B = joint_from_point(B,"B",1) pos_C, neg_C = joint_from_point(C,"C",1) pos_D, neg_D = joint_from_point(D,"D",1) pos_E, neg_E = joint_from_point(E,"E",1) pos_F, neg_F = joint_from_point(F,"F",1) pos_M, neg_M = joint_from_point(M,"M",1) pos_O, neg_O = joint_from_point(O,"O",1) b1_body = rationalize_segment(b1,[neg_M, neg_C, neg_D],"b1") b2_body = rationalize_segment(b2,[neg_B, neg_E],"b2") b3_body = rationalize_segment(b3, [neg_A,pos_C],"b3") b4_body = rationalize_segment(b4, [pos_E,pos_D], "b4") conn = rationalize_segment(conn, [neg_O, pos_M], "conn" ) # #create servo mount that connects to shaft connector b, j, c = create_klann_part(1,1, "1") A,_,B = j mt, m_attach, _ = create_servo_mount() # #add support for A,B mount_thickness= 3 # shaft coupler layer_thickness = 3 #O, A,B, C, D, E, F,M, b1,b2,b3,b4,conn = create_klann_geometry() ##create the attacher thing, with joints A_bar, a_attach = create_support_bar(A,mount_thickness) B_bar, b_attach = create_support_bar(B,mount_thickness + layer_thickness) m_attach_gen = m_attach.get_generator() a_gen = a_attach.get_generator() b_gen = b_attach.get_generator() a_join = solid.hull()(m_attach_gen, a_gen) b_join = solid.hull()(m_attach_gen, b_gen) cronenberg = PolyMesh(generator= solid.union()(a_join,b_join)) aparatus = cronenberg + A_bar + B_bar + mt shaft_conn = create_shaft_connector() OT = (0, 0, 0) OQ = (0, 0, 1, 0) OP = (OT, OQ) bt_pos, bt_neg = joint_from_point(B,"B",2) torso = Body( pose = OP, joints=[ pos_A, pos_O, bt_pos ], elts=[Layer( aparatus, name='lol', color='yellow', )], name='torso' ) coupler = Body( pose = OP, joints = [pos_O], elts = [Layer(shaft_conn, name='lol', color = 'blue')], name = 'coupler' ) kwargs['elts'] = [coupler, b1_body, b2_body, b3_body, b4_body, conn,torso]#[torso] #kwargs['children'] = [torso] if 'connections' not in kwargs.keys(): kwargs['connections'] = [ ((0, 'torso', 'A'),(0, 'b3', 'A')), ((0, 'torso', 'B'),(0, 'b2', 'B')), ((0,'torso', 'O'),(0, 'conn', 'O')), ((0, 'conn','M'),(0,'b1', 'M')), ((0,'b1','C'),(0,'b3','C')), ((0,'b1','D'), (0,'b4','D')), ((0,'b2','E'),(0,'b4','E')), ((0,'conn', 'O'), (0,'coupler', 'O')) ] super(KlannLinkage, self).__init__(**kwargs)
def __init__(self, **kwargs): if 'name' not in kwargs.keys(): kwargs['name'] = 'klann' if 'elts' not in kwargs.keys(): #create b1, j1, c1 = create_klann_part(1,1, "1",True) b2, j2, c2 = create_klann_part(1, 1+ np.pi/2, "2", True) # print(conn.joints) A1,_,B1 = j1 A2,_,B2 = j2 # A1 = voffset_joint(A1,-3, "1A") # B1 = voffset_joint(B1,0,"1B") link_bodies = b1+b2 link_conns = c1+c2 # # #create servo mount that connects to shaft connector mt, m_attach1, m_attach2 = create_servo_mount() # # #add support for A,B mount_thickness= 6 # shaft coupler layer_thickness = 15 # # ##create the attacher thing, with joints #first layer of standoffs st_body1,anch1 = standoff(mount_thickness) #contains joint "anchor" st_body2,anch2 = standoff(mount_thickness) st_body3,_ = standoff(layer_thickness) #contains joint "anchor" st_body4,_ = standoff(layer_thickness) st_conn1 = ((0,"1b3","1A"),(0,st_body1.name, "A")) st_conn2 = ((0,"1b2","1B"),(0,st_body2.name, "A")) #second layer: st_conn3 = ((0,"2b3", "2A"),(0,st_body3.name, "A")) st_conn4 = ((0,"2b2", "2B"),(0,st_body4.name, "A")) #A1_bar, a1_attach = create_support_bar(A1,mount_thickness) #B1_bar, b1_attach = create_support_bar(B1,mount_thickness + layer_thickness) # m_attach1_gen = m_attach1.get_generator() # b1_gen = b1_attach.get_generator() # ((dxa,dya,_),_) = A1.pose ((dxb,dyb,_),_) = B1.pose placed_anch1 = solid.translate([dxa,dya,0])(anch1) placed_anch2 = solid.translate([dxb,dyb,0])(anch2) a1_join = solid.hull()(m_attach1_gen, placed_anch1) b1_join = solid.hull()(m_attach1_gen, placed_anch2) # cronenberg1 = PolyMesh(generator= solid.union()(a1_join,b1_join)) aparatus = cronenberg1 +mt shaft_conn = create_shaft_connector() OT = (0, 0, 0) OQ = (0, 0, 1, 0) OP = (OT, OQ) pos_O, neg_O = joint_from_point(Point(0,0), "1O", 1) O_3, _ = joint_from_point(Point(0,0),"3O",5) torso = Body( pose = OP, joints = [pos_O, A1, B1], elts=[Layer( aparatus, name='lol', color='yellow', )], name='torso' ) coupler = Body( pose = OP, joints = [pos_O,O_3], elts = [Layer(shaft_conn, name='lol', color = 'blue')], name = 'coupler' ) kwargs['elts'] = link_bodies+ [coupler]#, st_body1, st_body2, st_body3, st_body4]#,torso]#[torso] [conn,torso]+ , [coupler]+ conn coupler, #kwargs['children'] = [torso] if 'connections' not in kwargs.keys(): kwargs['connections'] = [ ((0, '1conn', '1O'),(0,'coupler','1O')), ((0, 'coupler', '3O'),(0, '2conn','2O')) #st_conn1, #st_conn2, #st_conn3, #st_conn4 #((0, 'torso', '2O'),(0, 'conn','2O')), # ((0, 'torso', '1A'),(0, '1b3', '1A')), # ((0, 'torso', '1B'),(0, '1b2', '1B')), #((0, 'torso', '2A'),(0, '2b3', '2A')), #((0, 'torso', '2B'),(0, '2b2', '2B')) ] + link_conns super(DoubleDeckerKlannLinkage, self).__init__(**kwargs)
def __init__(self, **kwargs): if 'name' not in kwargs.keys(): kwargs['name'] = 'klann' if 'elts' not in kwargs.keys(): #create b1, j1, c1 = create_klann_part(1,1, "1") b2, j2, c2 = create_klann_part(-1, 1, "2") # + np.pi conn1 = b1.pop() conn2 = b2.pop() conn = combine_connectors(conn1,conn2) # print(conn.joints) A1,_,B1 = j1 A1 = voffset_joint(A1,-3, "1A") B1 = voffset_joint(B1,0,"1B") A2,_,B2 = j2 A2 = voffset_joint(A2, -9, "2A") B2 = voffset_joint(B2, -6, "2B") link_bodies = b1+b2 +[conn] link_conns = c1+c2 # #create servo mount that connects to shaft connector mt, m_attach1, m_attach2 = create_servo_mount() # #add support for A,B mount_thickness= 3 # shaft coupler layer_thickness = 3 ##create the attacher thing, with joints A1_bar, a1_attach = create_support_bar(A1,mount_thickness) B1_bar, b1_attach = create_support_bar(B1,mount_thickness) m_attach1_gen = m_attach1.get_generator() a1_gen = a1_attach.get_generator() b1_gen = b1_attach.get_generator() a1_join = solid.hull()(m_attach1_gen, a1_gen) b1_join = solid.hull()(m_attach1_gen, b1_gen) cronenberg1 = PolyMesh(generator= solid.union()(a1_join,b1_join)) # A2_bar, a2_attach = create_support_bar(A2,mount_thickness) # B2_bar, b2_attach = create_support_bar(B2,mount_thickness) # # m_attach2_gen = m_attach2.get_generator() # a2_gen = a2_attach.get_generator() # b2_gen = b2_attach.get_generator() # # a2_join = solid.hull()(m_attach2_gen, a2_gen) # b2_join = solid.hull()(m_attach2_gen, b2_gen) # cronenberg2 = PolyMesh(generator= solid.union()(a2_join,b2_join)) aparatus = cronenberg1 + A1_bar + B1_bar + mt #+ cronenberg2 + A2_bar + B2_bar shaft_conn = create_shaft_connector() OT = (0, 0, 0) OQ = (0, 0, 1, 0) OP = (OT, OQ) pos_O, neg_O = joint_from_point(Point(0,0), "1O", 1) torso = Body( pose = OP, joints = [pos_O, A2, B2, A1, B1], elts=[Layer( aparatus, name='lol', color='yellow', )], name='torso' ) coupler = Body( pose = OP, joints = [pos_O], elts = [Layer(shaft_conn, name='lol', color = 'blue')], name = 'coupler' ) kwargs['elts'] = [torso]+ link_bodies#[torso] , conn coupler, #kwargs['children'] = [torso] if 'connections' not in kwargs.keys(): kwargs['connections'] = [ #((0, 'conn', '1O'),(0,'coupler','1O')), #((0, 'torso', '1O'),(0, 'conn','1O')), #((0, 'torso', '2O'),(0, 'conn','2O')), ((0, 'torso', '1A'),(0, '1b3', '1A')), ((0, 'torso', '1B'),(0, '1b2', '1B')), ((0, 'torso', '2A'),(0, '2b3', '2A')), ((0, 'torso', '2B'),(0, '2b2', '2B')) ] + link_conns super(DoubleKlannLinkage, self).__init__(**kwargs)
def __init__(self, **kwargs): if 'name' not in kwargs.keys(): kwargs['name'] = 'klann' if 'elts' not in kwargs.keys(): #create ################################################## ################################################## b1, j1, c1 = create_klann_part(1,1, "1") b2, j2, c2 = create_klann_part(-1, 1+ np.pi, "2") conn1 = b1.pop() conn2 = b2.pop() conn = combine_connectors(conn1,conn2) # print(conn.joints) A1,_,B1 = j1 A1 = voffset_joint(A1,-3, "1A") B1 = voffset_joint(B1,0,"1B") A2,_,B2 = j2 A2 = voffset_joint(A2, -9, "2A") B2 = voffset_joint(B2, -6, "2B") link_bodies = b1+b2 +[conn] link_conns = c1+c2 # #create servo mount that connects to shaft connector mt, m_attach1, m_attach2 = create_servo_mount() # #add support for A,B mount_thickness= 3 # shaft coupler layer_thickness = 3 ##create the attacher thing, with joints A1_bar, a1_attach = create_support_bar(A1,mount_thickness) B1_bar, b1_attach = create_support_bar(B1,mount_thickness) m_attach1_gen = m_attach1.get_generator() a1_gen = a1_attach.get_generator() b1_gen = b1_attach.get_generator() a1_join = solid.hull()(m_attach1_gen, a1_gen) b1_join = solid.hull()(m_attach1_gen, b1_gen) cronenberg1 = PolyMesh(generator= solid.union()(a1_join,b1_join)) A2_bar, a2_attach = create_support_bar(A2,mount_thickness) B2_bar, b2_attach = create_support_bar(B2,mount_thickness) m_attach2_gen = m_attach2.get_generator() a2_gen = a2_attach.get_generator() b2_gen = b2_attach.get_generator() a2_join = solid.hull()(m_attach2_gen, a2_gen) b2_join = solid.hull()(m_attach2_gen, b2_gen) cronenberg2 = PolyMesh(generator= solid.union()(a2_join,b2_join)) aparatus = cronenberg1 + A1_bar + B1_bar + mt + cronenberg2 + A2_bar + B2_bar OT = (0, 0, 0) OQ = (0, 0, 1, 0) OP = (OT, OQ) pos_O, neg_O = joint_from_point(Point(0,0), "1O", 1) torso = Body( pose = OP, joints = [pos_O, A2, B2, A1, B1], elts=[Layer( aparatus, name='lol', color='yellow', )], name='torso' ) # coupler = Body( # pose = OP, # joints = [pos_O], # elts = [Layer(shaft_conn, name='lol', color = 'blue')], # name = 'coupler' # ) # kwargs['elts'] = [torso]+ link_bodies#[torso] , conn coupler, #kwargs['children'] = [torso] ################################################## #b3, j3, c3 = create_klann_part(-1,1+ np.pi/2, "3") b4, j4, c4 = create_klann_part(1, 1+ np.pi/2, "4", True) # print(conn.joints) #A3,_,B3 = j3 A4,_,B4 = j4 link_bodies = b4+link_bodies link_conns = c4+link_conns # # #create servo mount that connects to shaft connector #mt, m_attach1, m_attach2 = create_servo_mount() # # #add support for A,B mount_thickness= 6 # shaft coupler layer_thickness = 15 # # ##create the attacher thing, with joints #first layer of standoffs #st_body1,anch1 = standoff(mount_thickness) #contains joint "anchor" #st_body2,anch2 = standoff(mount_thickness) st_body3,_ = standoff(layer_thickness) #contains joint "anchor" st_body4,_ = standoff(layer_thickness) #st_conn1 = ((0,"1b3","1A"),(0,st_body1.name,"A")) #st_conn2 = ((0,"1b2","1B"),(0,st_body2.name,"A")) #second layer: st_conn3 = ((0,"4b3", "4A"),(0,st_body3.name, "A")) st_conn4 = ((0,"4b2", "4B"),(0,st_body4.name, "A")) #A1_bar, a1_attach = create_support_bar(A1,mount_thickness) #B1_bar, b1_attach = create_support_bar(B1,mount_thickness + layer_thickness) # #m_attach1_gen = m_attach1.get_generator() # b1_gen = b1_attach.get_generator() #((dxa,dya,_),_) = A1.pose #((dxb,dyb,_),_) = B1.pose #placed_anch1 = solid.translate([dxa,dya,0])(anch1) #placed_anch2 = solid.translate([dxb,dyb,0])(anch2) #a1_join = solid.hull()(m_attach1_gen, placed_anch1) #b1_join = solid.hull()(m_attach1_gen, placed_anch2) #cronenberg1 = PolyMesh(generator= solid.union()(a1_join,b1_join)) #aparatus = cronenberg1 +mt shaft_conn = create_shaft_connector() OT = (0, 0, 0) OQ = (0, 0, 1, 0) OP = (OT, OQ) pos_O, neg_O = joint_from_point(Point(0,0), "1O", 1) O_3, _ = joint_from_point(Point(0,0),"3O",5) # torso = Body( # pose = OP, # joints = j1+j2, # elts=[Layer( # aparatus, # name='lol', # color='yellow', # )], # name='torso' # ) coupler = Body( pose = OP, joints = [pos_O,O_3], elts = [Layer(shaft_conn, name='lol', color = 'blue')], name = 'coupler' ) kwargs['elts'] = link_bodies+ [coupler, st_body3, st_body4,torso]#[torso] [conn,torso]+ , [coupler]+ conn coupler, #kwargs['children'] = [torso] if 'connections' not in kwargs.keys(): kwargs['connections'] = [ #((0, 'conn', '1O'),(0,'coupler','1O')), #((0, 'coupler', '3O'),(0, '4conn','4O')), # 4O? #st_conn1, #st_conn2, st_conn3, st_conn4, # ((0, 'torso', '1O'),(0, 'coupler','1O')), ((0, 'torso', '1A'),(0, '1b3', '1A')), ((0, 'torso', '1B'),(0, '1b2', '1B')), ((0, 'torso', '2A'),(0, '2b3', '2A')), ((0, 'torso', '2B'),(0, '2b2', '2B')) ] + link_conns super(DoubleDoubleDeckerKlannLinkage, self).__init__(**kwargs)
def test_linearizer(): O,A,B,C,D,E,F,M,b1,b2,b3,b4,conn = create_klann_geometry(1,1) b1_dict = {b1: [M,D,C]} b2_dict = {b2: [B,E]} b3_dict = {b3: [A,C]} b4_dict = {b4:[E,D,F]} conn_dict = {conn: [M,O]} O2,A2,B2,C2,D2,E2,F2,M2,b12,b22,b32,b42,conn2 = create_klann_geometry(-1,1) b1_dict2 = {b12: [M2,D2,C2]} b2_dict2 = {b22: [B2,E2]} b3_dict2 = {b32: [A2,C2]} b4_dict2 = {b42:[E2,D2,F2]} O3,A3,B3,C3,D3,E3,F3,M3,b13,b23,b33,b43,conn3 = create_klann_geometry(1,1 + np.pi) b1_dict3 = {b13: [M3,D3,C3]} b2_dict3 = {b23: [B3,E3]} b3_dict3 = {b33: [A3,C3]} b4_dict3 = {b43:[E3,D3,F3]} O4,A4,B4,C4,D4,E4,F4,M4,b14,b24,b34,b44,conn4 = create_klann_geometry(-1,1 + np.pi) b1_dict4 = {b14: [M4,D4,C4]} b2_dict4 = {b24: [B4,E4]} b3_dict4 = {b34: [A4,C4]} b4_dict4 = {b44:[E4,D4,F4]} conn_dict4 = {conn4:[M4,O4]} # seg_paths = simulate_linkage_path(1,1) # seg_paths2 = simulate_linkage_path(-1,1) # seg_paths3 = simulate_linkage_path(1,1+np.pi) # seg_paths4 = simulate_linkage_path(-1,1+np.pi) # seg_paths.update(seg_paths2) # seg_paths.update(seg_paths3) # seg_paths.update(seg_paths4) # print("generated Geometry") # # seg_confs = seg_conflicts(seg_paths) # print("calculated conflicts") # # #add gear conflicts and joints gear = Segment(M,M3) cap = Segment(M3,M3) # seg_confs[b1]+=[gear] # seg_confs[b12]+=[gear] # seg_confs[b13]+=[gear] # seg_confs[b14]+=[gear] # seg_confs[gear] = [b1,b12,b13,b14] gear_dict = {gear:[M,M3]} cap_dict = {cap:[M3]} # seg_dicts = [b1_dict, b2_dict, b3_dict, b4_dict] seg_dicts2 = [b1_dict2, b2_dict2, b3_dict2, b4_dict2] seg_dicts3 = [b1_dict3, b2_dict3, b3_dict3, b4_dict3] seg_dicts4 = [b1_dict4, b2_dict4, b3_dict4, b4_dict4] all_dicts = [gear_dict, conn_dict, cap_dict] + seg_dicts + seg_dicts2 + seg_dicts3 + seg_dicts4 # print("added gear") # # neighbor_dicts = {list(seg.keys())[0]: [list(s.keys())[0] for s in all_dicts if shares_joint(s,seg)] # for seg in all_dicts} print("created neighbors") #optimal = create_layer_assignment(neighbor_dicts,seg_confs) optimal = {} optimal[gear] = 0 optimal[b1] = 1 optimal[b2] = 1 optimal[b3] = 2 optimal[b4] = 2 optimal[b12] = 2 optimal[b22] = 2 optimal[b32] = 1 optimal[b42] = 1 optimal[b13] = -2 optimal[b23] = -2 optimal[b33] = -1 optimal[b43] = -1 optimal[b14] = -1 optimal[b24] = -1 optimal[b34] = -2 optimal[b44] = -2 optimal[conn] = 3 optimal[cap] = -3 lock_joints = [conn,conn2,conn3,conn4,gear, cap] anchor_pts = [A,B,O,A4,B4] ratts, conns, seg_names, joint_names = rationalize_linkage(all_dicts, optimal, lock_joints, anchor_pts) pos_O, neg_O = joint_from_point(Point(0,0), "1O", 1) #Create torso mt, m_attach1, m_attach2 = create_servo_mount() # #add support for A,B mount_thickness= 3 # shaft coupler layer_thickness = 3 ##create the attacher thing, with joints A1_bar, a1_attach = create_support_bar(joint_from_point(A,"A",3)[0],mount_thickness) B1_bar, b1_attach = create_support_bar(joint_from_point(B,"B",2)[0],mount_thickness) m_attach1_gen = m_attach1.get_generator() a1_gen = a1_attach.get_generator() b1_gen = b1_attach.get_generator() a1_join = solid.hull()(m_attach1_gen, a1_gen) b1_join = solid.hull()(m_attach1_gen, b1_gen) cronenberg1 = PolyMesh(generator= solid.union()(a1_join,b1_join)) A2_bar, a2_attach = create_support_bar(joint_from_point(A2,"A2",2)[0],mount_thickness) B2_bar, b2_attach = create_support_bar(joint_from_point(B2,"B2",3)[0],mount_thickness) m_attach2_gen = m_attach2.get_generator() a2_gen = a2_attach.get_generator() b2_gen = b2_attach.get_generator() a2_join = solid.hull()(m_attach2_gen, a2_gen) b2_join = solid.hull()(m_attach2_gen, b2_gen) cronenberg2 = PolyMesh(generator= solid.union()(a2_join,b2_join)) aparatus = cronenberg1 + A1_bar + B1_bar + mt + cronenberg2 + A2_bar + B2_bar aparatus.save("torso.stl") OT = (0, 0, 0) OQ = Z_JOINT_POSE[1] OP = (OT, OQ) torso = Body( pose = OP, joints = [pos_O], elts=[Layer( aparatus, name='lol', color='yellow', )], name='torso' ) ratts += [torso] conns += [((0,'torso',"1O"),(0,seg_names[conn], joint_names[O]))] #print ratts #print conns return ratts, conns
def save(self, file): # Add screws screw_head_radius = 3.0 screw_head_length = 2.5 screw_shaft_radius = 1.40 # 2.8mm diameter = 0.3mm extra screw_shaft_length = 15.0 head = sc.translate([0,0,screw_shaft_length])( sc.cylinder(h=screw_head_length + 100, r=screw_head_radius, segments=self._round_segments) ) shaft = sc.cylinder(h=screw_shaft_length + 0.1, r=screw_shaft_radius, segments=self._round_segments) screw_down = sc.translate([0,0,-screw_shaft_length - screw_head_length])( sc.union()(head,shaft) ) # Origin is top of screw screw_side = sc.rotate([0,90,0])(screw_down) sc.scad_render_to_file(screw_side, "screw.scad", include_orig_code=False) # Place 4 screws in the right side screw_recess_side = 1.0 assert screw_recess_side < self._thickness_xy side_thick = self._thickness_xy - self._board_slot ymin = self._board_bbox.bot() - self._board_slot - side_thick/2.0 ymax = self._board_bbox.top() + self._board_slot + side_thick/2.0 zmin = -self.cavity_bot - self._thickness_z + screw_head_radius + self._min_screw_material zmax = self.cavity_top - self._thickness_z - screw_head_radius x = self._board_bbox.right() + self._thickness_xy + 1.0 # Add screws to the side for y in [ymin, ymax]: for z in [zmin, zmax]: self._case -= sc.translate([x,y,z])(screw_side) print "Free material around side screws: {0}mm".\ format(self._thickness_xy - self._board_slot - 2*screw_shaft_radius) # Add screws to the top screw_recess_top = 0 assert screw_recess_top < self._thickness_z min_screw_depth = 3.0 #Lowest depth screw can possibly go zmin = self.cavity_top + screw_head_length + min_screw_depth z_want = self.cavity_top + self._thickness_z - screw_recess_top z = max(zmin, z_want) ys = [self._board_bbox.top() + self._board_slot + (self._thickness_xy - self._board_slot)/2.0, self._board_bbox.bot() - self._board_slot - (self._thickness_xy - self._board_slot)/2.0] xs = [self._board_bbox.left() + screw_head_radius, self._board_bbox.right() - screw_shaft_length - 1.0] for y in ys: for x in xs: self._case -= sc.translate([x,y,z])(screw_down) #Top area: top of the case top_area_select = self._board_bbox.copy().pad(self._thickness_xy*2) top_area_select = rect2scad(top_area_select, self._thickness_z + 0.1, self.cavity_top - 0.05) # main_area is the case without the top or side main_area = self._board_bbox.copy() main_area.bounds[0][0] -= self._thickness_xy*2 main_area.bounds[0][1] -= self._thickness_xy*2 main_area.bounds[1][0] -= 0.05 #So we don't have a degenerate face main_area.bounds[1][1] += self._thickness_xy*2 main_area = rect2scad(main_area, self.height * 2, z_start = -self.height - 10) #Add screws to hold down the board remove_top = self._board_bbox.copy().pad(self._thickness_xy*2) remove_top = rect2scad(remove_top, self.height, self.cavity_top + 0.05) x = self._board_bbox.left() + (self._board_bbox.width + self._board_slot*2)/2.0 ys = [self._board_bbox.bot() - screw_shaft_radius - 0.5, self._board_bbox.top() + screw_shaft_radius + 0.5] z = screw_head_length for y in ys: self._case -= (sc.translate([x,y,z])(screw_down) - remove_top) print "Board screw location: ({0}, {1})".format(x,y) # Separate out the sides of the case main_part = self._case * main_area side = self._case - (main_area + top_area_select) # Side of the case, first part to screw on #The top of the case (screwed on after the side) top = self._case * top_area_select main_part -= top_area_select sc.scad_render_to_file(top, "top." + file, include_orig_code=False) sc.scad_render_to_file(main_part, "main." + file, include_orig_code=False) sc.scad_render_to_file(side, "side." + file, include_orig_code=False) exploded = sc.union()( main_part, sc.translate([40,0,0])(side), sc.translate([0,0,40])(top) ) sc.scad_render_to_file(exploded, "exploded." + file, include_orig_code=False) sc.scad_render_to_file(self._case, file, include_orig_code=False)