Tutorials | (back to the list of tutorials) |
import igeo.*; import processing.opengl.*; void setup() { size(480, 360, IG.GL); IG.duration(120); new MyAgent(IG.v(0, 0, 0), IG.v(1, 0, 0)).clr(0); } class MyAgent extends IAgent { IVec pt1, pt2; boolean isColliding=false; MyAgent(IVec pos, IVec dir) { pt1 = pos; pt2 = pos.cp(dir); } void interact(ArrayList < IDynamics > agents) { for (int i=0; i < agents.size() && !isColliding; i++) { if (agents.get(i) instanceof MyAgent) { MyAgent agent = (MyAgent)agents.get(i); if (agent != this) { double dist = agent.pt2.dist(pt2); //distance of end points double tolerance = 0.5; //smaller number allows more collision if (dist < pt1.dist(pt2)*tolerance) { isColliding = true; } } } } } void update() { if (isColliding) { del(); } else if (time()==0) { new ICurve(pt1, pt2).clr(clr()); if (IRand.pct(95)) { //branch 1 IVec dir = pt2.dif(pt1); double angle = IRand.get(-PI/6, PI/6); dir.rot(IG.zaxis, angle); double scale = IRand.get(0.90, 1.08); dir.mul(scale); new MyAgent(pt2.cp(), dir).clr(clr()); } if (IRand.pct(50)) { //branch 2 IVec dir = pt2.dif(pt1); double angle = IRand.get(-PI/3*2, PI/3*2); dir.rot(IG.zaxis, angle); double scale = IRand.get(0.90, 1.08); dir.mul(scale); new MyAgent(pt2, dir).clr(clr()); } } } }
The second code below puts polygon mesh boxes on the start points of
the agents. Polygon mesh box is created by this method in IG class.
       
IG.meshBox(corner, boxDir1, boxDir2, boxDir3)
The direction of the box is aligned to the direction of
the agent and its size is randomized.
The color is also randomized in gray scale.
import igeo.*; import processing.opengl.*; void setup() { size(480, 360, IG.GL); IG.duration(80); new MyAgent(IG.v(0, 0, 0), IG.v(1, 0, 0)).clr(0.5); } class MyAgent extends IAgent { IVec pt1, pt2; boolean isColliding=false; MyAgent(IVec pos, IVec dir) { pt1 = pos; pt2 = pos.cp(dir); } void interact(ArrayList < IDynamics > agents) { for (int i=0; i < agents.size() && !isColliding; i++) { if (agents.get(i) instanceof MyAgent) { MyAgent agent = (MyAgent)agents.get(i); if (agent != this) { double dist = agent.pt2.dist(pt2); //distance of end points double tolerance = 0.5; //smaller number allows more collision if (dist < pt1.dist(pt2)*tolerance) { isColliding = true; } } } } } void update() { if (isColliding) { del(); } else if (time()==0) { double boxScale = IRand.get(1.0, 2.5); IVec boxDir1 = pt2.dif(pt1).mul(boxScale); IVec boxDir2 = boxDir1.cp().rot(IG.zaxis, PI/2); IVec boxDir3 = IG.v(0,0,boxDir1.len()); IVec corner = pt1.cp().sub(boxDir1.cp().div(2)).sub(boxDir2.cp().div(2)); IG.meshBox(corner, boxDir1, boxDir2, boxDir3).clr(clr()); if (IRand.pct(95)) { //branch 1 IVec dir = pt2.dif(pt1); double angle = IRand.get(-PI/6, PI/6); dir.rot(IG.zaxis, angle); double scale = IRand.get(0.90, 1.08); dir.mul(scale); double gray = (red()+green()+blue())/3+ IRand.get(-0.05,0.05); new MyAgent(pt2.cp(), dir).clr(gray); } if (IRand.pct(50)) { //branch 2 IVec dir = pt2.dif(pt1); double angle = IRand.get(-PI/3*2, PI/3*2); dir.rot(IG.zaxis, angle); double scale = IRand.get(0.90, 1.08); dir.mul(scale); double gray = (red()+green()+blue())/3 + IRand.get(-0.05,0.05); new MyAgent(pt2, dir).clr(gray); } } } }
The next code manipulates a rotational axis of branching to create 3 dimensional branches. The agent class has a new data field axis as the rotational axis of branching rotation and also as one of edge directions of the box geometry.
import igeo.*; import processing.opengl.*; void setup() { size(480, 360, IG.GL); IRand.init(2); IG.duration(40); new MyAgent(IG.v(0, 0, 0), IG.v(1, 0, 0), IG.v(0, 0, 1)).clr(0.5); } class MyAgent extends IAgent { IVec pt1, pt2, axis; boolean isColliding=false; MyAgent(IVec pos, IVec dir, IVec ax) { pt1 = pos; pt2 = pos.cp(dir); axis = ax; } void interact(ArrayList < IDynamics > agents) { for (int i=0; i < agents.size() && !isColliding; i++) { if (agents.get(i) instanceof MyAgent) { MyAgent agent = (MyAgent)agents.get(i); if (agent != this) { double dist = agent.pt2.dist(pt2); //distance of end points double tolerance = 0.5; //smaller number allows more collision if (dist < pt1.dist(pt2)*tolerance) { isColliding = true; } } } } } void update() { if (isColliding) { del(); } else if (time()==0) { double boxScale = IRand.get(1.0, 2.5); IVec boxDir1 = pt2.dif(pt1).mul(boxScale); IVec boxDir2 = boxDir1.cp().rot(axis, PI/2); IVec boxDir3 = boxDir1.cross(boxDir2).len(boxDir1.len()); // perpendicular to boxDir1 and boxDir2 IVec corner = pt1.cp().sub(boxDir1.cp().div(2)).sub(boxDir2.cp().div(2)); IG.meshBox(corner, boxDir1, boxDir2, boxDir3).clr(clr()); axis = boxDir3; if (IRand.pct(95)) { //branch 1 IVec dir = pt2.dif(pt1); double angle = IRand.get(-PI/6, PI/6); dir.rot(axis, angle); double scale = IRand.get(0.90, 1.08); dir.mul(scale); IVec axis2 = axis.cp().rot(dir, IRand.get(-PI/6, PI/6)); double gray = (red()+green()+blue())/3+ IRand.get(-0.05,0.05); new MyAgent(pt2.cp(), dir, axis2).clr(gray); } if (IRand.pct(50)) { //branch 2 IVec dir = pt2.dif(pt1); double angle = IRand.get(-PI/3*2, PI/3*2); dir.rot(axis, angle); double scale = IRand.get(0.90, 1.08); dir.mul(scale); IVec axis2 = axis.cp().rot(dir, IRand.get(-PI/6, PI/6)); double gray = (red()+green()+blue())/3 + IRand.get(-0.05,0.05); new MyAgent(pt2, dir, axis2).clr(gray); } } } }
The code below takes a Rhino input file which contains
one polygon mesh geometry and
use this geometry as each agent's geometry instead of a box.
The agent class has a new data field of mesh
and the original template mesh geometry from the input file
is passed to each agents.
This template mesh geometry is copied, moved and rotated to the
agent's orientation which is defined by pt1, pt2 and
axis. The method to move and rotate is transform(xvec,yvec,zvec,translate).
       
mesh.cp().transform(meshDir1, meshDir2, meshDir3, pt1);
The first three input arguments of IVec are new vectors to map
the original X, Y and Z vectors onto.
The fourth input argument of IVec is to move the whole geometry,
just like adding a vector to the geometry.
The input file with a polygon mesh geometry used in the example is the following.
import igeo.*; import processing.opengl.*; void setup() { size(480, 360, IG.GL); IRand.init(2); IG.duration(40); IG.open("mesh1.3dm"); IMesh mesh = IG.mesh(0); mesh.del(); //hide the original new MyAgent(mesh, IG.v(0, 0, 0), IG.v(1, 0, 0), IG.v(0, 0, 1)).clr(0.5); } class MyAgent extends IAgent { IVec pt1, pt2, axis; boolean isColliding=false; IMesh mesh; MyAgent(IMesh m, IVec pos, IVec dir, IVec ax) { pt1 = pos; pt2 = pos.cp(dir); axis = ax; mesh = m; } void interact(ArrayList < IDynamics > agents) { for (int i=0; i < agents.size() && !isColliding; i++) { if (agents.get(i) instanceof MyAgent) { MyAgent agent = (MyAgent)agents.get(i); if (agent != this) { double dist = agent.pt2.dist(pt2); //distance of end points double tolerance = 0.5; //smaller number allows more collision if (dist < pt1.dist(pt2)*tolerance) { isColliding = true; } } } } } void update() { if (isColliding) { del(); } else if (time()==0) { double meshScale = IRand.get(2.0, 5.0); IVec meshDir1 = pt2.dif(pt1).mul(meshScale); IVec meshDir2 = meshDir1.cp().rot(axis, PI/2); IVec meshDir3 = meshDir1.cross(meshDir2).len(meshDir1.len()); // perpendicular to meshDir1 and meshDir2 mesh.cp().transform(meshDir1, meshDir2, meshDir3, pt1).clr(clr()); axis = meshDir3; if (IRand.pct(95)) { //branch 1 IVec dir = pt2.dif(pt1); double angle = IRand.get(-PI/3, PI/3); dir.rot(axis, angle); double scale = IRand.get(0.90, 1.05); dir.mul(scale); IVec axis2 = axis.cp().rot(dir, IRand.get(-PI/3, PI/3)); double gray = (red()+green()+blue())/3+ IRand.get(-0.05,0.05); new MyAgent(mesh, pt2.cp(), dir, axis2).clr(gray); } if (IRand.pct(50)) { //branch 2 IVec dir = pt2.dif(pt1); double angle = IRand.get(-PI/3*2, PI/3*2); dir.rot(axis, angle); double scale = IRand.get(0.90, 1.05); dir.mul(scale); IVec axis2 = axis.cp().rot(dir, IRand.get(-PI/3, PI/3)); double gray = (red()+green()+blue())/3 + IRand.get(-0.05,0.05); new MyAgent(mesh, pt2, dir, axis2).clr(gray); } } } }