1//////////////////////////////////////////////////////////////////////
   2// LibFile: threading.scad
   3//   Provides generic threading support and specialized support for standard triangular (UTS/ISO) threading,
   4//   trapezoidal threading (ACME), pipe threading, buttress threading, square threading and ball screws.  
   5// Includes:
   6//   include <BOSL2/std.scad>
   7//   include <BOSL2/threading.scad>
   8// FileGroup: Threaded Parts
   9// FileSummary: Various types of threaded rods and nuts.
  10//////////////////////////////////////////////////////////////////////
  11
  12
  13// Section: Thread Ends and Options
  14//   A standard process for making machine screws is to begin with round stock that has
  15//   beveled ends.  This stock is then rolled between flat, grooved plates to form the threads.
  16//   The result is a bolt that looks like this at the end:
  17// Figure(3D,Med,NoAxes,VPR=[83.7,0,115.5],VPT=[1.37344,1.26411,-0.299415],VPD=35.5861): 
  18//   threaded_rod(d=13,pitch=2,l=10,blunt_start=false,$fn=80);
  19// Figure(2D,Med,NoAxes): A properly mated screw and bolt with beveled ends
  20//   $fn=32;
  21//   projection(cut=true)
  22//   xrot(-90){
  23//   down(2.5)difference(){
  24//     cuboid([20,20,5]);
  25//     zrot(20)
  26//     threaded_rod(d=13.2, pitch=2,l=5.1,blunt_start=false,internal=true);
  27//   }
  28//   up(2.85-2)threaded_rod(d=13, pitch=2, l=10, blunt_start=false);
  29//   
  30//   }
  31// Continues:
  32//   Cross threading occurs when the bolt is misaligned with the threads in the nut.
  33//   It can destroy the threads, or cause the nut to jam.  The standard beveled end process
  34//   makes cross threading a possibility because the beveled partial threads can pass
  35//   each other when the screw enters the nut.
  36// Figure(2D,Med,NoAxes):
  37//   $fn=32;
  38//   projection(cut=true)
  39//   xrot(-90){
  40//   down(2.5)difference(){
  41//     cuboid([20,20,5]);
  42//     zrot(20)
  43//     threaded_rod(d=13.2, pitch=2,l=5.1,blunt_start=false,internal=true);
  44//   }
  45//   left(.6)up(2.99)yrot(-atan(2/13)-1)rot(180+30)threaded_rod(d=13, pitch=2, l=10, blunt_start=false);
  46//   }
  47// Continues:
  48//   In addition, those partial screw threads may be weak, and easily broken.  They do
  49//   not contribute to the strength of the assembly.  
  50//   In 1891 Clinton A. Higbee received a patent for a modification to screw threads
  51//   https://patents.google.com/patent/US447775A meant to address these limitations.
  52//   Instead of beveling the end of the screw, Higbee said to remove the partial thread.
  53//   The resulting screw might look like this:
  54// Figure(3D,Med,NoAxes,VPR=[72,0,294],VPT=[0,0,0],VPD=44):
  55//   $fn=48;
  56//   threaded_rod(d=13,pitch=2,l=10,blunt_start=true,lead_in_shape="cut",end_len=.2);
  57// Continues:
  58//   Because the threads are complete everywhere, cross threading is unlikely to occur.
  59//   This type of threading has been called "Higbee threads", but in recent machinist
  60//   handbooks it is called "blunt start" threading.  
  61//   This style of thread is not commonly used in metal fasteners because it requires
  62//   machining the threads, which is much more costly than the rolling procedure described
  63//   above.  However, plastic threads usually have some sort of gradual thread end.
  64//   For models that will be 3D printed, there is no reason to choose the standard
  65//   bevel end bolt, so in this library the blunt start threads are the default.
  66//   If you need standard bevel-end threads, you can choose them with the `blunt_start` options.
  67//   Note that blunt start threads are more efficient.
  68//   .
  69//   Various options exist for controlling the ends of threads. You can specify bevels on threaded rods.
  70//   In conventional threading, bevels are needed on the ends to remove sharp, thin edges, and
  71//   the bevel is sized to the full outer diameter of the threaded rod.  
  72//   With blunt start threading, the bevel appears on the unthreaded part of the rod.
  73//   On a threaded rod, a bevel value of `true` or a positive bevel value cut off the corner.
  74// Figure(3D,Med,NoAxes,VPR=[72,0,54],VPT=[0,0,0],VPD=44):
  75//   threaded_rod(d=13,pitch=2,l=10,blunt_start=true,bevel=true,$fn=80);
  76// Continues:
  77//   A negative bevel value produces a flaring bevel, that might be useful if the rod needs to mate with another part.
  78//   You can also set `bevel="reverse"` to get a flaring bevel of the default size.
  79// Figure(3D,Med,NoAxes,VPR=[72,0,54],VPT=[0,0,0],VPD=44): Negative bevel on a regular threaded rod.
  80//   threaded_rod(d=13,pitch=2,l=10,blunt_start=true,bevel=-2,$fn=80);
  81// Continues:
  82//   If you set `internal=true` to create a mask for a threaded hole, then bevels are reversed: positive bevels flare outward so that when you subtract
  83//   the threaded rod it gives a beveled edge to the hole.  In this case, negative bevels go inward, which might be useful to
  84//   create a bevel at the bottom of a threaded hole.
  85// Figure(3D,Med,NoAxes,VPR=[72,0,54],VPT=[0,0,0],VPD=44): Threaded rod mask produced using `internal=true` with regular bevel at the top and reversed bevel at the bottom.  
  86//   threaded_rod(d=13,pitch=2,l=10,blunt_start=true,bevel2=true,bevel1="reverse",internal=true,$fn=80);
  87// Continues:
  88//   You can also extend the unthreaded section using the `end_len` parameters.  A long unthreaded section will make
  89//   it impossible to tilt the bolt and produce misaligned threads, so it could make assembly easier.  
  90// Figure(3D,Med,NoAxes,VPR=[72,0,54],VPT=[0,0,0],VPD=48): Negative bevel on a regular threaded rod.
  91//   threaded_rod(d=13,pitch=2,l=15,end_len2=5,blunt_start=true,bevel=true,$fn=80);
  92// Continues:
  93//   It is also possible to adjust the length of the lead-in section of threads, or the
  94//   shape of that lead-in section.  The lead-in length can be set using the `lead_in` arguments
  95//   to specify a length or the `lead_in_ang` arguments to specify an angle.  For general
  96//   threading applications, making the lead in long creates a smaller thread that could
  97//   be more fragile and more prone to cross threading.  
  98// Figure(3D,Med,NoAxes,VPR=[52,0,300],VPT=[0,0,4],VPD=35.5861):
  99//   threaded_rod(d=13,pitch=2,l=10,lead_in=6,blunt_start=true,bevel=false,$fn=80);
 100// Continues:
 101//   To change the form of the thread end you use the `lead_in_shape` argument.
 102//   You can specify "sqrt", "cut" or "smooth" shapes.  The "sqrt" shape is the historical
 103//   shape used in the library.  The "cut" shape is available to model Higbee pattern threads, but
 104//   is not as good as the others in practice, because the flat faces on the threads can hit each other.
 105//   The lead-in shape is produced by applying a scale factor to the thread cross section that varies along the lead-in length. 
 106//   You can also specify a custom shape
 107//   by giving a function literal, `f(x,L)` where `L` will be the total linear
 108//   length of the lead-in section and `x` will be a value between 0 and 1 giving
 109//   the position in the lead in, with 0 being the tip and 1 being the full height thread.
 110//   The return value must be a 2-vector giving the thread width scale and thread height
 111//   scale at that location.  If `x<0` the function must return a thread height scale
 112//   of zero, but it is usually best if the thread width scale does not go to zero,
 113//   because that will give a sharply pointed thread end.  If `x>1` the function must
 114//   return `[1,1]`.  
 115// Figure(3D,Med,NoAxes,VPR=[75,0,338],VPT=[-2,0,3.3],VPD=25): The standard lead in shapes
 116//   left_half()zrot(0){
 117//   up(2)   threaded_rod(d=13,pitch=2,l=2,blunt_start=true,bevel=false,$fn=128,anchor=BOT);
 118//   up(4)   threaded_rod(d=13,pitch=2,l=2.5,blunt_start=true,bevel=false,$fn=128,lead_in_shape="cut",end_len2=.5,anchor=BOT);
 119//      threaded_rod(d=13,pitch=2,l=2,blunt_start=true,bevel=false,$fn=128,lead_in_shape="smooth",anchor=BOT);
 120//   }
 121//   $fn=64;
 122//   s=.85;
 123//   color("black")
 124//   up(3.5)left(4.5)fwd(6)rot($vpr){
 125//      back(1.9)text3d("cut",size=s);
 126//      text3d("sqrt",size=s);
 127//      fwd(1.9)text3d("smooth",size=s);
 128//   }   
 129
 130
 131// Section: Standard (UTS/ISO) Threading
 132
 133// Module: threaded_rod()
 134// Synopsis: Creates an UTS/ISO triangular threaded rod.
 135// SynTags: Geom
 136// Topics: Threading, Screws
 137// See Also: threaded_nut()
 138// Usage:
 139//   threaded_rod(d, l|length, pitch, [internal=], ...) [ATTACHMENTS];
 140// Description:
 141//   Constructs a standard ISO (metric) or UTS (English) threaded rod.  These threads are close to triangular,
 142//   with a 60 degree thread angle.  You can give diameter value which specifies the outer diameter and will produce
 143//   the "basic form" or you can
 144//   set d to a triplet [d_min, d_pitch, d_major] where are parameters determined by the ISO and UTS specifications
 145//   that define clearance sizing for the threading.  See screws.scad for how to make screws
 146//   using the specification parameters.  
 147// Arguments:
 148//   d = Outer diameter of threaded rod, or a triplet of [d_min, d_pitch, d_major]. 
 149//   l / length / h / height = length of threaded rod.
 150//   pitch = Length between threads.
 151//   ---
 152//   left_handed = if true, create left-handed threads.  Default = false
 153//   starts = The number of lead starts.  Default: 1
 154//   bevel = if true, bevel the thread ends.  Default: false
 155//   bevel1 = if true bevel the bottom end.
 156//   bevel2 = if true bevel the top end.
 157//   internal = If true, make this a mask for making internal threads.
 158//   d1 = Bottom outside diameter of threads.
 159//   d2 = Top outside diameter of threads.
 160//   blunt_start = If true apply truncated blunt start threads at both ends.  Default: true
 161//   blunt_start1 = If true apply truncated blunt start threads bottom end.
 162//   blunt_start2 = If true apply truncated blunt start threads top end.
 163//   end_len = Specify the unthreaded length at the end after blunt start threads.  Default: 0
 164//   end_len1 = Specify unthreaded length at the bottom
 165//   end_len2 = Specify unthreaded length at the top
 166//   lead_in = Specify linear length of the lead in section of the threading with blunt start threads
 167//   lead_in1 = Specify linear length of the lead in section of the threading at the bottom with blunt start threads
 168//   lead_in2 = Specify linear length of the lead in section of the threading at the top with blunt start threads
 169//   lead_in_ang = Specify angular length in degrees of the lead in section of the threading with blunt start threads
 170//   lead_in_ang1 = Specify angular length in degrees of the lead in section of the threading at the bottom with blunt start threads
 171//   lead_in_ang2 = Specify angular length in degrees of the lead in section of the threading at the top with blunt start threads
 172//   lead_in_shape = Specify the shape of the thread lead in by giving a text string or function.  Default: "default"
 173//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
 174//   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#subsection-spin).  Default: `0`
 175//   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
 176//   $slop = The printer-specific slop value, which adds clearance (`4*$slop`) to internal threads.
 177// Example(2D):
 178//   projection(cut=true)
 179//       threaded_rod(d=10, l=15, pitch=1.5, orient=BACK);
 180// Examples(Med):
 181//   threaded_rod(d=25, height=20, pitch=2, $fa=1, $fs=1);
 182//   threaded_rod(d=10, l=20, pitch=1.25, left_handed=true, $fa=1, $fs=1);
 183//   threaded_rod(d=25, l=20, pitch=2, $fa=1, $fs=1, end_len=1.5, bevel=true);
 184//   threaded_rod(d=25, l=20, pitch=2, $fa=1, $fs=1, blunt_start=false);
 185// Example(Big,NoAxes): Diamond threading where both left-handed and right-handed nuts travel (in the same direction) on the threaded rod:
 186//   $fn=32;
 187//   $slop = 0.075;
 188//   d = 3/8*INCH;
 189//   pitch = 1/16*INCH;
 190//   starts=3;
 191//   xdistribute(19){
 192//       intersection(){
 193//         threaded_rod(l=40, pitch=pitch, d=d,starts=starts,anchor=BOTTOM,end_len=.44);
 194//         threaded_rod(l=40, pitch=pitch, d=d, left_handed=true,starts=starts,anchor=BOTTOM);
 195//       }
 196//       threaded_nut(nutwidth=4.5/8*INCH,id=d,h=3/8*INCH,pitch=pitch,starts=starts,anchor=BOTTOM);
 197//       threaded_nut(nutwidth=4.5/8*INCH,id=d,h=3/8*INCH,pitch=pitch,starts=starts,left_handed=true,anchor=BOTTOM);
 198//   }
 199function threaded_rod(
 200    d, l, pitch,
 201    left_handed=false,
 202    bevel,bevel1,bevel2,starts=1,
 203    internal=false,
 204    d1, d2, length, h, height,
 205    blunt_start, blunt_start1, blunt_start2,
 206    lead_in, lead_in1, lead_in2,
 207    lead_in_ang, lead_in_ang1, lead_in_ang2,
 208    end_len, end_len1, end_len2,
 209    lead_in_shape="default",
 210    anchor, spin, orient
 211) = no_function("threaded_rod");
 212
 213module threaded_rod(
 214    d, l, pitch,
 215    left_handed=false,
 216    bevel,bevel1,bevel2,starts=1,
 217    internal=false,
 218    d1, d2, length, h, height,
 219    blunt_start, blunt_start1, blunt_start2,
 220    lead_in, lead_in1, lead_in2,
 221    lead_in_ang, lead_in_ang1, lead_in_ang2,
 222    end_len, end_len1, end_len2,
 223    lead_in_shape="default",
 224    anchor, spin, orient
 225) {
 226    dummy1=
 227      assert(all_positive(pitch))
 228      assert(all_positive(d) || (is_undef(d) && all_positive([d1,d2])));
 229    basic = is_num(d) || is_undef(d) || is_def(d1) || is_def(d2);
 230    dummy2 = assert(basic || is_vector(d,3));
 231    depth = basic ? cos(30) * 5/8
 232                  : (d[2] - d[0])/2/pitch;
 233    crestwidth = basic ? 1/8 : 1/2 - (d[2]-d[1])/sqrt(3)/pitch;
 234    profile =    [
 235                  [-depth/sqrt(3)-crestwidth/2, -depth],
 236                  [              -crestwidth/2,      0],
 237                  [               crestwidth/2,      0],
 238                  [ depth/sqrt(3)+crestwidth/2, -depth]
 239                 ];
 240    oprofile = internal? [
 241        [-6/16, -depth],
 242        [-1/16,  0],
 243        [-1/32,  0.02],
 244        [ 1/32,  0.02],
 245        [ 1/16,  0],
 246        [ 6/16, -depth]
 247    ] : [
 248        [-7/16, -depth*1.07],
 249        [-6/16, -depth],
 250        [-1/16,  0],
 251        [ 1/16,  0],
 252        [ 6/16, -depth],
 253        [ 7/16, -depth*1.07]
 254    ];
 255    generic_threaded_rod(
 256        d=basic ? d : d[2], d1=d1, d2=d2, l=l,
 257        pitch=pitch,
 258        profile=profile,starts=starts,
 259        left_handed=left_handed,
 260        bevel=bevel,bevel1=bevel1,bevel2=bevel2,
 261        internal=internal, length=length, height=height, h=h,
 262        blunt_start=blunt_start, blunt_start1=blunt_start1, blunt_start2=blunt_start2,
 263        lead_in=lead_in, lead_in1=lead_in1, lead_in2=lead_in2, lead_in_shape=lead_in_shape,
 264        lead_in_ang=lead_in_ang, lead_in_ang1=lead_in_ang1, lead_in_ang2=lead_in_ang2,
 265        end_len=end_len, end_len1=end_len1, end_len2=end_len2,
 266        anchor=anchor,
 267        spin=spin,
 268        orient=orient
 269    ) children();
 270}
 271
 272
 273
 274// Module: threaded_nut()
 275// Synopsis: Creates an UTS/ISO triangular threaded nut.
 276// SynTags: Geom
 277// Topics: Threading, Screws
 278// See Also: threaded_rod()
 279// Usage:
 280//   threaded_nut(nutwidth, id, h|height|thickness, pitch,...) [ATTACHMENTS];
 281// Description:
 282//   Constructs a hex nut or square nut for an ISO (metric) or UTS (English) threaded rod.
 283//   The inner diameter is measured from the bottom of the threads.  
 284// Arguments:
 285//   nutwidth = flat to flat width of nut
 286//   id = inner diameter of threaded hole, measured from bottom of threads
 287//   h / height / l / length / thickness = height/thickness of nut.
 288//   pitch = Distance between threads, or zero for no threads. 
 289//   ---
 290//   shape = specifies shape of nut, either "hex" or "square".  Default: "hex"
 291//   left_handed = if true, create left-handed threads.  Default = false
 292//   starts = The number of lead starts.  Default: 1
 293//   bevel = if true, bevel the outside of the nut.  Default: true for hex nuts, false for square nuts
 294//   bevel1 = if true, bevel the outside of the nut bottom.
 295//   bevel2 = if true, bevel the outside of the nut top. 
 296//   bevang = set the angle for the outside nut bevel.  Default: 30
 297//   ibevel = if true, bevel the inside (the hole).   Default: true
 298//   ibevel1 = if true bevel the inside, bottom end.
 299//   ibevel2 = if true bevel the inside, top end.
 300//   blunt_start = If true apply truncated blunt start threads at both ends.  Default: true
 301//   blunt_start1 = If true apply truncated blunt start threads bottom end.
 302//   blunt_start2 = If true apply truncated blunt start threads top end.
 303//   end_len = Specify the unthreaded length at the end after blunt start threads.  Default: 0
 304//   end_len1 = Specify unthreaded length at the bottom
 305//   end_len2 = Specify unthreaded length at the top
 306//   lead_in = Specify linear length of the lead in section of the threading with blunt start threads
 307//   lead_in1 = Specify linear length of the lead in section of the threading at the bottom with blunt start threads
 308//   lead_in2 = Specify linear length of the lead in section of the threading at the top with blunt start threads
 309//   lead_in_ang = Specify angular length in degrees of the lead in section of the threading with blunt start threads
 310//   lead_in_ang1 = Specify angular length in degrees of the lead in section of the threading at the bottom with blunt start threads
 311//   lead_in_ang2 = Specify angular length in degrees of the lead in section of the threading at the top with blunt start threads
 312//   lead_in_shape = Specify the shape of the thread lead in by giving a text string or function.  Default: "default"
 313//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
 314//   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#subsection-spin).  Default: `0`
 315//   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
 316//   $slop = The printer-specific slop value, which adds clearance (`4*$slop`) to internal threads.
 317// Examples(Med):
 318//   threaded_nut(nutwidth=16, id=8, h=8, pitch=1.25, $slop=0.05, $fa=1, $fs=1);
 319//   threaded_nut(nutwidth=16, id=8, h=8, pitch=1.25, left_handed=true, bevel=false, $slop=0.1, $fa=1, $fs=1);
 320//   threaded_nut(shape="square", nutwidth=16, id=8, h=8, pitch=1.25, $slop=0.1, $fa=1, $fs=1);
 321//   threaded_nut(shape="square", nutwidth=16, id=8, h=8, pitch=1.25, bevel2=true, $slop=0.1, $fa=1, $fs=1);
 322//   rot(90)threaded_nut(nutwidth=16, id=8, h=8, pitch=1.25,blunt_start=false, $slop=0.1, $fa=1, $fs=1);
 323function threaded_nut(
 324    nutwidth, id, h,
 325    pitch, starts=1, shape="hex", left_handed=false, bevel, bevel1, bevel2, id1,id2,
 326    ibevel1, ibevel2, ibevel, bevang=30, thickness, height,
 327    length, l,
 328    blunt_start, blunt_start1, blunt_start2,
 329    lead_in, lead_in1, lead_in2,
 330    lead_in_ang, lead_in_ang1, lead_in_ang2,
 331    end_len, end_len1, end_len2,
 332    lead_in_shape="default",
 333    anchor, spin, orient
 334)=no_function("threaded_nut");
 335module threaded_nut(
 336    nutwidth, id, h,
 337    pitch, starts=1, shape="hex", left_handed=false, bevel, bevel1, bevel2, id1,id2,
 338    ibevel1, ibevel2, ibevel, bevang=30, thickness, height,
 339    length, l,
 340    blunt_start, blunt_start1, blunt_start2,
 341    lead_in, lead_in1, lead_in2,
 342    lead_in_ang, lead_in_ang1, lead_in_ang2,
 343    end_len, end_len1, end_len2,
 344    lead_in_shape="default",
 345    anchor, spin, orient
 346) {
 347    dummy1=
 348          assert(all_nonnegative(pitch), "Nut pitch must be nonnegative")
 349          assert(all_positive(id), "Nut inner diameter must be positive")
 350          assert(all_positive(h),"Nut thickness must be positive");
 351    basic = is_num(id) || is_undef(id) || is_def(id1) || is_def(id2);
 352    dummy2 = assert(basic || is_vector(id,3));
 353    depth = basic ? cos(30) * 5/8
 354                  : (id[2] - id[0])/2/pitch;
 355    crestwidth = basic ? 1/8 : 1/2 - (id[2]-id[1])/sqrt(3)/pitch;
 356    profile =    [
 357                  [-depth/sqrt(3)-crestwidth/2, -depth],
 358                  [              -crestwidth/2,      0],
 359                  [               crestwidth/2,      0],
 360                  [ depth/sqrt(3)+crestwidth/2, -depth]
 361                 ];
 362    oprofile = [
 363        [-6/16, -depth/pitch],
 364        [-1/16,  0],
 365        [-1/32,  0.02],
 366        [ 1/32,  0.02],
 367        [ 1/16,  0],
 368        [ 6/16, -depth/pitch]
 369    ];
 370    generic_threaded_nut(
 371        nutwidth=nutwidth,
 372        id=basic ? id : id[2], id1=id1, id2=id2,
 373        h=h,
 374        pitch=pitch,
 375        profile=profile,starts=starts,shape=shape, 
 376        left_handed=left_handed,
 377        bevel=bevel,bevel1=bevel1,bevel2=bevel2,
 378        ibevel1=ibevel1, ibevel2=ibevel2, ibevel=ibevel,
 379        blunt_start=blunt_start, blunt_start1=blunt_start1, blunt_start2=blunt_start2,
 380        lead_in=lead_in, lead_in1=lead_in1, lead_in2=lead_in2, lead_in_shape=lead_in_shape,
 381        lead_in_ang=lead_in_ang, lead_in_ang1=lead_in_ang1, lead_in_ang2=lead_in_ang2,
 382        end_len=end_len, end_len1=end_len1, end_len2=end_len2,
 383        l=l,length=length,
 384        anchor=anchor, spin=spin,
 385        orient=orient
 386    ) children();
 387}
 388
 389// Section: Trapezoidal Threading
 390
 391
 392// Module: trapezoidal_threaded_rod()
 393// Synopsis: Creates a trapezoidal threaded rod.
 394// SynTags: Geom
 395// Topics: Threading, Screws
 396// See Also: trapezoidal_threaded_nut()
 397// Usage:
 398//   trapezoidal_threaded_rod(d, l|length, pitch, [thread_angle=|flank_angle=], [thread_depth=], [internal=], ...) [ATTACHMENTS];
 399// Description:
 400//   Constructs a threaded rod with a symmetric trapezoidal thread.  Trapezoidal threads are used for lead screws because
 401//   they are one of the strongest symmetric profiles.  This tooth shape is stronger than a similarly
 402//   sized square thread becuase of its wider base.  However, it does place a radial load on the nut, unlike the square thread.
 403//   For loads in only one direction the asymmetric buttress thread profile can bear greater loads.  
 404//   .
 405//   By default produces the nominal dimensions
 406//   for metric trapezoidal threads: a thread angle of 30 degrees and a depth set to half the pitch.
 407//   You can also specify your own trapezoid parameters.  For ACME threads see acme_threaded_rod().
 408// Figure(2D,Med,NoAxes):
 409//   pa_delta = tan(15)/4;
 410//   rr1 = -1/2;
 411//   z1 = 1/4-pa_delta;
 412//   z2 = 1/4+pa_delta;
 413//   profile = [
 414//               [-z2, rr1],
 415//               [-z1,  0],
 416//               [ z1,  0],
 417//               [ z2, rr1],
 418//             ];
 419//   fullprofile = 50*left(1/2,p=concat(profile, right(1, p=profile)));
 420//   stroke(fullprofile,width=1);
 421//   dir = fullprofile[2]-fullprofile[3];
 422//   dir2 = fullprofile[5]-fullprofile[4];
 423//   curve = arc(32,angle=[75,105],r=67.5);
 424//   avgpt = mean([fullprofile[5]+.1*dir2, fullprofile[5]+.4*dir2]);
 425//   color("red"){
 426//    stroke([fullprofile[2]+.1*dir, fullprofile[2]+.4*dir], width=1);
 427//    stroke([fullprofile[5]+.1*dir2, fullprofile[5]+.4*dir2], width=1);
 428//    stroke(move(-curve[0]+avgpt,p=curve), width=1,endcaps="arrow2");
 429//    back(10)text("thread",size=4,halign="center");
 430//    back(3)text("angle",size=4,halign="center");
 431//   }
 432// Figure(2D,Med,NoAxes):
 433//   pa_delta = tan(15)/4;
 434//      rr1 = -1/2;
 435//      z1 = 1/4-pa_delta;
 436//      z2 = 1/4+pa_delta;
 437//      profile = [
 438//                  [-z2, rr1],
 439//                  [-z1,  0],
 440//                  [ z1,  0],
 441//                  [ z2, rr1],
 442//                ];
 443//      fullprofile = 50*left(1/2,p=concat(profile, right(1, p=profile)));
 444//      stroke(fullprofile,width=1);
 445//      dir = fullprofile[2]-fullprofile[3];
 446//      dir2 = fullprofile[5]-fullprofile[4];
 447//      curve = arc(15,angle=[75,87],r=40 /*67.5*/);
 448//      avgpt = mean([fullprofile[5]+.1*dir2, fullprofile[5]+.4*dir2]);
 449//      color("red"){
 450//       stroke([fullprofile[4]+[0,1], fullprofile[4]+[0,37]], width=1);
 451//       stroke([fullprofile[5]+.1*dir2, fullprofile[5]+.4*dir2], width=1);
 452//       stroke(move(-curve[0]+avgpt,p=curve), width=0.71,endcaps="arrow2");
 453//       right(14)back(19)text("flank",size=4,halign="center");
 454//       right(14)back(14)text("angle",size=4,halign="center");
 455//      }
 456// Arguments:
 457//   d = Outer diameter of threaded rod.
 458//   l / length / h / height = Length of threaded rod.
 459//   pitch = Thread spacing. 
 460//   ---
 461//   thread_angle = Angle between two thread faces.  Default: 30
 462//   thread_depth = Depth of threads.  Default: pitch/2
 463//   flank_angle = Angle of thread faces to plane perpendicular to screw. 
 464//   left_handed = If true, create left-handed threads.  Default: false
 465//   starts = The number of lead starts.  Default: 1
 466//   bevel = if true, bevel the thread ends.  Default: false
 467//   bevel1 = if true bevel the bottom end.
 468//   bevel2 = if true bevel the top end. 
 469//   internal = If true, make this a mask for making internal threads.  Default: false
 470//   d1 = Bottom outside diameter of threads.
 471//   d2 = Top outside diameter of threads.
 472//   blunt_start = If true apply truncated blunt start threads at both ends.  Default: true
 473//   blunt_start1 = If true apply truncated blunt start threads bottom end.
 474//   blunt_start2 = If true apply truncated blunt start threads top end.
 475//   end_len = Specify the unthreaded length at the end after blunt start threads.  Default: 0
 476//   end_len1 = Specify unthreaded length at the bottom
 477//   end_len2 = Specify unthreaded length at the top
 478//   lead_in = Specify linear length of the lead in section of the threading with blunt start threads
 479//   lead_in1 = Specify linear length of the lead in section of the threading at the bottom with blunt start threads
 480//   lead_in2 = Specify linear length of the lead in section of the threading at the top with blunt start threads
 481//   lead_in_ang = Specify angular length in degrees of the lead in section of the threading with blunt start threads
 482//   lead_in_ang1 = Specify angular length in degrees of the lead in section of the threading at the bottom with blunt start threads
 483//   lead_in_ang2 = Specify angular length in degrees of the lead in section of the threading at the top with blunt start threads
 484//   lead_in_shape = Specify the shape of the thread lead in by giving a text string or function.  Default: "default"
 485//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
 486//   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#subsection-spin).  Default: `0`
 487//   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
 488//   $slop = The printer-specific slop value, which adds clearance (`4*$slop`) to internal threads.
 489// Example(2D):
 490//   projection(cut=true)
 491//       trapezoidal_threaded_rod(d=10, l=15, pitch=2, orient=BACK);
 492// Examples(Med): 
 493//   trapezoidal_threaded_rod(d=10, l=40, pitch=2, $fn=32);  // Standard metric threading
 494//   rot(-65)trapezoidal_threaded_rod(d=10, l=17, pitch=2, blunt_start=false, $fn=32);  // Standard metric threading
 495//   trapezoidal_threaded_rod(d=10, l=17, pitch=2, bevel=true, $fn=32);  // Standard metric threading
 496//   trapezoidal_threaded_rod(d=10, h=30, pitch=2, left_handed=true, $fa=1, $fs=1);  // Standard metric threading
 497//   trapezoidal_threaded_rod(d=10, l=40, pitch=3, left_handed=true, starts=3, $fn=36);
 498//   trapezoidal_threaded_rod(l=25, d=10, pitch=2, starts=3, $fa=1, $fs=1, bevel=true, orient=RIGHT, anchor=BOTTOM);
 499//   trapezoidal_threaded_rod(d=60, l=16, pitch=8, thread_depth=3, thread_angle=90, blunt_start=false, $fa=2, $fs=2);
 500//   trapezoidal_threaded_rod(d=60, l=16, pitch=8, thread_depth=3, thread_angle=90, end_len=0, $fa=2, $fs=2);   
 501//   trapezoidal_threaded_rod(d=60, l=16, pitch=8, thread_depth=3, thread_angle=90, left_handed=true, starts=4, $fa=2, $fs=2,end_len=0);
 502//   trapezoidal_threaded_rod(d=16, l=40, pitch=2, thread_angle=60);
 503//   trapezoidal_threaded_rod(d=25, l=40, pitch=10, thread_depth=8/3, thread_angle=100, starts=4, anchor=BOT, $fa=2, $fs=2,end_len=-2);
 504//   trapezoidal_threaded_rod(d=50, l=35, pitch=8, thread_angle=60, starts=11, lead_in=3, $fn=120);
 505//   trapezoidal_threaded_rod(d=10, l=40, end_len2=10, pitch=2, $fn=32);  // Unthreaded top end section
 506// Example(Med): Using as a Mask to Make Internal Threads
 507//   bottom_half() difference() {
 508//       cube(50, center=true);
 509//       trapezoidal_threaded_rod(d=40, l=51, pitch=5, thread_angle=30, internal=true, bevel=true, orient=RIGHT, $fn=36);
 510//   }
 511function trapezoidal_threaded_rod(
 512    d, l, pitch,
 513    thread_angle,
 514    thread_depth,
 515    flank_angle,
 516    left_handed=false,
 517    bevel,bevel1,bevel2,
 518    starts=1, 
 519    internal=false,
 520    d1, d2, length, h, height,
 521    blunt_start, blunt_start1, blunt_start2,
 522    lead_in, lead_in1, lead_in2,
 523    lead_in_ang, lead_in_ang1, lead_in_ang2,
 524    end_len, end_len1, end_len2,
 525    lead_in_shape="default",
 526    anchor, spin, orient
 527) = no_function("trapezoidal_threaded_rod");
 528module trapezoidal_threaded_rod(
 529    d, l, pitch,
 530    thread_angle,
 531    thread_depth,
 532    flank_angle,
 533    left_handed=false,
 534    bevel,bevel1,bevel2,
 535    starts=1, 
 536    internal=false,
 537    d1, d2, length, h, height,
 538    blunt_start, blunt_start1, blunt_start2,
 539    lead_in, lead_in1, lead_in2,
 540    lead_in_ang, lead_in_ang1, lead_in_ang2,
 541    end_len, end_len1, end_len2,
 542    lead_in_shape="default",
 543    anchor, spin, orient
 544) {
 545    dummy0 = assert(num_defined([thread_angle,flank_angle])<=1, "Cannot define both flank angle and thread angle");
 546    thread_angle = first_defined([thread_angle, u_mul(2,flank_angle), 30]);
 547    dummy1 = assert(all_nonnegative(pitch),"Must give a positive pitch value")
 548             assert(thread_angle>=0 && thread_angle<180, "Invalid thread angle or flank angle")
 549             assert(thread_angle<=90 || all_positive([thread_depth]),
 550                   "Thread angle (2*flank_angle) must be smaller than 90 degrees with default thread depth of pitch/2");
 551    depth = first_defined([thread_depth,pitch/2]);
 552    pa_delta = 0.5*depth*tan(thread_angle/2) / pitch;
 553    dummy2 = assert(pa_delta<=1/4, "Specified thread geometry is impossible");
 554    rr1 = -depth/pitch;
 555    z1 = 1/4-pa_delta;
 556    z2 = 1/4+pa_delta;
 557    profile = [
 558               [-z2, rr1],
 559               [-z1,  0],
 560               [ z1,  0],
 561               [ z2, rr1],
 562              ];
 563    generic_threaded_rod(d=d,l=l,pitch=pitch,profile=profile,
 564                         left_handed=left_handed,bevel=bevel,bevel1=bevel1,bevel2=bevel2,starts=starts,d1=d1,d2=d2,
 565                         internal=internal, length=length, height=height, h=h,
 566                         blunt_start=blunt_start, blunt_start1=blunt_start1, blunt_start2=blunt_start2,
 567                         lead_in=lead_in, lead_in1=lead_in1, lead_in2=lead_in2, lead_in_shape=lead_in_shape,
 568                         lead_in_ang=lead_in_ang, lead_in_ang1=lead_in_ang1, lead_in_ang2=lead_in_ang2,
 569                         end_len=end_len, end_len1=end_len1, end_len2=end_len2,
 570                         anchor=anchor,spin=spin,orient=orient)
 571      children();
 572}
 573
 574
 575// Module: trapezoidal_threaded_nut()
 576// Synopsis: Creates a trapezoidal threaded nut.
 577// SynTags: Geom
 578// Topics: Threading, Screws
 579// See Also: trapezoidal_threaded_rod()
 580// Usage:
 581//   trapezoidal_threaded_nut(nutwidth, id, h|height|thickness, pitch, [thread_angle=|flank_angle=], [thread_depth], ...) [ATTACHMENTS];
 582// Description:
 583//   Constructs a hex nut or square nut for a symmetric trapzoidal threaded rod.  By default produces
 584//   the nominal dimensions for metric trapezoidal threads: a thread angle of 30 degrees and a depth
 585//   set to half the pitch.  You can also specify your own trapezoid parameters.  For ACME threads see
 586//   acme_threaded_nut().
 587// Arguments:
 588//   nutwidth = flat to flat width of nut
 589//   id = inner diameter of threaded hole, measured from bottom of threads
 590//   h / height / l / length / thickness = height/thickness of nut.
 591//   pitch = Thread spacing.
 592//   ---
 593//   thread_angle = Angle between two thread faces.  Default: 30
 594//   thread_depth = Depth of the threads.  Default: pitch/2
 595//   flank_angle = Angle of thread faces to plane perpendicular to screw. 
 596//   shape = specifies shape of nut, either "hex" or "square".  Default: "hex"
 597//   left_handed = if true, create left-handed threads.  Default = false
 598//   starts = The number of lead starts.  Default = 1
 599//   bevel = if true, bevel the outside of the nut.  Default: true for hex nuts, false for square nuts
 600//   bevel1 = if true, bevel the outside of the nut bottom.
 601//   bevel2 = if true, bevel the outside of the nut top. 
 602//   bevang = set the angle for the outside nut bevel.  Default: 30
 603//   ibevel = if true, bevel the inside (the hole).   Default: true
 604//   ibevel1 = if true bevel the inside, bottom end.
 605//   ibevel2 = if true bevel the inside, top end.
 606//   blunt_start = If true apply truncated blunt start threads at both ends.  Default: true
 607//   blunt_start1 = If true apply truncated blunt start threads bottom end.
 608//   blunt_start2 = If true apply truncated blunt start threads top end.
 609//   end_len = Specify the unthreaded length at the end after blunt start threads.  Default: 0
 610//   end_len1 = Specify unthreaded length at the bottom
 611//   end_len2 = Specify unthreaded length at the top
 612//   lead_in = Specify linear length of the lead in section of the threading with blunt start threads
 613//   lead_in1 = Specify linear length of the lead in section of the threading at the bottom with blunt start threads
 614//   lead_in2 = Specify linear length of the lead in section of the threading at the top with blunt start threads
 615//   lead_in_ang = Specify angular length in degrees of the lead in section of the threading with blunt start threads
 616//   lead_in_ang1 = Specify angular length in degrees of the lead in section of the threading at the bottom with blunt start threads
 617//   lead_in_ang2 = Specify angular length in degrees of the lead in section of the threading at the top with blunt start threads
 618//   lead_in_shape = Specify the shape of the thread lead in by giving a text string or function.  Default: "default"
 619//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
 620//   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#subsection-spin).  Default: `0`
 621//   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
 622//   $slop = The printer-specific slop value, which adds clearance (`4*$slop`) to internal threads.
 623// Examples(Med):
 624//   trapezoidal_threaded_nut(nutwidth=16, id=8, h=8, pitch=2, $slop=0.1, anchor=UP);
 625//   trapezoidal_threaded_nut(nutwidth=16, id=8, h=8, pitch=2, bevel=false, $slop=0.05, anchor=UP);
 626//   trapezoidal_threaded_nut(nutwidth=17.4, id=10, h=10, pitch=2, $slop=0.1, left_handed=true);
 627//   trapezoidal_threaded_nut(nutwidth=17.4, id=10, h=10, pitch=2, starts=3, $fa=1, $fs=1, $slop=0.15);
 628//   trapezoidal_threaded_nut(nutwidth=17.4, id=10, h=10, pitch=2, starts=3, $fa=1, $fs=1, $slop=0.15, blunt_start=false);
 629//   trapezoidal_threaded_nut(nutwidth=17.4, id=10, h=10, pitch=0, $slop=0.2);   // No threads
 630function trapezoidal_threaded_nut(
 631    nutwidth,
 632    id,
 633    h,
 634    pitch,
 635    thread_angle,
 636    thread_depth, shape="hex",
 637    flank_angle,
 638    left_handed=false,
 639    starts=1,
 640    bevel,bevel1,bevel2,bevang=30,
 641    ibevel1,ibevel2,ibevel,
 642    thickness,height,
 643    id1,id2,
 644    length, l,
 645    blunt_start, blunt_start1, blunt_start2,
 646    lead_in, lead_in1, lead_in2,
 647    lead_in_ang, lead_in_ang1, lead_in_ang2,
 648    end_len, end_len1, end_len2,
 649    lead_in_shape="default",
 650    anchor, spin, orient
 651) = no_function("trapezoidal_threaded_nut");
 652module trapezoidal_threaded_nut(
 653    nutwidth,
 654    id,
 655    h,
 656    pitch,
 657    thread_angle,
 658    thread_depth, shape="hex",
 659    flank_angle,
 660    left_handed=false,
 661    starts=1,
 662    bevel,bevel1,bevel2,bevang=30,
 663    ibevel1,ibevel2,ibevel,
 664    thickness,height,
 665    id1,id2,
 666    length, l,
 667    blunt_start, blunt_start1, blunt_start2,
 668    lead_in, lead_in1, lead_in2,
 669    lead_in_ang, lead_in_ang1, lead_in_ang2,
 670    end_len, end_len1, end_len2,
 671    lead_in_shape="default",
 672    anchor, spin, orient
 673) {
 674    dummy0 = assert(num_defined([thread_angle,flank_angle])<=1, "Cannot define both flank angle and thread angle");
 675    thread_angle = first_defined([thread_angle, u_mul(2,flank_angle), 30]);
 676    dummy1 = assert(all_nonnegative(pitch),"Must give a positive pitch value")
 677             assert(thread_angle>=0 && thread_angle<180, "Invalid thread angle or flank angle")
 678             assert(thread_angle<=90 || all_positive([thread_depth]),
 679                   "Thread angle (2*flank_angle) must be smaller than 90 degrees with default thread depth of pitch/2");
 680    depth = first_defined([thread_depth,pitch/2]);
 681    pa_delta = 0.5*depth*tan(thread_angle/2) / pitch;
 682    dummy2 = assert(pitch==0 || pa_delta<1/4, "Specified thread geometry is impossible");
 683    rr1 = -depth/pitch;
 684    z1 = 1/4-pa_delta;
 685    z2 = 1/4+pa_delta;
 686    profile = [
 687               [-z2, rr1],
 688               [-z1,  0],
 689               [ z1,  0],
 690               [ z2, rr1],
 691              ];
 692    generic_threaded_nut(nutwidth=nutwidth,id=id,h=h,pitch=pitch,profile=profile,id1=id1,id2=id2,
 693                         shape=shape,left_handed=left_handed,bevel=bevel,bevel1=bevel1,bevel2=bevel2,starts=starts,
 694                         ibevel=ibevel,ibevel1=ibevel1,ibevel2=ibevel2,bevang=bevang,height=height,thickness=thickness,
 695                         blunt_start=blunt_start, blunt_start1=blunt_start1, blunt_start2=blunt_start2,
 696                         lead_in=lead_in, lead_in1=lead_in1, lead_in2=lead_in2, lead_in_shape=lead_in_shape,
 697                         lead_in_ang=lead_in_ang, lead_in_ang1=lead_in_ang1, lead_in_ang2=lead_in_ang2,
 698                         end_len=end_len, end_len1=end_len1, end_len2=end_len2,
 699                         l=l,length=length,
 700                         anchor=anchor,spin=spin,orient=orient)
 701      children();
 702}
 703
 704
 705// Module: acme_threaded_rod()
 706// Synopsis: Creates an ACME threaded rod.
 707// SynTags: Geom
 708// Topics: Threading, Screws
 709// See Also: acme_threaded_nut()
 710// Usage:
 711//   acme_threaded_rod(d, l|length, tpi|pitch=, [internal=], ...) [ATTACHMENTS];
 712// Description:
 713//   Constructs an ACME trapezoidal threaded screw rod.  This form has a 29 degree thread angle with a
 714//   symmetric trapezoidal thread.  
 715// Arguments:
 716//   d = Outer diameter of threaded rod.
 717//   l / length / h / height = Length of threaded rod.
 718//   tpi = threads per inch.
 719//   ---
 720//   pitch = thread spacing (alternative to tpi)
 721//   starts = The number of lead starts.  Default = 1
 722//   left_handed = if true, create left-handed threads.  Default = false
 723//   bevel = if true, bevel the thread ends.  Default: false
 724//   bevel1 = if true bevel the bottom end.
 725//   bevel2 = if true bevel the top end. 
 726//   internal = If true, this is a mask for making internal threads.
 727//   blunt_start = If true apply truncated blunt start threads at both ends.  Default: true
 728//   blunt_start1 = If true apply truncated blunt start threads bottom end.
 729//   blunt_start2 = If true apply truncated blunt start threads top end.
 730//   end_len = Specify the unthreaded length at the end after blunt start threads.  Default: 0
 731//   end_len1 = Specify unthreaded length at the bottom
 732//   end_len2 = Specify unthreaded length at the top
 733//   lead_in = Specify linear length of the lead in section of the threading with blunt start threads
 734//   lead_in1 = Specify linear length of the lead in section of the threading at the bottom with blunt start threads
 735//   lead_in2 = Specify linear length of the lead in section of the threading at the top with blunt start threads
 736//   lead_in_ang = Specify angular length in degrees of the lead in section of the threading with blunt start threads
 737//   lead_in_ang1 = Specify angular length in degrees of the lead in section of the threading at the bottom with blunt start threads
 738//   lead_in_ang2 = Specify angular length in degrees of the lead in section of the threading at the top with blunt start threads
 739//   lead_in_shape = Specify the shape of the thread lead in by giving a text string or function.  Default: "default"
 740//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
 741//   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#subsection-spin).  Default: `0`
 742//   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
 743//   $slop = The printer-specific slop value, which adds clearance (`4*$slop`) to internal threads.
 744// Example(2D):
 745//   projection(cut=true)
 746//       acme_threaded_rod(d=10, l=15, pitch=2, orient=BACK);
 747// Examples(Med):
 748//   acme_threaded_rod(d=3/8*INCH, l=20, pitch=1/8*INCH, $fn=32);
 749//   acme_threaded_rod(d=10, l=30, pitch=2, starts=3, $fa=1, $fs=1);
 750function acme_threaded_rod(
 751    d, l, tpi, pitch,
 752    starts=1,
 753    left_handed=false,
 754    bevel,bevel1,bevel2,
 755    internal=false, 
 756    d1, d2, length, h, height,
 757    blunt_start, blunt_start1, blunt_start2,
 758    lead_in, lead_in1, lead_in2,
 759    lead_in_ang, lead_in_ang1, lead_in_ang2,
 760    end_len, end_len1, end_len2,
 761    lead_in_shape="default",
 762    anchor, spin, orient
 763) = no_function("acme_threaded_rod");
 764module acme_threaded_rod(
 765    d, l, tpi, pitch,
 766    starts=1,
 767    left_handed=false,
 768    bevel,bevel1,bevel2,
 769    internal=false, 
 770    d1, d2, length, h, height,
 771    blunt_start, blunt_start1, blunt_start2,
 772    lead_in, lead_in1, lead_in2,
 773    lead_in_ang, lead_in_ang1, lead_in_ang2,
 774    end_len, end_len1, end_len2,
 775    lead_in_shape="default",
 776    anchor, spin, orient
 777) {
 778    dummy = assert(num_defined([pitch,tpi])==1,"Must give exactly one of pitch and tpi");
 779    pitch = is_undef(pitch) ? INCH/tpi : pitch;
 780    trapezoidal_threaded_rod(
 781        d=d, l=l, pitch=pitch,
 782        thread_angle=29,
 783        thread_depth=pitch/2,
 784        starts=starts,
 785        left_handed=left_handed,
 786        bevel=bevel,bevel1=bevel1,bevel2=bevel2,
 787        internal=internal, length=length, height=height, h=h,
 788        blunt_start=blunt_start, blunt_start1=blunt_start1, blunt_start2=blunt_start2,
 789        lead_in=lead_in, lead_in1=lead_in1, lead_in2=lead_in2, lead_in_shape=lead_in_shape,
 790        lead_in_ang=lead_in_ang, lead_in_ang1=lead_in_ang1, lead_in_ang2=lead_in_ang2,
 791        end_len=end_len, end_len1=end_len1, end_len2=end_len2,
 792        anchor=anchor,
 793        spin=spin,
 794        orient=orient
 795    ) children();
 796}
 797
 798
 799
 800// Module: acme_threaded_nut()
 801// Synopsis: Creates an ACME threaded nut.
 802// SynTags: Geom
 803// Topics: Threading, Screws
 804// See Also: acme_threaded_rod()
 805// Usage:
 806//   acme_threaded_nut(nutwidth, id, h|height|thickness, tpi|pitch=, [shape=], ...) [ATTACHMENTS];
 807// Description:
 808//   Constructs a hexagonal or square nut for an ACME threaded screw rod. 
 809// Arguments:
 810//   nutwidth = flat to flat width of nut.
 811//   id = inner diameter of threaded hole, measured from bottom of threads
 812//   h / height / l / length / thickness = height/thickness of nut.
 813//   tpi = threads per inch
 814//   ---
 815//   pitch = Thread spacing (alternative to tpi)
 816//   shape = specifies shape of nut, either "hex" or "square".  Default: "hex"
 817//   left_handed = if true, create left-handed threads.  Default = false
 818//   starts = Number of lead starts.  Default: 1
 819//   bevel = if true, bevel the outside of the nut.  Default: true for hex nuts, false for square nuts
 820//   bevel1 = if true, bevel the outside of the nut bottom.
 821//   bevel2 = if true, bevel the outside of the nut top. 
 822//   bevang = set the angle for the outside nut bevel.  Default: 30
 823//   ibevel = if true, bevel the inside (the hole).   Default: true
 824//   ibevel1 = if true bevel the inside, bottom end.
 825//   ibevel2 = if true bevel the inside, top end.
 826//   blunt_start = If true apply truncated blunt start threads at both ends.  Default: true
 827//   blunt_start1 = If true apply truncated blunt start threads bottom end.
 828//   blunt_start2 = If true apply truncated blunt start threads top end.
 829//   end_len = Specify the unthreaded length at the end after blunt start threads.  Default: 0
 830//   end_len1 = Specify unthreaded length at the bottom
 831//   end_len2 = Specify unthreaded length at the top
 832//   lead_in = Specify linear length of the lead in section of the threading with blunt start threads
 833//   lead_in1 = Specify linear length of the lead in section of the threading at the bottom with blunt start threads
 834//   lead_in2 = Specify linear length of the lead in section of the threading at the top with blunt start threads
 835//   lead_in_ang = Specify angular length in degrees of the lead in section of the threading with blunt start threads
 836//   lead_in_ang1 = Specify angular length in degrees of the lead in section of the threading at the bottom with blunt start threads
 837//   lead_in_ang2 = Specify angular length in degrees of the lead in section of the threading at the top with blunt start threads
 838//   lead_in_shape = Specify the shape of the thread lead in by giving a text string or function.  Default: "default"
 839//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
 840//   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#subsection-spin).  Default: `0`
 841//   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
 842//   $slop = The printer-specific slop value, which adds clearance (`4*$slop`) to internal threads.
 843// Examples(Med):
 844//   acme_threaded_nut(nutwidth=16, id=3/8*INCH, h=8, tpi=8, $slop=0.05);
 845//   acme_threaded_nut(nutwidth=16, id=3/8*INCH, h=10, tpi=12, starts=3, $slop=0.1, $fa=1, $fs=1, ibevel=false);
 846//   acme_threaded_nut(nutwidth=16, id=3/8*INCH, h=10, tpi=12, starts=3, $slop=0.1, $fa=1, $fs=1, blunt_start=false);
 847function acme_threaded_nut(
 848    nutwidth, id, h, tpi, pitch,
 849    starts=1,
 850    left_handed=false,shape="hex",
 851    bevel,bevel1,bevel2,bevang=30,
 852    ibevel,ibevel1,ibevel2,
 853    height,thickness,
 854    length, l,
 855    blunt_start, blunt_start1, blunt_start2,
 856    lead_in, lead_in1, lead_in2,
 857    lead_in_ang, lead_in_ang1, lead_in_ang2,
 858    end_len, end_len1, end_len2,
 859    lead_in_shape="default",
 860    anchor, spin, orient
 861) = no_function("acme_threaded_nut");
 862module acme_threaded_nut(
 863    nutwidth, id, h, tpi, pitch,
 864    starts=1,
 865    left_handed=false,shape="hex",
 866    bevel,bevel1,bevel2,bevang=30,
 867    ibevel,ibevel1,ibevel2,
 868    height,thickness,
 869    length, l,
 870    blunt_start, blunt_start1, blunt_start2,
 871    lead_in, lead_in1, lead_in2,
 872    lead_in_ang, lead_in_ang1, lead_in_ang2,
 873    end_len, end_len1, end_len2,
 874    lead_in_shape="default",
 875    anchor, spin, orient
 876) {
 877    dummy = assert(num_defined([pitch,tpi])==1,"Must give exactly one of pitch and tpi");
 878    pitch = is_undef(pitch) ? INCH/tpi : pitch;
 879    dummy2=assert(is_num(pitch) && pitch>=0);
 880    trapezoidal_threaded_nut(
 881        nutwidth=nutwidth, id=id, h=h, pitch=pitch,
 882        thread_depth = pitch/2, 
 883        thread_angle=29,shape=shape, 
 884        left_handed=left_handed,
 885        bevel=bevel,bevel1=bevel1,bevel2=bevel2,
 886        ibevel=ibevel,ibevel1=ibevel1,ibevel2=ibevel2,
 887        height=height,thickness=thickness,
 888        blunt_start=blunt_start, blunt_start1=blunt_start1, blunt_start2=blunt_start2,
 889        lead_in=lead_in, lead_in1=lead_in1, lead_in2=lead_in2, lead_in_shape=lead_in_shape,
 890        lead_in_ang=lead_in_ang, lead_in_ang1=lead_in_ang1, lead_in_ang2=lead_in_ang2,
 891        end_len=end_len, end_len1=end_len1, end_len2=end_len2,
 892        l=l,length=length,
 893        starts=starts,
 894        anchor=anchor,
 895        spin=spin,
 896        orient=orient
 897    ) children();
 898}
 899
 900
 901
 902
 903// Section: Pipe Threading
 904
 905// Module: npt_threaded_rod()
 906// Synopsis: Creates NPT pipe threading.
 907// SynTags: Geom
 908// Topics: Threading, Screws
 909// See Also: acme_threaded_rod()
 910// Usage:
 911//   npt_threaded_rod(size, [internal=], ...) [ATTACHMENTS];
 912// Description:
 913//   Constructs a standard NPT pipe end threading. If `internal=true`, creates a mask for making
 914//   internal pipe threads.  Tapers smaller upwards if `internal=false`.  Tapers smaller downwards
 915//   if `internal=true`.  If `hollow=true` and `internal=false`, then the pipe threads will be
 916//   hollowed out into a pipe with the apropriate internal diameter.
 917// Arguments:
 918//   size = NPT standard pipe size in inches.  1/16", 1/8", 1/4", 3/8", 1/2", 3/4", 1", 1+1/4", 1+1/2", or 2".  Default: 1/2"
 919//   ---
 920//   left_handed = If true, create left-handed threads.  Default = false
 921//   bevel = if true, bevel the thread ends.  Default: false
 922//   bevel1 = if true bevel the bottom end.
 923//   bevel2 = if true bevel the top end. 
 924//   hollow = If true, create a pipe with the correct internal diameter.
 925//   internal = If true, make this a mask for making internal threads.
 926//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
 927//   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#subsection-spin).  Default: `0`
 928//   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
 929//   $slop = The printer-specific slop value, which adds clearance (`4*$slop`) to internal threads.
 930// Example(2D): The straight gray rectangle reveals the tapered threads.  
 931//   projection(cut=true) npt_threaded_rod(size=1/4, orient=BACK);
 932//   right(.533*INCH/2) color("gray") rect([2,0.5946*INCH],anchor=LEFT);
 933// Examples(Med):
 934//   npt_threaded_rod(size=3/8, $fn=72);
 935//   npt_threaded_rod(size=1/2, $fn=72, bevel=true);
 936//   npt_threaded_rod(size=1/2, left_handed=true, $fn=72);
 937//   npt_threaded_rod(size=3/4, hollow=true, $fn=96);
 938// Example:
 939//   diff("remove"){
 940//      cuboid([40,40,40])
 941//      tag("remove"){
 942//        up(.01)position(TOP)
 943//            npt_threaded_rod(size=3/4, $fn=96, internal=true, $slop=0.1, anchor=TOP);
 944//        cyl(d=3/4*INCH, l=42, $fn=32);
 945//      }
 946//   }
 947function npt_threaded_rod(
 948    size=1/2,
 949    left_handed=false,
 950    bevel,bevel1,bevel2,
 951    hollow=false,
 952    internal=false,
 953    anchor, spin, orient
 954)=no_function("npt_threaded_rod");
 955module npt_threaded_rod(
 956    size=1/2,
 957    left_handed=false,
 958    bevel,bevel1,bevel2,
 959    hollow=false,
 960    internal=false,
 961    anchor, spin, orient
 962) {
 963    assert(is_finite(size));
 964    assert(is_bool(left_handed));
 965    assert(is_undef(bevel) || is_bool(bevel));
 966    assert(is_bool(hollow));
 967    assert(is_bool(internal));
 968    assert(!(internal&&hollow), "Cannot created a hollow internal threads mask.");
 969    info_table = [
 970        // Size    len      OD    TPI
 971        [ 1/16,  [ 0.3896, 0.308, 27  ]],
 972        [ 1/8,   [ 0.3924, 0.401, 27  ]],
 973        [ 1/4,   [ 0.5946, 0.533, 18  ]],
 974        [ 3/8,   [ 0.6006, 0.668, 18  ]],
 975        [ 1/2,   [ 0.7815, 0.832, 14  ]],
 976        [ 3/4,   [ 0.7935, 1.043, 14  ]],
 977        [ 1,     [ 0.9845, 1.305, 11.5]],
 978        [ 1+1/4, [ 1.0085, 1.649, 11.5]],
 979        [ 1+1/2, [ 1.0252, 1.888, 11.5]],
 980        [ 2,     [ 1.0582, 2.362, 11.5]],
 981    ];
 982    info = [for (data=info_table) if(approx(size,data[0])) data[1]][0];
 983    dummy1 = assert(is_def(info), "Unsupported NPT size.  Try one of 1/16, 1/8, 1/4, 3/8, 1/2, 3/4, 1, 1+1/4, 1+1/2, 2");
 984    l = INCH * info[0];
 985    d = INCH * info[1];
 986    pitch = INCH / info[2];
 987    rr = d/2;
 988    rr2 = rr - l/32;
 989    r1 = internal? rr2 : rr;
 990    r2 = internal? rr : rr2;
 991    depth = pitch * cos(30) * 5/8;
 992    profile = internal? [
 993        [-6/16, -depth/pitch],
 994        [-1/16,  0],
 995        [-1/32,  0.02],
 996        [ 1/32,  0.02],
 997        [ 1/16,  0],
 998        [ 6/16, -depth/pitch]
 999    ] : [
1000        [-7/16, -depth/pitch*1.07],
1001        [-6/16, -depth/pitch],
1002        [-1/16,  0],
1003        [ 1/16,  0],
1004        [ 6/16, -depth/pitch],
1005        [ 7/16, -depth/pitch*1.07]
1006    ];
1007    attachable(anchor,spin,orient, l=l, r1=r1, r2=r2) {
1008        difference() {
1009            generic_threaded_rod(
1010                d1=2*r1, d2=2*r2, l=l,
1011                pitch=pitch,
1012                profile=profile,
1013                left_handed=left_handed,
1014                bevel=bevel,bevel1=bevel1,bevel2=bevel2,
1015                internal=internal,
1016                blunt_start=true
1017            );
1018            if (hollow) cylinder(h=l+1, d=size*INCH, center=true);
1019        }
1020        children();
1021    }
1022}
1023
1024
1025
1026// Section: Buttress Threading
1027
1028// Module: buttress_threaded_rod()
1029// Synopsis: Creates a buttress-threaded rod.
1030// SynTags: Geom
1031// Topics: Threading, Screws
1032// See Also: buttress_threaded_nut()
1033// Usage:
1034//   buttress_threaded_rod(d, l|length, pitch, [internal=], ...) [ATTACHMENTS];
1035// Description:
1036//   Constructs a simple buttress threaded rod with a 45 degree angle.  The buttress thread or sawtooth thread has low friction and high loading
1037//   in one direction at the cost of higher friction and inferior loading in the other direction.  Buttress threads are sometimes used on
1038//   vises, which are loaded only in one direction.  
1039// Arguments:
1040//   d = Outer diameter of threaded rod.
1041//   l / length / h / height = Length of threaded rod.
1042//   pitch = Thread spacing.
1043//   ---
1044//   left_handed = if true, create left-handed threads.  Default = false
1045//   starts = Number of lead starts.  Default: 1
1046//   bevel = if true, bevel the thread ends.  Default: false
1047//   bevel1 = if true bevel the bottom end.
1048//   bevel2 = if true bevel the top end. 
1049//   internal = If true, this is a mask for making internal threads.
1050//   blunt_start = If true apply truncated blunt start threads at both ends.  Default: true
1051//   blunt_start1 = If true apply truncated blunt start threads bottom end.
1052//   blunt_start2 = If true apply truncated blunt start threads top end.
1053//   end_len = Specify the unthreaded length at the end after blunt start threads.  Default: 0
1054//   end_len1 = Specify unthreaded length at the bottom
1055//   end_len2 = Specify unthreaded length at the top
1056//   lead_in = Specify linear length of the lead in section of the threading with blunt start threads
1057//   lead_in1 = Specify linear length of the lead in section of the threading at the bottom with blunt start threads
1058//   lead_in2 = Specify linear length of the lead in section of the threading at the top with blunt start threads
1059//   lead_in_ang = Specify angular length in degrees of the lead in section of the threading with blunt start threads
1060//   lead_in_ang1 = Specify angular length in degrees of the lead in section of the threading at the bottom with blunt start threads
1061//   lead_in_ang2 = Specify angular length in degrees of the lead in section of the threading at the top with blunt start threads
1062//   lead_in_shape = Specify the shape of the thread lead in by giving a text string or function.  Default: "default"
1063//   d1 = Bottom outside diameter of threads.
1064//   d2 = Top outside diameter of threads.
1065//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
1066//   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#subsection-spin).  Default: `0`
1067//   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
1068//   $slop = The printer-specific slop value, which adds clearance (`4*$slop`) to internal threads.
1069// Example(2D):
1070//   projection(cut=true)
1071//       buttress_threaded_rod(d=10, l=15, pitch=2, orient=BACK);
1072// Examples(Med):
1073//   buttress_threaded_rod(d=25, l=20, pitch=2, $fa=1, $fs=1,end_len=0);
1074//   buttress_threaded_rod(d=10, l=20, pitch=1.25, left_handed=true, $fa=1, $fs=1);
1075function buttress_threaded_rod(
1076    d, l, pitch,
1077    left_handed=false, starts=1,
1078    bevel,bevel1,bevel2,
1079    internal=false,
1080    d1, d2, length, h, height,
1081    blunt_start, blunt_start1, blunt_start2,
1082    lead_in, lead_in1, lead_in2,
1083    lead_in_ang, lead_in_ang1, lead_in_ang2,
1084    end_len, end_len1, end_len2,
1085    lead_in_shape="default",
1086    anchor, spin, orient
1087) = no_function("buttress_threaded_rod");
1088module buttress_threaded_rod(
1089    d, l, pitch,
1090    left_handed=false, starts=1,
1091    bevel,bevel1,bevel2,
1092    internal=false,
1093    d1, d2, length, h, height,
1094    blunt_start, blunt_start1, blunt_start2,
1095    lead_in, lead_in1, lead_in2,
1096    lead_in_ang, lead_in_ang1, lead_in_ang2,
1097    end_len, end_len1, end_len2,
1098    lead_in_shape="default",
1099    anchor, spin, orient
1100) {
1101    depth = pitch * 3/4;
1102    profile = [
1103        [  -1/2, -0.77],
1104        [ -7/16, -0.75],
1105        [  5/16,  0],
1106        [  7/16,  0],
1107        [  7/16, -0.75],
1108        [   1/2, -0.77],
1109    ];
1110    generic_threaded_rod(
1111        d=d, l=l, pitch=pitch,
1112        profile=profile, 
1113        left_handed=left_handed,
1114        bevel=bevel,bevel1=bevel1,bevel2=bevel2,
1115        internal=internal, length=length, height=height, h=h,
1116        blunt_start=blunt_start, blunt_start1=blunt_start1, blunt_start2=blunt_start2,
1117        lead_in=lead_in, lead_in1=lead_in1, lead_in2=lead_in2, lead_in_shape=lead_in_shape,
1118        lead_in_ang=lead_in_ang, lead_in_ang1=lead_in_ang1, lead_in_ang2=lead_in_ang2,
1119        end_len=end_len, end_len1=end_len1, end_len2=end_len2,
1120        d1=d1,d2=d2,
1121        anchor=anchor,
1122        spin=spin,starts=starts,
1123        orient=orient
1124    ) children();
1125}
1126
1127
1128
1129// Module: buttress_threaded_nut()
1130// Synopsis: Creates a buttress-threaded nut.
1131// SynTags: Geom
1132// Topics: Threading, Screws
1133// See Also: buttress_threaded_rod()
1134// Usage:
1135//   buttress_threaded_nut(nutwidth, id, h|height|thickness, pitch, ...) [ATTACHMENTS];
1136// Description:
1137//   Constructs a hexagonal or square nut for a simple buttress threaded screw rod.  
1138// Arguments:
1139//   nutwidth = diameter of the nut.
1140//   id = inner diameter of threaded hole, measured from bottom of threads
1141//   h / height / l / length / thickness = height/thickness of nut.
1142//   pitch = Thread spacing. 
1143//   ---
1144//   shape = specifies shape of nut, either "hex" or "square".  Default: "hex"
1145//   left_handed = if true, create left-handed threads.  Default = false
1146//   starts = The number of lead starts.  Default: 1
1147//   bevel = if true, bevel the outside of the nut.  Default: true for hex nuts, false for square nuts
1148//   bevel1 = if true, bevel the outside of the nut bottom.
1149//   bevel2 = if true, bevel the outside of the nut top. 
1150//   bevang = set the angle for the outside nut bevel.  Default: 30
1151//   ibevel = if true, bevel the inside (the hole).   Default: true
1152//   ibevel1 = if true bevel the inside, bottom end.
1153//   ibevel2 = if true bevel the inside, top end.
1154//   blunt_start = If true apply truncated blunt start threads at both ends.  Default: true
1155//   blunt_start1 = If true apply truncated blunt start threads bottom end.
1156//   blunt_start2 = If true apply truncated blunt start threads top end.
1157//   end_len = Specify the unthreaded length at the end after blunt start threads.  Default: 0
1158//   end_len1 = Specify unthreaded length at the bottom
1159//   end_len2 = Specify unthreaded length at the top
1160//   lead_in = Specify linear length of the lead in section of the threading with blunt start threads
1161//   lead_in1 = Specify linear length of the lead in section of the threading at the bottom with blunt start threads
1162//   lead_in2 = Specify linear length of the lead in section of the threading at the top with blunt start threads
1163//   lead_in_ang = Specify angular length in degrees of the lead in section of the threading with blunt start threads
1164//   lead_in_ang1 = Specify angular length in degrees of the lead in section of the threading at the bottom with blunt start threads
1165//   lead_in_ang2 = Specify angular length in degrees of the lead in section of the threading at the top with blunt start threads
1166//   lead_in_shape = Specify the shape of the thread lead in by giving a text string or function.  Default: "default"
1167//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
1168//   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#subsection-spin).  Default: `0`
1169//   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
1170//   $slop = The printer-specific slop value, which adds clearance (`4*$slop`) to internal threads.
1171// Examples(Med):
1172//   buttress_threaded_nut(nutwidth=16, id=8, h=8, pitch=1.25, left_handed=true, $slop=0.05, $fa=1, $fs=1);
1173function buttress_threaded_nut(
1174    nutwidth, id, h,
1175    pitch, shape="hex", left_handed=false,
1176    bevel,bevel1,bevel2,bevang=30,starts=1,
1177    ibevel,ibevel1,ibevel2,height,thickness,
1178    length, l,
1179    blunt_start, blunt_start1, blunt_start2,
1180    lead_in, lead_in1, lead_in2,
1181    lead_in_ang, lead_in_ang1, lead_in_ang2,
1182    end_len, end_len1, end_len2,
1183    lead_in_shape="default",
1184    anchor, spin, orient
1185) = no_function("buttress_threaded_nut");
1186module buttress_threaded_nut(
1187    nutwidth, id, h,
1188    pitch, shape="hex", left_handed=false,
1189    bevel,bevel1,bevel2,bevang=30,starts=1,
1190    ibevel,ibevel1,ibevel2,height,thickness,
1191    length, l,
1192    blunt_start, blunt_start1, blunt_start2,
1193    lead_in, lead_in1, lead_in2,
1194    lead_in_ang, lead_in_ang1, lead_in_ang2,
1195    end_len, end_len1, end_len2,
1196    lead_in_shape="default",
1197    anchor, spin, orient
1198) {
1199    depth = pitch * 3/4;
1200    profile = [
1201        [  -1/2, -0.77],
1202        [ -7/16, -0.75],
1203        [  5/16,  0],
1204        [  7/16,  0],
1205        [  7/16, -0.75],
1206        [  1/ 2, -0.77],
1207    ];
1208    generic_threaded_nut(
1209        nutwidth=nutwidth, id=id, h=h,
1210        pitch=pitch,
1211        profile=profile,
1212        shape=shape,
1213        left_handed=left_handed,starts=starts,
1214        bevel=bevel,bevel1=bevel1,bevel2=bevel2,bevang=bevang,
1215        ibevel=ibevel,ibevel1=ibevel1,ibevel2=ibevel2,
1216        blunt_start=blunt_start, blunt_start1=blunt_start1, blunt_start2=blunt_start2,
1217        lead_in=lead_in, lead_in1=lead_in1, lead_in2=lead_in2, lead_in_shape=lead_in_shape,
1218        lead_in_ang=lead_in_ang, lead_in_ang1=lead_in_ang1, lead_in_ang2=lead_in_ang2,
1219        end_len=end_len, end_len1=end_len1, end_len2=end_len2,
1220        l=l,length=length,
1221        anchor=anchor, spin=spin, height=height, thickness=thickness, 
1222        orient=orient
1223    ) children();
1224}
1225
1226
1227
1228// Section: Square Threading
1229
1230// Module: square_threaded_rod()
1231// Synopsis: Creates a square-threaded rod.
1232// SynTags: Geom
1233// Topics: Threading, Screws
1234// See Also: square_threaded_nut()
1235// Usage:
1236//   square_threaded_rod(d, l|length, pitch, [internal=], ...) [ATTACHMENTS];
1237// Description:
1238//   Constructs a square profile threaded screw rod.  The greatest advantage of square threads is
1239//   that they have the least friction and a much higher intrinsic efficiency than trapezoidal threads.
1240//   They produce no radial load on the nut.  However, square threads cannot carry as much load as trapezoidal threads. 
1241// Arguments:
1242//   d = Outer diameter of threaded rod.
1243//   l / length / h / height = Length of threaded rod.
1244//   pitch = Thread spacing.
1245//   ---
1246//   left_handed = if true, create left-handed threads.  Default = false
1247//   starts = The number of lead starts.  Default = 1
1248//   bevel = if true, bevel the thread ends.  Default: false
1249//   bevel1 = if true bevel the bottom end.
1250//   bevel2 = if true bevel the top end. 
1251//   internal = If true, this is a mask for making internal threads.
1252//   blunt_start = If true apply truncated blunt start threads at both ends.  Default: true
1253//   blunt_start1 = If true apply truncated blunt start threads bottom end.
1254//   blunt_start2 = If true apply truncated blunt start threads top end.
1255//   end_len = Specify the unthreaded length at the end after blunt start threads.  Default: 0
1256//   end_len1 = Specify unthreaded length at the bottom
1257//   end_len2 = Specify unthreaded length at the top
1258//   lead_in = Specify linear length of the lead in section of the threading with blunt start threads
1259//   lead_in1 = Specify linear length of the lead in section of the threading at the bottom with blunt start threads
1260//   lead_in2 = Specify linear length of the lead in section of the threading at the top with blunt start threads
1261//   lead_in_ang = Specify angular length in degrees of the lead in section of the threading with blunt start threads
1262//   lead_in_ang1 = Specify angular length in degrees of the lead in section of the threading at the bottom with blunt start threads
1263//   lead_in_ang2 = Specify angular length in degrees of the lead in section of the threading at the top with blunt start threads
1264//   lead_in_shape = Specify the shape of the thread lead in by giving a text string or function.  Default: "default"
1265//   d1 = Bottom outside diameter of threads.
1266//   d2 = Top outside diameter of threads.
1267//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
1268//   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#subsection-spin).  Default: `0`
1269//   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
1270//   $slop = The printer-specific slop value, which adds clearance (`4*$slop`) to internal threads.
1271// Example(2D):
1272//   projection(cut=true)
1273//       square_threaded_rod(d=10, l=15, pitch=2, orient=BACK);
1274// Examples(Med):
1275//   square_threaded_rod(d=10, l=20, pitch=2, starts=2, $fn=32);
1276function square_threaded_rod(
1277    d, l, pitch,
1278    left_handed=false,
1279    bevel,bevel1,bevel2,
1280    starts=1,
1281    internal=false,
1282    d1, d2, length, h, height,
1283    blunt_start, blunt_start1, blunt_start2,
1284    lead_in, lead_in1, lead_in2,
1285    lead_in_ang, lead_in_ang1, lead_in_ang2,
1286    end_len, end_len1, end_len2,
1287    lead_in_shape="default",
1288    anchor, spin, orient
1289) = no_function("square_threaded_rod");
1290module square_threaded_rod(
1291    d, l, pitch,
1292    left_handed=false,
1293    bevel,bevel1,bevel2,
1294    starts=1,
1295    internal=false,
1296    d1, d2, length, h, height,
1297    blunt_start, blunt_start1, blunt_start2,
1298    lead_in, lead_in1, lead_in2,
1299    lead_in_ang, lead_in_ang1, lead_in_ang2,
1300    end_len, end_len1, end_len2,
1301    lead_in_shape="default",
1302    anchor, spin, orient
1303) {
1304    trapezoidal_threaded_rod(
1305        d=d, l=l, pitch=pitch,
1306        thread_angle=0.1,
1307        left_handed=left_handed,
1308        bevel=bevel,bevel1=bevel1,bevel2=bevel2,
1309        starts=starts,
1310        internal=internal, length=length, height=height, h=h,
1311        blunt_start=blunt_start, blunt_start1=blunt_start1, blunt_start2=blunt_start2,
1312        lead_in=lead_in, lead_in1=lead_in1, lead_in2=lead_in2, lead_in_shape=lead_in_shape,
1313        lead_in_ang=lead_in_ang, lead_in_ang1=lead_in_ang1, lead_in_ang2=lead_in_ang2,
1314        end_len=end_len, end_len1=end_len1, end_len2=end_len2,
1315        d1=d1,
1316        d2=d2,
1317        anchor=anchor,
1318        spin=spin,
1319        orient=orient
1320    ) children();
1321}
1322
1323
1324
1325// Module: square_threaded_nut()
1326// Synopsis: Creates a square-threaded nut.
1327// SynTags: Geom
1328// Topics: Threading, Screws
1329// See Also: square_threaded_rod()
1330// Usage:
1331//   square_threaded_nut(nutwidth, id, h|height|thickness, pitch, ...) [ATTACHMENTS];
1332// Description:
1333//   Constructs a hexagonal or square nut for a square profile threaded screw rod.  
1334// Arguments:
1335//   nutwidth = diameter of the nut.
1336//   id = inner diameter of threaded hole, measured from bottom of threads
1337//   h / height / l / length / thickness = height/thickness of nut.
1338//   pitch = Length between threads.
1339//   ---
1340//   shape = specifies shape of nut, either "hex" or "square".  Default: "hex"
1341//   left_handed = if true, create left-handed threads.  Default = false
1342//   starts = The number of lead starts.  Default = 1
1343//   bevel = if true, bevel the outside of the nut.  Default: true for hex nuts, false for square nuts
1344//   bevel1 = if true, bevel the outside of the nut bottom.
1345//   bevel2 = if true, bevel the outside of the nut top. 
1346//   bevang = set the angle for the outside nut bevel.  Default: 30
1347//   ibevel = if true, bevel the inside (the hole).   Default: true
1348//   ibevel1 = if true bevel the inside, bottom end.
1349//   ibevel2 = if true bevel the inside, top end.
1350//   blunt_start = If true apply truncated blunt start threads at both ends.  Default: true
1351//   blunt_start1 = If true apply truncated blunt start threads bottom end.
1352//   blunt_start2 = If true apply truncated blunt start threads top end.
1353//   end_len = Specify the unthreaded length at the end after blunt start threads.  Default: 0
1354//   end_len1 = Specify unthreaded length at the bottom
1355//   end_len2 = Specify unthreaded length at the top
1356//   lead_in = Specify linear length of the lead in section of the threading with blunt start threads
1357//   lead_in1 = Specify linear length of the lead in section of the threading at the bottom with blunt start threads
1358//   lead_in2 = Specify linear length of the lead in section of the threading at the top with blunt start threads
1359//   lead_in_ang = Specify angular length in degrees of the lead in section of the threading with blunt start threads
1360//   lead_in_ang1 = Specify angular length in degrees of the lead in section of the threading at the bottom with blunt start threads
1361//   lead_in_ang2 = Specify angular length in degrees of the lead in section of the threading at the top with blunt start threads
1362//   lead_in_shape = Specify the shape of the thread lead in by giving a text string or function.  Default: "default"
1363//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
1364//   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#subsection-spin).  Default: `0`
1365//   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
1366//   $slop = The printer-specific slop value, which adds clearance (`4*$slop`) to internal threads.
1367// Examples(Med):
1368//   square_threaded_nut(nutwidth=16, id=10, h=10, pitch=2, starts=2, $slop=0.1, $fn=32);
1369function square_threaded_nut(
1370    nutwidth, id, h,
1371    pitch,
1372    left_handed=false,
1373    bevel,bevel1,bevel2,bevang=30,
1374    ibevel,ibevel1,ibevel2,
1375    height,thickness,    
1376    length, l,
1377    blunt_start, blunt_start1, blunt_start2,
1378    lead_in, lead_in1, lead_in2,
1379    lead_in_ang, lead_in_ang1, lead_in_ang2,
1380    end_len, end_len1, end_len2,
1381    lead_in_shape="default",
1382    starts=1,
1383    anchor, spin, orient
1384) = no_function("square_threaded_nut");
1385module square_threaded_nut(
1386    nutwidth, id, h,
1387    pitch,
1388    left_handed=false,
1389    bevel,bevel1,bevel2,bevang=30,
1390    ibevel,ibevel1,ibevel2,
1391    height,thickness,    
1392    length, l,
1393    blunt_start, blunt_start1, blunt_start2,
1394    lead_in, lead_in1, lead_in2,
1395    lead_in_ang, lead_in_ang1, lead_in_ang2,
1396    end_len, end_len1, end_len2,
1397    lead_in_shape="default",
1398    starts=1,
1399    anchor, spin, orient
1400) {
1401    assert(is_num(pitch) && pitch>=0)
1402    trapezoidal_threaded_nut(
1403        nutwidth=nutwidth, id=id, h=h, pitch=pitch,
1404        thread_angle=0,
1405        left_handed=left_handed,
1406        bevel=bevel,bevel1=bevel1,bevel2=bevel2, bevang=bevang,
1407        ibevel=ibevel, ibevel1=ibevel1, ibevel2=ibevel2,
1408        height=height,thickness=thickness,
1409        starts=starts,
1410        blunt_start=blunt_start, blunt_start1=blunt_start1, blunt_start2=blunt_start2,
1411        lead_in=lead_in, lead_in1=lead_in1, lead_in2=lead_in2, lead_in_shape=lead_in_shape,
1412        lead_in_ang=lead_in_ang, lead_in_ang1=lead_in_ang1, lead_in_ang2=lead_in_ang2,
1413        end_len=end_len, end_len1=end_len1, end_len2=end_len2,
1414        l=l,length=length,
1415        anchor=anchor,
1416        spin=spin,
1417        orient=orient
1418    ) children();
1419}
1420
1421
1422// Section: Ball Screws
1423
1424// Module: ball_screw_rod()
1425// Synopsis: Creates a ball screw rod.
1426// SynTags: Geom
1427// Topics: Threading, Screws
1428// Usage:
1429//   ball_screw_rod(d, l|length, pitch, [ball_diam], [ball_arc], [internal=], ...) [ATTACHMENTS];
1430// Description:
1431//   Constructs a ball screw rod.  This type of rod is used with ball bearings.  
1432// Arguments:
1433//   d = Outer diameter of threaded rod.
1434//   l / length / h / height = Length of threaded rod.
1435//   pitch = Thread spacing. Also, the diameter of the ball bearings used.
1436//   ball_diam = The diameter of the ball bearings to use with this ball screw.
1437//   ball_arc = The arc portion that should touch the ball bearings. Default: 120 degrees.
1438//   ---
1439//   left_handed = if true, create left-handed threads.  Default = false
1440//   starts = The number of lead starts.  Default = 1
1441//   bevel = if true, bevel the thread ends.  Default: false
1442//   bevel1 = if true bevel the bottom end.
1443//   bevel2 = if true bevel the top end. 
1444//   internal = If true, make this a mask for making internal threads.
1445//   blunt_start = If true apply truncated blunt start threads at both ends.  Default: true
1446//   blunt_start1 = If true apply truncated blunt start threads bottom end.
1447//   blunt_start2 = If true apply truncated blunt start threads top end.
1448//   end_len = Specify the unthreaded length at the end after blunt start threads.  Default: 0
1449//   end_len1 = Specify unthreaded length at the bottom
1450//   end_len2 = Specify unthreaded length at the top
1451//   lead_in = Specify linear length of the lead in section of the threading with blunt start threads
1452//   lead_in1 = Specify linear length of the lead in section of the threading at the bottom with blunt start threads
1453//   lead_in2 = Specify linear length of the lead in section of the threading at the top with blunt start threads
1454//   lead_in_ang = Specify angular length in degrees of the lead in section of the threading with blunt start threads
1455//   lead_in_ang1 = Specify angular length in degrees of the lead in section of the threading at the bottom with blunt start threads
1456//   lead_in_ang2 = Specify angular length in degrees of the lead in section of the threading at the top with blunt start threads
1457//   lead_in_shape = Specify the shape of the thread lead in by giving a text string or function.  Default: "default"
1458//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
1459//   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#subsection-spin).  Default: `0`
1460//   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
1461//   $slop = The printer-specific slop value, which adds clearance (`4*$slop`) to internal threads.
1462// Example(2D): Thread Profile, ball_diam=4, ball_arc=100
1463//   projection(cut=true) ball_screw_rod(d=10, l=15, pitch=5, ball_diam=4, ball_arc=100, orient=BACK, $fn=24, blunt_start=false);
1464// Example(2D): Thread Profile, ball_diam=4, ball_arc=120
1465//   projection(cut=true) ball_screw_rod(d=10, l=15, pitch=5, ball_diam=4, ball_arc=120, orient=BACK, $fn=24, blunt_start=false);
1466// Example(2D): Thread Profile, ball_diam=3, ball_arc=120
1467//   projection(cut=true) ball_screw_rod(d=10, l=15, pitch=5, ball_diam=3, ball_arc=120, orient=BACK, $fn=24, blunt_start=false);
1468// Examples(Med):
1469//   ball_screw_rod(d=15, l=20, pitch=8, ball_diam=5, ball_arc=120, $fa=1, $fs=0.5, blunt_start=false);
1470//   ball_screw_rod(d=15, l=20, pitch=5, ball_diam=4, ball_arc=120, $fa=1, $fs=0.5, blunt_start=false);
1471//   ball_screw_rod(d=15, l=20, pitch=5, ball_diam=4, ball_arc=120, left_handed=true, $fa=1, $fs=0.5, blunt_start=false);
1472function ball_screw_rod(
1473    d, l, pitch, 
1474    ball_diam=5, ball_arc=100,
1475    starts=1,
1476    left_handed=false,
1477    internal=false,
1478    length, h, height,
1479    bevel, bevel1, bevel2,
1480    blunt_start, blunt_start1, blunt_start2,
1481    lead_in, lead_in1, lead_in2,
1482    lead_in_ang, lead_in_ang1, lead_in_ang2,
1483    end_len, end_len1, end_len2,
1484    lead_in_shape="default",
1485    anchor, spin, orient
1486) = no_function("ball_screw_rod");
1487module ball_screw_rod(
1488    d, l, pitch, 
1489    ball_diam=5, ball_arc=100,
1490    starts=1,
1491    left_handed=false,
1492    internal=false,
1493    length, h, height,
1494    bevel, bevel1, bevel2,
1495    blunt_start, blunt_start1, blunt_start2,
1496    lead_in, lead_in1, lead_in2,
1497    lead_in_ang, lead_in_ang1, lead_in_ang2,
1498    end_len, end_len1, end_len2,
1499    lead_in_shape="default",
1500    anchor, spin, orient
1501) {
1502    n = max(3,ceil(segs(ball_diam/2)*ball_arc/2/360));
1503    depth = ball_diam * (1-cos(ball_arc/2))/2;
1504    cpy = ball_diam/2/pitch*cos(ball_arc/2);
1505    profile = [
1506        each arc(n=n, d=ball_diam/pitch, cp=[-0.5,cpy], start=270, angle=ball_arc/2),
1507        each arc(n=n, d=ball_diam/pitch, cp=[+0.5,cpy], start=270-ball_arc/2, angle=ball_arc/2)
1508    ];
1509    generic_threaded_rod(
1510        d=d, l=l, pitch=pitch,
1511        profile=profile,
1512        left_handed=left_handed,
1513        starts=starts,
1514        bevel=bevel,bevel1=bevel1,bevel2=bevel2,
1515        internal=internal, length=length, height=height, h=h,
1516        blunt_start=blunt_start, blunt_start1=blunt_start1, blunt_start2=blunt_start2,
1517        lead_in=lead_in, lead_in1=lead_in1, lead_in2=lead_in2, lead_in_shape=lead_in_shape,
1518        lead_in_ang=lead_in_ang, lead_in_ang1=lead_in_ang1, lead_in_ang2=lead_in_ang2,
1519        end_len=end_len, end_len1=end_len1, end_len2=end_len2,
1520        anchor=anchor,
1521        spin=spin,
1522        orient=orient
1523    ) children();
1524}
1525
1526
1527// Section: Generic Threading
1528
1529// Module: generic_threaded_rod()
1530// Synopsis: Creates a generic threaded rod.
1531// SynTags: Geom
1532// Topics: Threading, Screws
1533// See Also: generic_threaded_nut()
1534// Usage:
1535//   generic_threaded_rod(d, l|length, pitch, profile, [internal=], ...) [ATTACHMENTS];
1536// Description:
1537//   Constructs a generic threaded rod using an arbitrary thread profile that you supply.  The rod can be tapered
1538//   (e.g. for pipe threads).  For specific thread types use other modules that supply the appropriate profile.
1539//   .
1540//   You give the profile as a 2D path that will be scaled by the pitch to produce the final thread shape.  The profile
1541//   X values must be between -1/2 and 1/2.  The Y=0 point will align with the specified rod diameter, so generally you
1542//   want a Y value of zero at the peak (which makes your specified diameter the outer diameter of the threads).  The
1543//   value in the valleys of the thread should then be `-depth/pitch` due to the scaling by the thread pitch.  The first
1544//   and last points should generally have the same Y value, but it is not necessary to give values at X=1/2 or X=-1/2
1545//   if unless the Y values differ from the interior points in the profile.  Generally you should center the profile
1546//   horizontally in the interval [-1/2, 1/2].
1547//   .
1548//   If internal is true then produce a thread mask to difference from an object.  When internal is true the rod
1549//   diameter is enlarged to correct for the polygonal nature of circles to ensure that the internal diameter is the
1550//   specified size.  The diameter is also increased by `4 * $slop` to create clearance for threading by allowing a `2 *
1551//   $slop` gap on each side.  If bevel is set to true and internal is false then the ends of the rod will be beveled.
1552//   When bevel is true and internal is true the ends of the rod will be filled in so that the rod mask will create a
1553//   bevel when subtracted from an object.  The bevel is at 45 deg and is the depth of the threads.
1554//   .
1555//   Blunt start threading, which is the default, specifies that the thread ends abruptly at its full width instead of
1556//   running off the end of the shaft and leaving a sharp edged partial thread at the end of the screw.  This makes
1557//   screws easier to start and prevents cross threading.  Blunt start threads should always be superior, and they are
1558//   faster to model, but if you really need standard threads that run off the end you can set `blunt_start=false`.
1559// Arguments:
1560//   d = Outer diameter of threaded rod.
1561//   l / length / h / height = Length of threaded rod.
1562//   pitch = Thread spacing.
1563//   profile = A 2D path giving the shape of a thread
1564//   ---
1565//   left_handed = If true, create left-handed threads.  Default: false
1566//   starts = The number of lead starts.  Default: 1
1567//   internal = If true, make this a mask for making internal threads.  Default: false
1568//   d1 = Bottom outside diameter of threads.
1569//   d2 = Top outside diameter of threads.
1570//   bevel = set to true to bevel both ends, a number to specify a bevel size, false for no bevel, and "reverse" for an inverted bevel
1571//   bevel1 = set bevel for bottom end. 
1572//   bevel2 = set bevel for top end.
1573//   blunt_start = If true apply truncated blunt start threads at both ends.  Default: true
1574//   blunt_start1 = If true apply truncated blunt start threads bottom end.
1575//   blunt_start2 = If true apply truncated blunt start threads top end.
1576//   end_len = Specify the unthreaded length at the end after blunt start threads.  Default: 0
1577//   end_len1 = Specify unthreaded length at the bottom
1578//   end_len2 = Specify unthreaded length at the top
1579//   lead_in = Specify linear length of the lead in section of the threading with blunt start threads
1580//   lead_in1 = Specify linear length of the lead in section of the threading at the bottom with blunt start threads
1581//   lead_in2 = Specify linear length of the lead in section of the threading at the top with blunt start threads
1582//   lead_in_ang = Specify angular length in degrees of the lead in section of the threading with blunt start threads
1583//   lead_in_ang1 = Specify angular length in degrees of the lead in section of the threading at the bottom with blunt start threads
1584//   lead_in_ang2 = Specify angular length in degrees of the lead in section of the threading at the top with blunt start threads
1585//   lead_in_shape = Specify the shape of the thread lead in by giving a text string or function.  Default: "default"
1586//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
1587//   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#subsection-spin).  Default: `0`
1588//   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
1589//   $slop = The printer-specific slop value, which adds clearance (`4*$slop`) to internal threads.
1590// Example(2DMed): Example Tooth Profile
1591//   pitch = 2;
1592//   depth = pitch * cos(30) * 5/8;
1593//   profile = [
1594//       [-7/16, -depth/pitch*1.07],
1595//       [-6/16, -depth/pitch],
1596//       [-1/16,  0],
1597//       [ 1/16,  0],
1598//       [ 6/16, -depth/pitch],
1599//       [ 7/16, -depth/pitch*1.07]
1600//   ];
1601//   stroke(profile, width=0.02);
1602// Example:
1603//   pitch = 2;
1604//   depth = pitch * cos(30) * 5/8;
1605//   profile = [
1606//       [-7/16, -depth/pitch*1.07],
1607//       [-6/16, -depth/pitch],
1608//       [-1/16,  0],
1609//       [ 1/16,  0],
1610//       [ 6/16, -depth/pitch],
1611//       [ 7/16, -depth/pitch*1.07]
1612//   ];
1613//   generic_threaded_rod(d=10, l=40, pitch=2, profile=profile);
1614
1615function generic_threaded_rod(
1616    d, l, pitch, profile,
1617    left_handed=false, internal=false,
1618    bevel, bevel1, bevel2, 
1619    starts=1,
1620    d1, d2, length, h, height,
1621    blunt_start, blunt_start1, blunt_start2,
1622    lead_in, lead_in1, lead_in2,
1623    lead_in_ang, lead_in_ang1, lead_in_ang2,
1624    end_len, end_len1, end_len2,
1625    lead_in_shape="default",
1626    anchor, spin, orient
1627) = no_function("generic_threaded_rod");
1628module generic_threaded_rod(
1629    d, l, pitch, profile,
1630    left_handed=false, internal=false,
1631    bevel, bevel1, bevel2, 
1632    starts=1,
1633    d1, d2, length, h, height,
1634    blunt_start, blunt_start1, blunt_start2,
1635    lead_in, lead_in1, lead_in2,
1636    lead_in_ang, lead_in_ang1, lead_in_ang2,
1637    end_len, end_len1, end_len2,
1638    lead_in_shape="default",
1639    anchor, spin, orient
1640) {
1641    len = one_defined([l,length,h,height],"l,length,h,height");
1642    bevel1 = first_defined([bevel1,bevel]);
1643    bevel2 = first_defined([bevel2,bevel]);
1644    blunt_start1 = first_defined([blunt_start1, blunt_start, true]);
1645    blunt_start2 = first_defined([blunt_start2, blunt_start, true]);                           
1646    r1 = get_radius(d1=d1, d=d);
1647    r2 = get_radius(d1=d2, d=d);
1648    lead_in1 = first_defined([lead_in1, lead_in]);
1649    lead_in2 = first_defined([lead_in2, lead_in]);
1650    lead_in_func = is_func(lead_in_shape) ? lead_in_shape
1651                 : assert(is_string(lead_in_shape),"lead_in_shape must be a function or string")
1652                   let(ind = search([lead_in_shape], _lead_in_table,0)[0])
1653                   assert(ind!=[],str("Unknown lead_in_shape, \"",lead_in_shape,"\""))
1654                   _lead_in_table[ind[0]][1];
1655    dummy0 = 
1656      assert(all_positive([pitch]),"Thread pitch must be a positive value")
1657      assert(all_positive([len]),"Length must be a postive value")
1658      assert(is_path(profile),"Profile must be a path")
1659      assert(is_bool(blunt_start1), "blunt_start1/blunt_start must be boolean")
1660      assert(is_bool(blunt_start2), "blunt_start2/blunt_start must be boolean")
1661      assert(is_bool(left_handed))
1662      assert(all_positive([r1,r2]), "Must give d or both d1 and d2 as positive values")
1663      assert(is_undef(bevel1) || is_num(bevel1) || is_bool(bevel1) || bevel1=="reverse", "bevel1/bevel must be a number, boolean or \"reverse\"")
1664      assert(is_undef(bevel2) || is_num(bevel2) || is_bool(bevel2) || bevel2=="reverse", "bevel2/bevel must be a number, boolean or \"reverse\"");
1665    sides = quantup(segs(max(r1,r2)), starts);
1666    rsc = internal? (1/cos(180/sides)) : 1;    // Internal radius adjusted for faceting
1667    islop = internal? 2*get_slop() : 0;
1668    r1adj = r1 * rsc + islop;
1669    r2adj = r2 * rsc + islop;
1670
1671    extreme = internal? max(column(profile,1)) : min(column(profile,1));
1672    profile = !internal ? profile
1673            : let(
1674                 maxidx = [for(i=idx(profile)) if (profile[i].y==extreme) i],
1675                 cutpt = len(maxidx)==1 ? profile(maxidx[0]).x
1676                       : mean([profile[maxidx[0]].x, profile[maxidx[1]].x])
1677              )
1678              [
1679                 for(entry=profile) if (entry.x>=cutpt) [entry.x-cutpt-1/2,entry.y], 
1680                 for(entry=profile) if (entry.x<cutpt) [entry.x-cutpt+1/2,entry.y]
1681              ];
1682    profmin = pitch * min(column(profile,1));
1683    pmax = pitch * max(column(profile,1));
1684    rmax = max(r1adj,r2adj)+pmax;
1685
1686    // These parameters give the size of the bevel, negative for an outward bevel (e.g. on internal thread mask)  
1687    bev1 = (bevel1=="reverse"?-1:1)*(internal?-1:1) *
1688               ( is_num(bevel1)? bevel1
1689               : bevel1==false? 0
1690               : blunt_start1? (bevel1==undef?0
1691                               :internal ? r1/6
1692                               :(r1+profmin)/6)
1693               : pmax-profmin);
1694    bev2 = (bevel2=="reverse"?-1:1)*(internal?-1:1) *
1695               ( is_num(bevel2)? bevel2
1696               : bevel2==false? 0
1697               : blunt_start2? (bevel2==undef?0
1698                               :internal ? r2/6
1699                               :(r2+profmin)/6)
1700               : pmax-profmin);
1701    // This is the bevel size used for constructing the polyhedron.  The bevel is integrated when blunt start is on, but
1702    // applied later via difference/union if blunt start is off, so set bevel to zero in the latter case.  
1703    bevel_size1 = blunt_start1?bev1:0;
1704    bevel_size2 = blunt_start2?bev2:0;
1705    // This is the bevel size for clipping, which is only done when blunt start is off
1706    clip_bev1 = blunt_start1?0:bev1;
1707    clip_bev2 = blunt_start2?0:bev2;
1708    end_len1_base = !blunt_start1? 0 : first_defined([end_len1,end_len, 0]);
1709    end_len2_base = !blunt_start2? 0 : first_defined([end_len2,end_len, 0]);    
1710    // Enlarge end lengths to give sufficient room for requested bevel
1711    end_len1 = abs(bevel_size1)>0 ? max(end_len1_base, abs(bevel_size1)) : end_len1_base;
1712    end_len2 = abs(bevel_size2)>0 ? max(end_len2_base, abs(bevel_size2)) : end_len2_base;
1713    // length to create below/above z=0, with an extra revolution in non-blunt-start case so
1714    // the threads can continue to the specified length and we can clip off the blunt start                       
1715    len1 = -len/2 - (blunt_start1?0:pitch);   
1716    len2 =  len/2 + (blunt_start2?0:pitch);
1717
1718    // Thread turns below and above z=0, with extra to ensure we go beyond the length needed
1719    turns1 = len1/pitch-1;
1720    turns2 = len2/pitch+1;
1721    dir = left_handed? -1 : 1;
1722    dummy2=
1723        assert(abs(bevel_size1)+abs(bevel_size2)<len, "Combined bevel size exceeds length of screw")
1724        assert(r1adj+extreme*pitch-bevel_size1>0, "bevel1 is too large to fit screw diameter")
1725        assert(r2adj+extreme*pitch-bevel_size2>0, "bevel2 is too large to fit screw diameter");
1726         
1727    margin1 = profile[0].y==extreme ? profile[0].x : -1/2;
1728    margin2 = last(profile).y==extreme? last(profile).x : 1/2;
1729    lead_in_default = pmax-profmin;//2*pitch;
1730        // 0*360/10;// /4/32*360; higlen_default;//0*4/32*360; //2/32*360;//360*max(pitch/2, pmax-depth)/(2*PI*r2adj);
1731    // lead_in length needs to be quantized to match the samples
1732    lead_in_ang1 = !blunt_start1? 0 :
1733         let(
1734             user_ang = first_defined([lead_in_ang1,lead_in_ang])
1735         )
1736         assert(is_undef(user_ang) || is_undef(lead_in1), "Cannot define lead_in/lead_in1 by both length and angle")
1737         quantup(
1738                 is_def(user_ang) ? user_ang : default(lead_in1, lead_in_default)*360/(2*PI*r1adj)
1739                 , 360/sides);
1740    lead_in_ang2 = !blunt_start2? 0 :
1741         let(
1742             user_ang = first_defined([lead_in_ang2,lead_in_ang])
1743         )
1744         assert(is_undef(user_ang) || is_undef(lead_in2), "Cannot define lead_in/lead_in2 by both length and angle")
1745         quantup(
1746                 is_def(user_ang) ? user_ang : default(lead_in2, lead_in_default)*360/(2*PI*r2adj)
1747                 , 360/sides);
1748    // cut_ang also need to be quantized, but the comparison is offset by 36*turns1/starts, so we need to pull that factor out
1749    // of the quantization.  (The loop over angle starts at 360*turns1/starts, not at a multiple of 360/sides.)  
1750//    cut_ang1 = 360 * (len1/pitch-margin1+end_len1/pitch) / starts + lead_in_ang1;
1751//    cut_ang2 = 360 * (len2/pitch-margin2-end_len2/pitch) / starts - lead_in_ang2;
1752    cut_ang1 = quantup(360 * (len1/pitch-margin1+end_len1/pitch) / starts + lead_in_ang1-360*turns1/starts,360/sides)+360*turns1/starts;
1753    cut_ang2 = quantdn(360 * (len2/pitch-margin2-end_len2/pitch) / starts - lead_in_ang2-360*turns1/starts,360/sides)+360*turns1/starts;
1754    dummy1 =
1755      assert(cut_ang1<cut_ang2, "lead in length are too long for the amount of thread: they overlap")
1756      assert(is_num(lead_in_ang1), "lead_in1/lead_in must be a number")
1757      assert(r1adj+profmin>0 && r2adj+profmin>0, "Screw profile deeper than rod radius");
1758    map_threads = right((r1adj + r2adj) / 2)                   // Shift profile out to thread radius
1759                * affine3d_skew(sxz=(r2adj-r1adj)/len)         // Skew correction for tapered threads
1760                * frame_map(x=[0,0,1], y=[1,0,0])          // Map profile to 3d, parallel to z axis
1761                * scale(pitch);                            // scale profile by pitch
1762    start_steps = sides / starts;
1763
1764    // This is the location for clipping the polyhedron, below the bevel, if one is present, or at length otherwise
1765    // Clipping is done before scaling to pitch, so we need to divide by the pitch
1766    rod_clip1 = (len1+abs(bevel_size1))/pitch;
1767    rod_clip2 = (len2-abs(bevel_size2))/pitch;
1768    prof3d=path3d(profile,1);
1769    thread_verts = [
1770        // Outer loop constructs a vertical column of the screw at each angle
1771        // covering 360/starts degrees of the cylinder.  
1772        for (step = [0:1:start_steps])
1773            let(
1774                ang = 360 * step/sides,
1775                dz = step / start_steps,    // z offset for threads at this angle
1776                rot_prof = zrot(ang*dir)*map_threads,   // Rotate profile to correct angular location
1777                full_profile =  [   // profile for the entire rod
1778                    for (turns = [turns1:1:turns2]) 
1779                        let(
1780                            tang = turns/starts * 360 + ang,
1781                            // EPSILON offset prevents funny looking extensions of the thread from its very tip
1782                            // by forcing values near the tip to evaluate as less than zero = beyond the tip end
1783                            hsc = tang < cut_ang1 ? lead_in_func(-EPSILON+1-(cut_ang1-tang)/lead_in_ang1,PI*2*r1adj*lead_in_ang1/360 )
1784                                : tang > cut_ang2 ? lead_in_func(-EPSILON+1-(tang-cut_ang2)/lead_in_ang2,PI*2*r2adj*lead_in_ang2/360 )
1785                                : [1,1],
1786                            shift_and_scale = [[hsc.x, 0], [0,hsc.y], [dz+turns,(1-hsc.y)*extreme]]
1787                        )
1788                        // This is equivalent to apply(right(dz+turns)*higscale, profile)
1789                        //
1790                        // The right movement finds the position of the thread along
1791                        // what will be the z axis after the profile is mapped to 3d,
1792                        // and higscale creates a taper and the end of the threads.  
1793                        each prof3d*shift_and_scale
1794                ],
1795                // Clip profile at the ends of the rod and add a z coordinate
1796                full_profile_clipped = [
1797                    for(pts=full_profile) [max(rod_clip1,min(rod_clip2,pts.x)), pts.y, 0]
1798                ]
1799            )
1800            [
1801              [0,0,len1],
1802              //if (true) apply(rot_prof, [len1/pitch,extreme+2/pitch ,0]), 
1803              if (bevel_size1) apply(rot_prof, [len1/pitch,extreme-bevel_size1/pitch ,0]), 
1804              each apply(rot_prof, full_profile_clipped),
1805              if (bevel_size2) apply(rot_prof, [len2/pitch,extreme-bevel_size2/pitch ,0]), 
1806              //if (true) apply(rot_prof, [len2/pitch,extreme+2/pitch ,0]), 
1807              [0, 0, len2]
1808            ]
1809    ];
1810    style=internal?"concave":"convex";
1811    thread_vnf = vnf_join([
1812                           for (i=[0:1:starts-1])
1813                             zrot(i*360/starts, p=vnf_vertex_array(thread_verts, reverse=left_handed, style=style,col_wrap=false)),
1814                          ]);
1815    slope = (r1adj-r2adj)/len;
1816    dummy3 = 
1817      assert(r1adj+pmax-clip_bev1>0, "bevel1 is too large to fit screw diameter")
1818      assert(r2adj+pmax-clip_bev2>0, "bevel2 is too large to fit screw diameter")
1819      assert(abs(clip_bev1)+abs(clip_bev2)<len, "Combined bevel size exceeds length of screw");
1820    attachable(anchor,spin,orient, r1=r1adj, r2=r2adj, l=len) {
1821        union(){
1822          difference() {
1823              vnf_polyhedron(thread_vnf,convexity=10);              
1824              if (clip_bev1>0)
1825                  rotate_extrude()
1826                      polygon([[                         0,-len/2],
1827                               [r1adj+pmax-clip_bev1      ,-len/2],
1828                               [r1adj+pmax-slope*clip_bev1,-len/2+clip_bev1],
1829                               [                    rmax+1,-len/2+clip_bev1],
1830                               [                    rmax+1, len1-1],
1831                               [                         0, len1-1]]);
1832              if (clip_bev2>0)
1833                  rotate_extrude()
1834                      polygon([[                         0, len/2],
1835                               [r2adj+pmax-clip_bev2      , len/2],
1836                               [r2adj+pmax+slope*clip_bev2, len/2-clip_bev2],
1837                               [                    rmax+1, len/2-clip_bev2],
1838                               [                    rmax+1, len2+1],
1839                               [                         0, len2+1]]);
1840              if (!blunt_start1 && clip_bev1<=0)
1841                  down(len/2) cuboid([2*rmax+1,2*rmax+1, -len1+1], anchor=TOP);                     
1842              if (!blunt_start2 && clip_bev2<=0)
1843                  up(len/2) cuboid([2*rmax+1,2*rmax+1, len2+1], anchor=BOTTOM);
1844          }
1845
1846          // Add bevel for internal thread mask
1847          if (clip_bev1<0) 
1848              down(len/2+.001)cyl(l=-clip_bev1, r2=r1adj+profmin, r1=r1adj+profmin+slope*clip_bev1-clip_bev1,anchor=BOTTOM);
1849          if (clip_bev2<0) 
1850              up(len/2+.001)cyl(l=-clip_bev2, r1=r2adj+profmin, r2=r2adj+profmin+slope*clip_bev1-clip_bev2,anchor=TOP);
1851        }
1852        children();
1853    }
1854}
1855
1856
1857
1858// Module: generic_threaded_nut()
1859// Synopsis: Creates a generic threaded nut.
1860// SynTags: Geom
1861// Topics: Threading, Screws
1862// See Also: generic_threaded_rod()
1863// Usage:
1864//   generic_threaded_nut(nutwidth, id, h|height|thickness, pitch, profile, [$slop], ...) [ATTACHMENTS];
1865// Description:
1866//   Constructs a hexagonal or square nut for an generic threaded rod using a user-supplied thread profile.
1867//   See {{generic_threaded_rod()}} for details on the profile specification.  
1868// Arguments:
1869//   nutwidth = outer dimension of nut from flat to flat.
1870//   id = inner diameter of threaded hole, measured from bottom of threads
1871//   h / height / thickness = height/thickness of nut.
1872//   pitch = Thread spacing.
1873//   profile = Thread profile.
1874//   ---
1875//   shape = specifies shape of nut, either "hex" or "square".  Default: "hex"
1876//   left_handed = if true, create left-handed threads.  Default = false
1877//   starts = The number of lead starts.  Default = 1
1878//   id1 = inner diameter at the bottom
1879//   id2 = inner diameter at the top
1880//   bevel = if true, bevel the outside of the nut.  Default: true for hex nuts, false for square nuts
1881//   bevel1 = if true, bevel the outside of the nut bottom.
1882//   bevel2 = if true, bevel the outside of the nut top. 
1883//   bevang = set the angle for the outside nut bevel.  Default: 30
1884//   ibevel = if true, bevel the inside (the hole).   Default: true
1885//   ibevel1 = if true bevel the inside, bottom end.
1886//   ibevel2 = if true bevel the inside, top end.
1887//   blunt_start = If true apply truncated blunt start threads at both ends.  Default: true
1888//   blunt_start1 = If true apply truncated blunt start threads bottom end.
1889//   blunt_start2 = If true apply truncated blunt start threads top end.
1890//   end_len = Specify the unthreaded length at the end after blunt start threads.  Default: 0
1891//   end_len1 = Specify unthreaded length at the bottom
1892//   end_len2 = Specify unthreaded length at the top
1893//   lead_in = Specify linear length of the lead in section of the threading with blunt start threads
1894//   lead_in1 = Specify linear length of the lead in section of the threading at the bottom with blunt start threads
1895//   lead_in2 = Specify linear length of the lead in section of the threading at the top with blunt start threads
1896//   lead_in_ang = Specify angular length in degrees of the lead in section of the threading with blunt start threads
1897//   lead_in_ang1 = Specify angular length in degrees of the lead in section of the threading at the bottom with blunt start threads
1898//   lead_in_ang2 = Specify angular length in degrees of the lead in section of the threading at the top with blunt start threads
1899//   lead_in_shape = Specify the shape of the thread lead in by giving a text string or function.  Default: "default"
1900//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
1901//   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#subsection-spin).  Default: `0`
1902//   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
1903//   $slop = The printer-specific slop value, which adds clearance (`4*$slop`) to internal threads.
1904function generic_threaded_nut(
1905    nutwidth,
1906    id,
1907    h,
1908    pitch,
1909    profile,
1910    shape="hex",
1911    left_handed=false,
1912    starts=1,
1913    bevel,bevel1,bevel2,bevang=30,
1914    ibevel, ibevel1, ibevel2,
1915    id1,id2, height, thickness, 
1916    length, l,
1917    blunt_start, blunt_start1, blunt_start2,
1918    lead_in, lead_in1, lead_in2,
1919    lead_in_ang, lead_in_ang1, lead_in_ang2,
1920    end_len, end_len1, end_len2,
1921    lead_in_shape="default",
1922    anchor, spin, orient
1923) = no_function("generic_threaded_nut");
1924module generic_threaded_nut(
1925    nutwidth,
1926    id,
1927    h,
1928    pitch,
1929    profile,
1930    shape="hex",
1931    left_handed=false,
1932    starts=1,
1933    bevel,bevel1,bevel2,bevang=30,
1934    ibevel, ibevel1, ibevel2,
1935    id1,id2, height, thickness, 
1936    length, l,
1937    blunt_start, blunt_start1, blunt_start2,
1938    lead_in, lead_in1, lead_in2,
1939    lead_in_ang, lead_in_ang1, lead_in_ang2,
1940    end_len, end_len1, end_len2,
1941    lead_in_shape="default",
1942    anchor, spin, orient
1943) {
1944    
1945    extra = 0.01;
1946    id1 = first_defined([id1,id]);
1947    id2 = first_defined([id2,id]);
1948    h = one_defined([h,height,thickness,l,length],"h,height,thickness,l,length");
1949    dummyA = assert(is_num(pitch) && pitch>=0, "pitch must be a nonnegative number")
1950             assert(is_num(h) && h>0, "height/thickness must be a positive number")
1951             assert(in_list(shape,["square","hex"]), "shape must be \"hex\" or \"square\"")
1952             assert(all_positive([id1,id2]), "Inner diameter(s) of nut must be positive number(s)");
1953    slope = (id2-id1)/h;
1954    full_id1 = id1-slope*extra/2;
1955    full_id2 = id2+slope*extra/2;
1956    ibevel1 = first_defined([ibevel1,ibevel,true]);
1957    ibevel2 = first_defined([ibevel2,ibevel,true]);
1958    bevel1 = first_defined([bevel1,bevel,shape=="hex"?true:false]);
1959    bevel2 = first_defined([bevel2,bevel,shape=="hex"?true:false]);
1960    depth = -pitch*min(column(profile,1));
1961    IBEV=0.05;
1962    vnf = linear_sweep(hexagon(id=nutwidth), height=h, center=true);
1963    attachable(anchor,spin,orient, size=shape=="square" ? [nutwidth,nutwidth,h] : undef, vnf=shape=="hex" ? vnf : undef) {
1964        difference() {
1965            _nutshape(nutwidth,h, shape,bevel1,bevel2);
1966            if (pitch==0) 
1967               cyl(l=h+extra, d1=full_id1+4*get_slop(), d2=full_id2+4*get_slop(),
1968                   chamfer1=ibevel1?-IBEV*full_id1:undef,
1969                   chamfer2=ibevel2?-IBEV*full_id2:undef);
1970            else
1971               generic_threaded_rod(
1972                     d1=full_id1,d2=full_id2,
1973                     l=h+extra,
1974                     pitch=pitch,
1975                     profile=profile,
1976                     left_handed=left_handed,
1977                     starts=starts,
1978                     internal=true,
1979                     bevel1=ibevel1,bevel2=ibevel2,
1980                     blunt_start=blunt_start, blunt_start1=blunt_start1, blunt_start2=blunt_start2,
1981                     lead_in=lead_in, lead_in1=lead_in1, lead_in2=lead_in2, lead_in_shape=lead_in_shape,
1982                     lead_in_ang=lead_in_ang, lead_in_ang1=lead_in_ang1, lead_in_ang2=lead_in_ang2,
1983                     end_len=end_len, end_len1=end_len1, end_len2=end_len2
1984                );
1985        }
1986        children();
1987    }
1988}
1989
1990
1991module _nutshape(nutwidth, h, shape, bevel1, bevel2)
1992{
1993   bevel_d=0.9;
1994   intersection(){
1995       if (shape=="hex")
1996         cyl(d=nutwidth, circum=true, $fn=6, l=h, chamfer1=bevel1?0:nutwidth*.01, chamfer2=bevel2?0:nutwidth*.01);
1997        //vnf_polyhedron(vnf);
1998       else
1999         cuboid([nutwidth,nutwidth,h],chamfer=nutwidth*.01, except=[if (bevel1) BOT, if(bevel2) TOP]);
2000       fn = quantup(segs(r=nutwidth/2),shape=="hex"?6:4);
2001       d = shape=="hex" ? 2*nutwidth/sqrt(3) : sqrt(2)*nutwidth;
2002       chamfsize = (d-nutwidth)/2/bevel_d;
2003       cyl(d=d*.99,h=h+.01,realign=true,circum=true,$fn=fn,chamfer1=bevel1?chamfsize:0,chamfer2=bevel2?chamfsize:0,chamfang=30);
2004   }
2005}
2006
2007
2008// Module: thread_helix()
2009// Synopsis: Creates a thread helix to add to a cylinder.
2010// SynTags: Geom
2011// Topics: Threading, Screws
2012// See Also: generic_threaded_rod()
2013// Usage:
2014//   thread_helix(d, pitch, [thread_depth], [flank_angle], [turns], [profile=], [left_handed=], [higbee=], [internal=]);
2015// Description:
2016//   Creates a right-handed helical thread with optional end tapering.  Unlike
2017//   {{generic_threaded_rod()}, this module just generates the thread, and you specify the total
2018//   angle of threading that you want, which makes it easy to put complete threads onto a longer
2019//   shaft.  It also optionally makes a finely divided taper at the thread ends.  However, it takes
2020//   2-3 times as long to render compared to {{generic_threaded_rod()}}.  This module was designed
2021//   to handle threads found in plastic and glass bottles.
2022//   .
2023//   You can specify a thread_depth and flank_angle, in which case you get a symmetric trapezoidal
2024//   thread, whose inner diameter (the base of the threads for external threading) is d (so the
2025//   total diameter will be d + thread_depth).  This differs from the threaded_rod modules, where
2026//   the specified diameter is the outer diameter.  Alternatively you can give a profile, following
2027//   the same rules as for general_threaded_rod.  The Y=0 point will align with the specified
2028//   diameter, and the profile should range in X from -1/2 to 1/2.  You cannot specify both the
2029//   profile and the thread_depth or flank_angle.
2030//   .
2031//   Unlike {{generic_threaded_rod()}, when internal=true this module generates the threads, not a thread mask.
2032//   The profile needs to be inverted to produce the proper thread form.  If you use the built-in trapezoidal
2033//   thread you get the inverted thread, designed so that the inner diameter is d.  If you supply a custom profile
2034//   you must invert it yourself to get internal threads.  With adequate clearance
2035//   this thread will mate with the thread that uses the same parameters but has internal=false.  Note that
2036//   unlike the threaded_rod modules, thread_helix does not adjust the diameter for faceting, nor does it
2037//   subtract any $slop for clearance.  
2038//   .
2039//   The taper options specify tapering at of the threads at each end, and is given as the linear distance
2040//   over which to taper.  If taper is positive the threads are lengthened by the specified distance; if taper
2041//   is negative, the taper is included in the thread length specified by `turns`.  Tapering works on both internal and external threads.  
2042// Figure(2D,Med,NoAxes):
2043//   pa_delta = tan(15)/4;
2044//      rr1 = -1/2;
2045//      z1 = 1/4-pa_delta;
2046//      z2 = 1/4+pa_delta;
2047//      profile = [
2048//                  [-z2, rr1],
2049//                  [-z1,  0],
2050//                  [ z1,  0],
2051//                  [ z2, rr1],
2052//                ];
2053//      fullprofile = 50*left(1/2,p=concat(profile, right(1, p=profile)));
2054//      stroke(fullprofile,width=1);
2055//      dir = fullprofile[2]-fullprofile[3];
2056//      dir2 = fullprofile[5]-fullprofile[4];
2057//      curve = arc(15,angle=[75,87],r=40 /*67.5*/);
2058//      avgpt = mean([fullprofile[5]+.1*dir2, fullprofile[5]+.4*dir2]);
2059//      color("red"){
2060//       stroke([fullprofile[4]+[0,1], fullprofile[4]+[0,37]], width=1);
2061//       stroke([fullprofile[5]+.1*dir2, fullprofile[5]+.4*dir2], width=1);
2062//       stroke(move(-curve[0]+avgpt,p=curve), width=0.71,endcaps="arrow2");
2063//       right(14)back(19)text("flank",size=4,halign="center");
2064//       right(14)back(14)text("angle",size=4,halign="center");
2065//      }
2066// Figure(2D,Med,NoAxes):
2067//   pa_delta = tan(15)/4;
2068//   rr1 = -1/2;
2069//   z1 = 1/4-pa_delta;
2070//   z2 = 1/4+pa_delta;
2071//   profile = [
2072//               [-z2, rr1],
2073//               [-z1,  0],
2074//               [ z1,  0],
2075//               [ z2, rr1],
2076//             ];
2077//   fullprofile = 50*left(1/2,p=concat(profile, right(1, p=profile)));
2078//   stroke(fullprofile,width=1);
2079//   dir = fullprofile[2]-fullprofile[3];
2080//   dir2 = fullprofile[5]-fullprofile[4];
2081//   curve = arc(32,angle=[75,105],r=67.5);
2082//   avgpt = mean([fullprofile[5]+.1*dir2, fullprofile[5]+.4*dir2]);
2083//   color("red"){
2084//    stroke([fullprofile[2]+.1*dir, fullprofile[2]+.4*dir], width=1);
2085//    stroke([fullprofile[5]+.1*dir2, fullprofile[5]+.4*dir2], width=1);
2086//    stroke(move(-curve[0]+avgpt,p=curve), width=1,endcaps="arrow2");
2087//    back(10)text("thread",size=4,halign="center");
2088//    back(3)text("angle",size=4,halign="center");
2089//   }
2090// Arguments:
2091//   d = Base diameter of threads.  Default: 10
2092//   pitch = Distance between threads.  Default: 2
2093//   ---
2094//   thread_depth = Depth of threads from top to bottom.
2095//   flank_angle = Angle of thread faces to plane perpendicular to screw.  Default: 15 degrees.
2096//   turns = Number of revolutions to rotate thread around.
2097//   thread_angle = Angle between two thread faces.  
2098//   profile = If an asymmetrical thread profile is needed, it can be specified here.
2099//   starts = The number of thread starts.  Default: 1
2100//   left_handed = If true, thread has a left-handed winding.
2101//   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
2102//   d1 = Bottom inside base diameter of threads.
2103//   d2 = Top inside base diameter of threads.
2104//   thread_angle = Angle between 
2105//   lead_in = Specify linear length of the lead in section of the threading with blunt start threads
2106//   lead_in1 = Specify linear length of the lead in section of the threading at the bottom with blunt start threads
2107//   lead_in2 = Specify linear length of the lead in section of the threading at the top with blunt start threads
2108//   lead_in_ang = Specify angular length in degrees of the lead in section of the threading with blunt start threads
2109//   lead_in_ang1 = Specify angular length in degrees of the lead in section of the threading at the bottom with blunt start threads
2110//   lead_in_ang2 = Specify angular length in degrees of the lead in section of the threading at the top with blunt start threads
2111//   lead_in_shape = Specify the shape of the thread lead in by giving a text string or function.  Default: "default"
2112//   lead_in_sample = Factor to increase sample rate in the lead-in section.  Default: 10
2113//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
2114//   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#subsection-spin).  Default: `0`
2115//   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
2116// Example(2DMed): Typical Tooth Profile
2117//   pitch = 2;
2118//   depth = pitch * cos(30) * 5/8;
2119//   profile = [
2120//       [-6/16, 0           ],
2121//       [-1/16, depth/pitch ],
2122//       [ 1/16, depth/pitch ],
2123//       [ 6/16, 0           ],
2124//   ];
2125//   stroke(profile, width=0.02);
2126// Examples:
2127//   thread_helix(d=10, pitch=2, thread_depth=0.75, flank_angle=15, turns=2.5, $fn=72);
2128//   thread_helix(d=10, pitch=2, thread_depth=0.75, flank_angle=15, turns=2.5, lead_in=1, $fn=72);
2129//   thread_helix(d=10, pitch=2, thread_depth=0.75, flank_angle=15, turns=2, lead_in=2, internal=true, $fn=72);
2130//   thread_helix(d=10, pitch=2, thread_depth=0.75, flank_angle=15, turns=1, left_handed=true, lead_in=1, $fn=36);
2131function thread_helix(
2132    d, pitch, thread_depth, flank_angle, turns,
2133    profile, starts=1, left_handed=false, internal=false,
2134    d1, d2, thread_angle, 
2135    lead_in_shape,
2136    lead_in, lead_in1, lead_in2,
2137    lead_in_ang, lead_in_ang1, lead_in_ang2,
2138    lead_in_sample=10,
2139    anchor, spin, orient
2140) = no_function("thread_helix");
2141module thread_helix(
2142    d, pitch, thread_depth, flank_angle, turns,
2143    profile, starts=1, left_handed=false, internal=false,
2144    d1, d2, thread_angle, 
2145    lead_in_shape,
2146    lead_in, lead_in1, lead_in2,
2147    lead_in_ang, lead_in_ang1, lead_in_ang2,
2148    lead_in_sample=10,
2149    anchor, spin, orient
2150) {
2151    dummy1=assert(num_defined([thread_angle,flank_angle])<=1, "Cannot define both flank angle and thread angle")
2152           assert(is_undef(profile) || !any_defined([thread_depth, flank_angle]),
2153                  "Cannot give thread_depth or flank_angle with a profile")
2154           assert(all_positive([turns]), "The turns parameter must be a positive number")
2155           assert(all_positive(pitch), "pitch must be a positive number")
2156           assert(num_defined([flank_angle,thread_angle])<=1, "Cannot give both thread_angle and flank_angle")
2157           assert(is_def(profile) || is_def(thread_depth), "If profile is not given, must give thread depth");
2158    flank_angle = first_defined([flank_angle,u_mul(0.5,thread_angle),15]);
2159    h = pitch*starts*abs(turns);
2160    r1 = get_radius(d1=d1, d=d, dflt=10);
2161    r2 = get_radius(d1=d2, d=d, dflt=10);
2162    profile = is_def(profile) ? profile :
2163        let(
2164            tdp = thread_depth / pitch,
2165            dz = tdp * tan(flank_angle),
2166            cap = (1 - 2*dz)/2
2167        )
2168        assert(cap/2+dz<=0.5, "Invalid geometry: incompatible thread depth and thread_angle/flank_angle")
2169        internal?
2170          [
2171            [-cap/2-dz, tdp],
2172            [-cap/2,    0  ],
2173            [+cap/2,    0  ],
2174            [+cap/2+dz, tdp],
2175          ]
2176        :
2177          [
2178            [+cap/2+dz, 0  ],
2179            [+cap/2,    tdp],
2180            [-cap/2,    tdp],
2181            [-cap/2-dz, 0  ],
2182          ];
2183
2184    pline = mirror([-1,1],  p = profile * pitch);
2185    dir = left_handed? -1 : 1;
2186    attachable(anchor,spin,orient, r1=r1, r2=r2, l=h) {
2187        union(){
2188        zrot_copies(n=starts)
2189            spiral_sweep(pline, h=h, r1=r1, r2=r2, turns=turns*dir, internal=internal,
2190                         lead_in_shape=lead_in_shape,
2191                         lead_in=lead_in, lead_in1=lead_in1, lead_in2=lead_in2,
2192                         lead_in_ang=lead_in_ang, lead_in_ang1=lead_in_ang1, lead_in_ang2=lead_in_ang2,
2193                         lead_in_sample=lead_in_sample,anchor=CENTER);
2194        }
2195        children();
2196    }
2197}
2198
2199
2200
2201// Questions
2202//   Should nut modules take d1/d2 for tapered nuts?
2203//
2204// Need explanation of what exactly the diff is between threaded_rod and helix_threads.
2205//
2206// What about blunt_start for ball screws?
2207// Should default bevel be capped at 1mm or 2mm or something like that?  Including/especially inner bevel on nuts
2208
2209// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
2210