//boom(socket) web version //mitchell whitelaw - april 2006 // int numBits = 40; int cloudRadius = 150; // float friction = 0.9965; //0.999; float velFloor = 0.015; // the lower limit for velocity: stop drawing when things get this slow float distanceCeiling = 1000; // stop drawing when things get this far from the origin // float distancefactor = 6000; // int drawing = 0; int totalDrawing = 0; int originX; int originY; int cloudX; int cloudY; Particle[] theCloud; // the array of particles static public void main(String args[]) { PApplet.main(new String[] { "--present", "--display=1", "boom_socket" }); } void setup() { //size (screen.width,screen.height); size (900,550); background(0); framerate(30); ellipseMode(CENTER_RADIUS); smooth(); noFill(); makeCloud(); } void makeCloud() { theCloud = new Particle[numBits]; for (int i=0; i < numBits; i++){ float radius = ((i+1)/float(numBits))*cloudRadius; float angle = random(TWO_PI); float xPos = cloudX + (radius*sin(angle)); float yPos = cloudY + (radius*cos(angle)); theCloud[i] = new Particle(xPos,yPos,0,0,i,0,0,0,0); // x,y,xvel,yvel,particle ID } } class Particle { int id; // particle ID float x; // x position float y; // y position float xvel; // x velocity float yvel; // y velocity int myNeighbour; // ID of my neighbour int myNeighbour2; float neighbourDistance; // distance to my neighbour float neighbourDistance2; int drawingFlag; // am I drawing or not? Particle(float xIn, float yIn, float xvelIn, float yvelIn, int idIn, int myNeighbourIn, float neighbourDistanceIn, int myNeighbourIn2, int neighbourDistanceIn2) { // particle constructor x = xIn; y = yIn; xvel = xvelIn; yvel = yvelIn; id = idIn; myNeighbour = myNeighbourIn; myNeighbour2 = myNeighbourIn2; neighbourDistance = neighbourDistanceIn; neighbourDistance2 = neighbourDistanceIn2; drawingFlag = 1; } void moveParticle(){ x += xvel; // add xvel to xpos y += yvel; // add yvel to ypos xvel = xvel*friction; // factor in friction yvel = yvel*friction; } void findNeighbour(){ int theNeighbour = 0; int thenextNeighbour = 0; float minDistance = 10000; // make it a high number so we can find the minimum float nextminDistance = 10000; float theDistance = 0; for (int i=0; i < numBits; i++){ theDistance = sqrt(sq(x - theCloud[i].x) + sq(y - theCloud[i].y)); // distance from this particle to each of the others if (theDistance < minDistance && theDistance > 0){ // if the distance is less than the lowest yet, and more than 0 (ie it's not the distance from me to me). minDistance = theDistance; theNeighbour = i; } if (theDistance < nextminDistance && theDistance > minDistance){ nextminDistance = theDistance; thenextNeighbour = i; } } myNeighbour = theNeighbour; // the ID of the neighbour particle neighbourDistance = minDistance; myNeighbour2 = thenextNeighbour; neighbourDistance2 = nextminDistance; } void goBoom(){ originX = mouseX; originY = mouseY; float xOffset = x - originX; float yOffset = y - originY; float thisDistance = sqrt(sq(xOffset) + sq(yOffset)); float absOffset = abs(xOffset) + abs(yOffset); float xRatio = xOffset/absOffset; // ratio of x/y - using abs to maintain sign of offset float yRatio = yOffset/absOffset; // ratio of y/x xvel = distancefactor*xRatio*(1/sq(thisDistance)); // the initial X velocity yvel = distancefactor*yRatio*(1/sq(thisDistance)); // the initial Y velocity drawingFlag=1; } void drawParticle() { float originDistance = sqrt(sq(x-originX) + sq(y-originY)); if (drawing == 1 && (abs(xvel)+abs(yvel)) > velFloor && originDistance < distanceCeiling) { float[] theCenterPoint = threePointCircle(x, y, theCloud[myNeighbour].x, theCloud[myNeighbour].y, theCloud[myNeighbour2].x, theCloud[myNeighbour2].y); float theRadius = sqrt(sq(x-theCenterPoint[0]) + sq(y-theCenterPoint[1])); stroke(255,10-(0.05*(min(200,theRadius)))); ellipse(theCenterPoint[0],theCenterPoint[1],theRadius,theRadius); } else { drawingFlag = 0; } } } void keyPressed(){ if (key == 'b') { drawing = 1; for (int i = 0; i < numBits; i++){ theCloud[i].goBoom(); // all go boom } } else if (key == 'c') { background (0); drawing = 0; } else if (key == 'r') { cloudX = mouseX; cloudY = mouseY; makeCloud(); // remake the cloud } } void draw(){ noFill(); int countDrawing = 0; for (int i=0; i < numBits; i++){ theCloud[i].findNeighbour(); theCloud[i].drawParticle(); theCloud[i].moveParticle(); countDrawing += theCloud[i].drawingFlag; } totalDrawing = countDrawing; if (totalDrawing == 0){ drawing=0; fill(0,5); stroke(0,5); rect(0,0,width,height); } } float[] threePointCircle(float x1, float y1, float x2, float y2, float x3, float y3) { // geometry thanks to Paul Bourke - http://astronomy.swin.edu.au/~pbourke/geometry/circlefrom3/ if ((x2-x1) == 0){ // first slope is vertical, rotate points float oldx = x1; float oldy = y1; x1 = x2; y1 = y2; x2 = x3; y2 = y3; x3 = oldx; y3 = oldy; } else if ((x3-x2) == 0){ // second slope is vertical, rotate points the other way float oldx = x3; float oldy = y3; x3 = x2; y3 = y2; x2 = x1; y2 = y1; x1 = oldx; y1 = oldy; } float slope1 = (y2-y1)/(x2-x1); // slope of the first line float slope2 = (y3-y2)/(x3-x2); // slope of the second line float centerx = ((slope1*slope2*(y1-y3)) + (slope2*(x1+x2)) - (slope1*(x2+x3)))/(2*(slope2 - slope1)); // x point float centery = ((-1*(centerx - 0.5*(x1+x2)))/slope1) + 0.5*(y1+y2); // y point float[] thisCenter = {centerx,centery}; return thisCenter; }