/* 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> */ // widthensions int num = 100; int time = 0; // display flag boolean showStructure = false; // object array Disc[] discs; // methods void setup() { size(500, 500); colorMode(RGB,255); ellipseMode(CENTER_RADIUS); background(0); framerate(30); // make 100 discs discs = new Disc[num]; // arrange linearly for (int i=0;i<num;i++) { float x = random(width); float y = random(width); float fy = 0; float fx = random(-1.0,1.0); float r = 20+random(20); discs[i] = new Disc(i,x,y,fx,fy,r); } } // main void loop() { if (showStructure) { background(0); // render circles and intersections for (int c=0;c<num;c++) { discs[c].draw(); } } // move discs for (int c=0;c<num;c++) { discs[c].move(); discs[c].render(); } time++; } void keyReleased () { if (key==' ') { background(0); if (showStructure) { showStructure = false; } else { showStructure = true; } } } // translucent point void tpoint(int x1, int y1, int gc, float a) { noStroke(); fill(gc,a*255); rect(x1,y1,1,1); } // disc object class Disc { // index identifier int id; // position float x,y; // radius float r, dr; // velocity float vx,vy; // sand painters int numsands = 1; SandPainter[] sands = new SandPainter[numsands]; 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=1.0; // create sand painters for (int n=0;n<numsands;n++) { sands[n] = new SandPainter(); } } void draw() { stroke(64); noFill(); ellipse(x,y,r,r); } void render() { // find intersecting points with all ascending discs for (int n=id+1;n<num;n++) { // 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 circle intersection 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) if (showStructure) { stroke(255); point(p3ax,p3ay); point(p3bx,p3by); } else { tpoint(int(p3ax-1),int(p3ay),255,0.21); tpoint(int(p3ax+1),int(p3ay),0,0.21); tpoint(int(p3bx-1),int(p3by),255,0.21); tpoint(int(p3ax+1),int(p3ay),0,0.21); } // draw sand painters for (int s=0;s<numsands;s++) { sands[s].render(p3ax,p3ay,p3bx,p3by); } } } } } void move() { // move radius towards destination radius if (r<dr) r+=0.02; // add velocity to position x+=vx; y+=vy; // bound check if (x+r<0) { x+=width+r+r; y=random(width); } if (x-r>width) { x-=width+r+r; y=random(width); } if (y+r<0) { y+=width+r+r; x=random(width); } if (y-r>width) { y-=width+r+r; x=random(width); } } } // sandpainter object class SandPainter { float p; float g; int c; SandPainter() { p = random(1.0); c = int(random(256)); g = random(0.01,0.1); } void render(float x, float y, float ox, float oy) { // draw painting sweeps tpoint(int(ox+(x-ox)*sin(p)),int(oy+(y-oy)*sin(p)),c,0.11); g+=random(-0.050,0.050); float maxg = 0.5; if (g<-maxg) g=-maxg; if (g>maxg) g=maxg; p+=random(-0.050,0.050); if (p<0) p=0; if (p>1.0) p=1.0; float w = g/10.0; for (int i=0;i<11;i++) { tpoint(int(ox+(x-ox)*sin(p + sin(i*w))),int(oy+(y-oy)*sin(p + sin(i*w))),c,0.1-i/110); tpoint(int(ox+(x-ox)*sin(p - sin(i*w))),int(oy+(y-oy)*sin(p - sin(i*w))),c,0.1-i/110); } } }