diff --git a/.github/check_for_tabs.json b/.github/check_for_tabs.json
new file mode 100644
index 0000000..c29a758
--- /dev/null
+++ b/.github/check_for_tabs.json
@@ -0,0 +1,15 @@
+{
+    "problemMatcher": [
+        {
+            "owner": "check_for_tabs",
+            "pattern": [
+                {
+                    "regexp": "^([^:]+):(\\d+):(.*)$",
+                    "file": 1,
+                    "line": 2,
+                    "message": 3
+                }
+            ]
+        }
+    ]
+}
diff --git a/.github/workflows/docsgen.yml b/.github/workflows/docsgen.yml
deleted file mode 100644
index 220a1da..0000000
--- a/.github/workflows/docsgen.yml
+++ /dev/null
@@ -1,60 +0,0 @@
-name: Docs
-on:
-  pull_request:
-    branches: [master]
-    types: [closed]
-
-jobs:
-  GenerateDocs:
-    if: github.event.pull_request.merged == true
-    runs-on: ubuntu-latest
-    steps:
-    - name: Checkout
-      uses: actions/checkout@v2
-
-    - name: Checkout Wiki
-      uses: actions/checkout@v2
-      with:
-        repository: revarbat/BOSL2.wiki
-        path: BOSL2.wiki
-
-    - name: Apt Update
-      run: sudo apt update
-
-    - name: Install Packages
-      run: sudo apt-get install -y python3-pip python3-dev python3-setuptools python3-pil gifsicle
-
-    - name: Install openscad-docsgen
-      run: sudo pip3 install openscad_docsgen
-
-    - name: Install OpenSCAD
-      run: |
-        cd $GITHUB_WORKSPACE
-        wget https://files.openscad.org/OpenSCAD-2021.01-x86_64.AppImage
-        sudo mv OpenSCAD-2021.01*-x86_64.AppImage /usr/local/bin/openscad
-        sudo chmod +x /usr/local/bin/openscad
-        echo "::add-matcher::.github/openscad_docsgen.json"
-
-    - name: Generating Docs Headless
-      run: |
-        export OPENSCADPATH=$(dirname $GITHUB_WORKSPACE)
-        xvfb-run --server-args="-screen 0, 1280x720x24" -a \
-        openscad-docsgen -ticmI *.scad
-
-    - name: Commit Wiki Docs
-      run: |
-        cd $GITHUB_WORKSPACE/BOSL2.wiki
-        git config user.name github-actions
-        git config user.email github-actions@github.com
-        git add --all
-        git commit -m "Wiki docs auto-regen." && git push || true
-
-    - name: Bump Release Version
-      run: |
-        cd $GITHUB_WORKSPACE
-        ./scripts/increment_version.sh
-        git config user.name github-actions
-        git config user.email github-actions@github.com
-        git add version.scad
-        git commit -m "Bump release version." && git push || true
-
diff --git a/.github/workflows/forced_docsgen.yml b/.github/workflows/forced_docsgen.yml
deleted file mode 100644
index 6393b90..0000000
--- a/.github/workflows/forced_docsgen.yml
+++ /dev/null
@@ -1,49 +0,0 @@
-name: FDocs
-on:
-  workflow_dispatch:
-    branches: [master]
-
-jobs:
-  GenerateDocs:
-    runs-on: ubuntu-latest
-    steps:
-    - name: Checkout
-      uses: actions/checkout@v2
-
-    - name: Checkout Wiki
-      uses: actions/checkout@v2
-      with:
-        repository: revarbat/BOSL2.wiki
-        path: BOSL2.wiki
-
-    - name: Apt Update
-      run: sudo apt update
-
-    - name: Install Packages
-      run: sudo apt-get install -y python3-pip python3-dev python3-setuptools python3-pil gifsicle
-
-    - name: Install openscad-docsgen
-      run: sudo pip3 install openscad_docsgen
-
-    - name: Install OpenSCAD
-      run: |
-        cd $GITHUB_WORKSPACE
-        wget https://files.openscad.org/OpenSCAD-2021.01-x86_64.AppImage
-        sudo mv OpenSCAD-2021.01*-x86_64.AppImage /usr/local/bin/openscad
-        sudo chmod +x /usr/local/bin/openscad
-        echo "::add-matcher::.github/openscad_docsgen.json"
-
-    - name: Generating Docs Headless
-      run: |
-        export OPENSCADPATH=$(dirname $GITHUB_WORKSPACE)
-        xvfb-run --server-args="-screen 0, 1280x720x24" -a \
-        openscad-docsgen -ticmIf *.scad
-
-    - name: Commit Wiki Docs
-      run: |
-        cd $GITHUB_WORKSPACE/BOSL2.wiki
-        git config user.name github-actions
-        git config user.email github-actions@github.com
-        git add --all
-        git commit -m "Wiki docs auto-regen." && git push || true
-
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index ebaa845..6283509 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -1,4 +1,4 @@
-name: CI
+name: Checks
 on: [pull_request]
 
 jobs:
@@ -49,6 +49,12 @@ jobs:
         sudo mv OpenSCAD-2021.01*-x86_64.AppImage /usr/local/bin/openscad
         sudo chmod +x /usr/local/bin/openscad
 
+    - name: Tabs Check
+      run: |
+        cd $GITHUB_WORKSPACE
+        echo "::add-matcher::.github/check_for_tabs.json"
+        ./scripts/check_for_tabs.sh
+
     - name: Checking Docs
       run: |
         cd $GITHUB_WORKSPACE
diff --git a/.github/workflows/testwf.yml b/.github/workflows/testwf.yml
deleted file mode 100644
index f99e8f6..0000000
--- a/.github/workflows/testwf.yml
+++ /dev/null
@@ -1,49 +0,0 @@
-name: TestWorkflow
-on:
-  workflow_dispatch:
-    branches: [master]
-
-jobs:
-  TestJob:
-    runs-on: ubuntu-latest
-    steps:
-    - name: Checkout
-      uses: actions/checkout@v2
-
-    - name: Checkout Wiki
-      uses: actions/checkout@v2
-      with:
-        repository: revarbat/BOSL2.wiki
-        path: BOSL2.wiki
-
-    - name: Setup OpenGL
-      uses: openrndr/setup-opengl@v1.1
-
-    - name: Apt Update
-      run: sudo apt update
-
-    - name: Install Packages
-      run: sudo apt-get install -y python3-pip python3-dev python3-setuptools python3-pil gifsicle
-
-    - name: Install openscad-docsgen
-      run: sudo pip3 install openscad_docsgen
-
-    - name: Install OpenSCAD
-      run: |
-        cd $GITHUB_WORKSPACE
-        wget https://files.openscad.org/OpenSCAD-2021.01-x86_64.AppImage
-        sudo mv OpenSCAD-2021.01*-x86_64.AppImage /usr/local/bin/openscad
-        sudo chmod +x /usr/local/bin/openscad
-        echo "::add-matcher::.github/openscad_docsgen.json"
-
-    - name: Make SCAD File
-      run: |
-        cd $GITHUB_WORKSPACE
-        echo "cube(50, center=100);" > testwf.scad
-
-    - name: TestScript
-      run: |
-        export OPENSCADPATH=$(dirname $GITHUB_WORKSPACE)
-        xvfb-run --server-args="-screen 0, 1280x720x24" -a \
-        glxinfo
-
diff --git a/arrays.scad b/arrays.scad
index 0df54af..69bc189 100644
--- a/arrays.scad
+++ b/arrays.scad
@@ -951,28 +951,34 @@ function shuffle(list,seed) =
 
 // idx should be an index of the arrays l[i]
 function _group_sort_by_index(l,idx) =
-	len(l) == 0 ? [] :
-	len(l) == 1 ? [l] : 
-	let( pivot   = l[floor(len(l)/2)][idx],
-       equal   = [ for(li=l) if( li[idx]==pivot) li ] ,
-       lesser  = [ for(li=l) if( li[idx]< pivot) li ] ,
-       greater = [ for(li=l) if( li[idx]> pivot) li ]
-  )
-  concat( _group_sort_by_index(lesser,idx), 
-          [equal], 
-          _group_sort_by_index(greater,idx) ) ;  
+    len(l) == 0 ? [] :
+    len(l) == 1 ? [l] : 
+    let(
+        pivot   = l[floor(len(l)/2)][idx],
+        equal   = [ for(li=l) if( li[idx]==pivot) li ],
+        lesser  = [ for(li=l) if( li[idx]< pivot) li ],
+        greater = [ for(li=l) if( li[idx]> pivot) li ]
+    )
+    concat(
+        _group_sort_by_index(lesser,idx), 
+        [equal], 
+        _group_sort_by_index(greater,idx)
+    );  
 
 function _group_sort(l) =
-	len(l) == 0 ? [] : 
-	len(l) == 1 ? [l] : 
-	let( pivot   = l[floor(len(l)/2)],
-       equal   = [ for(li=l) if( li==pivot) li ] ,
-       lesser  = [ for(li=l) if( li< pivot) li ] ,
-       greater = [ for(li=l) if( li> pivot) li ]
-  )
-  concat( _group_sort(lesser), 
-          [equal], 
-          _group_sort(greater) ) ;    
+    len(l) == 0 ? [] : 
+    len(l) == 1 ? [l] : 
+    let(
+        pivot   = l[floor(len(l)/2)],
+        equal   = [ for(li=l) if( li==pivot) li ] ,
+        lesser  = [ for(li=l) if( li< pivot) li ] ,
+        greater = [ for(li=l) if( li> pivot) li ]
+    )
+    concat(
+        _group_sort(lesser), 
+        [equal], 
+        _group_sort(greater)
+    );    
 
 
 // Sort a vector of scalar values with the native comparison operator
@@ -1171,11 +1177,11 @@ function group_sort(list, idx) =
     assert(is_list(list), "Input should be a list." )
     assert(is_undef(idx) || (is_finite(idx) && idx>=0) , "Invalid index." )
     len(list)<=1 ? [list] :
-		is_vector(list)? _group_sort(list) :
-		let( idx = is_undef(idx) ? 0 : idx )
-		assert( [for(entry=list) if(!is_list(entry) || len(entry)<idx || !is_num(entry[idx]) ) 1]==[],
-            "Some entry of the list is a list shorter than `idx` or the indexed entry of it is not a number."	)
-		_group_sort_by_index(list,idx);
+    is_vector(list)? _group_sort(list) :
+    let( idx = is_undef(idx) ? 0 : idx )
+    assert( [for(entry=list) if(!is_list(entry) || len(entry)<idx || !is_num(entry[idx]) ) 1]==[],
+        "Some entry of the list is a list shorter than `idx` or the indexed entry of it is not a number.")
+    _group_sort_by_index(list,idx);
         
 
 // Function: unique()
@@ -1197,23 +1203,27 @@ function unique(list) =
     is_string(list)? str_join(unique([for (x = list) x])) :
     len(list)<=1? list : 
     is_homogeneous(list,1) && ! is_list(list[0])
-		?   _unique_sort(list)
+    ?   _unique_sort(list)
     :   let( sorted = sort(list))
-				[   for (i=[0:1:len(sorted)-1])
-								if (i==0 || (sorted[i] != sorted[i-1]))
-										sorted[i]
-				];
+        [
+            for (i=[0:1:len(sorted)-1])
+            if (i==0 || (sorted[i] != sorted[i-1]))
+            sorted[i]
+        ];
 
 function _unique_sort(l) =
-		len(l) <= 1 ? l : 
-		let( pivot   = l[floor(len(l)/2)],
-				 equal   = [ for(li=l) if( li==pivot) li ] ,
-				 lesser  = [ for(li=l) if( li<pivot ) li ] ,
-				 greater = [ for(li=l) if( li>pivot) li ]
-		)
-		concat( _unique_sort(lesser), 
-						equal[0], 
-						_unique_sort(greater) ) ;    
+    len(l) <= 1 ? l : 
+    let(
+        pivot   = l[floor(len(l)/2)],
+        equal   = [ for(li=l) if( li==pivot) li ] ,
+        lesser  = [ for(li=l) if( li<pivot ) li ] ,
+        greater = [ for(li=l) if( li>pivot) li ]
+    )
+    concat(
+        _unique_sort(lesser), 
+        equal[0], 
+        _unique_sort(greater)
+    );    
 
 
 // Function: unique_count()
@@ -1232,13 +1242,23 @@ function unique_count(list) =
     assert(is_list(list) || is_string(list), "Invalid input." )
     list == [] ? [[],[]] : 
     is_homogeneous(list,1) && ! is_list(list[0])
-    ?		let( sorted = _group_sort(list) )
-				[ [for(s=sorted) s[0] ], [for(s=sorted) len(s) ] ]
-		:		let( list=sort(list) )
-				let( ind = [0, for(i=[1:1:len(list)-1]) if (list[i]!=list[i-1]) i] )
-				[ select(list,ind), deltas( concat(ind,[len(list)]) ) ];
+      ? let( sorted = _group_sort(list) ) [
+            [for(s=sorted) s[0] ],
+            [for(s=sorted) len(s) ]
+        ]
+      : let(
+            list=sort(list),
+            ind = [
+                0,
+                for(i=[1:1:len(list)-1])
+                    if (list[i]!=list[i-1]) i
+            ]
+        ) [
+            select(list,ind),
+            deltas( concat(ind,[len(list)]) )
+        ];
+
 
-		
 // Section: List Iteration Helpers
 
 // Function: idx()
diff --git a/bottlecaps.scad b/bottlecaps.scad
index 49aa340..8bf1529 100644
--- a/bottlecaps.scad
+++ b/bottlecaps.scad
@@ -502,7 +502,7 @@ module generic_bottle_neck(
 }
 
 function generic_bottle_neck(
-	neck_d,
+    neck_d,
     id,
     thread_od,
     height,
diff --git a/geometry.scad b/geometry.scad
index 2610abd..92d474f 100644
--- a/geometry.scad
+++ b/geometry.scad
@@ -1,4 +1,4 @@
-//////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////
 // LibFile: geometry.scad
 //   Geometry helpers.
 // Includes:
@@ -21,7 +21,7 @@
 //   eps = Tolerance in geometric comparisons.  Default: `EPSILON` (1e-9)
 function point_on_segment2d(point, edge, eps=EPSILON) =
     assert( is_finite(eps) && (eps>=0), "The tolerance should be a non-negative value." )
-    point_segment_distance(point, edge)<eps;   
+    point_segment_distance(point, edge)<eps;
 
 
 //Internal - distance from point `d` to the line passing through the origin with unit direction n
@@ -32,8 +32,8 @@ function _dist2line(d,n) = norm(d-(d * n) * n);
 function _point_above_below_segment(point, edge) =
     let( edge = edge - [point, point] )
     edge[0].y <= 0
-    ?   (edge[1].y >  0 && cross(edge[0], edge[1]-edge[0]) > 0) ?  1 : 0
-    :   (edge[1].y <= 0 && cross(edge[0], edge[1]-edge[0]) < 0) ? -1 : 0 ;
+      ? (edge[1].y >  0 && cross(edge[0], edge[1]-edge[0]) > 0) ?  1 : 0
+      : (edge[1].y <= 0 && cross(edge[0], edge[1]-edge[0]) < 0) ? -1 : 0;
 
 //Internal
 function _valid_line(line,dim,eps=EPSILON) =
@@ -77,8 +77,8 @@ function collinear(a, b, c, eps=EPSILON) =
             "Input should be 3 points or a list of points with same dimension.")
     assert( is_finite(eps) && (eps>=0), "The tolerance should be a non-negative value." )
     let( points = is_def(c) ? [a,b,c]: a )
-    len(points)<3 ? true
-    : noncollinear_triple(points,error=false,eps=eps)==[];
+    len(points)<3 ? true :
+    noncollinear_triple(points,error=false,eps=eps) == [];
 
 
 // Function: point_line_distance()
@@ -131,8 +131,7 @@ function point_segment_distance(pt, seg) =
 //   dist = segment_distance([[-14,3], [-15,9]], [[-10,0], [10,0]]);  // Returns: 5
 //   dist2 = segment_distance([[-5,5], [5,-5]], [[-10,3], [10,-3]]);  // Returns: 0
 function segment_distance(seg1, seg2) =
-    assert( is_matrix(concat(seg1,seg2),4),
-            "Inputs should be two valid segments." )
+    assert( is_matrix(concat(seg1,seg2),4), "Inputs should be two valid segments." )
     convex_distance(seg1,seg2);
 
 
@@ -155,9 +154,9 @@ function segment_distance(seg1, seg2) =
 //   color("blue") move_copies([p1,p2]) circle(d=2, $fn=12);
 function line_normal(p1,p2) =
     is_undef(p2)
-    ?   assert( len(p1)==2 && !is_undef(p1[1]) , "Invalid input." )
+      ? assert( len(p1)==2 && !is_undef(p1[1]) , "Invalid input." )
         line_normal(p1[0],p1[1])
-    :   assert( _valid_line([p1,p2],dim=2), "Invalid line." )
+      : assert( _valid_line([p1,p2],dim=2), "Invalid line." )
         unit([p1.y-p2.y,p2.x-p1.x]);
 
 
@@ -172,7 +171,8 @@ function line_normal(p1,p2) =
 function _general_line_intersection(s1,s2,eps=EPSILON) =
     let(
         denominator = det2([s1[0],s2[0]]-[s1[1],s2[1]])
-    ) approx(denominator,0,eps=eps)? [undef,undef,undef] : let(
+    ) approx(denominator,0,eps=eps)? [undef,undef,undef] :
+    let(
         t = det2([s1[0],s2[0]]-s2) / denominator,
         u = det2([s1[0],s1[0]]-[s2[0],s1[1]]) / denominator
     ) [s1[0]+t*(s1[1]-s1[0]), t, u];
@@ -211,11 +211,10 @@ function line_intersection(l1,l2,eps=EPSILON) =
 function line_ray_intersection(line,ray,eps=EPSILON) =
     assert( is_finite(eps) && (eps>=0), "The tolerance should be a non-negative value." )
     assert( _valid_line(line,dim=2,eps=eps) && _valid_line(ray,dim=2,eps=eps), "Invalid line or ray." )
-    let(
-        isect = _general_line_intersection(line,ray,eps=eps)
-    )
+    let( isect = _general_line_intersection(line,ray,eps=eps) )
     is_undef(isect[0]) ? undef :
-    (isect[2]<0-eps) ? undef : isect[0];
+    (isect[2]<0-eps) ? undef :
+    isect[0];
 
 
 // Function: line_segment_intersection()
@@ -232,9 +231,7 @@ function line_ray_intersection(line,ray,eps=EPSILON) =
 function line_segment_intersection(line,segment,eps=EPSILON) =
     assert( is_finite(eps) && (eps>=0), "The tolerance should be a non-negative value." )
     assert( _valid_line(line,  dim=2,eps=eps) &&_valid_line(segment,dim=2,eps=eps), "Invalid line or segment." )
-    let(
-        isect = _general_line_intersection(line,segment,eps=eps)
-    )
+    let( isect = _general_line_intersection(line,segment,eps=eps) )
     is_undef(isect[0]) ? undef :
     isect[2]<0-eps || isect[2]>1+eps ? undef :
     isect[0];
@@ -254,11 +251,10 @@ function line_segment_intersection(line,segment,eps=EPSILON) =
 function ray_intersection(r1,r2,eps=EPSILON) =
     assert( is_finite(eps) && (eps>=0), "The tolerance should be a non-negative value." )
     assert( _valid_line(r1,dim=2,eps=eps) && _valid_line(r2,dim=2,eps=eps), "Invalid ray(s)." )
-    let(
-        isect = _general_line_intersection(r1,r2,eps=eps)
-    )
+    let( isect = _general_line_intersection(r1,r2,eps=eps) )
     is_undef(isect[0]) ? undef :
-    isect[1]<0-eps || isect[2]<0-eps ? undef : isect[0];
+    isect[1]<0-eps || isect[2]<0-eps ? undef :
+    isect[0];
 
 
 // Function: ray_segment_intersection()
@@ -275,9 +271,7 @@ function ray_intersection(r1,r2,eps=EPSILON) =
 function ray_segment_intersection(ray,segment,eps=EPSILON) =
     assert( _valid_line(ray,dim=2,eps=eps) && _valid_line(segment,dim=2,eps=eps), "Invalid ray or segment." )
     assert( is_finite(eps) && (eps>=0), "The tolerance should be a non-negative value." )
-    let(
-        isect = _general_line_intersection(ray,segment,eps=eps)
-    )
+    let( isect = _general_line_intersection(ray,segment,eps=eps) )
     is_undef(isect[0]) ? undef :
     isect[1]<0-eps || isect[2]<0-eps || isect[2]>1+eps ? undef :
     isect[0];
@@ -297,9 +291,7 @@ function ray_segment_intersection(ray,segment,eps=EPSILON) =
 function segment_intersection(s1,s2,eps=EPSILON) =
     assert( _valid_line(s1,dim=2,eps=eps) && _valid_line(s2,dim=2,eps=eps), "Invalid segment(s)." )
     assert( is_finite(eps) && (eps>=0), "The tolerance should be a non-negative value." )
-    let(
-        isect = _general_line_intersection(s1,s2,eps=eps)
-    )
+    let( isect = _general_line_intersection(s1,s2,eps=eps) )
     is_undef(isect[0]) ? undef :
     isect[1]<0-eps || isect[1]>1+eps || isect[2]<0-eps || isect[2]>1+eps ? undef :
     isect[0];
@@ -361,7 +353,7 @@ function line_closest_point(line,pt) =
     assert(_valid_line(line), "Invalid line." )
     assert( is_vector(pt,len(line[0])), "Invalid point or incompatible dimensions." )
     let( n = unit( line[0]- line[1]) )
-    line[1]+((pt- line[1]) * n) * n;
+    line[1] + ((pt- line[1]) * n) * n;
 
 
 // Function: ray_closest_point()
@@ -503,7 +495,9 @@ function line_from_points(points, fast=false, eps=EPSILON) =
     assert( is_finite(eps) && (eps>=0), "The tolerance should be a non-negative value." )
     let( pb = furthest_point(points[0],points) )
     norm(points[pb]-points[0])<eps*max(norm(points[pb]),norm(points[0])) ? undef :
-    fast || collinear(points) ? [points[pb], points[0]] : undef;
+    fast || collinear(points)
+      ? [points[pb], points[0]]
+      : undef;
 
 
 
@@ -576,7 +570,8 @@ function law_of_sines(a, A, b, B) =
     //   a/sin(A) = b/sin(B) = c/sin(C)
     assert(num_defined([b,B]) == 1, "Must give exactly one of b= or B=.")
     let( r = a/sin(A) )
-    is_undef(b) ? r*sin(B) : asin(constrain(b/r, -1, 1));
+    is_undef(b) ? r*sin(B) :
+    asin(constrain(b/r, -1, 1));
 
 
 // Function: tri_calc()
@@ -647,11 +642,11 @@ function tri_calc(ang,ang2,adj,opp,hyp) =
                   hyp
                 : (adj!=undef? (adj/cos(ang))
                 : (opp/sin(ang)))
-    )
-    [adj, opp, hyp, ang, ang2];
+    ) [adj, opp, hyp, ang, ang2];
 
 
 // Function: hyp_opp_to_adj()
+// Alias: opp_hyp_to_adj()
 // Usage:
 //   adj = hyp_opp_to_adj(hyp,opp);
 // Topics: Geometry, Triangles
@@ -668,8 +663,11 @@ function hyp_opp_to_adj(hyp,opp) =
            "Triangle side lengths should be a positive numbers." )
     sqrt(hyp*hyp-opp*opp);
 
+function opp_hyp_to_adj(opp,hyp) = hyp_opp_to_adj(hyp,opp);
+
 
 // Function: hyp_ang_to_adj()
+// Alias: ang_hyp_to_adj()
 // Usage:
 //   adj = hyp_ang_to_adj(hyp,ang);
 // Topics: Geometry, Triangles
@@ -686,8 +684,11 @@ function hyp_ang_to_adj(hyp,ang) =
     assert(is_finite(ang) && ang>-90 && ang<90, "The angle should be an acute angle." )
     hyp*cos(ang);
 
+function ang_hyp_to_adj(ang,hyp) = hyp_ang_to_adj(hyp, ang);
+
 
 // Function: opp_ang_to_adj()
+// Alias: ang_opp_to_adj()
 // Usage:
 //   adj = opp_ang_to_adj(opp,ang);
 // Topics: Geometry, Triangles
@@ -704,8 +705,11 @@ function opp_ang_to_adj(opp,ang) =
     assert(is_finite(ang) && ang>-90 && ang<90, "The angle should be an acute angle." )
     opp/tan(ang);
 
+function ang_opp_to_adj(ang,opp) = opp_ang_to_adj(opp,ang);
+
 
 // Function: hyp_adj_to_opp()
+// Alias: adj_hyp_to_opp()
 // Usage:
 //   opp = hyp_adj_to_opp(hyp,adj);
 // Topics: Geometry, Triangles
@@ -721,8 +725,11 @@ function hyp_adj_to_opp(hyp,adj) =
            "Triangle side lengths should be a positive numbers." )
     sqrt(hyp*hyp-adj*adj);
 
+function adj_hyp_to_opp(adj,hyp) = hyp_adj_to_opp(hyp,adj);
+
 
 // Function: hyp_ang_to_opp()
+// Alias: ang_hyp_to_opp()
 // Usage:
 //   opp = hyp_ang_to_opp(hyp,adj);
 // Topics: Geometry, Triangles
@@ -738,8 +745,11 @@ function hyp_ang_to_opp(hyp,ang) =
     assert(is_finite(ang) && ang>-90 && ang<90, "The angle should be an acute angle." )
     hyp*sin(ang);
 
+function ang_hyp_to_opp(ang,hyp) = hyp_ang_to_opp(hyp,ang);
+
 
 // Function: adj_ang_to_opp()
+// Alias: ang_adj_to_opp()
 // Usage:
 //   opp = adj_ang_to_opp(adj,ang);
 // Topics: Geometry, Triangles
@@ -755,8 +765,11 @@ function adj_ang_to_opp(adj,ang) =
     assert(is_finite(ang) && ang>-90 && ang<90, "The angle should be an acute angle." )
     adj*tan(ang);
 
+function ang_adj_to_opp(ang,adj) = adj_ang_to_opp(adj,ang);
+
 
 // Function: adj_opp_to_hyp()
+// Alias: opp_adj_to_hyp()
 // Usage:
 //   hyp = adj_opp_to_hyp(adj,opp);
 // Topics: Geometry, Triangles
@@ -772,8 +785,11 @@ function adj_opp_to_hyp(adj,opp) =
            "Triangle side lengths should be a positive numbers." )
     norm([opp,adj]);
 
+function opp_adj_to_hyp(opp,adj) = adj_opp_to_hyp(adj,opp);
+
 
 // Function: adj_ang_to_hyp()
+// Alias: ang_adj_to_hyp()
 // Usage:
 //   hyp = adj_ang_to_hyp(adj,ang);
 // Topics: Geometry, Triangles
@@ -789,8 +805,11 @@ function adj_ang_to_hyp(adj,ang) =
     assert(is_finite(ang) && ang>-90 && ang<90, "The angle should be an acute angle." )
     adj/cos(ang);
 
+function ang_adj_to_hyp(ang,adj) = adj_ang_to_hyp(adj,ang);
+
 
 // Function: opp_ang_to_hyp()
+// Alias: ang_opp_to_hyp()
 // Usage:
 //   hyp = opp_ang_to_hyp(opp,ang);
 // Topics: Geometry, Triangles
@@ -806,8 +825,11 @@ function opp_ang_to_hyp(opp,ang) =
     assert(is_finite(ang) && ang>-90 && ang<90, "The angle should be an acute angle." )
     opp/sin(ang);
 
+function ang_opp_to_hyp(ang,opp) = opp_ang_to_hyp(opp,ang);
+
 
 // Function: hyp_adj_to_ang()
+// Alias: adj_hyp_to_ang()
 // Usage:
 //   ang = hyp_adj_to_ang(hyp,adj);
 // Description:
@@ -822,8 +844,11 @@ function hyp_adj_to_ang(hyp,adj) =
             "Triangle side lengths should be positive numbers." )
     acos(adj/hyp);
 
+function adj_hyp_to_ang(adj,hyp) = hyp_adj_to_ang(hyp,adj);
+
 
 // Function: hyp_opp_to_ang()
+// Alias: opp_hyp_to_ang()
 // Usage:
 //   ang = hyp_opp_to_ang(hyp,opp);
 // Topics: Geometry, Triangles
@@ -839,8 +864,11 @@ function hyp_opp_to_ang(hyp,opp) =
             "Triangle side lengths should be positive numbers." )
     asin(opp/hyp);
 
+function opp_hyp_to_ang(opp,hyp) = hyp_opp_to_ang(hyp,opp);
+
 
 // Function: adj_opp_to_ang()
+// Alias: opp_adj_to_ang()
 // Usage:
 //   ang = adj_opp_to_ang(adj,opp);
 // Topics: Geometry, Triangles
@@ -856,6 +884,8 @@ function adj_opp_to_ang(adj,opp) =
             "Triangle side lengths should be positive numbers." )
     atan2(opp,adj);
 
+function opp_adj_to_ang(opp,adj) = adj_opp_to_ang(adj,opp);
+
 
 // Function: triangle_area()
 // Usage:
@@ -900,8 +930,7 @@ function plane3pt(p1, p2, p3) =
     let(
         crx = cross(p3-p1, p2-p1),
         nrm = norm(crx)
-    )
-    approx(nrm,0) ? [] :
+    ) approx(nrm,0) ? [] :
     concat(crx, crx*p1)/nrm;
 
 
@@ -928,8 +957,7 @@ function plane3pt_indexed(points, i1, i2, i3) =
         p1 = points[i1],
         p2 = points[i2],
         p3 = points[i3]
-    )
-    plane3pt(p1,p2,p3);
+    ) plane3pt(p1,p2,p3);
 
 
 // Function: plane_from_normal()
@@ -953,7 +981,7 @@ function plane_from_normal(normal, pt=[0,0,0]) =
 // Based on: https://en.wikipedia.org/wiki/Eigenvalue_algorithm
 function _eigenvals_symm_3(M) =
   let( p1 = pow(M[0][1],2) + pow(M[0][2],2) + pow(M[1][2],2) )
-  (p1<EPSILON)  
+  (p1<EPSILON)
   ? -sort(-[ M[0][0], M[1][1], M[2][2] ]) //  diagonal matrix: eigenvals in decreasing order
   : let(  q  = (M[0][0]+M[1][1]+M[2][2])/3,
           B  = (M - q*ident(3)),
@@ -964,19 +992,19 @@ function _eigenvals_symm_3(M) =
           ph = acos(constrain(r,-1,1))/3,
           e1 = q + 2*p*cos(ph),
           e3 = q + 2*p*cos(ph+120),
-          e2 = 3*q - e1 - e3 ) 
+          e2 = 3*q - e1 - e3 )
     [ e1, e2, e3 ];
 
 
 // the i-th normalized eigenvector of a 3x3 symmetrical matrix M from its eigenvalues
 // using Cayley–Hamilton theorem according to:
-// https://en.wikipedia.org/wiki/Eigenvalue_algorithm 
-function _eigenvec_symm_3(M,evals,i=0) = 
-    let(  
-        I = ident(3), 
+// https://en.wikipedia.org/wiki/Eigenvalue_algorithm
+function _eigenvec_symm_3(M,evals,i=0) =
+    let(
+        I = ident(3),
         A = (M - evals[(i+1)%3]*I) * (M - evals[(i+2)%3]*I) ,
-        k = max_index( [for(i=[0:2]) norm(A[i]) ]) 
-       )
+        k = max_index( [for(i=[0:2]) norm(A[i]) ])
+    )
     norm(A[k])<EPSILON ? I[k] : A[k]/norm(A[k]);
 
 
@@ -1013,15 +1041,16 @@ function _covariance_evec_eval(points) =
 function plane_from_points(points, fast=false, eps=EPSILON) =
     assert( is_path(points,dim=3), "Improper 3d point list." )
     assert( is_finite(eps) && (eps>=0), "The tolerance should be a non-negative value." )
-    len(points) == 3 
-    ?   let( plane = plane3pt(points[0],points[1],points[2]) )
-        plane==[] ? [] : plane    
-    :   let(  
+    len(points) == 3
+      ? let( plane = plane3pt(points[0],points[1],points[2]) )
+        plane==[] ? [] : plane
+      : let(
             covmix = _covariance_evec_eval(points),
             pm     = covmix[0],
             evec   = covmix[1],
             eval0  = covmix[2],
-            plane  = [ each evec, pm*evec] )
+            plane  = [ each evec, pm*evec]
+        )
         !fast && _pointlist_greatest_distance(points,plane)>eps*eval0 ? undef :
         plane ;
 
@@ -1054,8 +1083,8 @@ function plane_from_polygon(poly, fast=false, eps=EPSILON) =
     triple==[] ? [] :
     let( plane = plane3pt(poly[triple[0]],poly[triple[1]],poly[triple[2]]))
     fast? plane: points_on_plane(poly, plane, eps=eps)? plane: [];
- 
- 
+
+
 // Function: plane_normal()
 // Usage:
 //   vec = plane_normal(plane);
@@ -1164,10 +1193,10 @@ function _general_plane_line_intersection(plane, line, eps=EPSILON) =
         b = plane*[each(line[1]-line[0]),0]  // difference between the plane expression evaluation at line[1] and at line[0]
     )
     approx(b,0,eps)                          // is  (line[1]-line[0]) "parallel" to the plane ?
-    ? approx(a,0,eps)                        // is line[0] on the plane ?
-       ? [line,undef]                        // line is on the plane
-       : undef                               // line is parallel but not on the plane
-    : [ line[0]-a/b*(line[1]-line[0]), -a/b ];
+      ? approx(a,0,eps)                      // is line[0] on the plane ?
+        ? [line,undef]                       // line is on the plane
+        : undef                              // line is parallel but not on the plane
+      : [ line[0]-a/b*(line[1]-line[0]), -a/b ];
 
 
 // Function: normalize_plane()
@@ -1197,8 +1226,7 @@ function plane_line_angle(plane, line) =
         normal    = plane_normal(plane),
         sin_angle = linedir*normal,
         cos_angle = norm(cross(linedir,normal))
-    )
-    atan2(sin_angle,cos_angle);
+    ) atan2(sin_angle,cos_angle);
 
 
 // Function: plane_line_intersection()
@@ -1222,8 +1250,7 @@ function plane_line_intersection(plane, line, bounded=false, eps=EPSILON) =
     let(
         bounded = is_list(bounded)? bounded : [bounded, bounded],
         res = _general_plane_line_intersection(plane, line, eps=eps)
-    )
-    is_undef(res) ? undef :
+    ) is_undef(res) ? undef :
     is_undef(res[1]) ? res[0] :
     bounded[0] && res[1]<0 ? undef :
     bounded[1] && res[1]>1 ? undef :
@@ -1254,41 +1281,37 @@ function polygon_line_intersection(poly, line, bounded=false, eps=EPSILON) =
         bounded = is_list(bounded)? bounded : [bounded, bounded],
         poly = deduplicate(poly),
         indices = noncollinear_triple(poly)
-    )
-    indices==[] ? undef :
+    ) indices==[] ? undef :
     let(
         p1 = poly[indices[0]],
         p2 = poly[indices[1]],
         p3 = poly[indices[2]],
         plane = plane3pt(p1,p2,p3),
         res = _general_plane_line_intersection(plane, line, eps=eps)
-    )
-    is_undef(res)? undef :
-    is_undef(res[1])
-    ? ( let(// Line is on polygon plane.
+    ) is_undef(res)? undef :
+    is_undef(res[1]) ? (
+        let(// Line is on polygon plane.
             linevec = unit(line[1] - line[0]),
             lp1 = line[0] + (bounded[0]? 0 : -1000000) * linevec,
             lp2 = line[1] + (bounded[1]? 0 :  1000000) * linevec,
             poly2d = clockwise_polygon(project_plane(plane, poly)),
             line2d = project_plane(plane, [lp1,lp2]),
             parts = split_path_at_region_crossings(line2d, [poly2d], closed=false),
-            inside = [for (part = parts)
-                          if (point_in_polygon(mean(part), poly2d)>0) part
-                     ]
-        )
-        !inside? undef :
-        let(
-            isegs = [for (seg = inside) lift_plane(plane, seg) ]
-        )
+            inside = [
+                for (part = parts)
+                if (point_in_polygon(mean(part), poly2d)>0) part
+            ]
+        ) !inside? undef :
+        let( isegs = [for (seg = inside) lift_plane(plane, seg) ] )
         isegs
-    )
-    :   bounded[0] && res[1]<0? undef :
-        bounded[1] && res[1]>1? undef :
-        let(
-            proj = clockwise_polygon(project_plane([p1, p2, p3], poly)),
-            pt = project_plane([p1, p2, p3], res[0])
-        )
-        point_in_polygon(pt, proj) < 0 ? undef : res[0];
+    ) :
+    bounded[0] && res[1]<0? undef :
+    bounded[1] && res[1]>1? undef :
+    let(
+        proj = clockwise_polygon(project_plane([p1, p2, p3], poly)),
+        pt = project_plane([p1, p2, p3], res[0])
+    ) point_in_polygon(pt, proj) < 0 ? undef :
+    res[0];
 
 
 // Function: plane_intersection()
@@ -1309,19 +1332,20 @@ function plane_intersection(plane1,plane2,plane3) =
     assert( _valid_plane(plane1) && _valid_plane(plane2) && (is_undef(plane3) ||_valid_plane(plane3)),
                 "The input must be 2 or 3 planes." )
     is_def(plane3)
-    ?   let(
-          matrix = [for(p=[plane1,plane2,plane3]) point3d(p)],
-          rhs = [for(p=[plane1,plane2,plane3]) p[3]]
+      ? let(
+            matrix = [for(p=[plane1,plane2,plane3]) point3d(p)],
+            rhs = [for(p=[plane1,plane2,plane3]) p[3]]
         )
         linear_solve(matrix,rhs)
-    :   let( normal = cross(plane_normal(plane1), plane_normal(plane2)) )
+      : let( normal = cross(plane_normal(plane1), plane_normal(plane2)) )
         approx(norm(normal),0) ? undef :
         let(
             matrix = [for(p=[plane1,plane2]) point3d(p)],
             rhs = [plane1[3], plane2[3]],
             point = linear_solve(matrix,rhs)
         )
-        point==[]? undef: [point, point+normal];
+        point==[]? undef:
+        [point, point+normal];
 
 
 // Function: coplanar()
@@ -1337,18 +1361,18 @@ function coplanar(points, eps=EPSILON) =
     assert( is_path(points,dim=3) , "Input should be a list of 3D points." )
     assert( is_finite(eps) && eps>=0, "The tolerance should be a non-negative value." )
     len(points)<=2 ? false
-    :   let( ip = noncollinear_triple(points,error=false,eps=eps) )
+      : let( ip = noncollinear_triple(points,error=false,eps=eps) )
         ip == [] ? false :
         let( plane  = plane3pt(points[ip[0]],points[ip[1]],points[ip[2]]) )
         _pointlist_greatest_distance(points,plane) < eps;
 
 
-// the maximum distance from points to the plane 
+// the maximum distance from points to the plane
 function _pointlist_greatest_distance(points,plane) =
-    let( 
+    let(
         normal = point3d(plane),
         pt_nrm = points*normal
-         )
+    )
     abs(max( max(pt_nrm) - plane[3], -min(pt_nrm) + plane[3])) / norm(normal);
 
 
@@ -1482,6 +1506,7 @@ function circle_2tangents(pt1, pt2, pt3, r, d, tangents=false) =
         )
         [cp, n, tp1, tp2, dang1, dang2];
 
+
 module circle_2tangents(pt1, pt2, pt3, r, d, h, center=false) {
     c = circle_2tangents(pt1=pt1, pt2=pt2, pt3=pt3, r=r, d=d);
     assert(!is_undef(c), "Cannot find circle when both rays are collinear.");
@@ -1498,6 +1523,7 @@ module circle_2tangents(pt1, pt2, pt3, r, d, h, center=false) {
     }
 }
 
+
 // Function&Module: circle_3points()
 // Usage: As Function
 //   circ = circle_3points(pt1, pt2, pt3);
@@ -1628,7 +1654,7 @@ function circle_point_tangents(r, d, cp, pt) =
 //   returns only two entries.  If one circle is inside the other one then no tangents exist
 //   so the function returns the empty set.  When the circles are tangent a degenerate tangent line
 //   passes through the point of tangency of the two circles:  this degenerate line is NOT returned.
-// Arguments: 
+// Arguments:
 //   c1 = Center of the first circle.
 //   r1 = Radius of the first circle.
 //   c2 = Center of the second circle.
@@ -1747,7 +1773,7 @@ function circle_line_intersection(c,r,d,line,bounded=false,eps=EPSILON) =
 //   If all points are collinear returns [] when `error=true` or an error otherwise .
 // Arguments:
 //   points = List of input points.
-//   error = Defines the behaviour for collinear input points. When `true`, produces an error, otherwise returns []. Default: `true`. 
+//   error = Defines the behaviour for collinear input points. When `true`, produces an error, otherwise returns []. Default: `true`.
 //   eps = Tolerance for collinearity test. Default: EPSILON.
 function noncollinear_triple(points,error=true,eps=EPSILON) =
     assert( is_path(points), "Invalid input points." )
@@ -1758,19 +1784,17 @@ function noncollinear_triple(points,error=true,eps=EPSILON) =
         b  = furthest_point(pa, points),
         pb = points[b],
         nrm = norm(pa-pb)
-        )
-    nrm <= eps*max(norm(pa),norm(pb))
-    ? assert(!error, "Cannot find three noncollinear points in pointlist.")
-        []
-    :   let(
-            n = (pb-pa)/nrm,
-            distlist = [for(i=[0:len(points)-1]) _dist2line(points[i]-pa, n)]
-           )
-        max(distlist) < eps*nrm
-        ?  assert(!error, "Cannot find three noncollinear points in pointlist.")
-           []
-        :  [0,b,max_index(distlist)];
-        
+    )
+    nrm <= eps*max(norm(pa),norm(pb)) ?
+        assert(!error, "Cannot find three noncollinear points in pointlist.") [] :
+    let(
+        n = (pb-pa)/nrm,
+        distlist = [for(i=[0:len(points)-1]) _dist2line(points[i]-pa, n)]
+    )
+    max(distlist) < eps*nrm ?
+        assert(!error, "Cannot find three noncollinear points in pointlist.") [] :
+    [0, b, max_index(distlist)];
+
 
 // Function: pointlist_bounds()
 // Usage:
@@ -1784,12 +1808,14 @@ function noncollinear_triple(points,error=true,eps=EPSILON) =
 //   pts = List of points.
 function pointlist_bounds(pts) =
     assert(is_path(pts,dim=undef,fast=true) , "Invalid pointlist." )
-    let( 
+    let(
         select = ident(len(pts[0])),
-        spread = [for(i=[0:len(pts[0])-1])
-                      let( spreadi = pts*select[i] ) 
-                      [min(spreadi), max(spreadi)] ] )
-    transpose(spread);
+        spread = [
+            for(i=[0:len(pts[0])-1])
+            let( spreadi = pts*select[i] )
+            [ min(spreadi), max(spreadi) ]
+        ]
+    ) transpose(spread);
 
 
 // Function: closest_point()
@@ -1935,7 +1961,7 @@ function reindex_polygon(reference, poly, return_error=false) =
                     [for(i=[0:N-1])
                       (reference[i]*poly[(i+k)%N]) ] ]*I,
         optimal_poly = polygon_shift(fixpoly, max_index(val))
-      )
+    )
     return_error? [optimal_poly, min(poly*(I*poly)-2*val)] :
     optimal_poly;
 
@@ -1968,7 +1994,8 @@ function align_polygon(reference, poly, angles, cp) =
             "The `angle` parameter must be a range or a non void list of numbers.")
     let(     // alignments is a vector of entries of the form: [polygon, error]
         alignments = [
-            for(angle=angles) reindex_polygon(
+            for(angle=angles)
+            reindex_polygon(
                 reference,
                 zrot(angle,p=poly,cp=cp),
                 return_error=true
@@ -1995,22 +2022,21 @@ function centroid(poly, eps=EPSILON) =
     assert( is_finite(eps) && (eps>=0), "The tolerance should be a non-negative value." )
     let(
         n = len(poly[0])==2 ? 1 :
-            let( 
-                plane = plane_from_points(poly, fast=true) )
+            let( plane = plane_from_points(poly, fast=true) )
             assert( !is_undef(plane), "The polygon must be planar." )
             plane_normal(plane),
         v0 = poly[0] ,
-        val = sum([for(i=[1:len(poly)-2])
-                        let(
-                           v1 = poly[i],
-                           v2 = poly[i+1],
-                           area = cross(v2-v0,v1-v0)*n
-                           )
-                        [ area, (v0+v1+v2)*area ]
-                    ] )
-          )
-      assert(!approx(val[0],0, eps), "The polygon is self-intersecting or its points are collinear.")
-      val[1]/val[0]/3;
+        val = sum([
+            for(i=[1:len(poly)-2])
+            let(
+                v1 = poly[i],
+                v2 = poly[i+1],
+                area = cross(v2-v0,v1-v0)*n
+            ) [ area, (v0+v1+v2)*area ]
+        ])
+    )
+    assert(!approx(val[0],0, eps), "The polygon is self-intersecting or its points are collinear.")
+    val[1]/val[0]/3;
 
 
 
@@ -2041,38 +2067,39 @@ function point_in_polygon(point, poly, nonzero=true, eps=EPSILON) =
     assert( is_finite(eps) && (eps>=0), "The tolerance should be a non-negative value." )
     // Does the point lie on any edges?  If so return 0.
     let(
-        on_brd = [for(i=[0:1:len(poly)-1])
-                    let( seg = select(poly,i,i+1) )
-                    if( !approx(seg[0],seg[1],eps) )
-                        point_on_segment2d(point, seg, eps=eps)? 1:0 ]
-        )
-    sum(on_brd) > 0
-    ? 0
-    :   nonzero
-        ?    // Compute winding number and return 1 for interior, -1 for exterior
-            let(
-                windchk = [for(i=[0:1:len(poly)-1])
-                            let(seg=select(poly,i,i+1))
-                            if(!approx(seg[0],seg[1],eps=eps))
-                                _point_above_below_segment(point, seg)
-                          ]
+        on_brd = [
+            for (i = [0:1:len(poly)-1])
+            let( seg = select(poly,i,i+1) )
+            if (!approx(seg[0],seg[1],eps) )
+            point_on_segment2d(point, seg, eps=eps)? 1:0
+        ]
+    )
+    sum(on_brd) > 0? 0 :
+    nonzero
+      ?  // Compute winding number and return 1 for interior, -1 for exterior
+        let(
+            windchk = [
+                for(i=[0:1:len(poly)-1])
+                let( seg=select(poly,i,i+1) )
+                if (!approx(seg[0],seg[1],eps=eps))
+                _point_above_below_segment(point, seg)
+            ]
+        ) sum(windchk) != 0 ? 1 : -1
+      : // or compute the crossings with the ray [point, point+[1,0]]
+        let(
+            n  = len(poly),
+            cross = [
+                for(i=[0:n-1])
+                let(
+                    p0 = poly[i]-point,
+                    p1 = poly[(i+1)%n]-point
                 )
-            sum(windchk) != 0 ? 1 : -1
-        :   // or compute the crossings with the ray [point, point+[1,0]]
-            let(
-              n  = len(poly),
-              cross =
-                [for(i=[0:n-1])
-                    let(
-                      p0 = poly[i]-point,
-                      p1 = poly[(i+1)%n]-point
-                      )
-                    if( ( (p1.y>eps && p0.y<=eps) || (p1.y<=eps && p0.y>eps) )
-                       &&  -eps < p0.x - p0.y *(p1.x - p0.x)/(p1.y - p0.y) )
-                    1
-                ]
-            ) 
-            2*(len(cross)%2)-1;
+                if (
+                    ( (p1.y>eps && p0.y<=eps) || (p1.y<=eps && p0.y>eps) )
+                    &&  -eps < p0.x - p0.y *(p1.x - p0.x)/(p1.y - p0.y)
+                ) 1
+            ]
+        ) 2*(len(cross)%2)-1;
 
 
 // Function: polygon_is_clockwise()
@@ -2128,7 +2155,7 @@ function ccw_polygon(poly) =
 //   poly = The list of the path points for the perimeter of the polygon.
 function reverse_polygon(poly) =
     assert(is_path(poly), "Input should be a polygon")
-   [poly[0], for(i=[len(poly)-1:-1:1]) poly[i] ]; 
+    [ poly[0], for(i=[len(poly)-1:-1:1]) poly[i] ];
 
 
 // Function: polygon_normal()
@@ -2311,7 +2338,7 @@ function split_polygons_at_each_z(polys, zs, _i=0) =
 //   test = is_convex_polygon(poly);
 // Topics: Geometry, Convexity, Test
 // Description:
-//   Returns true if the given 2D or 3D polygon is convex.  
+//   Returns true if the given 2D or 3D polygon is convex.
 //   The result is meaningless if the polygon is not simple (self-intersecting) or non coplanar.
 //   If the points are collinear an error is generated.
 // Arguments:
@@ -2325,14 +2352,16 @@ function split_polygons_at_each_z(polys, zs, _i=0) =
 //   test = is_convex_polygon(spiral);  // Returns: false
 function is_convex_polygon(poly,eps=EPSILON) =
     assert(is_path(poly), "The input should be a 2D or 3D polygon." )
-    let( lp = len(poly),
-         p0 = poly[0] )
+    let(
+        lp = len(poly),
+        p0 = poly[0]
+    )
     assert( lp>=3 , "A polygon must have at least 3 points" )
     let( crosses = [for(i=[0:1:lp-1]) cross(poly[(i+1)%lp]-poly[i], poly[(i+2)%lp]-poly[(i+1)%lp]) ] )
     len(p0)==2
-    ?   assert( !approx(sqrt(max(max(crosses),-min(crosses))),eps), "The points are collinear" )
+      ? assert( !approx(sqrt(max(max(crosses),-min(crosses))),eps), "The points are collinear" )
         min(crosses) >=0 || max(crosses)<=0
-    :   let( prod = crosses*sum(crosses),
+      : let( prod = crosses*sum(crosses),
              minc = min(prod),
              maxc = max(prod) )
         assert( !approx(sqrt(max(maxc,-minc)),eps), "The points are collinear" )
@@ -2346,9 +2375,9 @@ function is_convex_polygon(poly,eps=EPSILON) =
 // See also: 
 //   convex_collision(), hull()
 // Description:
-//   Returns the smallest distance between a point in convex hull of `points1` 
+//   Returns the smallest distance between a point in convex hull of `points1`
 //   and a point in the convex hull of `points2`. All the points in the lists
-//   should have the same dimension, either 2D or 3D. 
+//   should have the same dimension, either 2D or 3D.
 //   A zero result means the hulls intercept whithin a tolerance `eps`.
 // Arguments:
 //   points1 - first list of 2d or 3d points.
@@ -2366,7 +2395,7 @@ function is_convex_polygon(poly,eps=EPSILON) =
 // Example(3D):
 //    sphr1 = sphere(2,$fn=10);
 //    sphr2 = move([4,0,0], p=sphr1);
-//    sphr3 = move([4.5,0,0], p=sphr1);    
+//    sphr3 = move([4.5,0,0], p=sphr1);
 //    vnf_polyhedron(sphr1);
 //    vnf_polyhedron(sphr2);
 //    echo(convex_distance(sphr1[0], sphr2[0])); // Returns: 0
@@ -2378,25 +2407,25 @@ function convex_distance(points1, points2, eps=EPSILON) =
            "The input points should be 2d or 3d points.")
     let( d = points1[0]-points2[0] )
     norm(d)<eps ? 0 :
-    let( v = _support_diff(points1,points2,-d) ) 
+    let( v = _support_diff(points1,points2,-d) )
     norm(_GJK_distance(points1, points2, eps, 0, v, [v]));
 
 
 // Finds the vector difference between the hulls of the two pointsets by the GJK algorithm
 // Based on:
 // http://www.dtecta.com/papers/jgt98convex.pdf
-function _GJK_distance(points1, points2, eps=EPSILON, lbd, d, simplex=[]) = 
+function _GJK_distance(points1, points2, eps=EPSILON, lbd, d, simplex=[]) =
     let( nrd = norm(d) ) // distance upper bound
     nrd<eps ? d :
     let(
         v     = _support_diff(points1,points2,-d),
         lbd   = max(lbd, d*v/nrd), // distance lower bound
-        close = (nrd-lbd <= eps*nrd) 
+        close = (nrd-lbd <= eps*nrd)
     )
-    // v already in the simplex is a degenerence due to numerical errors 
+    // v already in the simplex is a degenerence due to numerical errors
     // and may produce a non-stopping loop
-    close || [for(nv=norm(v), s=simplex) if(norm(s-v)<=eps*nv) 1]!=[] ? d :  
-    let( newsplx = _closest_simplex(concat(simplex,[v]),eps) ) 
+    close || [for(nv=norm(v), s=simplex) if(norm(s-v)<=eps*nv) 1]!=[] ? d :
+    let( newsplx = _closest_simplex(concat(simplex,[v]),eps) )
     _GJK_distance(points1, points2, eps, lbd, newsplx[0], newsplx[1]);
 
 
@@ -2427,7 +2456,7 @@ function _GJK_distance(points1, points2, eps=EPSILON, lbd, d, simplex=[]) =
 // Example(3D):
 //    sphr1 = sphere(2,$fn=10);
 //    sphr2 = move([4,0,0], p=sphr1);
-//    sphr3 = move([4.5,0,0], p=sphr1);    
+//    sphr3 = move([4.5,0,0], p=sphr1);
 //    vnf_polyhedron(sphr1);
 //    vnf_polyhedron(sphr2);
 //    echo(convex_collision(sphr1[0], sphr2[0])); // Returns: true
@@ -2440,7 +2469,7 @@ function convex_collision(points1, points2, eps=EPSILON) =
            "The input points should be 2d or 3d points.")
     let( d = points1[0]-points2[0] )
     norm(d)<eps ? true :
-    let( v = _support_diff(points1,points2,-d) ) 
+    let( v = _support_diff(points1,points2,-d) )
     _GJK_collide(points1, points2, v, [v], eps);
 
 
@@ -2448,8 +2477,8 @@ function convex_collision(points1, points2, eps=EPSILON) =
 // http://uu.diva-portal.org/smash/get/diva2/FFULLTEXT01.pdf
 // or
 // http://www.dtecta.com/papers/jgt98convex.pdf
-function _GJK_collide(points1, points2, d, simplex, eps=EPSILON) = 
-    norm(d) < eps ? true :          // does collide 
+function _GJK_collide(points1, points2, d, simplex, eps=EPSILON) =
+    norm(d) < eps ? true :          // does collide
     let( v = _support_diff(points1,points2,-d) )
     v*d > eps ? false : // no collision
     let( newsplx = _closest_simplex(concat(simplex,[v]),eps) )
@@ -2461,7 +2490,7 @@ function _GJK_collide(points1, points2, d, simplex, eps=EPSILON) =
 //  - the smallest sub-simplex of s that contains that point
 function _closest_simplex(s,eps=EPSILON) =
     assert(len(s)>=2 && len(s)<=4, "Internal error.")
-    len(s)==2 ? _closest_s1(s,eps) : 
+    len(s)==2 ? _closest_s1(s,eps) :
     len(s)==3 ? _closest_s2(s,eps)
               : _closest_s3(s,eps);
 
@@ -2470,10 +2499,10 @@ function _closest_simplex(s,eps=EPSILON) =
 // Based on: http://uu.diva-portal.org/smash/get/diva2/FFULLTEXT01.pdf
 function _closest_s1(s,eps=EPSILON) =
     norm(s[1]-s[0])<eps*(norm(s[0])+norm(s[1]))/2 ? [ s[0], [s[0]] ] :
-    let( 
+    let(
         c = s[1]-s[0],
         t = -s[0]*c/(c*c)
-    ) 
+    )
     t<0 ? [ s[0], [s[0]] ] :
     t>1 ? [ s[1], [s[1]] ] :
     [ s[0]+t*c, s ];
@@ -2503,13 +2532,13 @@ function _closest_s2(s,eps=EPSILON) =
                     + (cross(nr,c-a)*a<0 ? 2 : 0 )
                     + (cross(nr,b-c)*b<0 ? 4 : 0 )
         )
-        assert( class!=1, "Internal error" )  
+        assert( class!=1, "Internal error" )
         class==0 ? [ nr*(nr*a)/(nr*nr), s] : // origin projects (or is) on the tri
 //        class==1 ? _closest_s1([s[0],s[1]]) :
-        class==2 ? _closest_s1([s[0],s[2]],eps) :  
+        class==2 ? _closest_s1([s[0],s[2]],eps) :
         class==4 ? _closest_s1([s[1],s[2]],eps) :
-//        class==3 ? a*(a-b)> 0 ? _closest_s1([s[0],s[1]]) : _closest_s1([s[0],s[2]]) : 
-        class==3 ? _closest_s1([s[0],s[2]],eps) : 
+//        class==3 ? a*(a-b)> 0 ? _closest_s1([s[0],s[1]]) : _closest_s1([s[0],s[2]]) :
+        class==3 ? _closest_s1([s[0],s[2]],eps) :
 //        class==5 ? b*(b-c)<=0 ? _closest_s1([s[0],s[1]]) : _closest_s1([s[1],s[2]]) :
         class==5 ? _closest_s1([s[1],s[2]],eps) :
         c*(c-a)>0 ? _closest_s1([s[0],s[2]],eps) : _closest_s1([s[1],s[2]],eps);
@@ -2521,13 +2550,13 @@ function _closest_s3(s,eps=EPSILON) =
     assert( len(s[0])==3 && len(s)==4, "Internal error." )
     let( nr = cross(s[1]-s[0],s[2]-s[0]),
          sz = [ norm(s[1]-s[0]), norm(s[1]-s[2]), norm(s[2]-s[0]) ] )
-    norm(nr)<eps*max(sz) 
-    ?   let( i = max_index(sz) )
+    norm(nr)<eps*max(sz)
+      ? let( i = max_index(sz) )
         _closest_s2([ s[i], s[(i+1)%3], s[3] ], eps) // degenerate case
-    // considering that s[3] was the last inserted vertex in s,
-    // the only possible outcomes will be:
-    //    s or some of the 3 triangles of s containing s[3]
-    :   let(
+        // considering that s[3] was the last inserted vertex in s,
+        // the only possible outcomes will be:
+        //    s or some of the 3 triangles of s containing s[3]
+      : let(
             tris = [ [s[0], s[1], s[3]],
                      [s[1], s[2], s[3]],
                      [s[2], s[0], s[3]] ],
diff --git a/math.scad b/math.scad
index 30b585e..9547702 100644
--- a/math.scad
+++ b/math.scad
@@ -791,13 +791,17 @@ function _med3(a,b,c) =
 //   d = convolve([[1,1],[2,2],[3,1]],[[1,2],[2,1]])); // Returns:  [3,9,11,7]
 function convolve(p,q) =
     p==[] || q==[] ? [] :
-    assert( (is_vector(p) || is_matrix(p))
-		        && ( is_vector(q) || (is_matrix(q) && ( !is_vector(p[0]) || (len(p[0])==len(q[0])) ) ) ) ,
-		        "The inputs should be vectors or paths all of the same dimension.")
-    let( n = len(p),
-         m = len(q))
-    [for(i=[0:n+m-2], k1 = max(0,i-n+1), k2 = min(i,m-1) )
-       sum([for(j=[k1:k2]) p[i-j]*q[j] ]) 
+    assert(
+        (is_vector(p) || is_matrix(p))
+            && ( is_vector(q) || (is_matrix(q) && ( !is_vector(p[0]) || (len(p[0])==len(q[0])) ) ) ) ,
+        "The inputs should be vectors or paths all of the same dimension."
+    )
+    let(
+        n = len(p),
+        m = len(q)
+    ) [
+        for (i=[0:n+m-2], k1 = max(0,i-n+1), k2 = min(i,m-1) )
+        sum([for(j=[k1:k2]) p[i-j]*q[j] ]) 
     ];
 
 
diff --git a/paths.scad b/paths.scad
index 3c79b97..8c056ec 100644
--- a/paths.scad
+++ b/paths.scad
@@ -1010,7 +1010,7 @@ module jittered_poly(path, dist=1/512) {
 //       xcopies(3) circle(3, $fn=32);
 //   }
 module extrude_from_to(pt1, pt2, convexity, twist, scale, slices) {
-		assert( is_path([pt1,pt2],3), "The points should be 3d points");
+    assert( is_path([pt1,pt2],3), "The points should be 3d points");
     rtp = xyz_to_spherical(pt2-pt1);
     translate(pt1) {
         rotate([0, rtp[2], rtp[1]]) {
diff --git a/scripts/check_for_tabs.sh b/scripts/check_for_tabs.sh
new file mode 100755
index 0000000..a075703
--- /dev/null
+++ b/scripts/check_for_tabs.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+if grep -H -n -P '\t' *.scad ; then
+    echo "Tabs found in source code." 2>&1
+    exit 1
+fi
+exit 0
+
+
diff --git a/shapes.scad b/shapes.scad
index 388bcec..235680b 100644
--- a/shapes.scad
+++ b/shapes.scad
@@ -405,6 +405,8 @@ function cuboid(
 //   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`
 //
+// See Also: rounded_prism()
+//
 // Example: Rectangular Pyramid
 //   prismoid([40,40], [0,0], h=20);
 // Example: Prism
@@ -479,8 +481,8 @@ module prismoid(
     anchor = get_anchor(anchor, center, BOT, BOT);
     vnf = prismoid(
         size1=size1, size2=size2, h=h, shift=shift,
-        rounding=rounding, rounding1=rounding1, rounding2=rounding2,
-        chamfer=chamfer, chamfer1=chamfer1, chamfer2=chamfer2,
+        rounding1=rounding1, rounding2=rounding2,
+        chamfer1=chamfer1, chamfer2=chamfer2,
         l=l, center=CENTER
     );
     attachable(anchor,spin,orient, size=[s1.x,s1.y,h], size2=s2, shift=shift) {
@@ -500,12 +502,36 @@ function prismoid(
     assert(is_vector(size2,2))
     assert(is_num(h) || is_num(l))
     assert(is_vector(shift,2))
-    assert(is_num(rounding) || is_vector(rounding,4), "Bad rounding argument.")
-    assert(is_undef(rounding1) || is_num(rounding1) || is_vector(rounding1,4), "Bad rounding1 argument.")
-    assert(is_undef(rounding2) || is_num(rounding2) || is_vector(rounding2,4), "Bad rounding2 argument.")
-    assert(is_num(chamfer) || is_vector(chamfer,4), "Bad chamfer argument.")
-    assert(is_undef(chamfer1) || is_num(chamfer1) || is_vector(chamfer1,4), "Bad chamfer1 argument.")
-    assert(is_undef(chamfer2) || is_num(chamfer2) || is_vector(chamfer2,4), "Bad chamfer2 argument.")
+    assert(
+        (is_num(rounding) && rounding>=0) ||
+        (is_vector(rounding,4) && all_nonnegative(rounding)),
+        "Bad rounding argument."
+    )
+    assert(
+        is_undef(rounding1) || (is_num(rounding1) && rounding1>=0) ||
+        (is_vector(rounding1,4) && all_nonnegative(rounding1)),
+        "Bad rounding1 argument."
+    )
+    assert(
+        is_undef(rounding2) || (is_num(rounding2) && rounding2>=0) ||
+        (is_vector(rounding2,4) && all_nonnegative(rounding2)),
+        "Bad rounding2 argument."
+    )
+    assert(
+        (is_num(chamfer) && chamfer>=0) ||
+        (is_vector(chamfer,4) && all_nonnegative(chamfer)),
+        "Bad chamfer argument."
+    )
+    assert(
+        is_undef(chamfer1) || (is_num(chamfer1) && chamfer1>=0) ||
+        (is_vector(chamfer1,4) && all_nonnegative(chamfer1)),
+        "Bad chamfer1 argument."
+    )
+    assert(
+        is_undef(chamfer2) || (is_num(chamfer2) && chamfer2>=0) ||
+        (is_vector(chamfer2,4) && all_nonnegative(chamfer2)),
+        "Bad chamfer2 argument."
+    )
     let(
         eps = pow(2,-14),
         h = first_defined([h,l,1]),
diff --git a/shapes2d.scad b/shapes2d.scad
index b54a64f..d685f5b 100644
--- a/shapes2d.scad
+++ b/shapes2d.scad
@@ -1434,10 +1434,10 @@ function trapezoid(h, w1, w2, angle, shift=0, chamfer=0, rounding=0, anchor=CENT
     assert(is_undef(angle) || is_finite(angle))
     assert(num_defined([h, w1, w2, angle]) == 3, "Must give exactly 3 of the arguments h, w1, w2, and angle.")
     assert(is_finite(shift))
-	assert(is_finite(chamfer)  || is_vector(chamfer,4))
-	assert(is_finite(rounding) || is_vector(rounding,4))
+    assert(is_finite(chamfer)  || is_vector(chamfer,4))
+    assert(is_finite(rounding) || is_vector(rounding,4))
     let(
-		simple = chamfer==0 && rounding==0,
+        simple = chamfer==0 && rounding==0,
         h  = !is_undef(h)?  h  : opp_ang_to_adj(abs(w2-w1)/2, abs(angle)),
         w1 = !is_undef(w1)? w1 : w2 + 2*(adj_ang_to_opp(h, angle) + shift),
         w2 = !is_undef(w2)? w2 : w1 - 2*(adj_ang_to_opp(h, angle) + shift)
@@ -1451,23 +1451,23 @@ function trapezoid(h, w1, w2, angle, shift=0, chamfer=0, rounding=0, anchor=CENT
             [-w1/2,-h/2],
             [w1/2,-h/2],
         ],
-		cpath = simple? base_path :
-			path_chamfer_and_rounding(
-				base_path, closed=true,
-				chamfer=chamfer,
-				rounding=rounding
-			),
-		path = reverse(cpath)
-	) simple?
-		reorient(anchor,spin, two_d=true, size=[w1,h], size2=w2, shift=shift, p=path) :
-		reorient(anchor,spin, two_d=true, path=path, p=path);
+        cpath = simple? base_path :
+            path_chamfer_and_rounding(
+                base_path, closed=true,
+                chamfer=chamfer,
+                rounding=rounding
+            ),
+        path = reverse(cpath)
+    ) simple
+      ? reorient(anchor,spin, two_d=true, size=[w1,h], size2=w2, shift=shift, p=path)
+      : reorient(anchor,spin, two_d=true, path=path, p=path);
 
 
 
 module trapezoid(h, w1, w2, angle, shift=0, chamfer=0, rounding=0, anchor=CENTER, spin=0) {
-	path = trapezoid(h=h, w1=w1, w2=w2, angle=angle, shift=shift, chamfer=chamfer, rounding=rounding);
+    path = trapezoid(h=h, w1=w1, w2=w2, angle=angle, shift=shift, chamfer=chamfer, rounding=rounding);
     union() {
-		simple = chamfer==0 && rounding==0;
+        simple = chamfer==0 && rounding==0;
         h  = !is_undef(h)?  h  : opp_ang_to_adj(abs(w2-w1)/2, abs(angle));
         w1 = !is_undef(w1)? w1 : w2 + 2*(adj_ang_to_opp(h, angle) + shift);
         w2 = !is_undef(w2)? w2 : w1 - 2*(adj_ang_to_opp(h, angle) + shift);
diff --git a/walls.scad b/walls.scad
index 973bba8..1284fa7 100644
--- a/walls.scad
+++ b/walls.scad
@@ -91,10 +91,10 @@ module thinning_wall(h=50, l=100, thick=5, ang=30, braces=false, strut, wall, an
     wall = is_num(wall)? wall : thick/2;
 
     bevel_h = strut + (thick-wall)/2/tan(ang);
-    cp1 = circle_2tangents([0,0,h/2], [l2/2,0,h/2], [l1/2,0,-h/2], r=strut)[0];
-    cp2 = circle_2tangents([0,0,h/2], [l2/2,0,h/2], [l1/2,0,-h/2], r=bevel_h)[0];
-    cp3 = circle_2tangents([0,0,-h/2], [l1/2,0,-h/2], [l2/2,0,h/2], r=bevel_h)[0];
-    cp4 = circle_2tangents([0,0,-h/2], [l1/2,0,-h/2], [l2/2,0,h/2], r=strut)[0];
+    cp1 = circle_2tangents([0,0,+h/2], [l2/2,0,+h/2], [l1/2,0,-h/2], r=strut)[0];
+    cp2 = circle_2tangents([0,0,+h/2], [l2/2,0,+h/2], [l1/2,0,-h/2], r=bevel_h)[0];
+    cp3 = circle_2tangents([0,0,-h/2], [l1/2,0,-h/2], [l2/2,0,+h/2], r=bevel_h)[0];
+    cp4 = circle_2tangents([0,0,-h/2], [l1/2,0,-h/2], [l2/2,0,+h/2], r=strut)[0];
 
     z1 = h/2;
     z2 = cp1.z;
@@ -116,7 +116,7 @@ module thinning_wall(h=50, l=100, thick=5, ang=30, braces=false, strut, wall, an
 
     size = [l1, thick, h];
     attachable(anchor,spin,orient, size=size, size2=[l2,thick]) {
-        union() {
+        zrot(90) {
             polyhedron(
                 points=[
                     [-x4, -y1, -z1],