Chapter 8. Fractals

“Pathological monsters! cried the terrified mathematician

Every one of them a splinter in my eye

I hate the Peano Space and the Koch Curve

I fear the Cantor Ternary Set

The Sierpinski Gasket makes me wanna cry

And a million miles away a butterfly flapped its wings

On a cold November day a man named Benoit Mandelbrot was born”

— Jonathan Coulton, lyrics from “Mandelbrot Set”

Once upon a time, I took a course in high school called “Geometry.” Perhaps you did too. You learned about shapes in one dimension, two dimensions, and maybe even three. What is the circumference of a circle? The area of a rectangle? The distance between a point and a line? Come to think of it, we’ve been studying geometry all along in this book, using vectors to describe the motion of bodies in Cartesian space. This sort of geometry is generally referred to as Euclidean geometry, after the Greek mathematician Euclid.

For us nature coders, we have to ask the question: Can we describe our world with Euclidean geometry? The LCD screen I’m staring at right now sure looks like a rectangle. And the plum I ate this morning is circular. But what if I were to look further, and consider the trees that line the street, the leaves that hang off those trees, the lightning from last night’s thunderstorm, the cauliflower I ate for dinner, the blood vessels in my body, and the mountains and coastlines that cover land beyond New York City? Most of the stuff you find in nature cannot be described by the idealized geometrical forms of Euclidean geometry. So if we want to start building computational designs with patterns beyond the simple shapes ellipse(), rect(), and line(), it’s time for us to learn about the concepts behind and techniques for simulating the geometry of nature: fractals.

8.1 What Is a Fractal? The term fractal (from the Latin fractus, meaning “broken”) was coined by the mathematician Benoit Mandelbrot in 1975. In his seminal work “The Fractal Geometry of Nature,” he defines a fractal as “a rough or fragmented geometric shape that can be split into parts, each of which is (at least approximately) a reduced-size copy of the whole.” Let’s illustrate this definition with two simple examples. First, let’s think about a tree branching structure (for which we’ll write the code later): Notice how the tree in Figure 8.3 has a single root with two branches connected at its end. Each one of those branches has two branches at its end and those branches have two branches and so on and so forth. What if we were to pluck one branch from the tree and examine it on its own? Looking closely at a given section of the tree, we find that the shape of this branch resembles the tree itself. This is known as self-similarity; as Mandelbrot stated, each part is a “reduced-size copy of the whole.” The above tree is perfectly symmetrical and the parts are, in fact, exact replicas of the whole. However, fractals do not have to be perfectly self-similar. Let’s take a look at a graph of the stock market (adapted from actual Apple stock data). And one more. In these graphs, the x-axis is time and the y-axis is the stock’s value. It’s not an accident that I omitted the labels, however. Graphs of stock market data are examples of fractals because they look the same at any scale. Are these graphs of the stock over one year? One day? One hour? There’s no way for you to know without a label. (Incidentally, graph A shows six months’ worth of data and graph B zooms into a tiny part of graph A, showing six hours.) This is an example of a stochastic fractal, meaning that it is built out of probabilities and randomness. Unlike the deterministic tree-branching structure, it is statistically self-similar. As we go through the examples in this chapter, we will look at both deterministic and stochastic techniques for generating fractal patterns. While self-similarity is a key trait of fractals, it’s important to realize that self-similarity alone does not make a fractal. After all, a line is self-similar. A line looks the same at any scale, and can be thought of as comprising lots of little lines. But it’s not a fractal. Fractals are characterized by having a fine structure at small scales (keep zooming into the stock market graph and you’ll continue to find fluctuations) and cannot be described with Euclidean geometry. If you can say “It’s a line!” then it’s not a fractal. Another fundamental component of fractal geometry is recursion. Fractals all have a recursive definition. We’ll start with recursion before developing techniques and code examples for building fractal patterns in Processing.

8.2 Recursion Let’s begin our discussion of recursion by examining the first appearance of fractals in modern mathematics. In 1883, German mathematician George Cantor developed simple rules to generate an infinite set: There is a feedback loop at work here. Take a single line and break it into two. Then return to those two lines and apply the same rule, breaking each line into two, and now we’re left with four. Then return to those four lines and apply the rule. Now you’ve got eight. This process is known as recursion: the repeated application of a rule to successive results. Cantor was interested in what happens when you apply these rules an infinite number of times. We, however, are working in a finite pixel space and can mostly ignore the questions and paradoxes that arise from infinite recursion. We will instead construct our code in such a way that we do not apply the rules forever (which would cause our program to freeze). Before we implement the Cantor set, let’s take a look at what it means to have recursion in code. Here’s something we’re used to doing all the time—calling a function inside another function. Show Raw void someFunction() { // Calling the function background() // in the definition of someFunction() background(0); } What would happen if we called the function we are defining within the function itself? Can someFunction() call someFunction()? Show Raw void someFunction() { someFunction(); } In fact, this is not only allowed, but it’s quite common (and essential to how we will implement the Cantor set). Functions that call themselves are recursive and good for solving certain problems. For example, certain mathematical calculations are implemented recursively; the most common example is factorial. The factorial of any number n, usually written as n!, is defined as: n! = n * n – 1 * . . . . * 3 * 2 * 1

0! = 1 Here we’ll write a function in Processing that uses a for loop to calculate factorial: Show Raw int factorial(int n) { int f = 1; //[full] Using a regular loop to compute factorial for (int i = 0; i < n; i++) { f = f * (i+1); } //[end] return f; } Upon close examination, you’ll notice something interesting about how factorial works. Let’s look at 4! and 3! 4! = 4 * 3 * 2 * 1

3! = 3 * 2 * 1 therefore. . . 4! = 4 * 3! In more general terms, for any positive integer n: n! = n * (n-1)!

1! = 1 Written out: The factorial of n is defined as n times the factorial of n-1. The definition of factorial includes factorial?! It’s kind of like defining “tired" as “the feeling you get when you are tired.” This concept of self-reference in functions is an example of recursion. And we can use it to write a factorial function that calls itself. Show Raw int factorial(int n) { if (n == 1) { return 1; } else { return n * factorial(n-1); } } It may look crazy, but it works. Here are the steps that happen when factorial(4) is called. We can apply the same principle to graphics with interesting results, as we will see in many examples throughout this chapter. Take a look at this recursive function. Your browser does not support the canvas tag. RESET PAUSE Example 8.1: Recursive Circles I Show Raw void drawCircle(int x, int y, float radius) { ellipse(x, y, radius, radius); if(radius > 2) { radius *= 0.75f; // The drawCircle() function is // calling itself recursively. drawCircle(x, y, radius); } } drawCircle() draws an ellipse based on a set of parameters that it receives as arguments. It then calls itself with those same parameters, adjusting them slightly. The result is a series of circles, each of which is drawn inside the previous circle. Notice that the above function only recursively calls itself if the radius is greater than 2. This is a crucial point. As with iteration, all recursive functions must have an exit condition! You likely are already aware that all for and while loops must include a boolean expression that eventually evaluates to false, thus exiting the loop. Without one, the program would crash, caught inside of an infinite loop. The same can be said about recursion. If a recursive function calls itself forever and ever, you’ll be most likely be treated to a nice frozen screen. This circles example is rather trivial; it could easily be achieved through simple iteration. However, for scenarios in which a function calls itself more than once, recursion becomes wonderfully elegant. Let’s make drawCircle() a bit more complex. For every circle displayed, draw a circle half its size to the left and right of that circle. Your browser does not support the canvas tag. RESET PAUSE Example 8.2: Recursion twice Show Raw void setup() { size(640,360); } void draw() { background(255); drawCircle(width/2,height/2,200); } void drawCircle(float x, float y, float radius) { stroke(0); noFill(); ellipse(x, y, radius, radius); if(radius > 2) { //[full] drawCircle() calls itself twice, creating // a branching effect. For every circle, // a smaller circle is drawn to the left and the right. drawCircle(x + radius/2, y, radius/2); drawCircle(x - radius/2, y, radius/2); //[end] } } With just a little more code, we could also add a circle above and below each circle. Your browser does not support the canvas tag. RESET PAUSE Example 8.3: Recursion four times Show Raw void drawCircle(float x, float y, float radius) { ellipse(x, y, radius, radius); if(radius > 8) { drawCircle(x + radius/2, y, radius/2); drawCircle(x - radius/2, y, radius/2); drawCircle(x, y + radius/2, radius/2); drawCircle(x, y - radius/2, radius/2); } } Try reproducing this sketch with iteration instead of recursion—I dare you!

8.3 The Cantor Set with a Recursive Function Now we’re ready to visualize the Cantor set in Processing using a recursive function. Where do we begin? Well, we know that the Cantor set begins with a line. So let’s start there and write a function that draws a line. Show Raw void cantor(float x, float y, float len) { line(x,y,x+len,y); } The above cantor() function draws a line that starts at pixel coordinate (x,y) with a length of len. (The line is drawn horizontally here, but this is an arbitrary decision.) So if we called that function, saying: Show Raw cantor(10, 20, width-20); we’d get the following: Now, the Cantor rule tells us to erase the middle third of that line, which leaves us with two lines, one from the beginning of the line to the one-third mark, and one from the two-thirds mark to the end of the line. We can now add two more lines of code to draw the second pair of lines, moving the y-location down a bunch of pixels so that we can see the result below the original line. Show Raw void cantor(float x, float y, float len) { line(x,y,x+len,y); y += 20; // From start to 1/3rd line(x,y,x+len/3,y); //[bold] // From 2/3rd to end line(x+len*2/3,y,x+len,y); //[bold] } While this is a fine start, such a manual approach of calling line() for each line is not what we want. It will get unwieldy very quickly, as we’d need four, then eight, then sixteen calls to line(). Yes, a for loop is our usual way around such a problem, but give that a try and you’ll see that working out the math for each iteration quickly proves inordinately complicated. Here is where recursion comes and rescues us. Take a look at where we draw that first line from the start to the one-third mark. Show Raw line(x,y,x+len/3,y); Instead of calling the line() function directly, we can simply call the cantor() function itself. After all, what does the cantor() function do? It draws a line at an (x,y) location with a given length! And so: Show Raw line(x,y,x+len/3,y); becomes -------> cantor(x,y,len/3); And for the second line: Show Raw line(x+len*2/3,y,x+len,y); becomes -------> cantor(x+len*2/3,y,len/3); Leaving us with: Show Raw void cantor(float x, float y, float len) { line(x,y,x+len,y); y += 20; cantor(x,y,len/3); cantor(x+len*2/3,y,len/3); } And since the cantor() function is called recursively, the same rule will be applied to the next lines and to the next and to the next as cantor() calls itself again and again! Now, don’t go and run this code yet. We’re missing that crucial element: an exit condition. We’ll want to make sure we stop at some point—for example, if the length of the line ever is less than 1 pixel. Your browser does not support the canvas tag. RESET PAUSE Example 8.4: Cantor set Show Raw void cantor(float x, float y, float len) { // Stop at 1 pixel! if (len >= 1) { line(x,y,x+len,y); y += 20; cantor(x,y,len/3); cantor(x+len*2/3,y,len/3); } } Exercise 8.1 Using drawCircle() and the Cantor set as models, generate your own pattern with recursion. Here is a screenshot of one that uses lines.

8.4 The Koch Curve and the ArrayList Technique Writing a function that recursively calls itself is one technique for generating a fractal pattern on screen. However, what if you wanted the lines in the above Cantor set to exist as individual objects that could be moved independently? The recursive function is simple and elegant, but it does not allow you to do much besides simply generating the pattern itself. However, there is another way we can apply recursion in combination with an ArrayList that will allow us to not only generate a fractal pattern, but keep track of all its individual parts as objects. To demonstrate this technique, let’s look at another famous fractal pattern, discovered in 1904 by Swedish mathematician Helge von Koch. Here are the rules. (Note that it starts the same way as the Cantor set, with a single line.) The result looks like: The “Monster” Curve The Koch curve and other fractal patterns are often called “mathematical monsters.” This is due to an odd paradox that emerges when you apply the recursive definition an infinite number of times. If the length of the original starting line is one, the first iteration of the Koch curve will yield a line of length four-thirds (each segment is one-third the length of the starting line). Do it again and you get a length of sixteen-ninths. As you iterate towards infinity, the length of the Koch curve approaches infinity. Yet it fits in the tiny finite space provided right here on this paper (or screen)! Since we are working in the Processing land of finite pixels, this theoretical paradox won’t be a factor for us. We’ll have to limit the number of times we recursively apply the Koch rules so that our program won’t run out of memory or crash. We could proceed in the same manner as we did with the Cantor set, and write a recursive function that iteratively applies the Koch rules over and over. Nevertheless, we are going to tackle this problem in a different manner by treating each segment of the Koch curve as an individual object. This will open up some design possibilities. For example, if each segment is an object, we could allow each segment to move independently from its original location and participate in a physics simulation. In addition, we could use a random color, line thickness, etc. to display each segment differently. In order to accomplish our goal of treating each segment as an individual object, we must first decide what this object should be in the first place. What data should it store? What functions should it have? The Koch curve is a series of connected lines, and so we will think of each segment as a “KochLine.” Each KochLine object has a start point (“a”) and an end point (“b”). These points are PVector objects, and the line is drawn with Processing’s line() function. Show Raw class KochLine { //[full] A line between two points: start and end PVector start; PVector end; //[end] KochLine(PVector a, PVector b) { start = a.get(); end = b.get(); } void display() { stroke(0); // Draw the line from PVector start to end. line(start.x, start.y, end.x, end.y); } } Now that we have our KochLine class, we can get started on the main program. We’ll need a data structure to keep track of what will eventually become many KochLine objects, and an ArrayList (see Chapter 4 for a review of ArrayLists) will do just fine. Show Raw ArrayList lines; In setup(), we’ll want to create the ArrayList and add the first line segment to it, a line that stretches from 0 to the width of the sketch. Show Raw void setup() { size(600, 300); // Create the ArrayList. lines = new ArrayList (); // Left side of window PVector start = new PVector(0, 200); // Right side of window PVector end = new PVector(width, 200); // The first KochLine object lines.add(new KochLine(start, end)); } Then in draw(), all KochLine objects (just one right now) can be displayed in a loop. Show Raw void draw() { background(255); for (KochLine l : lines) { l.display(); } } This is our foundation. Let’s review what we have so far: KochLine class: A class to keep track of a line from point A to B.

ArrayList: A list of all KochLine objects. With the above elements, how and where do we apply Koch rules and principles of recursion? Remember the Game of Life cellular automata? In that simulation, we always kept track of two generations: current and next. When we were finished computing the next generation, next became current and we moved on to computing the new next generation. We are going to apply a similar technique here. We have an ArrayList that keeps track of the current set of KochLine objects (at the start of the program, there is only one). We will need a second ArrayList (let’s call it “next”) where we will place all the new KochLine objects that are generated from applying the Koch rules. For every KochLine object in the current ArrayList, four new KochLine objects are added to the next ArrayList. When we’re done, the next ArrayList becomes the current one. Here’s how the code will look: Show Raw void generate() { // Create the next ArrayList... ArrayList next = new ArrayList (); // ...for every current line. for (KochLine l : lines) { //[full] Add four new lines. (We need to figure out how // to compute the locations of these lines!) next.add(new KochLine(???,???)); next.add(new KochLine(???,???)); next.add(new KochLine(???,???)); next.add(new KochLine(???,???)); //[end] } // The new ArrayList is now the // one we care about! lines = next; } By calling generate() over and over again (for example, each time the mouse is pressed), we recursively apply the Koch curve rules to the existing set of KochLine objects. Of course, the above omits the real “work” here, which is figuring out those rules. How do we break one line segment into four as described by the rules? While this can be accomplished with some simple arithmetic and trigonometry, since our KochLine object uses PVector, this is a nice opportunity for us to practice our vector math. Let’s establish how many points we need to compute for each KochLine object. As you can see from the above figure, we need five points (a, b, c, d, and e) to generate the new KochLine objects and make the new line segments (ab, cb, cd, and de). Show Raw next.add(new KochLine(a,b)); next.add(new KochLine(b,c)); next.add(new KochLine(c,d)); next.add(new KochLine(d,e)); Where do we get these points? Since we have a KochLine object, why not ask the KochLine object to compute all these points for us? Show Raw void generate() { ArrayList next = new ArrayList (); for (KochLine l : lines) { //[full] The KochLine object has five functions, // each of which return a PVector according // to the Koch rules. PVector a = l.kochA(); PVector b = l.kochB(); PVector c = l.kochC(); PVector d = l.kochD(); PVector e = l.kochE(); //[end] next.add(new KochLine(a, b)); next.add(new KochLine(b, c)); next.add(new KochLine(c, d)); next.add(new KochLine(d, e)); } lines = next; } Now we just need to write five new functions in the KochLine class, each one returning a PVector according to Figure 8.16 above. Let’s knock off kochA() and kochE() first, which are simply the start and end points of the original line. Show Raw PVector kochA() { // Note the use of get(), which returns a copy of the PVector. As was noted in // Chapter 6, section 14, we want to avoid making copies whenever // possible, but here we will need a new PVector in case we want the segments to move // independently of each other. return start.get(); } PVector kochE() { return end.get(); } Now let’s move on to points B and D. B is one-third of the way along the line segment and D is two-thirds. Here we can make a PVector that points from start to end and shrink it to one-third the length for B and two-thirds the length for D to find these points. Show Raw PVector kochB() { // PVector from start to end PVector v = PVector.sub(end, start); // One-third the length v.div(3); // Add that PVector to the beginning of the line // to find the new point. v.add(start); return v; } PVector kochD() { PVector v = PVector.sub(end, start); // Same thing here, only we need to move two-thirds // along the line instead of one-third. v.mult(2/3.0); v.add(start); return v; } The last point, C, is the most difficult one to find. However, if you recall that the angles of an equilateral triangle are all sixty degrees, this makes it a little bit easier. If we know how to find point B with a PVector one-third the length of the line, what if we were to rotate that same PVector sixty degrees and move along that vector from point B? We’d be at point C! Show Raw PVector kochC() { // Start at the beginning. PVector a = start.get(); PVector v = PVector.sub(end, start); // Move 1/3rd of the way to point B. v.div(3); a.add(v); // Rotate “above” the line 60 degrees. v.rotate(-radians(60)); // Move along that vector to point C. a.add(v); return a; } Putting it all together, if we call generate() five times in setup(), we’ll see the following result. Your browser does not support the canvas tag. RESET PAUSE Example 8.5: Koch curve Show Raw ArrayList lines; void setup() { size(600, 300); background(255); lines = new ArrayList (); PVector start = new PVector(0, 200); PVector end = new PVector(width, 200); lines.add(new KochLine(start, end)); // Arbitrarily apply the Koch rules five times. for (int i = 0; i < 5; i++) { generate(); } } Exercise 8.2 Draw the Koch snowflake (or some other variation of the Koch curve). Exercise 8.3 Try animating the Koch curve. For example, can you draw it from left to right? Can you vary the visual design of the line segments? Can you move the line segments using techniques from earlier chapters? What if each line segment were made into a spring (toxiclibs) or joint (Box2D)? Exercise 8.4 Rewrite the Cantor set example using objects and an ArrayList. Exercise 8.5 Draw the Sierpiński triangle (as seen in Wolfram elementary CA) using recursion.

8.5 Trees The fractals we have examined in this chapter so far are deterministic, meaning they have no randomness and will always produce the identical outcome each time they are run. They are excellent demonstrations of classic fractals and the programming techniques behind drawing them, but are too precise to feel natural. In this next part of the chapter, I want to examine some techniques behind generating a stochastic (or non-deterministic) fractal. The example we’ll use is a branching tree. Let’s first walk through the steps to create a deterministic version. Here are our production rules: Again, we have a nice fractal with a recursive definition: A branch is a line with two branches connected to it. Your browser does not support the canvas tag. RESET PAUSE The part that is a bit more difficult than our previous fractals lies in the use of the word rotate in the fractal’s rules. Each new branch must rotate relative to the previous branch, which is rotated relative to all its previous branches. Luckily for us, Processing has a mechanism to keep track of rotations for us—the transformation matrix. If you aren’t familiar with the functions pushMatrix() and popMatrix(), I suggest you read the online Processing tutorial 2D Transformations, which will cover the concepts you’ll need for this particular example. Let’s begin by drawing a single branch, the trunk of the tree. Since we are going to involve the rotate() function, we’ll need to make sure we are continuously translating along the branches while we draw the tree. And since the root starts at the bottom of the window (see above), the first step requires translating to that spot: Show Raw translate(width/2,height); …followed by drawing a line upwards (Figure 8.20): Show Raw line(0,0,0,-100); Once we’ve finished the root, we just need to translate to the end and rotate in order to draw the next branch. (Eventually, we’re going to need to package up what we’re doing right now into a recursive function, but let’s sort out the steps first.) Remember, when we rotate in Processing, we are always rotating around the point of origin, so here the point of origin must always be translated to the end of our current branch. Show Raw translate(0,-100); rotate(PI/6); line(0,0,0,-100); Now that we have a branch going to the right, we need one going to the left. We can use pushMatrix() to save the transformation state before we rotate, letting us call popMatrix() to restore that state and draw the branch to the left. Let’s look at all the code together. Show Raw translate(width/2,height); // The root line(0,0,0,-100); translate(0,-100); pushMatrix(); rotate(PI/6); // Branch to the right line(0,0,0,-100); popMatrix(); rotate(-PI/6); // Branch to the left line(0,0,0,-100); If you think of each call to the function line() as a “branch,” you can see from the code above that we have implemented our definition of branching as a line that has two lines connected to its end. We could keep adding more and more calls to line() for more and more branches, but just as with the Cantor set and Koch curve, our code would become incredibly complicated and unwieldy. Instead, we can use the above logic as our foundation for writing a recursive function, replacing the direct calls to line() with our own function called branch(). Let’s take a look. Example 8.6: Recursive tree Show Raw void branch() { // Draw the branch itself. line(0, 0, 0, -100); // Translate to the end. translate(0, -100); pushMatrix(); // Rotate to the right and branch again. rotate(PI/6); branch(); popMatrix(); pushMatrix(); // Rotate to the left and branch again. rotate(-PI/6); branch(); popMatrix(); } Notice how in the above code we use pushMatrix() and popMatrix() around each subsequent call to branch(). This is one of those elegant code solutions that feels almost like magic. Each call to branch() takes a moment to remember the location of that particular branch. If you turn yourself into Processing for a moment and try to follow the recursive function with pencil and paper, you’ll notice that it draws all of the branches to the right first. When it gets to the end, popMatrix() will pop us back along all of the branches we’ve drawn and start sending branches out to the left. Exercise 8.6 Emulate the Processing code in Example 8.6 and number the branches in the above diagram in the order that Processing would actually draw each one. You may have noticed that the recursive function we just wrote would not actually draw the above tree. After all, it has no exit condition and would get stuck in infinite recursive calls to itself. You’ll also probably notice that the branches of the tree get shorter at each level. Let’s look at how we can shrink the length of the lines as the tree is drawn, and stop branching once the lines have become too short. Show Raw // Each branch now receives // its length as an argument. void branch(float len) { line(0, 0, 0, -len); translate(0, -len); // Each branch’s length // shrinks by two-thirds. len *= 0.66; if (len > 2) { pushMatrix(); rotate(theta); // Subsequent calls to branch() // include the length argument. branch(len); popMatrix(); pushMatrix(); rotate(-theta); branch(len); popMatrix(); } } We’ve also included a variable for theta that allows us, when writing the rest of the code in setup() and draw(), to vary the branching angle according to, say, the mouseX location. Example 8.7: Recursive tree Show Raw float theta; void setup() { size(300, 200); } void draw() { background(255); // Pick an angle according to // the mouse location. theta = map(mouseX,0,width,0,PI/2); // The first branch starts at the // bottom of the window. translate(width/2, height); stroke(0); branch(60); } Exercise 8.7 Vary the strokeWeight() for each branch. Make the root thick and each subsequent branch thinner. Exercise 8.8 The tree structure can also be generated using the ArrayList technique demonstrated with the Koch curve. Recreate the tree using a Branch object and an ArrayList to keep track of the branches. Hint: you’ll want to keep track of the branch directions and lengths using vector math instead of Processing transformations. Exercise 8.9 Once you have the tree built with an ArrayList of Branch objects, animate the tree’s growth. Can you draw leaves at the end of the branches? The recursive tree fractal is a nice example of a scenario in which adding a little bit of randomness can make the tree look more natural. Take a look outside and you’ll notice that branch lengths and angles vary from branch to branch, not to mention the fact that branches don’t all have exactly the same number of smaller branches. First, let’s see what happens when we simply vary the angle and length. This is a pretty easy one, given that we can just ask Processing for a random number each time we draw the tree. Your browser does not support the canvas tag. RESET PAUSE Show Raw void branch(float len) { // Start by picking a random // angle for each branch. float theta = random(0,PI/3); line(0, 0, 0, -len); translate(0, -len); len *= 0.66; if (len > 2) { pushMatrix(); rotate(theta); branch(len); popMatrix(); pushMatrix(); rotate(-theta); branch(len); popMatrix(); } } In the above function, we always call branch() twice. But why not pick a random number of branches and call branch() that number of times? Your browser does not support the canvas tag. RESET PAUSE Example 8.8: Stochastic tree Show Raw void branch(float len) { line(0, 0, 0, -len); translate(0, -len); if (len > 2) { // Call branch() a random // number of times. int n = int(random(1,4)); for (int i = 0; i < n; i++) { // Each branch gets its own random angle. float theta = random(-PI/2, PI/2); pushMatrix(); rotate(theta); branch(h); popMatrix(); } } Exercise 8.10 Set the angles of the branches of the tree according to Perlin noise values. Adjust the noise values over time to animate the tree. See if you can get it to appear as if it is blowing in the wind. Exercise 8.11 Use toxiclibs to simulate tree physics. Each branch of the tree should be two particles connected with a spring. How can you get the tree to stand up and not fall down?