/* The LSystem class contains all of the algorithms necessary to create, iterate, and draw Fractal L-Systems. The theory behind an L-System is based upon a simple grammar that tells the system how to draw itself. The grammar is made up of 5 characters: F : draw a line forward by a define length + : rotate in the positive direction by a defined angle - : rotate in the negative direction by a defined angle [ : store our current position ] : retrieve the previous position Each L-System will start with an Axiom and a Rule, the Axiom is the starting condition (typically just "F"), and the Rule is a substitution applied at each step. A simple rule might be: "F[+F--F]+F" For each iteration of the fractal, every occurance of the letter "F" is replaced with the Rule. So when we begin, the Fractal is defined by it's axiom: 1: F At the second iteration we apply the rule: 2: F[+F--F]+F At the third iteration we apply the rule again, replacing every occurance of F with the rule: 3: F[+F--F]+F[+F[+F--F]+F--F[+F--F]+F]+F[+F--F]+F We can repeat this pattern as often as desired. At each iteration we shorten the length of the line segment drawn by any occurance of F. */ public class LSystem { private String axiom; private String rule; private String production; private float startLength; private float drawLength; private float theta; private int generations; public LSystem() { // create default values axiom = "F"; rule = "F+F--F+F"; startLength = 40.0f; theta = radians(60.0); reset(); } public LSystem(String axiom_, String rule_) { // save the values axiom = axiom_; rule = rule_; startLength = 80.0f; theta = radians(60.0); reset(); } public void useRule(String r_) { rule = r_; } public void useAxiom(String a_) { axiom = a_; } public void useLength(float l_) { startLength = l_; } public void useTheta(float t_) { theta = radians(t_); } public void reset() { production = axiom; drawLength = startLength; generations = 0; } public int getAge() { return generations; } /* We need to create a simple drawing system that walks through our production (the current state of our LSystem) and follows the rules provided to draw the system. */ public void render() { // start at the bottom center of the screen translate(width / 2, height); for (int i = 0; i < production.length(); i++) { char step = production.charAt(i); if (step == 'F') { // draw a line line(0, 0, 0, -drawLength); // move to the end of the line translate(0, -drawLength); } else if (step == '+') { // rotate rotate(theta); } else if (step == '-') { // rotate rotate(-theta); } else if (step == '[') { // save our position pushMatrix(); } else if (step == ']') { // reset our position popMatrix(); } } } /* Our basic simulate method is a little different, it will age our LSystem by one generation, leaving the rendering part for us to call later */ public void simulate() { production = iterate(production, rule); } /* For conveinience we have a second simulate method that lets us specify what age we want to simulate our LSystem up too. */ public void simulate(int gen) { while (getAge() < gen) { production = iterate(production, rule); } } /* It is up to our iterate method to update the production (text) of the LSystem, as well as the drawLength and age */ private String iterate(String prod_, String rule_) { // update our drawing size drawLength = drawLength * 0.6; // update our generations generations++; // run the iteration String newProduction = prod_; newProduction = newProduction.replaceAll("F", rule_); return newProduction; } }