Tutorials | (back to the list of tutorials) |
import igeo.*; import processing.opengl.*; void setup(){ size(480,360,IG.GL); IRand.init(3); IG.duration(700); new LineAgent(IG.v(-0.1,0,0), IG.v(1,0,0)).clr(0); new LineAgent(IG.v(500,-0.1,0), IG.v(0,1,0)).clr(0); new LineAgent(IG.v(500+0.1,500,0), IG.v(-1,0,0)).clr(0); new LineAgent(IG.v(0,500+0.1,0), IG.v(0,-1,0)).clr(0); for(int i=0; i < 10; i++){ new LineAgent(IRand.pt(100,100,0,400,400,0), IRand.pt(-10,-10,0,10,10,0)).clr(IRand.clr(0.4,0.4,0.4)); } } static class LineAgent extends IAgent{ // constants static final double length = 2; static final double clearance = 1.99; //less than length static final double angleThreshold = PI/20; static final double threshold = 10; IVec pt1, pt2; boolean isColliding=false; double angle=0; double minDist=0; double frontAngle=0; LineAgent(IVec pt, IVec dir){ pt1 = pt; pt2 = pt.cp(dir.cp().len(length)); } void interact(ArrayList < IDynamics > agents){ if(time == 0){ //only in the first time minDist = -1; //reset for(int i=0; i < agents.size() && !isColliding; i++){ if(agents.get(i) instanceof LineAgent){ LineAgent agent = (LineAgent)agents.get(i); if(agent != this){ //agents include "this" // checking clearance of end point double dist = agent.pt2.dist(pt2); if(dist < clearance){ isColliding=true; } else if(dist < threshold){ //not colliding but close if(!pt1.eq(agent.pt2) && //not the parent pt2.dif(pt1).angle(agent.pt2.dif(pt1)) < angleThreshold && //in front (minDist < 0 || dist < minDist) ){ //closest one minDist = dist; frontAngle = pt2.dif(pt1).angle(agent.pt2.dif(agent.pt1),IG.zaxis); } } } } } } } void update(){ if(time == 0){ if(isColliding){ del(); } else{ //if not colliding new ICurve(pt1,pt2).clr(clr()); IVec dir = pt2.dif(pt1); if(IRand.pct(1)){ //branching double r = red()+IRand.get(-0.1,0.1); double g = green()+IRand.get(-0.1,0.1); double b = blue()+IRand.get(-0.1,0.1); new LineAgent(pt2, dir.cp().rot(IRand.get(PI/3,2*PI/3))).clr(r,g,b); } if(frontAngle < 0){ frontAngle+=PI; } //going in only one direction double r = red()+IRand.get(-0.03,0.03); double g = green()+IRand.get(-0.03,0.03); double b = blue()+IRand.get(-0.03,0.03); new LineAgent(pt2, dir.rot(frontAngle)).clr(r,g,b); } } } }
The next code change the previous code to round the turning corner by bending the lines with a few segments. To enable bending through multiple generation of agents, the instance field of bendAngle and bendCount are added to LineAgent class.
import igeo.*; import processing.opengl.*; void setup(){ size(480,360,IG.GL); IRand.init(2); IG.duration(700); new LineAgent(IG.v(-0.1,0,0),IG.v(1,0,0),0,0).clr(0); new LineAgent(IG.v(500,-0.1,0),IG.v(0,1,0),0,0).clr(0); new LineAgent(IG.v(500+0.1,500,0),IG.v(-1,0,0),0,0).clr(0); new LineAgent(IG.v(0,500+0.1,0),IG.v(0,-1,0),0,0).clr(0); new LineAgent(IG.v(500/2,0,0),IG.v(1,0,0),0,0).clr(0); new LineAgent(IG.v(500,500/2,0),IG.v(0,1,0),0,0).clr(0); new LineAgent(IG.v(500/2,500,0),IG.v(-1,0,0),0,0).clr(0); new LineAgent(IG.v(0,500/2,0),IG.v(0,-1,0),0,0).clr(0); for(int i=0; i < 30; i++){ new LineAgent(IRand.pt(100,100,0,400,400,0),IRand.pt(-10,-10,0,10,10,0),0,0).clr(IRand.clr(0.4,0.4,0.4)); } } static class LineAgent extends IAgent{ // constants static final double length = 2; static final double clearance = 1.99; //less than length static final double angleThreshold = PI/20; static final double threshold = 10; static final int bendSize = 2; IVec pt1, pt2; boolean isColliding=false; double angle=0; double minDist=0; double frontAngle=0; double bendAngle=0; int bendCount = 0; LineAgent(IVec pt, IVec dir, double bend, int bcount){ pt1 = pt; pt2 = pt.cp(dir.cp().len(length)); bendAngle = bend; bendCount = bcount; } void interact(ArrayList < IDynamics > agents){ if(time == 0){ //only in the first time minDist = -1; //reset for(int i=0; i < agents.size() && !isColliding; i++){ if(agents.get(i) instanceof LineAgent){ LineAgent agent = (LineAgent)agents.get(i); if(agent != this){ //agents include "this" // checking clearance of end point double dist = agent.pt2.dist(pt2); if(dist < clearance){ isColliding=true; } else if(dist < threshold){ //not colliding but close if(!pt1.eq(agent.pt2) && //not the parent pt2.dif(pt1).angle(agent.pt2.dif(pt1)) < angleThreshold && //in front (minDist < 0 || dist < minDist) ){ //closest one minDist = dist; frontAngle = pt2.dif(pt1).angle(agent.pt2.dif(agent.pt1),IG.zaxis); } } } } } } } void update(){ if(time == 0){ if(isColliding){ del(); } else{ //if not colliding new ICurve(pt1,pt2).clr(clr()); IVec dir = pt2.dif(pt1); if(IRand.pct(1)){ //branching double r = red()+IRand.get(-0.1,0.1); double g = green()+IRand.get(-0.1,0.1); double b = blue()+IRand.get(-0.1,0.1); new LineAgent(pt2, dir.cp().rot(IRand.get(PI/3,2*PI/3)), 0, 0).clr(r,g,b); } double r = red()+IRand.get(-0.03,0.03); double g = green()+IRand.get(-0.03,0.03); double b = blue()+IRand.get(-0.03,0.03); //checking bend if(bendCount == 0 && minDist >=0 && frontAngle!=0){ if(frontAngle < 0){ frontAngle+=PI; }//going in only one direction bendCount = bendSize; bendAngle = frontAngle/bendCount; } if(bendCount > 0){ //bending dir.rot(bendAngle); new LineAgent(pt2, dir, bendAngle, bendCount-1).clr(r,g,b); } else{ //go straight new LineAgent(pt2, dir, 0, 0).clr(r,g,b); } } } } }