def thumb_tl_place(shape): shape = sl.rotate(10, [1, 0, 0])(shape) shape = sl.rotate(-23, [0, 1, 0])(shape) shape = sl.rotate(10, [0, 0, 1])(shape) shape = sl.translate(thumborigin())(shape) shape = sl.translate([-32, -15, -2])(shape) return shape
def arc(rad:float, start_degrees:float, end_degrees:float, segments:int=None) -> OpenSCADObject: # Note: the circle that this arc is drawn from gets segments, # not the arc itself. That means a quarter-circle arc will # have segments/4 segments. bottom_half_square = back(rad)(square([3 * rad, 2 * rad], center=True)) top_half_square = forward(rad)(square([3 * rad, 2 * rad], center=True)) start_shape = circle(rad, segments=segments) if abs((end_degrees - start_degrees) % 360) <= 180: end_angle = end_degrees - 180 ret = difference()( start_shape, rotate(a=start_degrees)(bottom_half_square.copy()), rotate(a=end_angle)(bottom_half_square.copy()) ) else: ret = intersection()( start_shape, union()( rotate(a=start_degrees)(top_half_square.copy()), rotate(a=end_degrees)(bottom_half_square.copy()) ) ) return ret
def thumb_mr_place(shape): shape = sl.rotate(-6, [1, 0, 0])(shape) shape = sl.rotate(-34, [0, 1, 0])(shape) shape = sl.rotate(48, [0, 0, 1])(shape) shape = sl.translate(thumborigin())(shape) shape = sl.translate([-29, -40, -13])(shape) return shape
def control_box(wall_length, wall_width, wall_height): max_board_thickness = max(pro_micro.board_thickness, distribution_board.board_thickness) board_surface_pos = max(20 + wall_thickness - wall_length, 5) case_length = (board_surface_pos + max_board_thickness + 3 + wall_thickness) case_width = (pro_micro.board_length + distribution_board.board_length + 3 * wall_thickness) board_offset_forward = (board_surface_pos + max_board_thickness - case_length / 2) def position_control_box(part): """Position the control box on the final model.""" #return left(case_width / 2)( return left(wall_width / 4 - case_width / 2)(forward( (wall_length + case_length) / 2)(up(wall_height / 2)(part))) def position_controller(part): """Position the controller board within the control box.""" return forward(board_offset_forward)( left(case_width / 2 - wall_thickness + wall_thickness / 4)(rotate( (90, -90, 0))(part))) def position_distribution_board(part): """Position the distribution board within the control box.""" return forward(board_offset_forward)( right(case_width / 2 - wall_thickness + wall_thickness / 4)(rotate( (90, 90, 0))(part))) center_post_length = max_board_thickness + 3 center_post_offset_right = (case_width / 2 - wall_thickness * 1.5 - distribution_board.board_length) inner = (down(wall_thickness / 2 + 1)(back(wall_thickness + 1)(cube( ( case_width - 2 * wall_thickness, case_length + 2, wall_height - wall_thickness + 1, ), center=True, ))) + rotate( (90, 0, 0))(right(center_post_offset_right)(cylinder_outer(4.5, 100)))) case = position_control_box( cube((case_width, case_length, wall_height), center=True) - inner # Center post (between the two boards): + forward(board_surface_pos - case_length / 2 + center_post_length / 2) (right(center_post_offset_right) (cube((wall_thickness * 2, center_post_length, wall_height), center=True) - rotate((90, 0, 0)) (cylinder_outer(m2_shaft_radius, center_post_length)))) - position_controller(pro_micro.board_profile(0)) - position_distribution_board(distribution_board.board_profile(0))) cutout = position_control_box(inner) return (case, cutout)
def 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 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 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 thumb_tr_place(shape): shape = sl.rotate(10, [1, 0, 0])(shape) shape = sl.rotate(-23, [0, 1, 0])(shape) shape = sl.rotate(10, [0, 0, 1])(shape) shape = sl.translate(thumborigin())(shape) shape = sl.translate([-12, -16, 3])(shape) return shape
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 cage_stabilizer(assemble=False): """stabilizer with 3 clamps for HolMOS-cage""" cage_base = 30 stabilizer_base = base.rods30_dist_third_rod stabilizer_height = 10 angle = -atan(cage_base / 2 / stabilizer_base) / math.pi * 180 stabilizer = translate((0, stabilizer_base / 2, 0))(cube( (cage_base + 4, stabilizer_base - 10, stabilizer_height), center=True)) stabilizer -= translate((-cage_base, stabilizer_base / 2, 0))(rotate( (0, 0, angle))(cube( (cage_base, stabilizer_base, 2 * stabilizer_height), center=True))) stabilizer -= translate((cage_base, stabilizer_base / 2, 0))(rotate( (0, 0, -angle))(cube( (cage_base, stabilizer_base, 2 * stabilizer_height), center=True))) stabilizer = translate((0, -25, 0))(stabilizer) for (dd, y) in ((25, 0), (10, 21)): stabilizer -= translate((0, y, 0))(cylinder(d=dd, h=20, center=True)) stabilizer += cage_3_clips() return stabilizer
def volume(): width = light.mount_width + 20. body = sp.hull()( spu.up(1.)(sp.cube((width, thickness, 2.), center=True)), spu.up(height)( sp.rotate((0., 90., 0.))( sp.cylinder(d=thickness, h=width, center=True) ) ), ) cutout = spu.up(height)( sp.rotate((0., 90., 0.))( sp.union()( sp.cylinder( d=thickness + 1., h=light.mount_width + 1., center=True ), sp.cylinder(d=light.mount_diameter, h=width + 1., center=True), ) ) ) mounting_holes = sp.linear_extrude(15.)(holes()) return body - cutout - mounting_holes()
def rounded_cube(size, corner_radius, segments=None, center=False): if isinstance(corner_radius, (int, float)): corner_radius = XYZ( (corner_radius, corner_radius, corner_radius, corner_radius), (corner_radius, corner_radius, corner_radius, corner_radius), (corner_radius, corner_radius, corner_radius, corner_radius), ) else: corner_radius = XYZ(*corner_radius) if isinstance(size, (int, float)): size = XYZ(size, size, size) else: size = XYZ(*size) shapex = linear_extrude(size.x)(rounded_rectangle(XY(size.z, size.y), corner_radius.z, segments)) shapex = rotate((0, 90, 0))(shapex) shapex = translate(XYZ(0, 0, size.z))(shapex) shapey = linear_extrude(size.y)(rounded_rectangle(XY(size.x, size.z), corner_radius.y, segments)) shapey = rotate((90, 0, 0))(shapey) shapey = translate(XYZ(0, size.y, 0))(shapey) shapez = linear_extrude(size.z)(rounded_rectangle(XY(size.x, size.y), corner_radius.x, segments)) rc = intersection()(shapex, shapey, shapez) return rc
def cage_side_stabilizer(): """stabilizer for both sides of new HolMOS-Cage""" sep_z = 100 sep_x = base.rods30_diag_third_rod strut_width = 10 strut_thick = 3 diagonal = (sep_x**2 + sep_z**2)**.5 strut_angle_deg = numpy.rad2deg(numpy.arctan(sep_x / sep_z)) # angle < 45° diag_strut = rounded_plate( (strut_width, diagonal + strut_width, strut_thick), strut_width / 2) cross = rotate((0, 0, -strut_angle_deg))(diag_strut) cross += rotate((0, 0, strut_angle_deg))(diag_strut) cross = translate((0, 0, -strut_thick / 2))(cross) # to z=0...-thick, mount_strut = cube((sep_x, strut_width, strut_thick), center=True) mount_strut = translate( (0, 0, -strut_thick / 2))(mount_strut) # to z=0...-thick, mount_strut += rotate((-90, 0, 0))(translate((0, 20, 0))(base.base_rods30( rod_sep=sep_x))) # from optical-axis coords to our coords. cross += translate((0, sep_z / 2, 0))(mount_strut) cross += translate((0, -sep_z / 2, 0))(mount_strut) return cross
def rotate_into(v1, v2): v1n = np.array(v1) v1l = np.sqrt(v1n.dot(v1n)) if v1l < 1.0E-9: return solid.rotate(0.0) v1n /= v1l v2n = np.array(v2) v2l = np.sqrt(v2n.dot(v2n)) if v2l < 1.0E-9: return solid.rotate(0.0) v2n /= v2l v3 = np.cross(v1n, v2n) l = np.sqrt(v3.dot(v3)) if l < 1.0E-9: if v1.dot(v2) > 0: return solid.rotate(0.0) else: for i in range(3): rot_axis = np.zeros(3) rot_axis[0] = 1.0 if np.abs(rot_axis.dot(v1)) > 1.0E-6: break v_parallel = rot_axis.dot(v1) v1n = v1 / np.sqrt(v1.dot(v1)) rot_axis -= v1n * v1n.dot(rot_axis) return solid.rotate(180.0, rot_axis) cosang = v1n.dot(v2n) ang = np.arccos(cosang) return solid.rotate(ang * 180.0 / np.pi, v=v3)
def thumb_ml_place(shape): shape = sl.rotate(6, [1, 0, 0])(shape) shape = sl.rotate(-34, [0, 1, 0])(shape) shape = sl.rotate(40, [0, 0, 1])(shape) shape = sl.translate(thumborigin())(shape) shape = sl.translate([-51, -25, -12])(shape) return shape
def thumb_bl_place(shape): shape = sl.rotate(-4, [1, 0, 0])(shape) shape = sl.rotate(-35, [0, 1, 0])(shape) shape = sl.rotate(52, [0, 0, 1])(shape) shape = sl.translate(thumborigin())(shape) shape = sl.translate([-56.3, -43.3, -23.5])(shape) return shape
def thumb_br_place(shape): shape = sl.rotate(-16, [1, 0, 0])(shape) shape = sl.rotate(-33, [0, 1, 0])(shape) shape = sl.rotate(54, [0, 0, 1])(shape) shape = sl.translate(thumborigin())(shape) shape = sl.translate([-37.8, -55.3, -25.3])(shape) return shape
def cherry_stem(rotate: float = 0, inset: float = 0, length: float = 4.4, depth: float = 4, height: float = 25, horiz_thickness: float = 1.3, vert_thickness: float = 1.3, border_width: float = 2.1, border_height: float = 1.0, border_length: float = 1.1, shape: callable = rounded_rectangle, chamfer_connector: bool = True) -> s.OpenSCADObject: """ a stem to connect keycap to a cherry mx switch refactored from key.scad in https://www.thingiverse.com/thing:2289371 """ base = shape([length + border_width, length + border_height, height], radius=.5, shape=s.sphere, center=True) cross = s.translate([0, 0, depth / 2 + inset])(s.union()( leg([length + border_width, horiz_thickness, depth]), s.rotate([0, 0, 90])(leg([length, vert_thickness, depth])))) out = s.difference()(base, cross) out = s.rotate([0, 0, rotate])(out) return out
def part(variant='', configuration='', debug=False): tmp = sp.cylinder(d=F_d, h=dim10) tmp += sp.translate([0, 0, dim10])(bseat()) thread = chamfers.mcad_chamfered_cylinder(dim17, internal=False)( threads.metric_thread(diameter=T_d, pitch=T_p, length=dim17, internal=False, clearance=T_c), chamfers.mcad_chamfer_cylinder(T_d, T_p + 0.25, angle=None, depth=None, internal=False)) tmp += sp.translate([0, 0, dim17 + B_h + dim10])(sp.rotate([180, 0, 0])(thread)) tmp += sp.rotate([180, 0, 0])(sp.translate([0, 0, -0.2])( sp.import_("../aux/Ender_3_spool_holder/" + "Ender3_Spool_Holder_Coupling.stl"))) pn = curved_text.mcad_cylinder_text(diameter=F_d - 2 * PN_d, t=_code_name + _version + variant, depth=PN_d + 0.001, size=PN_s, font="Open Sans:style=Bold", halign="center", valign="bottom", spacing=1, direction="ccw") tmp -= sp.translate([0, 0, dim10 / 2 - PN_s / 2])(pn) if debug: tmp += assembly.connector(BEARING_CONN) return tmp
def grooves(cube_size, diagonal=False, doubled=False, turnout=False): groove = groove_cylinder(cube_size) if diagonal: groove = rotate(-45)(groove) short_offset = 0.5 * (cube_size / 2 - GROOVE_OFFSET) long_offset = 0.5 * (cube_size / 2 + GROOVE_OFFSET) if turnout: x_offsets = [2 * short_offset - long_offset, long_offset] y_offsets = [long_offset, long_offset] else: x_offsets = y_offsets = [short_offset, long_offset] else: x_offsets = [0, 0] y_offsets = [-GROOVE_OFFSET, GROOVE_OFFSET] groove_pair = union()([ right(x_offset)(forward(y_offset)(groove)) for x_offset, y_offset in zip(x_offsets, y_offsets) ]) if turnout: limiting_block = forward(cube_size + GROOVE_OFFSET)(cube( [2 * cube_size, 2 * cube_size, 2 * cube_size], center=True)) groove_pair *= limiting_block if doubled: groove_pair += rotate(180, [0, 0, 1])(groove_pair) return groove_pair
def orient_relative(self, **kw): ''' This returns a function which produces a transformation (translation+rotation) of scadObj1 so that: (1) u_vec1 becomes parallel to u_vec2, (2) the projection of v_vec1_prime onto the plane perpendicular to u_vec is rotated with respect to the projection of v_vec2 onto that plane by azimuth_deg, and (3) origin1 is translated into origin2. ''' scadObj1 = kw['obj1'] scadObj2 = kw['obj2'] origin1 = kw['point1'] origin2 = kw['point2'] u_vec1 = kw['align_vec1'] u_vec2 = kw['align_vec2'] do_azimuth = False if 'azimuth_vec1' in kw and 'azimuth_vec2' in kw: v_vec1 = kw['azimuth_vec1'] v_vec2 = kw['azimuth_vec2'] do_azimuth = True azimuth_deg = kw.get('azimuth_deg', 0.0) u_vec1 = np.array(u_vec1) u_vec2 = np.array(u_vec2) trans1 = solid.translate(-origin1) rot1 = rotate_into(u_vec1, u_vec2) mx1 = rotate_into_mx(u_vec1, u_vec2) if do_azimuth: v_vec1 = np.array(v_vec1) v_vec2 = np.array(v_vec2) v_vec1_prime = mx1 @ v_vec1 u_vec_norm = u_vec2 / np.sqrt(u_vec2.dot(u_vec2)) v_vec1_perp_u = v_vec1_prime - u_vec_norm * u_vec_norm.dot( v_vec1_prime) l = np.sqrt(v_vec1_perp_u.dot(v_vec1_perp_u)) if l < 1.0E-9: raise Exception('v_vec1 appears to be parallel to u_vec1!') v = v_vec1_perp_u / l v_vec2_perp_u = v_vec2 - u_vec_norm * u_vec_norm.dot(v_vec1_prime) l = np.sqrt(v_vec2_perp_u.dot(v_vec2_perp_u)) if l < 1.0E-9: raise Exception('v_vec2 appears to be parallel to u_vec2!') x = v_vec2_perp_u / l z = u_vec_norm y = np.cross(z, x) x_comp = x.dot(v) y_comp = y.dot(v) current_azimuth_radians = np.arctan2(y_comp, x_comp) rotate_angle_deg = azimuth_deg - current_azimuth_radians * 180 / np.pi rot2 = solid.rotate(rotate_angle_deg, v=z) else: rot2 = solid.rotate(0.0) trans2 = solid.translate(origin2) transformation = lambda o: trans2(rot2(rot1(trans1(o)))) return transformation
def ff_rotate(a=None, b=None, c=None): if a is None and b is None and c is None: return solid.rotate(0, 0, 0) if (isinstance(a, (float, int)) and isinstance(b, (float, int)) and isinstance(c, (float, int))): return solid.rotate([a, b, c]) else: return solid.rotate(a=a, v=b)
def volume(angle_multiplier): return sp.difference()( sp.union()( sp.rotate((0., angle_multiplier * 90., 180.))(axle()), sp.rotate((0., angle_multiplier * camber, 0.))(bearing_housing()), ), sp.rotate((0., angle_multiplier * camber, 0.))(kingpin_hole()), )
def hJoint (right, out, name): female = out # Create the outer cylinder j = solid.rotate(a = [-90, 0, 0])\ (solid.cylinder(r=outerD/2, h=width, segments = 20)) j = solid.translate(v = [0, 0, outerD/2])(j) # Create the clamp j = j + solid.cube([outerD,width,border]) j = j + solid.translate([0, 0, border+thick])\ (solid.cube([outerD,width,border])) j = j - solid.translate(v = [0, 0, border])(solid.cube([outerD,width,thick+2*t])) # Create the center hole c = solid.rotate(a = [90, 0, 0])\ (solid.cylinder(r=innerD/2,center=True, h=2*width, segments=20)) if female: if (right and out) or (not right and not out): off = -(width-6) else: off = width-6 c = solid.translate(v = [0, width/2+off, outerD/2])(c) else: c = solid.translate(v = [0, width/2, outerD/2])(c) j = solid.difference()(j, c) if not female: if (right and out) or (not right and not out): off = -border else: off = border c = solid.rotate(a = [90, 0, 0])\ (solid.cylinder(r=(outerD)/2-border,center=True, h=width, segments = 20)) c = solid.translate(v = [0, width/2+off, outerD/2])(c) cube = solid.cube([outerD, width, 2*border+thick]) c = solid.difference()(c, \ solid.translate(v = [-outerD/2.0, 0, 0])(cube)) j = solid.difference()(j, c) # Create bolt holes j = solid.difference()(j, solid.translate(v=[.65*outerD, width/2, 0]) (solid.cylinder(r=bolt/2, h = outerD, segments = 20))) j = solid.difference()(j, solid.translate(v=[.85*outerD, width/2, 0]) (solid.cylinder(r=bolt/2, h = outerD, segments = 20))) # Support bar # j = j + solid.translate(v = [-thick,0,border])(solid.cube([thick, width, thick+2*t])) # Move and rotate j = solid.translate(v=[0, 0, -border])(j) if right: j = solid.translate(v=[width, 0, 0])(solid.rotate(a=[0, 0, 90])(j)) j = PolyMesh(generator=j) j.save("heliodon/joint" + name + ".stl") return j
def cyl_arc_lt_180(r, h, a0, a1): # centered arc section of cylinder, for angles up to 180deg positive_y_plane = translate([0, 2 * r, 0])(cube([4 * r, 4 * r, 2 * h], center=True)) result = cylinder(r, h, center=True) result *= positive_y_plane # keep 0...180 result = rotate([0, 0, -(a1 - a0)])(result) result -= positive_y_plane # keep 0...a1-a0 return rotate([0, 0, a1])(result)
def volume(): body = sp.union()(sp.rotate( (0, 180, 0))(sp.cylinder(d=wheel.inner_hole_diameter, h=a_length)), sp.cylinder(d=b_diameter, h=b_length), sp.cylinder(d=c_diameter, h=b_length + c_length)) axle = sp.cylinder(d=axle_diameter, h=200., center=True) return sp.rotate((0, 90, 0))(body - axle - wheel.mounting_holes())
def rotate_about_y(self, degree): for idx in range(len(self.vertices)): self.vertices[idx] = self.rotate_around_y(self.vertices[idx], degree) self.origin = self.rotate_around_y(self.origin, degree) self.shape = sl.rotate(degree, [0, 1, 0])(self.shape) if self.cap is not None: self.cap = sl.rotate(degree, [0, 1, 0])(self.cap) self.rotations.append(Rotation(degree, [0,1,0]))
def volume(): body = spu.up(2.)(sp.cylinder(d=diameter, h=thickness)) mount = spu.up(4.)(spu.back(diameter / 2.)(sp.rotate( (-60., 0., 0.))(sp.rotate((0., 90., 0.))(sp.hull()(place_at_centres( (20., 0.), sp.cylinder(d=mount_thickness, h=mount_width, center=True) )) - spu.right(10.)(sp.cylinder( d=mount_diameter, h=mount_width + 1., center=True)))))) return body + mount
def thumb(side="right"): # shape = thumb_1x_layout(single_plate(side=side)) # shape += thumb_15x_layout(single_plate(side=side)) # shape += thumb_15x_layout(double_plate()) shape = thumb_1x_layout(sl.rotate([0.0, 0.0, -90])(single_plate(side=side))) shape += thumb_15x_layout(sl.rotate([0.0, 0.0, -90])(single_plate(side=side))) shape += thumb_15x_layout(double_plate()) return shape
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 arc_inverted(rad: float, start_degrees: float, end_degrees: float, segments: int = None) -> OpenSCADObject: # Return the segment of an arc *outside* the circle of radius rad, # bounded by two tangents to the circle. This is the shape # needed for fillets. # Note: the circle that this arc is drawn from gets segments, # not the arc itself. That means a quarter-circle arc will # have segments/4 segments. # Leave the portion of a circumscribed square of sides # 2*rad that is NOT in the arc behind. This is most useful for 90-degree # segments, since it's what you'll add to create fillets and take away # to create rounds. # NOTE: an inverted arc is only valid for end_degrees-start_degrees <= 180. # If this isn't true, end_degrees and start_degrees will be swapped so # that an acute angle can be found. end_degrees-start_degrees == 180 # will yield a long rectangle of width 2*radius, since the tangent lines # will be parallel and never meet. # Fix start/end degrees as needed; find a way to make an acute angle if end_degrees < start_degrees: end_degrees += 360 if end_degrees - start_degrees >= 180: start_degrees, end_degrees = end_degrees, start_degrees # We want the area bounded by: # -- the circle from start_degrees to end_degrees # -- line tangent to the circle at start_degrees # -- line tangent to the circle at end_degrees # Note that this shape is only valid if end_degrees - start_degrees < 180, # since if the two angles differ by more than 180 degrees, # the tangent lines don't converge if end_degrees - start_degrees == 180: raise ValueError("Unable to draw inverted arc over 180 or more " "degrees. start_degrees: %s end_degrees: %s" % (start_degrees, end_degrees)) wide = 1000 high = 1000 top_half_square = translate((-(wide - rad), 0, 0))(square([wide, high], center=False)) bottom_half_square = translate( (-(wide - rad), -high, 0))(square([wide, high], center=False)) a = rotate(start_degrees)(top_half_square) b = rotate(end_degrees)(bottom_half_square) ret = (a * b) - circle(rad, segments=segments) return ret
def sizedipad(x, y, height): """Returns an iPad x,y size, with fixed size corners""" o = hull()( (ipadcorner(height)), translate([0, y, 0])(rotate([0, 0, -90])((ipadcorner(height)))), translate([x, y, 0])(rotate([0, 0, 180])((ipadcorner(height)))), translate([x, 0, 0])(rotate([0, 0, 90])((ipadcorner(height)))), translate([15, 15, 0])(cube([x - 30, y - 30, height])), ) return o
def create(i): obj = objects[i] obj = sc.rotate((0, 0, tilt_angle))(obj) obj = sc.rotate((90, 0, 0))(obj) facing_angle = math.degrees(i * hstep / radius) obj = sc.rotate(facing_angle + 90)(obj) hpos = utils.unit_point2(facing_angle) * radius pos = (*hpos, i * vstep) obj = sc.translate(pos)(obj) return obj
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 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 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 slice_mesh(fn="LOGOROBOT.stl", t_m=3.0): """ Return list of slices from stl modifed with through holes for alignment. Args: filename (str): STL file with 3D solid to turn into slices t_m (float): material thickness Returns: list of PolyLines that are the 2D profiles of the slices """ poly = PolyMesh(filename=fn) # custom rotation for LOGOROBOT rot = sl.rotate(-90, [1, 0, 0])(poly.get_generator()) poly = PolyMesh(generator=rot) slices = [] plane = sl.square(1000, True) axis = np.array([0, 0, 1]) # slice in Z direction (alpha_min, alpha_max) = mesh_extremum(poly, axis) for alpha in frange(alpha_min, alpha_max, t_m): norm = list(axis * alpha) slice_polyline = PolyLine(generator=plane) slice_args = (slice_polyline, norm) slice = planar_slice(poly, slice_args, t_m) slices.append(slice) return slices
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 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 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 process(outline_file, solderpaste_file, stencil_thickness=0.2, include_ledge=True, ledge_height=1.2, ledge_gap=0.0, increase_hole_size_by=0.0): outline_shape = create_outline_shape(outline_file) cutout_polygon = create_cutouts(solderpaste_file, increase_hole_size_by=increase_hole_size_by) if ledge_gap: # Add a gap between the ledge and the stencil outline_shape = offset_shape(outline_shape, ledge_gap) outline_polygon = polygon(outline_shape) stencil = linear_extrude(height=stencil_thickness)(outline_polygon - cutout_polygon) if include_ledge: ledge_shape = offset_shape(outline_shape, 1.2) ledge_polygon = polygon(ledge_shape) - outline_polygon # Cut the ledge in half by taking the bounding box of the outline, cutting it in half # and removing the resulting shape from the ledge shape # We always leave the longer side of the ledge intact so we don't end up with a tiny ledge. cutter = bounding_box(ledge_shape) height = abs(cutter[1][1] - cutter[0][1]) width = abs(cutter[0][0] - cutter[3][0]) if width > height: cutter[1][1] -= height/2 cutter[2][1] -= height/2 else: cutter[2][0] -= width/2 cutter[3][0] -= width/2 ledge_polygon = ledge_polygon - polygon(cutter) ledge = utils.down( ledge_height - stencil_thickness )( linear_extrude(height=ledge_height)(ledge_polygon) ) stencil = ledge + stencil # Rotate the stencil to make it printable stencil = rotate(a=180, v=[1, 0, 0])(stencil) return scad_render(stencil)
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 rationalize_planar_solids(solids, tf_xyz_rpy, offset): """ Args: List of solids modified for joinery Returns: List of PolyLines projected from solids, offset for laser kerf """ final_list = [] # reverse the transformation, then call layout for (p, r) in zip(solids, tf_xyz_rpy): translation, rotation = r # create reverse translation *= -1 rotation *= -1 solid_p = p.get_generator() translated_p = sl.translate(translation)(solid_p) rotated_p = sl.rotate(rotation)(translated_p) p_2d = sl.projection(rotated_p) polyline = PolyLine(generator=p_2d) offset = offset_polygon(polyline, solid) final_list.append(offset) return final_list
comment='Radius of hole to fix screw length.', end_comment='[2:4.5]') v.screw_radius = s.var(2, comment='Radius of screw thread.', end_comment='[1:4.5]') v.screw_length = s.var(10, comment='Length of thread to be inside spacer.', end_comment='[3:45]') v.head_hole_height = s.var('spacer_height - screw_length') body = s.cube(size=[spacer_depth, spacer_width, v.spacer_height]) slot = u.up(3)(s.cube(size=[spacer_depth, 10, 2])) slot_round = u.back(1)(u.up(2)( s.rotate(a=v.spacer_height, v=[1, 0, 0])( s.cube(size=[spacer_depth, 4, 4]) ) )) screw_hole = u.forward(5)( s.cylinder(r=v.screw_head_radius, h=v.head_hole_height, segments=32) + u.up(v.head_hole_height)( s.cylinder(r=v.screw_radius, h=v.screw_length, segments=32) ) ) screw_hole_1 = u.right(screw_offset)(screw_hole) screw_hole_2 = u.right(screw_offset_2)(screw_hole) wire_run = u.up(20)(s.cube(size=[spacer_depth, 4, 9]))
legs = join_list([leg1, leg2, leg3, leg4]) legs = solid.color([0,0,0])(legs) table = solid.cube([length,width,thick]) table -= solid.translate([depth+3,-1,3])(solid.cube([length+1-depth ,width+2,thick-6])) table -= solid.translate([-1,3,3])(solid.cube([depth,width-6,thick-6])) table = solid.translate([0,0,clearance])(table) table = solid.color(t55_to_1([140,80,33]))(table) mid = solid.translate([length-20,width/2,clearance])(solid.color([0,0,0])(solid.cylinder(r=5,h=thick-1))) glass = solid.translate([0,0,clearance+thick])(solid.color([1,1,1,.3])(solid.cube([length,width,3]))) drawer = solid.cube([depth,width-6, thick-7 ]) drawer -= solid.translate([1,1,1])(solid.cube([depth-2, width-8, thick-5])) drawer += solid.cube([2,width-6, thick-6]) handle, theth, rh = circle_arch(30, 7, 2) handle = solid.translate([13,width/2-3, thick/2-3])(solid.rotate([0,0,90+45])(handle)) drawer+= handle drawer = solid.translate([-10,3,clearance+3])(solid.color([.1,.1,.9])(drawer)) fake_me = solid.translate([-50,-10,0])(mannequin()) object = [fake_me, table+legs, mid, glass, drawer] print>>out_file, solid.scad_render(join_list(object))
### new subroutines ### out_file = make_output() rcling = 5 rbutt = 20 rail1 = solid.utils.arc( rad = rcling, start_degrees = 0, end_degrees = 180) rail1 -= solid.utils.arc( rad = rcling-1, start_degrees = 0, end_degrees = 180) rail2= solid.translate([0,0,6])(rail1) rail3 = solid.translate([0,0,6])(rail2) rails = solid.translate([0,0,4])(join_list([rail1,rail2, rail3])) rails += solid.translate([1,-.5,0])(solid.cube([4,1,20])) rails = solid.translate([30,20,-rcling+2])((solid.rotate([90,90,0])(rails))) rails = solid.color([0,0,0])(rails) buttress1 = solid.utils.arc( rad = rbutt, start_degrees = 0, end_degrees = 90) buttress1 -= solid.utils.arc( rad = rbutt-3, start_degrees = 0, end_degrees = 180) buttress1 += solid.translate([0,rbutt-2, -1.5])(solid.cube([rbutt, 2,3])) buttress2 = solid.translate([0,0,10])(buttress1) buttresses = buttress1 + buttress2 buttresses = solid.rotate([-90,-90,0])(solid.translate([0,0,5])(buttresses)) buttresses = solid.translate([30-rbutt-5,0,-rbutt+2])(buttresses) buttresses = solid.color([0,0,.8])(buttresses) board = solid.color([.4,.4,.4])(solid.cube([30,20,2])) object = [board, rails, buttresses]
''' light measurements 123 cm long 15 cm wide 5 cm tall 1:30 slope, or 6 degree slant. ''' light = solid.cube([5,15,123])- solid.translate([1,1,1])(solid.cube([5,13,121])) light = solid.color([.4,.4,.4])(light) tube1 = solid.color([1,1,1])(solid.translate([4,4,1])(solid.cylinder(r=2, h=121))) tube2 = solid.translate([0,6,0])(tube1) trough = solid.color([.4,.4,.4])(solid.translate([15,-2.5,0])(solid.cube([10,20,123]))) trough -= solid.translate([16,-1.5,-1])(solid.cube([8,18,125])) thole = solid.translate([14,7.5,10])(solid.rotate([0,90,0])(solid.cylinder(r=8, h = 5) )) tslots = [] for i in range(6): tslots += [solid.translate([0,0,i*18])(thole)] trough -= solid.translate([0,0,7])(join_list(tslots)) bucket = solid.translate([22.5,7.5,10])(solid.rotate([0,-90,0])(splanter())) bslots = [] for i in range(6): bslots += [solid.translate([0,0,i*18])(bucket)] planters = join_list(bslots) planters = solid.translate([0,0,7])(planters) object = [trough, light, tube1, tube2, planters]
### ''' components and thoughts solid base to place books on solid back to prevent things falling behind it sides and roof are tiled in hexagons spaces to save on material 4 columns topped in a circular arch to bear most of the weight. ''' out_file = make_output() bord = 2 side = hexfield(4, bord, 4, 50, 50) side = solid.cube([40,30,2])-side frame = solid.cube([40,30,2])-solid.translate([2,2,-1])(solid.cube([36,26,4])) side = side + frame side2 =solid.rotate([0,-90,0])(side) side = solid.translate([30,0,0])(solid.rotate([0,-90,0])(side)) sides = solid.color([.1,.1,.9])(side+side2) base = solid.translate([-2,0,-2])(solid.cube([32,30,2])) top = solid.translate([0,0,40])(base) back = solid.translate([0,28,0])(solid.cube([28,2,38])) panels = solid.color([.25,.25,.15])(base+top+back) support1 = solid.rotate([0,-90,90])(ssupport()) support2 = solid.translate([0,7,0])(support1) support1 = solid.translate([0,21,0])(support1) supports = solid.color([.8, .1, .8])(support1 + support2) cubby = join_list([sides, panels, supports])
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)
def path_render3D(self, pconfig, border=False): global _delta, PRECISION, SCALEUP self.rotations_to_3D() config={} config=self.overwrite(config,pconfig) inherited = self.get_config() # if('transformations' in config): config=self.overwrite(config, inherited) if border==False and 'zoffset' in pconfig: zoffset= pconfig['zoffset'] elif 'zoffset' in config and config['zoffset']: zoffset= config['zoffset'] else: zoffset = 0 if 'thickness' not in config: config['thickness']=pconfig['thickness'] if config['z0'] is None or config['z0'] is False: z0=0 else: z0=config['z0'] if border==False: z0 += 1 if (config['z1'] is False or config['z1'] is None) and config['z0'] is not None and config['thickness'] is not None: if border==False: z1 = - config['thickness']- 20 else: z1 = - config['thickness'] else: z1= config['z1'] z0 *=config['zdir'] z1*=config['zdir'] # z0 = - config['thickness'] - z0 # z1 = - config['thickness'] - z1 # try to avoid faces and points touching by offsetting them slightly z0+=_delta z1-=_delta _delta+=0.00001 outline = [] points = self.polygonise(RESOLUTION) # extrude_path = [ Point3(0,0,zoffset + float(z0)), Point3(0,0, zoffset + float(z1)) ] for p in points: outline.append( [round(p[0],PRECISION)*SCALEUP, round(p[1],PRECISION)*SCALEUP ]) outline.append([round(points[0][0],PRECISION)*SCALEUP, round(points[0][1],PRECISION)*SCALEUP]) # outline.append( Point3(p[0], p[1], p[2] )) # outline.append( Point3(points[0][0], points[0][1], points[0][2] )) h = round(abs(z1-z0),PRECISION)*SCALEUP bottom = round((min(z1,z0)+zoffset),PRECISION) *SCALEUP # extruded = extrude_along_path(shape_pts=outline, path_pts=extrude_path) if self.extrude_scale is not None: scale = self.extrude_scale if self.extrude_centre is None: self.extrude_centre = V(0,0) centre = (PSharp(V(0,0)).point_transform(config['transformations']).pos+self.extrude_centre) centre = [centre[0], centre[1]] uncentre = [-centre[0], -centre[1]] extruded = solid.translate([0,0,bottom])( solid.translate(centre)( solid.linear_extrude(height=h, center=False, scale = scale)( solid.translate(uncentre)(solid.polygon(points=outline))))) else: scale = 1 extruded = solid.translate([0,0,bottom])(solid.linear_extrude(height=h, center=False)(solid.polygon(points=outline))) #extruded = translate([0,0,bottom])(linear_extrude(height=h, center=False)(solid.polygon(points=outline))) # if 'isback' in config and config['isback'] and border==False: # extruded = mirror([1,0,0])(extruded ) if 'colour' in config and config['colour']: extruded = solid.color(self.scad_colour(config['colour']))(extruded) if hasattr(self, 'transform') and self.transform is not None and self.transform is not False and 'matrix3D' in self.transform: if type(self.transform['matrix3D'][0]) is list: extruded=solid.translate([-self.transform['rotate3D'][1][0], - self.transform['rotate3D'][1][1]])(extruded) extruded=solid.multmatrix(m=self.transform['matrix3D'][0])(extruded) extruded=solid.translate([self.transform['rotate3D'][1][0], self.transform['rotate3D'][1][1]])(extruded) else: extruded=solid.multmatrix(m=self.transform['matrix3D'])(extruded) if hasattr(self, 'transform') and self.transform is not None and self.transform is not False and 'rotate3D' in self.transform: if type(self.transform['rotate3D'][0]) is list: print [-self.transform['rotate3D'][1][0], - self.transform['rotate3D'][1][1], - self.transform['rotate3D'][1][2]- zoffset] extruded=solid.translate([-self.transform['rotate3D'][1][0], - self.transform['rotate3D'][1][1], - self.transform['rotate3D'][1][2]- zoffset])(extruded) extruded=solid.rotate([self.transform['rotate3D'][0][0], self.transform['rotate3D'][0][1],self.transform['rotate3D'][0][2] ])(extruded) extruded=solid.translate([self.transform['rotate3D'][1][0], self.transform['rotate3D'][1][1], self.transform['rotate3D'][1][1] + zoffset])(extruded) else: extruded=solid.rotate([self.transform['rotate3D'][0], self.transform['rotate3D'][1],self.transform['rotate3D'][2] ])(extruded) if hasattr(self, 'transform') and self.transform is not None and self.transform is not False and 'translate3D' in self.transform: extruded=solid.translate([self.transform['translate3D'][0], self.transform['translate3D'][1],self.transform['translate3D'][2] ])(extruded) return [extruded]
''' light measurements 123 cm long 15 cm wide 5 cm tall 1:30 slope, or 6 degree slant. ''' light = solid.cube([5,15,123])- solid.translate([1,1,1])(solid.cube([5,13,121])) light = solid.color([.4,.4,.4])(light) tube1 = solid.color([1,1,1])(solid.translate([4,4,1])(solid.cylinder(r=2, h=121))) tube2 = solid.translate([0,6,0])(tube1) trough = solid.color([.4,.4,.4])(solid.translate([15,-2.5,0])(solid.cube([10,20,123]))) trough -= solid.translate([16,-1.5,-1])(solid.cube([8,18,125])) thole = solid.translate([14,7.5,10])(solid.rotate([0,90,0])(solid.cylinder(r=8, h = 5) )) tslots = [] for i in range(6): tslots += [solid.translate([0,0,i*18])(thole)] trough -= solid.translate([0,0,7])(join_list(tslots)) bucket = solid.translate([22.5,7.5,10])(solid.rotate([0,-90,0])(splanter())) bslots = [] for i in range(6): bslots += [solid.translate([0,0,i*18])(bucket)] planters = join_list(bslots) planters = solid.translate([0,0,7])(planters) waterout = solid.cube([10, 20,10])-solid.translate([1,1,-1])(solid.cube([10, 18,10])) waterin = solid.translate([10,0,0])(solid.rotate([0,180,0])(waterout))
bolt_z = height / 2.0 bolt1_y = bolt_from_edge - outer_rad bolt2_y = square_width + outer_rad - bolt_from_edge bolt_base1_y = (bolt_base_dia / 2.0) - outer_rad bolt_base2_y = square_width + outer_rad - (bolt_base_dia / 2.0) bolt_base_depth = depth * 0.66 # rotation of bolt base to merge into the side bolt_base_angle = math.degrees(math.atan2( bolt_base_depth, bolt_base_dia / 2.0)) hnt = nt / 2.0 # half nested tolerance # body centre body = s.cube(size=[depth, square_width, height]) # body round edge 1 body += u.up(outer_rad)(s.rotate(a=[0, 90, 0])( s.cylinder(r=outer_rad, h=depth, segments=segments) )) # body round edge 2 body += u.forward(square_width)(u.up(outer_rad)(s.rotate(a=[0, 90, 0])( s.cylinder(r=outer_rad, h=depth, segments=segments) ))) # inner to subtract from the body for the body inner = s.cube( size=[depth - wall_width, square_width, height - walls_width] ) inner += u.up(inner_rad)(s.rotate(a=[0, 90, 0])( s.cylinder(r=inner_rad, h=depth - wall_width, segments=segments) )) inner += u.forward(square_width)(u.up(inner_rad)( s.rotate(a=[0, 90, 0])(
### ''' heights 0-1, base 1-4, lighting 5-6 floor/pane 7-top, chamber ''' out_file = make_output() orange = t55_to_1([255,127,0]) battery = solid.color([1,0,0])(solid.cylinder(r=1,h=3)) battery += solid.color([0,0,0])(solid.translate([0,0,3])(solid.cylinder(r=1,h=3))) battery = solid.translate([11,2,2])(solid.rotate([0,90,0])(battery)) led = solid.cylinder(r=1,h=1, segments = 20) led += solid.translate([0,0,1])(solid.sphere(r=1, segments= 20)) wire = solid.cube([.2,.2,1]) led += solid.translate([-.1,.8,-1])(wire)+ solid.translate([-.1,-1,-1])(wire) led = solid.color(orange)(led) led2 = solid.translate([5,3,1.5])(led) led = solid.translate([9,3,1.5])(led) vessel = solid.cube([20,7,15])- solid.translate([1,1,1])(solid.cube([18,5,15])) vessel -= solid.translate([1,-1,6])(solid.cube([18,3,10])) vessel -= solid.translate([.5,.25,5.5])(solid.cube([19,.5,10])) vessel -= solid.translate([1,1,1])(solid.cube([20,5,3])) vessel -= solid.translate([.5,.5, 5.25])(solid.cube([20,6,.5])) vessel = solid.color([0,.5,9])(vessel)