Code viewer for World: Koch Curve
/*https://editor.p5js.org/p5/sketches/Simulate:_Koch
 * @name Koch Curve
 * @description Renders a simple fractal, the Koch snowflake. Each recursive level is drawn in sequence.
 * By Daniel Shiffman
 */

let k;

function setup() {
  createCanvas(710, 400);
  frameRate(1);  // Animate slowly
  k = new KochFractal();
}

function draw() {
  background(0);
  // Draws the snowflake!
  k.render();
  // Iterate
  k.nextLevel();
  // Let's not do it more than 5 times. . .
  if (k.getCount() > 5) {
    k.restart();
  }
}

// A class to describe one line segment in the fractal
// Includes methods to calculate midp5.Vectors along the line according to the Koch algorithm

class KochLine {
  constructor(a,b) {
    // Two p5.Vectors,
    // start is the "left" p5.Vector and
    // end is the "right p5.Vector
    this.start = a.copy();
    this.end = b.copy();
  }

  display() {
    stroke(255);
    line(this.start.x, this.start.y, this.end.x, this.end.y);
  }

  kochA() {
    return this.start.copy();
  }

  // This is easy, just 1/3 of the way
  kochB() {
    let v = p5.Vector.sub(this.end, this.start);
    v.div(3);
    v.add(this.start);
    return v;
  }

  // More complicated, have to use a little trig to figure out where this p5.Vector is!
  kochC() {
    let a = this.start.copy(); // Start at the beginning
    let v = p5.Vector.sub(this.end, this.start);
    v.div(3);
    a.add(v);  // Move to point B
    v.rotate(-PI/3); // Rotate 60 degrees
    a.add(v);  // Move to point C
    return a;
  }

  // Easy, just 2/3 of the way
  kochD() {
    let v = p5.Vector.sub(this.end, this.start);
    v.mult(2/3.0);
    v.add(this.start);
    return v;
  }

  kochE() {
    return this.end.copy();
  }
}

// A class to manage the list of line segments in the snowflake pattern

class KochFractal {
  constructor() {
    this.start = createVector(0,height-20);   // A p5.Vector for the start
    this.end = createVector(width,height-20); // A p5.Vector for the end
    this.lines = [];                         // An array to keep track of all the lines
    this.count = 0;
    this.restart();
  }

  nextLevel() {
    // For every line that is in the arraylist
    // create 4 more lines in a new arraylist
    this.lines = this.iterate(this.lines);
    this.count++;
  }

  restart() {
    this.count = 0;      // Reset count
    this.lines = [];  // Empty the array list
    this.lines.push(new KochLine(this.start,this.end));  // Add the initial line (from one end p5.Vector to the other)
  }

  getCount() {
    return this.count;
  }

  // This is easy, just draw all the lines
  render() {
    for(let i = 0; i < this.lines.length; i++) {
      this.lines[i].display();
    }
  }

  // This is where the **MAGIC** happens
  // Step 1: Create an empty arraylist
  // Step 2: For every line currently in the arraylist
  //   - calculate 4 line segments based on Koch algorithm
  //   - add all 4 line segments into the new arraylist
  // Step 3: Return the new arraylist and it becomes the list of line segments for the structure

  // As we do this over and over again, each line gets broken into 4 lines, which gets broken into 4 lines, and so on. . .
  iterate(before) {
    let now = [];    // Create emtpy list
    for(let i = 0; i < this.lines.length; i++) {
      let l = this.lines[i];
      // Calculate 5 koch p5.Vectors (done for us by the line object)
      let a = l.kochA();
      let b = l.kochB();
      let c = l.kochC();
      let d = l.kochD();
      let e = l.kochE();
      // Make line segments between all the p5.Vectors and add them
      now.push(new KochLine(a,b));
      now.push(new KochLine(b,c));
      now.push(new KochLine(c,d));
      now.push(new KochLine(d,e));
    }
    return now;
  }
}