/*
* Copyright (c) 2012 Gwyllim Jahn
* http://scripts.crida.net/gh
* Developed By Gwyllim Jahn, Mark Kowalyov and ZHU Teng Fei
* 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.
*
*/
//—————————————————–strata ——————————————————–//
import processing.video.*;
import processing.dxf.*;
import processing.opengl.*;
import javax.media.opengl.*;
import peasy.org.apache.commons.math.*;
import peasy.*;
import peasy.org.apache.commons.math.geometry.*;
import toxi.math.conversion.*;
import toxi.geom.*;
import toxi.geom.mesh2d.*;
import toxi.util.datatypes.*;
import toxi.util.events.*;
import toxi.geom.mesh.subdiv.*;
import toxi.geom.mesh.*;
import toxi.util.*;
import toxi.math.noise.*;
import toxi.volume.*;
import toxi.math.*;
import controlP5.*;
import toxi.color.*;
//——————————Volume Params
int DX=300;
int DY=300;
int DZ=300;
OscillatingVolume volumeV;
VolumetricBrush brushV;
Vec3D SCALE=new Vec3D(DX,DY,DZ);
int sX = int(SCALE.x/DX);
int sY = int(SCALE.y/DY);
int sZ = int(SCALE.z/DZ);
//——————————Agent params
//==============================
//Trail length and agent speed – obviously if you want
//to run the agents for ages, you will need longer trails.
//agent speed also has a significant effect on the root geom.
int trailLength = 200;
float agentSpeed = 1;
//ammount to confine to a particular threshold
float confineToThreshold = 0.1;
//distance between trail points
int dropSpacing = 2;
//number of agents
int numAgents = 500;
//if the agent cant find a value in its neighbouring
//voxels that is less than this number from the ideal
//threshold (by default 0.5) =dead. LOWER=MORE DEATH
float cutoffToDie = 0.01;
//if the agent finds a value in its neighbouring
//voxels that is less than this number from the ideal
//threshold (by default 0.5), then it starts counting
//towards branching LOWER=LESS BRANCHING
float cutoffToThinkAboutBranching = 0.00015;
//The agent needs to have been within its branching cutoff
//for this number of steps, then it branches.
int numEasyMovesBeforeBranch =10;
//number of new agents to make.
int splitIntoAgents=3;
//==============================
//parameters for how the agents modify the field…
//how big the brush is that modifies the diffusion f parameter.
float rootRadius = 2;
int searchRad = 3;
//density value for the agents – a negative
//number removes material from the diffusion,
//numbers closer to 0 mean that more agents need to fly
//down a similar path to actually remove the material …
float density = -0.02;
float noiseScale = 2;
Boolean drawAgents = true;
Boolean saveRaw = false;
MovieMaker mm;
Boolean filming =true;
//——————————Diffusion params
int NUM_ITERATIONS = 10;
ControlP5 controlP5;
ControlWindow controlWindow;
PeasyCam cam;
World world;
NoiseInterpolator nI = new NoiseInterpolator();
void setup() {
size(500,500,OPENGL);
cam = new PeasyCam(this,180);
//setup voxels
volumeV=new OscillatingVolume(SCALE,DX,DY,DZ);
brushV=new RoundBrush(volumeV,5);
volumeV.setLandscape();
setupP5();
world = new World();
world.spawn();
}
void draw() {
background(255);
world.update();
volumeV.drawPoints();
}
void keyPressed(){
if(key == ‘q’){
GsaveData(volumeV,”E:/”+day()+”_”+hour()+”_”+minute()+”_”+second()+”voxels.raw”);
}
if(key == ‘w’){
savePts();
}
if(key == ‘e’){
saveParams();
}
if(key == ‘ ‘){
mm.finish();
}
}
//—————————————————–Agent ——————————————————–//
//simple agent class to interact with the data
//field and other agents
class Agent {
Vec3D loc,vel,origLoc;
ArrayList trail;
float gVal;
float dropNum;
boolean alive;
int id;
float aX,aY,aZ,lastBest;
int easy;
Agent(Vec3D _loc, Vec3D _vel,int _id){
loc = _loc;
vel = _vel;
trail = new ArrayList();
gVal = 255;
dropNum = 0;
alive = true;
id = _id;
easy = 0;
lastBest = 0;
}
void run(){
if (alive){
getGridPos();
pushPullToData(true,0.5);
//branch();
volBrushLocation();
update();
}
render();
}
//————————————————————————————-
//Behaviour for avoiding the worst (highest greyscale value) data within a proximity,
//and interpolating the agent velocity away that point.
//————————————————————————————-
void getGridPos(){
aX = constrain(loc.x,0,SCALE.x);
aX = map(aX,0,SCALE.x,0,DX);
aY = constrain(loc.y,0,SCALE.y);
aY = map(aY,0,SCALE.y,0,DY);
aZ = constrain(loc.z,0,SCALE.z);
aZ = map(aZ,0,SCALE.z,0,DZ);
if(loc.x>SCALE.x || loc.y >SCALE.y || loc.z>SCALE.z)vel.invert();
if(loc.x }
void pushPullToData(Boolean push, float t){
float bestThreshDiff = 100;
Vec3D bestThreshPt = new Vec3D(0,0,0);
//iterate over neighbouring grid pos
for (int i =-searchRad;i for (int j =-searchRad;j for (int k =-searchRad; k=0&&(aX+i)=0&&(aY+j)=0&&(aZ+k)0.0001 &&val float threshVal = abs(val-t);
if(threshVal cutoffToDie){
alive=false;
print(“dead”);
}
//if in a good posy, see if we should branch
if(bestThreshDiff easy++;
}else{
easy = 0;
}
}
Boolean moveToThreshold(int searchRad){
getGridPos();
for (int i =-searchRad;ifor (int j =-searchRad;jfor (int k =-searchRad;k=0&&(aX+i)=0&&(aY+j)=0&&(aZ+k)=1&&valnumEasyMovesBeforeBranch){
easy =0;
for (int i = 1;i0) brushV.drawAtGridPos(aX+5,aY,aZ,-density*2);
// if(aZ-5>0) brushV.drawAtGridPos(aX,aY,aZ-5,-density*2);
// brushV.drawAtGridPos(aX,aY,aZ,density);
}
//————————————————————————————-
//Functions for managing trails and rendering the agent.
//————————————————————————————-
void update(){
//move the agent randomly
vel.normalizeTo(agentSpeed);
//vel.interpolateToSelf(new Vec3D (0,0,1),vert);
loc.addSelf(vel);
//update the trail geom every 5 moves
if(dropNum%dropSpacing==0){
if(trail.size() trail.add(new Vec3D(loc.x, loc.y, loc.z));
}else{
trail.remove(0);
}
dropNum=0;
}
dropNum++;
}
void render(){
//render agent trail as lines
Vec3D ls = null;
for (Vec3D l : trail){
if(ls !=null){
stroke(0);
line (l.x,l.y,l.z,ls.x,ls.y,ls.z);
}
ls = l;
}
}
}
//—————————————————–Controllers ——————————————————–//
void setupP5 (){
controlP5 = new ControlP5(this);
controlP5.setAutoDraw(false);
controlWindow = controlP5.addControlWindow(“controlP5window”,100,100,400,300);
controlWindow.hideCoordinates();
controlWindow.setTitle(“Spring GUI”);
//—————————————————–Oscillating Volumes ——————————————————–//
class OscillatingVolume extends VolumetricSpaceArray {
int z;
public OscillatingVolume (Vec3D _S, int _DX, int _DY,int _DZ) {
super(_S,_DX,_DY,_DZ);
z = 0;
}
//—————————
void setLandscape(){
for (int i=0;ifor (int j =0;jfor (int k=0;k
//create the noise field – dividing k steps the field.
//used to emphasise the difference generated by the agents
//setVoxelAt(i,j,k,nI.getValType(i,j,k/4));
//use this function to make the entire field a particular type
setVoxelAt(i,j,k,nI.getValType(i,j,k/4,0));
}
}
}
}
void drawPoints() {
int r=4;
for(int i=0;i for(int j=0;j for(int k=0;k=90&&v stroke(100);
line(i,j,k,i,j,k+1);
}
}
}
}
}
}
//—————————————————–Voxel Functions ——————————————————–//
public void GsaveData(OscillatingVolume v,String fn) {
print(“saving volume data…”);
int c=0;
int tot = v.getData().length;
try {
BufferedOutputStream ds = new BufferedOutputStream(new FileOutputStream(fn));
// ds.writeInt(volumeData.length);
for (float element : v.getData()) {
if(element ds.write((int)(element*100));
}
ds.flush();
ds.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//—————————————————–World——————————————————–//
//Class to manage addition and subtraction of agents from
//the environment
class World {
ArrayListagentPop;
ArrayList newPop;
World(){
agentPop = new ArrayList();
newPop = new ArrayList();
}
//————————–main function
void update(){
newPop = new ArrayList();
runAgents();
if(newPop.size()>0) addAgents();
}
void runAgents(){
int c = 0;
for (Agent a :agentPop){
a.run();
}
}
void addAgents(){
agentPop.addAll(newPop);
}
void spawn(){
newPop = new ArrayList();
agentPop = new ArrayList();
for (int i=0;i // Vec3D loc = new Vec3D(random(0,gW*gRes),random(0,gH*gRes),0);
Vec3D loc = new Vec3D(random(0,DX),random(0,DY),SCALE.z);
Vec3D vel = new Vec3D(0,0,-3);
Agent a = new Agent(loc,vel,i);
a.origLoc = loc.copy();
agentPop.add(a);
}
}
void spawnOnThreshold(){
newPop = new ArrayList();
agentPop = new ArrayList();
for (int i=0;i50) searching = false;
}
}
}
}
//—————————————————–Noise Interpolator ——————————————————–//
class NoiseInterpolator {
int aLimit,bLimit,cLimit,dLimit,eLimit;
float aScale,bScale,cScale,dScale,eScale;
float aContrast, bContrast, cContrast, dContrast,eContrast;
float aCompression,bCompression,cCompression,dCompression,eCompression;
NoiseInterpolator(){
aLimit = 0;
aScale = 1.75;
aContrast = 0.2;
aCompression = 1;
bLimit = (int)SCALE.z/4;
bScale = 4;
bContrast = 0;
bCompression = 3;
cLimit = (int)SCALE.z/2;
cScale = 7;
cContrast = 0.35;
cCompression = 8;
dLimit = (int)(SCALE.z/4)*3;
dScale = 4;
dContrast = 0;
dCompression = 1;
eLimit = (int)SCALE.z;
eScale = 10;
eContrast = 0;
eCompression = 1;
}
float getVal(int x, int y, int z){
int type = floor(((float)z/DZ)*4);
float f = ((float)z%(DZ/4));
f = (f/(DZ/4));
float ns = noiseScale;
float nContrast = 0;
float nCompression =1;
if(type == 0){
//between a and b
ns = aScale + ( bScale – aScale ) * f;
nContrast = aContrast + ( bContrast – aContrast ) * f;
nCompression = aCompression + ( bCompression – aCompression ) * f;
}else if (type ==1){
//between b and c
ns = bScale + ( cScale – bScale ) * f;
nContrast = bContrast + ( cContrast – bContrast ) * f;
nCompression = bCompression + ( cCompression – bCompression ) * f;
}
else if (type ==2){
//between c and d
ns = cScale + ( dScale – cScale ) * f;
nContrast = cContrast + ( dContrast – cContrast ) * f;
nCompression = cCompression + ( dCompression – cCompression ) * f;
}
else if (type ==3){
//between d and …
ns = dScale + ( eScale – dScale ) * f;
nContrast = dContrast + ( eContrast – dContrast ) * f;
nCompression = dCompression + ( eCompression – dCompression ) * f;
}
ns = ns/100;
float n = noise(x*ns,y*ns,z*ns*nCompression);
n = (map(n,nContrast,1-nContrast,0,1));
return n;
}
float getValType(int x, int y, int z,int type){
float ns = noiseScale;
float nContrast = 0;
float nCompression =1;
if(type == 0){
//between a and b
ns = aScale;
nContrast = aContrast;
nCompression = aCompression;
}else if (type ==1){
//between b and c
ns = bScale;
nContrast = bContrast;
nCompression = bCompression;
}
else if (type ==2){
//between c and d
ns = cScale;
nContrast = cContrast;
nCompression = cCompression;
}
else if (type ==3){
//between d and …
ns = dScale;
nContrast = dContrast ;
nCompression = dCompression;
}
ns = ns/100;
float n = noise(x*ns,y*ns,z*ns*nCompression);
n = (map(n,nContrast,1-nContrast,0,1));
return n;
}
}
//—————————————————–saving ——————————————————–//
void savePts(){
String[] lines = new String[world.agentPop.size()];
int c=0;
for (int i =0;i Agent a = (Agent) world.agentPop.get(i);
lines[c] = “”;
for(Vec3D t:a.trail){
lines[c] =lines[c]+ (t.x +”,” + t.y + “,” + t.z + “/”);
}
c++;
}
saveStrings(“G:/ncertainties/export/”+day()+”_”+hour()+”_”+minute()+”_”+second()+”lines.txt”, lines);
}
void saveParams(){
String[] lines = new String[23];
lines[0] = “agentSpeed=”+agentSpeed;
lines[1] = “trailLength=”+trailLength;
lines[2] = “confineToThreshold=”+confineToThreshold;
lines[3] = “dropSpacing=”+dropSpacing;
lines[4] = “numAgents=”+numAgents;
lines[5] = “cutoffToDie=”+cutoffToDie;
lines[6] = “cutoffToThinkAboutBranching=”+cutoffToThinkAboutBranching;
lines[7] = “numEasyMovesBeforeBranch=”+numEasyMovesBeforeBranch;
lines[8] = “splitIntoAgents=”+splitIntoAgents;
lines[10] = “rootRadius=”+rootRadius;
lines[11] = “density=”+density;
lines[20] = “DX=”+DX;
lines[21] = “DY=”+DY;
lines[22] = “DZ=”+DZ;
saveStrings(“G:/ncertainties/export/”+day()+”_”+hour()+”_”+minute()+”_”+second()+”paramaters.txt”, lines);
}