// Code by Antti Tiihonen, 2009 int pixelNum = 0; int pixelX[] = new int[1]; int pixelY[] = new int[1]; int mouseX2 = 0; int mouseY2 = 0; boolean simulationActive = false; int corners = 4; // Amount of corners in the construction float angle = TWO_PI / corners; // Figure out the increment of an angle float deviation = 0.01 * TWO_PI; float rotation = random(TWO_PI); // Rotate the whole thingy float drift = 0.0005 * TWO_PI; // How much can the angles drift between iterations float maxLength = 0; float minLength = 0; PVector randomPixelAPos, randomPixelBPos; void setup() { background(255); size(640, 640, P2D); frameRate(30); randomPixelAPos = new PVector(0, 0); randomPixelBPos = new PVector(0, 0); } void draw() { if(simulationActive == true) { spawnLine(); } } void spawnLine() { int randomPixelA = int(random(pixelNum)); // Pick a random pixel float direction = ceil(random(corners)) * angle + random(deviation) + rotation; // The direction of the new line rotation += random(-drift, drift); randomPixelAPos.x = pixelX[randomPixelA]; randomPixelAPos.y = pixelY[randomPixelA]; randomPixelBPos.set(0, 0, 0); randomPixelBPos.x += cos(direction); // Turn the destination to point towards chosen direction randomPixelBPos.y += sin(direction); randomPixelBPos.normalize(); randomPixelAPos.add(randomPixelBPos); // Add some distance to the first point to avoid early collision randomPixelAPos.add(randomPixelBPos); randomPixelAPos.add(randomPixelBPos); randomPixelBPos.mult(random(minLength, maxLength)); randomPixelBPos.add(randomPixelAPos); drawLine(int(randomPixelAPos.x), int(randomPixelAPos.y), int(randomPixelBPos.x), int(randomPixelBPos.y)); stroke(0); strokeWeight(1); line(int(randomPixelAPos.x), int(randomPixelAPos.y), pixelX[randomPixelA], pixelY[randomPixelA]); // Bridge the gap } void drawLine(int x1, int y1, int x2, int y2) { // Measure the length of the line float lineLength = dist(x1, y1, x2, y2); // Lerp between coords and store pixels. for(int i = 1; i < int(lineLength); i++) { float lerpPos = norm(i, 0, lineLength); float x = lerp(x1, x2, lerpPos); float y = lerp(y1, y2, lerpPos); // If a solid line is encountered, give up! int r = ((get(int(x), int(y))) >> 16) & 0xFF; if(r < 2) { i = int(lineLength); x2 = int(lerp(x1, x2, lerpPos)); y2 = int(lerp(y1, y2, lerpPos)); } fillPixel(int(x), int(y)); } // Draw main line stroke(0); strokeWeight(1); line(x1, y1, x2, y2); // Draw the shading line stroke(0, 0, 60, 22); float shadingWeight = min(sq(lineLength * 0.03), 4); strokeWeight(shadingWeight); line(x1, y1 + shadingWeight * 0.7, x2, y2 + shadingWeight * 0.7); } void fillPixel(int xPos, int yPos) { // Increase the size of arrays if needed if(pixelNum >= pixelX.length) { pixelX = expand(pixelX); pixelY = expand(pixelY); } pixelX[pixelNum] = xPos; pixelY[pixelNum] = yPos; pixelNum++; } void mousePressed() { mouseX2 = mouseX; mouseY2 = mouseY; } void mouseReleased() { drawLine(mouseX2, mouseY2, mouseX, mouseY); maxLength = dist(mouseX2, mouseY2, mouseX, mouseY) * 1.5; minLength = maxLength * 0.05; simulationActive = true; } void keyPressed() { if(key == 'r' || key == 'R') { reset(); simulationActive = false; } if(key == 'p' || key == 'P') { if(simulationActive == false) { simulationActive = true; } else { simulationActive = false; } } if(key == 'a' || key == 'A') { if(corners == 3) { corners = 4; } else if(corners == 4) { corners = 8; } else if(corners == 8) { corners = 3; } angle = TWO_PI / corners; reset(); simulationActive = false; } } void reset() { pixelNum = 0; pixelX = expand(pixelX, 1); pixelY = expand(pixelY, 1); simulationActive = false; background(255); randomPixelAPos.set(0, 0, 0); randomPixelBPos.set(0, 0, 0); rotation = random(TWO_PI); }