The geometry of the agents is always a simple 3D sphere of a radius of 3
             
             
              
             
             
              Here is the main script with the super class and one of the subclasses. The rest are similar.
             
             
              I hope it helps. :(
             
             
              
             
             
              
             
             
              import peasy.org.apache.commons.math.*;  // imports all 3D related libraries
             
             
              import peasy.*;
             
             
              import peasy.org.apache.commons.math.geometry.*;
             
             
              import processing.opengl.*;
             
             
              
             
             
              PeasyCam cam;
             
             
              PMatrix3D currCameraMatrix;
             
             
              PGraphics3D g3;
             
             
              
             
             
              float worldSize = 300;  // the space - rendered as a cube - limiting agents movement
             
             
              
             
             
              StopWatchTimer sw;  // a visual timer-clock implementation on canvas
             
             
              int time;  // a counter for time triggering events
             
             
              int wait = 1000;  // 1 second
             
             
              
             
             
              Facilities work;  // wondering agent -- represents (W)
             
             
              Facilities retail;  // wondering agent -- represents (R)
             
             
              Facilities school;  // wondering agent -- represents (S)
             
             
              Facilities leisure;  // wondering agent -- represents (L)
             
             
              
             
             
              ArrayList <Capsule> agents;
             
             
              
             
             
              float d = 25;
             
             
              
             
             
              int counter=0;  // counter inception
             
             
              int temp=0;
             
             
              
             
             
              boolean animate = true;  // boolean for pausing the animation sequence
             
             
              
             
             
              void setup() {
             
             
                
             
             
                size(600,600,OPENGL);
             
             
                cam = new PeasyCam(this, 300);
             
             
                cam.lookAt(150, 150, 300);
             
             
                cam.setMinimumDistance(10);
             
             
                cam.setMaximumDistance(1500);
             
             
                
             
             
                time = millis();  // store the current time
             
             
                
             
             
                smooth();  // setup of visual time clock
             
             
                println (millis());
             
             
                sw = new StopWatchTimer();
             
             
                sw.start(); 
             
             
                
             
             
                // creating the facilities
             
             
                work = new Facilities(50,50,50);  // generates a hypothetic invisible agent (W)
             
             
                retail = new Facilities(30,30,30);  // generates a hypothetic invisible agent (R)
             
             
                school = new Facilities(240,240,240);  // generates a hypothetic invisible agent (S)
             
             
                leisure = new Facilities(90,90,90);  // generates a hypothetic invisible agent (L)
             
             
                
             
             
                agents = new ArrayList<Capsule>();  // creating the agents
             
             
                
             
             
                // setting the emitter in random positions for each group
             
             
                  for (int i = 0; i < 115; i++) {
             
             
                    if      (i < 20)  agents.add(new MW1(150,150,150,color(255,0,0),i));    // Red
             
             
                    else if (i < 45)  agents.add(new FW1(100,100,100,color(0,255,0),i));    // Green
             
             
                    else if (i < 65)  agents.add(new MW2(200,200,200,color(0,255,255),i));  // Cyan
             
             
                    else if (i < 85)  agents.add(new FnW2(80,80,80,color(0,155,0),i));      // dark Green
             
             
                    else if (i < 95)  agents.add(new MW3(130,130,130,color(255,255,0),i));  // Yellow
             
             
                    else if (i < 105) agents.add(new FnW3(60,60,60,color(255,0,255),i));    // Purple
             
             
                    else              agents.add(new CS3(10,10,10,color(0,0,255),i));       // Blue
             
             
                  }
             
             
              }
             
             
              
             
             
              //--------------configuring the canvas & the counter-------------
             
             
              
             
             
              void draw() {
             
             
                background(255);
             
             
                time();  // reference to the visual timer
             
             
                
             
             
                displayWorldCenter();
             
             
                
             
             
                noLights();
             
             
                cam.beginHUD();
             
             
                cam.endHUD();
             
             
                
             
             
                cam.setMouseControlled(true);
             
             
                if(mouseY<80) {
             
             
                  cam.setMouseControlled(false);
             
             
                } 
             
             
                
             
             
                // check the difference between now and the previously stored time is greater than the wait interval
             
             
                if (animate) {
             
             
                  if(millis() - time >= wait){
             
             
                    println(counter);// if it is, do something
             
             
                      temp=counter;
             
             
                      time = millis();// also update the stored time
             
             
                      counter++; // counter augmentation
             
             
                    
             
             
                    if(counter >180){  // check whether time exceeds 180 sec. aka 24:00 hours - enables looping
             
             
                    counter=0; 
             
             
                    }
             
             
                  }
             
             
                }
             
             
                  
             
             
                //-------------------------------------------------------------
             
             
                
             
             
                work.Default();  // main-basic functions of (W) facility
             
             
                retail.Default();  // main-basic functions of (R) facility
             
             
                school.Default();  // main-basic functions of (S) facility
             
             
                leisure.Default();  // main-basic functions of (L) facility
             
             
                
             
             
                PVector vectorOfwork = new PVector(work.location.x, work.location.y, work.location.z);  // creates a vector that connects all individual agents with the (W) facility
             
             
                PVector vectorOfretail = new PVector(retail.location.x, retail.location.y, retail.location.z);  // creates a vector that connects all individual agents with the (R) facility
             
             
                PVector vectorOfschool = new PVector(school.location.x, school.location.y, school.location.z);  // creates a vector that connects all individual agents with the (S) facility
             
             
                PVector vectorOfleisure = new PVector(leisure.location.x, leisure.location.y, leisure.location.z);  // creates a vector that connects all individual agents with the (L) facility
             
             
                
             
             
                int i = 0;  // i & j make sure that each agent returns to the family it belongs
             
             
                int j = 0;
             
             
                
             
             
                for (Capsule agent : agents) {  // instancing - creating objects
             
             
                  agent.display();
             
             
                  
             
             
                  if (animate) {
             
             
                    
             
             
                  agent.boundaries();  // basic behavior for ALL the agents
             
             
                  agent.update();
             
             
                  agent.wander();
             
             
                  agent.wander3D();
             
             
                  agent.separateSpecial(agents);  // global separation that affects ALL the agents
             
             
                   
             
             
                    if (counter>0 && counter<=60) {
             
             
                      
             
             
                      if (agent instanceof FnW2){  // females attach&follow males - couples
             
             
                        agent.arrive( agents.get(i-20).location ); 
             
             
                      }
             
             
                        else if (agent instanceof FnW3) {  // females attach&follow males - 3 member family
             
             
                          agent.arrive( agents.get(i-10).location );
             
             
                        }
             
             
                        else if (agent instanceof CS3) {  // children attach&follow females - 3 member family
             
             
                          agent.arrive( agents.get(i-10).location );
             
             
                        }
             
             
                        
             
             
                      i++;
             
             
                      
             
             
                    }
             
             
                    
             
             
                    if (counter>60 && counter<=120) {  // time reference to 6.00-14.00 hours
             
             
                      agent.separate(agents);
             
             
                      
             
             
                      if (agent instanceof MW1){
             
             
                        agent.arrive( vectorOfwork ); 
             
             
                      }
             
             
                        else if (agent instanceof MW2) {
             
             
                          agent.arrive( vectorOfwork );
             
             
                        }  
             
             
                        else if (agent instanceof MW3) {
             
             
                          agent.arrive( vectorOfwork );
             
             
                        }  
             
             
                        else if (agent instanceof FW1) {
             
             
                          agent.arrive( vectorOfwork );
             
             
                        }  
             
             
                        else if (agent instanceof FnW2) {
             
             
                          agent.arrive( vectorOfretail );
             
             
                        }  
             
             
                        else if (agent instanceof FnW3) {
             
             
                          agent.arrive( vectorOfretail );
             
             
                        }  
             
             
                        else if (agent instanceof CS3) {
             
             
                          agent.arrive( vectorOfschool );
             
             
                        }  
             
             
                    }
             
             
                     
             
             
                    if (counter>120 && counter<=180) {
             
             
                      
             
             
                      if (agent instanceof FnW2){  // females attach&follow males - couples
             
             
                        agent.arrive( agents.get(j-20).location ); 
             
             
                      }
             
             
                        else if (agent instanceof FnW3) {  // females attach&follow males - 3 member family
             
             
                          agent.arrive( agents.get(j-10).location );
             
             
                        }
             
             
                        else if (agent instanceof CS3) {  // children attach&follow females - 3 member family
             
             
                          agent.arrive( agents.get(j-10).location );
             
             
                        }
             
             
                        
             
             
                        j ++;
             
             
                        
             
             
                      }
             
             
                  }
             
             
                }
             
             
              }
             
             
                
             
             
              void displayWorldCenter(){
             
             
                pushMatrix();
             
             
                translate(150,150,150);
             
             
                stroke(120); noFill();  // stroke of the cube (box)
             
             
                box(worldSize);
             
             
                stroke(#209889); noFill();  // stroke of the ellipses(center)
             
             
                ellipse(0,0,20,20);
             
             
                rotateY(radians(90));
             
             
                ellipse(0,0,20,20);
             
             
                rotateZ(radians(90));
             
             
                ellipse(0,0,20,20);
             
             
                rotateX(radians(90));  
             
             
                rotateY(radians(90));
             
             
                ellipse(0,0,20,20);
             
             
                popMatrix();
             
             
              }
             
             
              
             
             
                //-------------------------------------------------------------
             
             
              
             
             
              void time() {  // visual configuration for the timer-clock  
             
             
                fill(#000000);
             
             
                textAlign(CENTER);
             
             
                text(nf(sw.hour(), 2)+":"+nf(sw.minute(), 2)+":"+nf(sw.second(), 2)+":"+nf(sw.hundrensec(), 2), 260, 290);
             
             
              }
             
             
              
             
             
              void keyPressed(){
             
             
                if (key=='a') animate = true;
             
             
                else if (key=='s') animate = false;
             
             
              } 
             
             
              
             
             
              
             
             
              
             
             
              abstract class Capsule {  //the super-class that defines the chararacteristics of the agents
             
             
              
             
             
                PVector location;
             
             
                PVector velocity;
             
             
                PVector acceleration;
             
             
                float r;  // the radius of the circles-spheres/ agents
             
             
                float wandertheta, wanderphi, wanderpsi;
             
             
                float maxforce;    // Maximum steering force
             
             
                float maxspeed;    // Maximum speed
             
             
                color fillColor;  // differentiation of agent types are based on complementary coloring
             
             
                int name;  // gives an ID - number to each different agent
             
             
                
             
             
                Capsule(float x, float y, float z, color c, int nam) {  // the class constructor
             
             
                  acceleration = new PVector(0,0,0);
             
             
                  velocity = new PVector(0,0,0);
             
             
                  location = new PVector(x,y,z);
             
             
                  r = 6;
             
             
                  wandertheta = 0;
             
             
                  wanderphi = 0;
             
             
                  wanderpsi = 0;
             
             
                  maxspeed = 0.5;
             
             
                  maxforce = 0.05;
             
             
                  fillColor = c;
             
             
                  name = nam;
             
             
                }
             
             
               
             
             
                void update() {  // Method to update location
             
             
                  velocity.add(acceleration);  // Update velocity
             
             
                  velocity.limit(maxspeed);  // Limit speed
             
             
                  location.add(velocity);  // Reset accelertion to 0 each cycle
             
             
                  acceleration.mult(0);
             
             
                }
             
             
              
             
             
                void wander() {  // Method that makes the agent float into 2D space
             
             
                  float wanderR = 25;  // Radius for our "wander circle"
             
             
                  float wanderD = 200;  // Distance for our "wander circle"
             
             
                  float change = 0.05;
             
             
                  wandertheta += random(-change,change);  // Randomly change wander theta
             
             
              
             
             
                  // calculating the new location to steer towards on the wander circle
             
             
                  PVector circleloc = velocity.get();    // Start with velocity
             
             
                  circleloc.normalize();   // Normalize to get heading
             
             
                  circleloc.mult(wanderD);  // Multiply by distance
             
             
                  circleloc.add(location);  // Make it relative to boid's location
             
             
                  
             
             
                  float h = velocity.heading2D();  // We need to know the heading to offset wandertheta
             
             
              
             
             
                  PVector circleOffSet = new PVector(wanderR*cos(wandertheta+h),wanderR*sin(wandertheta+h));
             
             
                  PVector target = PVector.add(circleloc,circleOffSet);
             
             
                  seek(target);
             
             
                }  
             
             
                
             
             
                PVector wander3D() {
             
             
                   float wanderR = 30.0;         // Radius for our "wander circle"
             
             
                   float wanderD = 30.0;         // Distance for our "wander circle"
             
             
                   float change = 0.5;
             
             
                 
             
             
                   wandertheta += random(-change, change);     // Randomly change wander theta
             
             
                   wanderphi += random(-change, change);       // Randomly change wander phi
             
             
                   wanderpsi += random(-change, change);       // Randomly change wander psi
             
             
                   
             
             
                   PVector circleloc = velocity.get();  // Start with velocity
             
             
                   circleloc.normalize();            // Normalize to get heading
             
             
                   circleloc.mult(wanderD);          // Multiply by distance
             
             
                   circleloc.add(location);               // Make it relative to boid's location
             
             
              
             
             
                   PVector circleOffSet = new PVector(wanderR*cos(wandertheta),wanderR*sin(wanderphi), wanderR*cos(wanderpsi));
             
             
                   PVector target = PVector.add(circleloc,circleOffSet);
             
             
                   return target; 
             
             
                }
             
             
              
             
             
                void applyForce(PVector force) {  // Newton's second law; We could add mass here if we want A = F / M
             
             
                  acceleration.add(force);
             
             
                }
             
             
              
             
             
              
             
             
                // A method that calculates and applies a steering force towards a target
             
             
                // STEER = DESIRED MINUS VELOCITY
             
             
                void seek(PVector target) {
             
             
                  PVector desired = PVector.sub(target,location);  // A vector pointing from the location to the target
             
             
                  desired.normalize();  // Normalize desired and scale to maximum speed
             
             
                  desired.mult(maxspeed);
             
             
                  PVector steer = PVector.sub(desired,velocity);  // Steering = Desired minus Velocity
             
             
                  steer.limit(maxforce);  // Limit to maximum steering force
             
             
                  applyForce(steer);
             
             
                }
             
             
                
             
             
                // Method that lowers the speed of the agent by the time he reaches the target - see: "buffer zone"
             
             
                void arrive(PVector target) {
             
             
                  PVector desired = PVector.sub(target,location);  // A vector pointing from the location to the target
             
             
                  float d = desired.mag();
             
             
                  desired.normalize();  // Normalize desired and scale with arbitrary damping within 100 pixels
             
             
                  if (d < r) {
             
             
                    float m = map(d,0,15,0,maxspeed);
             
             
                    desired.mult(m);
             
             
                  } else {
             
             
                    desired.mult(maxspeed);
             
             
                  }
             
             
              
             
             
                  PVector steer = PVector.sub(desired,velocity);  // Steering = Desired minus Velocity
             
             
                  steer.limit(5*maxforce);  // Limit to maximum steering force
             
             
                  applyForce(steer);
             
             
                }
             
             
                
             
             
                void display() {  // Draws an ellipse that represents an agent-capsule
             
             
                  fill(fillColor);
             
             
                  noStroke();
             
             
                  pushMatrix();
             
             
                  translate(location.x, location.y, location.z);
             
             
                  sphere(3);
             
             
                  popMatrix();
             
             
                }
             
             
                
             
             
                // Method that checkes the maximum floating range of the agents - bouncing on the edges of the cube
             
             
                void boundaries() {
             
             
              
             
             
                  if (location.x < 0 || location.x > worldSize) {
             
             
                    velocity.x *=-1;
             
             
                  }  
             
             
              
             
             
                  if (location.y < 0 || location.y > worldSize) {
             
             
                    velocity.y *=-1;
             
             
                  }  
             
             
                  
             
             
                  if (location.z < 0 || location.z > worldSize) {
             
             
                    velocity.z *=-1;
             
             
                  }  
             
             
                }
             
             
                
             
             
                // Method that separates the agents from one-another -- see: "buffer zone"
             
             
                void separate (ArrayList<Capsule> agent) {
             
             
                  float desiredseparation = r*4;  // 4*r = separation ONLY for wandering
             
             
                  PVector sum = new PVector();
             
             
                  int count = 0;
             
             
                  
             
             
                  // For every agent in the system, check if it's too close
             
             
                  for (Capsule v : agent) {
             
             
                    float d = PVector.dist(location, v.location);
             
             
                    
             
             
                    // If the distance is greater than 0 and less than an arbitrary amount (0 when you are yourself)
             
             
                    if ((d > 0) && (d < desiredseparation)) {
             
             
                      
             
             
                      // Calculate vector pointing away from neighbor
             
             
                      PVector diff = PVector.sub(location, v.location);
             
             
                      diff.normalize();
             
             
                      diff.div(d);        // Weight by distance
             
             
                      sum.add(diff);
             
             
                      count++;            // Keep track of how many
             
             
                    }
             
             
                  }
             
             
                  // Average -- divide by how many
             
             
                  if (count > 0) {
             
             
                    sum.div(count);
             
             
                    sum.normalize();  // Our desired vector is the average scaled to maximum speed
             
             
                    sum.mult(maxspeed);
             
             
                    
             
             
                    // Implement Reynolds: Steering = Desired - Velocity
             
             
                    PVector steer = PVector.sub(sum, velocity);
             
             
                    steer.limit(maxforce);
             
             
                    applyForce(steer);
             
             
                  }
             
             
                }  
             
             
                
             
             
                // Method that separates the agents from one-another -- see: "buffer zone"
             
             
                void separateSpecial (ArrayList<Capsule> agent) {
             
             
                  float desiredseparation = r;  //
             
             
                  PVector sum = new PVector();
             
             
                  int count = 0;
             
             
                  
             
             
                  // For every agent in the system, check if it's too close
             
             
                  for (Capsule v : agent) {
             
             
                    float d = PVector.dist(location, v.location);
             
             
                    
             
             
                    // If the distance is greater than 0 and less than an arbitrary amount (0 when you are yourself)
             
             
                    if ((d > 0) && (d < desiredseparation)) {
             
             
                      
             
             
                      // Calculate vector pointing away from neighbor
             
             
                      PVector diff = PVector.sub(location, v.location);
             
             
                      diff.normalize();
             
             
                      diff.div(d);        // Weight by distance
             
             
                      sum.add(diff);
             
             
                      count++;            // Keep track of how many
             
             
                    }
             
             
                  }
             
             
                  // Average -- divide by how many
             
             
                  if (count > 0) {
             
             
                    sum.div(count);
             
             
                    sum.normalize();  // Our desired vector is the average scaled to maximum speed
             
             
                    sum.mult(maxspeed);
             
             
                    
             
             
                    // Implement Reynolds: Steering = Desired - Velocity
             
             
                    PVector steer = PVector.sub(sum, velocity);
             
             
                    steer.limit(maxforce);
             
             
                    applyForce(steer);
             
             
                  }
             
             
                }
             
             
                
             
             
                // Alignment
             
             
                // For every nearby agent in the system, calculate the average velocity
             
             
                PVector align (ArrayList<Capsule> agent) {
             
             
                  float neighbordist = 50;
             
             
                  PVector sum = new PVector(0,0);
             
             
                  int count = 0;
             
             
                  for (Capsule v : agent) {
             
             
                    float d = PVector.dist(location,v.location);
             
             
                    if ((d > 0) && (d < neighbordist)) {
             
             
                      sum.add(v.velocity);
             
             
                      count++;
             
             
                    }
             
             
                  }
             
             
                  if (count > 0) {
             
             
                    sum.div((float)count);
             
             
                    sum.normalize();
             
             
                    sum.mult(maxspeed);
             
             
                    PVector steer = PVector.sub(sum,velocity);
             
             
                    steer.limit(maxforce);
             
             
                    return steer;
             
             
                  } else {
             
             
                    return new PVector(0,0);
             
             
                  }
             
             
                }
             
             
              }
             
             
              
             
             
              
             
             
              
             
             
              
             
             
              class MW1 extends Capsule {  // subclass: male_worker_single
             
             
              
             
             
                MW1(float x_mw1, float y_mw1, float z_mw1, color c_mw1, int nam_mw1) {
             
             
                  super(x_mw1,y_mw1,z_mw1,c_mw1,nam_mw1);
             
             
                }
             
             
                
             
             
                void display() {
             
             
                  fill(255,0,0);
             
             
                  noStroke();
             
             
                  pushMatrix();
             
             
                  translate(location.x, location.y, location.z);
             
             
                  sphere(3);
             
             
                  popMatrix();
             
             
                }
             
             
              }