diff --git a/bottlecaps.scad b/bottlecaps.scad index cd9be58..81313c5 100644 --- a/bottlecaps.scad +++ b/bottlecaps.scad @@ -117,7 +117,7 @@ module pco1810_neck(wall=2, anchor="support-ring", spin=0, orient=UP) thread_depth=thread_h+0.1, flank_angle=flank_angle, turns=810/360, - higbee=thread_h*2, + taper=-thread_h*2, anchor=TOP ); zrot_copies(rots=[90,270]) { @@ -190,7 +190,7 @@ module pco1810_cap(wall=2, texture="none", anchor=BOTTOM, spin=0, orient=UP) } up(wall) cyl(d=cap_id, h=tamper_ring_h+wall, anchor=BOTTOM); } - up(wall+2) thread_helix(d=thread_od-thread_depth*2, pitch=thread_pitch, thread_depth=thread_depth, flank_angle=flank_angle, turns=810/360, higbee=thread_depth, internal=true, anchor=BOTTOM); + up(wall+2) thread_helix(d=thread_od-thread_depth*2, pitch=thread_pitch, thread_depth=thread_depth, flank_angle=flank_angle, turns=810/360, taper=-thread_depth, internal=true, anchor=BOTTOM); } children(); } @@ -306,7 +306,7 @@ module pco1881_neck(wall=2, anchor="support-ring", spin=0, orient=UP) thread_depth=thread_h+0.1, flank_angle=flank_angle, turns=650/360, - higbee=thread_h*2, + taper=-thread_h*2, anchor=TOP ); zrot_copies(rots=[90,270]) { @@ -371,7 +371,7 @@ module pco1881_cap(wall=2, texture="none", anchor=BOTTOM, spin=0, orient=UP) } up(wall) cyl(d=28.58, h=11.2+wall, anchor=BOTTOM); } - up(wall+2) thread_helix(d=25.5, pitch=2.7, thread_depth=1.6, flank_angle=15, turns=650/360, higbee=1.6, internal=true, anchor=BOTTOM); + up(wall+2) thread_helix(d=25.5, pitch=2.7, thread_depth=1.6, flank_angle=15, turns=650/360, taper=-1.6, internal=true, anchor=BOTTOM); } children(); } @@ -475,7 +475,7 @@ module generic_bottle_neck( thread_depth = thread_h + 0.1 * diamMagMult, flank_angle = flank_angle, turns = (height - pitch - lip_roundover_r) * .6167 / pitch, - higbee = thread_h * 2, + taper = -thread_h * 2, anchor = TOP ); zrot_copies(rots = [90, 270]) { @@ -578,7 +578,8 @@ module generic_bottle_cap( } difference(){ up(wall + pitch / 2) { - thread_helix(d = neckOuterDTol, pitch = pitch, thread_depth = threadDepth, flank_angle = flank_angle, turns = ((height - pitch) / pitch), higbee = threadDepth, internal = true, anchor = BOTTOM); + thread_helix(d = neckOuterDTol, pitch = pitch, thread_depth = threadDepth, flank_angle = flank_angle, + turns = ((height - pitch) / pitch), taper = -threadDepth, internal = true, anchor = BOTTOM); } } } @@ -1100,8 +1101,7 @@ module sp_neck(diam,type,wall,id,style="L",bead=false, anchor, spin, orient) profile = _sp_thread_profile(tpi,a,S,style); depth = a/2; - higlen = 2*a; - higang = higlen / ((T-2*depth)*PI) * 360; + taperlen = 2*a; beadmax = type==400 ? (T/2-depth)+depth*1.25 : diam <=15 ? (T-.15)/2 : (T-.05)/2; @@ -1126,7 +1126,7 @@ module sp_neck(diam,type,wall,id,style="L",bead=false, anchor, spin, orient) up((H+extra_bot)/2){ difference(){ union(){ - thread_helix(d=T-.01, profile=profile, pitch = INCH/tpi, turns=(twist+2*higang)/360, higbee=higlen, anchor=TOP); + thread_helix(d=T-.01, profile=profile, pitch = INCH/tpi, turns=twist/360, taper=taperlen, anchor=TOP); cylinder(d=T-depth*2,l=H,anchor=TOP); if (bead) down(bead_shift) @@ -1144,7 +1144,7 @@ module sp_neck(diam,type,wall,id,style="L",bead=false, anchor, spin, orient) // Module: sp_cap() // Usage: -// sp_cap(diam, type, wall, [style=], [top_adj=], [bot_adj=], [$slop]) [ATTACHMENTS]; +// sp_cap(diam, type, wall, [style=], [top_adj=], [bot_adj=], [texture=], [$slop]) [ATTACHMENTS]; // Description: // Make a SPI (Society of Plastics Industry) threaded bottle neck. You must // supply the nominal outer diameter of the threads and the thread type, one of @@ -1175,6 +1175,7 @@ module sp_neck(diam,type,wall,id,style="L",bead=false, anchor, spin, orient) // style = Either "L" or "M" to specify the thread style. Default: "L" // top_adj = Amount to reduce top space in the cap, which means it doesn't screw down as far. Default: 0 // bot_adj = Amount to reduce extension of cap at the bottom, which also means it doesn't screw down as far. Default: 0 +// texture = texture for outside of cap, one of "knurled", "ribbed" or "none. Default: "none" // $slop = Increase inner diameter by `2 * $slop`. // anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER` // spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0` @@ -1183,7 +1184,7 @@ module sp_neck(diam,type,wall,id,style="L",bead=false, anchor, spin, orient) // sp_cap(48,400,2); // sp_cap(22,410,2); // sp_cap(28,415,1.5,style="M"); -module sp_cap(diam,type,wall,style="L",top_adj=0, bot_adj=0, anchor, spin, orient) +module sp_cap(diam,type,wall,style="L",top_adj=0, bot_adj=0, texture="none", anchor, spin, orient) { table = struct_val(_sp_specs,type); dum1=assert(is_def(table),"Unknown SP closure type. Type must be one of 400, 410, or 415"); @@ -1206,20 +1207,24 @@ module sp_cap(diam,type,wall,style="L",top_adj=0, bot_adj=0, anchor, spin, orien profile = fwd(-bounds[0].y,yflip(oprofile)); depth = a/2; - higlen = 2*a; - higang = higlen / ((T-2*depth)*PI) * 360; - - echo(a=a,depth=depth,halfdepth=depth/2, tpi*pointlist_bounds(profile)); - + taperlen = 2*a; + assert(in_list(texture, ["none","knurled","ribbed"])); space=2*depth/10+2*get_slop(); attachable(anchor,spin,orient,r= (T+space)/2+wall, l=H-bot_adj+wall){ xrot(180) up((H-bot_adj)/2-wall/2){ difference(){ - up(wall)cyl(d=T+space+2*wall,l=H+wall-bot_adj,anchor=TOP,chamfer2=.8); + up(wall){ + if (texture=="knurled") + cyl(d=T+space+2*wall,l=H+wall-bot_adj,anchor=TOP,chamfer2=.8*0,texture="diamonds", tex_size=[3,3], tex_style="concave"); + else if (texture == "ribbed") + cyl(d=T+space+2*wall,l=H+wall-bot_adj,anchor=TOP,chamfer2=.8*0,texture="trunc_ribs", tex_size=[3,3], tex_style="min_edge"); + else + cyl(d=T+space+2*wall,l=H+wall-bot_adj,anchor=TOP,chamfer2=.8); + } cyl(d=T+space, l=H-bot_adj+1, anchor=TOP); } - thread_helix(d=T+space-.01, profile=profile, pitch = INCH/tpi, turns=(twist+2*higang)/360, higbee=higlen, anchor=TOP, internal=true); + thread_helix(d=T+space-.01, profile=profile, pitch = INCH/tpi, turns=twist/360, taper=taperlen, anchor=TOP, internal=true); } children(); } diff --git a/skin.scad b/skin.scad index adf4522..cfe5cd5 100644 --- a/skin.scad +++ b/skin.scad @@ -991,8 +991,8 @@ module rotate_sweep( // Function&Module: spiral_sweep() // Usage: As Module -// spiral_sweep(poly, h, r|d=, turns, [higbee=], [center=], [higbee1=], [higbee2=], [internal=], ...)[ATTACHMENTS]; -// spiral_sweep(poly, h, r1=|d1=, r2=|d2=, turns, [higbee=], [center=], [higbee1=], [higbee2=], [internal=], ...)[ATTACHMENTS]; +// spiral_sweep(poly, h, r|d=, turns, [taper=], [center=], [taper1=], [taper2=], [internal=], ...)[ATTACHMENTS]; +// spiral_sweep(poly, h, r1=|d1=, r2=|d2=, turns, [taper=], [center=], [taper1=], [taper2=], [internal=], ...)[ATTACHMENTS]; // Usage: As Function // vnf = spiral_sweep(poly, h, r|d=, turns, ...); // vnf = spiral_sweep(poly, h, r1=|d1=, r1=|d2=, turns, ...); @@ -1002,19 +1002,22 @@ module rotate_sweep( // of a given radius, height and degrees of rotation. The origin in the profile traces out the helix of the specified radius. // If turns is positive the path will be right-handed; if turns is negative the path will be left-handed. // . -// Higbee specifies tapering applied to the ends of the extrusion and is given as the linear distance -// over which to taper. +// The taper options specify tapering at of the ends of the extrusion, and are given as the linear distance +// over which to taper. If taper is positive the extrusion lengthened by the specified distance; if taper +// is negative, the taper is included in the extrusion length specified by `turns`. // Arguments: // poly = Array of points of a polygon path, to be extruded. // h = height of the spiral to extrude along. -// r = Radius of the spiral to extrude along. Default: 50 +// r = Radius of the spiral to extrude along. // turns = number of revolutions to spiral up along the height. // --- // d = Diameter of the spiral to extrude along. -// higbee = Length to taper thread ends over. -// higbee1 = Taper length at start -// higbee2 = Taper length at end -// internal = direction to taper the threads with higbee. If true threads taper outward; if false they taper inward. Default: false +// d1|r1 = Bottom inside diameter or radius of spiral to extrude along. +// d2|r2 = Top inside diameter or radius of spiral to extrude along. +// taper = Length of tapers for thread ends. Positive to add taper to threads, negative to taper within specified length. Default: 0 +// taper1 = Length of taper for bottom thread end +// taper2 = Length of taper for top thread end +// internal = if true make internal threads. The only effect this has is to change how the extrusion tapers if tapering is selected. When true, the extrusion tapers towards the outside; when false, it tapers towards the inside. Default: false // anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER` // spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0` // orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#subsection-orient). Default: `UP` @@ -1026,66 +1029,75 @@ module rotate_sweep( function _taperfunc(x) = let(higofs = pow(0.05,2)) // Smallest hig scale is the square root of this value sqrt((1-higofs)*x+higofs); -function _taperfunc(x) = +function _taperfunc_ellipse(x) = sqrt(1-(1-x)^2); function _ss_polygon_r(N,theta) = let( alpha = 360/N ) cos(alpha/2)/(cos(posmod(theta,alpha)-alpha/2)); -function spiral_sweep(poly, h, r, turns=1, higbee, center, r1, r2, d, d1, d2, higbee1, higbee2, internal=false, anchor=CENTER, spin=0, orient=UP) = +function spiral_sweep(poly, h, r, turns=1, taper, center, r1, r2, d, d1, d2, taper1, taper2, internal=false, anchor=CENTER, spin=0, orient=UP) = assert(is_num(turns) && turns != 0) let( - twist = 360*turns, - higsample = 10, // Oversample factor for higbee tapering + tapersample = 10, // Oversample factor for higbee tapering + dir = sign(turns), + r1 = get_radius(r1=r1, r=r, d1=d1, d=d, dflt=50), + r2 = get_radius(r1=r2, r=r, d1=d2, d=d, dflt=50), bounds = pointlist_bounds(poly), yctr = (bounds[0].y+bounds[1].y)/2, xmin = bounds[0].x, xmax = bounds[1].x, poly = path3d(clockwise_polygon(poly)), anchor = get_anchor(anchor,center,BOT,BOT), - r1 = get_radius(r1=r1, r=r, d1=d1, d=d, dflt=50), - r2 = get_radius(r1=r2, r=r, d1=d2, d=d, dflt=50), sides = segs(max(r1,r2)), - dir = sign(twist), - ang_step = 360/sides*dir, - orig_anglist = [for(ang = [0:ang_step:twist-EPSILON]) ang, - twist], - higbee1 = first_defined([higbee1, higbee, 0]), - higbee2 = first_defined([higbee2, higbee, 0]), - higang1 = 360 * higbee1 / (2 * r1 * PI), - higang2 = 360 * higbee2 / (2 * r2 * PI) + ang_step = 360/sides, + turns = abs(turns), + taper1 = first_defined([taper1, taper, 0]), + taper2 = first_defined([taper2, taper, 0]), + taperang1 = 360 * abs(taper1) / (2 * r1 * PI), + taperang2 = 360 * abs(taper2) / (2 * r2 * PI), + minang = taper1<=0 ? 0 : -taperang1, + tapercut1 = taper1<=0 ? taperang1 : 0, + maxang = taper2<=0 ? 360*turns : 360*turns+taperang2, + tapercut2 = taper2<=0 ? 360*turns-taperang2 : 360*turns ) - assert(higbee1>=0 && higbee2>=0) - assert(higang1 < dir*twist/2,"Higbee1 is more than half the threads") - assert(higang2 < dir*twist/2,"Higbee2 is more than half the threads") + assert( tapercut1higang1+EPSILON && (twist-a)*dir>higang2+EPSILON) a, - twist-dir*higang2, - for(a=orig_anglist) if ((twist-a)*dirtapercut1+EPSILON && atapercut2+EPSILON) a ], interp_ang = [ for(i=idx(anglist,e=-2)) each lerpn(anglist[i],anglist[i+1], - (higang1>0 && dir*anglist[i+1]<=higang1) || (higang2>0 && dir*(twist-anglist[i])<=higang2) - ? ceil((anglist[i+1]-anglist[i])/ang_step*higsample) + (taper1!=0 && anglist[i+1]<=tapercut1) || (taper2!=0 && anglist[i]>=tapercut2) + ? ceil((anglist[i+1]-anglist[i])/ang_step*tapersample) : 1, endpoint=false), last(anglist) ], + e=echo(lenlist=len(interp_ang)), skewmat = affine3d_skew_xz(xa=atan2(r2-r1,h)), points = [ for (a = interp_ang) let ( - hsc = dir*atapercut2 ? _taperfunc((maxang-a)/taperang2) : 1, - u = a/twist, + u = a/(360*turns), r = lerp(r1,r2,u), - mat = affine3d_zrot(a) - * affine3d_translate([_ss_polygon_r(sides,a)*r, 0, h * (u-0.5)]) + mat = affine3d_zrot(dir*a) + * affine3d_translate([_ss_polygon_r(sides,dir*a)*r, 0, dir*h * (u-0.5)]) * affine3d_xrot(90) * skewmat * scale([hsc,lerp(hsc,1,0.25),1], cp=[internal ? xmax : xmin, yctr, 0]), @@ -1102,12 +1114,15 @@ function spiral_sweep(poly, h, r, turns=1, higbee, center, r1, r2, d, d1, d2, hi -module spiral_sweep(poly, h, r, turns=1, higbee, center, r1, r2, d, d1, d2, higbee1, higbee2, internal=false, anchor=CENTER, spin=0, orient=UP) { - vnf = spiral_sweep(poly, h, r, turns, higbee, center, r1, r2, d, d1, d2, higbee1, higbee2, internal); +module spiral_sweep(poly, h, r, turns=1, taper, center, r1, r2, d, d1, d2, taper1, taper2, internal=false, anchor=CENTER, spin=0, orient=UP) { + vnf = spiral_sweep(poly, h, r, turns, taper, center, r1, r2, d, d1, d2, taper1, taper2, internal); r1 = get_radius(r1=r1, r=r, d1=d1, d=d, dflt=50); r2 = get_radius(r1=r2, r=r, d1=d2, d=d, dflt=50); + taper1 = first_defined([taper1,taper,0]); + taper2 = first_defined([taper2,taper,0]); + extra = PI/2*(max(0,taper1/r1)+max(0,taper2/r2)); attachable(anchor,spin,orient, r1=r1, r2=r2, l=h) { - vnf_polyhedron(vnf, convexity=ceil(abs(2*turns))); + vnf_polyhedron(vnf, convexity=ceil(2*(abs(turns)+extra))); children(); } } diff --git a/threading.scad b/threading.scad index 824be3f..a9bef17 100644 --- a/threading.scad +++ b/threading.scad @@ -1436,9 +1436,8 @@ module _nutshape(nutwidth, h, shape, bevel1, bevel2) // Module: thread_helix() // Usage: -// thread_helix(d, pitch, [thread_depth], [flank_angle], [twist], [profile=], [left_handed=], [higbee=], [internal=]); +// thread_helix(d, pitch, [thread_depth], [flank_angle], [turns], [profile=], [left_handed=], [higbee=], [internal=]); // Description: - // Creates a right-handed helical thread with optional end tapering. Unlike // {{generic_threaded_rod()}, this module just generates the thread, and you specify the total // angle of threading that you want, which makes it easy to put complete threads onto a longer @@ -1462,24 +1461,25 @@ module _nutshape(nutwidth, h, shape, bevel1, bevel2) // unlike the threaded_rod modules, thread_helix does not adjust the diameter for faceting, nor does it // subtract any $slop for clearance. // . -// The taper options specify Higbee specifies tapering applied to the ends of the threads and is given as the linear distance -// over which to taper. Tapering works on both internal and external threads. +// The taper options specify tapering at of the threads at each end, and is given as the linear distance +// over which to taper. If taper is positive the threads are lengthened by the specified distance; if taper +// is negative, the taper is included in the thread length specified by `turns`. Tapering works on both internal and external threads. // Arguments: // d = Inside base diameter of threads. Default: 10 -// pitch = Distance between threads. Default: 2mm/thread +// pitch = Distance between threads. Default: 2 // thread_depth = Depth of threads from top to bottom. // flank_angle = Angle of thread faces to plane perpendicular to screw. Default: 15 degrees. -// turns = Number of revolutions to rotate thread around. Default: 2. +// turns = Number of revolutions to rotate thread around. // --- // profile = If an asymmetrical thread profile is needed, it can be specified here. // starts = The number of thread starts. Default: 1 // left_handed = If true, thread has a left-handed winding. -// internal = If true, apply tapers for internal threading, and invert the default profile. Default: false +// internal = if true make internal threads. The only effect this has is to change how the threads taper if tapering is selected. When true, threads taper towards the outside; when false, they taper towards the inside. Default: false // d1 = Bottom inside base diameter of threads. // d2 = Top inside base diameter of threads. -// higbee = Length to taper thread ends over. Default: 0 -// higbee1 = Length to taper bottom thread end over. -// higbee2 = Length to taper top thread end over. +// taper = Length of tapers for thread ends. Positive to add taper to threads, negative to taper within specified length. Default: 0 +// taper1 = Length of taper for bottom thread end +// taper2 = Length of taper for top thread end // anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER` // spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0` // orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#subsection-orient). Default: `UP` @@ -1519,19 +1519,19 @@ module _nutshape(nutwidth, h, shape, bevel1, bevel2) // } // Examples: // thread_helix(d=10, pitch=2, thread_depth=0.75, flank_angle=15, turns=2.5, $fn=72); -// thread_helix(d=10, pitch=2, thread_depth=0.75, flank_angle=15, turns=2.5, higbee=1, $fn=72); -// thread_helix(d=10, pitch=2, thread_depth=0.75, flank_angle=15, turns=2, higbee=2, internal=true, $fn=72); -// thread_helix(d=10, pitch=2, thread_depth=0.75, flank_angle=15, turns=1, left_handed=true, higbee=1, $fn=36); +// thread_helix(d=10, pitch=2, thread_depth=0.75, flank_angle=15, turns=2.5, taper=1, $fn=72); +// thread_helix(d=10, pitch=2, thread_depth=0.75, flank_angle=15, turns=2, taper=2, internal=true, $fn=72); +// thread_helix(d=10, pitch=2, thread_depth=0.75, flank_angle=15, turns=1, left_handed=true, taper=1, $fn=36); function thread_helix( - d, pitch, thread_depth, flank_angle, turns=2, + d, pitch, thread_depth, flank_angle, turns, profile, starts=1, left_handed=false, internal=false, - d1, d2, higbee, higbee1, higbee2, + d1, d2, taper, taper1, taper2, anchor, spin, orient ) = no_function("thread_helix"); module thread_helix( d, pitch, thread_depth, flank_angle, turns=2, profile, starts=1, left_handed=false, internal=false, - d1, d2, higbee, higbee1, higbee2, + d1, d2, taper, taper1, taper2, anchor, spin, orient ) { dummy1=assert(is_undef(profile) || !any_defined([thread_depth, flank_angle]),"Cannot give thread_depth or flank_angle with a profile"); @@ -1562,7 +1562,7 @@ module thread_helix( dir = left_handed? -1 : 1; attachable(anchor,spin,orient, r1=r1, r2=r2, l=h) { zrot_copies(n=starts) { - spiral_sweep(pline, h=h, r1=r1, r2=r2, turns=turns*dir, higbee=higbee, higbee1=higbee1, higbee2=higbee2, internal=internal, anchor=CENTER); + spiral_sweep(pline, h=h, r1=r1, r2=r2, turns=turns*dir, taper=taper, taper1=taper1, taper2=taper2, internal=internal, anchor=CENTER); } children(); }