diff --git a/skin.scad b/skin.scad index 4602441..1e7c8b6 100644 --- a/skin.scad +++ b/skin.scad @@ -1079,6 +1079,7 @@ module rotate_sweep( // poly = [[-10,0], [-3,-5], [3,-5], [10,0], [0,-30]]; // spiral_sweep(poly, h=200, r=50, turns=3, $fn=36); function _taperfunc(x) = + x>1 ? 1 : x<0 ? 0: let(higofs = pow(0.05,2)) // Smallest hig scale is the square root of this value sqrt((1-higofs)*x+higofs); function _taperfunc_ellipse(x) = @@ -1087,7 +1088,8 @@ 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, taper, center, r1, r2, d, d1, d2, taper1, taper2, internal=false, anchor=CENTER, spin=0, orient=UP) = - assert(is_num(turns) && turns != 0) + assert(is_num(turns) && turns != 0, "turns must be a nonzero number") + assert(all_positive([h]), "Spiral height must be a positive number") let( tapersample = 10, // Oversample factor for higbee tapering dir = sign(turns), @@ -1148,7 +1150,7 @@ function spiral_sweep(poly, h, r, turns=1, taper, center, r1, r2, d, d1, d2, tap u = a/(360*turns), r = lerp(r1,r2,u), mat = affine3d_zrot(dir*a) - * affine3d_translate([_ss_polygon_r(sides,dir*a)*r, 0, dir*h * (u-0.5)]) + * affine3d_translate([_ss_polygon_r(sides,dir*a)*r, 0, h * (u-0.5)]) * affine3d_xrot(90) * skewmat * scale([hsc,lerp(hsc,1,0.25),1], cp=[internal ? xmax : xmin, yctr, 0]), @@ -2637,7 +2639,7 @@ function associate_vertices(polygons, split, curpoly=0) = // Figure(3D): This is the "hexgrid" VNF tile, which creates a hexagonal grid texture, something which doesn't work well with a height field because the edges of the hexagon don't align with the grid. Note how the tile ranges between 0 and 1 in both X, Y and Z. // tex = texture("hex_grid"); // vnf_polyhedron(tex); -// Figure(3D): This is an example of a tile that has no edges at the top or bottom, so it creates disconnected rings. See below for examples showing this tile in use. +// Figure(3D): This is an example of a tile that has no edges at the top or bottom, so it creates disconnected rings. See {{linear_sweep()}} for examples showing this tile in use. // shape = skin([ // rect(2/5), // rect(2/3), diff --git a/threading.scad b/threading.scad index 0d3d1ff..7251aa3 100644 --- a/threading.scad +++ b/threading.scad @@ -1175,15 +1175,16 @@ module generic_threaded_rod( higbee2 = thigbee2==0 ? true : thigbee2; extra_thread1 = higbee1==false && internal ? 1 : 0; extra_thread2 = higbee2==false && internal ? 1 : 0; + r1 = get_radius(d1=d1, d=d); + r2 = get_radius(d1=d2, d=d); dummy0 = assert(all_positive([pitch]),"Thread pitch must be a positive value") assert(all_positive([l]),"Length must be a postive value") assert(is_path(profile),"Profile must be a path") assert(is_finite(higbee1) || is_bool(higbee1), str("higbee",is_undef(higbee)?"1":""," must be boolean or a number")) assert(is_finite(higbee2) || is_bool(higbee2), str("higbee",is_undef(higbee)?"1":""," must be boolean or a number")) - assert(is_bool(left_handed)); - r1 = get_radius(d1=d1, d=d); - r2 = get_radius(d1=d2, d=d); + assert(is_bool(left_handed)) + assert(all_positive([r1,r2]), "Must give d or both d1 and d2 as positive values"); sides = quantup(segs(max(r1,r2)), starts); rsc = internal? (1/cos(180/sides)) : 1; islop = internal? 2*get_slop() : 0; @@ -1216,6 +1217,8 @@ module generic_threaded_rod( * frame_map(x=[0,0,1], y=[1,0,0]) // Map profile to 3d, parallel to z axis * scale(pitch); // scale profile by pitch start_steps = sides / starts; + higlen = 4/32*360;//360*max(pitch/2, pmax-depth)/(2*PI*_r2); + echo(higlen=higlen); thread_verts = [ // Outer loop constructs a vertical column of the screw at each angle // covering 1/starts * 360 degrees of the cylinder. @@ -1227,14 +1230,15 @@ module generic_threaded_rod( full_profile = [ // profile for the entire rod for (thread = [-threads/2:1:threads/2-1]) let( - tang = (thread/starts) * 360 + ang, - adjusted_prof3d = tang < -twist/2+higang1 || tang > twist/2-higang2 - ? [for(v=prof3d) [v.x,internal?pmax/pitch:-pdepth,v.z]] - : prof3d + tang = thread/starts * 360 + ang, + hsc = tang < -twist/2+higang1 ? _taperfunc(1-(-twist/2+higang1-tang)/higlen ) + : tang > twist/2-higang2 ? _taperfunc(1-(tang-twist/2+higang2)/higlen ) + : 1, + higscale=scale([lerp(hsc,1,0.25),hsc,1], cp=[0,internal ? pmax/pitch:-pdepth, 0]) ) // The right movement finds the position of the thread along // what will be the z axis after the profile is mapped to 3d - each apply(right(dz + thread) , adjusted_prof3d) + each apply(right(dz + thread) * higscale, prof3d) ] ) [ @@ -1271,13 +1275,12 @@ module generic_threaded_rod( slope = (_r1-_r2)/l; maxlen = 5*pitch; - attachable(anchor,spin,orient, r1=_r1, r2=_r2, l=l) { union(){ // This method is faster but more complex code and it produces green tops difference() { vnf_polyhedron(vnf_quantize(thread_vnfs),convexity=10); - + if (!internal){ if (bevel1 || bevel2) rotate_extrude(){ @@ -1544,8 +1547,9 @@ module thread_helix( 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"); - h = pitch*starts*turns; + dummy1=assert(is_undef(profile) || !any_defined([thread_depth, flank_angle]),"Cannot give thread_depth or flank_angle with a profile") + assert(all_positive([turns]), "The turns parameter must be a positive number"); + h = pitch*starts*abs(turns); r1 = get_radius(d1=d1, d=d, dflt=10); r2 = get_radius(d1=d2, d=d, dflt=10); profile = is_def(profile) ? profile :