// The flocking Class
 
class flocking
{
   
 public:
   typedef struct { double velx, vely, velz, x, y, z; int boidIndex; }
   Boid;
   Boid myFlock [10];
   double bound_x[2], bound_y[2], bound_z[2];
   
   flocking(double x0, double y0, double z0, double x1, double y1, double
	    z1) {
      bound_x[0] = x0; bound_x[1] = x1;
      bound_y[0] = y0; bound_y[1] = y1;
      bound_z[0] = z0; bound_z[1] = z1;
   }
   
   /*	~flocking() {
    for(int i = 0; i < 10; i++)
    {  
    delete myFlock[i];
    }  */

   double distance(double x, double y, double z)
   {
      return sqrt(x*x + y*y + z*z);
   }
   
   void add(Boid &b)
  {
     b.x = (((double)random())/((double)RAND_MAX));
     b.y = (((double)random())/((double)RAND_MAX));
     b.z = (((double)random())/((double)RAND_MAX));
     b.velx = ((((double)random())/((double)RAND_MAX))-0.5)/5000;
     b.vely = ((((double)random())/((double)RAND_MAX))-0.5)/5000;
     b.velz = ((((double)random())/((double)RAND_MAX))-0.5)/5000;
  }
   
   void centreOfMass(Boid &b) //rule 1
   {
      double cx = 0;
      double cy = 0;
      double cz = 0;
      
      for (int i = 0; i < 10; i++)
      {
	 if (i!=b.boidIndex) {
	    cx += myFlock[i].x;
	    cy += myFlock[i].y;
	    cz += myFlock[i].z;
	 }
      }  
      cx /= 9;
      cy /= 9;
      cz /= 9;
      
      b.velx += (cx-b.x)/1000;
      b.vely += (cy-b.y)/1000;
      b.velz += (cz-b.z)/1000;
   }//centre of mass, rule 1
   
   void stayAway(Boid &b) //rule 2
   {
      double vx = 0;
      double vy = 0;
      double vz = 0;
      
      for (int i = 0; i < 10; i++)
      {
	 if (i!=b.boidIndex) {
	    if ( distance(myFlock[i].x - b.x, myFlock[i].y - b.y, myFlock[i].z - b.z) < KeepBack) {
	       vx = vx - (myFlock[i].x - b.x)/40;
	       vy = vy - (myFlock[i].y - b.y)/40;
	       vz = vz - (myFlock[i].z - b.z)/40;
	    }
	 }   
      }     
      b.velx += vx;
      b.vely += vy;
      b.velz += vz;
   } //keeping from bumping into each other, rule 2
   
   void velMatch(Boid &b) //rule 3
   {
      double vx = 0;
      double vy = 0;
      double vz = 0;
      
      for (int i = 0; i < 10; i++)
      {
	 if (i!=b.boidIndex) {
	    vx += myFlock[i].velx;
	    vy += myFlock[i].vely;
	    vz += myFlock[i].velz;
	 }
      }   
      vx /= 9;
      vy /= 9;
      vz /= 9;
      
      b.velx += (vx-b.velx)/50;
      b.vely += (vy-b.vely)/50;
      b.velz += (vz-b.velz)/50;
      
   }//velocity matching, rule 3
   
   void boundingOfPos(Boid &b)
   {
      if (b.x < bound_x[0]) {
	 b.velx += 0.01;  
      } else if (b.x > bound_x[1]) {
	 b.velx -= 0.01;
      }
      
      if (b.y < bound_y[0]) {
	 b.vely += 0.01;
      } else if (b.y > bound_y[1]) {
	 b.vely -= 0.01;
      }
      
      if (b.z < bound_z[0]) {
	 b.velz += 0.01;
      } else if (b.z > bound_z[1]) {
	 b.velz -= 0.01;
      }
   }  
   
   void boundingVel(Boid &b)
   {
      if (abs(b.velx) > MaxVel) b.velx *= 0.9;
      if (abs(b.vely) > MaxVel) b.vely *= 0.9;
      if (abs(b.velz) > MaxVel) b.velz *= 0.9;
   }
   
   void draw(Boid &b)
   {
      double boidsize = 0.5;
      
      tiPrimitiveBegin (TYPE_POLYGON);
      tiPrimitiveNormal (sin(b.x * 0.1), sin(b.y * 0.1), sin(b.z *
							     0.1));
      tiPrimitiveVertex (b.x, b.y, b.z);
      tiPrimitiveVertex (b.x + boidsize, b.y, b.z);
      tiPrimitiveVertex (b.x + boidsize, b.y, b.z + boidsize);
      tiPrimitiveVertex (b.x, b.y, b.z + boidsize);
      tiPrimitiveEnd ();
   }	
   
   
   void updateFlock(Boid &b)
   {
      boundingOfPos(b);
      boundingVel(b);  
      
      centreOfMass(b);  //calling rule 1
      stayAway(b); //calling rule 2
      velMatch(b); //calling rule 3
      
      b.x+=b.velx;
      b.y+=b.vely;
      b.z+=b.velz;
      
      draw(b);
   }
   
}; //flocking


