Tutorials | (back to the list of tutorials) |
The first code below has a line agent class LineAgent which reproduces a child line agent in a specific direction but the agent class inherits IParticle class instead of inheriting IAgent class in the previous line agent classes like the ones in this page. In the update method, the agent instantiates ISpringLine which is a line with spring force to maintain the distance of two end point particles instead of a simple line in the previous line agents.
import igeo.*; import processing.opengl.*; void setup(){ size(480,360,IG.GL); new LineAgent(new IParticle(0,0,0).hide().fric(0.2), new IVec(0,2,0)); IG.bg(1.0,1.0,1.0); IG.top(); } class LineAgent extends IParticle{ LineAgent parent; IVec dir; LineAgent(IParticle parent, IVec dir){ super(parent.pos().cp(dir)); if(parent instanceof LineAgent){ this.parent = (LineAgent)parent; } hide(); // hide point this.dir = dir; fric(0.2); } void update(){ if(time()==0 && alive()){ if(parent!=null && parent.alive()){ //line between this and parent with spring force 100 new ISpringLine(this,parent,100).clr(0); } new LineAgent(this, dir); } } }
The below codes shows the response of particle-based line agents to some force fields like attractors.
import igeo.*; import processing.opengl.*; void setup(){ size(480,360,IG.GL); new LineAgent(new IParticle(0,0,0).hide().fric(0.2), new IVec(0,2,0)); for(int i=0; i < 20; i++){ new IAttractor(IRand.pt(-200,0,0,200,400,0)).linear(100).intensity(-200); //repulsion force } IG.bg(1.0,1.0,1.0); IG.top(); } class LineAgent extends IParticle{ LineAgent parent; IVec dir; LineAgent(IParticle parent, IVec dir){ super(parent.pos().cp(dir)); if(parent instanceof LineAgent){ this.parent = (LineAgent)parent; } hide(); // hide point this.dir = dir; fric(0.2); } void update(){ if(time()==0 && alive()){ if(parent!=null && parent.alive()){ new ISpringLine(this,parent,100).clr(0); //line with spring force } new LineAgent(this, dir); } } }
import igeo.*; import processing.opengl.*; void setup(){ size(480,360,IG.GL); for(int i=0; i < 4; i++){ new LineAgent(new IParticle(IRand.pt(-40,-40,0,40,40,0)).hide().fric(0.2), IRand.dir(IG.zaxis).len(2)); } for(int i=0; i < 20; i++){ new IAttractor(IRand.pt(-200,0,0,200,400,0)).linear(100).intensity(-200); //repulsion force } IG.bg(1.0,1.0,1.0); IG.top(); } class LineAgent extends IParticle{ LineAgent parent; IVec dir; LineAgent(IParticle parent, IVec dir){ super(parent.pos().cp(dir)); if(parent instanceof LineAgent){ this.parent = (LineAgent)parent; } hide(); // hide point this.dir = dir; fric(0.2); } void update(){ if(time()==0 && alive()){ if(parent!=null && parent.alive()){ ISpringLine ln = new ISpringLine(this, parent,100); //line with spring force double t = -cos(IG.time()*0.06)*0.5+0.5; ln.hsb( 0.7-t*0.2, 1, 0.8-t*0.2); //color by time } new LineAgent(this, dir); IVec dir2 = dir.cp(); dir2.rot(PI*0.12); if( IRand.pct(5) ){ // 5% branching probability new LineAgent(this,dir2); } } } }
import igeo.*; import processing.opengl.*; void setup(){ size(480,360,IG.GL); for(int i=0; i < 4; i++){ new LineAgent(new IParticle(IRand.pt(-40,-40,0,40,40,0)).hide().fric(0.2), IRand.dir(IG.zaxis).len(2)); } for(int i=0; i < 20; i++){ new IAttractor(IRand.pt(-200,0,0,200,400,0)).linear(100).intensity(-200); //repulsion force } IG.bg(1.0,1.0,1.0); IG.top(); } class LineAgent extends IParticle{ LineAgent parent; boolean isColliding; IVec dir; LineAgent(IParticle parent, IVec dir){ super(parent.pos().cp(dir)); if(parent instanceof LineAgent){ this.parent = (LineAgent)parent; } isColliding=false; hide(); // hide point this.dir = dir; fric(0.2); } void interact(ArrayListagents){ if(time()==0){ //only in the first time for(int i=0; i < agents.size(); i++){ if(agents.get(i) instanceof LineAgent){ LineAgent lineAgent = (LineAgent)agents.get(i); if(lineAgent!=this){ //agents include "this" if(lineAgent.parent!=null && lineAgent.pos().dist(pos()) < pos().dist(parent.pos())*2){ IVec intxn = IVec.intersectSegment(lineAgent.parent.pos(),lineAgent.pos(),parent.pos(),pos()); if(intxn != null && !intxn.eq(parent.pos()) && !lineAgent.isColliding ){ isColliding = true; return; } } } } } } } void update(){ if( isColliding ){ del(); } else{ if(time()==0 && alive()){ if(parent!=null && parent.alive()){ ISpringLine ln = new ISpringLine(this, parent,100); double t = -cos(IG.time()*0.06)*0.5+0.5; ln.hsb( 0.7-t*0.2, 1, 0.8-t*0.2, 1.0); // color by time } new LineAgent(this, dir); IVec dir2 = dir.cp(); dir2.rot(PI*0.12); if( IRand.pct(5) ){ // 5% branching probability new LineAgent(this,dir2); } } } } }
import igeo.*; import processing.opengl.*; void setup(){ size(480,360,IG.GL); for(int i=0; i < 4; i++){ new LineAgent(new IParticle(IRand.pt(-40,-40,0,40,40,0)).hide().fric(0.2), IRand.dir(IG.zaxis).len(2)); } for(int i=0; i < 20; i++){ new IAttractor(IRand.pt(-200,-200,0,200,200,0)).linear(50).intensity(-100); //repulsion force } IG.bg(1.0,1.0,1.0); IG.top(); } class LineAgent extends IParticle{ LineAgent parent; boolean isColliding; IVec dir; LineAgent(IParticle parent, IVec dir){ super(parent.pos().cp(dir)); if(parent instanceof LineAgent){ this.parent = (LineAgent)parent; } isColliding=false; hide(); // hide point this.dir = dir; fric(0.2); } void interact(ArrayListagents){ if(time()==0){ //only in the first time for(int i=0; i < agents.size(); i++){ if(agents.get(i) instanceof LineAgent){ LineAgent lineAgent = (LineAgent)agents.get(i); if(lineAgent!=this){ //agents include "this" if(lineAgent.parent!=null && lineAgent.pos().dist(pos()) < pos().dist(parent.pos())*2){ IVec intxn = IVec.intersectSegment(lineAgent.parent.pos(),lineAgent.pos(),parent.pos(),pos()); if( intxn != null && !intxn.eq(parent.pos()) && !lineAgent.isColliding ){ isColliding = true; return; } } } } } } } void update(){ if( isColliding ){ del(); } else{ if(time()==0 && alive()){ if(parent!=null && parent.alive()){ ISpringLine ln = new ISpringLine(this, parent,100); double t = -cos(IG.time()*0.06)*0.5+0.5; ln.hsb( 0.7-t*0.2, 1, 0.8-t*0.2, 1.0); // color by time } IVec dir2 = dir.cp(); double angle = PI*0.12 ; if( IRand.pct(50) ){ dir.rot(angle); dir2.rot(-angle); } else{ dir.rot(-angle); dir2.rot(angle); } new LineAgent(this, dir); if( IRand.pct(20) ){ // 20% branching probability new LineAgent(this,dir2); } } } } }
import igeo.*; import processing.opengl.*; void setup(){ size(480,360,IG.GL); for(int i=0; i < 4; i++){ new LineAgent(new IParticle(IRand.pt(-40,-40,0,40,40,0)).hide().fric(0.2), IRand.dir(IG.zaxis).len(2)); } for(int i=0; i < 20; i++){ new IAttractor(IRand.pt(-200,-200,0,200,200,0)).linear(50).intensity(-100); //repulsion force } IG.bg(1.0,1.0,1.0); IG.top(); } class LineAgent extends IParticle{ LineAgent parent; boolean isColliding; IVec dir; LineAgent(IParticle parent, IVec dir){ super(parent.pos().cp(dir)); if(parent instanceof LineAgent){ this.parent = (LineAgent)parent; } isColliding=false; hide(); // hide point this.dir = dir; fric(0.2); } void interact(ArrayListagents){ if(time()==0){ //only in the first time for(int i=0; i < agents.size(); i++){ if(agents.get(i) instanceof LineAgent){ LineAgent lineAgent = (LineAgent)agents.get(i); if(lineAgent!=this){ //agents include "this" if(lineAgent.parent!=null && lineAgent.pos().dist(pos()) < pos().dist(parent.pos())*2){ IVec intxn = IVec.intersectSegment(lineAgent.parent.pos(),lineAgent.pos(),parent.pos(),pos()); if( intxn != null && !intxn.eq(parent.pos()) && !lineAgent.isColliding ){ isColliding = true; return; } } } } } } } void update(){ if( isColliding ){ del(); } else{ if(time()==0 && alive()){ if(parent!=null && parent.alive()){ ISpringLine ln = new ISpringLine(this, parent,100); double t = -cos(IG.time()*0.06)*0.5+0.5; ln.hsb( 0.7-t*0.2, 1, 0.8-t*0.2, 1.0); ln.len(ln.len()*2); //set spring length longer } IVec dir2 = dir.cp(); double angle = PI*0.12 ; if( IRand.pct(50) ){ dir.rot(angle); dir2.rot(-angle); } else{ dir.rot(-angle); dir2.rot(angle); } new LineAgent(this, dir); if( IRand.pct(20) ){ // 20% branching probability new LineAgent(this,dir2); } } } } }
As a result of setting the spring length to be the double of the original branch length, it expands after it's created making the lines jaggy.
import igeo.*; import processing.opengl.*; void setup(){ size(480,360,IG.GL); for(int i=0; i < 4; i++){ new LineAgent(new IParticle(IRand.pt(-40,-40,0,40,40,0)).hide().fric(0.2), IRand.dir(IG.zaxis).len(2)); } for(int i=0; i < 20; i++){ new IAttractor(IRand.pt(-200,-200,0,200,200,0)).linear(50).intensity(-30); //repulsion force } IG.bg(1.0,1.0,1.0); IG.top(); } class LineAgent extends IParticle{ LineAgent parent; boolean isColliding; IVec dir; LineAgent(IParticle parent, IVec dir){ super(parent.pos().cp(dir)); if(parent instanceof LineAgent){ this.parent = (LineAgent)parent; } isColliding=false; hide(); // hide point this.dir = dir; fric(0.2); } void interact(ArrayListagents){ if(time()==0){ //only in the first time for(int i=0; i < agents.size(); i++){ if(agents.get(i) instanceof LineAgent){ LineAgent lineAgent = (LineAgent)agents.get(i); if(lineAgent!=this){ //agents include "this" if(lineAgent.parent!=null && lineAgent.pos().dist(pos()) < pos().dist(parent.pos())*2){ IVec intxn = IVec.intersectSegment(lineAgent.parent.pos(),lineAgent.pos(),parent.pos(),pos()); if( intxn != null && !intxn.eq(parent.pos()) && !lineAgent.isColliding ){ isColliding = true; return; } } } } } } } void update(){ if( isColliding ){ del(); } else{ if(time()==0 && alive()){ if(parent!=null && parent.alive()){ ISpringLine ln = new ISpringLine(this, parent,100); double t = -cos(IG.time()*0.015)*0.5+0.5; ln.hsb( 0.7-t*0.2, 1, 0.8-t*0.2, 0.5); // color by time if(parent.parent!=null && parent.parent.alive()){ IStraightenerCurve st = new IStraightenerCurve(this,parent,parent.parent).tension(100); st.hsb( 0.7-t*0.2, 1, 0.8-t*0.2, 0.5); } } } if(time()==4){ IVec dir2 = dir.cp(); double angle = PI*0.12 ; if( IRand.pct(50) ){ dir.rot(angle); dir2.rot(-angle); } else{ dir.rot(-angle); dir2.rot(angle); } new LineAgent(this, dir); if( IRand.pct(20) ){ // 20% branching probability new LineAgent(this,dir2); } } } } }
import igeo.*; import processing.opengl.*; void setup(){ size(480,360,IG.GL); for(int i=0; i < 4; i++){ new LineAgent(new IParticle(IRand.pt(-40,-40,0,40,40,0)).hide().fric(0.2), IRand.dir(IG.zaxis).len(2), null); } for(int i=0; i < 20; i++){ new IAttractor(IRand.pt(-200,-200,0,200,200,0)).linear(50).intensity(-30); //repulsion force } IG.bg(1.0,1.0,1.0); IG.top(); } class LineAgent extends IParticle{ LineAgent parent, root; boolean isColliding; IVec dir; LineAgent(IParticle parent, IVec dir, LineAgent root){ super(parent.pos().cp(dir)); if(parent instanceof LineAgent){ this.parent = (LineAgent)parent; } isColliding=false; hide(); // hide point this.dir = dir; fric(0.2); if(root!=null){ this.root = root; } else{ this.root = this; } } void interact(ArrayList< IDynamics > agents){ if(time()==0){ //only in the first time for(int i=0; i < agents.size(); i++){ if(agents.get(i) instanceof LineAgent){ LineAgent lineAgent = (LineAgent)agents.get(i); if(lineAgent!=this){ //agents include "this" if(lineAgent.parent!=null && lineAgent.pos().dist(pos()) < pos().dist(parent.pos())*2){ IVec intxn = IVec.intersectSegment(lineAgent.parent.pos(),lineAgent.pos(),parent.pos(),pos()); if( intxn != null && !intxn.eq(parent.pos()) && !lineAgent.isColliding ){ isColliding = true; return; } } } } } } else if(time()==1){ for(int i=0; i < agents.size(); i++){ if(agents.get(i) instanceof LineAgent){ LineAgent lineAgent = (LineAgent)agents.get(i); if(lineAgent!=this && lineAgent.alive()){ //agents include "this" if(lineAgent.root != root){ // different branch IVec dif = lineAgent.pos().dif(pos()); if(dif.len() < dir.len()*2.5 && dif.len()>dir.len()){ // within threshold ISpringLine sp = new ISpringLine(lineAgent,this,5,dir.len()*1.5).tension(5); double t = -cos(IG.time()*0.015)*0.5+0.5; sp.hsb(0.7-t*0.2, 1, 0.8-t*0.2, 0.2); } } } } } } } void update(){ if( isColliding ){ del(); } else{ if(time()==0 && alive()){ if(parent!=null && parent.alive()){ ISpringLine ln = new ISpringLine(this, parent,100); double t = -cos(IG.time()*0.015)*0.5+0.5; ln.hsb( 0.7-t*0.2, 1, 0.8-t*0.2, 0.2); // color by tim if(parent.parent!=null && parent.parent.alive()){ IStraightenerCurve st = new IStraightenerCurve(this,parent,parent.parent).tension(100); st.hsb( 0.7-t*0.2, 1, 0.8-t*0.2, 0.2); } } } if(time()==4){ IVec dir2 = dir.cp(); double angle = PI*0.12 ; if( IRand.pct(50) ){ dir.rot(angle); dir2.rot(-angle); } else{ dir.rot(-angle); dir2.rot(angle); } new LineAgent(this, dir, root); if( IRand.pct(20) ){ // 20% branching probability new LineAgent(this,dir2, null); } } } } }
import igeo.*; import processing.opengl.*; void setup(){ size(480,360,IG.GL); for(int i=0; i < 4; i++){ new LineAgent(new IParticle(IRand.pt(-40,-40,0,40,40,0)).hide().fric(0.2), IRand.dir(IG.zaxis).len(2), null); } for(int i=0; i < 20; i++){ new IAttractor(IRand.pt(-200,-200,0,200,200,0)).linear(50).intensity(-30);//repulsion force } new IPointCurlField(new IVec(0,0,0), new IVec(0,0,1)).intensity(50); //spinning force IG.bg(1.0,1.0,1.0); IG.top(); } class LineAgent extends IParticle{ LineAgent parent, root; boolean isColliding; IVec dir; LineAgent(IParticle parent, IVec dir, LineAgent root){ super(parent.pos().cp(dir)); if(parent instanceof LineAgent){ this.parent = (LineAgent)parent; } isColliding=false; hide(); // hide point this.dir = dir; fric(0.2); if(root!=null){ this.root = root; } else{ this.root = this; } } void interact(ArrayList< IDynamics > agents){ if(time()==0){ //only in the first time for(int i=0; i < agents.size(); i++){ if(agents.get(i) instanceof LineAgent){ LineAgent lineAgent = (LineAgent)agents.get(i); if(lineAgent!=this){ //agents include "this" if(lineAgent.parent!=null && lineAgent.pos().dist(pos()) < pos().dist(parent.pos())*2){ IVec intxn = IVec.intersectSegment(lineAgent.parent.pos(),lineAgent.pos(),parent.pos(),pos()); if( intxn != null && !intxn.eq(parent.pos()) && !lineAgent.isColliding ){ isColliding = true; return; } } } } } } else if(time()==1){ for(int i=0; i < agents.size(); i++){ if(agents.get(i) instanceof LineAgent){ LineAgent lineAgent = (LineAgent)agents.get(i); if(lineAgent!=this && lineAgent.alive()){ //agents include "this" if(lineAgent.root != root){ // different branch IVec dif = lineAgent.pos().dif(pos()); if(dif.len() < dir.len()*2.5 && dif.len()>dir.len()){ // within threshold ISpringLine sp = new ISpringLine(lineAgent,this,5,dir.len()*1.5).tension(5); double t = -cos(IG.time()*0.015)*0.5+0.5; sp.hsb(0.7-t*0.2, 1, 0.8-t*0.2, 0.2); } } } } } } } void update(){ if( isColliding ){ del(); } else{ if(time()==0 && alive()){ if(parent!=null && parent.alive()){ ISpringLine ln = new ISpringLine(this, parent,100); double t = -cos(IG.time()*0.015)*0.5+0.5; ln.hsb( 0.7-t*0.2, 1, 0.8-t*0.2, 0.2); // color by tim if(parent.parent!=null && parent.parent.alive()){ IStraightenerCurve st = new IStraightenerCurve(this,parent,parent.parent).tension(100); st.hsb( 0.7-t*0.2, 1, 0.8-t*0.2, 0.2); } } } if(time()==4){ IVec dir2 = dir.cp(); double angle = PI*0.12 ; if( IRand.pct(50) ){ dir.rot(angle); dir2.rot(-angle); } else{ dir.rot(-angle); dir2.rot(angle); } new LineAgent(this, dir, root); if( IRand.pct(20) ){ // 20% branching probability new LineAgent(this,dir2, null); } } } } }