From 6da612f7e6ae2ed1f87c2b654aed2dc893cac15a Mon Sep 17 00:00:00 2001 From: Adrian Mariano Date: Mon, 23 Aug 2021 23:03:25 -0400 Subject: [PATCH] Fixed higbee=0 problem in spiral_sweep, cleaned up thread_helix. Made spiral sweep force its input to be clockwise to avoid reversed polyhedra. Changed thread_angle in thread_helix to flank_angle, which is the correct term for this angle, and then propagated change in bottlecap.scad. --- bottlecaps.scad | 28 ++++++++++++++-------------- paths.scad | 29 ++++++++++++++++++----------- threading.scad | 46 ++++++++++++++++++++++++++++------------------ 3 files changed, 60 insertions(+), 43 deletions(-) diff --git a/bottlecaps.scad b/bottlecaps.scad index fb83a0f2..89bd3e97 100644 --- a/bottlecaps.scad +++ b/bottlecaps.scad @@ -53,7 +53,7 @@ module pco1810_neck(wall=2, anchor="support-ring", spin=0, orient=UP) tamper_base_h = 14.10; threadbase_d = 24.51; thread_pitch = 3.18; - thread_angle = 20; + flank_angle = 20; thread_od = 27.43; lip_d = 25.07; lip_h = 1.70; @@ -113,7 +113,7 @@ module pco1810_neck(wall=2, anchor="support-ring", spin=0, orient=UP) d=threadbase_d-0.1, pitch=thread_pitch, thread_depth=thread_h+0.1, - thread_angle=thread_angle, + flank_angle=flank_angle, twist=810, higbee=thread_h*2, anchor=TOP @@ -164,7 +164,7 @@ module pco1810_cap(wall=2, texture="none", anchor=BOTTOM, spin=0, orient=UP) cap_id = 28.58; tamper_ring_h = 14.10; thread_pitch = 3.18; - thread_angle = 20; + flank_angle = 20; thread_od = cap_id; thread_depth = 1.6; @@ -192,7 +192,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, thread_angle=thread_angle, twist=810, 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, twist=810, higbee=thread_depth, internal=true, anchor=BOTTOM); } children(); } @@ -246,7 +246,7 @@ module pco1881_neck(wall=2, anchor="support-ring", spin=0, orient=UP) tamper_divot_r = 1.08; threadbase_d = 24.20; thread_pitch = 2.70; - thread_angle = 15; + flank_angle = 15; thread_od = 27.4; lip_d = 25.07; lip_h = 1.70; @@ -306,7 +306,7 @@ module pco1881_neck(wall=2, anchor="support-ring", spin=0, orient=UP) d=threadbase_d-0.1, pitch=thread_pitch, thread_depth=thread_h+0.1, - thread_angle=thread_angle, + flank_angle=flank_angle, twist=650, higbee=thread_h*2, anchor=TOP @@ -376,7 +376,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, thread_angle=15, twist=650, 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, twist=650, higbee=1.6, internal=true, anchor=BOTTOM); } children(); } @@ -428,7 +428,7 @@ module generic_bottle_neck( neck_d = neck_d; supp_d = max(neck_d, support_d); thread_pitch = pitch; - thread_angle = 15; + flank_angle = 15; diamMagMult = neck_d / 26.19; heightMagMult = height / 17.00; @@ -478,7 +478,7 @@ module generic_bottle_neck( d = threadbase_d - 0.1 * diamMagMult, pitch = thread_pitch, thread_depth = thread_h + 0.1 * diamMagMult, - thread_angle = thread_angle, + flank_angle = flank_angle, twist = 360 * (height - pitch - lip_roundover_r) * .6167 / pitch, higbee = thread_h * 2, anchor = TOP @@ -527,7 +527,7 @@ function generic_bottle_neck( // thread_od = Outer diameter of the threads in mm. // tolerance = Extra space to add to the outer diameter of threads and neck in mm. Applied to radius. // neck_od = Outer diameter of neck in mm. -// thread_angle = Angle of taper on threads. +// flank_angle = Angle of taper on threads. // pitch = Thread pitch in mm. // anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#anchor). Default: `CENTER` // spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#spin). Default: `0` @@ -545,7 +545,7 @@ module generic_bottle_cap( thread_od = 28.58, tolerance = .2, neck_od = 25.5, - thread_angle = 15, + flank_angle = 15, pitch = 4, anchor = BOTTOM, spin = 0, @@ -587,7 +587,7 @@ module generic_bottle_cap( } difference(){ up(wall + pitch / 2) { - thread_helix(d = neckOuterDTol, pitch = pitch, thread_depth = threadDepth, thread_angle = thread_angle, twist = 360 * ((height - pitch) / pitch), higbee = threadDepth, internal = true, anchor = BOTTOM); + thread_helix(d = neckOuterDTol, pitch = pitch, thread_depth = threadDepth, flank_angle = flank_angle, twist = 360 * ((height - pitch) / pitch), higbee = threadDepth, internal = true, anchor = BOTTOM); } } } @@ -598,7 +598,7 @@ module generic_bottle_cap( function generic_bottle_cap( wall, texture, height, thread_od, tolerance, - neck_od, thread_angle, pitch, + neck_od, flank_angle, pitch, anchor, spin, orient ) = no_function("generic_bottle_cap"); @@ -689,7 +689,7 @@ module bottle_adapter_neck_to_cap( thread_od = cap_thread_od, tolerance = tolerance, neck_od = cap_neck_od, - thread_angle = cap_thread_taper, + flank_angle = cap_thread_taper, orient = DOWN, pitch = cap_thread_pitch ); diff --git a/paths.scad b/paths.scad index 8522a7ae..d43640f1 100644 --- a/paths.scad +++ b/paths.scad @@ -1030,8 +1030,11 @@ module extrude_from_to(pt1, pt2, convexity, twist, scale, slices) { // Module: spiral_sweep() // Description: -// Takes a closed 2D polygon path, centered on the XY plane, and sweeps/extrudes it along a 3D spiral path. -// of a given radius, height and twist. +// Takes a closed 2D polygon path, centered on the XY plane, and sweeps/extrudes it along a right-handed 3D spiral path +// of a given radius, height and twist. The origin in the profile traces out the helix of the specified radius. +// . +// Higbee specifies tapering applied to the ends of the extrusion and is given as the linear distance +// over which to taper. // Arguments: // poly = Array of points of a polygon path, to be extruded. // h = height of the spiral to extrude along. @@ -1055,7 +1058,7 @@ module spiral_sweep(poly, h, r, twist=360, higbee, center, r1, r2, d, d1, d2, hi yctr = (bounds[0].y+bounds[1].y)/2; xmin = bounds[0].x; xmax = bounds[1].x; - poly = path3d(poly); + 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); @@ -1063,17 +1066,19 @@ module spiral_sweep(poly, h, r, twist=360, higbee, center, r1, r2, d, d1, d2, hi steps = ceil(sides*(twist/360)); higbee1 = first_defined([higbee1, higbee, 0]); higbee2 = first_defined([higbee2, higbee, 0]); + assert(higbee1>=0 && higbee2>=0); higang1 = 360 * higbee1 / (2 * r1 * PI); higang2 = 360 * higbee2 / (2 * r2 * PI); higsteps1 = ceil(higang1/360*sides); higsteps2 = ceil(higang2/360*sides); + assert(twist>0); assert(higang1 < twist/2); assert(higang2 < twist/2); function higsize(a) = lookup(a,[ - [-0.001, 0], - for (x=[0.125:0.125:1]) [ x*higang1, pow(x,1/2)], - for (x=[0.125:0.125:1]) [twist-x*higang2, pow(x,1/2)], - [twist+0.001, 0] + [-0.001, higang1>0?0:1], + if (higang1>0) for (x=[0.125:0.125:1]) [ x*higang1, pow(x,1/2)], + if (higang2>0) for (x=[0.125:0.125:1]) [twist-x*higang2, pow(x,1/2)], + [twist+0.001, higang2>0?0:1] ]); us = [ @@ -1089,11 +1094,13 @@ module spiral_sweep(poly, h, r, twist=360, higbee, center, r1, r2, d, d1, d2, hi u = p / steps, a = twist * u, hsc = higsize(a), + r = lerp(r1,r2,u), + mat = affine3d_zrot(a) * affine3d_translate([r, 0, h * (u-0.5)]) * affine3d_xrot(90) * - affine3d_skew_xz(xa=zang) * + affine3d_skew_xz(xa=zang) * //affine3d_scale([hsc,lerp(hsc,1,0.25),1]), scale([hsc,lerp(hsc,1,0.25),1], cp=[internal ? xmax : xmin, yctr, 0]), pts = apply(mat, poly) @@ -1101,12 +1108,12 @@ module spiral_sweep(poly, h, r, twist=360, higbee, center, r1, r2, d, d1, d2, hi ]; vnf = vnf_vertex_array( - points, col_wrap=true, caps=true, reverse=true, - style=(abs(higbee1)+abs(higbee2))>0? "quincunx" : "alt" + points, col_wrap=true, caps=true, reverse=true, + style=higbee1>0 || higbee2>0 ? "quincunx" : "alt" ); attachable(anchor,spin,orient, r1=r1, r2=r2, l=h) { - vnf_polyhedron(vnf, convexity=2*twist/360); + vnf_polyhedron(vnf, convexity=ceil(2*twist/360)); children(); } } diff --git a/threading.scad b/threading.scad index 1466f466..a39624ea 100644 --- a/threading.scad +++ b/threading.scad @@ -15,7 +15,9 @@ // For specific thread types use other modules that supply the appropriate profile. // . // You give the profile as a 2D path that will be scaled by the pitch to produce the final thread shape. The profile X values -// must be between -1/2 and 1/2. The Y value is 0 at the peak and, due to scaling by the pitch, `-depth/pitch` in the valleys. The segment between the end +// must be between -1/2 and 1/2. The Y=0 point will align with the specified rod diameter, so generally you want a Y value of zero at the peak (which +// makes your specified diameter the outer diameter of the threads). +// The value in the valleys of the thread should then be `-depth/pitch` due to the scaling by the thread pitch. The segment between the end // of one thread and the start of the next is added automatically, so you should not have the path start and end at equivalent points (X = ±1/2 with the same Y value). // Generally you should center the profile horizontally in the interval [-1/2, 1/2]. // . @@ -99,7 +101,6 @@ module generic_threaded_rod( _r1 = r1 * rsc + islop; _r2 = r2 * rsc + islop; threads = quantup(l/pitch+2,1); // Was quantup(1/pitch+2,2*starts); - echo(threads=threads); dir = left_handed? -1 : 1; twist = 360 * l / pitch / starts; higang1 = first_defined([higbee1, higbee, 0]); @@ -141,7 +142,6 @@ module generic_threaded_rod( : (higang2==0 && tang>=0)? 1 : lookup(tang, hig_table), higscale = yscale(hsc,cp = -pdepth) // Scale for higbee - //,eff=echo(tang=tang, twist=twist) ) // The right movement finds the position of the thread along // what will be the z axis after the profile is mapped to 3d @@ -261,7 +261,6 @@ module generic_threaded_nut( slope = (id2-id1)/h; full_id1 = id1-slope*extra/2; full_id2 = id2+slope*extra/2; - echo(id1=full_id1,id2=full_id2); bevel1 = first_defined([bevel1,bevel,false]); bevel2 = first_defined([bevel2,bevel,false]); dummy1 = assert(is_num(pitch) && pitch>0); @@ -288,14 +287,21 @@ module generic_threaded_nut( // Module: thread_helix() // Usage: -// thread_helix(d, pitch, thread_depth, [thread_angle], [twist], [profile=], [left_handed=], [higbee=], [internal=]); +// thread_helix(d, pitch, [thread_depth], [flank_angle], [twist], [profile=], [left_handed=], [higbee=], [internal=]); // Description: -// Creates a helical thread with optional end tapering. +// Creates a right-handed helical thread with optional end tapering. You can specify a thread_depth and flank_angle, in which +// case you get a symmetric trapezoidal thread, whose base is at the diameter (so the total diameter will be d + thread_depth). +// Atlernatively you can give a profile, following the same rules as for general_threaded_rod. +// The Y=0 point will align with the specified diameter, and the profile should +// range in X from -1/2 to 1/2. You cannot specify both the profile and the thread_depth or flank_angle. +// . +// Higbee specifies tapering applied to the ends of the extrusion and is given as the linear distance +// over which to taper. // Arguments: // d = Inside base diameter of threads. Default: 10 // pitch = Distance between threads. Default: 2mm/thread // thread_depth = Depth of threads from top to bottom. -// thread_angle = Angle of the thread faces. Default: 15 degrees. +// flank_angle = Angle of thread faces to plane perpendicular to screw. Default: 15 degrees. // twist = Number of degrees to rotate thread around. Default: 720 degrees. // --- // profile = If an asymmetrical thread profile is needed, it can be specified here. @@ -321,35 +327,39 @@ module generic_threaded_nut( // ]; // stroke(profile, width=0.02); // Example: -// thread_helix(d=10, pitch=2, thread_depth=0.75, thread_angle=15, twist=900, $fn=72); +// thread_helix(d=10, pitch=2, thread_depth=0.75, flank_angle=15, twist=900, $fn=72); module thread_helix( - d, pitch=2, thread_depth, thread_angle=15, twist=720, + d, pitch, thread_depth, flank_angle, twist=720, profile, starts=1, left_handed=false, internal=false, d1, d2, higbee, higbee1, higbee2, anchor, spin, orient ) { + dummy1=assert(is_undef(profile) || !any_defined([thread_depth, flank_angle]),"Cannot give thread_depth or flank_angle with a profile"); h = pitch*starts*twist/360; r1 = get_radius(d1=d1, d=d, dflt=10); r2 = get_radius(d1=d2, d=d, dflt=10); - tdp = thread_depth / pitch; - dz = tdp * tan(thread_angle); - cap = (1 - 2*dz)/2; - profile = !is_undef(profile)? profile : ( - internal? [ + profile = is_def(profile) ? profile : + let( + tdp = thread_depth / pitch, + dz = tdp * tan(flank_angle), + cap = (1 - 2*dz)/2 + ) + internal? + [ [-cap/2-dz, tdp], [-cap/2, 0 ], [+cap/2, 0 ], [+cap/2+dz, tdp], - ] : [ + ] + : + [ [+cap/2+dz, 0 ], [+cap/2, tdp], [-cap/2, tdp], [-cap/2-dz, 0 ], - ] - ); + ]; pline = mirror([-1,1], p = profile * pitch); dir = left_handed? -1 : 1; - idir = internal? -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, twist=twist*dir, higbee=higbee, higbee1=higbee1, higbee2=higbee2, internal=internal, anchor=CENTER);