def standoff(thickness): """ Stackable, gluable 3D printable standoff connector w/pivot axis. """ global standnumber OT = (0, 0, 0) OQ = (0, 0, 1, 0) OP = (OT, OQ) peg_height = 5.5 clearance = 3.2 base = solid.cylinder(r=4, h=thickness, segments = 100) conn = solid.cylinder(r=1.9, h=peg_height, segments = 100) #wtf??? can't get z axis on Joint to work, no matter what I put it just #defaults to 0, so I'm going to orient everything at the origin. anchor = Joint((0,0, -100),Z_JOINT_POSE[1],name="A") b_placed = solid.translate([0,0,-thickness])(base) unit = b_placed+ conn - solid.translate([0,0,-(clearance+ thickness)])(conn) pm = PolyMesh(generator = unit) stand = Body( pose = OP, joints = [anchor], elts = [Layer(pm, name="lol", color = 'yellow')], name = 'standoff'+str(standnumber) ) standnumber = standnumber + 1 return stand, b_placed
def connector(): """ Connector 2.0!!! comes in two better sized segments, now with indent! """ global pinnumber OT = (0, 0, 0) OQ = (0, 0, 1, 0) OP = (OT, OQ) base = solid.cylinder(r=4, h = 4, segments = 100) conn = solid.cylinder(r = 1.9, h = 8, segments = 100 ) #8.2 anchor = Joint( ((0, 0, 8),Z_JOINT_POSE[1]), name="pin" ) bottom = base+ solid.translate([0,0,4])(conn) cap = solid.translate([0,0,4+6.4])(base) dimple_cap = cap - bottom p1 = PolyMesh(generator = bottom) p2 = PolyMesh(generator = dimple_cap) #p1.save("pin.stl") #p2.save("cap.stl") poly = p1+p2 pin = Body( pose = OP, joints = [anchor], elts = [Layer(poly, name='lol', color = 'blue')], name = 'coupler'+str(pinnumber) ) pinnumber = pinnumber + 1 return pin
def locked_offset(): global locked_count name = "locked_" + str(locked_count) locked_count +=1 j_name = "locked_joint_" + str(locked_count) thickness = 6 #span 2 layers peg_height = 3.2 clearance = 3.2 base = solid.cylinder(r=1.9, h=thickness, segments = 100) conn1 = solid.cube([4/math.sqrt(2),4/math.sqrt(2),3],center=True) conn2 = solid.cube([4/math.sqrt(2),4/math.sqrt(2),3],center=True) #wtf??? can't get z axis on Joint to work, no matter what I put it just #defaults to 0, so I'm going to orient everything at the origin. b_placed = solid.translate([0,0,3])(base) unit = b_placed + solid.translate([0,0,1.5])(conn1) + solid.translate([0,0,10.5])(conn2) pm = PolyMesh(generator = unit) pm.save("lock.stl") j1 = Joint( ((0, 0, 12),NZ_JOINT_POSE[1]), #9 name=j_name ) OT = (0, 0, 0) OQ = (0, 0, 1, 0) OP = (OT, OQ) layers=Layer( pm, name="lol", color='blue' ) b = Body(pose=OP, elts=[layers], joints=[j1], name=name) return b, name, j_name
def strunk(): c1 = solid.cylinder(r= 15, h = 70) c2 = solid.translate([9,0,0])(solid.cylinder(r=15, h= 70)) m1 = solid.translate([0,-15,0])(solid.cube([9,30,70])) total = join_list([c1,c2,m1]) total = solid.translate([0,0,84])(total) return total
def spacerMaker(radius, right, out, spacer, name): s = solid.rotate(a = [-90, 0, 0])\ (solid.cylinder(r=outerD/2, h=spacer, segments = 20)) s1 = solid.rotate(a = [90, 0, 0])\ (solid.cylinder(r=innerD/2, h=3*spacer, segments = 20, center=True)) s = solid.difference()(s, s1) """s1 = solid.rotate(a = [90, 0, 0])\ (solid.cylinder(r=innerD/2, h=2*border, segments = 20)) s1 = solid.translate(v = [0, spacer+2*border, 0])(s1) s = s + s1""" if not out: s = solid.translate(v = [0, -spacer, 0])(s) off = radius - width else: off = radius s = solid.translate(v = [0, off, 0])(s) if right: s = solid.rotate(a = [0, 0, -90])(s) s = PolyMesh(generator=s) s.save("heliodon/spacer" + name +".stl") return s
def sarms(): hand = solid.sphere(r=4) arm = solid.translate([0,0,4])( solid.cylinder(r=4, h = 68)) shoulder = solid.translate([0,0,72])( solid.sphere(r=4)) a1 = hand+arm+shoulder a2 = solid.translate([50,0,70])(a1) a1 = solid.translate([-40,0,70])(a1) a1 = solid.rotate([0,10,0])(a1) a2 = solid.rotate([0,-10,0])(a2) return a1+a2
def ssupport(): arch1 ,thet1, rad1= circle_arch(30.0, 5.0, 3) arch1 = solid.translate([14,-28/2,0])(solid.rotate([0,0, -thet1/2])(arch1)) arch2 = solid.translate([0,0,1])(arch1) arch3 = solid.translate([0,0,-1])(arch1) arch1 = join_list([arch1, arch2, arch3]) pillar1 = solid.rotate([0,90,0])(solid.cylinder(r=2, h=35) ) pillar1 = pillar1 - solid.translate([-1,0,-3])(solid.cube([37,4, 8])) pillar2 = solid.rotate([180,0,0])(solid.translate([0,28])(pillar1)) return join_list([arch1, pillar1, pillar2])
def create_shaft_connector(): """ Oriented relative to the shaft that will be driven at the origin in the +Z direction. TODO: Consider refactoring into mechanism with joint at O. """ mount_plate = solid.cylinder(r = 10, h= 3) shaft = solid.translate([-2,-2,0])(solid.cube([4,4,20])) shifted_shaft = solid.translate([0,0,3])(shaft) total = mount_plate+shaft pl = PolyMesh(generator=total) return pl
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 rasp_pi(): base = solid.color([0,.7,.1])(solid.cube([8.5,5.5,.1])) metal = t55_to_1([209,209,209]) yellow = t55_to_1([255, 188, 60]) ether = solid.translate([-0.1,3.9,0])(solid.cube([2.1,1.6,1.4])) ether = solid.color(metal)(ether) usb = solid.cube([1.7,1.3,1.5]) usb = solid.translate([-.7,1.9,0])(solid.color(metal)(usb)) audio = solid.cube([1.2, 1.5, 1.2]) audio = solid.translate([1.5,-.5,0])(solid.color([0,0,0])(audio)) tv = solid.cube([1,1.9,1.5]) tv = solid.translate([3.4,-.8,0])(solid.color(yellow)(tv)) hdmi = solid.cube([1.5,1.1,.9]) hdmi = solid.translate([3.4,4.6,0])(solid.color(metal)(hdmi)) gpio = solid.cube([3.2,.4,1.2]) gpio = solid.translate([5.3,.1,0])(solid.color([0,0,0])(gpio)) sdcard = solid.cube([1.8,2.9,.4]) sdcard = solid.translate([6.7, 1.6, -.4])(solid.color([0,0,0])(sdcard)) musb = solid.cube([.5,.7,.3]) musb = solid.translate([7.9, 4.5, 0])(solid.color([0,0,0])(musb)) out = [base, ether, usb, audio, tv, hdmi, gpio, sdcard, musb] return join_list(out)
def scaffold(length, color=[0, 0, 1, 1]): h = solid.translate([diameter / 2.0, 0, length / 2.0])( solid.scale([diameter, diameter, length])( solid.cube(center=True) ) ) + solid.translate([0, 0, length / 2.0])( solid.scale([center_notch + tool_radius * 2, center_notch, length])( solid.cube(center=True) ) ) # scale & move in Z to ensure overlap h = solid.translate([0, 0, -(length * .1)/2.0])(solid.scale([1, 1, 1.1])(h)) return solid.color(color)(h)
def genAsOpenscad(self): """Generates zebrafish geometry as solid python object. Useful if geometry is used to be passed to openscad. Returns: solid.solidpython.openscad_object: Solid python object. """ outerBall=solid.translate([self.center[0],self.center[1],-self.outerRadius])(solid.sphere(r=self.outerRadius)) innerBall=solid.translate([self.center[0],self.center[1],-self.outerRadius-self.centerDist])(solid.sphere(r=self.innerRadius)) return outerBall-innerBall
def planar_slice_3d(mesh, slice_args, slice_width=1): (plane, offset) = slice_args slice_gen = sl.linear_extrude(slice_width)(plane.get_generator()) slice_gen = sl.translate(offset)(slice_gen) slice = PolyMesh(generator=slice_gen) intersection = slice.intersected(mesh) return intersection
def assemble_chair(polygons, tf_xyz_rpy, t=3.0): """ Create a 3D rendering of a chair from part outlines. Args: polygons ([PolyLine]): list of PolyLines representing the outlines of the chair parts tf_xyz_rpy ([[x,y,z][r,p,y]]): List of transformations as x,y,z offsets and roll, pitch, yaw rotations in degrees t (int): material thickness Returns: A list of PolyMeshes, with one PolyMesh per input polygon, transformed by corresponding tf input """ polys = [] for (p, r) in zip(polygons, tf_xyz_rpy): translation, rotation = r solid_p = p.get_generator() thick_p = sl.linear_extrude(t)(solid_p) rotated_p = sl.rotate(rotation)(thick_p) translated_p = sl.translate(translation)(rotated_p) poly = PolyMesh(generator=translated_p) polys.append(poly) return polys
def create_crank_shaft(save = False): """ Oriented relative to the shaft that will be driven at the origin in the +Z direction. """ global shaft_count name = "shaft_" + str(shaft_count) j_name = "shaft_joint_" + str(shaft_count) mount_plate = solid.cylinder(r = 10, h= 3) shaft = solid.cube([4/math.sqrt(2),4/math.sqrt(2),6], center = True) shifted_shaft = solid.translate([0,0,3])(shaft) total = mount_plate+shaft pl = PolyMesh(generator=total) if save: pl.save("crank.stl") j1 = Joint( ((0, 0, 0),Z_JOINT_POSE[1]), name=j_name ) OT = (0, 0, 0) OQ = (0, 0, 1, 0) OP = (OT, OQ) layers=Layer( pl, name="lol", color='blue' ) b = Body(pose=OP, elts=[layers], joints=[j1], name=name) return b, name, j_name
def create_support_bar(jt, offset): """ create a support bar to the point from the origin XY plane account for default klann spacing for now. plan on gluing two segments with acetone """ ((dx,dy,dz),_) = jt.pose placed_base = solid.translate([0,0,-offset])(solid.cylinder(r = 4, h = offset)) clevis_pin = solid.translate([0,0,-(offset+5.5)])(solid.cylinder(r=1.9, h = 5.5,segments=300)) total = placed_base + clevis_pin translated = solid.translate([dx,dy,dz])(total) pl = PolyMesh(generator=translated) attach = PolyMesh(generator = solid.translate([dx,dy,dz])(placed_base)) return pl, attach
def viz(self,position): """ Generates a OpenScad model to visualize the sun position """ ## Generating the hemisphere ## starting_sphere = solid.sphere(self.r, segments= 64) box_sub = solid.utils.down(((self.r * 2 + 10)/2))(solid.cube((self.r * 2 + 10), center= True)) hemisphere = starting_sphere - box_sub hemisphere = PolyMesh(generator= hemisphere).simplified() #hemisphere = (solid.utils.color([0.75,0.75,0.75,0.1]))(hemisphere.get_generator()) #this sucks...need to do this way in order do render #hemisphere = PolyMesh(generator= hemisphere) ## Generate the sphere for the sun ## sun_sphere = solid.sphere(5, segments= 64) vector = position sun_sphere = (solid.translate(vector))(sun_sphere) sun_sphere = PolyMesh(generator= sun_sphere).simplified() L1 = Layer(hemisphere, name= "hem", color=[200,200,200,1000]) L2 = Layer(sun_sphere, name="sun", color='yellow') B1 = Block([L1, L2]) return B1.show(is_2d= False)
def combine_shapes(shapes): """ Transform and combine shapes as in all_shapes below using OpenSCAD generators and functions. Args: shapes = (open_pl, squarcle_pl, star_pl) Retruns: A single PolyLine with transformed and combined geometry """ open_pl, squarcle_pl, star_pl = shapes small_open_pl = solid.scale(0.5)( open_pl.get_generator() ) trans_squarcle_pl = solid.translate([0,50])( squarcle_pl.get_generator() ) trans_rot_star_pl = solid.translate([50,175])( solid.rotate(numpy.pi/2)( star_pl.get_generator() ) ) combined = (small_open_pl + trans_squarcle_pl + trans_rot_star_pl) return PolyLine(generator=combined)
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 create_servo_mount(): """ right now designed to fit Jacobs institute model """ width = 6.5 length = 20.0 depth = 2.3 voffset = -18.5 - 9 left_bar = solid.cube([width,length,depth], center = True) hole = solid.cylinder(r=2,h=10, center =True,segments = 100) hole1 = solid.translate([0,4,0])(hole) hole2 = solid.translate([0,-4,0])(hole) left_bar = solid.difference()(left_bar, hole1) left_bar = solid.difference()(left_bar, hole2) right_bar = solid.cube([width,length,depth],center = True) right_bar = solid.difference()(right_bar, hole1) right_bar = solid.difference()(right_bar, hole2) left_spread = -30.0 right_spread = 17.0 left_bar = solid.translate([left_spread, 0,-(depth/2 + voffset)])(left_bar) right_bar = solid.translate([right_spread, 0 , -(depth/2+voffset)])(right_bar) connector = solid.cube([(right_spread - left_spread) + width,width,depth],center=True) placed_connector = solid.translate([(left_spread+right_spread)/2,-(length/2 +width/2), -(depth/2+voffset)])(connector) total_mount = left_bar + placed_connector + right_bar pl = PolyMesh(generator= total_mount) attach_point1 = PolyMesh(generator =solid.translate([width, 0,0])(right_bar)) attach_point2 = PolyMesh(generator =solid.translate([-width, 0,0])(left_bar)) return pl, attach_point1, attach_point2
def conic_section(theta): line = solid.polygon(points = [[0,0],[50,50],[49.9,50],[0,.1]]) cone = solid.rotate_extrude( convexity = 20)(line) plane = solid.translate([0,0,5])(solid.cube([50,50,.1],center = True)) plane = solid.rotate([0,theta,0])(plane) section = solid.rotate([0,-1*theta, 0])(solid.intersection()(cone, plane)) return section
def rampSide(leng, wide, high, transl, rotat): '''Return a bar of specified length, width, height, except with ends ramping at 45 degrees at one end, -45 at other. Is like a rampBar rotated +/- 90 degrees about the x axis. Parameters: First four as for rampBar. rotat: +/- 90 for amount of rotation about the x axis. ''' # x-axis rotate below exchanges hi, wide - next two lines compensate. tcorr = [0,0,-wide] if rotat>0 else [0,-high,0] s = rotate([rotat,0,0])(rampBar(leng, high, wide, tcorr)) return translate(transl)(s)
def sunk_hole(r=1, length=10): """ Hole from below into z=0 plane. Countersunk: larger diameter at beginning, for easier insertion. :param r: Default: r=1 for M2.3 screws :param length: :return: """ hole = translate([0, 0, length / 2])(cylinder(r, h=length, center=True)) hole += cylinder(r1=2 * r, r2=r, h=1.4 * r, center=True) return hole
def three_point_cicle(p0: Point2, p1: Point2, p2: Point2, radius_adjustment=0, segments=100): center = _circle_center_by_three_points(p0, p1, p2) radius = ((center[0] - p0[0])**2 + (center[1] - p0[1])**2)**0.5 return solid.translate( (center[0], center[1], 0))(solid.circle(radius + radius_adjustment, segments=segments))
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 double_plate(): plate_height = (sa_double_length - mount_height) / 3 # plate_height = (2*sa_length-mount_height) / 3 top_plate = sl.cube([mount_width, plate_height, web_thickness], center=True) top_plate = sl.translate([ 0, (plate_height + mount_height) / 2, plate_thickness - (web_thickness / 2) ])(top_plate) return sl.union()(top_plate, sl.mirror([0, 1, 0])(top_plate))
def rationalize_segment(seg,joints,name, state= {}, is_locked = False): p1 = seg p2 = seg if type(seg) != Point: p1 = seg.p1 p2 = seg.p2 buff = 6 thickness = 3 p1x = p1.x.evalf(subs=state) p1y = p1.y.evalf(subs=state) p2x = p2.x.evalf(subs=state) p2y = p2.y.evalf(subs=state) c = solid.cylinder(r= buff, h =thickness, segments =100) c1 = solid.translate([p1x, p1y, 0])(c) c2 = solid.translate([p2x, p2y, 0])(c) link = solid.hull()(c1,c2) OT = (0, 0, 0) OQ = (0, 0, 1, 0) OP = (OT, OQ) pm = PolyMesh(generator=link) for joint in joints: if is_locked: pm = square_neg(pm,joint) else: pm = clevis_neg(pm,joint) if "conn" in name: #this is a connector joint pm = add_servo_mount(pm) layers=Layer( pm, name="lol", color='green' ) link_body = Body(pose=OP, elts=[layers], joints=joints, name=name) return link_body
def wire_post(direction, offset): s1 = sl.cube( [wire_post_diameter, wire_post_diameter, wire_post_height], center=True ) s1 = sl.translate([0, -wire_post_diameter * 0.5 * direction, 0])(s1) s2 = sl.cube( [wire_post_diameter, wire_post_overhang, wire_post_diameter], center=True ) s2 = sl.translate( [0, -wire_post_overhang * 0.5 * direction, -wire_post_height / 2] )(s2) shape = sl.union()(s1, s2) shape = sl.translate([0, -offset, (-wire_post_height / 2) + 3])(shape) shape = sl.rotate(-alpha / 2, [1, 0, 0])(shape) shape = sl.translate([3, -mount_height / 2, 0])(shape) return shape
def usb_holder_hole(): shape = sl.cube(usb_holder_size, center=True) shape = sl.translate( [ usb_holder_position[0], usb_holder_position[1], (usb_holder_size[2] + usb_holder_thickness) / 2, ] )(shape) return shape
def projection(): p = outer_projection(3.1) horn_button = sp.translate((-18, 15))(sp.square(cherry_mx_cutout, center=True)) headlight_button = sp.translate((-18, -15))(sp.square(cherry_mx_cutout, center=True)) light_switch = sp.translate((0, -15))(sp.circle(d=switch_diameter, segments=32)) gear_select_switch = sp.translate((18, 15))(sp.circle(d=switch_diameter, segments=32)) display_button = sp.translate((18, -15))(sp.square(cherry_mx_cutout, center=True)) return p - horn_button - headlight_button - light_switch - gear_select_switch - display_button
def test_transform_equivalent(self) -> None: original_connector = connector.Connector( point=vector.Vector.from_raw([1, 1, 1]), axis=vector.Vector.from_raw([0, 0, 1]), normal=vector.Vector.from_raw([1, 0, 0]), ) self.assertEqual( original_connector.rotate(solid.rotate(a=[90, 90, 90])).translate( solid.translate([1, 1, 1])).scale(solid.scale([2, 2, 2])), original_connector.transform([ solid.rotate(a=90, v=[1, 0, 0]), solid.rotate(a=90, v=[0, 1, 0]), solid.rotate(a=90, v=[0, 0, 1]), solid.translate([1, 1, 1]), solid.scale([2, 2, 2]), ]), msg= "Transform should accept & correctly dispatch multiple transformations", )
def splanter(): bucket = solid.cylinder( r= 8, h= 9)- solid.translate([0,0,2])(solid.cylinder(r=7, h=9)) hole = solid.cylinder(r=.5, h= 2) bottom_holes = [] for i in range(10): for j in range(10): x= 2*i-7 y= 2*j - 7 if x**2 + y**2<(6.5)**2: bottom_holes+=[solid.translate([x,y,-1])(hole)] bucket -= join_list(bottom_holes) wall_holes = [] wallh = solid.translate([7,0,1.5])(solid.rotate([0,90,0])(hole)) for i in range(12): wall_holes += [solid.rotate([0,0,i*30])(wallh)] wall_ho = join_list(wall_holes) bucket -= wall_ho bucket -= solid.translate([0,0,2])(solid.rotate([0,0,15])(wall_ho)) bucket = solid.color("SaddleBrown")(bucket) return bucket
def rect2scad(rect, height, z_start = 0.0, mirrored = False): """ Convert a Rectangle into an openscad cube by giving it a height and Z start """ scad_cube = sc.translate([rect.left(), rect.bot(), z_start])( sc.cube([rect.width, rect.height, height]) ) if mirrored: return sc.scale([1,1,-1])(scad_cube) else: return scad_cube
def base_rods30(rod_sep=30, z_length=10): """base for attaching to two parallel rods of 6mm diameter set 30mm apart.""" mount_height = 10 # height (y) of mount single_clamp = translate((rod_sep / 2, 0, 0))(single_rod_clamp(z_length)) base = single_clamp + mirror((1, 0, 0))(single_clamp) r_arc = (rod_sep**2 - 20**2)**.5 # TODO hardcoded arc_width = rod_sep + 10 - 6 * 3 # TODO r*diam_hole of single_rod_clamp arc = cube((arc_width, mount_height, z_length), center=True) arc -= translate( (0, -r_arc + mount_height / 4, 0))(cylinder(r=r_arc, h=4 * z_length, center=True)) base += arc base = translate((0, -20 - mount_height / 2, 0))(base) return base
def main(params: Params): profile = utils.profile_with_screws(params) cutout = None if params.cutout_depth > 0: cutout = s.linear_extrude(params.depth)(s.square( [params.interface_width, params.cutout_depth])) if cutout is not None: cutout_x = params.screw_spacing * 2 + params.screw_head_radius * 2 cutout_y1 = 0 cutout_y2 = params.height - params.cutout_depth profile = s.difference()( profile, s.translate([cutout_x, cutout_y1])(cutout), s.translate([cutout_x, cutout_y2])(cutout), ) return profile
def base(width, length, height): left = side(length) right = translate((width, 0, 0))( mirror((1, 0, 0))(left) ) center = translate((width/2-0.75, 0, 0))( translate((0, 1.5, 0))(cube((1.5, length-3, 1.375))) + translate((0, 0, 1.375))(cube((1.5, length, 1.375))) ) foot = end(width) head = translate((0, length, 0))( mirror((0, 1, 0))(foot) ) return union()( end_color(head), end_color(foot), side_color(left), side_color(right), side_color(center), )
def arc(radius): a = solid.difference()( solid.cylinder(r=radius, h=thick, segments=48), solid.cylinder(r=radius-width, h=thick, segments=48)) a = solid.intersection()(a, solid.cube([radius, radius, thick])) a = solid.difference()(a, solid.translate(v=[.75*outerD, radius-width/2, 0]) (solid.cylinder(r=bolt/2, h=2*thick, segments=20, center=True))) a = solid.difference()(a, solid.translate(v=[radius-width/2, .75*outerD, width/2.0]) (solid.cylinder(r=bolt/2, h=2*thick, segments=20, center=True))) c = solid.translate(v=[radius-width/2, 0, 0])\ (solid.cylinder(r=bolt/2, h=2*thick, segments=20, center=True)) # Add bolt holes for fastening the two sheets of acryllic together for step in range(1,3): a = solid.difference()(a, solid.rotate(a = [0,0, step * 30])(c)) PolyLine(generator = solid.projection()(a)).save("heliodon/a" + str(radius) + ".dxf") return PolyMesh(generator=a)
def rampBar(leng, wide, high, transl): '''Return a bar of specified length, width, height, except with ends ramping up at 45 degrees at one end, -45 at other, in a plane rotated about y axis. Parameters: leng, wide, high give x,y,z sizes. transl = 3-vector with x,y,z distances to translate the origin-corner of the bar. ''' s2 = sqrt(2) cu = cube([leng, wide, high]) box = rotate(a=[0,-45,0])(back(wide)((cube([s2*high, 3*wide, s2*high])))) return translate(transl)(cu-box-right(leng)(box))
def vertices_shape(self, idxs=[0, 1, 2, 3], rotate=True): verts = [] for idx in idxs: vert = self.vertices[idx] color = self.vert_colors[idx] shape = sl.cube([1,1,self.thickness], center=True) if rotate: for rot in self.rotations: shape = rot.rotate(shape) verts.append(sl.color(color)(sl.translate(vert)(shape))) return verts
def test_transform_dispatch_translation(self) -> None: holonomic_transformable = MockHolonomicTransformable() translation = solid.translate([21.0, 22.0, 23.0]) holonomic_transformable.transform(translation) self.assertEqual( holonomic_transformable._translations, [translation], msg="Translation should be correctly dispatched", )
def bearing(bearing_type: str = '624') -> OpenSCADObject: dims = bearing_dimensions[bearing_type.lower()] outerR = dims['outer_d'] / 2 innerR = dims['inner_d'] / 2 thickness = dims['thickness'] bearing = cylinder(outerR, thickness) bearing.add_param('$fs', 1) hole = cylinder(innerR, thickness + 2) hole.add_param('$fs', 1) bearing = difference()(bearing, translate([0, 0, -1])(hole)) return bearing
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 thing(d=27.9, h=10, width=16, width_hole=10.2, z=0, X=45): center = solid.cube(size=(width, width, h), center=True) - solid.hole()( solid.cube(size=(width_hole, width_hole, h * 2), center=True)) axis_base = solid.cube(size=(d, width_hole / 2, h), center=True) axis_1 = solid.rotate(a=X)(axis_base) axis_2 = solid.rotate(a=-X)(axis_base) outer_cylinder = solid.cylinder(d=d, h=h, center=True, segments=256) ret = (center + axis_1 + axis_2) * outer_cylinder return solid.translate(v=(0, 0, z + h / 2))(ret)
def bseat(): d = B_d h = B_h + 0.001 tmp = chamfers.mcad_chamfered_cylinder(h, internal=False)( sp.cylinder(d=d, h=h), chamfers.mcad_chamfer_cylinder(diameter=d, length=None, angle=30, depth=1, internal=False)) tmp = sp.translate([0, 0, h - 0.001])(sp.rotate([180, 0, 0])(tmp)) return tmp
def getOblongArm(self): '''Return a SolidPython object modeling an oblong arm (per specs in ArmParams object) bounded by four arcs of circles. ''' eps = 0.01 p, q, s, t, u, w = self.p, self.q, self.s, self.t, self.u, self.w r1, r2 = p - s, q - t domis, chi, dhi = 2 * max(r1, r2), 1.1, -0.05 arc1 = back(r1 + s)(cylinder(r=r1, h=1)) arc2 = back(q - r2)(cylinder(r=r2, h=1)) rl, vl, p1, p2 = self.solveArcArc(p, q, s, t, u) rr, vr, p3, p4 = self.solveArcArc(p, q, s, t, w) rightcircle = color(Green)(translate([u, -vl, dhi])(cylinder(r=rl, h=chi))) leftcircle = color(Red)(translate([w, -vr, dhi])(cylinder(r=rr, h=chi))) yrhi, yrlo, ylhi, yllo = p1[1], p2[1], p3[1], p4[1] xr, xl = min(p1[0], p2[0]), max(p3[0], p4[0]) dominol = translate([xl - domis, -yllo, dhi])(cube([domis, yllo - ylhi, chi])) dominor = translate([xr, -yrlo, dhi])(cube([domis, yrlo - yrhi, chi])) return (arc1 * arc2 - dominol - dominor) + rightcircle + leftcircle
def bottom_hull(p, height=0.001): shape = None for item in p: proj = sl.projection()(p) t_shape = sl.linear_extrude(height=height, twist=0, convexity=0, center=True)( proj ) t_shape = sl.translate([0, 0, height / 2 - 10])(t_shape) if shape is None: shape = t_shape shape = sl.hull()(p, shape, t_shape) return shape
def plot_space(dict, tl): path_labels = sorted(dict.keys()) path_count = len(path_labels) out =[] for i in range(path_count): color = t55_to_1( colorout2(i,path_count) ) for j in range(len(dict[path_labels[i]])): x = dict[path_labels[i]][j][0]*tl y = dict[path_labels[i]][j][1]*tl z = j*tl out += [solid.color(color)(solid.translate([x,y,z])(solid.cube([tl,tl,1])))] return out
def create_upper_case(): p0 = switches.get_switch_position((0, 3)) + Point2(-0.5, 0.5) p1 = switches.get_switch_position((2, 3)) + Point2(-0.5, 0.5) p2 = switches.get_switch_position((4, 3)) + Point2(0.5, 0.5) case = utils.three_point_cicle(p0, p1, p2, radius_adjustment=-1.5 * mm, segments=1000) # cut left edge case = case * sc.translate( (utils.big_cutter_length - 0.5, 0, 0))(utils.big_cutter_square) # cut right edge case = case * sc.translate( (-utils.big_cutter_length + 4.5, 0, 0))(utils.big_cutter_square) # cut buttom edge _, buttom_left_switch_y = switches.get_switch_position((0, 1)) case = case * sc.translate( (0, utils.big_cutter_length + buttom_left_switch_y - 0.5, 0))( utils.big_cutter_square) return case
def create_offset(): """ Oriented relative to the shaft that will be driven at the origin in the +Z direction. TODO: Consider refactoring into mechanism with joint at O. """ global offset_count name = "offset_" + str(offset_count) offset_count +=1 j_name = "offset_joint_" + str(offset_count) thickness = 6 #span 2 layers peg_height = 5.5 clearance = 3.2 base = solid.cylinder(r=4, h=thickness, segments = 100) conn = solid.cylinder(r=1.9, h=peg_height, segments = 100) #wtf??? can't get z axis on Joint to work, no matter what I put it just #defaults to 0, so I'm going to orient everything at the origin. b_placed = solid.translate([0,0,-thickness])(base) unit = b_placed+ conn - solid.translate([0,0,-(clearance+ thickness)])(conn) pm = PolyMesh(generator = unit) pm.save("offset.stl") j1 = Joint( ((0, 0, 0),NZ_JOINT_POSE[1]), name=j_name ) OT = (0, 0, 0) OQ = (0, 0, 1, 0) OP = (OT, OQ) layers=Layer( pm, name="lol", color='blue' ) b = Body(pose=OP, elts=[layers], joints=[j1], name=name) return b, name, j_name
def cage_circumference(d_outer=80.5, wall_thick=2, h=10, assemble=None): """Circle to fit cage ends, e.g. to transport cage inside a cylindrical tube""" d_inner = base.rods30_dist_third_rod + 7 # absolute diameter: contact to clips. clamp = translate((0, 0, 5))(cage_3_clips(inside=True)) # bottom at z=0 circ_x_at_clamp = ((d_outer / 2)**2 - 30**2)**.5 back_face = cube((2 * circ_x_at_clamp, wall_thick, h), center=True) back_face = translate((0, -30 + wall_thick / 2, h / 2))(back_face) circle = cylinder(d=d_outer, h=h) circle -= translate( (0, 0, wall_thick))(cylinder(d=d_outer - 2 * wall_thick, h=2 * h)) # relative diameter: wall thickness circle -= translate((0, 0, -2))(cylinder(d=d_inner, h=2 * h)) # clear space past -y of clamps, so that cage can rest against wall when used with hook. helper_block_y = 30 circle -= translate((0, -20 - 10 - helper_block_y / 2, 0))(cube( (100, helper_block_y, 100), center=True)) # add some holes to screw cage onto something for angle_deg in (-30, 30, 150, 210): hole_position = lambda obj: rotate(angle_deg)(translate( (d_inner / 2, 0, 0))(obj)) circle += hole_position(cylinder(d=8, h=wall_thick)) circle -= hole_position(cylinder(d=3.2, h=2 * h, center=True)) return clamp + circle + back_face
def label(a_str: str, width: float = 15, halign: str = "left", valign: str = "baseline", size: int = 10, depth: float = 0.5, lineSpacing: float = 1.15, font: str = "MgOpen Modata:style=Bold", segments: int = 40, spacing: int = 1) -> OpenSCADObject: """Renders a multi-line string into a single 3D object. __author__ = 'NerdFever.com' __copyright__ = 'Copyright 2018-2019 NerdFever.com' __version__ = '' __email__ = '*****@*****.**' __status__ = 'Development' __license__ = Copyright 2018-2019 NerdFever.com """ lines = a_str.splitlines() texts = [] for idx, l in enumerate(lines): t = text(text=l, halign=halign, valign=valign, font=font, spacing=spacing).add_param('$fn', segments) t = linear_extrude(height=1)(t) t = translate([0, -size * idx * lineSpacing, 0])(t) texts.append(t) result = union()(texts) result = resize([width, 0, depth])(result) result = translate([0, (len(lines) - 1) * size / 2, 0])(result) return result
def makeGear(self, sg, ap): '''Produce CSG for one gear. Parameter sg is None if this will be a sun gear, else is the sun Gear object. Other data is in ap, a GearAssembly object. ''' hh, h0, h1, h2, h3 = 0.1, 1, 1.1, 1.2, 1.3 nT, tLen, tRad = self.nT, (self.td - self.rd) * .3, self.rd / 2 asm = cylinder(d=self.rd, h=h2) for i in range(nT): tAngle = self.sma + 2 * i * pi / nT c = rotate(tAngle * 180 / pi)(cube([tLen, tLen / (6 + i), h2])) dx, dy = tRad * cos(tAngle), tRad * sin(tAngle) asm += translate([dx, dy, 0])(c) asm = color(Black)(asm) + color(Magenta)(cylinder(d=self.pd, h=h1)) centerHole = down(hh)(cylinder(d=ap.h / 10, h=h3)) asm = (asm + color(Green)(cylinder(d=self.td, h=h0))) - centerHole if sg: cDist = (sg.pd + self.pd) / 2 self.cx, self.cy = cDist * cos(self.loca), cDist * sin(self.loca) return translate([self.cx, self.cy, 0])(asm) else: self.cx, self.cy = 0, 0 return asm
def wall_brace(place1, dx1, dy1, post1, place2, dx2, dy2, post2): hulls = [] hulls.append(place1(post1)) hulls.append(place1(sl.translate(wall_locate1(dx1, dy1))(post1))) hulls.append(place1(sl.translate(wall_locate2(dx1, dy1))(post1))) hulls.append(place1(sl.translate(wall_locate3(dx1, dy1))(post1))) hulls.append(place2(post2)) hulls.append(place2(sl.translate(wall_locate1(dx2, dy2))(post2))) hulls.append(place2(sl.translate(wall_locate2(dx2, dy2))(post2))) hulls.append(place2(sl.translate(wall_locate3(dx2, dy2))(post2))) shape1 = sl.hull()(*hulls) hulls = [] hulls.append(place1(sl.translate(wall_locate2(dx1, dy1))(post1))) hulls.append(place1(sl.translate(wall_locate3(dx1, dy1))(post1))) hulls.append(place2(sl.translate(wall_locate2(dx2, dy2))(post2))) hulls.append(place2(sl.translate(wall_locate3(dx2, dy2))(post2))) shape2 = bottom_hull(hulls) return shape1 + shape2
def rounded_rect_extrude_func(prof, r, sizes): edges = [] for i in range(4): l = sizes[i % 2] tx = [0, 0, 0] if i == 0: tx[1] = -r if i == 1: tx[0] = -sizes[1] + r if i == 2: tx[0] = -sizes[1] tx[1] = -sizes[0] + r if i == 3: tx[0] = -r tx[1] = -sizes[0] edge = S.translate(tx)(S.rotate([90, 0, i * 90])( S.linear_extrude(l - r * 2)(prof))) edges.append(edge) tx2 = list(tx) if i == 0 or i == 3: tx2[0] -= r if i == 1: tx2[1] -= r if i == 2: tx2[0] += r if i == 3: tx2[1] += r tx2[0] += r edges.append( S.translate(tx2)(S.rotate([0, 0, i * 90])(S.rotate_extrude(90)( S.translate([r, 0, 0])(prof))))) obj = S.translate([sizes[1] / 2, sizes[0] / 2, 0])(S.union()(edges)) return obj
def produce_slice(lower, upper, outer_offset=0.0): res = [] step = (upper - lower) / slice_steps for i, f in enumerate(frange(lower, upper, step)): r1 = cone_at(f) r2 = cone_at(f + step) offset = i * step + outer_offset res.append( solid.translate([0, 0, offset])( solid.cylinder(h=step, r1=r1, r2=r2) ) ) return res
def profile_with_screws(p: ProfileWithScrewsParams): screw_y = p.screw_spacing + p.screw_head_radius screw_x1 = screw_y screw_x2 = p.screw_spacing * 3 + p.interface_width + p.screw_head_radius * 3 profile = roundrect([p.width, p.height], p.corner_radius) body = s.linear_extrude(p.depth)(profile) screw_holes = screws_with_padding( p.screw_radius, p.depth, p.screw_head_radius, p.screw_head_angle, p.screw_spacing, p.screws_per_side, ) return s.difference()( body, s.translate([screw_x1, screw_y, 0])(screw_holes), s.translate([screw_x2, screw_y, 0])(screw_holes), )
def screws(): """The screw holes that need to be applied to both halves""" threads = [] for x in [0, IPAD_W + WALL * 1 + SLIP * 2 + INNER_WALL * 1 + WALL_PADDING]: for y in [ 30, IPAD_H + WALL * 2 + SLIP * 2 + INNER_WALL + WALL_PADDING - 30 ]: threads.append( translate([x, y, BACK + IPAD_D / 2])(rotate([0, 90, 0])(screwthread()))) return union()(*threads)
def create_thumb_fan(): p0 = switches.get_switch_position((0, 0)) p1 = switches.get_switch_position((2, 0)) p2 = switches.get_switch_position((4, 0)) outer_cicle = utils.three_point_cicle(p0, p1, p2, radius_adjustment=0.5, segments=1000) inner_cicle = utils.three_point_cicle(p0, p1, p2, radius_adjustment=-0.5, segments=1000) ring = outer_cicle - inner_cicle # rough cut left edge ring = ring * sc.translate( (utils.big_cutter_length + p0.x - 0.5 - 2.5 * mm, 0, 0))( utils.big_cutter_square) # rough cut right edge ring = ring * sc.translate( (0, utils.big_cutter_length - 3.5, 0))(utils.big_cutter_square) # cut parallel to 1st and last switches def create_cutter(addr, left_or_right_dir): pos = switches.get_switch_position(addr) pos = Point3(*pos, 0) angle = switches.get_switch_angle(addr) cutter = switches.create_switch(addr, size=1) cutter = sc.translate(pos)(sc.scale( (4, 4, 0))(sc.translate(pos * -1)(cutter))) offset = utils.unit_point2(angle) * 2.5 * left_or_right_dir cutter = sc.translate((*offset, 0))(cutter) return cutter ring = ring - (create_cutter(Point2(0, 0), -1)) ring = ring - (create_cutter(Point2(switches.thumb_fan_size - 1, 0), 1)) return ring
def example(): """Run lab_0 example. Creates all_shapes.scad and all_shapes.dxf files. Returns: open, squarcle, and star PolyLines """ # Make an open PolyLine defined with points open_pl = PolyLine([[0,0],[0,60],[100,0],[200,0]]) # Make an OpenSCAD generator squarcle_gen = ( solid.square(50) + solid.translate([50,25])(solid.circle(25)) - solid.translate([20,15])(solid.text('S',size=20)) ) # Use the OpenSCAD generator to make a PolyLine squarcle_pl = PolyLine(generator=squarcle_gen).simplified() # Create star.dxf by saving a PolyLine star().save('star.dxf') # Load PolyLine from DXF file star_pl = PolyLine(filename='star.dxf').simplified() # Scale, translate and rotate PolyLines small_open_pl = 0.5 * open_pl trans_squarcle_pl = (0,50,0) * squarcle_pl trans_rot_star_pl = (50,175,numpy.pi/2) * star_pl # Combine the geometries and save them all_shapes = small_open_pl + trans_squarcle_pl + trans_rot_star_pl all_shapes.save('all_shapes.scad') all_shapes.save('all_shapes.dxf') return (open_pl, squarcle_pl, star_pl)