Tutorials (back to the list of tutorials)

## Physics Simulation and Swarm Examples

### Swarm Example 1 (requires iGeo version 7.6.2 or higher)

The codes below shows an example of the swarm algorithm applied on a surface creating polygon mesh geometries.

The first code below has the swarm agent class MyBoid inheriting IBoid class. This adds a behavior to stay in the range from 0.0 to 1.0 in X and Y. In the update() method the position of the agent is checked and if it's out of the range, it adds or subtracts 1.0 to X or Y to jump to the other end of the range. To avoid drawing a line from one end to the other end, boolean variable jump is defined to check if it's jumping and if so it doesn't create a line. In setup() method, IG.top() method turns iGeo to show only top view instead of 4 views and IG.focus() method adjusts the view to zoom into the existing geometries.

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

void setup() {
size(480, 360, IG.GL);
IG.duration(800);
for(int i=0; i < 200; i++){
new MyBoid(IRand.pt(1,1,0),
IRand.pt(-0.01,-0.01,0,0.01,0.01,0));
}
IG.top(); //only showing the top view
IG.focus(); //focusing into existing geometries
}

class MyBoid extends IBoid {
IVec prevPos;
MyBoid(IVec pos, IVec vel) {
super(pos, vel);
cohesionDist(0.03);
cohesionRatio(1);
separationDist(0.04);
separationRatio(2);
alignmentDist(0.03);
alignmentRatio(0);
}

void update() {
boolean jump=false;
if (pos().x() < 0.0 ) {
jump=true;
}
else if (pos().x() > 1.0) {
pos().sub(1, 0, 0);
jump=true;
}
if (pos().y() < 0.0 ) {
jump=true;
}
else if (pos().y() > 1.0) {
pos().sub(0, 1, 0);
jump=true;
}

IVec curPos = pos().cp();
if(prevPos!=null && !jump){
new ICurve(prevPos, curPos).clr(0);
}
prevPos = curPos;
}
}
```

This second code keeps movements of the swarm agents same but drawing lines in different locations. Whereas the previous code draws lines on the trace of the movement, this code draws lines between two agents when two agents are closer than a certain distance. These two lines calculates a distance between two agents and limit the condition when the distance is smaller than 0.08 (note that the whole range is from 0.0 to 1.0).
double dist = pos().dist( b.pos() );
if ( dist < 0.08 ) {

Another if-condition of if ( IG.time()%15==0 ) { is added to control the density of lines.

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

void setup() {
size(480, 360, IG.GL);
IG.duration(800);
for(int i=0; i < 200; i++){
new MyBoid(IRand.pt(1,1,0),
IRand.pt(-0.01,-0.01,0,0.01,0.01,0));
}
IG.top(); //only showing the top view
IG.focus(); //focusing into existing geometries
}

class MyBoid extends IBoid {

MyBoid(IVec pos, IVec vel) {
super(pos, vel);
cohesionDist(0.03);
cohesionRatio(1);
separationDist(0.04);
separationRatio(2);
alignmentDist(0.03);
alignmentRatio(0);
}

void interact(ArrayList < IDynamics > agents){
super.interact(agents);
for(int i=0; i < agents.size() && agents.get(i)!=this; i++){
if(agents.get(i) instanceof MyBoid){
MyBoid b = (MyBoid)agents.get(i);
double dist = pos().dist(b.pos());
if ( dist < 0.08 ) {
if ( IG.time()%15==0 ) {
new ICurve(pos().cp(), b.pos().cp()).clr(0);
}
}
}
}
}

void update() {
if (pos().x() < 0.0 ) {
}
else if (pos().x() > 1.0) {
pos().sub(1, 0, 0);
}
if (pos().y() < 0.0 ) {
}
else if (pos().y() > 1.0) {
pos().sub(0, 1, 0);
}
}
}
```

The next code only changes the color of line drawing. The background color is changed by the method IG.bg(0) to black. When you put one number into this method ( IG.bg(double) ) it's gray scale color and when you put three numbers (IG.bg(double,double,double) ) it's RGB color. The color of the lines is changed to transparent white color at this line by setting the alpha value of the color to 0.2.
new ICurve(pos().cp(), b.pos().cp()).clr(1.0,0.2); //transparent white
The points of agents are also hidden by the agent's method hide().
if ( time()==0 ) { hide(); } //hiding a point of boid

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

void setup() {
size(480, 360, IG.GL);
IG.duration(800);
for(int i=0; i < 200; i++){
new MyBoid(IRand.pt(1,1,0),
IRand.pt(-0.01,-0.01,0,0.01,0.01,0));
}
IG.bg(0); //black background
IG.top(); //only showing the top view
IG.focus(); //focusing into existing geometries
}

class MyBoid extends IBoid {

MyBoid(IVec pos, IVec vel) {
super(pos, vel);
cohesionDist(0.03);
cohesionRatio(1);
separationDist(0.04);
separationRatio(2);
alignmentDist(0.03);
alignmentRatio(0);
}

void interact(ArrayList < IDynamics > agents){
super.interact(agents);
for(int i=0; i < agents.size() && agents.get(i)!=this; i++){
if(agents.get(i) instanceof MyBoid){
MyBoid b = (MyBoid)agents.get(i);
double dist = pos().dist(b.pos());
if ( dist < 0.08 ) {
if ( IG.time()%15==0 ) {
new ICurve(pos().cp(), b.pos().cp()).clr(1.0,0.2); //transparent white
}
}
}
}
}

void update() {
if ( time()==0 ) { hide(); } //hiding a point of boid
if (pos().x() < 0.0 ) {
}
else if (pos().x() > 1.0) {
pos().sub(1, 0, 0);
}
if (pos().y() < 0.0 ) {
}
else if (pos().y() > 1.0) {
pos().sub(0, 1, 0);
}
}
}
```

The code below maps the swarm agents onto a surface. It reads an input Rhino file and takes one surface out to put it into an agent of MyBoidOnSurface class. MyBoidOnSurface class contains two data fields.
ISurface surface;
IVec surfPt;

With those fields, the agent keeps the information of a surface to map onto and mapped vector location on the surface. The original position information on the agent pos() is used as U-V coordinates. Although the original position is interpreted as U-V coordinates, the actual point of the agent still exists in X-Y-Z coordinates. To hide this point, the method hide() is called inside the constructor. If you don't hide the point, it floats somewhere on X-Y plane within (0.0, 0.0) - (1.0, 1.0).

This agent's original position pos() is then mapped onto the position on the surface by this line inside the constructor and also inside update() method to keep the field surfPt updated.
surfPt = surface.pt(pos);
Then this surfPt is used to measure the distance and to create a line in 3D X-Y-Z coordinates. The input Rhino file used in the example is this one below.

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

void setup() {
size(480, 360, IG.GL);
IG.duration(800);
IG.open("surface13.3dm");
ISurface surf = IG.surface(0);
for(int i=0; i < 300; i++){
new MyBoidOnSurface(surf,
IRand.pt(1,1,0),
IRand.pt(-0.01,-0.01,0,0.01,0.01,0));
}
surf.del();
}

class MyBoidOnSurface extends IBoid {
ISurface surface;
IVec surfPt;

MyBoidOnSurface(ISurface srf, IVec pos, IVec vel) {
super(pos, vel);
surface = srf;
surfPt = surface.pt(pos);
hide(); //hiding a point of boid
cohesionDist(0.03);
cohesionRatio(1);
separationDist(0.04);
separationRatio(2);
alignmentDist(0.03);
alignmentRatio(0);
}

void interact(ArrayList < IDynamics > agents){
super.interact(agents);
for(int i=0; i < agents.size() && agents.get(i)!=this; i++){
if(agents.get(i) instanceof MyBoidOnSurface){
MyBoidOnSurface b = (MyBoidOnSurface)agents.get(i);
double dist = surfPt.dist(b.surfPt);
if ( dist < 5.0 ) {
if ( IG.time()%15==0 ){
new ICurve(surfPt.cp(), b.surfPt.cp()).clr(0);
}
}
}
}
}

void update() {
if ( pos().x() < 0.0 ) { pos().add(1, 0, 0); }
else if ( pos().x() > 1.0 ) { pos().sub(1, 0, 0); }
if ( pos().y() < 0.0 ){ pos().add(0, 1, 0); }
else if ( pos().y() > 1.0 ) { pos().sub(0, 1, 0); }

surfPt = surface.pt(pos()); //update surface point
}
}
```

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

void setup() {
size(480, 360, IG.GL);
IG.duration(800);
IG.open("surface13.3dm");
ISurface surf = IG.surface(0);
for(int i=0; i < 300; i++){
new MyBoidOnSurface(surf, IRand.pt(1,1,0),
IRand.pt(-0.01,-0.01,0,0.01,0.01,0));
}
surf.del();
}

class MyBoidOnSurface extends IBoid {
ISurface surface;
IVec surfPt;

MyBoidOnSurface(ISurface srf, IVec pos, IVec vel) {
super(pos, vel);
surface=srf;
surfPt = surface.pt(pos);
hide(); //hiding a point of boid
cohesionDist(0.03);
cohesionRatio(1);
separationDist(0.04);
separationRatio(2);
alignmentDist(0.03);
alignmentRatio(0);
}

void interact(ArrayList < IDynamics > agents){
super.interact(agents);
for(int i=0; i < agents.size() && agents.get(i) != this; i++){
if ( agents.get(i) instanceof MyBoidOnSurface ) {
MyBoidOnSurface b = (MyBoidOnSurface)agents.get(i);
double dist = surfPt.dist(b.surfPt);
if ( dist < 5.0 && dist > 2.0 ) {
if ( IG.time()%15==0 ) {
//controlling depth
double depth = sin(IG.time()*0.01)*1.5;
IVec pt1 = surface.pt(pos().x, pos().y, depth);
IVec pt2 = b.surface.pt(b.pos().x, b.pos().y, depth);
double gray = sin(IG.time()*0.01)*0.5+0.5;
IG.meshSquareStick(pt1,pt2,0.4).clr(gray);
}
}
}
}
}

void update() {
if ( pos().x() < 0.0 ) { pos().add(1, 0, 0); }
else if ( pos().x() > 1.0 ) { pos().sub(1, 0, 0); }
if ( pos().y() < 0.0 ){ pos().add(0, 1, 0); }
else if ( pos().y() > 1.0 ) { pos().sub(0, 1, 0); }

surfPt = surface.pt(pos()); //update surface point
}
}
```

(back to the list of tutorials)