From db460ea8d8bbba0e141f21d438d98cec397c941d Mon Sep 17 00:00:00 2001
From: Garth Minette <gminette@gmail.com>
Date: Tue, 5 Jan 2021 14:16:58 -0800
Subject: [PATCH 1/5] Fixed argument formatting issue in tube().

---
 shapes.scad  | 322 +++++++++++++++++++++++++--------------------------
 version.scad |   2 +-
 2 files changed, 162 insertions(+), 162 deletions(-)

diff --git a/shapes.scad b/shapes.scad
index f453d5d5..019f1975 100644
--- a/shapes.scad
+++ b/shapes.scad
@@ -487,6 +487,166 @@ function prismoid(
     ) reorient(anchor,spin,orient, size=[s1.x,s1.y,h], size2=s2, shift=shift, p=vnf);
 
 
+// Module: rect_tube()
+// Usage:
+//   rect_tube(size, wall, h, [center]);
+//   rect_tube(isize, wall, h, [center]);
+//   rect_tube(size, isize, h, [center]);
+//   rect_tube(size1, size2, wall, h, [center]);
+//   rect_tube(isize1, isize2, wall, h, [center]);
+//   rect_tube(size1, size2, isize1, isize2, h, [center]);
+// Description:
+//   Creates a rectangular or prismoid tube with optional roundovers and/or chamfers.
+//   You can only round or chamfer the vertical(ish) edges.  For those edges, you can
+//   specify rounding and/or chamferring per-edge, and for top and bottom, inside and
+//   outside  separately.
+//   Note: if using chamfers or rounding, you **must** also include the hull.scad file:
+//   ```
+//   include <BOSL2/hull.scad>
+//   ```
+// Arguments:
+//   size = The outer [X,Y] size of the rectangular tube.
+//   isize = The inner [X,Y] size of the rectangular tube.
+//   h|l = The height or length of the rectangular tube.  Default: 1
+//   wall = The thickness of the rectangular tube wall.
+//   size1 = The [X,Y] side of the outside of the bottom of the rectangular tube.
+//   size2 = The [X,Y] side of the outside of the top of the rectangular tube.
+//   isize1 = The [X,Y] side of the inside of the bottom of the rectangular tube.
+//   isize2 = The [X,Y] side of the inside of the top of the rectangular tube.
+//   rounding = The roundover radius for the outside edges of the rectangular tube.
+//   rounding1 = The roundover radius for the outside bottom corner of the rectangular tube.
+//   rounding2 = The roundover radius for the outside top corner of the rectangular tube.
+//   chamfer = The chamfer size for the outside edges of the rectangular tube.
+//   chamfer1 = The chamfer size for the outside bottom corner of the rectangular tube.
+//   chamfer2 = The chamfer size for the outside top corner of the rectangular tube.
+//   irounding = The roundover radius for the inside edges of the rectangular tube. Default: Same as `rounding`
+//   irounding1 = The roundover radius for the inside bottom corner of the rectangular tube.
+//   irounding2 = The roundover radius for the inside top corner of the rectangular tube.
+//   ichamfer = The chamfer size for the inside edges of the rectangular tube.  Default: Same as `chamfer`
+//   ichamfer1 = The chamfer size for the inside bottom corner of the rectangular tube.
+//   ichamfer2 = The chamfer size for the inside top corner of the rectangular tube.
+//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#anchor).  Default: `BOTTOM`
+//   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#spin).  Default: `0`
+//   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#orient).  Default: `UP`
+// Examples:
+//   rect_tube(size=50, wall=5, h=30);
+//   rect_tube(size=[100,60], wall=5, h=30);
+//   rect_tube(isize=[60,80], wall=5, h=30);
+//   rect_tube(size=[100,60], isize=[90,50], h=30);
+//   rect_tube(size1=[100,60], size2=[70,40], wall=5, h=30);
+//   rect_tube(size1=[100,60], size2=[70,40], isize1=[40,20], isize2=[65,35], h=15);
+// Example: Outer Rounding Only
+//   include <BOSL2/hull.scad>
+//   rect_tube(size=100, wall=5, rounding=10, irounding=0, h=30);
+// Example: Outer Chamfer Only
+//   include <BOSL2/hull.scad>
+//   rect_tube(size=100, wall=5, chamfer=5, ichamfer=0, h=30);
+// Example: Outer Rounding, Inner Chamfer
+//   include <BOSL2/hull.scad>
+//   rect_tube(size=100, wall=5, rounding=10, ichamfer=8, h=30);
+// Example: Inner Rounding, Outer Chamfer
+//   include <BOSL2/hull.scad>
+//   rect_tube(size=100, wall=5, chamfer=10, irounding=8, h=30);
+// Example: Gradiant Rounding
+//   include <BOSL2/hull.scad>
+//   rect_tube(size1=100, size2=80, wall=5, rounding1=10, rounding2=0, irounding1=8, irounding2=0, h=30);
+// Example: Per Corner Rounding
+//   include <BOSL2/hull.scad>
+//   rect_tube(size=100, wall=10, rounding=[0,5,10,15], irounding=0, h=30);
+// Example: Per Corner Chamfer
+//   include <BOSL2/hull.scad>
+//   rect_tube(size=100, wall=10, chamfer=[0,5,10,15], ichamfer=0, h=30);
+// Example: Mixing Chamfer and Rounding
+//   include <BOSL2/hull.scad>
+//   rect_tube(size=100, wall=10, chamfer=[0,5,0,10], ichamfer=0, rounding=[5,0,10,0], irounding=0, h=30);
+// Example: Really Mixing It Up
+//   include <BOSL2/hull.scad>
+//   rect_tube(
+//       size1=[100,80], size2=[80,60],
+//       isize1=[50,30], isize2=[70,50], h=20,
+//       chamfer1=[0,5,0,10], ichamfer1=[0,3,0,8],
+//       chamfer2=[5,0,10,0], ichamfer2=[3,0,8,0],
+//       rounding1=[5,0,10,0], irounding1=[3,0,8,0],
+//       rounding2=[0,5,0,10], irounding2=[0,3,0,8]
+//   );
+module rect_tube(
+    size, isize,
+    h, shift=[0,0], wall,
+    size1, size2,
+    isize1, isize2,
+    rounding=0, rounding1, rounding2,
+    irounding=0, irounding1, irounding2,
+    chamfer=0, chamfer1, chamfer2,
+    ichamfer=0, ichamfer1, ichamfer2,
+    anchor, spin=0, orient=UP,
+    center, l
+) {
+    h = first_defined([h,l,1]);
+    assert(is_num(h), "l or h argument required.");
+    assert(is_vector(shift,2));
+    s1 = is_num(size1)? [size1, size1] :
+        is_vector(size1,2)? size1 :
+        is_num(size)? [size, size] :
+        is_vector(size,2)? size :
+        undef;
+    s2 = is_num(size2)? [size2, size2] :
+        is_vector(size2,2)? size2 :
+        is_num(size)? [size, size] :
+        is_vector(size,2)? size :
+        undef;
+    is1 = is_num(isize1)? [isize1, isize1] :
+        is_vector(isize1,2)? isize1 :
+        is_num(isize)? [isize, isize] :
+        is_vector(isize,2)? isize :
+        undef;
+    is2 = is_num(isize2)? [isize2, isize2] :
+        is_vector(isize2,2)? isize2 :
+        is_num(isize)? [isize, isize] :
+        is_vector(isize,2)? isize :
+        undef;
+    size1 = is_def(s1)? s1 :
+        (is_def(wall) && is_def(is1))? (is1+2*[wall,wall]) :
+        undef;
+    size2 = is_def(s2)? s2 :
+        (is_def(wall) && is_def(is2))? (is2+2*[wall,wall]) :
+        undef;
+    isize1 = is_def(is1)? is1 :
+        (is_def(wall) && is_def(s1))? (s1-2*[wall,wall]) :
+        undef;
+    isize2 = is_def(is2)? is2 :
+        (is_def(wall) && is_def(s2))? (s2-2*[wall,wall]) :
+        undef;
+    assert(wall==undef || is_num(wall));
+    assert(size1!=undef, "Bad size/size1 argument.");
+    assert(size2!=undef, "Bad size/size2 argument.");
+    assert(isize1!=undef, "Bad isize/isize1 argument.");
+    assert(isize2!=undef, "Bad isize/isize2 argument.");
+    assert(isize1.x < size1.x, "Inner size is larger than outer size.");
+    assert(isize1.y < size1.y, "Inner size is larger than outer size.");
+    assert(isize2.x < size2.x, "Inner size is larger than outer size.");
+    assert(isize2.y < size2.y, "Inner size is larger than outer size.");
+    anchor = get_anchor(anchor, center, BOT, BOT);
+    attachable(anchor,spin,orient, size=[each size1, h], size2=size2, shift=shift) {
+        diff("_H_o_L_e_")
+        prismoid(
+            size1, size2, h=h, shift=shift,
+            rounding=rounding, rounding1=rounding1, rounding2=rounding2,
+            chamfer=chamfer, chamfer1=chamfer1, chamfer2=chamfer2,
+            anchor=CTR
+        ) {
+            children();
+            tags("_H_o_L_e_") prismoid(
+                isize1, isize2, h=h+0.05, shift=shift,
+                rounding=irounding, rounding1=irounding1, rounding2=irounding2,
+                chamfer=ichamfer, chamfer1=ichamfer1, chamfer2=ichamfer2,
+                anchor=CTR
+            );
+        }
+        children();
+    }
+}
+
+
 // Module: right_triangle()
 //
 // Usage:
@@ -859,7 +1019,7 @@ module zcyl(l=undef, r=undef, d=undef, r1=undef, r2=undef, d1=undef, d2=undef, h
 //   tube(h|l, ir1|id1, ir2|id2, or1|od1, or2|od2, [realign]);
 //
 // Arguments:
-//   h|l = height of tube. (Default: 1)
+//   h / l = height of tube. (Default: 1)
 //   or = Outer radius of tube.
 //   or1 = Outer radius of bottom of tube.  (Default: value of r)
 //   or2 = Outer radius of top of tube.  (Default: value of r)
@@ -936,166 +1096,6 @@ module tube(
 }
 
 
-// Module: rect_tube()
-// Usage:
-//   rect_tube(size, wall, h, [center]);
-//   rect_tube(isize, wall, h, [center]);
-//   rect_tube(size, isize, h, [center]);
-//   rect_tube(size1, size2, wall, h, [center]);
-//   rect_tube(isize1, isize2, wall, h, [center]);
-//   rect_tube(size1, size2, isize1, isize2, h, [center]);
-// Description:
-//   Creates a rectangular or prismoid tube with optional roundovers and/or chamfers.
-//   You can only round or chamfer the vertical(ish) edges.  For those edges, you can
-//   specify rounding and/or chamferring per-edge, and for top and bottom, inside and
-//   outside  separately.
-//   Note: if using chamfers or rounding, you **must** also include the hull.scad file:
-//   ```
-//   include <BOSL2/hull.scad>
-//   ```
-// Arguments:
-//   size = The outer [X,Y] size of the rectangular tube.
-//   isize = The inner [X,Y] size of the rectangular tube.
-//   h|l = The height or length of the rectangular tube.  Default: 1
-//   wall = The thickness of the rectangular tube wall.
-//   size1 = The [X,Y] side of the outside of the bottom of the rectangular tube.
-//   size2 = The [X,Y] side of the outside of the top of the rectangular tube.
-//   isize1 = The [X,Y] side of the inside of the bottom of the rectangular tube.
-//   isize2 = The [X,Y] side of the inside of the top of the rectangular tube.
-//   rounding = The roundover radius for the outside edges of the rectangular tube.
-//   rounding1 = The roundover radius for the outside bottom corner of the rectangular tube.
-//   rounding2 = The roundover radius for the outside top corner of the rectangular tube.
-//   chamfer = The chamfer size for the outside edges of the rectangular tube.
-//   chamfer1 = The chamfer size for the outside bottom corner of the rectangular tube.
-//   chamfer2 = The chamfer size for the outside top corner of the rectangular tube.
-//   irounding = The roundover radius for the inside edges of the rectangular tube. Default: Same as `rounding`
-//   irounding1 = The roundover radius for the inside bottom corner of the rectangular tube.
-//   irounding2 = The roundover radius for the inside top corner of the rectangular tube.
-//   ichamfer = The chamfer size for the inside edges of the rectangular tube.  Default: Same as `chamfer`
-//   ichamfer1 = The chamfer size for the inside bottom corner of the rectangular tube.
-//   ichamfer2 = The chamfer size for the inside top corner of the rectangular tube.
-//   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#anchor).  Default: `BOTTOM`
-//   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#spin).  Default: `0`
-//   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#orient).  Default: `UP`
-// Examples:
-//   rect_tube(size=50, wall=5, h=30);
-//   rect_tube(size=[100,60], wall=5, h=30);
-//   rect_tube(isize=[60,80], wall=5, h=30);
-//   rect_tube(size=[100,60], isize=[90,50], h=30);
-//   rect_tube(size1=[100,60], size2=[70,40], wall=5, h=30);
-//   rect_tube(size1=[100,60], size2=[70,40], isize1=[40,20], isize2=[65,35], h=15);
-// Example: Outer Rounding Only
-//   include <BOSL2/hull.scad>
-//   rect_tube(size=100, wall=5, rounding=10, irounding=0, h=30);
-// Example: Outer Chamfer Only
-//   include <BOSL2/hull.scad>
-//   rect_tube(size=100, wall=5, chamfer=5, ichamfer=0, h=30);
-// Example: Outer Rounding, Inner Chamfer
-//   include <BOSL2/hull.scad>
-//   rect_tube(size=100, wall=5, rounding=10, ichamfer=8, h=30);
-// Example: Inner Rounding, Outer Chamfer
-//   include <BOSL2/hull.scad>
-//   rect_tube(size=100, wall=5, chamfer=10, irounding=8, h=30);
-// Example: Gradiant Rounding
-//   include <BOSL2/hull.scad>
-//   rect_tube(size1=100, size2=80, wall=5, rounding1=10, rounding2=0, irounding1=8, irounding2=0, h=30);
-// Example: Per Corner Rounding
-//   include <BOSL2/hull.scad>
-//   rect_tube(size=100, wall=10, rounding=[0,5,10,15], irounding=0, h=30);
-// Example: Per Corner Chamfer
-//   include <BOSL2/hull.scad>
-//   rect_tube(size=100, wall=10, chamfer=[0,5,10,15], ichamfer=0, h=30);
-// Example: Mixing Chamfer and Rounding
-//   include <BOSL2/hull.scad>
-//   rect_tube(size=100, wall=10, chamfer=[0,5,0,10], ichamfer=0, rounding=[5,0,10,0], irounding=0, h=30);
-// Example: Really Mixing It Up
-//   include <BOSL2/hull.scad>
-//   rect_tube(
-//       size1=[100,80], size2=[80,60],
-//       isize1=[50,30], isize2=[70,50], h=20,
-//       chamfer1=[0,5,0,10], ichamfer1=[0,3,0,8],
-//       chamfer2=[5,0,10,0], ichamfer2=[3,0,8,0],
-//       rounding1=[5,0,10,0], irounding1=[3,0,8,0],
-//       rounding2=[0,5,0,10], irounding2=[0,3,0,8]
-//   );
-module rect_tube(
-    size, isize,
-    h, shift=[0,0], wall,
-    size1, size2,
-    isize1, isize2,
-    rounding=0, rounding1, rounding2,
-    irounding=0, irounding1, irounding2,
-    chamfer=0, chamfer1, chamfer2,
-    ichamfer=0, ichamfer1, ichamfer2,
-    anchor, spin=0, orient=UP,
-    center, l
-) {
-    h = first_defined([h,l,1]);
-    assert(is_num(h), "l or h argument required.");
-    assert(is_vector(shift,2));
-    s1 = is_num(size1)? [size1, size1] :
-        is_vector(size1,2)? size1 :
-        is_num(size)? [size, size] :
-        is_vector(size,2)? size :
-        undef;
-    s2 = is_num(size2)? [size2, size2] :
-        is_vector(size2,2)? size2 :
-        is_num(size)? [size, size] :
-        is_vector(size,2)? size :
-        undef;
-    is1 = is_num(isize1)? [isize1, isize1] :
-        is_vector(isize1,2)? isize1 :
-        is_num(isize)? [isize, isize] :
-        is_vector(isize,2)? isize :
-        undef;
-    is2 = is_num(isize2)? [isize2, isize2] :
-        is_vector(isize2,2)? isize2 :
-        is_num(isize)? [isize, isize] :
-        is_vector(isize,2)? isize :
-        undef;
-    size1 = is_def(s1)? s1 :
-        (is_def(wall) && is_def(is1))? (is1+2*[wall,wall]) :
-        undef;
-    size2 = is_def(s2)? s2 :
-        (is_def(wall) && is_def(is2))? (is2+2*[wall,wall]) :
-        undef;
-    isize1 = is_def(is1)? is1 :
-        (is_def(wall) && is_def(s1))? (s1-2*[wall,wall]) :
-        undef;
-    isize2 = is_def(is2)? is2 :
-        (is_def(wall) && is_def(s2))? (s2-2*[wall,wall]) :
-        undef;
-    assert(wall==undef || is_num(wall));
-    assert(size1!=undef, "Bad size/size1 argument.");
-    assert(size2!=undef, "Bad size/size2 argument.");
-    assert(isize1!=undef, "Bad isize/isize1 argument.");
-    assert(isize2!=undef, "Bad isize/isize2 argument.");
-    assert(isize1.x < size1.x, "Inner size is larger than outer size.");
-    assert(isize1.y < size1.y, "Inner size is larger than outer size.");
-    assert(isize2.x < size2.x, "Inner size is larger than outer size.");
-    assert(isize2.y < size2.y, "Inner size is larger than outer size.");
-    anchor = get_anchor(anchor, center, BOT, BOT);
-    attachable(anchor,spin,orient, size=[each size1, h], size2=size2, shift=shift) {
-        diff("_H_o_L_e_")
-        prismoid(
-            size1, size2, h=h, shift=shift,
-            rounding=rounding, rounding1=rounding1, rounding2=rounding2,
-            chamfer=chamfer, chamfer1=chamfer1, chamfer2=chamfer2,
-            anchor=CTR
-        ) {
-            children();
-            tags("_H_o_L_e_") prismoid(
-                isize1, isize2, h=h+0.05, shift=shift,
-                rounding=irounding, rounding1=irounding1, rounding2=irounding2,
-                chamfer=ichamfer, chamfer1=ichamfer1, chamfer2=ichamfer2,
-                anchor=CTR
-            );
-        }
-        children();
-    }
-}
-
-
 // Module: torus()
 //
 // Description:
diff --git a/version.scad b/version.scad
index 40aa24a5..bea9c45e 100644
--- a/version.scad
+++ b/version.scad
@@ -6,7 +6,7 @@
 //////////////////////////////////////////////////////////////////////
 
 
-BOSL_VERSION = [2,0,512];
+BOSL_VERSION = [2,0,513];
 
 
 // Section: BOSL Library Version Functions

From d139384b36e07e7a787eb0e9bb83e596349a3071 Mon Sep 17 00:00:00 2001
From: Garth Minette <gminette@gmail.com>
Date: Tue, 5 Jan 2021 14:32:24 -0800
Subject: [PATCH 2/5] Moved GitHUB actions to using 2021.01.03 nightlies
 OpenSCAD.

---
 .github/workflows/docsgen.yml | 2 +-
 .github/workflows/main.yml    | 8 ++++----
 version.scad                  | 2 +-
 3 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/.github/workflows/docsgen.yml b/.github/workflows/docsgen.yml
index 911fac27..2da164f7 100644
--- a/.github/workflows/docsgen.yml
+++ b/.github/workflows/docsgen.yml
@@ -32,7 +32,7 @@ jobs:
 
     - name: Install OpenSCAD
       run: |
-        curl -L -o OpenSCAD.dmg https://files.openscad.org/OpenSCAD-2019.05.dmg
+        curl -L -o OpenSCAD.dmg https://files.openscad.org/snapshots/OpenSCAD-2021.01.04.dmg
         hdiutil attach OpenSCAD.dmg
         cp -a /Volumes/OpenSCAD/OpenSCAD.app /Applications/
 
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 13c3151b..58aabc33 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -23,8 +23,8 @@ jobs:
     - name: Get OpenSCAD Appimage
       run: |
         cd $GITHUB_WORKSPACE
-        wget https://files.openscad.org/OpenSCAD-2019.05-x86_64.AppImage
-        sudo mv OpenSCAD-2019.05-x86_64.AppImage /usr/local/bin/openscad
+        wget https://files.openscad.org/snapshots/OpenSCAD-2021.01.03.ai6611-a980a3a-x86_64.AppImage
+        sudo mv OpenSCAD-2021.01.03.*-x86_64.AppImage /usr/local/bin/openscad
         sudo chmod +x /usr/local/bin/openscad
 
     - name: Run Regression Tests
@@ -63,8 +63,8 @@ jobs:
     - name: Install OpenSCAD
       run: |
         cd $GITHUB_WORKSPACE
-        wget https://files.openscad.org/OpenSCAD-2019.05-x86_64.AppImage
-        sudo mv OpenSCAD-2019.05-x86_64.AppImage /usr/local/bin/openscad
+        wget https://files.openscad.org/snapshots/OpenSCAD-2021.01.03.ai6611-a980a3a-x86_64.AppImage
+        sudo mv OpenSCAD-2021.01.03.*-x86_64.AppImage /usr/local/bin/openscad
         sudo chmod +x /usr/local/bin/openscad
 
     - name: Generate Index
diff --git a/version.scad b/version.scad
index bea9c45e..39f29a6d 100644
--- a/version.scad
+++ b/version.scad
@@ -6,7 +6,7 @@
 //////////////////////////////////////////////////////////////////////
 
 
-BOSL_VERSION = [2,0,513];
+BOSL_VERSION = [2,0,514];
 
 
 // Section: BOSL Library Version Functions

From 697368b3a323b412dd7801656ae54cbb19e91306 Mon Sep 17 00:00:00 2001
From: Garth Minette <gminette@gmail.com>
Date: Tue, 5 Jan 2021 17:53:03 -0800
Subject: [PATCH 3/5] Fix projection_on_plane() example.

---
 geometry.scad | 13 ++++++++++---
 version.scad  |  2 +-
 2 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/geometry.scad b/geometry.scad
index 7fa07cc6..bb236741 100644
--- a/geometry.scad
+++ b/geometry.scad
@@ -1005,10 +1005,17 @@ function plane_transform(plane) =
 // Arguments:
 //   plane = The `[A,B,C,D]` plane definition where `Ax+By+Cz=D` is the formula of the plane.
 //   points = List of points to project
-// Example(3D):
-//   points = move([10,20,30], p=yrot(25, p=path3d(circle(d=100))));
-//   plane = plane3pt([1,0,0],[0,1,0],[0,0,1]);
+// Example(3D,FlatSpin):
+//   plane = plane_from_normal([1,0,1]);
 //   proj = projection_on_plane(plane,points);
+//   color("red") move_copies(points) sphere(d=2,$fn=12);
+//   color("blue") move_copies(proj) sphere(d=2,$fn=12);
+//   rot(from=UP,to=plane_normal(plane)) {
+//       left(10) {
+//           anchor_arrow(30);
+//           %cube([120,150,0.1],center=true);
+//       }
+//   }
 function projection_on_plane(plane, points) =
     assert( _valid_plane(plane), "Invalid plane." )
     assert( is_path(points), "Invalid list of points or dimension." )
diff --git a/version.scad b/version.scad
index 39f29a6d..20c5e9cb 100644
--- a/version.scad
+++ b/version.scad
@@ -6,7 +6,7 @@
 //////////////////////////////////////////////////////////////////////
 
 
-BOSL_VERSION = [2,0,514];
+BOSL_VERSION = [2,0,515];
 
 
 // Section: BOSL Library Version Functions

From 7b9fd862ea64639c08ba92930008ac07c7affa97 Mon Sep 17 00:00:00 2001
From: Garth Minette <gminette@gmail.com>
Date: Tue, 5 Jan 2021 18:04:41 -0800
Subject: [PATCH 4/5] Fixed worm_gear() module example code.

---
 involute_gears.scad | 2 +-
 version.scad        | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/involute_gears.scad b/involute_gears.scad
index b9400273..1cb98423 100644
--- a/involute_gears.scad
+++ b/involute_gears.scad
@@ -1208,7 +1208,7 @@ module worm(
 // Example: Multiple Starts
 //   worm_gear(pitch=5, teeth=36, worm_diam=30, worm_starts=4);
 // Example: Metric Worm Gear
-//   worm_gear(mod=25, teeth=32, worm_diam=30, worm_starts=1);
+//   worm_gear(mod=2, teeth=32, worm_diam=30, worm_starts=1);
 // Example: Called as Function
 //   vnf = worm_gear(pitch=8, teeth=30, worm_diam=30, worm_starts=1);
 //   vnf_polyhedron(vnf);
diff --git a/version.scad b/version.scad
index 20c5e9cb..ca3798a8 100644
--- a/version.scad
+++ b/version.scad
@@ -6,7 +6,7 @@
 //////////////////////////////////////////////////////////////////////
 
 
-BOSL_VERSION = [2,0,515];
+BOSL_VERSION = [2,0,516];
 
 
 // Section: BOSL Library Version Functions

From 3b4f3d3f0e384b76dd16ac1ab7957706626fba0c Mon Sep 17 00:00:00 2001
From: Garth Minette <gminette@gmail.com>
Date: Tue, 5 Jan 2021 22:07:40 -0800
Subject: [PATCH 5/5] Examples fixes for joiners, hingesnaps,
 projection_on_plane()

---
 geometry.scad   |  5 ++--
 hingesnaps.scad | 13 +++++----
 joiners.scad    | 70 +++++++++++++++++++++++++------------------------
 version.scad    |  2 +-
 4 files changed, 46 insertions(+), 44 deletions(-)

diff --git a/geometry.scad b/geometry.scad
index bb236741..b5a4c235 100644
--- a/geometry.scad
+++ b/geometry.scad
@@ -1006,12 +1006,13 @@ function plane_transform(plane) =
 //   plane = The `[A,B,C,D]` plane definition where `Ax+By+Cz=D` is the formula of the plane.
 //   points = List of points to project
 // Example(3D,FlatSpin):
+//   points = move([10,20,30], p=yrot(25, p=path3d(circle(d=100, $fn=36))));
 //   plane = plane_from_normal([1,0,1]);
 //   proj = projection_on_plane(plane,points);
 //   color("red") move_copies(points) sphere(d=2,$fn=12);
 //   color("blue") move_copies(proj) sphere(d=2,$fn=12);
-//   rot(from=UP,to=plane_normal(plane)) {
-//       left(10) {
+//   move(centroid(proj)) {
+//       rot(from=UP,to=plane_normal(plane)) {
 //           anchor_arrow(30);
 //           %cube([120,150,0.1],center=true);
 //       }
diff --git a/hingesnaps.scad b/hingesnaps.scad
index 3211c882..3b022e85 100644
--- a/hingesnaps.scad
+++ b/hingesnaps.scad
@@ -128,10 +128,8 @@ module snap_socket(thick, snaplen=5, snapdiam=5, layerheight=0.2, foldangle=90,
 //   apply_folding_hinges_and_snaps(
 //       thick=3, foldangle=54.74,
 //       hinges=[
-//           for (a=[0,120,240]) each [
-//               [100, rot(a,p=[ size/4, 0        ]), a+90],
-//               [100, rot(a,p=[-size/2,-size/2.33]), a+90],
-//               [100, rot(a,p=[-size/2, size/2.33]), a+90]
+//           for (a=[0,120,240], b=[-size/2,size/4]) each [
+//               [200, polar_to_xy(b,a), a+90]
 //           ]
 //       ],
 //       snaps=[
@@ -147,10 +145,11 @@ module snap_socket(thick, snaplen=5, snapdiam=5, layerheight=0.2, foldangle=90,
 //           ]
 //       ]
 //   ) {
+//       $fn=3;
 //       difference() {
-//           cylinder(r=size-1, h=3, spin=180, $fn=3);
-//           down(0.01) cylinder(r=size/4, h=3.1, spin=0, $fn=3);
-//           down(0.01) for (a=[0:120:359.9]) zrot(a) right(size/2) cylinder(r=size/4, h=3.1, spin=180, $fn=3);
+//           cylinder(r=size-1, h=3);
+//           down(0.01) cylinder(r=size/4.5, h=3.1, spin=180);
+//           down(0.01) for (a=[0:120:359.9]) zrot(a) right(size/2) cylinder(r=size/4.5, h=3.1);
 //       }
 //   }
 module apply_folding_hinges_and_snaps(thick, foldangle=90, hinges=[], snaps=[], sockets=[], snaplen=5, snapdiam=5, hingegap=undef, layerheight=0.2)
diff --git a/joiners.scad b/joiners.scad
index 11815074..a3cc6365 100644
--- a/joiners.scad
+++ b/joiners.scad
@@ -28,7 +28,7 @@ include <rounding.scad>
 //   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#spin).  Default: `0`
 //   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#orient).  Default: `UP`
 // Example:
-//   half_joiner_clear(spin=-90);
+//   half_joiner_clear();
 module half_joiner_clear(h=20, w=10, a=30, clearance=0, overlap=0.01, anchor=CENTER, spin=0, orient=UP)
 {
     dmnd_height = h*1.0;
@@ -74,8 +74,9 @@ module half_joiner_clear(h=20, w=10, a=30, clearance=0, overlap=0.01, anchor=CEN
 //   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#spin).  Default: `0`
 //   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#orient).  Default: `UP`
 //   $slop = Printer specific slop value to make parts fit more closely.
-// Example:
-//   half_joiner(screwsize=3, spin=-90);
+// Examples(FlatSpin):
+//   half_joiner(screwsize=3);
+//   half_joiner(h=20,w=10,l=10);
 module half_joiner(h=20, w=10, l=10, a=30, screwsize=undef, guides=true, anchor=CENTER, spin=0, orient=UP)
 {
     dmnd_height = h*1.0;
@@ -133,7 +134,6 @@ module half_joiner(h=20, w=10, l=10, a=30, screwsize=undef, guides=true, anchor=
         children();
     }
 }
-//half_joiner(screwsize=3);
 
 
 
@@ -152,8 +152,9 @@ module half_joiner(h=20, w=10, l=10, a=30, screwsize=undef, guides=true, anchor=
 //   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#anchor).  Default: `CENTER`
 //   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#spin).  Default: `0`
 //   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#orient).  Default: `UP`
-// Example:
-//   half_joiner2(screwsize=3, spin=-90);
+// Examples(FlatSpin):
+//   half_joiner2(screwsize=3);
+//   half_joiner2(h=20,w=10,l=10);
 module half_joiner2(h=20, w=10, l=10, a=30, screwsize=undef, guides=true, anchor=CENTER, spin=0, orient=UP)
 {
     dmnd_height = h*1.0;
@@ -201,7 +202,7 @@ module half_joiner2(h=20, w=10, l=10, a=30, screwsize=undef, guides=true, anchor
 //   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#spin).  Default: `0`
 //   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#orient).  Default: `UP`
 // Example:
-//   joiner_clear(spin=-90);
+//   joiner_clear();
 module joiner_clear(h=40, w=10, a=30, clearance=0, overlap=0.01, anchor=CENTER, spin=0, orient=UP)
 {
     dmnd_height = h*0.5;
@@ -236,9 +237,9 @@ module joiner_clear(h=40, w=10, a=30, clearance=0, overlap=0.01, anchor=CENTER,
 //   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#spin).  Default: `0`
 //   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#orient).  Default: `UP`
 //   $slop = Printer specific slop value to make parts fit more closely.
-// Examples:
-//   joiner(screwsize=3, spin=-90);
-//   joiner(w=10, l=10, h=40, spin=-90) cuboid([10, 10*2, 40], anchor=RIGHT);
+// Examples(FlatSpin):
+//   joiner(screwsize=3);
+//   joiner(w=10, l=10, h=40);
 module joiner(h=40, w=10, l=10, a=30, screwsize=undef, guides=true, anchor=CENTER, spin=0, orient=UP)
 {
     attachable(anchor,spin,orient, size=[w, 2*l, h]) {
@@ -310,12 +311,12 @@ module joiner_pair_clear(spacing=100, h=40, w=10, a=30, n=2, clearance=0, overla
 //   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#spin).  Default: `0`
 //   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#orient).  Default: `UP`
 //   $slop = Printer specific slop value to make parts fit more closely.
+// Example(FlatSpin):
+//   joiner_pair(spacing=50, l=10);
 // Examples:
-//   joiner_pair(spacing=50, l=10, spin=-90) cuboid([10, 50+10-0.1, 40], anchor=RIGHT);
-//   joiner_pair(spacing=50, l=10, n=2, spin=-90);
-//   joiner_pair(spacing=50, l=10, n=3, alternate=false, spin=-90);
-//   joiner_pair(spacing=50, l=10, n=3, alternate=true, spin=-90);
-//   joiner_pair(spacing=50, l=10, n=3, alternate="alt", spin=-90);
+//   joiner_pair(spacing=50, l=10, n=3, alternate=false);
+//   joiner_pair(spacing=50, l=10, n=3, alternate=true);
+//   joiner_pair(spacing=50, l=10, n=3, alternate="alt");
 module joiner_pair(spacing=100, h=40, w=10, l=10, a=30, n=2, alternate=true, screwsize=undef, guides=true, anchor=CENTER, spin=0, orient=UP)
 {
     attachable(anchor,spin,orient, size=[spacing+w, 2*l, h]) {
@@ -385,19 +386,19 @@ module joiner_quad_clear(xspacing=undef, yspacing=undef, spacing1=undef, spacing
 //   l = Length of the backing to the joiners.
 //   a = Overhang angle of the joiners.
 //   n = Number of joiners in a row.  Default: 2
-//   alternate = If true (default), each joiner alternates it's orientation.  If alternate is "alt", do opposite alternating orientations.
+//   alternate = If true (default), joiners on each side alternate orientations.  If alternate is "alt", do opposite alternating orientations.
 //   screwsize = Diameter of screwhole.
 //   guides = If true, create sliding alignment guides.
 //   $slop = Printer specific slop value to make parts fit more closely.
 //   anchor = Translate so anchor point is at origin (0,0,0).  See [anchor](attachments.scad#anchor).  Default: `CENTER`
 //   spin = Rotate this many degrees around the Z axis after anchor.  See [spin](attachments.scad#spin).  Default: `0`
 //   orient = Vector to rotate top towards, after spin.  See [orient](attachments.scad#orient).  Default: `UP`
+// Example(FlatSpin):
+//   joiner_quad(spacing1=50, spacing2=50, l=10);
 // Examples:
-//   joiner_quad(spacing1=50, spacing2=50, l=10, spin=-90) cuboid([50, 50+10-0.1, 40]);
-//   joiner_quad(spacing1=50, spacing2=50, l=10, n=2, spin=-90);
-//   joiner_quad(spacing1=50, spacing2=50, l=10, n=3, alternate=false, spin=-90);
-//   joiner_quad(spacing1=50, spacing2=50, l=10, n=3, alternate=true, spin=-90);
-//   joiner_quad(spacing1=50, spacing2=50, l=10, n=3, alternate="alt", spin=-90);
+//   joiner_quad(spacing1=50, spacing2=50, l=10, n=3, alternate=false);
+//   joiner_quad(spacing1=50, spacing2=50, l=10, n=3, alternate=true);
+//   joiner_quad(spacing1=50, spacing2=50, l=10, n=3, alternate="alt");
 module joiner_quad(spacing1=undef, spacing2=undef, xspacing=undef, yspacing=undef, h=40, w=10, l=10, a=30, n=2, alternate=true, screwsize=undef, guides=true, anchor=CENTER, spin=0, orient=UP)
 {
     spacing1 = first_defined([spacing1, xspacing, 100]);
@@ -405,7 +406,7 @@ module joiner_quad(spacing1=undef, spacing2=undef, xspacing=undef, yspacing=unde
     attachable(anchor,spin,orient, size=[w+spacing1, spacing2, h]) {
         zrot_copies(n=2) {
             back(spacing2/2) {
-                joiner_pair(spacing=spacing1, n=n, h=h, w=w, l=l, a=a, screwsize=screwsize, guides=guides);
+                joiner_pair(spacing=spacing1, n=n, h=h, w=w, l=l, a=a, screwsize=screwsize, guides=guides, alternate=alternate);
             }
         }
         children();
@@ -430,6 +431,7 @@ module joiner_quad(spacing1=undef, spacing2=undef, xspacing=undef, yspacing=unde
 //   with male dovetails oriented UP and female ones DOWN.  
 //
 // Arguments:
+//   gender = A string, "male" or "female", to specify the gender of the dovetail.
 //   l / length = Length of the dovetail (amount the joint slides during assembly)
 //   h / height = Height of the dovetail
 //   w / width = Width (at the wider, top end) of the dovetail before tapering
@@ -442,11 +444,11 @@ module joiner_quad(spacing1=undef, spacing2=undef, xspacing=undef, yspacing=unde
 //   round = true to round both corners of the dovetail and give it a puzzle piece look.  Default: false.  
 //   extra = amount of extra length and base extension added to dovetails for unions and differences.  Default: 0.01
 // Example: Ordinary straight dovetail, male version (sticking up) and female version (below the xy plane)
-//   dovetail("male", length=30, width=15, height=8);
-//   right(20) dovetail("female", length=30, width=15, height=8);
+//   dovetail("male", l=30, w=15, h=8);
+//   right(20) dovetail("female", l=30, w=15, h=8);
 // Example: Adding a 6 degree taper (Such a big taper is usually not necessary, but easier to see for the example.)
-//   dovetail("male", length=30, width=15, height=8, taper=6);
-//   right(20) dovetail("female", length=30, width=15, height=8, taper=6);
+//   dovetail("male", l=30, w=15, h=8, taper=6);
+//   right(20) dovetail("female", l=30, w=15, h=8, taper=6);
 // Example: A block that can link to itself
 //   diff("remove")
 //     cuboid([50,30,10]){
@@ -467,16 +469,16 @@ module joiner_quad(spacing1=undef, spacing2=undef, xspacing=undef, yspacing=unde
 //     }
 // Example: Rounding the outside corners is another option
 //   diff("remove")
-//     cuboid([50,30,10]){
-//       attach(BACK) dovetail("male", length=10, width=15, height=8,radius=1,$fn=32);
-//       attach(FRONT) dovetail("female", length=10, width=15, height=8,radius=1,$tags="remove",$fn=32);
-//     }
+//   cuboid([50,30,10]) {
+//       attach(BACK)  dovetail("male", length=10, width=15, height=8, radius=1, $fn=32);
+//       attach(FRONT, overlap=-0.1) dovetail("female", length=10, width=15, height=8, radius=1, $tags="remove", $fn=32);
+//   }
 // Example: Or you can make a fully rounded joint
 //   $fn=32;
 //   diff("remove")
-//     cuboid([50,30,10]){
+//   cuboid([50,30,10]){
 //       attach(BACK) dovetail("male", length=10, width=15, height=8,radius=1.5, round=true);
-//       attach(FRONT) dovetail("female", length=10, width=15, height=8,radius=1.5, round=true, $tags="remove");
+//       attach(FRONT,overlap=-0.1) dovetail("female", length=10, width=15, height=8,radius=1.5, round=true, $tags="remove");
 //   }
 // Example: With a long joint like this, a taper makes the joint easy to assemble.  It will go together easily and wedge tightly if you get the tolerances right.  Specifying the taper with `back_width` may be easier than using a taper angle.  
 //   cuboid([50,30,10])
@@ -517,7 +519,7 @@ module dovetail(gender, length, l, width, w, height, h, angle, slope, taper, bac
     extra_slop = gender == "female" ? 2*$slop : 0;
     width = w + extra_slop;
     height = h + extra_slop;
-    back_width = back_width + extra_slop;
+    back_width = u_add(back_width, extra_slop);
 
     front_offset = is_def(taper) ? -extra * tan(taper) :
         is_def(back_width) ? extra * (back_width-width)/length/2 : 0;
@@ -546,7 +548,7 @@ module dovetail(gender, length, l, width, w, height, h, angle, slope, taper, bac
         is_def(back_width) ? (back_width-width) / 2 : 0;
     bigend_points = move([offset,length+2*extra,0], p=smallend_points);
 
-    adjustment = gender == "male" ? -0.01 : 0.01;  // Adjustment for default overlap in attach()
+    adjustment = $overlap * (gender == "male" ? -1 : 1);  // Adjustment for default overlap in attach()
 
     attachable(anchor,spin,orient, size=[width+2*offset, length, height]) {
         down(height/2+adjustment) {
diff --git a/version.scad b/version.scad
index ca3798a8..fb04b742 100644
--- a/version.scad
+++ b/version.scad
@@ -6,7 +6,7 @@
 //////////////////////////////////////////////////////////////////////
 
 
-BOSL_VERSION = [2,0,516];
+BOSL_VERSION = [2,0,517];
 
 
 // Section: BOSL Library Version Functions