//////////////////////////////////////////////////////////////////////
// LibFile: threading.scad
//   Provides generic threading support and specialized support for standard triangular (UTS/ISO) threading,
//   trapezoidal threading (ACME), pipe threading, buttress threading, square threading and ball screws.  
// Includes:
//   include <BOSL2/std.scad>
//   include <BOSL2/threading.scad>
// FileGroup: Threaded Parts
// FileSummary: Various types of threaded rods and nuts.
//////////////////////////////////////////////////////////////////////


// Section: Thread Ends and Options
//   A standard process for making machine screws is to begin with round stock that has
//   beveled ends.  This stock is then rolled between flat, grooved plates to form the threads.
//   The result is a bolt that looks like this at the end:
// Figure(3D,Med,NoAxes,VPR=[83.7,0,115.5],VPT=[1.37344,1.26411,-0.299415],VPD=35.5861): 
//   threaded_rod(d=13,pitch=2,l=10,blunt_start=false,$fn=80);
// Figure(2D,Med,NoAxes): A properly mated screw and bolt with beveled ends
//   $fn=32;
//   projection(cut=true)
//   xrot(-90){
//   down(2.5)difference(){
//     cuboid([20,20,5]);
//     zrot(20)
//     threaded_rod(d=13.2, pitch=2,l=5.1,blunt_start=false,internal=true);
//   }
//   up(2.85-2)threaded_rod(d=13, pitch=2, l=10, blunt_start=false);
//   
//   }
// Continues:
//   Cross threading occurs when the bolt is misaligned with the threads in the nut.
//   It can destroy the threads, or cause the nut to jam.  The standard beveled end process
//   makes cross threading a possibility because the beveled partial threads can pass
//   each other when the screw enters the nut.
// Figure(2D,Med,NoAxes):
//   $fn=32;
//   projection(cut=true)
//   xrot(-90){
//   down(2.5)difference(){
//     cuboid([20,20,5]);
//     zrot(20)
//     threaded_rod(d=13.2, pitch=2,l=5.1,blunt_start=false,internal=true);
//   }
//   left(.6)up(2.99)yrot(-atan(2/13)-1)rot(180+30)threaded_rod(d=13, pitch=2, l=10, blunt_start=false);
//   }
// Continues:
//   In addition, those partial screw threads may be weak, and easily broken.  They do
//   not contribute to the strength of the assembly.  
//   In 1891 Clinton A. Higbee received a patent for a modification to screw threads
//   https://patents.google.com/patent/US447775A meant to address these limitations.
//   Instead of beveling the end of the screw, Higbee said to remove the partial thread.
//   The resulting screw might look like this:
// Figure(3D,Med,NoAxes,VPR=[72,0,294],VPT=[0,0,0],VPD=44):
//   $fn=48;
//   threaded_rod(d=13,pitch=2,l=10,blunt_start=true,lead_in_shape="cut",end_len=.2);
// Continues:
//   Because the threads are complete everywhere, cross threading is unlikely to occur.
//   This type of threading has been called "Higbee threads", but in recent machinist
//   handbooks it is called "blunt start" threading.  
//   This style of thread is not commonly used in metal fasteners because it requires
//   machining the threads, which is much more costly than the rolling procedure described
//   above.  However, plastic threads usually have some sort of gradual thread end.
//   For models that will be 3D printed, there is no reason to choose the standard
//   bevel end bolt, so in this library the blunt start threads are the default.
//   If you need standard bevel-end threads, you can choose them with the `blunt_start` options.
//   Note that blunt start threads are more efficient.
//   .
//   Various options exist for controlling the ends of threads. You can specify bevels on threaded rods.
//   In conventional threading, bevels are needed on the ends to remove sharp, thin edges, and
//   the bevel is sized to the full outer diameter of the threaded rod.  
//   With blunt start threading, the bevel appears on the unthreaded part of the rod.
//   On a threaded rod, a bevel value of `true` or a positive bevel value cut off the corner.
// Figure(3D,Med,NoAxes,VPR=[72,0,54],VPT=[0,0,0],VPD=44):
//   threaded_rod(d=13,pitch=2,l=10,blunt_start=true,bevel=true,$fn=80);
// Continues:
//   A negative bevel value produces a flaring bevel, that might be useful if the rod needs to mate with another part.
//   You can also set `bevel="reverse"` to get a flaring bevel of the default size.
// Figure(3D,Med,NoAxes,VPR=[72,0,54],VPT=[0,0,0],VPD=44): Negative bevel on a regular threaded rod.
//   threaded_rod(d=13,pitch=2,l=10,blunt_start=true,bevel=-2,$fn=80);
// Continues:
//   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
//   the threaded rod it gives a beveled edge to the hole.  In this case, negative bevels go inward, which might be useful to
//   create a bevel at the bottom of a threaded hole.
// 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.  
//   threaded_rod(d=13,pitch=2,l=10,blunt_start=true,bevel2=true,bevel1="reverse",internal=true,$fn=80);
// Continues:
//   You can also extend the unthreaded section using the `end_len` parameters.  A long unthreaded section will make
//   it impossible to tilt the bolt and produce misaligned threads, so it could make assembly easier.  
// Figure(3D,Med,NoAxes,VPR=[72,0,54],VPT=[0,0,0],VPD=48): Negative bevel on a regular threaded rod.
//   threaded_rod(d=13,pitch=2,l=15,end_len2=5,blunt_start=true,bevel=true,$fn=80);
// Continues:
//   It is also possible to adjust the length of the lead-in section of threads, or the
//   shape of that lead-in section.  The lead-in length can be set using the `lead_in` arguments
//   to specify a length or the `lead_in_ang` arguments to specify an angle.  For general
//   threading applications, making the lead in long creates a smaller thread that could
//   be more fragile and more prone to cross threading.  
// Figure(3D,Med,NoAxes,VPR=[52,0,300],VPT=[0,0,4],VPD=35.5861):
//   threaded_rod(d=13,pitch=2,l=10,lead_in=6,blunt_start=true,bevel=false,$fn=80);
// Continues:
//   To change the form of the thread end you use the `lead_in_shape` argument.
//   You can specify "sqrt", "cut" or "smooth" shapes.  The "sqrt" shape is the historical
//   shape used in the library.  The "cut" shape is available to model Higbee pattern threads, but
//   is not as good as the others in practice, because the flat faces on the threads can hit each other.
//   The lead-in shape is produced by applying a scale factor to the thread cross section that varies along the lead-in length. 
//   You can also specify a custom shape
//   by giving a function literal, `f(x,L)` where `L` will be the total linear
//   length of the lead-in section and `x` will be a value between 0 and 1 giving
//   the position in the lead in, with 0 being the tip and 1 being the full height thread.
//   The return value must be a 2-vector giving the thread width scale and thread height
//   scale at that location.  If `x<0` the function must return a thread height scale
//   of zero, but it is usually best if the thread width scale does not go to zero,
//   because that will give a sharply pointed thread end.  If `x>1` the function must
//   return `[1,1]`.  
// Figure(3D,Med,NoAxes,VPR=[75,0,338],VPT=[-2,0,3.3],VPD=25): The standard lead in shapes
//   left_half()zrot(0){
//   up(2)   threaded_rod(d=13,pitch=2,l=2,blunt_start=true,bevel=false,$fn=128,anchor=BOT);
//   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);
//      threaded_rod(d=13,pitch=2,l=2,blunt_start=true,bevel=false,$fn=128,lead_in_shape="smooth",anchor=BOT);
//   }
//   $fn=64;
//   s=.85;
//   color("black")
//   up(3.5)left(4.5)fwd(6)rot($vpr){
//      back(1.9)text3d("cut",size=s);
//      text3d("sqrt",size=s);
//      fwd(1.9)text3d("smooth",size=s);
//   }   


// Section: Standard (UTS/ISO) Threading

// Module: threaded_rod()
// Synopsis: Creates an UTS/ISO triangular threaded rod.
// SynTags: Geom
// Topics: Threading, Screws
// See Also: threaded_nut()
// Usage:
//   threaded_rod(d, l|length, pitch, [internal=], ...) [ATTACHMENTS];
// Description:
//   Constructs a standard ISO (metric) or UTS (English) threaded rod.  These threads are close to triangular,
//   with a 60 degree thread angle.  You can give the outer diameter and get the "basic form" or you can
//   set d to a triplet [d_min, d_pitch, d_major] where are parameters determined by the ISO and UTS specifications
//   that define clearance sizing for the threading.  See screws.scad for how to make screws
//   using the specification parameters.  
// Arguments:
//   d = Outer diameter of threaded rod, or a triplet of [d_min, d_pitch, d_major]. 
//   l / length / h / height = length of threaded rod.
//   pitch = Length between threads.
//   ---
//   left_handed = if true, create left-handed threads.  Default = false
//   starts = The number of lead starts.  Default: 1
//   bevel = if true, bevel the thread ends.  Default: false
//   bevel1 = if true bevel the bottom end.
//   bevel2 = if true bevel the top end.
//   internal = If true, make this a mask for making internal threads.
//   d1 = Bottom outside diameter of threads.
//   d2 = Top outside diameter of threads.
//   blunt_start = If true apply truncated blunt start threads at both ends.  Default: true
//   blunt_start1 = If true apply truncated blunt start threads bottom end.
//   blunt_start2 = If true apply truncated blunt start threads top end.
//   end_len = Specify the unthreaded length at the end after blunt start threads.  Default: 0
//   end_len1 = Specify unthreaded length at the bottom
//   end_len2 = Specify unthreaded length at the top
//   lead_in = Specify linear length of the lead in section of the threading with blunt start threads
//   lead_in1 = Specify linear length of the lead in section of the threading at the bottom with blunt start threads
//   lead_in2 = Specify linear length of the lead in section of the threading at the top with blunt start threads
//   lead_in_ang = Specify angular length in degrees of the lead in section of the threading with blunt start threads
//   lead_in_ang1 = Specify angular length in degrees of the lead in section of the threading at the bottom with blunt start threads
//   lead_in_ang2 = Specify angular length in degrees of the lead in section of the threading at the top with blunt start threads
//   lead_in_shape = Specify the shape of the thread lead in by giving a text string or function.  Default: "default"
//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
//   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#subsection-spin).  Default: `0`
//   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
//   $slop = The printer-specific slop value, which adds clearance (`4*$slop`) to internal threads.
// Example(2D):
//   projection(cut=true)
//       threaded_rod(d=10, l=15, pitch=1.5, orient=BACK);
// Examples(Med):
//   threaded_rod(d=25, height=20, pitch=2, $fa=1, $fs=1);
//   threaded_rod(d=10, l=20, pitch=1.25, left_handed=true, $fa=1, $fs=1);
//   threaded_rod(d=25, l=20, pitch=2, $fa=1, $fs=1, end_len=1.5, bevel=true);
//   threaded_rod(d=25, l=20, pitch=2, $fa=1, $fs=1, blunt_start=false);
// Example(Big,NoAxes): Diamond threading where both left-handed and right-handed nuts travel (in the same direction) on the threaded rod:
//   $fn=32;
//   $slop = 0.075;
//   d = 3/8*INCH;
//   pitch = 1/16*INCH;
//   starts=3;
//   xdistribute(19){
//       intersection(){
//         threaded_rod(l=40, pitch=pitch, d=d,starts=starts,anchor=BOTTOM,end_len=.44);
//         threaded_rod(l=40, pitch=pitch, d=d, left_handed=true,starts=starts,anchor=BOTTOM);
//       }
//       threaded_nut(nutwidth=4.5/8*INCH,id=d,h=3/8*INCH,pitch=pitch,starts=starts,anchor=BOTTOM);
//       threaded_nut(nutwidth=4.5/8*INCH,id=d,h=3/8*INCH,pitch=pitch,starts=starts,left_handed=true,anchor=BOTTOM);
//   }
function threaded_rod(
    d, l, pitch,
    left_handed=false,
    bevel,bevel1,bevel2,starts=1,
    internal=false,
    d1, d2, length, h, height,
    blunt_start, blunt_start1, blunt_start2,
    lead_in, lead_in1, lead_in2,
    lead_in_ang, lead_in_ang1, lead_in_ang2,
    end_len, end_len1, end_len2,
    lead_in_shape="default",
    anchor, spin, orient
) = no_function("threaded_rod");

module threaded_rod(
    d, l, pitch,
    left_handed=false,
    bevel,bevel1,bevel2,starts=1,
    internal=false,
    d1, d2, length, h, height,
    blunt_start, blunt_start1, blunt_start2,
    lead_in, lead_in1, lead_in2,
    lead_in_ang, lead_in_ang1, lead_in_ang2,
    end_len, end_len1, end_len2,
    lead_in_shape="default",
    anchor, spin, orient
) {
    dummy1=
      assert(all_positive(pitch))
      assert(all_positive(d) || (is_undef(d) && all_positive([d1,d2])));
    basic = is_num(d) || is_undef(d) || is_def(d1) || is_def(d2);
    dummy2 = assert(basic || is_vector(d,3));
    depth = basic ? cos(30) * 5/8
                  : (d[2] - d[0])/2/pitch;
    crestwidth = basic ? 1/8 : 1/2 - (d[2]-d[1])/sqrt(3)/pitch;
    profile =    [
                  [-depth/sqrt(3)-crestwidth/2, -depth],
                  [              -crestwidth/2,      0],
                  [               crestwidth/2,      0],
                  [ depth/sqrt(3)+crestwidth/2, -depth]
                 ];
    oprofile = internal? [
        [-6/16, -depth],
        [-1/16,  0],
        [-1/32,  0.02],
        [ 1/32,  0.02],
        [ 1/16,  0],
        [ 6/16, -depth]
    ] : [
        [-7/16, -depth*1.07],
        [-6/16, -depth],
        [-1/16,  0],
        [ 1/16,  0],
        [ 6/16, -depth],
        [ 7/16, -depth*1.07]
    ];
    generic_threaded_rod(
        d=basic ? d : d[2], d1=d1, d2=d2, l=l,
        pitch=pitch,
        profile=profile,starts=starts,
        left_handed=left_handed,
        bevel=bevel,bevel1=bevel1,bevel2=bevel2,
        internal=internal, length=length, height=height, h=h,
        blunt_start=blunt_start, blunt_start1=blunt_start1, blunt_start2=blunt_start2,
        lead_in=lead_in, lead_in1=lead_in1, lead_in2=lead_in2, lead_in_shape=lead_in_shape,
        lead_in_ang=lead_in_ang, lead_in_ang1=lead_in_ang1, lead_in_ang2=lead_in_ang2,
        end_len=end_len, end_len1=end_len1, end_len2=end_len2,
        anchor=anchor,
        spin=spin,
        orient=orient
    ) children();
}



// Module: threaded_nut()
// Synopsis: Creates an UTS/ISO triangular threaded nut.
// SynTags: Geom
// Topics: Threading, Screws
// See Also: threaded_rod()
// Usage:
//   threaded_nut(nutwidth, id, h|height|thickness, pitch,...) [ATTACHMENTS];
// Description:
//   Constructs a hex nut or square nut for an ISO (metric) or UTS (English) threaded rod. 
// Arguments:
//   nutwidth = flat to flat width of nut
//   id = diameter of threaded rod to screw onto.
//   h / height / l / length / thickness = height/thickness of nut.
//   pitch = Distance between threads, or zero for no threads. 
//   ---
//   shape = specifies shape of nut, either "hex" or "square".  Default: "hex"
//   left_handed = if true, create left-handed threads.  Default = false
//   starts = The number of lead starts.  Default: 1
//   bevel = if true, bevel the outside of the nut.  Default: true for hex nuts, false for square nuts
//   bevel1 = if true, bevel the outside of the nut bottom.
//   bevel2 = if true, bevel the outside of the nut top. 
//   bevang = set the angle for the outside nut bevel.  Default: 30
//   ibevel = if true, bevel the inside (the hole).   Default: true
//   ibevel1 = if true bevel the inside, bottom end.
//   ibevel2 = if true bevel the inside, top end.
//   blunt_start = If true apply truncated blunt start threads at both ends.  Default: true
//   blunt_start1 = If true apply truncated blunt start threads bottom end.
//   blunt_start2 = If true apply truncated blunt start threads top end.
//   end_len = Specify the unthreaded length at the end after blunt start threads.  Default: 0
//   end_len1 = Specify unthreaded length at the bottom
//   end_len2 = Specify unthreaded length at the top
//   lead_in = Specify linear length of the lead in section of the threading with blunt start threads
//   lead_in1 = Specify linear length of the lead in section of the threading at the bottom with blunt start threads
//   lead_in2 = Specify linear length of the lead in section of the threading at the top with blunt start threads
//   lead_in_ang = Specify angular length in degrees of the lead in section of the threading with blunt start threads
//   lead_in_ang1 = Specify angular length in degrees of the lead in section of the threading at the bottom with blunt start threads
//   lead_in_ang2 = Specify angular length in degrees of the lead in section of the threading at the top with blunt start threads
//   lead_in_shape = Specify the shape of the thread lead in by giving a text string or function.  Default: "default"
//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
//   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#subsection-spin).  Default: `0`
//   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
//   $slop = The printer-specific slop value, which adds clearance (`4*$slop`) to internal threads.
// Examples(Med):
//   threaded_nut(nutwidth=16, id=8, h=8, pitch=1.25, $slop=0.05, $fa=1, $fs=1);
//   threaded_nut(nutwidth=16, id=8, h=8, pitch=1.25, left_handed=true, bevel=false, $slop=0.1, $fa=1, $fs=1);
//   threaded_nut(shape="square", nutwidth=16, id=8, h=8, pitch=1.25, $slop=0.1, $fa=1, $fs=1);
//   threaded_nut(shape="square", nutwidth=16, id=8, h=8, pitch=1.25, bevel2=true, $slop=0.1, $fa=1, $fs=1);
//   rot(90)threaded_nut(nutwidth=16, id=8, h=8, pitch=1.25,blunt_start=false, $slop=0.1, $fa=1, $fs=1);
function threaded_nut(
    nutwidth, id, h,
    pitch, starts=1, shape="hex", left_handed=false, bevel, bevel1, bevel2, id1,id2,
    ibevel1, ibevel2, ibevel, bevang=30, thickness, height,
    length, l,
    blunt_start, blunt_start1, blunt_start2,
    lead_in, lead_in1, lead_in2,
    lead_in_ang, lead_in_ang1, lead_in_ang2,
    end_len, end_len1, end_len2,
    lead_in_shape="default",
    anchor, spin, orient
)=no_function("threaded_nut");
module threaded_nut(
    nutwidth, id, h,
    pitch, starts=1, shape="hex", left_handed=false, bevel, bevel1, bevel2, id1,id2,
    ibevel1, ibevel2, ibevel, bevang=30, thickness, height,
    length, l,
    blunt_start, blunt_start1, blunt_start2,
    lead_in, lead_in1, lead_in2,
    lead_in_ang, lead_in_ang1, lead_in_ang2,
    end_len, end_len1, end_len2,
    lead_in_shape="default",
    anchor, spin, orient
) {
    dummy1=
          assert(all_nonnegative(pitch), "Nut pitch must be nonnegative")
          assert(all_positive(id), "Nut inner diameter must be positive")
          assert(all_positive(h),"Nut thickness must be positive");
    basic = is_num(id) || is_undef(id) || is_def(id1) || is_def(id2);
    dummy2 = assert(basic || is_vector(id,3));
    depth = basic ? cos(30) * 5/8
                  : (id[2] - id[0])/2/pitch;
    crestwidth = basic ? 1/8 : 1/2 - (id[2]-id[1])/sqrt(3)/pitch;
    profile =    [
                  [-depth/sqrt(3)-crestwidth/2, -depth],
                  [              -crestwidth/2,      0],
                  [               crestwidth/2,      0],
                  [ depth/sqrt(3)+crestwidth/2, -depth]
                 ];
    oprofile = [
        [-6/16, -depth/pitch],
        [-1/16,  0],
        [-1/32,  0.02],
        [ 1/32,  0.02],
        [ 1/16,  0],
        [ 6/16, -depth/pitch]
    ];
    generic_threaded_nut(
        nutwidth=nutwidth,
        id=basic ? id : id[2], id1=id1, id2=id2,
        h=h,
        pitch=pitch,
        profile=profile,starts=starts,shape=shape, 
        left_handed=left_handed,
        bevel=bevel,bevel1=bevel1,bevel2=bevel2,
        ibevel1=ibevel1, ibevel2=ibevel2, ibevel=ibevel,
        blunt_start=blunt_start, blunt_start1=blunt_start1, blunt_start2=blunt_start2,
        lead_in=lead_in, lead_in1=lead_in1, lead_in2=lead_in2, lead_in_shape=lead_in_shape,
        lead_in_ang=lead_in_ang, lead_in_ang1=lead_in_ang1, lead_in_ang2=lead_in_ang2,
        end_len=end_len, end_len1=end_len1, end_len2=end_len2,
        l=l,length=length,
        anchor=anchor, spin=spin,
        orient=orient
    ) children();
}

// Section: Trapezoidal Threading


// Module: trapezoidal_threaded_rod()
// Synopsis: Creates a trapezoidal threaded rod.
// SynTags: Geom
// Topics: Threading, Screws
// See Also: trapezoidal_threaded_nut()
// Usage:
//   trapezoidal_threaded_rod(d, l|length, pitch, [thread_angle=|flank_angle=], [thread_depth=], [internal=], ...) [ATTACHMENTS];
// Description:
//   Constructs a threaded rod with a symmetric trapezoidal thread.  Trapezoidal threads are used for lead screws because
//   they are one of the strongest symmetric profiles.  This tooth shape is stronger than a similarly
//   sized square thread becuase of its wider base.  However, it does place a radial load on the nut, unlike the square thread.
//   For loads in only one direction the asymmetric buttress thread profile can bear greater loads.  
//   .
//   By default produces the nominal dimensions
//   for metric trapezoidal threads: a thread angle of 30 degrees and a depth set to half the pitch.
//   You can also specify your own trapezoid parameters.  For ACME threads see acme_threaded_rod().
// Figure(2D,Med,NoAxes):
//   pa_delta = tan(15)/4;
//   rr1 = -1/2;
//   z1 = 1/4-pa_delta;
//   z2 = 1/4+pa_delta;
//   profile = [
//               [-z2, rr1],
//               [-z1,  0],
//               [ z1,  0],
//               [ z2, rr1],
//             ];
//   fullprofile = 50*left(1/2,p=concat(profile, right(1, p=profile)));
//   stroke(fullprofile,width=1);
//   dir = fullprofile[2]-fullprofile[3];
//   dir2 = fullprofile[5]-fullprofile[4];
//   curve = arc(32,angle=[75,105],r=67.5);
//   avgpt = mean([fullprofile[5]+.1*dir2, fullprofile[5]+.4*dir2]);
//   color("red"){
//    stroke([fullprofile[2]+.1*dir, fullprofile[2]+.4*dir], width=1);
//    stroke([fullprofile[5]+.1*dir2, fullprofile[5]+.4*dir2], width=1);
//    stroke(move(-curve[0]+avgpt,p=curve), width=1,endcaps="arrow2");
//    back(10)text("thread",size=4,halign="center");
//    back(3)text("angle",size=4,halign="center");
//   }
// Figure(2D,Med,NoAxes):
//   pa_delta = tan(15)/4;
//      rr1 = -1/2;
//      z1 = 1/4-pa_delta;
//      z2 = 1/4+pa_delta;
//      profile = [
//                  [-z2, rr1],
//                  [-z1,  0],
//                  [ z1,  0],
//                  [ z2, rr1],
//                ];
//      fullprofile = 50*left(1/2,p=concat(profile, right(1, p=profile)));
//      stroke(fullprofile,width=1);
//      dir = fullprofile[2]-fullprofile[3];
//      dir2 = fullprofile[5]-fullprofile[4];
//      curve = arc(15,angle=[75,87],r=40 /*67.5*/);
//      avgpt = mean([fullprofile[5]+.1*dir2, fullprofile[5]+.4*dir2]);
//      color("red"){
//       stroke([fullprofile[4]+[0,1], fullprofile[4]+[0,37]], width=1);
//       stroke([fullprofile[5]+.1*dir2, fullprofile[5]+.4*dir2], width=1);
//       stroke(move(-curve[0]+avgpt,p=curve), width=0.71,endcaps="arrow2");
//       right(14)back(19)text("flank",size=4,halign="center");
//       right(14)back(14)text("angle",size=4,halign="center");
//      }
// Arguments:
//   d = Outer diameter of threaded rod.
//   l / length / h / height = Length of threaded rod.
//   pitch = Thread spacing. 
//   ---
//   thread_angle = Angle between two thread faces.  Default: 30
//   thread_depth = Depth of threads.  Default: pitch/2
//   flank_angle = Angle of thread faces to plane perpendicular to screw. 
//   left_handed = If true, create left-handed threads.  Default: false
//   starts = The number of lead starts.  Default: 1
//   bevel = if true, bevel the thread ends.  Default: false
//   bevel1 = if true bevel the bottom end.
//   bevel2 = if true bevel the top end. 
//   internal = If true, make this a mask for making internal threads.  Default: false
//   d1 = Bottom outside diameter of threads.
//   d2 = Top outside diameter of threads.
//   blunt_start = If true apply truncated blunt start threads at both ends.  Default: true
//   blunt_start1 = If true apply truncated blunt start threads bottom end.
//   blunt_start2 = If true apply truncated blunt start threads top end.
//   end_len = Specify the unthreaded length at the end after blunt start threads.  Default: 0
//   end_len1 = Specify unthreaded length at the bottom
//   end_len2 = Specify unthreaded length at the top
//   lead_in = Specify linear length of the lead in section of the threading with blunt start threads
//   lead_in1 = Specify linear length of the lead in section of the threading at the bottom with blunt start threads
//   lead_in2 = Specify linear length of the lead in section of the threading at the top with blunt start threads
//   lead_in_ang = Specify angular length in degrees of the lead in section of the threading with blunt start threads
//   lead_in_ang1 = Specify angular length in degrees of the lead in section of the threading at the bottom with blunt start threads
//   lead_in_ang2 = Specify angular length in degrees of the lead in section of the threading at the top with blunt start threads
//   lead_in_shape = Specify the shape of the thread lead in by giving a text string or function.  Default: "default"
//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
//   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#subsection-spin).  Default: `0`
//   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
//   $slop = The printer-specific slop value, which adds clearance (`4*$slop`) to internal threads.
// Example(2D):
//   projection(cut=true)
//       trapezoidal_threaded_rod(d=10, l=15, pitch=2, orient=BACK);
// Examples(Med): 
//   trapezoidal_threaded_rod(d=10, l=40, pitch=2, $fn=32);  // Standard metric threading
//   rot(-65)trapezoidal_threaded_rod(d=10, l=17, pitch=2, blunt_start=false, $fn=32);  // Standard metric threading
//   trapezoidal_threaded_rod(d=10, l=17, pitch=2, bevel=true, $fn=32);  // Standard metric threading
//   trapezoidal_threaded_rod(d=10, h=30, pitch=2, left_handed=true, $fa=1, $fs=1);  // Standard metric threading
//   trapezoidal_threaded_rod(d=10, l=40, pitch=3, left_handed=true, starts=3, $fn=36);
//   trapezoidal_threaded_rod(l=25, d=10, pitch=2, starts=3, $fa=1, $fs=1, bevel=true, orient=RIGHT, anchor=BOTTOM);
//   trapezoidal_threaded_rod(d=60, l=16, pitch=8, thread_depth=3, thread_angle=90, blunt_start=false, $fa=2, $fs=2);
//   trapezoidal_threaded_rod(d=60, l=16, pitch=8, thread_depth=3, thread_angle=90, end_len=0, $fa=2, $fs=2);   
//   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);
//   trapezoidal_threaded_rod(d=16, l=40, pitch=2, thread_angle=60);
//   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);
//   trapezoidal_threaded_rod(d=50, l=35, pitch=8, thread_angle=60, starts=11, lead_in=3, $fn=120);
//   trapezoidal_threaded_rod(d=10, l=40, end_len2=10, pitch=2, $fn=32);  // Unthreaded top end section
// Example(Med): Using as a Mask to Make Internal Threads
//   bottom_half() difference() {
//       cube(50, center=true);
//       trapezoidal_threaded_rod(d=40, l=51, pitch=5, thread_angle=30, internal=true, bevel=true, orient=RIGHT, $fn=36);
//   }
function trapezoidal_threaded_rod(
    d, l, pitch,
    thread_angle,
    thread_depth,
    flank_angle,
    left_handed=false,
    bevel,bevel1,bevel2,
    starts=1, 
    internal=false,
    d1, d2, length, h, height,
    blunt_start, blunt_start1, blunt_start2,
    lead_in, lead_in1, lead_in2,
    lead_in_ang, lead_in_ang1, lead_in_ang2,
    end_len, end_len1, end_len2,
    lead_in_shape="default",
    anchor, spin, orient
) = no_function("trapezoidal_threaded_rod");
module trapezoidal_threaded_rod(
    d, l, pitch,
    thread_angle,
    thread_depth,
    flank_angle,
    left_handed=false,
    bevel,bevel1,bevel2,
    starts=1, 
    internal=false,
    d1, d2, length, h, height,
    blunt_start, blunt_start1, blunt_start2,
    lead_in, lead_in1, lead_in2,
    lead_in_ang, lead_in_ang1, lead_in_ang2,
    end_len, end_len1, end_len2,
    lead_in_shape="default",
    anchor, spin, orient
) {
    dummy0 = assert(num_defined([thread_angle,flank_angle])<=1, "Cannot define both flank angle and thread angle");
    thread_angle = first_defined([thread_angle, u_mul(2,flank_angle), 30]);
    dummy1 = assert(all_nonnegative(pitch),"Must give a positive pitch value")
             assert(thread_angle>=0 && thread_angle<180, "Invalid thread angle or flank angle")
             assert(thread_angle<=90 || all_positive([thread_depth]),
                   "Thread angle (2*flank_angle) must be smaller than 90 degrees with default thread depth of pitch/2");
    depth = first_defined([thread_depth,pitch/2]);
    pa_delta = 0.5*depth*tan(thread_angle/2) / pitch;
    dummy2 = assert(pa_delta<=1/4, "Specified thread geometry is impossible");
    rr1 = -depth/pitch;
    z1 = 1/4-pa_delta;
    z2 = 1/4+pa_delta;
    profile = [
               [-z2, rr1],
               [-z1,  0],
               [ z1,  0],
               [ z2, rr1],
              ];
    generic_threaded_rod(d=d,l=l,pitch=pitch,profile=profile,
                         left_handed=left_handed,bevel=bevel,bevel1=bevel1,bevel2=bevel2,starts=starts,d1=d1,d2=d2,
                         internal=internal, length=length, height=height, h=h,
                         blunt_start=blunt_start, blunt_start1=blunt_start1, blunt_start2=blunt_start2,
                         lead_in=lead_in, lead_in1=lead_in1, lead_in2=lead_in2, lead_in_shape=lead_in_shape,
                         lead_in_ang=lead_in_ang, lead_in_ang1=lead_in_ang1, lead_in_ang2=lead_in_ang2,
                         end_len=end_len, end_len1=end_len1, end_len2=end_len2,
                         anchor=anchor,spin=spin,orient=orient)
      children();
}


// Module: trapezoidal_threaded_nut()
// Synopsis: Creates a trapezoidal threaded nut.
// SynTags: Geom
// Topics: Threading, Screws
// See Also: trapezoidal_threaded_rod()
// Usage:
//   trapezoidal_threaded_nut(nutwidth, id, h|height|thickness, pitch, [thread_angle=|flank_angle=], [thread_depth], ...) [ATTACHMENTS];
// Description:
//   Constructs a hex nut or square nut for a symmetric trapzoidal threaded rod.  By default produces
//   the nominal dimensions for metric trapezoidal threads: a thread angle of 30 degrees and a depth
//   set to half the pitch.  You can also specify your own trapezoid parameters.  For ACME threads see
//   acme_threaded_nut().
// Arguments:
//   nutwidth = flat to flat width of nut
//   id = diameter of threaded rod to screw onto.
//   h / height / l / length / thickness = height/thickness of nut.
//   pitch = Thread spacing.
//   ---
//   thread_angle = Angle between two thread faces.  Default: 30
//   thread_depth = Depth of the threads.  Default: pitch/2
//   flank_angle = Angle of thread faces to plane perpendicular to screw. 
//   shape = specifies shape of nut, either "hex" or "square".  Default: "hex"
//   left_handed = if true, create left-handed threads.  Default = false
//   starts = The number of lead starts.  Default = 1
//   bevel = if true, bevel the outside of the nut.  Default: true for hex nuts, false for square nuts
//   bevel1 = if true, bevel the outside of the nut bottom.
//   bevel2 = if true, bevel the outside of the nut top. 
//   bevang = set the angle for the outside nut bevel.  Default: 30
//   ibevel = if true, bevel the inside (the hole).   Default: true
//   ibevel1 = if true bevel the inside, bottom end.
//   ibevel2 = if true bevel the inside, top end.
//   blunt_start = If true apply truncated blunt start threads at both ends.  Default: true
//   blunt_start1 = If true apply truncated blunt start threads bottom end.
//   blunt_start2 = If true apply truncated blunt start threads top end.
//   end_len = Specify the unthreaded length at the end after blunt start threads.  Default: 0
//   end_len1 = Specify unthreaded length at the bottom
//   end_len2 = Specify unthreaded length at the top
//   lead_in = Specify linear length of the lead in section of the threading with blunt start threads
//   lead_in1 = Specify linear length of the lead in section of the threading at the bottom with blunt start threads
//   lead_in2 = Specify linear length of the lead in section of the threading at the top with blunt start threads
//   lead_in_ang = Specify angular length in degrees of the lead in section of the threading with blunt start threads
//   lead_in_ang1 = Specify angular length in degrees of the lead in section of the threading at the bottom with blunt start threads
//   lead_in_ang2 = Specify angular length in degrees of the lead in section of the threading at the top with blunt start threads
//   lead_in_shape = Specify the shape of the thread lead in by giving a text string or function.  Default: "default"
//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
//   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#subsection-spin).  Default: `0`
//   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
//   $slop = The printer-specific slop value, which adds clearance (`4*$slop`) to internal threads.
// Examples(Med):
//   trapezoidal_threaded_nut(nutwidth=16, id=8, h=8, pitch=2, $slop=0.1, anchor=UP);
//   trapezoidal_threaded_nut(nutwidth=16, id=8, h=8, pitch=2, bevel=false, $slop=0.05, anchor=UP);
//   trapezoidal_threaded_nut(nutwidth=17.4, id=10, h=10, pitch=2, $slop=0.1, left_handed=true);
//   trapezoidal_threaded_nut(nutwidth=17.4, id=10, h=10, pitch=2, starts=3, $fa=1, $fs=1, $slop=0.15);
//   trapezoidal_threaded_nut(nutwidth=17.4, id=10, h=10, pitch=2, starts=3, $fa=1, $fs=1, $slop=0.15, blunt_start=false);
//   trapezoidal_threaded_nut(nutwidth=17.4, id=10, h=10, pitch=0, $slop=0.2);   // No threads
function trapezoidal_threaded_nut(
    nutwidth,
    id,
    h,
    pitch,
    thread_angle,
    thread_depth, shape="hex",
    flank_angle,
    left_handed=false,
    starts=1,
    bevel,bevel1,bevel2,bevang=30,
    ibevel1,ibevel2,ibevel,
    thickness,height,
    id1,id2,
    length, l,
    blunt_start, blunt_start1, blunt_start2,
    lead_in, lead_in1, lead_in2,
    lead_in_ang, lead_in_ang1, lead_in_ang2,
    end_len, end_len1, end_len2,
    lead_in_shape="default",
    anchor, spin, orient
) = no_function("trapezoidal_threaded_nut");
module trapezoidal_threaded_nut(
    nutwidth,
    id,
    h,
    pitch,
    thread_angle,
    thread_depth, shape="hex",
    flank_angle,
    left_handed=false,
    starts=1,
    bevel,bevel1,bevel2,bevang=30,
    ibevel1,ibevel2,ibevel,
    thickness,height,
    id1,id2,
    length, l,
    blunt_start, blunt_start1, blunt_start2,
    lead_in, lead_in1, lead_in2,
    lead_in_ang, lead_in_ang1, lead_in_ang2,
    end_len, end_len1, end_len2,
    lead_in_shape="default",
    anchor, spin, orient
) {
    dummy0 = assert(num_defined([thread_angle,flank_angle])<=1, "Cannot define both flank angle and thread angle");
    thread_angle = first_defined([thread_angle, u_mul(2,flank_angle), 30]);
    dummy1 = assert(all_nonnegative(pitch),"Must give a positive pitch value")
             assert(thread_angle>=0 && thread_angle<180, "Invalid thread angle or flank angle")
             assert(thread_angle<=90 || all_positive([thread_depth]),
                   "Thread angle (2*flank_angle) must be smaller than 90 degrees with default thread depth of pitch/2");
    depth = first_defined([thread_depth,pitch/2]);
    pa_delta = 0.5*depth*tan(thread_angle/2) / pitch;
    dummy2 = assert(pitch==0 || pa_delta<1/4, "Specified thread geometry is impossible");
    rr1 = -depth/pitch;
    z1 = 1/4-pa_delta;
    z2 = 1/4+pa_delta;
    profile = [
               [-z2, rr1],
               [-z1,  0],
               [ z1,  0],
               [ z2, rr1],
              ];
    generic_threaded_nut(nutwidth=nutwidth,id=id,h=h,pitch=pitch,profile=profile,id1=id1,id2=id2,
                         shape=shape,left_handed=left_handed,bevel=bevel,bevel1=bevel1,bevel2=bevel2,starts=starts,
                         ibevel=ibevel,ibevel1=ibevel1,ibevel2=ibevel2,bevang=bevang,height=height,thickness=thickness,
                         blunt_start=blunt_start, blunt_start1=blunt_start1, blunt_start2=blunt_start2,
                         lead_in=lead_in, lead_in1=lead_in1, lead_in2=lead_in2, lead_in_shape=lead_in_shape,
                         lead_in_ang=lead_in_ang, lead_in_ang1=lead_in_ang1, lead_in_ang2=lead_in_ang2,
                         end_len=end_len, end_len1=end_len1, end_len2=end_len2,
                         l=l,length=length,
                         anchor=anchor,spin=spin,orient=orient)
      children();
}


// Module: acme_threaded_rod()
// Synopsis: Creates an ACME threaded rod.
// SynTags: Geom
// Topics: Threading, Screws
// See Also: acme_threaded_nut()
// Usage:
//   acme_threaded_rod(d, l|length, tpi|pitch=, [internal=], ...) [ATTACHMENTS];
// Description:
//   Constructs an ACME trapezoidal threaded screw rod.  This form has a 29 degree thread angle with a
//   symmetric trapezoidal thread.  
// Arguments:
//   d = Outer diameter of threaded rod.
//   l / length / h / height = Length of threaded rod.
//   tpi = threads per inch.
//   ---
//   pitch = thread spacing (alternative to tpi)
//   starts = The number of lead starts.  Default = 1
//   left_handed = if true, create left-handed threads.  Default = false
//   bevel = if true, bevel the thread ends.  Default: false
//   bevel1 = if true bevel the bottom end.
//   bevel2 = if true bevel the top end. 
//   internal = If true, this is a mask for making internal threads.
//   blunt_start = If true apply truncated blunt start threads at both ends.  Default: true
//   blunt_start1 = If true apply truncated blunt start threads bottom end.
//   blunt_start2 = If true apply truncated blunt start threads top end.
//   end_len = Specify the unthreaded length at the end after blunt start threads.  Default: 0
//   end_len1 = Specify unthreaded length at the bottom
//   end_len2 = Specify unthreaded length at the top
//   lead_in = Specify linear length of the lead in section of the threading with blunt start threads
//   lead_in1 = Specify linear length of the lead in section of the threading at the bottom with blunt start threads
//   lead_in2 = Specify linear length of the lead in section of the threading at the top with blunt start threads
//   lead_in_ang = Specify angular length in degrees of the lead in section of the threading with blunt start threads
//   lead_in_ang1 = Specify angular length in degrees of the lead in section of the threading at the bottom with blunt start threads
//   lead_in_ang2 = Specify angular length in degrees of the lead in section of the threading at the top with blunt start threads
//   lead_in_shape = Specify the shape of the thread lead in by giving a text string or function.  Default: "default"
//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
//   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#subsection-spin).  Default: `0`
//   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
//   $slop = The printer-specific slop value, which adds clearance (`4*$slop`) to internal threads.
// Example(2D):
//   projection(cut=true)
//       acme_threaded_rod(d=10, l=15, pitch=2, orient=BACK);
// Examples(Med):
//   acme_threaded_rod(d=3/8*INCH, l=20, pitch=1/8*INCH, $fn=32);
//   acme_threaded_rod(d=10, l=30, pitch=2, starts=3, $fa=1, $fs=1);
function acme_threaded_rod(
    d, l, tpi, pitch,
    starts=1,
    left_handed=false,
    bevel,bevel1,bevel2,
    internal=false, 
    d1, d2, length, h, height,
    blunt_start, blunt_start1, blunt_start2,
    lead_in, lead_in1, lead_in2,
    lead_in_ang, lead_in_ang1, lead_in_ang2,
    end_len, end_len1, end_len2,
    lead_in_shape="default",
    anchor, spin, orient
) = no_function("acme_threaded_rod");
module acme_threaded_rod(
    d, l, tpi, pitch,
    starts=1,
    left_handed=false,
    bevel,bevel1,bevel2,
    internal=false, 
    d1, d2, length, h, height,
    blunt_start, blunt_start1, blunt_start2,
    lead_in, lead_in1, lead_in2,
    lead_in_ang, lead_in_ang1, lead_in_ang2,
    end_len, end_len1, end_len2,
    lead_in_shape="default",
    anchor, spin, orient
) {
    dummy = assert(num_defined([pitch,tpi])==1,"Must give exactly one of pitch and tpi");
    pitch = is_undef(pitch) ? INCH/tpi : pitch;
    trapezoidal_threaded_rod(
        d=d, l=l, pitch=pitch,
        thread_angle=29,
        thread_depth=pitch/2,
        starts=starts,
        left_handed=left_handed,
        bevel=bevel,bevel1=bevel1,bevel2=bevel2,
        internal=internal, length=length, height=height, h=h,
        blunt_start=blunt_start, blunt_start1=blunt_start1, blunt_start2=blunt_start2,
        lead_in=lead_in, lead_in1=lead_in1, lead_in2=lead_in2, lead_in_shape=lead_in_shape,
        lead_in_ang=lead_in_ang, lead_in_ang1=lead_in_ang1, lead_in_ang2=lead_in_ang2,
        end_len=end_len, end_len1=end_len1, end_len2=end_len2,
        anchor=anchor,
        spin=spin,
        orient=orient
    ) children();
}



// Module: acme_threaded_nut()
// Synopsis: Creates an ACME threaded nut.
// SynTags: Geom
// Topics: Threading, Screws
// See Also: acme_threaded_rod()
// Usage:
//   acme_threaded_nut(nutwidth, id, h|height|thickness, tpi|pitch=, [shape=], ...) [ATTACHMENTS];
// Description:
//   Constructs a hexagonal or square nut for an ACME threaded screw rod. 
// Arguments:
//   nutwidth = flat to flat width of nut. 
//   id = diameter of threaded rod to screw onto.
//   h / height / l / length / thickness = height/thickness of nut.
//   tpi = threads per inch
//   ---
//   pitch = Thread spacing (alternative to tpi)
//   shape = specifies shape of nut, either "hex" or "square".  Default: "hex"
//   left_handed = if true, create left-handed threads.  Default = false
//   starts = Number of lead starts.  Default: 1
//   bevel = if true, bevel the outside of the nut.  Default: true for hex nuts, false for square nuts
//   bevel1 = if true, bevel the outside of the nut bottom.
//   bevel2 = if true, bevel the outside of the nut top. 
//   bevang = set the angle for the outside nut bevel.  Default: 30
//   ibevel = if true, bevel the inside (the hole).   Default: true
//   ibevel1 = if true bevel the inside, bottom end.
//   ibevel2 = if true bevel the inside, top end.
//   blunt_start = If true apply truncated blunt start threads at both ends.  Default: true
//   blunt_start1 = If true apply truncated blunt start threads bottom end.
//   blunt_start2 = If true apply truncated blunt start threads top end.
//   end_len = Specify the unthreaded length at the end after blunt start threads.  Default: 0
//   end_len1 = Specify unthreaded length at the bottom
//   end_len2 = Specify unthreaded length at the top
//   lead_in = Specify linear length of the lead in section of the threading with blunt start threads
//   lead_in1 = Specify linear length of the lead in section of the threading at the bottom with blunt start threads
//   lead_in2 = Specify linear length of the lead in section of the threading at the top with blunt start threads
//   lead_in_ang = Specify angular length in degrees of the lead in section of the threading with blunt start threads
//   lead_in_ang1 = Specify angular length in degrees of the lead in section of the threading at the bottom with blunt start threads
//   lead_in_ang2 = Specify angular length in degrees of the lead in section of the threading at the top with blunt start threads
//   lead_in_shape = Specify the shape of the thread lead in by giving a text string or function.  Default: "default"
//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
//   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#subsection-spin).  Default: `0`
//   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
//   $slop = The printer-specific slop value, which adds clearance (`4*$slop`) to internal threads.
// Examples(Med):
//   acme_threaded_nut(nutwidth=16, id=3/8*INCH, h=8, tpi=8, $slop=0.05);
//   acme_threaded_nut(nutwidth=16, id=3/8*INCH, h=10, tpi=12, starts=3, $slop=0.1, $fa=1, $fs=1, ibevel=false);
//   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);
function acme_threaded_nut(
    nutwidth, id, h, tpi, pitch,
    starts=1,
    left_handed=false,shape="hex",
    bevel,bevel1,bevel2,bevang=30,
    ibevel,ibevel1,ibevel2,
    height,thickness,
    length, l,
    blunt_start, blunt_start1, blunt_start2,
    lead_in, lead_in1, lead_in2,
    lead_in_ang, lead_in_ang1, lead_in_ang2,
    end_len, end_len1, end_len2,
    lead_in_shape="default",
    anchor, spin, orient
) = no_function("acme_threaded_nut");
module acme_threaded_nut(
    nutwidth, id, h, tpi, pitch,
    starts=1,
    left_handed=false,shape="hex",
    bevel,bevel1,bevel2,bevang=30,
    ibevel,ibevel1,ibevel2,
    height,thickness,
    length, l,
    blunt_start, blunt_start1, blunt_start2,
    lead_in, lead_in1, lead_in2,
    lead_in_ang, lead_in_ang1, lead_in_ang2,
    end_len, end_len1, end_len2,
    lead_in_shape="default",
    anchor, spin, orient
) {
    dummy = assert(num_defined([pitch,tpi])==1,"Must give exactly one of pitch and tpi");
    pitch = is_undef(pitch) ? INCH/tpi : pitch;
    dummy2=assert(is_num(pitch) && pitch>=0);
    trapezoidal_threaded_nut(
        nutwidth=nutwidth, id=id, h=h, pitch=pitch,
        thread_depth = pitch/2, 
        thread_angle=29,shape=shape, 
        left_handed=left_handed,
        bevel=bevel,bevel1=bevel1,bevel2=bevel2,
        ibevel=ibevel,ibevel1=ibevel1,ibevel2=ibevel2,
        height=height,thickness=thickness,
        blunt_start=blunt_start, blunt_start1=blunt_start1, blunt_start2=blunt_start2,
        lead_in=lead_in, lead_in1=lead_in1, lead_in2=lead_in2, lead_in_shape=lead_in_shape,
        lead_in_ang=lead_in_ang, lead_in_ang1=lead_in_ang1, lead_in_ang2=lead_in_ang2,
        end_len=end_len, end_len1=end_len1, end_len2=end_len2,
        l=l,length=length,
        starts=starts,
        anchor=anchor,
        spin=spin,
        orient=orient
    ) children();
}




// Section: Pipe Threading

// Module: npt_threaded_rod()
// Synopsis: Creates NPT pipe threading.
// SynTags: Geom
// Topics: Threading, Screws
// See Also: acme_threaded_rod()
// Usage:
//   npt_threaded_rod(size, [internal=], ...) [ATTACHMENTS];
// Description:
//   Constructs a standard NPT pipe end threading. If `internal=true`, creates a mask for making
//   internal pipe threads.  Tapers smaller upwards if `internal=false`.  Tapers smaller downwards
//   if `internal=true`.  If `hollow=true` and `internal=false`, then the pipe threads will be
//   hollowed out into a pipe with the apropriate internal diameter.
// Arguments:
//   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"
//   ---
//   left_handed = If true, create left-handed threads.  Default = false
//   bevel = if true, bevel the thread ends.  Default: false
//   bevel1 = if true bevel the bottom end.
//   bevel2 = if true bevel the top end. 
//   hollow = If true, create a pipe with the correct internal diameter.
//   internal = If true, make this a mask for making internal threads.
//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
//   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#subsection-spin).  Default: `0`
//   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
//   $slop = The printer-specific slop value, which adds clearance (`4*$slop`) to internal threads.
// Example(2D): The straight gray rectangle reveals the tapered threads.  
//   projection(cut=true) npt_threaded_rod(size=1/4, orient=BACK);
//   right(.533*INCH/2) color("gray") rect([2,0.5946*INCH],anchor=LEFT);
// Examples(Med):
//   npt_threaded_rod(size=3/8, $fn=72);
//   npt_threaded_rod(size=1/2, $fn=72, bevel=true);
//   npt_threaded_rod(size=1/2, left_handed=true, $fn=72);
//   npt_threaded_rod(size=3/4, hollow=true, $fn=96);
// Example:
//   diff("remove"){
//      cuboid([40,40,40])
//      tag("remove"){
//        up(.01)position(TOP)
//            npt_threaded_rod(size=3/4, $fn=96, internal=true, $slop=0.1, anchor=TOP);
//        cyl(d=3/4*INCH, l=42, $fn=32);
//      }
//   }
function npt_threaded_rod(
    size=1/2,
    left_handed=false,
    bevel,bevel1,bevel2,
    hollow=false,
    internal=false,
    anchor, spin, orient
)=no_function("npt_threaded_rod");
module npt_threaded_rod(
    size=1/2,
    left_handed=false,
    bevel,bevel1,bevel2,
    hollow=false,
    internal=false,
    anchor, spin, orient
) {
    assert(is_finite(size));
    assert(is_bool(left_handed));
    assert(is_undef(bevel) || is_bool(bevel));
    assert(is_bool(hollow));
    assert(is_bool(internal));
    assert(!(internal&&hollow), "Cannot created a hollow internal threads mask.");
    info_table = [
        // Size    len      OD    TPI
        [ 1/16,  [ 0.3896, 0.308, 27  ]],
        [ 1/8,   [ 0.3924, 0.401, 27  ]],
        [ 1/4,   [ 0.5946, 0.533, 18  ]],
        [ 3/8,   [ 0.6006, 0.668, 18  ]],
        [ 1/2,   [ 0.7815, 0.832, 14  ]],
        [ 3/4,   [ 0.7935, 1.043, 14  ]],
        [ 1,     [ 0.9845, 1.305, 11.5]],
        [ 1+1/4, [ 1.0085, 1.649, 11.5]],
        [ 1+1/2, [ 1.0252, 1.888, 11.5]],
        [ 2,     [ 1.0582, 2.362, 11.5]],
    ];
    info = [for (data=info_table) if(approx(size,data[0])) data[1]][0];
    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");
    l = INCH * info[0];
    d = INCH * info[1];
    pitch = INCH / info[2];
    rr = d/2;
    rr2 = rr - l/32;
    r1 = internal? rr2 : rr;
    r2 = internal? rr : rr2;
    depth = pitch * cos(30) * 5/8;
    profile = internal? [
        [-6/16, -depth/pitch],
        [-1/16,  0],
        [-1/32,  0.02],
        [ 1/32,  0.02],
        [ 1/16,  0],
        [ 6/16, -depth/pitch]
    ] : [
        [-7/16, -depth/pitch*1.07],
        [-6/16, -depth/pitch],
        [-1/16,  0],
        [ 1/16,  0],
        [ 6/16, -depth/pitch],
        [ 7/16, -depth/pitch*1.07]
    ];
    attachable(anchor,spin,orient, l=l, r1=r1, r2=r2) {
        difference() {
            generic_threaded_rod(
                d1=2*r1, d2=2*r2, l=l,
                pitch=pitch,
                profile=profile,
                left_handed=left_handed,
                bevel=bevel,bevel1=bevel1,bevel2=bevel2,
                internal=internal,
                blunt_start=true
            );
            if (hollow) cylinder(h=l+1, d=size*INCH, center=true);
        }
        children();
    }
}



// Section: Buttress Threading

// Module: buttress_threaded_rod()
// Synopsis: Creates a buttress-threaded rod.
// SynTags: Geom
// Topics: Threading, Screws
// See Also: buttress_threaded_nut()
// Usage:
//   buttress_threaded_rod(d, l|length, pitch, [internal=], ...) [ATTACHMENTS];
// Description:
//   Constructs a simple buttress threaded rod with a 45 degree angle.  The buttress thread or sawtooth thread has low friction and high loading
//   in one direction at the cost of higher friction and inferior loading in the other direction.  Buttress threads are sometimes used on
//   vises, which are loaded only in one direction.  
// Arguments:
//   d = Outer diameter of threaded rod.
//   l / length / h / height = Length of threaded rod.
//   pitch = Thread spacing.
//   ---
//   left_handed = if true, create left-handed threads.  Default = false
//   starts = Number of lead starts.  Default: 1
//   bevel = if true, bevel the thread ends.  Default: false
//   bevel1 = if true bevel the bottom end.
//   bevel2 = if true bevel the top end. 
//   internal = If true, this is a mask for making internal threads.
//   blunt_start = If true apply truncated blunt start threads at both ends.  Default: true
//   blunt_start1 = If true apply truncated blunt start threads bottom end.
//   blunt_start2 = If true apply truncated blunt start threads top end.
//   end_len = Specify the unthreaded length at the end after blunt start threads.  Default: 0
//   end_len1 = Specify unthreaded length at the bottom
//   end_len2 = Specify unthreaded length at the top
//   lead_in = Specify linear length of the lead in section of the threading with blunt start threads
//   lead_in1 = Specify linear length of the lead in section of the threading at the bottom with blunt start threads
//   lead_in2 = Specify linear length of the lead in section of the threading at the top with blunt start threads
//   lead_in_ang = Specify angular length in degrees of the lead in section of the threading with blunt start threads
//   lead_in_ang1 = Specify angular length in degrees of the lead in section of the threading at the bottom with blunt start threads
//   lead_in_ang2 = Specify angular length in degrees of the lead in section of the threading at the top with blunt start threads
//   lead_in_shape = Specify the shape of the thread lead in by giving a text string or function.  Default: "default"
//   d1 = Bottom outside diameter of threads.
//   d2 = Top outside diameter of threads.
//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
//   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#subsection-spin).  Default: `0`
//   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
//   $slop = The printer-specific slop value, which adds clearance (`4*$slop`) to internal threads.
// Example(2D):
//   projection(cut=true)
//       buttress_threaded_rod(d=10, l=15, pitch=2, orient=BACK);
// Examples(Med):
//   buttress_threaded_rod(d=25, l=20, pitch=2, $fa=1, $fs=1,end_len=0);
//   buttress_threaded_rod(d=10, l=20, pitch=1.25, left_handed=true, $fa=1, $fs=1);
function buttress_threaded_rod(
    d, l, pitch,
    left_handed=false, starts=1,
    bevel,bevel1,bevel2,
    internal=false,
    d1, d2, length, h, height,
    blunt_start, blunt_start1, blunt_start2,
    lead_in, lead_in1, lead_in2,
    lead_in_ang, lead_in_ang1, lead_in_ang2,
    end_len, end_len1, end_len2,
    lead_in_shape="default",
    anchor, spin, orient
) = no_function("buttress_threaded_rod");
module buttress_threaded_rod(
    d, l, pitch,
    left_handed=false, starts=1,
    bevel,bevel1,bevel2,
    internal=false,
    d1, d2, length, h, height,
    blunt_start, blunt_start1, blunt_start2,
    lead_in, lead_in1, lead_in2,
    lead_in_ang, lead_in_ang1, lead_in_ang2,
    end_len, end_len1, end_len2,
    lead_in_shape="default",
    anchor, spin, orient
) {
    depth = pitch * 3/4;
    profile = [
        [  -1/2, -0.77],
        [ -7/16, -0.75],
        [  5/16,  0],
        [  7/16,  0],
        [  7/16, -0.75],
        [   1/2, -0.77],
    ];
    generic_threaded_rod(
        d=d, l=l, pitch=pitch,
        profile=profile, 
        left_handed=left_handed,
        bevel=bevel,bevel1=bevel1,bevel2=bevel2,
        internal=internal, length=length, height=height, h=h,
        blunt_start=blunt_start, blunt_start1=blunt_start1, blunt_start2=blunt_start2,
        lead_in=lead_in, lead_in1=lead_in1, lead_in2=lead_in2, lead_in_shape=lead_in_shape,
        lead_in_ang=lead_in_ang, lead_in_ang1=lead_in_ang1, lead_in_ang2=lead_in_ang2,
        end_len=end_len, end_len1=end_len1, end_len2=end_len2,
        d1=d1,d2=d2,
        anchor=anchor,
        spin=spin,starts=starts,
        orient=orient
    ) children();
}



// Module: buttress_threaded_nut()
// Synopsis: Creates a buttress-threaded nut.
// SynTags: Geom
// Topics: Threading, Screws
// See Also: buttress_threaded_rod()
// Usage:
//   buttress_threaded_nut(nutwidth, id, h|height|thickness, pitch, ...) [ATTACHMENTS];
// Description:
//   Constructs a hexagonal or square nut for a simple buttress threaded screw rod.  
// Arguments:
//   nutwidth = diameter of the nut.
//   id = diameter of threaded rod to screw onto.
//   h / height / l / length / thickness = height/thickness of nut.
//   pitch = Thread spacing. 
//   ---
//   shape = specifies shape of nut, either "hex" or "square".  Default: "hex"
//   left_handed = if true, create left-handed threads.  Default = false
//   starts = The number of lead starts.  Default: 1
//   bevel = if true, bevel the outside of the nut.  Default: true for hex nuts, false for square nuts
//   bevel1 = if true, bevel the outside of the nut bottom.
//   bevel2 = if true, bevel the outside of the nut top. 
//   bevang = set the angle for the outside nut bevel.  Default: 30
//   ibevel = if true, bevel the inside (the hole).   Default: true
//   ibevel1 = if true bevel the inside, bottom end.
//   ibevel2 = if true bevel the inside, top end.
//   blunt_start = If true apply truncated blunt start threads at both ends.  Default: true
//   blunt_start1 = If true apply truncated blunt start threads bottom end.
//   blunt_start2 = If true apply truncated blunt start threads top end.
//   end_len = Specify the unthreaded length at the end after blunt start threads.  Default: 0
//   end_len1 = Specify unthreaded length at the bottom
//   end_len2 = Specify unthreaded length at the top
//   lead_in = Specify linear length of the lead in section of the threading with blunt start threads
//   lead_in1 = Specify linear length of the lead in section of the threading at the bottom with blunt start threads
//   lead_in2 = Specify linear length of the lead in section of the threading at the top with blunt start threads
//   lead_in_ang = Specify angular length in degrees of the lead in section of the threading with blunt start threads
//   lead_in_ang1 = Specify angular length in degrees of the lead in section of the threading at the bottom with blunt start threads
//   lead_in_ang2 = Specify angular length in degrees of the lead in section of the threading at the top with blunt start threads
//   lead_in_shape = Specify the shape of the thread lead in by giving a text string or function.  Default: "default"
//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
//   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#subsection-spin).  Default: `0`
//   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
//   $slop = The printer-specific slop value, which adds clearance (`4*$slop`) to internal threads.
// Examples(Med):
//   buttress_threaded_nut(nutwidth=16, id=8, h=8, pitch=1.25, left_handed=true, $slop=0.05, $fa=1, $fs=1);
function buttress_threaded_nut(
    nutwidth, id, h,
    pitch, shape="hex", left_handed=false,
    bevel,bevel1,bevel2,bevang=30,starts=1,
    ibevel,ibevel1,ibevel2,height,thickness,
    length, l,
    blunt_start, blunt_start1, blunt_start2,
    lead_in, lead_in1, lead_in2,
    lead_in_ang, lead_in_ang1, lead_in_ang2,
    end_len, end_len1, end_len2,
    lead_in_shape="default",
    anchor, spin, orient
) = no_function("buttress_threaded_nut");
module buttress_threaded_nut(
    nutwidth, id, h,
    pitch, shape="hex", left_handed=false,
    bevel,bevel1,bevel2,bevang=30,starts=1,
    ibevel,ibevel1,ibevel2,height,thickness,
    length, l,
    blunt_start, blunt_start1, blunt_start2,
    lead_in, lead_in1, lead_in2,
    lead_in_ang, lead_in_ang1, lead_in_ang2,
    end_len, end_len1, end_len2,
    lead_in_shape="default",
    anchor, spin, orient
) {
    depth = pitch * 3/4;
    profile = [
        [  -1/2, -0.77],
        [ -7/16, -0.75],
        [  5/16,  0],
        [  7/16,  0],
        [  7/16, -0.75],
        [  1/ 2, -0.77],
    ];
    generic_threaded_nut(
        nutwidth=nutwidth, id=id, h=h,
        pitch=pitch,
        profile=profile,
        shape=shape,
        left_handed=left_handed,starts=starts,
        bevel=bevel,bevel1=bevel1,bevel2=bevel2,bevang=bevang,
        ibevel=ibevel,ibevel1=ibevel1,ibevel2=ibevel2,
        blunt_start=blunt_start, blunt_start1=blunt_start1, blunt_start2=blunt_start2,
        lead_in=lead_in, lead_in1=lead_in1, lead_in2=lead_in2, lead_in_shape=lead_in_shape,
        lead_in_ang=lead_in_ang, lead_in_ang1=lead_in_ang1, lead_in_ang2=lead_in_ang2,
        end_len=end_len, end_len1=end_len1, end_len2=end_len2,
        l=l,length=length,
        anchor=anchor, spin=spin, height=height, thickness=thickness, 
        orient=orient
    ) children();
}



// Section: Square Threading

// Module: square_threaded_rod()
// Synopsis: Creates a square-threaded rod.
// SynTags: Geom
// Topics: Threading, Screws
// See Also: square_threaded_nut()
// Usage:
//   square_threaded_rod(d, l|length, pitch, [internal=], ...) [ATTACHMENTS];
// Description:
//   Constructs a square profile threaded screw rod.  The greatest advantage of square threads is
//   that they have the least friction and a much higher intrinsic efficiency than trapezoidal threads.
//   They produce no radial load on the nut.  However, square threads cannot carry as much load as trapezoidal threads. 
// Arguments:
//   d = Outer diameter of threaded rod.
//   l / length / h / height = Length of threaded rod.
//   pitch = Thread spacing.
//   ---
//   left_handed = if true, create left-handed threads.  Default = false
//   starts = The number of lead starts.  Default = 1
//   bevel = if true, bevel the thread ends.  Default: false
//   bevel1 = if true bevel the bottom end.
//   bevel2 = if true bevel the top end. 
//   internal = If true, this is a mask for making internal threads.
//   blunt_start = If true apply truncated blunt start threads at both ends.  Default: true
//   blunt_start1 = If true apply truncated blunt start threads bottom end.
//   blunt_start2 = If true apply truncated blunt start threads top end.
//   end_len = Specify the unthreaded length at the end after blunt start threads.  Default: 0
//   end_len1 = Specify unthreaded length at the bottom
//   end_len2 = Specify unthreaded length at the top
//   lead_in = Specify linear length of the lead in section of the threading with blunt start threads
//   lead_in1 = Specify linear length of the lead in section of the threading at the bottom with blunt start threads
//   lead_in2 = Specify linear length of the lead in section of the threading at the top with blunt start threads
//   lead_in_ang = Specify angular length in degrees of the lead in section of the threading with blunt start threads
//   lead_in_ang1 = Specify angular length in degrees of the lead in section of the threading at the bottom with blunt start threads
//   lead_in_ang2 = Specify angular length in degrees of the lead in section of the threading at the top with blunt start threads
//   lead_in_shape = Specify the shape of the thread lead in by giving a text string or function.  Default: "default"
//   d1 = Bottom outside diameter of threads.
//   d2 = Top outside diameter of threads.
//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
//   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#subsection-spin).  Default: `0`
//   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
//   $slop = The printer-specific slop value, which adds clearance (`4*$slop`) to internal threads.
// Example(2D):
//   projection(cut=true)
//       square_threaded_rod(d=10, l=15, pitch=2, orient=BACK);
// Examples(Med):
//   square_threaded_rod(d=10, l=20, pitch=2, starts=2, $fn=32);
function square_threaded_rod(
    d, l, pitch,
    left_handed=false,
    bevel,bevel1,bevel2,
    starts=1,
    internal=false,
    d1, d2, length, h, height,
    blunt_start, blunt_start1, blunt_start2,
    lead_in, lead_in1, lead_in2,
    lead_in_ang, lead_in_ang1, lead_in_ang2,
    end_len, end_len1, end_len2,
    lead_in_shape="default",
    anchor, spin, orient
) = no_function("square_threaded_rod");
module square_threaded_rod(
    d, l, pitch,
    left_handed=false,
    bevel,bevel1,bevel2,
    starts=1,
    internal=false,
    d1, d2, length, h, height,
    blunt_start, blunt_start1, blunt_start2,
    lead_in, lead_in1, lead_in2,
    lead_in_ang, lead_in_ang1, lead_in_ang2,
    end_len, end_len1, end_len2,
    lead_in_shape="default",
    anchor, spin, orient
) {
    trapezoidal_threaded_rod(
        d=d, l=l, pitch=pitch,
        thread_angle=0.1,
        left_handed=left_handed,
        bevel=bevel,bevel1=bevel1,bevel2=bevel2,
        starts=starts,
        internal=internal, length=length, height=height, h=h,
        blunt_start=blunt_start, blunt_start1=blunt_start1, blunt_start2=blunt_start2,
        lead_in=lead_in, lead_in1=lead_in1, lead_in2=lead_in2, lead_in_shape=lead_in_shape,
        lead_in_ang=lead_in_ang, lead_in_ang1=lead_in_ang1, lead_in_ang2=lead_in_ang2,
        end_len=end_len, end_len1=end_len1, end_len2=end_len2,
        d1=d1,
        d2=d2,
        anchor=anchor,
        spin=spin,
        orient=orient
    ) children();
}



// Module: square_threaded_nut()
// Synopsis: Creates a square-threaded nut.
// SynTags: Geom
// Topics: Threading, Screws
// See Also: square_threaded_rod()
// Usage:
//   square_threaded_nut(nutwidth, id, h|height|thickness, pitch, ...) [ATTACHMENTS];
// Description:
//   Constructs a hexagonal or square nut for a square profile threaded screw rod.  
// Arguments:
//   nutwidth = diameter of the nut.
//   id = diameter of threaded rod to screw onto.
//   h / height / l / length / thickness = height/thickness of nut.
//   pitch = Length between threads.
//   ---
//   shape = specifies shape of nut, either "hex" or "square".  Default: "hex"
//   left_handed = if true, create left-handed threads.  Default = false
//   starts = The number of lead starts.  Default = 1
//   bevel = if true, bevel the outside of the nut.  Default: true for hex nuts, false for square nuts
//   bevel1 = if true, bevel the outside of the nut bottom.
//   bevel2 = if true, bevel the outside of the nut top. 
//   bevang = set the angle for the outside nut bevel.  Default: 30
//   ibevel = if true, bevel the inside (the hole).   Default: true
//   ibevel1 = if true bevel the inside, bottom end.
//   ibevel2 = if true bevel the inside, top end.
//   blunt_start = If true apply truncated blunt start threads at both ends.  Default: true
//   blunt_start1 = If true apply truncated blunt start threads bottom end.
//   blunt_start2 = If true apply truncated blunt start threads top end.
//   end_len = Specify the unthreaded length at the end after blunt start threads.  Default: 0
//   end_len1 = Specify unthreaded length at the bottom
//   end_len2 = Specify unthreaded length at the top
//   lead_in = Specify linear length of the lead in section of the threading with blunt start threads
//   lead_in1 = Specify linear length of the lead in section of the threading at the bottom with blunt start threads
//   lead_in2 = Specify linear length of the lead in section of the threading at the top with blunt start threads
//   lead_in_ang = Specify angular length in degrees of the lead in section of the threading with blunt start threads
//   lead_in_ang1 = Specify angular length in degrees of the lead in section of the threading at the bottom with blunt start threads
//   lead_in_ang2 = Specify angular length in degrees of the lead in section of the threading at the top with blunt start threads
//   lead_in_shape = Specify the shape of the thread lead in by giving a text string or function.  Default: "default"
//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
//   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#subsection-spin).  Default: `0`
//   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
//   $slop = The printer-specific slop value, which adds clearance (`4*$slop`) to internal threads.
// Examples(Med):
//   square_threaded_nut(nutwidth=16, id=10, h=10, pitch=2, starts=2, $slop=0.1, $fn=32);
function square_threaded_nut(
    nutwidth, id, h,
    pitch,
    left_handed=false,
    bevel,bevel1,bevel2,bevang=30,
    ibevel,ibevel1,ibevel2,
    height,thickness,    
    length, l,
    blunt_start, blunt_start1, blunt_start2,
    lead_in, lead_in1, lead_in2,
    lead_in_ang, lead_in_ang1, lead_in_ang2,
    end_len, end_len1, end_len2,
    lead_in_shape="default",
    starts=1,
    anchor, spin, orient
) = no_function("square_threaded_nut");
module square_threaded_nut(
    nutwidth, id, h,
    pitch,
    left_handed=false,
    bevel,bevel1,bevel2,bevang=30,
    ibevel,ibevel1,ibevel2,
    height,thickness,    
    length, l,
    blunt_start, blunt_start1, blunt_start2,
    lead_in, lead_in1, lead_in2,
    lead_in_ang, lead_in_ang1, lead_in_ang2,
    end_len, end_len1, end_len2,
    lead_in_shape="default",
    starts=1,
    anchor, spin, orient
) {
    assert(is_num(pitch) && pitch>=0)
    trapezoidal_threaded_nut(
        nutwidth=nutwidth, id=id, h=h, pitch=pitch,
        thread_angle=0,
        left_handed=left_handed,
        bevel=bevel,bevel1=bevel1,bevel2=bevel2, bevang=bevang,
        ibevel=ibevel, ibevel1=ibevel1, ibevel2=ibevel2,
        height=height,thickness=thickness,
        starts=starts,
        blunt_start=blunt_start, blunt_start1=blunt_start1, blunt_start2=blunt_start2,
        lead_in=lead_in, lead_in1=lead_in1, lead_in2=lead_in2, lead_in_shape=lead_in_shape,
        lead_in_ang=lead_in_ang, lead_in_ang1=lead_in_ang1, lead_in_ang2=lead_in_ang2,
        end_len=end_len, end_len1=end_len1, end_len2=end_len2,
        l=l,length=length,
        anchor=anchor,
        spin=spin,
        orient=orient
    ) children();
}


// Section: Ball Screws

// Module: ball_screw_rod()
// Synopsis: Creates a ball screw rod.
// SynTags: Geom
// Topics: Threading, Screws
// Usage:
//   ball_screw_rod(d, l|length, pitch, [ball_diam], [ball_arc], [internal=], ...) [ATTACHMENTS];
// Description:
//   Constructs a ball screw rod.  This type of rod is used with ball bearings.  
// Arguments:
//   d = Outer diameter of threaded rod.
//   l / length / h / height = Length of threaded rod.
//   pitch = Thread spacing. Also, the diameter of the ball bearings used.
//   ball_diam = The diameter of the ball bearings to use with this ball screw.
//   ball_arc = The arc portion that should touch the ball bearings. Default: 120 degrees.
//   ---
//   left_handed = if true, create left-handed threads.  Default = false
//   starts = The number of lead starts.  Default = 1
//   bevel = if true, bevel the thread ends.  Default: false
//   bevel1 = if true bevel the bottom end.
//   bevel2 = if true bevel the top end. 
//   internal = If true, make this a mask for making internal threads.
//   blunt_start = If true apply truncated blunt start threads at both ends.  Default: true
//   blunt_start1 = If true apply truncated blunt start threads bottom end.
//   blunt_start2 = If true apply truncated blunt start threads top end.
//   end_len = Specify the unthreaded length at the end after blunt start threads.  Default: 0
//   end_len1 = Specify unthreaded length at the bottom
//   end_len2 = Specify unthreaded length at the top
//   lead_in = Specify linear length of the lead in section of the threading with blunt start threads
//   lead_in1 = Specify linear length of the lead in section of the threading at the bottom with blunt start threads
//   lead_in2 = Specify linear length of the lead in section of the threading at the top with blunt start threads
//   lead_in_ang = Specify angular length in degrees of the lead in section of the threading with blunt start threads
//   lead_in_ang1 = Specify angular length in degrees of the lead in section of the threading at the bottom with blunt start threads
//   lead_in_ang2 = Specify angular length in degrees of the lead in section of the threading at the top with blunt start threads
//   lead_in_shape = Specify the shape of the thread lead in by giving a text string or function.  Default: "default"
//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
//   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#subsection-spin).  Default: `0`
//   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
//   $slop = The printer-specific slop value, which adds clearance (`4*$slop`) to internal threads.
// Example(2D): Thread Profile, ball_diam=4, ball_arc=100
//   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);
// Example(2D): Thread Profile, ball_diam=4, ball_arc=120
//   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);
// Example(2D): Thread Profile, ball_diam=3, ball_arc=120
//   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);
// Examples(Med):
//   ball_screw_rod(d=15, l=20, pitch=8, ball_diam=5, ball_arc=120, $fa=1, $fs=0.5, blunt_start=false);
//   ball_screw_rod(d=15, l=20, pitch=5, ball_diam=4, ball_arc=120, $fa=1, $fs=0.5, blunt_start=false);
//   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);
function ball_screw_rod(
    d, l, pitch, 
    ball_diam=5, ball_arc=100,
    starts=1,
    left_handed=false,
    internal=false,
    length, h, height,
    bevel, bevel1, bevel2,
    blunt_start, blunt_start1, blunt_start2,
    lead_in, lead_in1, lead_in2,
    lead_in_ang, lead_in_ang1, lead_in_ang2,
    end_len, end_len1, end_len2,
    lead_in_shape="default",
    anchor, spin, orient
) = no_function("ball_screw_rod");
module ball_screw_rod(
    d, l, pitch, 
    ball_diam=5, ball_arc=100,
    starts=1,
    left_handed=false,
    internal=false,
    length, h, height,
    bevel, bevel1, bevel2,
    blunt_start, blunt_start1, blunt_start2,
    lead_in, lead_in1, lead_in2,
    lead_in_ang, lead_in_ang1, lead_in_ang2,
    end_len, end_len1, end_len2,
    lead_in_shape="default",
    anchor, spin, orient
) {
    n = max(3,ceil(segs(ball_diam/2)*ball_arc/2/360));
    depth = ball_diam * (1-cos(ball_arc/2))/2;
    cpy = ball_diam/2/pitch*cos(ball_arc/2);
    profile = [
        each arc(n=n, d=ball_diam/pitch, cp=[-0.5,cpy], start=270, angle=ball_arc/2),
        each arc(n=n, d=ball_diam/pitch, cp=[+0.5,cpy], start=270-ball_arc/2, angle=ball_arc/2)
    ];
    generic_threaded_rod(
        d=d, l=l, pitch=pitch,
        profile=profile,
        left_handed=left_handed,
        starts=starts,
        bevel=bevel,bevel1=bevel1,bevel2=bevel2,
        internal=internal, length=length, height=height, h=h,
        blunt_start=blunt_start, blunt_start1=blunt_start1, blunt_start2=blunt_start2,
        lead_in=lead_in, lead_in1=lead_in1, lead_in2=lead_in2, lead_in_shape=lead_in_shape,
        lead_in_ang=lead_in_ang, lead_in_ang1=lead_in_ang1, lead_in_ang2=lead_in_ang2,
        end_len=end_len, end_len1=end_len1, end_len2=end_len2,
        anchor=anchor,
        spin=spin,
        orient=orient
    ) children();
}


// Section: Generic Threading

// Module: generic_threaded_rod()
// Synopsis: Creates a generic threaded rod.
// SynTags: Geom
// Topics: Threading, Screws
// See Also: generic_threaded_nut()
// Usage:
//   generic_threaded_rod(d, l|length, pitch, profile, [internal=], ...) [ATTACHMENTS];
// Description:
//   Constructs a generic threaded rod using an arbitrary thread profile that you supply.  The rod can be tapered
//   (e.g. for pipe threads).  For specific thread types use other modules that supply the appropriate profile.
//   .
//   You give the profile as a 2D path that will be scaled by the pitch to produce the final thread shape.  The profile
//   X values must be between -1/2 and 1/2.  The Y=0 point will align with the specified rod diameter, so generally you
//   want a Y value of zero at the peak (which makes your specified diameter the outer diameter of the threads).  The
//   value in the valleys of the thread should then be `-depth/pitch` due to the scaling by the thread pitch.  The first
//   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
//   if unless the Y values differ from the interior points in the profile.  Generally you should center the profile
//   horizontally in the interval [-1/2, 1/2].
//   .
//   If internal is true then produce a thread mask to difference from an object.  When internal is true the rod
//   diameter is enlarged to correct for the polygonal nature of circles to ensure that the internal diameter is the
//   specified size.  The diameter is also increased by `4 * $slop` to create clearance for threading by allowing a `2 *
//   $slop` gap on each side.  If bevel is set to true and internal is false then the ends of the rod will be beveled.
//   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
//   bevel when subtracted from an object.  The bevel is at 45 deg and is the depth of the threads.
//   .
//   Blunt start threading, which is the default, specifies that the thread ends abruptly at its full width instead of
//   running off the end of the shaft and leaving a sharp edged partial thread at the end of the screw.  This makes
//   screws easier to start and prevents cross threading.  Blunt start threads should always be superior, and they are
//   faster to model, but if you really need standard threads that run off the end you can set `blunt_start=false`.
// Arguments:
//   d = Outer diameter of threaded rod.
//   l / length / h / height = Length of threaded rod.
//   pitch = Thread spacing.
//   profile = A 2D path giving the shape of a thread
//   ---
//   left_handed = If true, create left-handed threads.  Default: false
//   starts = The number of lead starts.  Default: 1
//   internal = If true, make this a mask for making internal threads.  Default: false
//   d1 = Bottom outside diameter of threads.
//   d2 = Top outside diameter of threads.
//   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
//   bevel1 = set bevel for bottom end. 
//   bevel2 = set bevel for top end.
//   blunt_start = If true apply truncated blunt start threads at both ends.  Default: true
//   blunt_start1 = If true apply truncated blunt start threads bottom end.
//   blunt_start2 = If true apply truncated blunt start threads top end.
//   end_len = Specify the unthreaded length at the end after blunt start threads.  Default: 0
//   end_len1 = Specify unthreaded length at the bottom
//   end_len2 = Specify unthreaded length at the top
//   lead_in = Specify linear length of the lead in section of the threading with blunt start threads
//   lead_in1 = Specify linear length of the lead in section of the threading at the bottom with blunt start threads
//   lead_in2 = Specify linear length of the lead in section of the threading at the top with blunt start threads
//   lead_in_ang = Specify angular length in degrees of the lead in section of the threading with blunt start threads
//   lead_in_ang1 = Specify angular length in degrees of the lead in section of the threading at the bottom with blunt start threads
//   lead_in_ang2 = Specify angular length in degrees of the lead in section of the threading at the top with blunt start threads
//   lead_in_shape = Specify the shape of the thread lead in by giving a text string or function.  Default: "default"
//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
//   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#subsection-spin).  Default: `0`
//   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
//   $slop = The printer-specific slop value, which adds clearance (`4*$slop`) to internal threads.
// Example(2DMed): Example Tooth Profile
//   pitch = 2;
//   depth = pitch * cos(30) * 5/8;
//   profile = [
//       [-7/16, -depth/pitch*1.07],
//       [-6/16, -depth/pitch],
//       [-1/16,  0],
//       [ 1/16,  0],
//       [ 6/16, -depth/pitch],
//       [ 7/16, -depth/pitch*1.07]
//   ];
//   stroke(profile, width=0.02);
// Example:
//   pitch = 2;
//   depth = pitch * cos(30) * 5/8;
//   profile = [
//       [-7/16, -depth/pitch*1.07],
//       [-6/16, -depth/pitch],
//       [-1/16,  0],
//       [ 1/16,  0],
//       [ 6/16, -depth/pitch],
//       [ 7/16, -depth/pitch*1.07]
//   ];
//   generic_threaded_rod(d=10, l=40, pitch=2, profile=profile);

function generic_threaded_rod(
    d, l, pitch, profile,
    left_handed=false, internal=false,
    bevel, bevel1, bevel2, 
    starts=1,
    d1, d2, length, h, height,
    blunt_start, blunt_start1, blunt_start2,
    lead_in, lead_in1, lead_in2,
    lead_in_ang, lead_in_ang1, lead_in_ang2,
    end_len, end_len1, end_len2,
    lead_in_shape="default",
    anchor, spin, orient
) = no_function("generic_threaded_rod");
module generic_threaded_rod(
    d, l, pitch, profile,
    left_handed=false, internal=false,
    bevel, bevel1, bevel2, 
    starts=1,
    d1, d2, length, h, height,
    blunt_start, blunt_start1, blunt_start2,
    lead_in, lead_in1, lead_in2,
    lead_in_ang, lead_in_ang1, lead_in_ang2,
    end_len, end_len1, end_len2,
    lead_in_shape="default",
    anchor, spin, orient
) {
    len = one_defined([l,length,h,height],"l,length,h,height");
    bevel1 = first_defined([bevel1,bevel]);
    bevel2 = first_defined([bevel2,bevel]);
    blunt_start1 = first_defined([blunt_start1, blunt_start, true]);
    blunt_start2 = first_defined([blunt_start2, blunt_start, true]);                           
    r1 = get_radius(d1=d1, d=d);
    r2 = get_radius(d1=d2, d=d);
    lead_in1 = first_defined([lead_in1, lead_in]);
    lead_in2 = first_defined([lead_in2, lead_in]);
    lead_in_func = is_func(lead_in_shape) ? lead_in_shape
                 : assert(is_string(lead_in_shape),"lead_in_shape must be a function or string")
                   let(ind = search([lead_in_shape], _lead_in_table,0)[0])
                   assert(ind!=[],str("Unknown lead_in_shape, \"",lead_in_shape,"\""))
                   _lead_in_table[ind[0]][1];
    dummy0 = 
      assert(all_positive([pitch]),"Thread pitch must be a positive value")
      assert(all_positive([len]),"Length must be a postive value")
      assert(is_path(profile),"Profile must be a path")
      assert(is_bool(blunt_start1), "blunt_start1/blunt_start must be boolean")
      assert(is_bool(blunt_start2), "blunt_start2/blunt_start must be boolean")
      assert(is_bool(left_handed))
      assert(all_positive([r1,r2]), "Must give d or both d1 and d2 as positive values")
      assert(is_undef(bevel1) || is_num(bevel1) || is_bool(bevel1) || bevel1=="reverse", "bevel1/bevel must be a number, boolean or \"reverse\"")
      assert(is_undef(bevel2) || is_num(bevel2) || is_bool(bevel2) || bevel2=="reverse", "bevel2/bevel must be a number, boolean or \"reverse\"");
    sides = quantup(segs(max(r1,r2)), starts);
    rsc = internal? (1/cos(180/sides)) : 1;    // Internal radius adjusted for faceting
    islop = internal? 2*get_slop() : 0;
    r1adj = r1 * rsc + islop;
    r2adj = r2 * rsc + islop;

    extreme = internal? max(column(profile,1)) : min(column(profile,1));
    profile = !internal ? profile
            : let(
                 maxidx = [for(i=idx(profile)) if (profile[i].y==extreme) i],
                 cutpt = len(maxidx)==1 ? profile(maxidx[0]).x
                       : mean([profile[maxidx[0]].x, profile[maxidx[1]].x])
              )
              [
                 for(entry=profile) if (entry.x>=cutpt) [entry.x-cutpt-1/2,entry.y], 
                 for(entry=profile) if (entry.x<cutpt) [entry.x-cutpt+1/2,entry.y]
              ];
    profmin = pitch * min(column(profile,1));
    pmax = pitch * max(column(profile,1));
    rmax = max(r1adj,r2adj)+pmax;

    // These parameters give the size of the bevel, negative for an outward bevel (e.g. on internal thread mask)  
    bev1 = (bevel1=="reverse"?-1:1)*(internal?-1:1) *
               ( is_num(bevel1)? bevel1
               : bevel1==false? 0
               : blunt_start1? (bevel1==undef?0
                               :internal ? r1/6
                               :(r1+profmin)/6)
               : pmax-profmin);
    bev2 = (bevel2=="reverse"?-1:1)*(internal?-1:1) *
               ( is_num(bevel2)? bevel2
               : bevel2==false? 0
               : blunt_start2? (bevel2==undef?0
                               :internal ? r2/6
                               :(r2+profmin)/6)
               : pmax-profmin);
    // This is the bevel size used for constructing the polyhedron.  The bevel is integrated when blunt start is on, but
    // applied later via difference/union if blunt start is off, so set bevel to zero in the latter case.  
    bevel_size1 = blunt_start1?bev1:0;
    bevel_size2 = blunt_start2?bev2:0;
    // This is the bevel size for clipping, which is only done when blunt start is off
    clip_bev1 = blunt_start1?0:bev1;
    clip_bev2 = blunt_start2?0:bev2;
    end_len1_base = !blunt_start1? 0 : first_defined([end_len1,end_len, 0]);
    end_len2_base = !blunt_start2? 0 : first_defined([end_len2,end_len, 0]);    
    // Enlarge end lengths to give sufficient room for requested bevel
    end_len1 = abs(bevel_size1)>0 ? max(end_len1_base, abs(bevel_size1)) : end_len1_base;
    end_len2 = abs(bevel_size2)>0 ? max(end_len2_base, abs(bevel_size2)) : end_len2_base;
    // length to create below/above z=0, with an extra revolution in non-blunt-start case so
    // the threads can continue to the specified length and we can clip off the blunt start                       
    len1 = -len/2 - (blunt_start1?0:pitch);   
    len2 =  len/2 + (blunt_start2?0:pitch);

    // Thread turns below and above z=0, with extra to ensure we go beyond the length needed
    turns1 = len1/pitch-1;
    turns2 = len2/pitch+1;
    dir = left_handed? -1 : 1;
    dummy2=
        assert(abs(bevel_size1)+abs(bevel_size2)<len, "Combined bevel size exceeds length of screw")
        assert(r1adj+extreme*pitch-bevel_size1>0, "bevel1 is too large to fit screw diameter")
        assert(r2adj+extreme*pitch-bevel_size2>0, "bevel2 is too large to fit screw diameter");
         
    margin1 = profile[0].y==extreme ? profile[0].x : -1/2;
    margin2 = last(profile).y==extreme? last(profile).x : 1/2;
    lead_in_default = pmax-profmin;//2*pitch;
        // 0*360/10;// /4/32*360; higlen_default;//0*4/32*360; //2/32*360;//360*max(pitch/2, pmax-depth)/(2*PI*r2adj);
    // lead_in length needs to be quantized to match the samples
    lead_in_ang1 = !blunt_start1? 0 :
         let(
             user_ang = first_defined([lead_in_ang1,lead_in_ang])
         )
         assert(is_undef(user_ang) || is_undef(lead_in1), "Cannot define lead_in/lead_in1 by both length and angle")
         quantup(
                 is_def(user_ang) ? user_ang : default(lead_in1, lead_in_default)*360/(2*PI*r1adj)
                 , 360/sides);
    lead_in_ang2 = !blunt_start2? 0 :
         let(
             user_ang = first_defined([lead_in_ang2,lead_in_ang])
         )
         assert(is_undef(user_ang) || is_undef(lead_in2), "Cannot define lead_in/lead_in2 by both length and angle")
         quantup(
                 is_def(user_ang) ? user_ang : default(lead_in2, lead_in_default)*360/(2*PI*r2adj)
                 , 360/sides);
    // cut_ang also need to be quantized, but the comparison is offset by 36*turns1/starts, so we need to pull that factor out
    // of the quantization.  (The loop over angle starts at 360*turns1/starts, not at a multiple of 360/sides.)  
//    cut_ang1 = 360 * (len1/pitch-margin1+end_len1/pitch) / starts + lead_in_ang1;
//    cut_ang2 = 360 * (len2/pitch-margin2-end_len2/pitch) / starts - lead_in_ang2;
    cut_ang1 = quantup(360 * (len1/pitch-margin1+end_len1/pitch) / starts + lead_in_ang1-360*turns1/starts,360/sides)+360*turns1/starts;
    cut_ang2 = quantdn(360 * (len2/pitch-margin2-end_len2/pitch) / starts - lead_in_ang2-360*turns1/starts,360/sides)+360*turns1/starts;
    dummy1 =
      assert(cut_ang1<cut_ang2, "lead in length are too long for the amount of thread: they overlap")
      assert(is_num(lead_in_ang1), "lead_in1/lead_in must be a number")
      assert(r1adj+profmin>0 && r2adj+profmin>0, "Screw profile deeper than rod radius");
    map_threads = right((r1adj + r2adj) / 2)                   // Shift profile out to thread radius
                * affine3d_skew(sxz=(r2adj-r1adj)/len)         // Skew correction for tapered threads
                * frame_map(x=[0,0,1], y=[1,0,0])          // Map profile to 3d, parallel to z axis
                * scale(pitch);                            // scale profile by pitch
    start_steps = sides / starts;

    // This is the location for clipping the polyhedron, below the bevel, if one is present, or at length otherwise
    // Clipping is done before scaling to pitch, so we need to divide by the pitch
    rod_clip1 = (len1+abs(bevel_size1))/pitch;
    rod_clip2 = (len2-abs(bevel_size2))/pitch;
    prof3d=path3d(profile,1);
    thread_verts = [
        // Outer loop constructs a vertical column of the screw at each angle
        // covering 360/starts degrees of the cylinder.  
        for (step = [0:1:start_steps])
            let(
                ang = 360 * step/sides,
                dz = step / start_steps,    // z offset for threads at this angle
                rot_prof = zrot(ang*dir)*map_threads,   // Rotate profile to correct angular location
                full_profile =  [   // profile for the entire rod
                    for (turns = [turns1:1:turns2]) 
                        let(
                            tang = turns/starts * 360 + ang,
                            // EPSILON offset prevents funny looking extensions of the thread from its very tip
                            // by forcing values near the tip to evaluate as less than zero = beyond the tip end
                            hsc = tang < cut_ang1 ? lead_in_func(-EPSILON+1-(cut_ang1-tang)/lead_in_ang1,PI*2*r1adj*lead_in_ang1/360 )
                                : tang > cut_ang2 ? lead_in_func(-EPSILON+1-(tang-cut_ang2)/lead_in_ang2,PI*2*r2adj*lead_in_ang2/360 )
                                : [1,1],
                            shift_and_scale = [[hsc.x, 0], [0,hsc.y], [dz+turns,(1-hsc.y)*extreme]]
                        )
                        // This is equivalent to apply(right(dz+turns)*higscale, profile)
                        //
                        // The right movement finds the position of the thread along
                        // what will be the z axis after the profile is mapped to 3d,
                        // and higscale creates a taper and the end of the threads.  
                        each prof3d*shift_and_scale
                ],
                // Clip profile at the ends of the rod and add a z coordinate
                full_profile_clipped = [
                    for(pts=full_profile) [max(rod_clip1,min(rod_clip2,pts.x)), pts.y, 0]
                ]
            )
            [
              [0,0,len1],
              //if (true) apply(rot_prof, [len1/pitch,extreme+2/pitch ,0]), 
              if (bevel_size1) apply(rot_prof, [len1/pitch,extreme-bevel_size1/pitch ,0]), 
              each apply(rot_prof, full_profile_clipped),
              if (bevel_size2) apply(rot_prof, [len2/pitch,extreme-bevel_size2/pitch ,0]), 
              //if (true) apply(rot_prof, [len2/pitch,extreme+2/pitch ,0]), 
              [0, 0, len2]
            ]
    ];
    style=internal?"concave":"convex";
    thread_vnf = vnf_join([
                           for (i=[0:1:starts-1])
                             zrot(i*360/starts, p=vnf_vertex_array(thread_verts, reverse=left_handed, style=style,col_wrap=false)),
                          ]);
    slope = (r1adj-r2adj)/len;
    dummy3 = 
      assert(r1adj+pmax-clip_bev1>0, "bevel1 is too large to fit screw diameter")
      assert(r2adj+pmax-clip_bev2>0, "bevel2 is too large to fit screw diameter")
      assert(abs(clip_bev1)+abs(clip_bev2)<len, "Combined bevel size exceeds length of screw");
    attachable(anchor,spin,orient, r1=r1adj, r2=r2adj, l=len) {
        union(){
          difference() {
              vnf_polyhedron(thread_vnf,convexity=10);              
              if (clip_bev1>0)
                  rotate_extrude()
                      polygon([[                         0,-len/2],
                               [r1adj+pmax-clip_bev1      ,-len/2],
                               [r1adj+pmax-slope*clip_bev1,-len/2+clip_bev1],
                               [                    rmax+1,-len/2+clip_bev1],
                               [                    rmax+1, len1-1],
                               [                         0, len1-1]]);
              if (clip_bev2>0)
                  rotate_extrude()
                      polygon([[                         0, len/2],
                               [r2adj+pmax-clip_bev2      , len/2],
                               [r2adj+pmax+slope*clip_bev2, len/2-clip_bev2],
                               [                    rmax+1, len/2-clip_bev2],
                               [                    rmax+1, len2+1],
                               [                         0, len2+1]]);
              if (!blunt_start1 && clip_bev1<=0)
                  down(len/2) cuboid([2*rmax+1,2*rmax+1, -len1+1], anchor=TOP);                     
              if (!blunt_start2 && clip_bev2<=0)
                  up(len/2) cuboid([2*rmax+1,2*rmax+1, len2+1], anchor=BOTTOM);
          }

          // Add bevel for internal thread mask
          if (clip_bev1<0) 
              down(len/2+.001)cyl(l=-clip_bev1, r2=r1adj+profmin, r1=r1adj+profmin+slope*clip_bev1-clip_bev1,anchor=BOTTOM);
          if (clip_bev2<0) 
              up(len/2+.001)cyl(l=-clip_bev2, r1=r2adj+profmin, r2=r2adj+profmin+slope*clip_bev1-clip_bev2,anchor=TOP);
        }
        children();
    }
}



// Module: generic_threaded_nut()
// Synopsis: Creates a generic threaded nut.
// SynTags: Geom
// Topics: Threading, Screws
// See Also: generic_threaded_rod()
// Usage:
//   generic_threaded_nut(nutwidth, id, h|height|thickness, pitch, profile, [$slop], ...) [ATTACHMENTS];
// Description:
//   Constructs a hexagonal or square nut for an generic threaded rod using a user-supplied thread profile.
//   See {{generic_threaded_rod()}} for details on the profile specification.  
// Arguments:
//   nutwidth = outer dimension of nut from flat to flat. 
//   id = diameter of threaded rod to screw onto.
//   h / height / thickness = height/thickness of nut.
//   pitch = Thread spacing.
//   profile = Thread profile.
//   ---
//   shape = specifies shape of nut, either "hex" or "square".  Default: "hex"
//   left_handed = if true, create left-handed threads.  Default = false
//   starts = The number of lead starts.  Default = 1
//   id1 = inner diameter at the bottom
//   id2 = inner diameter at the top
//   bevel = if true, bevel the outside of the nut.  Default: true for hex nuts, false for square nuts
//   bevel1 = if true, bevel the outside of the nut bottom.
//   bevel2 = if true, bevel the outside of the nut top. 
//   bevang = set the angle for the outside nut bevel.  Default: 30
//   ibevel = if true, bevel the inside (the hole).   Default: true
//   ibevel1 = if true bevel the inside, bottom end.
//   ibevel2 = if true bevel the inside, top end.
//   blunt_start = If true apply truncated blunt start threads at both ends.  Default: true
//   blunt_start1 = If true apply truncated blunt start threads bottom end.
//   blunt_start2 = If true apply truncated blunt start threads top end.
//   end_len = Specify the unthreaded length at the end after blunt start threads.  Default: 0
//   end_len1 = Specify unthreaded length at the bottom
//   end_len2 = Specify unthreaded length at the top
//   lead_in = Specify linear length of the lead in section of the threading with blunt start threads
//   lead_in1 = Specify linear length of the lead in section of the threading at the bottom with blunt start threads
//   lead_in2 = Specify linear length of the lead in section of the threading at the top with blunt start threads
//   lead_in_ang = Specify angular length in degrees of the lead in section of the threading with blunt start threads
//   lead_in_ang1 = Specify angular length in degrees of the lead in section of the threading at the bottom with blunt start threads
//   lead_in_ang2 = Specify angular length in degrees of the lead in section of the threading at the top with blunt start threads
//   lead_in_shape = Specify the shape of the thread lead in by giving a text string or function.  Default: "default"
//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
//   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#subsection-spin).  Default: `0`
//   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
//   $slop = The printer-specific slop value, which adds clearance (`4*$slop`) to internal threads.
function generic_threaded_nut(
    nutwidth,
    id,
    h,
    pitch,
    profile,
    shape="hex",
    left_handed=false,
    starts=1,
    bevel,bevel1,bevel2,bevang=30,
    ibevel, ibevel1, ibevel2,
    id1,id2, height, thickness, 
    length, l,
    blunt_start, blunt_start1, blunt_start2,
    lead_in, lead_in1, lead_in2,
    lead_in_ang, lead_in_ang1, lead_in_ang2,
    end_len, end_len1, end_len2,
    lead_in_shape="default",
    anchor, spin, orient
) = no_function("generic_threaded_nut");
module generic_threaded_nut(
    nutwidth,
    id,
    h,
    pitch,
    profile,
    shape="hex",
    left_handed=false,
    starts=1,
    bevel,bevel1,bevel2,bevang=30,
    ibevel, ibevel1, ibevel2,
    id1,id2, height, thickness, 
    length, l,
    blunt_start, blunt_start1, blunt_start2,
    lead_in, lead_in1, lead_in2,
    lead_in_ang, lead_in_ang1, lead_in_ang2,
    end_len, end_len1, end_len2,
    lead_in_shape="default",
    anchor, spin, orient
) {
    
    extra = 0.01;
    id1 = first_defined([id1,id]);
    id2 = first_defined([id2,id]);
    h = one_defined([h,height,thickness,l,length],"h,height,thickness,l,length");
    dummyA = assert(is_num(pitch) && pitch>=0, "pitch must be a nonnegative number")
             assert(is_num(h) && h>0, "height/thickness must be a positive number")
             assert(in_list(shape,["square","hex"]), "shape must be \"hex\" or \"square\"")
             assert(all_positive([id1,id2]), "Inner diameter(s) of nut must be positive number(s)");
    slope = (id2-id1)/h;
    full_id1 = id1-slope*extra/2;
    full_id2 = id2+slope*extra/2;
    ibevel1 = first_defined([ibevel1,ibevel,true]);
    ibevel2 = first_defined([ibevel2,ibevel,true]);
    bevel1 = first_defined([bevel1,bevel,shape=="hex"?true:false]);
    bevel2 = first_defined([bevel2,bevel,shape=="hex"?true:false]);
    depth = -pitch*min(column(profile,1));
    IBEV=0.05;
    vnf = linear_sweep(hexagon(id=nutwidth), height=h, center=true);
    attachable(anchor,spin,orient, size=shape=="square" ? [nutwidth,nutwidth,h] : undef, vnf=shape=="hex" ? vnf : undef) {
        difference() {
            _nutshape(nutwidth,h, shape,bevel1,bevel2);
            if (pitch==0) 
               cyl(l=h+extra, d1=full_id1+4*get_slop(), d2=full_id2+4*get_slop(),
                   chamfer1=ibevel1?-IBEV*full_id1:undef,
                   chamfer2=ibevel2?-IBEV*full_id2:undef);
            else
               generic_threaded_rod(
                     d1=full_id1,d2=full_id2,
                     l=h+extra,
                     pitch=pitch,
                     profile=profile,
                     left_handed=left_handed,
                     starts=starts,
                     internal=true,
                     bevel1=ibevel1,bevel2=ibevel2,
                     blunt_start=blunt_start, blunt_start1=blunt_start1, blunt_start2=blunt_start2,
                     lead_in=lead_in, lead_in1=lead_in1, lead_in2=lead_in2, lead_in_shape=lead_in_shape,
                     lead_in_ang=lead_in_ang, lead_in_ang1=lead_in_ang1, lead_in_ang2=lead_in_ang2,
                     end_len=end_len, end_len1=end_len1, end_len2=end_len2
                );
        }
        children();
    }
}


module _nutshape(nutwidth, h, shape, bevel1, bevel2)
{
   bevel_d=0.9;
   intersection(){
       if (shape=="hex")
         cyl(d=nutwidth, circum=true, $fn=6, l=h, chamfer1=bevel1?0:nutwidth*.01, chamfer2=bevel2?0:nutwidth*.01);
        //vnf_polyhedron(vnf);
       else
         cuboid([nutwidth,nutwidth,h],chamfer=nutwidth*.01, except=[if (bevel1) BOT, if(bevel2) TOP]);
       fn = quantup(segs(r=nutwidth/2),shape=="hex"?6:4);
       d = shape=="hex" ? 2*nutwidth/sqrt(3) : sqrt(2)*nutwidth;
       chamfsize = (d-nutwidth)/2/bevel_d;
       cyl(d=d*.99,h=h+.01,realign=true,circum=true,$fn=fn,chamfer1=bevel1?chamfsize:0,chamfer2=bevel2?chamfsize:0,chamfang=30);
   }
}


// Module: thread_helix()
// Synopsis: Creates a thread helix to add to a cylinder.
// SynTags: Geom
// Topics: Threading, Screws
// See Also: generic_threaded_rod()
// Usage:
//   thread_helix(d, pitch, [thread_depth], [flank_angle], [turns], [profile=], [left_handed=], [higbee=], [internal=]);
// Description:
//   Creates a right-handed helical thread with optional end tapering.  Unlike
//   {{generic_threaded_rod()}, this module just generates the thread, and you specify the total
//   angle of threading that you want, which makes it easy to put complete threads onto a longer
//   shaft.  It also optionally makes a finely divided taper at the thread ends.  However, it takes
//   2-3 times as long to render compared to {{generic_threaded_rod()}}.  This module was designed
//   to handle threads found in plastic and glass bottles.
//   .
//   You can specify a thread_depth and flank_angle, in which case you get a symmetric trapezoidal
//   thread, whose inner diameter (the base of the threads for external threading) is d (so the
//   total diameter will be d + thread_depth).  This differs from the threaded_rod modules, where
//   the specified diameter is the outer diameter.  Alternatively you can give a profile, following
//   the same rules as for general_threaded_rod.  The Y=0 point will align with the specified
//   diameter, and the profile should range in X from -1/2 to 1/2.  You cannot specify both the
//   profile and the thread_depth or flank_angle.
//   .
//   Unlike {{generic_threaded_rod()}, when internal=true this module generates the threads, not a thread mask.
//   The profile needs to be inverted to produce the proper thread form.  If you use the built-in trapezoidal
//   thread you get the inverted thread, designed so that the inner diameter is d.  If you supply a custom profile
//   you must invert it yourself to get internal threads.  With adequate clearance
//   this thread will mate with the thread that uses the same parameters but has internal=false.  Note that
//   unlike the threaded_rod modules, thread_helix does not adjust the diameter for faceting, nor does it
//   subtract any $slop for clearance.  
//   .
//   The taper options specify tapering at of the threads at each end, and is given as the linear distance
//   over which to taper.  If taper is positive the threads are lengthened by the specified distance; if taper
//   is negative, the taper is included in the thread length specified by `turns`.  Tapering works on both internal and external threads.  
// Figure(2D,Med,NoAxes):
//   pa_delta = tan(15)/4;
//      rr1 = -1/2;
//      z1 = 1/4-pa_delta;
//      z2 = 1/4+pa_delta;
//      profile = [
//                  [-z2, rr1],
//                  [-z1,  0],
//                  [ z1,  0],
//                  [ z2, rr1],
//                ];
//      fullprofile = 50*left(1/2,p=concat(profile, right(1, p=profile)));
//      stroke(fullprofile,width=1);
//      dir = fullprofile[2]-fullprofile[3];
//      dir2 = fullprofile[5]-fullprofile[4];
//      curve = arc(15,angle=[75,87],r=40 /*67.5*/);
//      avgpt = mean([fullprofile[5]+.1*dir2, fullprofile[5]+.4*dir2]);
//      color("red"){
//       stroke([fullprofile[4]+[0,1], fullprofile[4]+[0,37]], width=1);
//       stroke([fullprofile[5]+.1*dir2, fullprofile[5]+.4*dir2], width=1);
//       stroke(move(-curve[0]+avgpt,p=curve), width=0.71,endcaps="arrow2");
//       right(14)back(19)text("flank",size=4,halign="center");
//       right(14)back(14)text("angle",size=4,halign="center");
//      }
// Figure(2D,Med,NoAxes):
//   pa_delta = tan(15)/4;
//   rr1 = -1/2;
//   z1 = 1/4-pa_delta;
//   z2 = 1/4+pa_delta;
//   profile = [
//               [-z2, rr1],
//               [-z1,  0],
//               [ z1,  0],
//               [ z2, rr1],
//             ];
//   fullprofile = 50*left(1/2,p=concat(profile, right(1, p=profile)));
//   stroke(fullprofile,width=1);
//   dir = fullprofile[2]-fullprofile[3];
//   dir2 = fullprofile[5]-fullprofile[4];
//   curve = arc(32,angle=[75,105],r=67.5);
//   avgpt = mean([fullprofile[5]+.1*dir2, fullprofile[5]+.4*dir2]);
//   color("red"){
//    stroke([fullprofile[2]+.1*dir, fullprofile[2]+.4*dir], width=1);
//    stroke([fullprofile[5]+.1*dir2, fullprofile[5]+.4*dir2], width=1);
//    stroke(move(-curve[0]+avgpt,p=curve), width=1,endcaps="arrow2");
//    back(10)text("thread",size=4,halign="center");
//    back(3)text("angle",size=4,halign="center");
//   }
// Arguments:
//   d = Inside base diameter of threads.  Default: 10
//   pitch = Distance between threads.  Default: 2
//   ---
//   thread_depth = Depth of threads from top to bottom.
//   flank_angle = Angle of thread faces to plane perpendicular to screw.  Default: 15 degrees.
//   turns = Number of revolutions to rotate thread around.
//   thread_angle = Angle between two thread faces.  
//   profile = If an asymmetrical thread profile is needed, it can be specified here.
//   starts = The number of thread starts.  Default: 1
//   left_handed = If true, thread has a left-handed winding.
//   internal = if true make internal threads.  The only effect this has is to change how the threads taper if tapering is selected. When true, threads taper towards the outside; when false, they taper towards the inside.  Default: false
//   d1 = Bottom inside base diameter of threads.
//   d2 = Top inside base diameter of threads.
//   thread_angle = Angle between 
//   lead_in = Specify linear length of the lead in section of the threading with blunt start threads
//   lead_in1 = Specify linear length of the lead in section of the threading at the bottom with blunt start threads
//   lead_in2 = Specify linear length of the lead in section of the threading at the top with blunt start threads
//   lead_in_ang = Specify angular length in degrees of the lead in section of the threading with blunt start threads
//   lead_in_ang1 = Specify angular length in degrees of the lead in section of the threading at the bottom with blunt start threads
//   lead_in_ang2 = Specify angular length in degrees of the lead in section of the threading at the top with blunt start threads
//   lead_in_shape = Specify the shape of the thread lead in by giving a text string or function.  Default: "default"
//   lead_in_sample = Factor to increase sample rate in the lead-in section.  Default: 10
//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#subsection-anchor).  Default: `CENTER`
//   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#subsection-spin).  Default: `0`
//   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#subsection-orient).  Default: `UP`
// Example(2DMed): Typical Tooth Profile
//   pitch = 2;
//   depth = pitch * cos(30) * 5/8;
//   profile = [
//       [-6/16, 0           ],
//       [-1/16, depth/pitch ],
//       [ 1/16, depth/pitch ],
//       [ 6/16, 0           ],
//   ];
//   stroke(profile, width=0.02);
// Examples:
//   thread_helix(d=10, pitch=2, thread_depth=0.75, flank_angle=15, turns=2.5, $fn=72);
//   thread_helix(d=10, pitch=2, thread_depth=0.75, flank_angle=15, turns=2.5, lead_in=1, $fn=72);
//   thread_helix(d=10, pitch=2, thread_depth=0.75, flank_angle=15, turns=2, lead_in=2, internal=true, $fn=72);
//   thread_helix(d=10, pitch=2, thread_depth=0.75, flank_angle=15, turns=1, left_handed=true, lead_in=1, $fn=36);
function thread_helix(
    d, pitch, thread_depth, flank_angle, turns,
    profile, starts=1, left_handed=false, internal=false,
    d1, d2, thread_angle, 
    lead_in_shape,
    lead_in, lead_in1, lead_in2,
    lead_in_ang, lead_in_ang1, lead_in_ang2,
    lead_in_sample=10,
    anchor, spin, orient
) = no_function("thread_helix");
module thread_helix(
    d, pitch, thread_depth, flank_angle, turns,
    profile, starts=1, left_handed=false, internal=false,
    d1, d2, thread_angle, 
    lead_in_shape,
    lead_in, lead_in1, lead_in2,
    lead_in_ang, lead_in_ang1, lead_in_ang2,
    lead_in_sample=10,
    anchor, spin, orient
) {
    dummy1=assert(num_defined([thread_angle,flank_angle])<=1, "Cannot define both flank angle and thread angle")
           assert(is_undef(profile) || !any_defined([thread_depth, flank_angle]),
                  "Cannot give thread_depth or flank_angle with a profile")
           assert(all_positive([turns]), "The turns parameter must be a positive number")
           assert(all_positive(pitch), "pitch must be a positive number")
           assert(num_defined([flank_angle,thread_angle])<=1, "Cannot give both thread_angle and flank_angle")
           assert(is_def(profile) || is_def(thread_depth), "If profile is not given, must give thread depth");
    flank_angle = first_defined([flank_angle,u_mul(0.5,thread_angle),15]);
    h = pitch*starts*abs(turns);
    r1 = get_radius(d1=d1, d=d, dflt=10);
    r2 = get_radius(d1=d2, d=d, dflt=10);
    profile = is_def(profile) ? profile :
        let(
            tdp = thread_depth / pitch,
            dz = tdp * tan(flank_angle),
            cap = (1 - 2*dz)/2
        )
        assert(cap/2+dz<=0.5, "Invalid geometry: incompatible thread depth and thread_angle/flank_angle")
        internal?
          [
            [-cap/2-dz, tdp],
            [-cap/2,    0  ],
            [+cap/2,    0  ],
            [+cap/2+dz, tdp],
          ]
        :
          [
            [+cap/2+dz, 0  ],
            [+cap/2,    tdp],
            [-cap/2,    tdp],
            [-cap/2-dz, 0  ],
          ];

    pline = mirror([-1,1],  p = profile * pitch);
    dir = left_handed? -1 : 1;
    attachable(anchor,spin,orient, r1=r1, r2=r2, l=h) {
        union(){
        zrot_copies(n=starts)
            spiral_sweep(pline, h=h, r1=r1, r2=r2, turns=turns*dir, internal=internal,
                         lead_in_shape=lead_in_shape,
                         lead_in=lead_in, lead_in1=lead_in1, lead_in2=lead_in2,
                         lead_in_ang=lead_in_ang, lead_in_ang1=lead_in_ang1, lead_in_ang2=lead_in_ang2,
                         lead_in_sample=lead_in_sample,anchor=CENTER);
        }
        children();
    }
}



// Questions
//   Should nut modules take d1/d2 for tapered nuts?
//
// Need explanation of what exactly the diff is between threaded_rod and helix_threads.
//
// What about blunt_start for ball screws?
// Should default bevel be capped at 1mm or 2mm or something like that?  Including/especially inner bevel on nuts

// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap