Fractal-like triangles process
The Processing sketch generates fractal shapes using a triangle and recursion. The main function is `iterate` which generates a new triangle based on a given triangle and calls itself for two new triangles (left and right). This is repeated until a certain condition is met (the length of the triangle’s side is smaller than 20). The final result is stored in an ArrayList of Triangles.
Start variables: l – length of the first triangle; startPoint – starting point for the first triangle
// ––––––––––––––––––––––––––––––––––––––––––––––––––––––––
// A Processing sketch that generates fractal-like triangles.
//
// C
// / \
// / \
// / \
// / \
// B /---------\A
//
// Andreas Pirchner, 2020
// ––––––––––––––––––––––––––––––––––––––––––––––––––––––––
import processing.svg.*; // import the library for SVG output
import processing.pdf.*; // import the library for PDF output
ArrayList triangles; // Create an ArrayList to store the triangles
float l = 150; // length of the first triangle
int g = 1; // variable to hold the generations of iterations
int id = Math.round(random(10000)); // random ID for the PDF export
PVector startPoint; // Create a PVector to store the starting point
// The setup function is called once when the sketch starts
void setup(){
size(1000,1000); // set the size of the window
background(255); // set the background color to white
noFill(); // do not fill the shapes
triangles = new ArrayList(); // initialize the triangles ArrayList
//beginRecord(PDF, "export"+id+"layer-1.pdf"); // start recording the export PDF
startPoint = new PVector(width/2, height/2); // set the starting point to the center of the window
translate(startPoint.x, startPoint.y); // Translate to the starting point
line(-l,0,l,0); // draw the first hypotenuse
iterate(l,g, 0, startPoint, 0); // call the iterate function to start generating triangles
rotate(PI); // rotate the entire sketch by 180 degrees
iterate(l,g, 0, startPoint, 0); // call the iterate function again to generate more triangles
println(triangles.size()); // print the number of triangles generated
}
void draw(){
}
void iterate(float _l, int _g, float _angle, PVector _absolutePos, float _absoluteAngle){
float angle = -random(PI/16, PI*15/16);
//float angle = _angle;
//float angle = -PI/4; //random(PI); // The Angle for this iteration
// (how are the side lengths of this right angled triangle)
PVector _m = new PVector(0, 0); // Make Vektors for this iteration
PVector _a = new PVector(_l, 0);
PVector _b = new PVector(-_l, 0);
PVector _c = new PVector(_m.x + _l*cos(angle), _m.y + _l * sin(angle));
paint(_m, _a, _b, _c, _l);
PVector mAC = PVector.lerp(_a, _c, 0.5); // middle of side AC
PVector mBC = PVector.lerp(_b, _c, 0.5); // middle of side BC
float one = PI- PI/2 - angle/2; // calculate rotations of children triangles
float three = PI/2 - one;
float nextRotationLeft = three; // left child trianlge (hypotenuse: BC)
float nextRotationRight = (PI - PI/2 - (-angle/2)); // right child trianlge (hypotenuse: AC)
float _lBC = PVector.dist(_b, _c)/2; // length for left child
float _lAC = PVector.dist(_a, _c)/2; // length for right child
PVector nextAbsolutePos1 = PVector.add(_absolutePos, mBC); //mBC.rotate(nextRotationLeft)); // absolute pos of m of left child
PVector nextAbsolutePos2 = PVector.add(_absolutePos, mAC); //mAC.rotate(nextRotationRight)); // absolute pos of m of right child
float nextAbsoluteAngle1 = _absoluteAngle + nextRotationLeft; // absolute angle of left child
float nextAbsoluteAngle2 = _absoluteAngle + nextRotationRight;// absolute angle of right child
_g ++;
if (_lBC > 20){
//float nextAngle1 = -random(PI/16, PI*15/16);
float nextAngle1 = -PI/2;
triangles.add(new Triangle(nextAbsolutePos1, _lBC, nextRotationLeft, nextAngle1, _g, nextAbsoluteAngle1));
push();
translate(mBC.x, mBC.y);
rotate(nextRotationLeft);
iterate(_lBC, _g, nextAngle1, nextAbsolutePos1, nextAbsoluteAngle1);
pop();
}
if (_lAC > 20){
//float nextAngle2 = -random(PI/16, PI*15/16);
float nextAngle2 = -PI/2;
triangles.add(new Triangle(nextAbsolutePos2, _lAC, nextRotationRight, nextAngle2, _g, nextAbsoluteAngle2));
push();
translate(mAC.x, mAC.y);
rotate(nextRotationRight);
iterate(_lAC, _g, nextAngle2, nextAbsolutePos2, nextAbsoluteAngle2);
pop();
}
}
// Function to draw the triangle with given parameters
void paint(PVector _m, PVector _a, PVector _b, PVector _c, float _l) {
// Set the color and opacity for drawing the circles
stroke(100, 0, 0, 80); // Red color with 80% opacity
// Don't fill the circles with any color
noFill();
// Set the stroke weight (thickness) of the circles
strokeWeight(1);
// Draw the first circle with the given parameters
// The circle will have the same x and y position as _m and the diameter will be 2 times _l
ellipse(_m.x, _m.y, _l * 2, _l * 2);
// Set the color and opacity for the remaining circles
stroke(0); // Black color
// Draw the second circle with the same x and y position as _m
// The diameter of the circle is 5 pixels
ellipse(_m.x, _m.y, 5, 5);
// Draw the third circle with the given parameters
// The x and y position of the circle is _c and the diameter is 5 pixels
ellipse(_c.x, _c.y, 5, 5);
// Don't fill the triangle
noFill();
// Draw the first line from _a to _c
line(_a.x, _a.y, _c.x, _c.y);
// Draw the second line from _b to _c
line(_b.x, _b.y, _c.x, _c.y);
}
void keyPressed() {
// Check if the 'n' key is pressed
if (key == 'n') {
// Clear the background color to white
background(255);
// Clear the array of triangles
triangles.clear();
// Set the length of the first triangle
l = 150;
// Generate a random ID for the PDF export
int id = Math.round(random(10000));
// Start recording the first layer of the PDF export
beginRecord(SVG, "export" + id + "layer-1.svg");
// Translate the origin point to the center of the screen
translate(width / 2, height / 2);
// Rotate the screen by a random angle
rotate(random(TWO_PI));
// Draw the first hypotenuse with the given length
line(-l, 0, l, 0);
// Call the iterate function
iterate(l, g, 0, startPoint, 0);
// Rotate the screen by 180 degrees
rotate(PI);
// Call the iterate function again
iterate(l, g, 0, startPoint, 0);
// End recording the first layer of the PDF export
endRecord();
}
// Check if the 'p' key is pressed
if (key == 'p') {
// Clear the background color to white
background(255);
// Loop through the array of triangles
for (int i = 0; i < triangles.size(); i++) {
// Get the current triangle from the array
Triangle t = triangles.get(i);
// Call the paint function for the current triangle
t.paint();
}
//endRecord();
}
}
// ––––––––––––––––––––––––––––––––––––––––––––––––––––––––
// Andreas Pirchner, 2021
// ––––––––––––––––––––––––––––––––––––––––––––––––––––––––
class Triangle{
// Three points defining the triangle
PVector absolutePos, a, b, c;
// Length of the base side of the triangle
float l;
// Rotation of the triangle
float r;
// Angle of the triangle
float angle;
// Absolute angle of the triangle
float absoluteAngle;
// Generation of the triangle
int generation;
// Constructor of the Triangle class
Triangle (PVector _absolutePos, float _l, float _rotation, float _thisAlpha, int _generation, float _absoluteAngle) {
// Initialize the absolute position of the triangle
absolutePos = _absolutePos;
// Initialize the length of the base side of the triangle
l = _l;
// Initialize the rotation of the triangle
r = _rotation;
// Initialize the angle of the triangle
angle = _thisAlpha;
// Initialize the generation of the triangle
generation = _generation;
// Initialize the absolute angle of the triangle
absoluteAngle = _absoluteAngle;
// Calculate the three points defining the triangle
a = new PVector(l, 0);
b = new PVector(-l, 0);
c = new PVector( + l*cos(angle), + l * sin(angle));
}
// Function to paint the triangle on the screen
void paint(){
// store the current matrix position
push();
// Translate the triangle to its absolute position
translate(absolutePos.x, absolutePos.y);
// Rotate the triangle based on its absolute angle
rotate(absoluteAngle);
// Debugging information
println(absoluteAngle);
// Fill the center of the triangle with red color
fill(255,0,0);
ellipse(0, 0, 5,5);
// Fill point C of the triangle with green color
fill(0,255,0);
ellipse(c.x,c.y,5,5);
// Show the generation number of the triangle
text(generation,0,0);
// Draw the three sides of the triangle
line(a.x, a.y, c.x, c.y);
line(b.x, b.y, c.x, c.y);
// Restore the previous matrix position
pop();
}
}