From c78eade2f2590a8fd7502e2dfb904f5aae53298d Mon Sep 17 00:00:00 2001
From: Revar Desmera <revarbat@gmail.com>
Date: Sun, 22 Mar 2020 01:14:26 -0700
Subject: [PATCH] Added initial Fractal Tree demo tutorial.  Still need to gen
 images.

---
 examples/fractal_tree.scad            |  55 +++-------
 examples/randomized_fractal_tree.scad |  48 +++++++++
 tutorials/Fractal_Tree.md             | 139 ++++++++++++++++++++++++++
 version.scad                          |   2 +-
 4 files changed, 200 insertions(+), 44 deletions(-)
 create mode 100644 examples/randomized_fractal_tree.scad
 create mode 100644 tutorials/Fractal_Tree.md

diff --git a/examples/fractal_tree.scad b/examples/fractal_tree.scad
index 0cb34c2..5ef423e 100644
--- a/examples/fractal_tree.scad
+++ b/examples/fractal_tree.scad
@@ -1,48 +1,17 @@
 include <BOSL2/std.scad>
-include <BOSL2/paths.scad>
-include <BOSL2/beziers.scad>
-
-module leaf(s) {
-	path = [
-		[0,0], [1.5,-1],
-		[2,1], [0,3], [-2,1],
-		[-1.5,-1], [0,0]
-	];
-	xrot(90)
-	linear_sweep_bezier(
-		scale_points(path, [s,s]/2),
-		height=0.02
-	);
-}
-
-module branches(minsize, s1, s2){
-    if(s2>minsize) {
+module tree(l=1500, sc=0.7, depth=10)
+	recolor("lightgray")
+	cylinder(l=l, d1=l/5, d2=l/5*sc)
 		attach(TOP)
-		zrot(gaussian_rands(90,20)[0])
-		zrot_copies(n=floor(log_rands(2,5,4)[0]))
-		zrot(gaussian_rands(0,5)[0])
-		yrot(gaussian_rands(30,10)[0]) {
-			sc = gaussian_rands(0.7,0.05)[0];
-			cylinder(d1=s2, d2=s2*sc, l=s1)
-				branches(minsize, s1*sc, s2*sc);
-		}
-	} else {
-		recolor("springgreen")
-		attach(TOP) zrot(90)
-		leaf(gaussian_rands(100,5)[0]);
-	}
-}
-
-module tree(h, d, minsize) {
-	sc = gaussian_rands(0.7,0.05)[0];
-	recolor("lightgray") {
-		cylinder(d1=d, d2=d*sc, l=h) {
-			branches(minsize, h, d*sc);
-		}
-	}
-}
-
-tree(d=300, h=1500, minsize=10);
+			if (depth>0)
+				zrot(90)
+				zrot_copies(n=2)
+				yrot(30) tree(depth=depth-1, l=l*sc, sc=sc);
+			else
+				recolor("springgreen")
+				yscale(0.67)
+				teardrop(d=l*3, l=1, anchor=BOT, spin=90);
+tree();
 
 
 // vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/examples/randomized_fractal_tree.scad b/examples/randomized_fractal_tree.scad
new file mode 100644
index 0000000..0cb34c2
--- /dev/null
+++ b/examples/randomized_fractal_tree.scad
@@ -0,0 +1,48 @@
+include <BOSL2/std.scad>
+include <BOSL2/paths.scad>
+include <BOSL2/beziers.scad>
+
+module leaf(s) {
+	path = [
+		[0,0], [1.5,-1],
+		[2,1], [0,3], [-2,1],
+		[-1.5,-1], [0,0]
+	];
+	xrot(90)
+	linear_sweep_bezier(
+		scale_points(path, [s,s]/2),
+		height=0.02
+	);
+}
+
+module branches(minsize, s1, s2){
+    if(s2>minsize) {
+		attach(TOP)
+		zrot(gaussian_rands(90,20)[0])
+		zrot_copies(n=floor(log_rands(2,5,4)[0]))
+		zrot(gaussian_rands(0,5)[0])
+		yrot(gaussian_rands(30,10)[0]) {
+			sc = gaussian_rands(0.7,0.05)[0];
+			cylinder(d1=s2, d2=s2*sc, l=s1)
+				branches(minsize, s1*sc, s2*sc);
+		}
+	} else {
+		recolor("springgreen")
+		attach(TOP) zrot(90)
+		leaf(gaussian_rands(100,5)[0]);
+	}
+}
+
+module tree(h, d, minsize) {
+	sc = gaussian_rands(0.7,0.05)[0];
+	recolor("lightgray") {
+		cylinder(d1=d, d2=d*sc, l=h) {
+			branches(minsize, h, d*sc);
+		}
+	}
+}
+
+tree(d=300, h=1500, minsize=10);
+
+
+// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
diff --git a/tutorials/Fractal_Tree.md b/tutorials/Fractal_Tree.md
new file mode 100644
index 0000000..095f6d6
--- /dev/null
+++ b/tutorials/Fractal_Tree.md
@@ -0,0 +1,139 @@
+# Fractal Tree Tutorial
+
+### Start with a Tree Trunk
+
+Firstoff, include the BOSL2 library, then add a tapered cylinder for the tree trunk.
+
+```openscad-example
+include <BOSL2/std.scad>
+cylinder(l=1500, d1=300, d2=210);
+```
+
+### Parameterize It
+
+It's easier to adjust a model if you split out the defining parameters.
+
+```openscad-example
+include <BOSL2/std.scad>
+l = 1500;
+sc = 0.7;
+cylinder(l=l, d1=l/5, d2=l/5*sc);
+```
+
+### Attaching Branches
+
+You can attach branches to the top of the trunk by using `attach()` as a child of the trunk cylinder.
+
+```openscad-example
+include <BOSL2/std.scad>
+l = 1500;
+sc = 0.7;
+cylinder(l=l, d1=l/5, d2=l/5*sc) {
+    attach(TOP) yrot( 30) cylinder(l=l*sc, d1=l/5*sc, d2=l/5*sc*sc);
+    attach(TOP) yrot(-30) cylinder(l=l*sc, d1=l/5*sc, d2=l/5*sc*sc);
+}
+```
+
+### Replicate Branches
+
+Instead of attaching each branch individually, you can attach multiple branch copies at once.
+
+```openscad-example
+include <BOSL2/std.scad>
+l = 1500;
+sc = 0.7;
+cylinder(l=l, d1=l/5, d2=l/5*sc)
+    attach(TOP)
+        zrot_copies(n=2)  // Make multiple rotated copies
+        yrot(30) cylinder(l=l*sc, d1=l/5*sc, d2=l/5*sc*sc);
+```
+
+### Make it a Module
+
+Lets make this into a module, for convenience.
+
+```openscad-example
+include <BOSL2/std.scad>
+module tree(l=1500, sc=0.7)
+    cylinder(l=l, d1=l/5, d2=l/5*sc)
+        attach(TOP)
+            zrot_copies(n=2)
+            yrot(30) cylinder(l=l*sc, d1=l/5*sc, d2=l/5*sc*sc);
+tree();
+```
+
+### Use Recursion
+
+Since branches look much like the main trunk, we can make it recursive. Don't forget the termination clause, or else it'll try to recurse forever!
+
+```openscad-example
+include <BOSL2/std.scad>
+module tree(l=1500, sc=0.7, depth=10)
+    cylinder(l=l, d1=l/5, d2=l/5*sc)
+        attach(TOP)
+            if (depth>0)  // Important!
+                zrot_copies(n=2)
+                yrot(30) tree(depth=depth-1, l=l*sc, sc=sc);
+tree();
+```
+
+### Make it Not Flat
+
+A flat planar tree isn't what we want, so lets bush it out a bit by rotating each level 90 degrees.
+
+```openscad-example
+include <BOSL2/std.scad>
+module tree(l=1500, sc=0.7, depth=10)
+    cylinder(l=l, d1=l/5, d2=l/5*sc)
+        attach(TOP)
+            if (depth>0)
+                zrot(90)  // Bush it out
+                zrot_copies(n=2)
+                yrot(30) tree(depth=depth-1, l=l*sc, sc=sc);
+tree();
+```
+
+### Adding Leaves
+
+Let's add leaves. They look much like squashed versions of the standard teardrop() module, so lets use that.
+
+```openscad-example
+include <BOSL2/std.scad>
+module tree(l=1500, sc=0.7, depth=10)
+    cylinder(l=l, d1=l/5, d2=l/5*sc)
+        attach(TOP)
+            if (depth>0)
+                zrot(90)
+                zrot_copies(n=2)
+                yrot(30) tree(depth=depth-1, l=l*sc, sc=sc);
+            else
+                yscale(0.67)
+                teardrop(d=l*3, l=1, anchor=BOT, spin=90);
+tree();
+```
+
+### Adding Color
+
+We can finish this off with some color. The `color()` module will force all it's children and
+their descendants to the new color, even if they were colored before. The `recolor()` module,
+however, will only color children and decendants that don't already have a color set by a more
+nested `recolor()`.
+
+```openscad-example
+include <BOSL2/std.scad>
+module tree(l=1500, sc=0.7, depth=10)
+    recolor("lightgray")
+    cylinder(l=l, d1=l/5, d2=l/5*sc)
+        attach(TOP)
+            if (depth>0)
+                zrot(90)
+                zrot_copies(n=2)
+                yrot(30)
+                tree(depth=depth-1, l=l*sc, sc=sc);
+            else
+                recolor("springgreen")
+                yscale(0.67)
+                teardrop(d=l*3, l=1, anchor=BOT, spin=90);
+tree();
+```
+
diff --git a/version.scad b/version.scad
index 73cabf9..8cdf21c 100644
--- a/version.scad
+++ b/version.scad
@@ -8,7 +8,7 @@
 //////////////////////////////////////////////////////////////////////
 
 
-BOSL_VERSION = [2,0,212];
+BOSL_VERSION = [2,0,213];
 
 
 // Section: BOSL Library Version Functions