Tutorials (back to the list of tutorials)

## Physics Simulation and Swarm Examples

### Multi-Agent 3D Example 2 (requires iGeo version 7.6.0 or higher)

The example code below takes the previous tutorial code at "Multi-Agent 2D Example 3" and adding height depending on time and creating polygon mesh geometries.

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

void setup() {
size(480, 360, IG.GL);
IG.duration(300);
// left 100%, right 4.5%
new LineAgent(IG.v(0,0,0), IG.v(2,0,0), 100.0, 4.5).clr(0);
}

static class LineAgent extends IAgent{
IVec pos;
IVec dir;
double pctL, pctR;
boolean isColliding=false;
IVec intersection;

LineAgent(IVec pt, IVec dir, double pctL, double pctR) {
pos = pt;
this.dir = dir;
this.pctL = pctL;
this.pctR = pctR;
}

public void interact(ArrayList < IDynamics > agents){

if(time()==0){
for(int i=0; i < agents.size() && !isColliding ; i++){
if(agents.get(i) instanceof LineAgent){
LineAgent a = (LineAgent)agents.get(i);
if(a != this){
IVec pos2 = pos.cp(dir);
IVec apos2 = a.pos.cp(a.dir);

if(!apos2.eq(pos) && !a.pos.eq(pos)){ //not sharing root
intersection = IVec.intersectLine(a.pos,apos2,pos,pos2); //keep intersection to draw line later
if(intersection!=null){ //intersecting
isColliding=true;
}
}
}
}
}
}
}

public void update() {
if(time()==0){

double thickness = 0.3;
IVec widthDir = dir.dup().rot(PI/2).len(thickness/2);
double z1 = sin(IG.time()*0.05)*10+15;
double z2 = sin((IG.time()+1)*0.05)*10+15;
IVec meshPt1 = pos;
IVec meshPt2 = pos2;
if(isColliding){ meshPt2 = intersection; }

IG.meshBox(meshPt1.dup().sub(widthDir),
meshPt2.dup().sub(widthDir),

if(isColliding){
del();
return;
}

double r = red() + IRand.get(-0.05, 0.05);
double g = green() + IRand.get(-0.05, 0.05);
double b = blue() + IRand.get(-0.05, 0.05);

boolean branchL = IRand.pct(pctL);
boolean branchR = IRand.pct(pctR);

double lenL = dir.len();
double lenR = dir.len();
lenL*=0.995;  //shrinking length
lenR*=0.995;  //shrinking length

if (branchL && branchR) { //only when branching both
if(IRand.pct(50.0)){
if (pctL < pctR) { lenL *= 0.9; }
else{ lenR *= 0.9; }
}
else if(IRand.pct(6.0)){
if (pctL < pctR) { lenL *= 0.4; }
else{ lenR *= 0.4; }
}
else if(IRand.pct(5.0)){
if (pctL < pctR) { lenL *= 4; }
else{ lenR *= 4; }
}
}

if (branchL) { //bend left
IVec dir2 = dir.dup();
dir2.len(lenL); //update length
dir2.rot(PI/30);

if(branchR && pctR > pctL){ //swap L/R% when branching both
new LineAgent(pos2, dir2, pctR, pctL).clr(r,g,b);
}
else{
new LineAgent(pos2, dir2, pctL, pctR).clr(r,g,b);
}
}

if (branchR) { //bend right
IVec dir2 = dir.dup();
dir2.len(lenR); //update length
dir2.rot(-PI/30);

if(branchL && pctR < pctL){ //swap L/R% when branching both
new LineAgent(pos2, dir2, pctR, pctL).clr(r,g,b);
}
else{
new LineAgent(pos2, dir2, pctL, pctR).clr(r,g,b);
}
}
}
}
}
```

The example code below takes the previous tutorial code at "Multi-Agent 2D Example 3" and layering multiple agents in different z levels and interconnect them. All the branches and interconnection lines are made out of polygon mesh sticks.

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

void setup() {
size(480, 360, IG.GL);
IG.duration(80);
double z = 0;
for(int i=0; i < 20; i++){
//IRand.dir() is giving a random direction with given length perpendicular to given axis
new LineAgent(IRand.pt(-30,-30,z,30,30,z), IRand.dir(IG.zaxis,2), 100.0, 4.5).clr(0);
z += IRand.get(1,5);
}
}

static class LineAgent extends IAgent{
IVec pos;
IVec dir;
double pctL, pctR;
boolean isColliding=false;
IVec intersection;

LineAgent(IVec pt, IVec dir, double pctL, double pctR) {
pos = pt;
this.dir = dir;
this.pctL = pctL;
this.pctR = pctR;
}

public void interact(ArrayList < IDynamics > agents){

if(time()==0){
for(int i=0; i < agents.size() && !isColliding ; i++){
if(agents.get(i) instanceof LineAgent){
LineAgent a = (LineAgent)agents.get(i);
if(a != this){
//draw interconnection in z
if( !pos.eqZ(a.pos) ){ //z is not equal
double minLen = dir.len();
if(a.dir.len() < minLen){ minLen = a.dir.len(); }
double threshold = minLen * 2.5;
if( pos.eqX(a.pos, threshold) && pos.eqY(a.pos, threshold) ){ //x and y is equal with in given tolerance
if(IRand.pct(60)){
//new ICurve(pos, a.pos).clr(clr());
IG.meshSquareStick(pos, a.pos, 0.3).clr(clr());
}
}
}
else{
IVec pos2 = pos.cp(dir);
IVec apos2 = a.pos.cp(a.dir);

if(!apos2.eq(pos) && !a.pos.eq(pos)){ //not sharing root
intersection = IVec.intersectLine(a.pos,apos2,pos,pos2); //keep intersection to draw line later
if(intersection!=null){ //intersecting
isColliding=true;
}
}
}
}
}
}
}
}

public void update() {
if(time()==0){
if(isColliding){
//new ICurve(pos, intersection).clr(clr());
IG.meshSquareStick(pos, intersection, 0.5).clr(clr()); //keep line to intersection
del();
return;
}

//new ICurve(pos, pos2).clr(clr());
IG.meshSquareStick(pos, pos2, 0.5).clr(clr());

double r = red() + IRand.get(-0.05, 0.05);
double g = green() + IRand.get(-0.05, 0.05);
double b = blue() + IRand.get(-0.05, 0.05);

boolean branchL = IRand.pct(pctL);
boolean branchR = IRand.pct(pctR);

double lenL = dir.len();
double lenR = dir.len();
lenL*=0.995;  //shrinking length
lenR*=0.995;  //shrinking length

if (branchL && branchR) {  //only when branching both
if(IRand.pct(50.0)){
if (pctL < pctR) { lenL *= 0.9; }
else{ lenR *= 0.9; }
}
else if(IRand.pct(6.0)){
if (pctL < pctR) { lenL *= 0.4; }
else{ lenR *= 0.4; }
}
else if(IRand.pct(5.0)){
if (pctL < pctR) { lenL *= 1.4; }
else{ lenR *= 1.4; }
}
}

if (branchL) {  //bend left
IVec dir2 = dir.dup();
dir2.len(lenL);  //update length
dir2.rot(PI/30);

if(branchR && pctR > pctL){  //swap L/R% when branching both
new LineAgent(pos2, dir2, pctR, pctL).clr(r,g,b);
}
else{
new LineAgent(pos2, dir2, pctL, pctR).clr(r,g,b);
}
}

if (branchR) {  //bend right
IVec dir2 = dir.dup();
dir2.len(lenR);  //update length
dir2.rot(-PI/30);

if(branchL && pctR < pctL){  //swap L/R% when branching both
new LineAgent(pos2, dir2, pctR, pctL).clr(r,g,b);
}
else{
new LineAgent(pos2, dir2, pctL, pctR).clr(r,g,b);
}
}
}
}
}
```

(back to the list of tutorials)