PVector center; Actor[] populus; void setup() { size(645, 500 ); // Draw Settings ellipseMode( CENTER ); strokeCap(ROUND); strokeWeight( .25 ); noFill(); smooth(); // Static inits. populus = new Actor[100]; center = new PVector( width/2, height/2, 0 ); Fire(); } void draw() { for( int i = 0; i < populus.length; ++i) { populus[i].Update(); } beginShape(LINES); { for( int i = 0; i < populus.length; ++i) { for( int j = i + 1; j < populus.length; ++j) populus[i].Pair(populus[j]); } } endShape(); } // (Re)Start the sequence void Fire() { background( 255, 255, 255 ); PVector hotspot = new PVector( random(0, width), random( 0, height)); PVector wind = PVector.sub( center, hotspot); wind.normalize(); float scalar = .5; float dim = height* scalar; for( int i = 0; i < populus.length; ++i) { PVector pos = new PVector( random( -1, 1), random( -1, 1 ), 0); pos.normalize(); pos.mult( random( dim * .5 ) ) ; pos.add( hotspot ); color col = GetPalette(); float rad = random( dim * .35); PVector vel = PVector.add( wind, new PVector( random( -1.2, 1.2), random( -1.2, 1.2 ), 0) ); vel.mult( scalar ); populus[i] = new Actor( pos, vel, col, rad ); } } // Get some set of colors that hopefully look nice color GetPalette() { // Replace with a way to pick colors from a predefined swatch float lum = random( 0.0, 1.5 ); PVector distribution = new PVector( random(0,1), random(0,1), random(0,1) ); distribution.normalize(); distribution.mult( lum ); return color( int(255 * distribution.x), int(255 * distribution.y), int(255 * distribution.z), 50 ); } // A generic circle that flies through the world linking with other circles. class Actor { PVector pos; PVector vel; PVector per; float rad; color col; float off; float life; Actor( PVector pos, PVector vel, color col, float rad ) { this.pos = pos; this.vel = vel; this.rad = rad; this.col = col; this.per = new PVector( vel.y, -vel.x ); this.off = random( 8000 ); this.life = 1.0; } void Update() { pos.add( vel ); pos.add( PVector.mult(per, .01 * rad * sin(off + millis() * .001)) ); } // Draw lines connecting Actors if they overlap. void Pair( Actor B ) { // Find intersections Actor A = this; float d = PVector.dist( A.pos, B.pos ); // Conecting Line PVector connect = PVector.sub( B.pos, A.pos ); connect.normalize(); // 2D perpendicular to connecting line PVector perp = new PVector( connect.y, -connect.x ); // Not separate if ( d > A.rad + B.rad ) return; // Not concentric if ( d == 0 ) return; // Not contained if ( d < abs( A.rad - B.rad ) ) return; // Dist from A Center to intersecting line float a = ( A.rad*A.rad - B.rad*B.rad + d*d ) / (2.0 * d ); // Bisector point PVector bisect = PVector.add( A.pos, PVector.mult( connect, a ) ); // Distance from bisector to intersections float h = sqrt( A.rad*A.rad - a*a ); PVector AI = PVector.add( bisect, PVector.mult( perp, h ) ); PVector BI = PVector.add( bisect, PVector.mult( perp, -h ) ); stroke( red(A.col), green(A.col), blue(A.col), floor(alpha(A.col) * life) ); vertex( AI.x, AI.y ); stroke( red(B.col), green(B.col), blue(B.col), alpha(B.col) * life ); vertex( BI.x, BI.y ); } } // Allow the user to restart void keyPressed() { Fire(); } void mousePressed() { Fire(); }