home processing download documents tutorial python tutorial gallery source about
 Tutorials (back to the list of tutorials)

Physics Simulation and Swarm Examples

     Swarm Example 2 (requires iGeo version 7.6.0 or higher)

The codes below show examples of use of the swarm algorithm to create clustering volumes.

The first code below describes a swarm agent class MyBoid and this agent draws profile polygon lines around the agent's position instead of drawing trace lines behind. The number of vertices of the polygon lines is defined by the variable of pointNum in MyBoid class. Each vertex of the polygon is calculated by rotating points around the velocity vector of the agent.

import processing.opengl.*;
import igeo.*;

void setup(){
  size(480, 360, IG.GL);
  IG.duration(170);
  int num = 16;
  for(int i=0; i < num; i++){
    new MyBoid(IG.v(80,0,0).rot(PI*2/num*i), //circular configuration
               IG.v(-IRand.get(20,40),0,i%2*20-10).rot(PI*2/num*i+PI/4)).fric(0.001).clr(IRand.gray());
  }
  new Attractor(IG.v(0,0,0));
}

class MyBoid extends IBoid{
  int pointNum = 5;
  IVec[] points;
  
  MyBoid(IVec p, IVec v){ 
    super(p,v); 
    cohesionDist(60);
    cohesionRatio(5);
    separationDist(50);
    separationRatio(8);
    alignmentDist(40);
    alignmentRatio(0);
    points = new IVec[pointNum];
  }

  void update(){ //drawing line
    double radius = 3;
    for(int i=0; i < pointNum; i++){
      IVec axis = vel().cross(IG.zaxis);
      axis.len(radius);
      axis.rot(vel(), 2*PI/pointNum*i);
      points[i] = pos().cp(axis);
    }

    for(int i=0; i < pointNum; i++){
      new ICurve(points[i], points[(i+1)%pointNum]).clr(clr());
    }
  }
}

class Attractor extends IAgent{
  double attraction = 0.4; 
  IVec pos;
  Attractor(IVec p){ pos = p; }
  
  void interact(ArrayList < IDynamics > agents){
    for(int i=0; i < agents.size(); i++){
      if(agents.get(i) instanceof MyBoid){
        MyBoid b = (MyBoid)agents.get(i);
        IVec frc = b.pos().dif(pos).mul(attraction);
        b.pull(frc);
      }
    }
  }
}

The next code controls the radius of polygon by time and connects profile polygon lines with diagonal lines creating truss connections.

import processing.opengl.*;
import igeo.*;

void setup(){
  size(480, 360, IG.GL);
  IG.duration(170);
  int num = 16;
  for(int i=0; i < num; i++){
    new MyBoid(IG.v(80,0,0).rot(PI*2/num*i), //circular configuration
               IG.v(-IRand.get(20,40),0,i%2*20-10).rot(PI*2/num*i+PI/4)).fric(0.001).clr(IRand.gray());
  }
  new Attractor(IG.v(0,0,0));
}

class MyBoid extends IBoid{
  int pointNum = 5;
  IVec[] points, prevPoints;
  
  MyBoid(IVec p, IVec v){ 
    super(p,v); 
    cohesionDist(60);
    cohesionRatio(5);
    separationDist(50);
    separationRatio(8);
    alignmentDist(40);
    alignmentRatio(0);
    points = new IVec[pointNum];
  }

  void update(){ //drawing line
    double radius = sin(IG.time()*0.1)*2 + 3; //changing radius by time
    for(int i=0; i < pointNum; i++){
      IVec axis = vel().cross(IG.zaxis);
      axis.len(radius);
      axis.rot(vel(), 2*PI/pointNum*i);
      points[i] = pos().cp(axis);
    }

    if(prevPoints!=null){
      for(int i=0; i < pointNum; i++){
        new ICurve(points[i], points[(i+1)%pointNum]).clr(clr());
        new ICurve(points[i], prevPoints[(i+1)%pointNum]).clr(clr());
        new ICurve(points[i], prevPoints[i]).clr(clr());
      }
    }
    else{
      prevPoints = new IVec[pointNum];
    }
    
    for(int i=0; i < pointNum; i++){
      prevPoints[i] = points[i];
    }
  }
}

class Attractor extends IAgent{
  double attraction = 0.4; 
  IVec pos;
  Attractor(IVec p){ pos = p; }
  
  void interact(ArrayList < IDynamics > agents){
    for(int i=0; i < agents.size(); i++){
      if(agents.get(i) instanceof MyBoid){
        MyBoid b = (MyBoid)agents.get(i);
        IVec frc = b.pos().dif(pos).mul(attraction);
        b.pull(frc);
      }
    }
  }
}

The code below shows an algorithm to interconnect trajectories of swarm agents. The swarm agent draws lines not only to other swarm agents' position but also to the past trajectories of other agents. To keep the information of past trajectories, a new agent class Anchor is introduced. Each swarm agent of MyBoid class puts an instance of Anchor at its position of the moment. This Anchor agent stays at the position checking other swarm agents and if other agents are coming close enough, it draws lines to them. This check of other swarm agents is done by this line.
        if(boid!=parent && dist < 18 && dist > 8 ){
It checks if it's not the parent swarm agent and if the distance is smaller than 18 and also larger than 8 (not to draw too short lines), the Anchor agent draws a line to the MyBoid agent.

import processing.opengl.*;
import igeo.*;

void setup(){
  size(480, 360, IG.GL);
  IG.duration(170);
  IG.bg(0);
  int num = 16;
  for(int i=0; i < num; i++){
    new MyBoid(IG.v(80,0,0).rot(PI*2/num*i), //circular configuration
               IG.v(-IRand.get(20,40),0,i%2*20-10).rot(PI*2/num*i+PI/4)).friction(0.001).clr(IRand.gray(48));
  }
  new Attractor(IG.v(0,0,0));
}

class Anchor extends IAgent{
  IVec pos;
  MyBoid parent;
  
  Anchor(MyBoid b){ 
    parent = b;
    pos = b.pos().cp();
  }
  
  void interact(IDynamics agent){
    if(agent instanceof MyBoid){
      MyBoid boid = (MyBoid)agent;
      double dist = boid.pos().dist(pos);
      if(boid!=parent && dist < 18 && dist > 8 ){
        new ICurve(boid.pos().cp(), pos).clr(parent.clr());
      }
    }
  }
}

class MyBoid extends IBoid{
  IVec prevPos;
  
  MyBoid(IVec p, IVec v){ 
    super(p,v); 
    cohesionDist(60);
    cohesionRatio(5);
    separationDist(50);
    separationRatio(8);
    alignmentDist(40);
    alignmentRatio(0);
  }

  void update(){ //drawing line
    new Anchor(this); //leaving an anchor behind
    IVec curPos = pos().cp();
    if(prevPos!=null){
      new ICurve(prevPos, curPos).clr(clr());
    }
    prevPos = curPos;
  }
}

class Attractor extends IAgent{
  double attraction = 0.4; 
  IVec pos;
  Attractor(IVec p){ pos = p; }
  
  void interact(ArrayList < IDynamics > agents){
    for(int i=0; i < agents.size(); i++){
      if(agents.get(i) instanceof MyBoid){
        MyBoid b = (MyBoid)agents.get(i);
        IVec frc = b.pos().dif(pos).mul(attraction);
        b.pull(frc);
      }
    }
  }
}

The code below combines the algorithm to create polygon truss geometries and the another algorithm to interconnect trajectories of swarm agents. The connection line of trajectories are drawn from the vertices of the truss geometries and the line is drawn as a closed polygon mesh geometry by the method IG.meshSquareStick(pt1, pt2, size).

import processing.opengl.*;
import igeo.*;

void setup(){
  size(480, 360, IG.GL);
  IG.duration(170);
  IG.bg(0);
  int num = 16;
  for(int i=0; i < num; i++){
    new MyBoid(IG.v(80,0,0).rot(PI*2/num*i), //circular configuration
               IG.v(-IRand.get(20,40),0,i%2*20-10).rot(PI*2/num*i+PI/4)).fric(0.001).clr(IRand.gray(48));
  }
  new Attractor(IG.v(0,0,0));
}

class Anchor extends IAgent{
  IVec pos;
  IVec[] points;
  MyBoid parent;
  
  Anchor(MyBoid b){ 
    parent = b;
    pos = b.pos().cp();
    points = new IVec[b.points.length];
    for(int i=0; i < points.length; i++){ points[i] = b.points[i]; }
  }
  
  void interact(IDynamics agent){
    if(agent instanceof MyBoid){
      MyBoid boid = (MyBoid)agent;
      double dist = boid.pos().dist(pos);
      if(boid!=parent && dist < 18 && dist > 8 ){
        double meshSize = 0.5;
        double r = sin(IG.time()*0.1)*0.1+0.3;
        double g = 0.2;
        double b = sin(IG.time()*0.1)*0.4+0.6;
        for(int i=0; i < points.length; i++){
          if(IRand.pct(40)){ //only 40%
            IG.meshSquareStick(boid.points[i],points[i],meshSize).clr(r,g,b);
          }
        }
      }
    }
  }
}

class MyBoid extends IBoid{
  int pointNum = 3;
  IVec[] points, prevPoints;
  
  MyBoid(IVec p, IVec v){ 
    super(p,v); 
    cohesionDist(60);
    cohesionRatio(5);
    separationDist(50);
    separationRatio(8);
    alignmentDist(40);
    alignmentRatio(0);
    points = new IVec[pointNum];
  }

  void update(){ //drawing line
    if(time()%2==0){ //adjusting interval
      double radius = sin(IG.time()*0.1)*2 + 3; //changing radius by time
      for(int i=0; i < pointNum; i++){
        IVec axis = vel().cross(IG.zaxis);
        axis.len(radius);
        axis.rot(vel(), 2*PI/pointNum*i);
        points[i] = pos().cp(axis);
      }

      new Anchor(this); //leaving an anchor behind

      double meshSize = 0.5;
      double r = sin(IG.time()*0.1)*0.1+0.3;
      double g = 0.2;
      double b = sin(IG.time()*0.1)*0.4+0.6;
      if(prevPoints!=null){
        for(int i=0; i < pointNum; i++){
          IG.meshSquareStick(points[i], prevPoints[i], meshSize).clr(r,g,b);
          IG.meshSquareStick(points[i], prevPoints[(i+1)%pointNum], meshSize).clr(r,g,b);
          IG.meshSquareStick(points[i], points[(i+1)%pointNum], meshSize).clr(r,g,b);
        }
      }
      else{
        prevPoints = new IVec[pointNum];
      }
      
      for(int i=0; i < pointNum; i++){
        prevPoints[i] = points[i];
      }
    }
  }
}

class Attractor extends IAgent{
  double attraction = 0.4; 
  IVec pos;
  Attractor(IVec p){ pos = p; }
  
  void interact(ArrayList < IDynamics > agents){
    for(int i=0; i < agents.size(); i++){
      if(agents.get(i) instanceof MyBoid){
        MyBoid b = (MyBoid)agents.get(i);
        IVec frc = b.pos().dif(pos).mul(attraction);
        b.pull(frc);
      }
    }
  }
}

The image below shows rendered geometries.


(back to the list of tutorials)

HOME
FOR PROCESSING
DOWNLOAD
DOCUMENTS
TUTORIALS (Java / Python)
GALLERY
SOURCE CODE(GitHub)
ABOUT