Tutorials | (back to the list of tutorials) |
import processing.opengl.*; import igeo.*; void setup() { size(480, 360, IG.GL); IG.duration(700); // left 99.0%, right 1.5% new LineAgent(IG.v(0,0,0), IG.v(2,0,0), 99.0, 1.5).clr(0); } static class LineAgent extends IAgent{ IVec pos; IVec dir; double pctL, pctR; LineAgent(IVec pt, IVec dir, double pctL, double pctR) { pos = pt; this.dir = dir; this.pctL = pctL; this.pctR = pctR; } public void update() { if(time()==0){ //putting line geometry IVec pos2 = pos.dup().add(dir); new ICurve(pos, pos2).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); if(IRand.pct(3.0)){ //swap L/R percent double tmp = pctL; pctL = pctR; pctR = tmp; } if (IRand.pct(pctL)) { //bend left IVec dir2 = dir.dup(); dir2.rot(PI/30); new LineAgent(pos2, dir2, pctL, pctR).clr(r,g,b); } if (IRand.pct(pctR)) { //bend right IVec dir2 = dir.dup(); dir2.rot(-PI/30); new LineAgent(pos2, dir2, pctL, pctR).clr(r,g,b); } del(); } } }
The next code adds interact() method to the previous code to detect collision of line agents. A line agent stops when it collides into other existing agents. Then the algorithm to swap left and right probability is also changed to swap them only when an agent creates a new branch.
import processing.opengl.*; import igeo.*; void setup() { size(480, 360, IG.GL); IG.duration(350); // left 99.0%, right 7.0% new LineAgent(IG.v(0,0,0), IG.v(2,0,0), 99.0, 7.0).clr(0); } static class LineAgent extends IAgent{ IVec pos; IVec dir; double pctL, pctR; boolean isColliding=false; LineAgent(IVec pt, IVec dir, double pctL, double pctR) { pos = pt; this.dir = dir; this.pctL = pctL; this.pctR = pctR; } public void interact(ArrayListagents){ 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){ if(a.pos.dist(pos.cp(dir)) < dir.len()*0.999){ isColliding=true; } } } } } } public void update() { if(time()==0){ if(isColliding){ del(); return; } //putting line geometry IVec pos2 = pos.dup().add(dir); new ICurve(pos, pos2).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 switch L boolean branchR = IRand.pct(pctR); //boolean switch R if (branchL) { //bend left IVec dir2 = dir.dup(); 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.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 code below
changes the length of agent's line at every update.
The lengths of all agents are slightly scaled down
constantly, creating swirling curves.
On top of it, the length is scaled up or down stochastically,
only when the agent is creating a branch.
In intersect() method, the
collision detection algorithm is changed.
It's using the method of
IVec.intersectLine(IVec line1Pt1, IVec line1Pt2, IVec line2Pt1, IVec line2Pt2)
to calculate intersection of two line segments because
the previous algorithm of collision detection wouldn't work
when there are different lengths of lines.
import processing.opengl.*; import igeo.*; void setup() { size(480, 360, IG.GL); IG.duration(400); // 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; LineAgent(IVec pt, IVec dir, double pctL, double pctR) { pos = pt; this.dir = dir; this.pctL = pctL; this.pctR = pctR; } public void interact(ArrayListagents){ 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 IVec.intersectLine(a.pos,apos2,pos,pos2)!=null){ //intersecting isColliding=true; } } } } } } public void update() { if(time()==0){ if(isColliding){ del(); return; } IVec pos2 = pos.dup().add(dir); new ICurve(pos, pos2).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 *= 4.0; } else{ lenR *= 4.0; } } } 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); } } } } }