import java.util.*; import processing.video.*; Edge root; MovieMaker mm; boolean doVideo = false; void setup() { size(600, 800); fill(255); smooth(); noStroke(); spawn(); } void spawn() { if(doVideo) { try { new java.io.File("tree.mov").delete(); } catch (Exception e){} mm = new MovieMaker( this, width, height, "tree"+(millis())+".mov", 30, MovieMaker.JPEG, MovieMaker.LOSSLESS ); } root = new Edge( new Point(width/2, height-50), new Point( (int)random(-50,50) + (width/2), (int)((height*8/9)+random(-5,5))), 8.f + random(5), 5.f + random(2.5f) ); root.haveChildNodes(2, 4); } void mousePressed() { spawn(); } void keyPressed() { if(doVideo) mm.finish(); exit(); } void draw() { background(0); root.draw(); if(doVideo) mm.addFrame(); } public class Edge { int timeToGrow = 5000; Point start; Point end; Point growingEnd; Edge parent; float startRadius; float endRadius; ArrayList children; /** * Create a tree root */ Edge(Point start, Point end, float startRadius, float endRadius) { parent = null; this.start = start; this.end = end; this.startRadius = startRadius; this.endRadius = endRadius; children = null; } /** * Child edge (branch) */ Edge(Edge parent, Point end, float endRadius) { this.parent = parent; start = parent.end; startRadius = parent.endRadius; this.end = end; this.endRadius = endRadius; children = null; } void haveChildNodes(int number, int generations) { children = new ArrayList(); for(int i = 0; i < number; i++) { Point p = new Point(); p.x = (int)(end.x + ((end.x-start.x)*random(0.8, 1))); p.y = (int)(end.y + ((end.y-start.y)*random(-0.1, 2))); Edge child = new Edge( this, p, this.endRadius*0.6); if(generations>0) { child.haveChildNodes(number, generations - 1); } children.add(child); } } Edge [] childEdges() { if(children==null) { return null; } else { return (Edge []) children.toArray(); } } void drawPill(Point a, Point b, float radiusA, float radiusB) { ellipse(a.x, a.y, radiusA*2, radiusA*2); ellipse(b.x, b.y, radiusB*2, radiusB*2); float angle = atan2(b.y-a.y, b.x-a.x); float deltaX = radiusA*cos(angle + (PI/2)); float deltaY = radiusA*sin(angle + (PI/2)); beginShape(); vertex(a.x+deltaX, a.y+deltaY); vertex(a.x-deltaX, a.y-deltaY); deltaX = radiusB*cos(angle + (PI/2)); deltaY = radiusB*sin(angle + (PI/2)); vertex(b.x-deltaX, b.y-deltaY); vertex(b.x+deltaX, b.y+deltaY); endShape(CLOSE); } float pos = 0; int totalTime = (int)(30+random(30)); void draw() { pos += (totalTime - pos)/(totalTime); float time = pos/totalTime; if(time > 1.f) { time = 1.f; } growingEnd = new Point(); if(parent==null) { growingEnd.x = (int)(start.x + (end.x-start.x)*time); growingEnd.y = (int)(start.y + (end.y-start.y)*time); drawPill(start, growingEnd, startRadius*((0.5*time)+0.5), endRadius*time); } else { growingEnd.x = (int)(parent.growingEnd.x + (end.x-parent.growingEnd.x)*time); growingEnd.y = (int)(parent.growingEnd.y + (end.y-parent.growingEnd.y)*time); drawPill(parent.growingEnd, growingEnd, startRadius*((0.5*time)+0.5), endRadius*time); } if(children!=null && time>0.5f) { for(int i = 0; i < children.size(); i++) { Edge e = (Edge) children.get(i); e.draw(); } } } }