(n)certainties RMIT-UTS Spring 012

(n)certainties RMIT-UTS Spring 012 header image 3

The Opus of Caspar Questel_Coding

/*
* 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);
}