import java.applet.*; import java.awt.*; import java.awt.image.*; import java.awt.event.*; import java.io.*; import java.net.*; import java.text.*; import java.util.*; import java.util.zip.*; import netscape.javascript.*; import javax.comm.*; import javax.sound.midi.*; import javax.sound.midi.spi.*; import javax.sound.sampled.*; import javax.sound.sampled.spi.*; import javax.xml.parsers.*; import javax.xml.transform.*; import javax.xml.transform.dom.*; import javax.xml.transform.sax.*; import javax.xml.transform.stream.*; import org.xml.sax.*; import org.xml.sax.ext.*; import org.xml.sax.helpers.*; public class relations extends BApplet {// RELATIONS -- LARVAE EVOLUTION --
// by Alessandro Capozzo March 2004 www.ghostagency.net
// inspired by Reynolds boids algorithm
// built with proce55ing alpha .68
Structure [] list;
int num=3;
int countList=50;
int medx,medy;
void setup() {
  size(600,400);
  smooth();
  framerate(30);
  list=new Structure[countList];
  for(int index=0;index<countList;index++){
    int xx=(int)(random(width)+1);
    int yy=(int)(random(height)+1);
    list[index]=new Structure(index,num,xx,yy);
    list[index].startMe();
  }

}

void loop() {
  background(120,30,70);
  for(int index=0;index<countList;index++){
    list[index].update();
  }

}
class Structure{
  int id;
  int nBall;
  int xBall,yBall;
  public Ball [] cont;

  Structure (int me,int n,int stx,int sty){
    id=me;
    nBall=n;
    xBall=stx;
    yBall=sty;

  }
  void startMe(){
    cont=new Ball[nBall];
    for (int index = 0; index < nBall; index++) {
      int rx=(int)(random(500));
      int ry=(int)(random(500));
      cont[index]=new Ball(.04f*(index+2),ry,rx,15,index,xBall,yBall,id);
    }

  }
  void update(){

    ellipseMode(CENTER_DIAMETER);
    int colorSpeed=(int)(abs(cont[0].velocityX)+abs(cont[0].velocityY));
    stroke(255-(colorSpeed),200,220-colorSpeed,90);
    fill(255-(colorSpeed),190,210-colorSpeed,90);
    for (int res = 0; res <nBall; res++) {
      int ox=cont[res].bx;
      int oy= cont[res].by;
      cont[res].update();
      int nx=cont[res].bx;
      int ny= cont[res].by;
      ellipse(nx,ny,4,4);

    }
  }
  class Ball {
    int bx,by;
    int difX,difY;
    int dim;
    int me;
    int radius;
    float objX,objY;
    float beta,dist;
    float xSpeed,ySpeed,ndelay;
    float angx,angy,coef;
    int posx,posy;
    float dirX,dirY;
    int sx,sy;
    int adgX,adgY;
    int parent;
    int flagx,flagy;
    float velocityX;
    float velocityY;
    Ball(float d,int initX,int initY,int magnitude, int iid,int _sx,int _sy,int _pid){
      ndelay=d;
      bx=initX;
      by=initY;
      difX=0;
      difY=0;
      xSpeed=0.00f;
      ySpeed=0.00f;
      dim=magnitude;
      me=iid;
      parent=_pid;
      if(me==0){
        posx=(int)(random(height));
        posy=(int)(random(width));
        xSpeed=_sx;
        ySpeed=_sy;
        dirX=xSpeed;
        dirY=ySpeed;
        coef=TWO_PI/40;

      }
    }
    void update (){
      if(me!=0){
        distance();
      } else{

        float ax=0;
        float ay=0;
        
        int atrac=0;
        float ndelay=.13f;
        for (int r1=0;r1<countList-1;r1++){
          if(r1!=id){
            ax+=list[r1].cont[0].bx;
            ay+=list[r1].cont[0].by;
          }

        }
        ax=ax/(countList-1);
        ax=(ax-bx)*0.002f;
        ay=ay/(countList-1);
        ay=(ay-by)*0.002f;
        int cx=0;
        int cy=0;
        for (int r2=0;r2<countList;r2++){
          if(r2!=id){
            for(int ND=0;ND<num;ND++){
              float distanza=dist(bx,by,list[r2].cont[ND].bx,list[r2].cont[ND].by);
              if(abs(distanza)<8){
                
                cx=cx-(bx-list[r2].cont[ND].bx);
                cy=cy-(by-list[r2].cont[ND].by);
              } else  if(abs(distanza)<50){
                stroke(200-distanza,200-distanza,200-distanza,100-distanza);
                line(bx,by,list[r2].cont[ND].bx,list[r2].cont[ND].by);
               }
            }
          }

        }
        float velox=0;
        float veloy=0;
        int distC=0;
        for (int r3=0;r3<countList;r3++){
        float distanza=dist(bx,by,list[r3].cont[0].bx,list[r3].cont[0].by);
        if(abs(distanza)<200){
          if(r3!=id){
            distC++;
            velox=velox+list[r3].cont[0].velocityX;
            veloy=veloy+list[r3].cont[0].velocityY;
          }
          }

        }
        velox=velox/(distC);
        velox=(velox-velocityX)*0.08f;
        veloy=veloy/(distC);
        veloy=(veloy-velocityY)*0.08f;

        velocityX+=ax+cx+velox;
        velocityY+=ay+cy+veloy;

        int limitV=15;
        if(velocityX>limitV){
          velocityX=limitV;
        }
        if(velocityY>limitV){
          velocityY=limitV;
        }
        if(velocityX<-limitV){
          velocityX=-limitV;
        }
        if(velocityY<-limitV){
          velocityY=-limitV;
        }
        bx=bx+(int)(velocityX);
        by=by+(int)(velocityY);
        if(bx<30){
          if(velocityX<0){
            velocityX+=1;
          }
          if(bx<0){
            bx+=30;
          }
        }
        if(by<30){
          if(velocityY<0){
            velocityY+=1;
          }
          if(by<0){
            by+=30;
          }
        }
        if (bx>(width-30)){
          if(velocityX>0){
            velocityX-=1;
          }
          if(bx>width){
            bx-=30;
          }
        }
        if (by>(height-30)){
          if(velocityY>0){
            velocityY-=1;
          }
          if(by>height){
            by-=30;
          }
        }
      }
    }
    void distance(){

      objX=cont[me-1].bx-bx;
      objY=cont[me-1].by-by;
      dist=sqrt(sq(objX)+sq(objY));
      if(abs(dist)!=15){
        objY+=.01f;
        objX+=.01f;

        beta=(float)(Math.atan(objY/objX));

        if(cont[me-1].by>=by){
          radius=15;
        }else {
          radius=-15;
        }
        if(beta>0){

          bx=cont[me-1].bx-(int)((radius)*cos(beta));
          by=cont[me-1].by-(int)((radius)*sin(beta));

        }else {

          bx=cont[me-1].bx+(int)((radius)*cos(beta));
          by=cont[me-1].by+(int)((radius)*sin(beta));

        }

        line(cont[me-1].bx,cont[me-1].by,bx,by);

      }

    }
  }

}
}