Merge pull request #1006 from adrianVmariano/master

spiral_sweep fixes
This commit is contained in:
Revar Desmera 2022-12-14 21:04:43 -08:00 committed by GitHub
commit 1257b9b936
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 98 additions and 78 deletions

View file

@ -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,texture="trunc_pyramids", tex_size=[3,3], tex_style="convex");
else if (texture == "ribbed")
cyl(d=T+space+2*wall,l=H+wall-bot_adj,anchor=TOP,chamfer2=.8,tex_taper=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();
}

101
skin.scad
View file

@ -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( tapercut1<tapercut2 && tapercut1<maxang, "Tapers are too long to fit")
assert( all_positive([r1,r2]), "Diameter/radius must be positive")
let(
// This complicated sampling scheme is designed to ensure that there is always a facet boundary
// at the $fn specified location, regardless of what kind of subsampling occurs for tapers."
// This complicated sampling scheme is designed to ensure that faceting always starts at angle zero
// for alignment with cylinders, and there is always a facet boundary at the $fn specified locations,
// regardless of what kind of subsampling occurs for tapers.
orig_anglist = [
if (minang<0) minang,
each reverse([for(ang = [-ang_step:-ang_step:minang+EPSILON]) ang]),
for(ang = [0:ang_step:maxang-EPSILON]) ang,
maxang
],
anglist = [
for(a=orig_anglist) if (a*dir<higang1-EPSILON) a,
dir*higang1,
for(a=orig_anglist) if (a*dir>higang1+EPSILON && (twist-a)*dir>higang2+EPSILON) a,
twist-dir*higang2,
for(a=orig_anglist) if ((twist-a)*dir<higang2-EPSILON) a
for(a=orig_anglist) if (a<tapercut1-EPSILON) a,
tapercut1,
for(a=orig_anglist) if (a>tapercut1+EPSILON && a<tapercut2-EPSILON) a,
tapercut2,
for(a=orig_anglist) if (a>tapercut2+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*a<higang1 ? _taperfunc(dir*a/higang1)
: dir*(twist-a)<higang2 ? _taperfunc(dir*(twist-a)/higang2)
hsc = a<tapercut1 ? _taperfunc((a-minang)/taperang1)
: a>tapercut2 ? _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();
}
}

View file

@ -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();
}