Koch
koch.pde
/**
* Koch Curve
* by Daniel Shiffman.
*
* Renders a simple fractal, the Koch snowflake.
* Each recursive level is drawn in sequence.
*/
// Koch Curve
// A class to describe one line segment in the fractal
// Includes methods to calculate midPVectors along the line according to the Koch algorithm
struct KochLine {
// Two PVectors,
// a is the "left" PVector and
// b is the "right" PVector
PVector a;
PVector b;
KochLine(PVector start, PVector end) {
a = start.copy();
b = end.copy();
}
void display() {
stroke(255);
line(a.x, a.y, b.x, b.y);
}
PVector start() {
return a.copy();
}
PVector end() {
return b.copy();
}
// This is easy, just 1/3 of the way
PVector kochleft() {
PVector v = PVector::sub(b, a);
v.div(3);
v.add(a);
return v;
}
// More complicated, have to use a little trig to figure out where this PVector is!
PVector kochmiddle() {
PVector v = PVector::sub(b, a);
v.div(3);
PVector p = a.copy();
p.add(v);
v.rotate(-radians(60));
p.add(v);
return p;
}
// Easy, just 2/3 of the way
PVector kochright() {
PVector v = PVector::sub(a, b);
v.div(3);
v.add(b);
return v;
}
};
// Koch Curve
// A class to manage the list of line segments in the snowflake pattern
struct KochFractal {
PVector start; // A PVector for the start
PVector end; // A PVector for the end
std::vector<KochLine> lines; // A list to keep track of all the lines
int count;
KochFractal() {
start = PVector(0, height - 20);
end = PVector(width, height - 20);
count = 0;
restart();
}
void nextLevel() {
// For every line that is in the vector
// create 4 more lines in a new vector
lines = iterate(lines);
count++;
}
void restart() {
count = 0; // Reset count
lines.clear(); // Empty the vector
lines.push_back(KochLine(start, end)); // Add the initial line
}
int getCount() {
return count;
}
// This is easy, just draw all the lines
void render() {
for (KochLine& l : lines) {
l.display();
}
}
// This is where the **MAGIC** happens
// Step 1: Create an empty vector
// Step 2: For every line currently in the vector
// - calculate 4 line segments based on Koch algorithm
// - add all 4 line segments into the new vector
// Step 3: Return the new vector 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. . .
std::vector<KochLine> iterate(std::vector<KochLine>& before) {
std::vector<KochLine> now; // Create empty list
for (KochLine& l : before) {
// Calculate 5 koch PVectors (done for us by the line object)
PVector a = l.start();
PVector b = l.kochleft();
PVector c = l.kochmiddle();
PVector d = l.kochright();
PVector e = l.end();
// Make line segments between all the PVectors and add them
now.push_back(KochLine(a, b));
now.push_back(KochLine(b, c));
now.push_back(KochLine(c, d));
now.push_back(KochLine(d, e));
}
return now;
}
};
KochFractal k;
void setup() {
size(640, 360);
frameRate(1); // Animate slowly
k = KochFractal();
}
void 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();
}
}