/* A surface filled with one hundred medium to small sized circles. Each circle has a different size and direction, but moves at the same slow rate. Display: >>> A. The instantaneous intersections of the circles B. The aggregate intersections of the circles Implemented by J. Tarbell <http://levitated.net> 8 April 2004 Processing v.68 <http://processing.org> */ int num = 100; int time = 0; // object array Disc[] discs; // initialization void setup() { size(500, 500); colorMode(RGB,255); ellipseMode(CENTER_RADIUS); background(0); framerate(30); // make some discs discs = new Disc[num]; // arrange in anti-collapsing circle for (int i=0;i<num;i++) { float fx = 0.4*width*cos(TWO_PI*i/num); float fy = 0.4*width*sin(TWO_PI*i/num); float x = random(width/2) + fx; float y = random(width/2) + fy; float r = 5+random(45); int bt = 1; if (random(100)<50) bt=-1; discs[i] = new Disc(i,x,y,bt*fx/1000.0,bt*fy/1000.0,r); } } // main void loop() { background(0); // move discs for (int c=0;c<num;c++) { discs[c].move(); discs[c].render(); discs[c].renderPxRiders(); } time++; } // disc object class Disc { // index identifier int id; // position float x,y; // radius float r, dr; // velocity float vx,vy; // pixel riders int numr; int maxr = 40; PxRider[] pxRiders; Disc(int Id, float X, float Y, float Vx, float Vy, float R) { // construct id=Id; x=X; y=Y; vx=Vx; vy=Vy; dr=R; r=0; numr = int(R/1.62); if (numr>maxr) numr=maxr; // create pixel riders pxRiders = new PxRider[maxr]; for (int n=0;n<maxr;n++) { pxRiders[n] = new PxRider(); } } void draw() { stroke(0,50); noFill(); ellipse(x,y,r,r); } void render() { // find intersecting points with all ascending discs for (int n=id+1;n<num;n++) { if (n!=id) { // find distance to other disc float dx = discs[n].x-x; float dy = discs[n].y-y; float d = sqrt(dx*dx+dy*dy); // intersection test if (d<(discs[n].r+r)) { // complete containment test if (d>abs(discs[n].r-r)) { // find solutions float a = (r*r - discs[n].r*discs[n].r + d*d ) / (2*d); float p2x = x + a*(discs[n].x - x)/d; float p2y = y + a*(discs[n].y - y)/d; float h = sqrt(r*r - a*a); float p3ax = p2x + h*(discs[n].y - y)/d; float p3ay = p2y - h*(discs[n].x - x)/d; float p3bx = p2x - h*(discs[n].y - y)/d; float p3by = p2y + h*(discs[n].x - x)/d; // P3a and P3B may be identical - ignore this case (for now) stroke(255); point(p3ax,p3ay); point(p3bx,p3by); } } } } } void move() { // add velocity to position x+=vx; y+=vy; // bound check if (x+r<0) x+=width+r+r; if (x-r>width) x-=width+r+r; if (y+r<0) y+=width+r+r; if (y-r>width) y-=width+r+r; // increase to destination radius if (r<dr) { r+=0.1; } } void renderPxRiders() { for (int n=0;n<numr;n++) { pxRiders[n].move(x,y,r); } } // pixel rider object class PxRider { float t; float vt; int mycharge; PxRider() { t=random(TWO_PI); vt=0.0; } void move(float x, float y, float r) { // add velocity to theta t=(t+vt+PI)%TWO_PI - PI; vt+=random(-0.001,0.001); // apply friction brakes if (abs(vt)>0.02) vt*=0.9; // draw float px = x+r*cos(t); float py = y+r*sin(t); color c = get(int(px),int(py)); if (brightness(c)>48) { glowpoint(px,py); mycharge = 164; } else { stroke(mycharge); point(px,py); mycharge*=0.98; } } } } // methods void glowpoint(float px, float py) { for (int i=-2;i<3;i++) { for (int j=-2;j<3;j++) { float a = 0.8 - i*i*0.1 - j*j*0.1; tpoint(int(px+i),int(py+j),#FFFFFF,a); } } } void tpoint(int x1, int y1, color myc, float a) { // place translucent point int r, g, b; color c; c = get(x1, y1); r = int(red(c) + (red(myc) - red(c)) * a); g = int(green(c) +(green(myc) - green(c)) * a); b = int(blue(c) + (blue(myc) - blue(c)) * a); color nc = color(r, g, b); stroke(nc); point(x1,y1); }