/*
* Copyright (c) 2012 Gwyllim Jahn
* http://scripts.crida.net/gh
* Developed By Gwyllim Jahn, Kiet Nguyen and Vonne Yang
* during the 2012 RMIT nCertainties studio.
*
* This code makes extensive use of several freely distributed
* processing libraries – thankyou especially to toxi.
* This code is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* http://creativecommons.org/licenses/LGPL/2.1/
*
* This code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
*/
/
//BONE_WEAVING
/—————————————————–StitchersImport_black_moving——————————————————–//
import processing.video.*;
import toxi.physics2d.constraints.*;
import toxi.physics.*;
import toxi.physics.constraints.*;
import toxi.physics2d.behaviors.*;
import toxi.physics.behaviors.*;
import toxi.physics2d.*;
import controlP5.*;
import processing.dxf.*;
import toxi.geom.*;
import org.apache.commons.collections.keyvalue.*;
import org.apache.commons.collections.set.*;
import org.apache.commons.collections.iterators.*;
import org.apache.commons.collections.map.*;
import org.apache.commons.collections.bag.*;
import org.apache.commons.collections.list.*;
import org.apache.commons.collections.bidimap.*;
import org.apache.commons.collections.collection.*;
import org.apache.commons.collections.*;
import org.apache.commons.collections.functors.*;
import peasy.org.apache.commons.math.*;
import peasy.*;
import peasy.org.apache.commons.math.geometry.*;
import processing.opengl.*;
// ———————————————————————————-GLOBALS
//accessable by anything in your script.
VerletPhysics physics = new VerletPhysics();
PeasyCam cam;
ControlP5 controlP5;
ControlWindow controlWindow;
//number of agents per tree
int numAgents = 30;
boolean record = false;
boolean agentsOn = true;
ArrayList<Agent>agentPop = new ArrayList<Agent>();
ArrayList<Agent>addList = new ArrayList<Agent>();
MultiValueMap particleMap = new MultiValueMap();
MovieMaker mm;
int gridRes = 20;
boolean recording = false;
//add the pause variable
Boolean paused = true;
Boolean bundling = false;
//agent variables
Boolean drawSingle = false;
int ct =0;
//agent variables
//number of points to draw a trail with
int trailLength = 300;
float agentSpeed = 1;
//distance between trail points
int dropRate = 2;
//size of field to spawn agents
float spawnSizeXY = 30;
float aAttract = 0.9;
float aAlign = 0.05;
float aRepel = 4;
float aAccel = 0.04;
//bundling variables
float cutoff = 20;
float stiffness = 0.05;
float numToMove = 1;
float nodeStiffness = 0.05;
float strandStiffness = 0.08;
// ———————————————————————————-SETUP
void setup(){
size(600,600,OPENGL);
cam =new PeasyCam(this,-50,-50,0,200);
physics.setDrag(0.05);
//spawn();
setupP5();
importFibres();
mm = new MovieMaker(this, width, height, “drawing.mov”, 30, MovieMaker.ANIMATION, MovieMaker.HIGH);
background(0);
}
void draw(){
print(frameRate+” “);
background(0);
float[] gLA = cam.getLookAt();
cam.lookAt(gLA[0],gLA[1],gLA[2]+1);
if(record){
beginRaw(DXF,”test.dxf”);
}
//update the physics engine
physics.update();
for (Agent a: agentPop){
a.run();
}
if(record){
endRaw();
record = false;
}
if(recording)mm.addFrame();
}
void keyPressed(){
//save a dxf
if (key == ‘e’) {
record = !record;
}
//add the pause function
if (key == ‘p’) {
paused = !paused;
}
if (key == ‘a’) {
agentsOn = !agentsOn;
}
//save a screengrab
if (key == ‘s’) {
savePts();
}
//reset the sketch
if (key == ‘r’) {
background(255);
//importLandscape();
physics = new VerletPhysics();
}
if (key == ‘ ‘) {
if(!recording) {
recording = true;
}else{
recording = false;
mm.finish(); // Finish the movie if space bar is pressed!
}
}
}
//—————————————————–Agents——————————————————–//
//simple agent class to interact with the data
//field and other agents
class Agent {
Vec3D loc,vel,acc;
Strand trail;
ArrayList<Strand> pastStrands;
boolean locked;
Agent(Vec3D _loc, Vec3D _vel, boolean l){
loc = _loc;
vel = _vel;
locked = l;
if(!locked){
acc= new Vec3D(0,0,0);
trail = new Strand(loc);
pastStrands = new ArrayList<Strand>();
}
}
void run(){
//moves the particles based on proximity to trees
if(!locked){
if(!paused){
searchAgents();
updatePos();
}
trail.update(loc);
trail.run();
for(Strand s:pastStrands){
s.run();
}
}else{
//line(loc.x,loc.y,loc.z,loc.x+vel.x,loc.y+vel.y,loc.z+vel.z);
}
}
//————————————————————————————-
//Behaviours
//————————————————————————————-
void searchAgents(){
//reset accel
for (Agent a:agentPop){
//get essential variables
Vec3D diff = a.loc.sub(loc.copy());
float d = diff.magnitude();
float val = 1;
if (a.locked) val = 2;
if(d<30&&d>0){
attract(diff.copy(),d/val); //attract to neighbour
align(a.vel.copy(),d); //align with neighbour
if(d<10) {
repel(diff.copy(),d); //avoid neighbour
}
}
}
}
void attract (Vec3D v, float d){
acc.interpolateToSelf(v,(aAttract/d));
}
void align(Vec3D v, float d){
acc.interpolateToSelf(v,aAlign);
}
void repel (Vec3D v, float d){
v.invert();
acc.interpolateToSelf(v,(aRepel/d));
}
void respawn(){
Vec3D loc = new Vec3D(random(spawnSizeXY/2,spawnSizeXY*1.5),random(spawnSizeXY/2,spawnSizeXY*1.5),0);
Vec3D vel = new Vec3D(0,0,1);
Agent a = new Agent(loc,vel,false);
addList.add(a);
}
//————————————————————————————-
//Functions for managing trails and rendering the agent.
//————————————————————————————-
void updatePos(){
//move the agent
acc.limit(aAccel);
vel.addSelf(acc);
vel.limit(agentSpeed);
loc.addSelf(vel);
}
}
//—————————————————–Controllers——————————————————–//
void setupP5 (){
controlP5 = new ControlP5(this);
controlP5.setAutoDraw(false);
controlWindow = controlP5.addControlWindow(“controlP5window”,100,100,400,320);
controlWindow.hideCoordinates();
Controller mySlider6 =controlP5.addSlider(“agentSpeed”,0.1,3.5).linebreak();
mySlider6.setWindow(controlWindow);
controlWindow.setTitle(“Spring GUI”);
}
//—————————————————–Initalisation——————————————————–//
void spawn(Vec3D l,Vec3D v){
for (int i=0;i<numAgents;i++){
// Vec3D loc = new Vec3D(random(0,gW*gRes),random(0,gH*gRes),0);
Vec3D loc = new Vec3D(random(-spawnSizeXY/2,spawnSizeXY*1.5),random(-spawnSizeXY/2,spawnSizeXY*1.5),0);
loc.addSelf(l);
Vec3D vel = v.copy();
Agent a = new Agent(loc,vel,false);
agentPop.add(a);
}
}
//———————————import functions
void importFibres() {
//load text
String[] txtLines = loadStrings(“fibres2import.txt”);
// loop thru them
int count = 0;
int fPt;
for (int i = 0; i < txtLines.length; ++i) {
//splits strand points
String[] arrCoords = split(txtLines[i], ‘_’);
Vec3D lastPt = null;
for (int j = 0; j < arrCoords.length; ++j) {
//separates coords
String[] arrToks = split(arrCoords[j], ‘,’);
float xx = Float.valueOf(arrToks[0]);
float yy = Float.valueOf(arrToks[1]);
float zz = Float.valueOf(arrToks[2]);
//create node
Vec3D tmpPt = new Vec3D(xx, yy, zz);
//set siblings
if (j>0) {
Vec3D loc = lastPt.copy();
Vec3D vel = tmpPt.sub(lastPt);
Agent a= new Agent(loc,vel,true);
agentPop.add(a);
if(j==1) spawn(loc,vel);
}
lastPt = tmpPt.copy();
}
}
}
//—————————————————–Strand——————————————————–//
class Strand{
ArrayList<VerletSpring> trail;
ArrayList<MapParticle> pts;
float dropNum;
boolean hang;
Strand(Vec3D _loc){
trail = new ArrayList<VerletSpring>();
pts = new ArrayList<MapParticle>();
MapParticle p = new MapParticle(_loc,getCoord(_loc),this);
p.lock();
pts.add(p);
dropNum = 0;
hang = false;
}
void update(Vec3D _loc){
//update the trail geom every 5 moves
if(dropNum%dropRate==0){
if(trail.size()<trailLength){
MapParticle p = new MapParticle(_loc,getCoord(_loc),this);
p.lock();
String coord = getCoord(p);
particleMap.put(coord,p);
MapParticle lastP = pts.get(pts.size()-1);
lastP.unlock();
VerletSpring s = new VerletSpring(pts.get(pts.size()-1),p,(p.distanceTo(lastP)),strandStiffness);
physics.addParticle(p);
physics.addSpring(s);
trail.add(s);
pts.add(p);
}else{
physics.removeSpringElements(trail.get(0));
trail.remove(0);
pts.remove(0);
}
dropNum=0;
}
dropNum++;
}
String getCoord(Vec3D p){
String s = “”+floor(p.x/gridRes)+floor(p.y/gridRes)+floor(p.z/gridRes);
return s;
}
void run(){
//render agent trail as lines
strokeWeight(1);
float c =1;
if(agentsOn){
for (VerletSpring l : trail){
l.setStrength(l.getStrength()*0.99);
float gs = ((trail.size()-c)/trail.size())*255;
stroke(gs);
MapParticle a = (MapParticle) l.a;
if(hang)a.addVelocity(new Vec3D(0,0,-0.09));
a.run();
line (l.a.x,l.a.y,l.a.z,l.b.x,l.b.y,l.b.z);
c+=1;
}
}
//only hang once
}
}
//—————————————————–mapParticales——————————————————–//
class MapParticle extends VerletParticle {
String mapCoord;
Strand parent;
int age;
boolean alive;
MapParticle(Vec3D _loc, String _s,Strand _p) {
super (_loc);
mapCoord = _s;
parent = _p;
age = 0;
alive = true;
}
void run() {
//get the grid pos and update if necessary
if(alive){
age++;
String newMapCoord = getCoord();
if (newMapCoord != mapCoord) {
particleMap.remove(mapCoord, this);
particleMap.put(newMapCoord, this);
mapCoord = newMapCoord;
}
ArrayList<Vec3D> closest = new ArrayList<Vec3D>();
float minD = 999999;
//attract to neighbouring particles
if (particleMap.getCollection(mapCoord)!=null) {
for (MapParticle p: (ArrayList<MapParticle>)particleMap.getCollection(mapCoord)) {
if(p.parent!=parent){
Vec3D diff = sub(p);
diff.invert();
float d = diff.magnitude();
if(d>0.1){
if (d<minD){
closest.add(diff);
if(closest.size()>numToMove) closest.remove(0);
minD =d;
}
}
}
}
}
for (Vec3D v:closest){
float d = v.magnitude();
v.scaleSelf(nodeStiffness/d);
addVelocity(v);
}
}
if(age>50){
physics.particles.remove(this);
alive = false;
age = 0;
}
}
String getCoord(){
String s = “”+Math.floor(x/gridRes)+Math.floor(y/gridRes)+Math.floor(z/gridRes);
return s;
}
}
//—————————————————–Saving——————————————————–//
void savePts(){
String[] lines = new String[agentPop.size()];
int c=0;
for (int i =0;i<agentPop.size();i++) {
Agent a = (Agent) agentPop.get(i);
lines[c] = “”;
if(a.trail!=null){
for(MapParticle t:a.trail.pts){
lines[c] =lines[c]+ (t.x +”,” + t.y + “,” + t.z + “/”);
}
}
c++;
}
saveStrings(“lines.txt”, lines);
}
BONE_&_SKIN
/—————————————————–StitchersImportSkin——————————————————–//
import toxi.physics2d.constraints.*;
import toxi.physics.*;
import toxi.physics.constraints.*;
import toxi.physics2d.behaviors.*;
import toxi.physics.behaviors.*;
import toxi.physics2d.*;
import controlP5.*;
import processing.dxf.*;
import toxi.geom.*;
import org.apache.commons.collections.keyvalue.*;
import org.apache.commons.collections.set.*;
import org.apache.commons.collections.iterators.*;
import org.apache.commons.collections.map.*;
import org.apache.commons.collections.bag.*;
import org.apache.commons.collections.list.*;
import org.apache.commons.collections.bidimap.*;
import org.apache.commons.collections.collection.*;
import org.apache.commons.collections.*;
import org.apache.commons.collections.functors.*;
import peasy.org.apache.commons.math.*;
import peasy.*;
import peasy.org.apache.commons.math.geometry.*;
import processing.opengl.*;
// ———————————————————————————-GLOBALS
//accessable by anything in your script.
VerletPhysics physics = new VerletPhysics();
PeasyCam cam;
ControlP5 controlP5;
ControlWindow controlWindow;
//number of agents per tree
int numAgents = 3;
boolean record = false;
boolean agentsOn = true;
ArrayList<Agent>agentPop = new ArrayList<Agent>();
ArrayList<Agent>addList = new ArrayList<Agent>();
MultiValueMap particleMap = new MultiValueMap();
int gridRes = 20;
//add the pause variable
Boolean paused = false;
Boolean bundling = false;
//agent variables
Boolean drawSingle = false;
int ct =0;
//agent variables
//number of points to draw a trail with
int trailLength = 300;
float agentSpeed = 1;
//distance between trail points
int dropRate = 2;
//size of field to spawn agents
float spawnSizeXY = 20;
float aAttract = 1;
float aAlign = 0.03;
float aRepel = 3;
float aAccel = 0.02;
//bundling variables
float cutoff = 20;
float stiffness = 0.05;
float numToMove = 1;
float nodeStiffness = 0.05;
float strandStiffness = 0.08;
int numVertPerSkin = 80;
// ———————————————————————————-SETUP
void setup(){
size(600,600,OPENGL);
cam =new PeasyCam(this,200);
physics.setDrag(0.05);
//spawn();
setupP5();
importFibres();
background(255);
}
void draw(){
// print(frameRate+” “);
background(255);
if(record){
beginRaw(DXF,”test.dxf”);
}
//update the physics engine
if(!paused)physics.update();
boolean allLocked = true;
for (Agent a: agentPop){
a.run();
if(!a.locked)allLocked = false;
}
if(allLocked) importFibres();
if(record){
endRaw();
record = false;
}
}
void keyPressed(){
//save a dxf
if (key == ‘e’) {
record = !record;
}
//add the pause function
if (key == ‘p’) {
paused = !paused;
}
if (key == ‘a’) {
agentsOn = !agentsOn;
}
//save a screengrab
if (key == ‘s’) {
savePts();
}
//reset the sketch
if (key == ‘r’) {
background(255);
//importLandscape();
physics = new VerletPhysics();
}
}
/—————————————————–Agents——————————————————–//
//simple agent class to interact with the data
//field and other agents
class Agent {
Vec3D initLoc,initVel;
Vec3D loc,vel,acc;
Strand trail;
ArrayList<Strand> pastStrands;
boolean locked;
int depositNum;
int age;
Agent(Vec3D _loc, Vec3D _vel, boolean l){
loc = _loc;
vel = _vel;
initLoc = _loc.copy();
initVel = _vel.copy();
locked = l;
if(!locked){
acc= new Vec3D(0,0,0);
trail = new Strand(loc);
pastStrands = new ArrayList<Strand>();
}
depositNum = 0;
age = 0;
}
void run(){
//moves the particles based on proximity to trees
if(!locked){
if(!paused){
searchAgents();
updatePos();
trail.update(loc);
makeSkin();
}
age++;
}
if(age>0){
trail.run();
for(Strand s:pastStrands){
s.run();
}
}
line(loc.x,loc.y,loc.z,loc.x+vel.x,loc.y+vel.y,loc.z+vel.z);
if(age>300)locked = true;
}
//————————————————————————————-
//Behaviours
//————————————————————————————-
void searchAgents(){
//reset accel
for (Agent a:agentPop){
//get essential variables
Vec3D diff = a.loc.sub(loc.copy());
float d = diff.magnitude();
if(d<100&&d>0){
attract(diff.copy(),d); //attract to neighbour
if(a.locked){
float ang = vel.angleBetween(a.vel);
if(ang>PI/2){
align(a.vel.copy().invert(),d);
}else{
align(a.vel.copy(),d);
}
}else{
align(a.vel.copy(),d); //align with neighbour
}
if(d<30) {
if(a.locked) d=d*2;
repel(diff.copy(),d); //avoid neighbour
}
}
}
}
void attract (Vec3D v, float d){
acc.interpolateToSelf(v,(aAttract/d));
}
void align(Vec3D v, float d){
acc.interpolateToSelf(v,aAlign);
}
void repel (Vec3D v, float d){
v.invert();
acc.interpolateToSelf(v,(aRepel/d));
}
void respawn(){
Vec3D loc = new Vec3D(random(spawnSizeXY/2,spawnSizeXY*1.5),random(spawnSizeXY/2,spawnSizeXY*1.5),0);
Vec3D vel = new Vec3D(0,0,1);
Agent a = new Agent(loc,vel,false);
addList.add(a);
}
//————————————————————————————-
//Functions for managing trails and rendering the agent.
//————————————————————————————-
void updatePos(){
//move the agent
acc.limit(aAccel);
vel.addSelf(acc);
vel.limit(agentSpeed);
loc.addSelf(vel);
}
void makeSkin(){
if(depositNum>numVertPerSkin){
Strand skin = new Strand(loc);
VerletSpring s = new VerletSpring(skin.pts.get(0),trail.pts.get(trail.pts.size()-1),0,strandStiffness);
physics.addSpring(s);
skin.hang = true;
Vec3D svel = new Vec3D(random(-1,1),random(-1,1),0);
for (int i = 1;i<=numVertPerSkin/2;i++){
svel.normalizeTo(i*2);
skin.addParticle(loc.add(svel));
}
pastStrands.add(skin);
depositNum = 0;
}
depositNum++;
}
/—————————————————–Controllers——————————————————–//
void setupP5 (){
controlP5 = new ControlP5(this);
controlP5.setAutoDraw(false);
controlWindow = controlP5.addControlWindow(“controlP5window”,100,100,400,320);
controlWindow.hideCoordinates();
Controller mySlider6 =controlP5.addSlider(“agentSpeed”,0.1,3.5).linebreak();
mySlider6.setWindow(controlWindow);
controlWindow.setTitle(“Spring GUI”);
/—————————————————–Initialisation——————————————————–//
void spawn(Vec3D l,Vec3D v){
for (int i=0;i<numAgents;i++){
// Vec3D loc = new Vec3D(random(0,gW*gRes),random(0,gH*gRes),0);
Vec3D loc = new Vec3D(random(-spawnSizeXY/2,spawnSizeXY*1.5),random(-spawnSizeXY/2,spawnSizeXY*1.5),0);
loc.addSelf(l);
Vec3D vel = v.copy();
Agent a = new Agent(loc,vel,false);
agentPop.add(a);
}
}
//———————————import functions
void importFibres() {
//load text
String[] txtLines = loadStrings(“fibres2import.txt”);
// loop thru them
int count = 0;
int fPt;
for (int i = 0; i < txtLines.length; ++i) {
//splits strand points
String[] arrCoords = split(txtLines[i], ‘_’);
Vec3D lastPt = null;
for (int j = 0; j < arrCoords.length; ++j) {
//separates coords
String[] arrToks = split(arrCoords[j], ‘,’);
float xx = Float.valueOf(arrToks[0]);
float yy = Float.valueOf(arrToks[1]);
float zz = Float.valueOf(arrToks[2]);
//create node
Vec3D tmpPt = new Vec3D(xx, yy, zz);
if (j>0) {
Vec3D loc = lastPt.copy();
Vec3D vel = tmpPt.sub(lastPt);
//Agent a= new Agent(loc,vel,true);
//agentPop.add(a);
if(j==1) spawn(loc,vel);
}
lastPt = tmpPt.copy();
}
}
}
/—————————————————–Strand——————————————————–//
class Strand{
ArrayList<VerletSpring> trail;
ArrayList<MapParticle> pts;
float dropNum;
boolean hang;
Strand(Vec3D _loc){
trail = new ArrayList<VerletSpring>();
pts = new ArrayList<MapParticle>();
MapParticle p = new MapParticle(_loc,getCoord(_loc),this);
p.lock();
pts.add(p);
dropNum = 0;
hang = false;
}
void update(Vec3D _loc){
//update the trail geom every 5 moves
if(dropNum%dropRate==0){
if(trail.size()<trailLength){
MapParticle p = new MapParticle(_loc,getCoord(_loc),this);
p.lock();
String coord = getCoord(p);
particleMap.put(coord,p);
MapParticle lastP = pts.get(pts.size()-1);
lastP.unlock();
VerletSpring s = new VerletSpring(pts.get(pts.size()-1),p,(p.distanceTo(lastP)),strandStiffness);
physics.addParticle(p);
physics.addSpring(s);
trail.add(s);
pts.add(p);
}else{
physics.removeSpringElements(trail.get(0));
trail.remove(0);
pts.remove(0);
}
dropNum=0;
}
dropNum++;
}
void addParticle(Vec3D _loc){
//update the trail geom every 5 moves
if(trail.size()<trailLength){
MapParticle p = new MapParticle(_loc,getCoord(_loc),this);
String coord = getCoord(p);
particleMap.put(coord,p);
MapParticle lastP = pts.get(pts.size()-1);
VerletSpring s = new VerletSpring(pts.get(pts.size()-1),p,(p.distanceTo(lastP)),strandStiffness);
physics.addParticle(p);
physics.addSpring(s);
trail.add(s);
pts.add(p);
}
}
String getCoord(Vec3D p){
String s = “”+floor(p.x/gridRes)+floor(p.y/gridRes)+floor(p.z/gridRes);
return s;
}
void run(){
//render agent trail as lines
strokeWeight(1);
float c =1;
if(agentsOn){
for (VerletSpring l : trail){
if(!paused){
l.setStrength(l.getStrength()*0.98);
MapParticle a = (MapParticle) l.a;
if(hang)a.addVelocity(new Vec3D(0,0,-0.09));
a.run();
}
float gs = ((trail.size()-c)/trail.size())*255;
stroke(gs);
line (l.a.x,l.a.y,l.a.z,l.b.x,l.b.y,l.b.z);
c+=1;
}
}
//if hanging look for ground condition or other particles
if(hang){
//check to see if the end of the strand meets some conditions
MapParticle last = pts.get(pts.size()-1);
last.addVelocity(new Vec3D(0,0,-0.09));
last.run();
if(last.closestP!=null){
float d = last.distanceTo(last.closestP);
if(d<2){
print(“yep”);
//make a spring between the two and contract
pts.get(0).unlock();
VerletSpring s = new VerletSpring(last,last.closestP,d,strandStiffness);
physics.addSpring(s);
trail.add(s);
for (VerletSpring spr:trail){
spr.setRestLength(0);
hang = false;
}
}
}
if(last.z<0){
last.lock();
pts.get(0).unlock();
for (VerletSpring spr:trail){
spr.setRestLength(0);
//spr.setStrength(strandStiffness*2);
}
hang = false;
}
}
}
}
/—————————————————–mapParticles——————————————————–//
class MapParticle extends VerletParticle {
String mapCoord;
Strand parent;
int age;
boolean alive;
MapParticle closestP;
MapParticle(Vec3D _loc, String _s,Strand _p) {
super (_loc);
mapCoord = _s;
parent = _p;
age = 0;
alive = true;
closestP = null;
}
void run() {
//get the grid pos and update if necessary
if(alive){
age++;
String newMapCoord = getCoord();
if (newMapCoord != mapCoord) {
particleMap.remove(mapCoord, this);
particleMap.put(newMapCoord, this);
mapCoord = newMapCoord;
}
ArrayList<Vec3D> closest = new ArrayList<Vec3D>();
float minD = 999999;
//attract to neighbouring particles
if (particleMap.getCollection(mapCoord)!=null) {
for (MapParticle p: (ArrayList<MapParticle>)particleMap.getCollection(mapCoord)) {
if(p.parent!=parent){
Vec3D diff = sub(p);
diff.invert();
float d = diff.magnitude();
if(d>0.1){
if (d<minD){
closest.add(diff);
if(closest.size()>numToMove) closest.remove(0);
minD =d;
closestP=p;
}
}
}
}
}
for (Vec3D v:closest){
float d = v.magnitude();
v.scaleSelf(nodeStiffness/d);
addVelocity(v);
}
}
if(age>200){
physics.particles.remove(this);
alive = false;
age = 0;
}
}
String getCoord(){
String s = “”+Math.floor(x/gridRes)+Math.floor(y/gridRes)+Math.floor(z/gridRes);
return s;
}
}
/—————————————————–saving——————————————————–//
void savePts(){
String[] lines = new String[agentPop.size()];
int c=0;
for (int i =0;i<agentPop.size();i++) {
Agent a = (Agent) agentPop.get(i);
lines[c] = “”;
if(a.trail!=null){
for(MapParticle t:a.trail.pts){
lines[c] =lines[c]+ (t.x +”,” + t.y + “,” + t.z + “/”);
}
}
c++;
}
saveStrings(“lines.txt”, lines);
String[] skin = new String[agentPop.size()];
c=0;
for (int i =0;i<agentPop.size();i++) {
Agent a = (Agent) agentPop.get(i);
if(a.pastStrands!=null){
for(Strand s:a.pastStrands){
skin[c] = “”;
for(MapParticle t:s.pts){
skin[c] =skin[c]+ (t.x +”,” + t.y + “,” + t.z + “/”);
}
}
}
c++;
}
saveStrings(“skin.txt”, skin);
}