diff --git a/screw_drive.scad b/screw_drive.scad index 642df16..67b6213 100644 --- a/screw_drive.scad +++ b/screw_drive.scad @@ -168,7 +168,7 @@ function hex_drive_mask(size,length,l,h,height,anchor,spin,orient) = no_function // See Also: phillips_mask(), hex_drive_mask(), torx_mask(), phillips_depth(), phillips_diam(), robertson_mask() // Usage: // torx_mask(size, l, [center]) [ATTACHMENTS]; -// Description: Creates a torx bit tip. +// Description: Creates a torx bit tip. The anchors are located on the circumscribing cylinder. See {{torx_info()}} for allowed sizes. // Arguments: // size = Torx size. // l = Length of bit. @@ -191,7 +191,6 @@ module torx_mask(size, l=5, center, anchor, spin=0, orient=UP) { } - // Module: torx_mask2d() // Synopsis: Creates the 2D cross section for a torx drive recess. // SynTags: Geom @@ -199,13 +198,12 @@ module torx_mask(size, l=5, center, anchor, spin=0, orient=UP) { // See Also: phillips_mask(), hex_drive_mask(), torx_mask(), phillips_depth(), phillips_diam(), torx_info(), robertson_mask() // Usage: // torx_mask2d(size); -// Description: Creates a torx bit 2D profile. +// Description: Creates a torx bit 2D profile. The anchors are located on the circumscribing circle. See {{torx_info()}} for allowed sizes. // Arguments: // size = Torx size. // Example(2D): // torx_mask2d(size=30, $fa=1, $fs=1); -module torx_mask2d(size) { - no_children($children); +module torx_mask2d(size,anchor=CENTER,spin) { info = torx_info(size); od = info[0]; id = info[1]; @@ -213,26 +211,29 @@ module torx_mask2d(size) { rounding = info[4]; base = od - 2*tip; $fn = quantup(segs(od/2),12); - difference() { - union() { - circle(d=base); - zrot_copies(n=2) { - hull() { - zrot_copies(n=3) { - translate([base/2,0,0]) { - circle(r=tip, $fn=$fn/2); + attachable(anchor,spin,two_d=true,d=od){ + difference() { + union() { + circle(d=base); + zrot_copies(n=2) { + hull() { + zrot_copies(n=3) { + translate([base/2,0,0]) { + circle(r=tip, $fn=$fn/2); + } } } } } - } - zrot_copies(n=6) { - zrot(180/6) { - translate([id/2+rounding,0,0]) { - circle(r=rounding); + zrot_copies(n=6) { + zrot(180/6) { + translate([id/2+rounding,0,0]) { + circle(r=rounding); + } } } } + children(); } } @@ -251,6 +252,10 @@ module torx_mask2d(size) { // - Drive Hole Depth // - External Tip Rounding Radius // - Inner Rounding Radius +// . +// The allowed torx sizes are: +// 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 27, 30, 40, 45, 50, 55, +// 60, 70, 80, 90, 100. // Arguments: // size = Torx size. function torx_info(size) = @@ -333,6 +338,11 @@ function torx_depth(size) = torx_info(size)[2]; // ang = taper angle of each face. Default: 2.5 // --- // $slop = enlarge recess by this twice amount. Default: 0 +// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: TOP +// 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` +// Side Effects: +// Sets tag to "remove" if no tag is set. // Example: // robertson_mask(size=2); // Example: @@ -340,7 +350,7 @@ function torx_depth(size) = torx_info(size)[2]; // cyl(d1=2, d2=8, h=4, anchor=TOP); // robertson_mask(size=2); // } -module robertson_mask(size, extra=1, ang=2.5) { +module robertson_mask(size, extra=1, ang=2.5,anchor=TOP,spin,orient) { dummy=assert(is_int(size) && size>=0 && size<=4); Mmin = [0.0696, 0.0900, 0.1110, 0.1315, 0.1895][size]; Mmax = [0.0710, 0.0910, 0.1126, 0.1330, 0.1910][size]; @@ -353,14 +363,18 @@ module robertson_mask(size, extra=1, ang=2.5) { F = (Fmin + Fmax) / 2 * INCH; h = T + extra; Mslop=M+2*get_slop(); - down(T) { - intersection(){ - Mtop = Mslop + 2*adj_ang_to_opp(F+extra,ang); - Mbot = Mslop - 2*adj_ang_to_opp(T-F,ang); - prismoid([Mbot,Mbot],[Mtop,Mtop],h=h,anchor=BOT); - cyl(d1=0, d2=Mslop/(T-F)*sqrt(2)*h, h=h, anchor=BOT); - } - } + Mtop = Mslop + 2*adj_ang_to_opp(F+extra,ang); + Mbot = Mslop - 2*adj_ang_to_opp(T-F,ang); + anchors = [named_anchor("standard",[0,0,T-h/2], UP, 0)]; + default_tag("remove") + attachable(anchor,spin,orient,size=[Mbot,Mbot,T],size2=[Mtop,Mtop],anchors=anchors){ + down(T/2) + intersection(){ + prismoid([Mbot,Mbot],[Mtop,Mtop],h=h,anchor=BOT); + cyl(d1=0, d2=Mslop/(T-F)*sqrt(2)*h, h=h, anchor=BOT); + } + children(); + } } diff --git a/screws.scad b/screws.scad index 7a564ba..089eec5 100644 --- a/screws.scad +++ b/screws.scad @@ -1442,63 +1442,68 @@ module screw_head(screw_info,details=false, counterbore=0,flat_height,teardrop=f counterbore = counterbore_temp==0 && head!="flat" ? counterbore_temp : counterbore_temp + 0.01; adj_diam = struct_val(screw_info, "diameter") + head_oversize; // Used for determining chamfers and ribbing - if (head!="flat" && counterbore>0){ - d = head=="hex"? 2*head_size/sqrt(3) : head_size; - if (teardrop) - teardrop(d=d, l=counterbore, orient=BACK, anchor=BACK); - else - cyl(d=d, l=counterbore, anchor=BOTTOM); - } - if (head=="flat") { // For flat head, counterbore is integrated - angle = struct_val(screw_info, "head_angle")/2; - sharpsize = struct_val(screw_info, "head_size_sharp")+head_oversize; - sidewall_height = (sharpsize - head_size)/2 / tan(angle); - cylheight = counterbore + sidewall_height; - slopeheight = flat_height - sidewall_height; - r1 = head_size/2; - r2 = r1 - tan(angle)*slopeheight; - n = segs(r1); - prof1 = teardrop ? teardrop2d(r=r1,$fn=n) : circle(r=r1, $fn=n); - prof2 = teardrop ? teardrop2d(r=r2,$fn=n) : circle(r=r2, $fn=n); - skin([prof2,prof1,prof1], z=[-flat_height, -flat_height+slopeheight, counterbore],slices=0); - } - if (head!="flat" && counterbore==0) { - if (in_list(head,["round","pan round","button","fillister","cheese"])) { - base = head=="fillister" ? 0.75*head_height : - head=="pan round" ? .6 * head_height : - head=="cheese" ? .7 * head_height : - 0.1 * head_height; // round and button - head_size2 = head=="cheese" ? head_size-2*tan(5)*head_height : head_size; // 5 deg slope on cheese head - segs = segs(head_size); - cyl(l=base, d1=head_size, d2=head_size2,anchor=BOTTOM, $fn=segs) - attach(TOP) - zrot(180) // Needed to align facets when $fn is odd - rotate_extrude($fn=segs) // ensure same number of segments for cap as for head body - intersection(){ - arc(points=[[-head_size2/2,0], [0,-base+head_height * (head=="button"?4/3:1)], [head_size2/2,0]]); - square([head_size2, head_height-base]); + attachable(){ + union(){ + if (head!="flat" && counterbore>0){ + d = head=="hex"? 2*head_size/sqrt(3) : head_size; + if (teardrop) + teardrop(d=d, l=counterbore, orient=BACK, anchor=BACK); + else + cyl(d=d, l=counterbore, anchor=BOTTOM); + } + if (head=="flat") { // For flat head, counterbore is integrated + angle = struct_val(screw_info, "head_angle")/2; + sharpsize = struct_val(screw_info, "head_size_sharp")+head_oversize; + sidewall_height = (sharpsize - head_size)/2 / tan(angle); + cylheight = counterbore + sidewall_height; + slopeheight = flat_height - sidewall_height; + r1 = head_size/2; + r2 = r1 - tan(angle)*slopeheight; + n = segs(r1); + prof1 = teardrop ? teardrop2d(r=r1,$fn=n) : circle(r=r1, $fn=n); + prof2 = teardrop ? teardrop2d(r=r2,$fn=n) : circle(r=r2, $fn=n); + skin([prof2,prof1,prof1], z=[-flat_height, -flat_height+slopeheight, counterbore],slices=0); + } + if (head!="flat" && counterbore==0) { + if (in_list(head,["round","pan round","button","fillister","cheese"])) { + base = head=="fillister" ? 0.75*head_height : + head=="pan round" ? .6 * head_height : + head=="cheese" ? .7 * head_height : + 0.1 * head_height; // round and button + head_size2 = head=="cheese" ? head_size-2*tan(5)*head_height : head_size; // 5 deg slope on cheese head + segs = segs(head_size); + cyl(l=base, d1=head_size, d2=head_size2,anchor=BOTTOM, $fn=segs) + attach(TOP) + zrot(180) // Needed to align facets when $fn is odd + rotate_extrude($fn=segs) // ensure same number of segments for cap as for head body + intersection(){ + arc(points=[[-head_size2/2,0], [0,-base+head_height * (head=="button"?4/3:1)], [head_size2/2,0]]); + square([head_size2, head_height-base]); + } + } + if (head=="pan flat") + cyl(l=head_height, d=head_size, rounding2=0.2*head_size, anchor=BOTTOM); + if (head=="socket") + cyl(l=head_height, d=head_size, anchor=BOTTOM, chamfer2=details? adj_diam/10:undef); + if (head=="socket ribbed"){ + // These numbers are based on ISO specifications that dictate how much oversizsed a ribbed socket head can be + // We are making our ribbed heads the same size as unribbed (by cutting the ribbing away), but these numbers are presumably a good guide + rib_size = [[2, .09], + [3, .09], + [6, .11], + [12, .135], + [20, .165]]; + intersection() { + cyl(h=head_height/4, d=head_size, anchor=BOT) + attach(TOP) cyl(l=head_height*3/4, d=head_size, anchor=BOT, texture="trunc_ribs", tex_counts=[31,1], tex_scale=-lookup(adj_diam,rib_size)); + cyl(h=head_height,d=head_size, chamfer2=adj_diam/10, anchor=BOT); } - } - if (head=="pan flat") - cyl(l=head_height, d=head_size, rounding2=0.2*head_size, anchor=BOTTOM); - if (head=="socket") - cyl(l=head_height, d=head_size, anchor=BOTTOM, chamfer2=details? adj_diam/10:undef); - if (head=="socket ribbed"){ - // These numbers are based on ISO specifications that dictate how much oversizsed a ribbed socket head can be - // We are making our ribbed heads the same size as unribbed (by cutting the ribbing away), but these numbers are presumably a good guide - rib_size = [[2, .09], - [3, .09], - [6, .11], - [12, .135], - [20, .165]]; - intersection() { - cyl(h=head_height/4, d=head_size, anchor=BOT) - attach(TOP) cyl(l=head_height*3/4, d=head_size, anchor=BOT, texture="trunc_ribs", tex_counts=[31,1], tex_scale=-lookup(adj_diam,rib_size)); - cyl(h=head_height,d=head_size, chamfer2=adj_diam/10, anchor=BOT); - } - } - if (head=="hex") - up(head_height/2)_nutshape(head_size,head_height,"hex",false,true); + } + if (head=="hex") + up(head_height/2)_nutshape(head_size,head_height,"hex",false,true); + } + } + union(){}; } }