2016-05-02

Swarm 3D GUI – with a tail

I wrote this short swarm script with GUI interface in Processing about 4 years ago (When I began to code)… Now I figure out lots of code from this script should be improved! For instance, we can implement KDTree later… Hope this code from the previous version will help people who needs or interested in it.

Processing Source Code:

drawLineFish3DUI.pde

//============================================================================
// Name        : drawLineFish3DUI.pde
// Author      : Gene Ting-Chun Kao
// Version     : 2012-7-19
// Copyright   : GNU General Public License
// Description : Swarm 3D with Tail GUI
//============================================================================
 
import toxi.geom.*;
import processing.opengl.*;
import peasy.*; 
import controlP5.*;
import java.util.Calendar;
 
Manage man;
PeasyCam jCam;
ControlP5 jControl;
ArrayList fishes; 
 
PMatrix3D currCameraMatrix;
PGraphics3D g3;
 
int c1 = 0;
int c2 = 0;
int c3 = 0;
boolean attractor = false;
boolean stop = false;
 
void setup() {
  size(1200, 800, OPENGL);
  smooth();
  g3 = (PGraphics3D)g;
 
  jCam = new PeasyCam(this, 100);
  Slider();
 
  man = new Manage(400, 50); 
  man.createFish();
}
 
void draw() {
 
  if (jControl.window(this).isMouseOver()) {
    jCam.setActive(false);
  } 
  else {
    jCam.setActive(true);
  }
 
  background(0);
  man.display();
 
  gui();
}
 
void keyReleased() { 
  if (key == 's' || key == 'S') saveFrame(timestamp()+"_##.png");
}
  
String timestamp() {
  Calendar now = Calendar.getInstance();
  return String.format("%1$ty%1$tm%1$td_%1$tH%1$tM%1$tS", now);
}
 
void Slider() {
   
  jControl = new ControlP5(this);
  //mousePosistion 
  jControl.addSlider("c1",-200,200,10,610,100,10);
  jControl.addSlider("c2",-200,200,10,630,100,10);
  jControl.addSlider("c3",-200,200,10,650,100,10);
   
  jControl.addToggle("attractor", false, 10, 680, 100, 10).setMode(ControlP5.SWITCH);
  jControl.addToggle("stop", false, 10, 715, 45, 10);
   
  jControl.setAutoDraw(false);
 
}
 
void gui() {
  currCameraMatrix = new PMatrix3D(g3.camera);
  camera();
  jControl.draw();
  g3.camera = currCameraMatrix;
}

Fish.pde

//============================================================================
// Name        : Fish.pde
// Author      : Gene Ting-Chun Kao
// Version     : 2012-7-19
// Copyright   : GNU General Public License
// Description : Swarm 3D with Tail GUI
//============================================================================
 
class Fish {
 
  //PROPERTISE
  Vec3D loc; //= new Vec3D(width/2, height/2, 0);
  Vec3D speed = new Vec3D(random(-2, 2), random(-2, 2), random(-2, 2));
  Vec3D acc = new Vec3D();
 
  int num = 1000; 
  float[] x = new float[num];
  float[] y = new float[num];
  float[] z = new float[num];
  int indexPosition = 0;
 
 
  //CONSTRUCTOR
  Fish(Vec3D loc, int num) {
    this.loc = loc;
    this.num = num;
  }
 
  //METHODS
  void run() {
    displayTail();
    display(); 
    swim();
    turnback();
    flock();
    //lineBetween();
  }
 
  void run2() {
    displayTail();
    display(); 
    //2swim();
    //turnback();
    //flock();
    //lineBetween();
  }
 
  void initial() {
    for (int i = 0; i < num; i++) {
      x[i] = loc.x; 
      y[i] = loc.y;
      z[i] = loc.z;
    }
  }
 
  void display() {
    strokeWeight(7);
    stroke(232, 0, 116, 220);
    point(loc.x, loc.y, loc.z);
 
    strokeWeight(15);
    stroke(255, 255, 0);
    if (attractor == true) {
      stroke(0, 255, 0);
      strokeWeight(20);
    }
    point(c1, c2, c3);
  }
 
  void displayTail() {
 
    if (stop == false) { // draw tail if the stop bottum is not pressed
      x[indexPosition] = loc.x;
      y[indexPosition] = loc.y;
      z[indexPosition] = loc.z;
      indexPosition = (indexPosition + 1) % num;
    }
 
    for (int i = 20; i < num; i++) {
      int pos = (indexPosition + i) % num;
      int posb = (indexPosition + (i-10)) % num;
      if (i%10 == 1) {
        stroke(0, 255, 255, 170);
        strokeWeight(5);
        point(x[pos], y[pos], z[pos]);
        stroke(255, 100);
        strokeWeight(1);
        line(x[pos], y[pos], z[pos], x[posb], y[posb], z[posb]);
      }
    }
  }
 
  void swim() {
    speed.addSelf(acc);
    speed.limit(2);
    loc.addSelf(speed);
    acc.clear();
  }
 
  void turnback() {
    if (loc.x > 200 || loc.x < -200) {
      speed.x *= -1.5;
    }
    if (loc.y > 200 || loc.y < -200) {
      speed.y *= -1.5;
    }
    if ((loc.z > 200) || (loc.z < -200)) {
      speed.z *= -1.5;
    }
  }
 
  void fishbox() {
    stroke(255);
    strokeWeight(1);
    noFill();
    box(400);
  }
 
  float getLocX() {
    return loc.x;
  }
 
  float getLocY() {
    return loc.y;
  }
 
  Vec3D getVel() {
    return speed;
  }
  Vec3D getAcc() {
    return acc;
  }
  Vec3D getLoc() {
    return loc;
  }
  void setLoc(Vec3D loc) {
    this.loc = loc;
  }
  void setVel(Vec3D vel) {
    this.speed = speed;
  }
  void setAcc(Vec3D acc) {
    this.acc = acc;
  }
 
 
  void flock() {
 
    separate(4);
    cohesion(0.001);
    align(0.1);
  }
 
  void align(float magnitude) {
    Vec3D steer = new Vec3D();
    int count = 0;
 
    for (int i = 0; i < fishes.size(); i++) {
      Fish other = (Fish) fishes.get(i);
 
      float distance = loc.distanceTo(other.loc);
      if (distance > 0 && distance < 40) {
 
        steer.addSelf(other.speed);
        count++;
      }
    }
 
    if (count > 0) {      
      steer.scaleSelf(1.0/count);
    }
 
    steer.scaleSelf(magnitude);
 
    acc.addSelf(steer);
  }
 
 
  void cohesion(float magnitude) {
    Vec3D sum = new Vec3D();
    int count = 0;  
 
    for (int i = 0; i < fishes.size(); i++) {
      Fish other = (Fish) fishes.get(i);
 
      float distance = loc.distanceTo(other.loc);
      if (distance > 0 && distance < 60) {
 
        sum.addSelf(other.loc);
        count++;
      }
    }  
    if (count > 0) {       
      sum.scaleSelf(1.0/count);
    }
 
    Vec3D steer = sum.sub(loc);
    steer.scaleSelf(magnitude);
    acc.addSelf(steer);
  }
 
 
  void separate(float maganitude) {
 
    Vec3D steer = new Vec3D();
    int count = 0;
 
    for (int i = 0; i < fishes.size(); i++) {
      Fish other = (Fish) fishes.get(i);
 
      float distance = loc.distanceTo(other.loc);
      if (distance > 0 && distance < 30) {
 
        Vec3D diff = loc.sub(other.loc);
        diff.normalizeTo(1.0/distance);
 
        steer.addSelf(diff);
        count++;
      }
    }
 
    if (count > 0) {
      steer.scaleSelf(1.0/count);
    }   
 
    steer.scaleSelf(maganitude);
    acc.addSelf(steer);
  }
   
  void lineBetween() {
    for (int i = 0; i < fishes.size(); i++) {
      Fish other = (Fish) fishes.get(i);
      float distance = loc.distanceTo(other.loc);
      if (distance > 0 && distance < 80) {
        stroke(255, 0, 0, 100);
        strokeWeight(0.1);
        line(loc.x, loc.y, loc.z, other.loc.x, other.loc.y, other.loc.z);
      }
    }
  }
}

Manage.pde

//============================================================================
// Name        : Manage.pde
// Author      : Gene Ting-Chun Kao
// Version     : 2012-7-19
// Copyright   : GNU General Public License
// Description : Swarm 3D with Tail GUI
//============================================================================
 
class Manage {
 
  //Propertise
  Vec3D loc;
  Vec3D vel;
  Vec3D acc;
  int tail; 
  Fish myfish = new Fish(loc, tail);
  int num;
 
  //Constructor
  Manage(int num, int tail) {
    this.tail = tail;
    this.num = num; 
    fishes = new ArrayList();
  }
 
  // Methods
  void createFish() {
    for (int i = 0; i < num; i++) {
      Vec3D loc = new Vec3D(random(-200, 200), random(-200, 200), random(-200, 200));
      Vec3D vel = new Vec3D(random(-0.2, 0.2), random(-0.2, 0.2), random(-0.2, 0.2));
      Vec3D acc = new Vec3D(0, 0, 0);
      Fish myfish = new Fish(loc, tail);
      fishes.add(myfish);
    }
     
    for (int i = 0; i < fishes.size(); i++) {
      Fish a = (Fish)fishes.get(i); 
      a.initial();
    }
     
  }
 
  void display() {
 
    myfish.fishbox();
 
    for (int i = 0; i < fishes.size(); i++) {
      Fish myfish = (Fish) fishes.get(i);     
      //println(fishCollection.size());
 
      if (attractor == true) {
        Vec3D m = new Vec3D(c1, c2, c3);
        Vec3D diff = m.subSelf(myfish.getLoc()); 
        Vec3D velPlus = diff.addSelf(myfish.getVel());
        Vec3D accPlus = velPlus.addSelf(myfish.getAcc());
        accPlus.normalizeTo(0.1);
        myfish.setAcc(diff);
      }
      if (stop == false) {
        myfish.run();
      } 
      else {
        myfish.run2();
      }
    }
  }
}