Tutorials | (back to the list of tutorials) |
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){ IVec pos2 = pos.dup().add(dir); 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), meshPt2.dup().add(widthDir), meshPt1.dup().add(widthDir), meshPt1.dup().sub(widthDir).add(0,0,z1), meshPt2.dup().sub(widthDir).add(0,0,z2), meshPt2.dup().add(widthDir).add(0,0,z2), meshPt1.dup().add(widthDir).add(0,0,z1)).clr(clr()); 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; } IVec pos2 = pos.dup().add(dir); //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); } } } } }