/* Ok, These are the little creatures who run around and move the data*/ class Gremlin { //Declarations PVector loc; PVector vel; PVector acc; int radius; float deweynumber; int weight; PVector temp; //Each movement is multiplied by this factor in this direction PVector friction; double time; boolean heavy; ArrayList neighbors; double tempmultby; PVector inertia; String say; //The radius is actually the effective diameter Gremlin(PVector l, int radius_, int deweycat_, double time_) { time = time_; acc = new PVector(0,0); vel = new PVector(0,0); loc = l.get(); radius = radius_; deweynumber = deweycat_; weight = 1; temp = new PVector(0,0); friction = new PVector( 0.7 , 0.5 ); inertia = new PVector( 1 , 0.5 ); neighbors = new ArrayList(); heavy = false; } void friction() { vel.x = friction.x * vel.x; vel.y = friction.y * vel.y; } void inertia() { acc.x = inertia.x * acc.x; acc.y = inertia.y * acc.y; } //Draws the Gremlin void render() { float myz = zscale*sqrt(weight); colorMode(HSB,255); //Draws the wimpy gremlins if (weight <= 4) { if (renderg == true) { strokeWeight(3); stroke(120); if (littlecolors == true) { if (renderc == false) { stroke(deweynumber*255/1000, 200, 210, 200); } else { stroke((float) time*255.0, 200, 210, 200); } } point(loc.x,loc.y, myz); } } else //Draw the big gremlins { if (renderl == true){ strokeWeight(linet); stroke(0); //Draws the surface lines for (int k = 0; k < neighbors.size(); k++) { Gremlin other = (Gremlin) neighbors.get(k); line(loc.x,loc.y,myz,other.loc.x,other.loc.y, zscale*sqrt(other.weight)); } } //Do we want to look at dewey space or time space if (renderc == false) { stroke(deweynumber*255/1000, 200, 210, 200); fill(deweynumber*255/1000, 200, 210); say = Integer.toString((int) deweynumber); } else { stroke((int)(time*255), 200, 210, 200); fill((int)(time*255), 200, 210); say = timeAsString(time); } strokeWeight(10); if (rendera == true){ //Get the point color //Write the dewey number over it if (rendert == true){ text( say,loc.x,loc.y,myz); } else { point(loc.x,loc.y, myz ); } } else if ( (renderb == true) && (heavy == true) ) { //Write the dewey number over it if (rendert == true){ text( say,loc.x,loc.y,myz); } else { point(loc.x,loc.y,myz ); } } } colorMode(RGB,255); } //This method updates all of the positions and resets the acceleration vector void update() { inertia(); vel.add(acc); friction(); if (vel.mag() > radius/5) { vel.normalize(); vel.mult(radius/5); } loc.add(vel); acc.mult(0); if (loc.x < PLOTX1 + radius) { loc.x = PLOTX1 + radius; vel.sub(1.5 * vel.x, 0f, 0f); } if (loc.x > PLOTX2 - radius) { loc.x = PLOTX2 - radius; vel.sub(1.5 * vel.x, 0f,0f); } if (loc.y < PLOTY1 + radius) { loc.y = PLOTY1 + radius; vel.sub(0f,1.5 * vel.y,0f); } if (loc.y > PLOTY2 - radius) { loc.y = PLOTY2 - radius; vel.sub(0f,1.5 * vel.y,0f); } } //Gremlins like to dance, It's just what they do void run(ArrayList gremlins) { //Interact with neighbors The interactions go both ways! So we only need to step through interactions that haven't occured yet for (int i = gremlins.indexOf(this); i < gremlins.size(); i++) { Gremlin other = (Gremlin) gremlins.get(i); if (other != this) { float d = loc.dist(other.loc); //Figure out the direction unit-vector temp = other.loc.get(); temp.sub(loc); temp.div(d); //whoops... Turns out it's all balanced for the... Hold on, This is the DIRECTION VECTOR... Roll back. //Figure out what to do with it if (d > radius) { //Base force //remove weight to get acc //square of the distance. temp.mult( (0.0001 * other.weight) / (d * d) ); //If we're alike in dewey space, get alot! more force that way if (deweynumber == other.deweynumber) { temp.mult(d*d); } //Enforcing this relationship with friction in the Y axis This further encourages time binning. if ( (time <= other.time + (.0008 * height / radius)) && ( time >= other.time - (.0008 * height / radius) ) ) { temp.mult(10*d*d); } //If we're alike in time space, get alot more force that way //temp.div((float)(time - other.time)); acc.add(temp); temp.mult(weight / other.weight); other.acc.sub(temp); } else if (d > ceil(radius / 10.0)) { //low weight particles are weakly interacting with heavy particles... but fine with themselves //Repulsve force temp.mult(-0.1 * other.weight / weight); acc.add(temp); temp.mult(weight * weight / (other.weight * other.weight)); other.acc.sub(temp); } // Generates a dynamic list of large neighbors if (heavy == true && d < 1.1 * radius && d > 0.7 * radius && other.heavy == true && !(other.neighbors.contains(this)) && !(neighbors.contains(other)) ) { if (neighbors.size() > 1) { for( int k = 0; k < neighbors.size(); k++ ) { Gremlin other2 = (Gremlin) neighbors.get(k); if (other.loc.dist(other2.loc) < 0.5 * radius && other2.weight < other.weight) { neighbors.remove(k); } } } neighbors.add(other); } } } } void clean(ArrayList gremlins) { heavy = true; for (int i = 0 ; i < gremlins.size(); i++) { Gremlin other = (Gremlin) gremlins.get(i); float d = loc.dist(other.loc); temp = vel.get(); temp.sub(other.vel); if (d < radius*0.9 && other != this && other.weight >= weight && other.heavy == true ) { heavy = false; } if (d <= radius / 10 && other != this && temp.mag() <= 5 && deweynumber == other.deweynumber) { weight = weight + other.weight; // deweynumber = (weight * deweynumber + other.weight * other.deweynumber) / (weight + other.weight); time = (weight * time + other.weight * other.time) / (weight + other.weight); if (other.heavy == true) { heavy = true; neighbors.addAll(other.neighbors); } basement.removeGremlin(other); other = null; } } if (heavy == false) { neighbors.clear(); } for (int k = 0; k < neighbors.size(); k++) { Gremlin other = (Gremlin) neighbors.get(k); if(loc.dist(other.loc) > radius) { neighbors.remove(k); } } } double getTime() { return time; } PVector getLoc() { return loc; } float getDewey() { return deweynumber; } }