Tutorials
(back to the list of tutorials)
Variation of Geometries on Multi Agent Algorithm
(requires iGeo version 7.4.0 or higher)
 
Pipes on Agents
This section shows examples of variation of geometries created along agents. Taking one of the examples of multi-agent algorithms already shown in the tutorials, different ways to put geometries on agents are described. The multi-agent algorithm used here is this branching algorithm. The following example shows a simple way to put one square pipe on each agent.
import processing.opengl.*;
import igeo.*;
void setup(){
size(480, 360, IG.GL);
IG.duration(100);
new LineAgent(new IVec(0,0,0), new IVec(1,0,0));
}
static class LineAgent extends IAgent{
static double length = 2;
static double clearance = 1.99; //less than length
IVec pt1, pt2;
boolean isColliding=false;
LineAgent(IVec pt, IVec dir){
pt1 = pt;
pt2 = pt.dup().add(dir.dup().len(length));
}
void interact(ArrayList < IDynamics > agents){
super.interact(agents);
if(time == 0){ //only in the first time
for(int i=0; i < agents.size() && !isColliding; i++){
if(agents.get(i) instanceof LineAgent){
LineAgent lineAgent =
(LineAgent)agents.get(i);
if(lineAgent != this){ //agents include "this"
// checking clearance of end point
if(lineAgent.pt2.dist(pt2) < clearance){
isColliding=true;
}
}
}
}
}
}
void update(){
super.update();
if(isColliding){
del();
}
else if(time == 0){ //if not colliding
IG.squarePipe(pt1,pt2,.2).clr(IRandom.gray());
IVec dir = pt2.diff(pt1);
//rotation axis with random direction
IVec axis = IRandom.pt(-1,1).len(1);
if(IRandom.percent(50)){ //bend
new LineAgent(pt2, dir.dup().rot(axis,
IRandom.get(PI/3,PI/3*2)));
}
if(IRandom.percent(50)){ //bend the other way
new LineAgent(pt2, dir.dup().rot(axis,
-IRandom.get(PI/3,PI/3*2)));
}
if(IRandom.percent(80)){ //straight
new LineAgent(pt2, dir.dup());
}
}
}
}
 
Tangent Curves on Agents
import processing.opengl.*;
import igeo.*;
void setup(){
size(480, 360, IG.GL);
IG.duration(100);
new LineAgent(new IVec(0,0,0), new IVec(1,0,0)).clr(0);
}
static class LineAgent extends IAgent{
static double length = 2;
static double clearance = 1.99; //less than length
IVec pt1, pt2;
boolean isColliding=false;
LineAgent(IVec pt, IVec dir){
pt1 = pt;
pt2 = pt.dup().add(dir.dup().len(length));
}
void interact(ArrayList < IDynamics > agents){
super.interact(agents);
if(time == 0){ //only in the first time
for(int i=0; i < agents.size() && !isColliding; i++){
if(agents.get(i) instanceof LineAgent){
LineAgent lineAgent =
(LineAgent)agents.get(i);
if(lineAgent != this){ //agents include "this"
// checking clearance of end point
if(lineAgent.pt2.dist(pt2) < clearance){
isColliding=true;
}
}
}
}
}
}
void update(){
super.update();
if(isColliding){
del();
}
else if(time == 0){ //if not colliding
IVec dir = pt2.diff(pt1);
IVec axis = IRandom.pt(-1,1).len(1);
if(IRandom.percent(100)){ //bend
IVec nextDir1 =
dir.dup().rot(axis,IRandom.get(PI/3,PI/3*2));
//degree 2 curve at midpoint of pt1&pt2, pt2, and midpoint of pt2 and next agent's point
new ICurve(new IVec[]{ pt1.mid(pt2),
pt2,
pt2.mid(pt2.cp(nextDir1))},
2).clr(clr());
new LineAgent(pt2, nextDir1).clr(clr());
}
if(IRandom.percent(50)){ //bend the other way
//degree 2 curve at midpoint of pt1&pt2, pt2, and midpoint of pt2 and next agent's point
IVec nextDir2 =
dir.dup().rot(axis,-IRandom.get(PI/3,PI/3*2));
new ICurve(new IVec[]{ pt1.mid(pt2),
pt2,
pt2.mid(pt2.cp(nextDir2))},
2).clr(clr());
new LineAgent(pt2, nextDir2).clr(clr());
}
}
}
}
 
Surfaces with Tangent Edges on Agents
import processing.opengl.*;
import igeo.*;
void setup(){
size(480, 360, IG.GL);
IRand.init(8);
IG.duration(120);
new LineAgent(new IVec(0,0,0), new IVec(1,0,0)).clr(0);
IG.fill();
}
static class LineAgent extends IAgent{
static double length = 2;
static double clearance = 1.99; //less than length
IVec pt1, pt2;
boolean isColliding=false;
LineAgent(IVec pt, IVec dir){
pt1 = pt;
pt2 = pt.dup().add(dir.dup().len(length));
}
void interact(ArrayList < IDynamics > agents){
super.interact(agents);
if(time == 0){ //only in the first time
for(int i=0; i < agents.size() && !isColliding; i++){
if(agents.get(i) instanceof LineAgent){
LineAgent lineAgent =
(LineAgent)agents.get(i);
if(lineAgent != this){ //agents include "this"
//checking clearance of end point
if(lineAgent.pt2.dist(pt2) < clearance){
isColliding=true;
}
}
}
}
}
}
void update(){
super.update();
if(isColliding){ del(); }
else if(time == 0){ //if not colliding
IVec dir = pt2.diff(pt1);
IVec axis = IRand.pt(-1,1).len(1);
IVec nextDir1 = dir.dup().rot(axis,PI/3);
IVec nextDir2 = dir.dup().rot(axis,-PI/3);
//degree 2 surface with 3x3 control points
IVec[][] cpts = new IVec[3][3];
cpts[0][0] = pt1.mid(pt2);
cpts[0][1] = pt1.mid(pt2);
cpts[0][2] = pt1.mid(pt2);
cpts[1][0] = pt2;
cpts[1][1] = pt2;
cpts[1][2] = pt2;
cpts[2][0] = pt2.mid(pt2.cp(nextDir1));
cpts[2][1] = pt2;
cpts[2][2] = pt2.mid(pt2.cp(nextDir2));
new ISurface(cpts, 2, 2).clr(clr());
int r = clr().getRed() + IRand.getInt(-10, 10);
int g = clr().getGreen() + IRand.getInt(-10, 10);
int b = clr().getBlue() + IRand.getInt(-10, 10);
if(IRand.percent(80)){ //bend
new LineAgent(pt2, nextDir1).clr(r,g,b);
}
if(IRand.percent(50)){ //bend the other way
new LineAgent(pt2, nextDir2).clr(r,g,b);
}
}
}
}
 
Surfaces around Agents: 1
import processing.opengl.*;
import igeo.*;
void setup(){
size(480, 360, IG.GL);
IRand.init(3);
IG.duration(30);
new LineAgent(new IVec(0,0,0), new IVec(1,0,0)).clr(0);
IG.fill();
}
static class LineAgent extends IAgent{
static double length = 2;
static double clearance = 1.99; //less than length
IVec pt1, pt2;
boolean isColliding=false;
LineAgent(IVec pt, IVec dir){
pt1 = pt;
pt2 = pt.dup().add(dir.dup().len(length));
}
void interact(ArrayList < IDynamics > agents){
super.interact(agents);
if(time == 0){ //only in the first time
for(int i=0; i < agents.size() && !isColliding; i++){
if(agents.get(i) instanceof LineAgent){
LineAgent lineAgent =
(LineAgent)agents.get(i);
if(lineAgent != this){ //agents include "this"
//checking clearance of end point
if(lineAgent.pt2.dist(pt2) < clearance){
isColliding=true;
}
}
}
}
}
}
void update(){
super.update();
if(isColliding){ del(); }
else if(time == 0){ //if not colliding
new ICurve(pt1,pt2); // center line
IVec dir = pt2.diff(pt1);
//making axis perpendicular to dir
IVec axis = IRand.pt(-1,1).cross(dir);
// child dir & points
IVec nextDir1 = dir.dup().rot(axis,PI/3);
IVec nextDir2 = dir.dup().rot(axis,-PI/3);
IVec nextPt1 = pt2.cp(nextDir1);
IVec nextPt2 = pt2.cp(nextDir2);
//midpoints
IVec mid1 = pt1.mid(pt2);
IVec mid2 = pt2.mid(nextPt1);
IVec mid3 = pt2.mid(nextPt2);
//mid of midpoints
IVec quarter1 = pt2.mid(mid1);
IVec quarter2 = pt2.mid(mid2);
IVec quarter3 = pt2.mid(mid3);
double offsetWidth = -0.5;
IVec offset1 = dir.cross(axis).len(offsetWidth);
IVec offset2 = nextDir1.cross(axis).len(offsetWidth);
IVec offset3 = nextDir2.cross(axis).len(offsetWidth);
//offset edge points 1
IVec edgePt11 = mid1.cp(offset1);
IVec edgePt12 = quarter1.cp(offset1);
IVec edgePt13 = quarter2.cp(offset2);
IVec edgePt14 = mid2.cp(offset2);
//offset edge points 2
offset2.flip(); //offset to opposite
IVec edgePt21 = mid2.cp(offset2);
IVec edgePt22 = quarter2.cp(offset2);
IVec edgePt23 = quarter3.cp(offset3);
IVec edgePt24 = mid3.cp(offset3);
//offset edge points 3
offset1.flip(); //offset to opposite
offset3.flip(); //offset to opposite
IVec edgePt31 = mid3.cp(offset3);
IVec edgePt32 = quarter3.cp(offset3);
IVec edgePt33 = quarter1.cp(offset1);
IVec edgePt34 = mid1.cp(offset1);
//degree 3 curves
new ICurve(new IVec[]{ edgePt11,edgePt12,
edgePt13,edgePt14 }, 3).clr(0);
new ICurve(new IVec[]{ edgePt21,edgePt22,
edgePt23,edgePt24 }, 3).clr(0);
new ICurve(new IVec[]{ edgePt31,edgePt32,
edgePt33,edgePt34 }, 3).clr(0);
if(IRand.percent(80)){ //bend
new LineAgent(pt2, nextDir1);
}
if(IRand.percent(50)){ //bend the other way
new LineAgent(pt2, nextDir2);
}
}
}
}
Then next, a surface on the offset curve is calculated by shifting the control points on both direction of the axis with the depthVec vector.
import processing.opengl.*;
import igeo.*;
void setup(){
size(480, 360, IG.GL);
IRand.init(3);
IG.duration(30);
new LineAgent(new IVec(0,0,0), new IVec(1,0,0)).clr(0);
IG.fill();
}
static class LineAgent extends IAgent{
static double length = 2;
static double clearance = 1.99; //less than length
IVec pt1, pt2;
boolean isColliding=false;
LineAgent(IVec pt, IVec dir){
pt1 = pt;
pt2 = pt.dup().add(dir.dup().len(length));
}
void interact(ArrayList < IDynamics > agents){
super.interact(agents);
if(time == 0){ //only in the first time
for(int i=0; i < agents.size() && !isColliding; i++){
if(agents.get(i) instanceof LineAgent){
LineAgent lineAgent =
(LineAgent)agents.get(i);
if(lineAgent != this){ //agents include "this"
//checking clearance of end point
if(lineAgent.pt2.dist(pt2) < clearance){
isColliding=true;
}
}
}
}
}
}
void update(){
super.update();
if(isColliding){ del(); }
else if(time == 0){ //if not colliding
new ICurve(pt1,pt2); // center line
IVec dir = pt2.diff(pt1);
//making axis perpendicular to dir
IVec axis = IRand.pt(-1,1).cross(dir);
// child dir & points
IVec nextDir1 = dir.dup().rot(axis,PI/3);
IVec nextDir2 = dir.dup().rot(axis,-PI/3);
IVec nextPt1 = pt2.cp(nextDir1);
IVec nextPt2 = pt2.cp(nextDir2);
//midpoints
IVec mid1 = pt1.mid(pt2);
IVec mid2 = pt2.mid(nextPt1);
IVec mid3 = pt2.mid(nextPt2);
//mid of midpoints
IVec quarter1 = pt2.mid(mid1);
IVec quarter2 = pt2.mid(mid2);
IVec quarter3 = pt2.mid(mid3);
double offsetWidth = -0.5;
IVec offset1 = dir.cross(axis).len(offsetWidth);
IVec offset2 = nextDir1.cross(axis).len(offsetWidth);
IVec offset3 = nextDir2.cross(axis).len(offsetWidth);
//offset edge points 1
IVec edgePt11 = mid1.cp(offset1);
IVec edgePt12 = quarter1.cp(offset1);
IVec edgePt13 = quarter2.cp(offset2);
IVec edgePt14 = mid2.cp(offset2);
//offset edge points 2
offset2.flip(); //offset to opposite
IVec edgePt21 = mid2.cp(offset2);
IVec edgePt22 = quarter2.cp(offset2);
IVec edgePt23 = quarter3.cp(offset3);
IVec edgePt24 = mid3.cp(offset3);
//offset edge points 3
offset1.flip(); //offset to opposite
offset3.flip(); //offset to opposite
IVec edgePt31 = mid3.cp(offset3);
IVec edgePt32 = quarter3.cp(offset3);
IVec edgePt33 = quarter1.cp(offset1);
IVec edgePt34 = mid1.cp(offset1);
double depth = 0.5;
IVec depthVec = axis.dup().len(depth);
IVec[][] cpts1 = new IVec[4][2];
cpts1[0][0] = edgePt11.dup().add(depthVec);
cpts1[1][0] = edgePt12.dup().add(depthVec);
cpts1[2][0] = edgePt13.dup().add(depthVec);
cpts1[3][0] = edgePt14.dup().add(depthVec);
cpts1[0][1] = edgePt11.dup().sub(depthVec);
cpts1[1][1] = edgePt12.dup().sub(depthVec);
cpts1[2][1] = edgePt13.dup().sub(depthVec);
cpts1[3][1] = edgePt14.dup().sub(depthVec);
IVec[][] cpts2 = new IVec[4][2];
cpts2[0][0] = edgePt21.dup().add(depthVec);
cpts2[1][0] = edgePt22.dup().add(depthVec);
cpts2[2][0] = edgePt23.dup().add(depthVec);
cpts2[3][0] = edgePt24.dup().add(depthVec);
cpts2[0][1] = edgePt21.dup().sub(depthVec);
cpts2[1][1] = edgePt22.dup().sub(depthVec);
cpts2[2][1] = edgePt23.dup().sub(depthVec);
cpts2[3][1] = edgePt24.dup().sub(depthVec);
IVec[][] cpts3 = new IVec[4][2];
cpts3[0][0] = edgePt31.dup().add(depthVec);
cpts3[1][0] = edgePt32.dup().add(depthVec);
cpts3[2][0] = edgePt33.dup().add(depthVec);
cpts3[3][0] = edgePt34.dup().add(depthVec);
cpts3[0][1] = edgePt31.dup().sub(depthVec);
cpts3[1][1] = edgePt32.dup().sub(depthVec);
cpts3[2][1] = edgePt33.dup().sub(depthVec);
cpts3[3][1] = edgePt34.dup().sub(depthVec);
new ISurface(cpts1, 3, 1);
new ISurface(cpts2, 3, 1);
new ISurface(cpts3, 3, 1);
if(IRand.percent(80)){ //bend
new LineAgent(pt2, nextDir1);
}
if(IRand.percent(50)){ //bend the other way
new LineAgent(pt2, nextDir2);
}
}
}
}
In this example, the surface edges between an agent and the next child are not matching. A technique to make it connected and tangent is shown in the next example.
 
Surfaces around Agents: 2
import processing.opengl.*;
import igeo.*;
void setup(){
size(480, 360, IG.GL);
IRand.init(3);
IG.duration(30);
//second and third vector needs to be perpendicular
new LineAgent(new IVec(0,0,0), new IVec(1,0,0),
new IVec(0,0,1)).clr(0);
IG.fill();
}
static class LineAgent extends IAgent{
static double length = 2;
static double clearance = 1.99; //less than length
IVec pt1, pt2, axis;
boolean isColliding=false;
LineAgent(IVec pt, IVec dir, IVec ax){
pt1 = pt;
pt2 = pt.dup().add(dir.dup().len(length));
axis = ax;
}
void interact(ArrayList < IDynamics > agents){
super.interact(agents);
if(time == 0){ //only in the first time
for(int i=0; i < agents.size() && !isColliding; i++){
if(agents.get(i) instanceof LineAgent){
LineAgent lineAgent =
(LineAgent)agents.get(i);
if(lineAgent != this){ //agents include "this"
//checking clearance of end point
if(lineAgent.pt2.dist(pt2) < clearance){
isColliding=true;
}
}
}
}
}
}
void update(){
super.update();
if(isColliding){ del(); }
else if(time == 0){ //if not colliding
new ICurve(pt1,pt2); // center line
IVec dir = pt2.diff(pt1);
// child dir & points
IVec nextDir1 = dir.dup().rot(axis, IRand.get(PI/4,PI/3));
IVec nextDir2 = dir.dup().rot(axis,-IRand.get(PI/4,PI/3));
IVec nextPt1 = pt2.cp(nextDir1);
IVec nextPt2 = pt2.cp(nextDir2);
//midpoints
IVec mid1 = pt1.mid(pt2);
IVec mid2 = pt2.mid(nextPt1);
IVec mid3 = pt2.mid(nextPt2);
//mid of midpoints
IVec quarter1 = pt2.mid(mid1);
IVec quarter2 = pt2.mid(mid2);
IVec quarter3 = pt2.mid(mid3);
//axis of child agents
IVec nextAxis1 = axis.dup().rot(nextDir1, IRand.get(-PI/3,PI/3));
IVec nextAxis2 = axis.dup().rot(nextDir2, IRand.get(-PI/3,PI/3));
double offsetWidth = -0.5;
IVec offset1 = dir.cross(axis).len(offsetWidth);
IVec offset2 = nextDir1.cross(nextAxis1).len(offsetWidth);
IVec offset3 = nextDir2.cross(nextAxis2).len(offsetWidth);
//offset edge points 1
IVec edgePt11 = mid1.cp(offset1);
IVec edgePt12 = quarter1.cp(offset1);
IVec edgePt13 = quarter2.cp(offset2);
IVec edgePt14 = mid2.cp(offset2);
//offset edge points 2
offset2.flip(); //offset to opposite
IVec edgePt21 = mid2.cp(offset2);
IVec edgePt22 = quarter2.cp(offset2);
IVec edgePt23 = quarter3.cp(offset3);
IVec edgePt24 = mid3.cp(offset3);
//offset edge points 3
offset1.flip(); //offset to opposite
offset3.flip(); //offset to opposite
IVec edgePt31 = mid3.cp(offset3);
IVec edgePt32 = quarter3.cp(offset3);
IVec edgePt33 = quarter1.cp(offset1);
IVec edgePt34 = mid1.cp(offset1);
//degree 3 curves
new ICurve(new IVec[]{ edgePt11,edgePt12,
edgePt13,edgePt14 }, 3).clr(0);
new ICurve(new IVec[]{ edgePt21,edgePt22,
edgePt23,edgePt24 }, 3).clr(0);
new ICurve(new IVec[]{ edgePt31,edgePt32,
edgePt33,edgePt34 }, 3).clr(0);
if(IRand.percent(80)){ //bend
new LineAgent(pt2, nextDir1, nextAxis1);
}
if(IRand.percent(50)){ //bend the other way
new LineAgent(pt2, nextDir2, nextAxis2);
}
}
}
}
The surfaces are created on the offset curves. The code to create a surface out of 4 control points and two different ex is separated in a method of createEdgeSurface.
import processing.opengl.*;
import igeo.*;
void setup(){
size(480, 360, IG.GL);
IRand.init(3);
IG.duration(30);
//second and third vector needs to be perpendicular
new LineAgent(new IVec(0,0,0), new IVec(1,0,0),
new IVec(0,0,1)).clr(0);
IG.fill();
}
static class LineAgent extends IAgent{
static double length = 2;
static double clearance = 1.99; //less than length
IVec pt1, pt2, axis;
boolean isColliding=false;
LineAgent(IVec pt, IVec dir, IVec ax){
pt1 = pt;
pt2 = pt.dup().add(dir.dup().len(length));
axis = ax;
}
void interact(ArrayList < IDynamics > agents){
super.interact(agents);
if(time == 0){ //only in the first time
for(int i=0; i < agents.size() && !isColliding; i++){
if(agents.get(i) instanceof LineAgent){
LineAgent lineAgent =
(LineAgent)agents.get(i);
if(lineAgent != this){ //agents include "this"
//checking clearance of end point
if(lineAgent.pt2.dist(pt2) < clearance){
isColliding=true;
}
}
}
}
}
}
void update(){
super.update();
if(isColliding){ del(); }
else if(time == 0){ //if not colliding
new ICurve(pt1,pt2); // center line
IVec dir = pt2.diff(pt1);
// child dir & points
IVec nextDir1 = dir.dup().rot(axis, IRand.get(PI/4,PI/3));
IVec nextDir2 = dir.dup().rot(axis,-IRand.get(PI/4,PI/3));
IVec nextPt1 = pt2.cp(nextDir1);
IVec nextPt2 = pt2.cp(nextDir2);
//midpoints
IVec mid1 = pt1.mid(pt2);
IVec mid2 = pt2.mid(nextPt1);
IVec mid3 = pt2.mid(nextPt2);
//mid of midpoints
IVec quarter1 = pt2.mid(mid1);
IVec quarter2 = pt2.mid(mid2);
IVec quarter3 = pt2.mid(mid3);
//axis of child agents
IVec nextAxis1 =
axis.dup().rot(nextDir1, IRand.get(-PI/4,PI/4));
IVec nextAxis2 =
axis.dup().rot(nextDir2, IRand.get(-PI/4,PI/4));
double offsetWidth = -0.5;
IVec offset1 = dir.cross(axis).len(offsetWidth);
IVec offset2 = nextDir1.cross(nextAxis1).len(offsetWidth);
IVec offset3 = nextDir2.cross(nextAxis2).len(offsetWidth);
//offset edge points 1
IVec edgePt11 = mid1.cp(offset1);
IVec edgePt12 = quarter1.cp(offset1);
IVec edgePt13 = quarter2.cp(offset2);
IVec edgePt14 = mid2.cp(offset2);
//offset edge points 2
offset2.flip(); //offset to opposite
IVec edgePt21 = mid2.cp(offset2);
IVec edgePt22 = quarter2.cp(offset2);
IVec edgePt23 = quarter3.cp(offset3);
IVec edgePt24 = mid3.cp(offset3);
//offset edge points 3
offset1.flip(); //offset to opposite
offset3.flip(); //offset to opposite
IVec edgePt31 = mid3.cp(offset3);
IVec edgePt32 = quarter3.cp(offset3);
IVec edgePt33 = quarter1.cp(offset1);
IVec edgePt34 = mid1.cp(offset1);
double depth = 0.5;
IVec depthVec1 = axis.dup().len(depth);
IVec depthVec2 = nextAxis1.dup().len(depth);
IVec depthVec3 = nextAxis2.dup().len(depth);
createEdgeSurface(edgePt11,edgePt12,edgePt13,edgePt14,
depthVec1, depthVec2);
createEdgeSurface(edgePt21,edgePt22,edgePt23,edgePt24,
depthVec2, depthVec3);
createEdgeSurface(edgePt31,edgePt32,edgePt33,edgePt34,
depthVec3, depthVec1);
if(IRand.percent(80)){ //bend
new LineAgent(pt2, nextDir1, nextAxis1);
}
if(IRand.percent(50)){ //bend the other way
new LineAgent(pt2, nextDir2, nextAxis2);
}
}
}
ISurface createEdgeSurface(IVec pt1, IVec pt2,
IVec pt3, IVec pt4,
IVec extrudeDir1,
IVec extrudeDir2){
IVec[][] cpts = new IVec[4][2];
cpts[0][0] = pt1.dup().add(extrudeDir1);
cpts[1][0] = pt2.dup().add(extrudeDir1);
cpts[2][0] = pt3.dup().add(extrudeDir2);
cpts[3][0] = pt4.dup().add(extrudeDir2);
cpts[0][1] = pt1.dup().sub(extrudeDir1);
cpts[1][1] = pt2.dup().sub(extrudeDir1);
cpts[2][1] = pt3.dup().sub(extrudeDir2);
cpts[3][1] = pt4.dup().sub(extrudeDir2);
return new ISurface(cpts, 3, 1);
}
}
 
Surfaces around Agents: 3
import processing.opengl.*;
import igeo.*;
void setup(){
size(480, 360, IG.GL);
IRand.init(3);
IG.duration(30);
//second and third vector needs to be perpendicular
new LineAgent(new IVec(0,0,0), new IVec(1,0,0),
new IVec(0,0,1)).clr(0);
IG.fill();
}
static class LineAgent extends IAgent{
static double length = 2;
static double clearance = 1.99; //less than length
IVec pt1, pt2, axis;
boolean isColliding=false;
LineAgent(IVec pt, IVec dir, IVec ax){
pt1 = pt;
pt2 = pt.dup().add(dir.dup().len(length));
axis = ax;
}
void interact(ArrayList < IDynamics > agents){
super.interact(agents);
if(time == 0){ //only in the first time
for(int i=0; i < agents.size() && !isColliding; i++){
if(agents.get(i) instanceof LineAgent){
LineAgent lineAgent =
(LineAgent)agents.get(i);
if(lineAgent != this){ //agents include "this"
//checking clearance of end point
if(lineAgent.pt2.dist(pt2) < clearance){
isColliding=true;
}
}
}
}
}
}
void update(){
super.update();
if(isColliding){ del(); }
else if(time == 0){ //if not colliding
new ICurve(pt1,pt2); // center line
IVec dir = pt2.diff(pt1);
// child dir & points
IVec nextDir1 = dir.dup().rot(axis, IRand.get(PI/4,PI/3));
IVec nextDir2 = dir.dup().rot(axis,-IRand.get(PI/4,PI/3));
IVec nextPt1 = pt2.cp(nextDir1);
IVec nextPt2 = pt2.cp(nextDir2);
//midpoints
IVec mid1 = pt1.mid(pt2);
IVec mid2 = pt2.mid(nextPt1);
IVec mid3 = pt2.mid(nextPt2);
//mid of midpoints
IVec quarter1 = pt2.mid(mid1);
IVec quarter2 = pt2.mid(mid2);
IVec quarter3 = pt2.mid(mid3);
//axis of child agents
IVec nextAxis1 =
axis.dup().rot(nextDir1, IRand.get(-PI/4,PI/4));
IVec nextAxis2 =
axis.dup().rot(nextDir2, IRand.get(-PI/4,PI/4));
double offsetWidth = -0.5;
IVec offset1 = dir.cross(axis).len(offsetWidth);
IVec offset2 = nextDir1.cross(nextAxis1).len(offsetWidth);
IVec offset3 = nextDir2.cross(nextAxis2).len(offsetWidth);
double depth = 0.5;
IVec depthVec1 = axis.dup().len(depth);
IVec depthVec2 = nextAxis1.dup().len(depth);
IVec depthVec3 = nextAxis2.dup().len(depth);
createEdgeSurface(mid1,quarter1,quarter2,mid2,
offset1, offset2,
depthVec1, depthVec2);
createEdgeSurface(mid2,quarter2,quarter3,mid3,
offset2.dup().flip(), offset3,
depthVec2, depthVec3);
createEdgeSurface(mid3,quarter3,quarter1,mid1,
offset3.dup().flip(), offset1.dup().flip(),
depthVec3, depthVec1);
if(IRand.percent(80)){ //bend
new LineAgent(pt2, nextDir1, nextAxis1);
}
if(IRand.percent(50)){ //bend the other way
new LineAgent(pt2, nextDir2, nextAxis2);
}
}
}
ISurface createEdgeSurface(IVec pt1, IVec pt2,
IVec pt3, IVec pt4,
IVec offsetDir1,
IVec offsetDir2,
IVec extrudeDir1,
IVec extrudeDir2){
IVec[][] cpts = new IVec[4][3];
cpts[0][0] = pt1.dup().add(extrudeDir1);
cpts[1][0] = pt2.dup().add(extrudeDir1);
cpts[2][0] = pt3.dup().add(extrudeDir2);
cpts[3][0] = pt4.dup().add(extrudeDir2);
cpts[0][1] = pt1.dup().add(offsetDir1);
cpts[1][1] = pt2.dup().add(offsetDir1);
cpts[2][1] = pt3.dup().add(offsetDir2);
cpts[3][1] = pt4.dup().add(offsetDir2);
cpts[0][2] = pt1.dup().sub(extrudeDir1);
cpts[1][2] = pt2.dup().sub(extrudeDir1);
cpts[2][2] = pt3.dup().sub(extrudeDir2);
cpts[3][2] = pt4.dup().sub(extrudeDir2);
return new ISurface(cpts, 3, 1);
}
}
 
Surfaces around Agents: 4
import processing.opengl.*;
import igeo.*;
void setup(){
size(480, 360, IG.GL);
IRand.init(3);
IG.duration(30);
//second and third vector needs to be perpendicular
new LineAgent(new IVec(0,0,0), new IVec(1,0,0),
new IVec(0,0,1)).clr(0);
IG.fill();
}
static class LineAgent extends IAgent{
static double length = 2;
static double clearance = 1.99; //less than length
IVec pt1, pt2, axis;
boolean isColliding=false;
LineAgent(IVec pt, IVec dir, IVec ax){
pt1 = pt;
pt2 = pt.dup().add(dir.dup().len(length));
axis = ax;
}
void interact(ArrayList < IDynamics > agents){
super.interact(agents);
if(time == 0){ //only in the first time
for(int i=0; i < agents.size() && !isColliding; i++){
if(agents.get(i) instanceof LineAgent){
LineAgent lineAgent =
(LineAgent)agents.get(i);
if(lineAgent != this){ //agents include "this"
//checking clearance of end point
if(lineAgent.pt2.dist(pt2) < clearance){
isColliding=true;
}
}
}
}
}
}
void update(){
super.update();
if(isColliding){ del(); }
else if(time == 0){ //if not colliding
new ICurve(pt1,pt2); // center line
IVec dir = pt2.diff(pt1);
// child dir & points
IVec nextDir1 = dir.dup().rot(axis, IRand.get(PI/4,PI/3));
IVec nextDir2 = dir.dup().rot(axis,-IRand.get(PI/4,PI/3));
IVec nextPt1 = pt2.cp(nextDir1);
IVec nextPt2 = pt2.cp(nextDir2);
//midpoints
IVec mid1 = pt1.mid(pt2);
IVec mid2 = pt2.mid(nextPt1);
IVec mid3 = pt2.mid(nextPt2);
//mid of midpoints
IVec quarter1 = pt2.mid(mid1);
IVec quarter2 = pt2.mid(mid2);
IVec quarter3 = pt2.mid(mid3);
//axis of child agents
IVec nextAxis1 =
axis.dup().rot(nextDir1, IRand.get(-PI/4,PI/4));
IVec nextAxis2 =
axis.dup().rot(nextDir2, IRand.get(-PI/4,PI/4));
double offsetWidth = -0.5;
IVec offset1 = dir.cross(axis).len(offsetWidth);
IVec offset2 = nextDir1.cross(nextAxis1).len(offsetWidth);
IVec offset3 = nextDir2.cross(nextAxis2).len(offsetWidth);
double depth = 0.5;
IVec depthVec1 = axis.dup().len(depth);
IVec depthVec2 = nextAxis1.dup().len(depth);
IVec depthVec3 = nextAxis2.dup().len(depth);
createEdgeSurface(mid1,quarter1,quarter2,mid2,
offset1, offset2,
depthVec1, depthVec2);
createEdgeSurface(mid2,quarter2,quarter3,mid3,
offset2.dup().flip(), offset3,
depthVec2, depthVec3);
createEdgeSurface(mid3,quarter3,quarter1,mid1,
offset3.dup().flip(), offset1.dup().flip(),
depthVec3, depthVec1);
createCapSurface(mid1,quarter1,mid2,quarter2,mid3,quarter3,
depthVec1,depthVec2,depthVec3);
createCapSurface(mid1,quarter1,mid3,quarter3,mid2,quarter2,
depthVec1.flip(),depthVec3.flip(),depthVec2.flip());
if(IRand.percent(80)){ //bend
new LineAgent(pt2, nextDir1, nextAxis1);
}
if(IRand.percent(50)){ //bend the other way
new LineAgent(pt2, nextDir2, nextAxis2);
}
}
}
ISurface createEdgeSurface(IVec pt1, IVec pt2,
IVec pt3, IVec pt4,
IVec offsetDir1,
IVec offsetDir2,
IVec extrudeDir1,
IVec extrudeDir2){
IVec[][] cpts = new IVec[4][4];
cpts[0][0] = pt1.dup().add(extrudeDir1);
cpts[1][0] = pt2.dup().add(extrudeDir1);
cpts[2][0] = pt3.dup().add(extrudeDir2);
cpts[3][0] = pt4.dup().add(extrudeDir2);
cpts[0][1] = pt1.dup().add(offsetDir1).add(extrudeDir1);
cpts[1][1] = pt2.dup().add(offsetDir1).add(extrudeDir1);
cpts[2][1] = pt3.dup().add(offsetDir2).add(extrudeDir2);
cpts[3][1] = pt4.dup().add(offsetDir2).add(extrudeDir2);
cpts[0][2] = pt1.dup().add(offsetDir1).sub(extrudeDir1);
cpts[1][2] = pt2.dup().add(offsetDir1).sub(extrudeDir1);
cpts[2][2] = pt3.dup().add(offsetDir2).sub(extrudeDir2);
cpts[3][2] = pt4.dup().add(offsetDir2).sub(extrudeDir2);
cpts[0][3] = pt1.dup().sub(extrudeDir1);
cpts[1][3] = pt2.dup().sub(extrudeDir1);
cpts[2][3] = pt3.dup().sub(extrudeDir2);
cpts[3][3] = pt4.dup().sub(extrudeDir2);
return new ISurface(cpts, 3, 1);
}
ISurface createCapSurface(IVec pt1, IVec pt2,
IVec pt3, IVec pt4,
IVec pt5, IVec pt6,
IVec shiftDir1,
IVec shiftDir2,
IVec shiftDir3){
IVec[][] cpts = new IVec[4][4];
cpts[0][0] = pt1.dup().add(shiftDir1);
cpts[1][0] = pt1.dup().add(shiftDir1);
cpts[2][0] = pt1.dup().add(shiftDir1);
cpts[3][0] = pt1.dup().add(shiftDir1);
cpts[0][1] = pt2.dup().add(shiftDir1);
cpts[1][1] = pt2.dup().add(shiftDir1);
cpts[2][1] = pt2.dup().add(shiftDir1);
cpts[3][1] = pt2.dup().add(shiftDir1);
cpts[0][2] = pt4.dup().add(shiftDir2);
cpts[1][2] = pt4.mid(pt6).add(shiftDir2.mid(shiftDir3));
cpts[2][2] = pt4.mid(pt6).add(shiftDir2.mid(shiftDir3));
cpts[3][2] = pt6.dup().add(shiftDir3);
cpts[0][3] = pt3.dup().add(shiftDir2);
cpts[1][3] = pt4.dup().add(shiftDir2);
cpts[2][3] = pt6.dup().add(shiftDir3);
cpts[3][3] = pt5.dup().add(shiftDir3);
return new ISurface(cpts, 3, 3);
}
}
The code below creates surfaces with curved section having v-degree 3 NURBS surfaces.
import processing.opengl.*;
import igeo.*;
void setup(){
size(480, 360, IG.GL);
IRand.init(3);
IG.duration(30);
//second and third vector needs to be perpendicular
new LineAgent(new IVec(0,0,0), new IVec(1,0,0),
new IVec(0,0,1)).clr(0);
IG.fill();
}
static class LineAgent extends IAgent{
static double length = 2;
static double clearance = 1.99; //less than length
IVec pt1, pt2, axis;
boolean isColliding=false;
LineAgent(IVec pt, IVec dir, IVec ax){
pt1 = pt;
pt2 = pt.dup().add(dir.dup().len(length));
axis = ax;
}
void interact(ArrayList < IDynamics > agents){
super.interact(agents);
if(time == 0){ //only in the first time
for(int i=0; i < agents.size() && !isColliding; i++){
if(agents.get(i) instanceof LineAgent){
LineAgent lineAgent =
(LineAgent)agents.get(i);
if(lineAgent != this){ //agents include "this"
//checking clearance of end point
if(lineAgent.pt2.dist(pt2) < clearance){
isColliding=true;
}
}
}
}
}
}
void update(){
super.update();
if(isColliding){ del(); }
else if(time == 0){ //if not colliding
new ICurve(pt1,pt2); // center line
IVec dir = pt2.diff(pt1);
// child dir & points
IVec nextDir1 = dir.dup().rot(axis, IRand.get(PI/4,PI/3));
IVec nextDir2 = dir.dup().rot(axis,-IRand.get(PI/4,PI/3));
IVec nextPt1 = pt2.cp(nextDir1);
IVec nextPt2 = pt2.cp(nextDir2);
//midpoints
IVec mid1 = pt1.mid(pt2);
IVec mid2 = pt2.mid(nextPt1);
IVec mid3 = pt2.mid(nextPt2);
//mid of midpoints
IVec quarter1 = pt2.mid(mid1);
IVec quarter2 = pt2.mid(mid2);
IVec quarter3 = pt2.mid(mid3);
//axis of child agents
IVec nextAxis1 =
axis.dup().rot(nextDir1, IRand.get(-PI/4,PI/4));
IVec nextAxis2 =
axis.dup().rot(nextDir2, IRand.get(-PI/4,PI/4));
double offsetWidth = -0.75;
IVec offset1 = dir.cross(axis).len(offsetWidth);
IVec offset2 = nextDir1.cross(nextAxis1).len(offsetWidth);
IVec offset3 = nextDir2.cross(nextAxis2).len(offsetWidth);
double depth = 0.75;
IVec depthVec1 = axis.dup().len(depth);
IVec depthVec2 = nextAxis1.dup().len(depth);
IVec depthVec3 = nextAxis2.dup().len(depth);
createEdgeSurface(mid1,quarter1,quarter2,mid2,
offset1, offset2,
depthVec1, depthVec2);
createEdgeSurface(mid2,quarter2,quarter3,mid3,
offset2.dup().flip(), offset3,
depthVec2, depthVec3);
createEdgeSurface(mid3,quarter3,quarter1,mid1,
offset3.dup().flip(), offset1.dup().flip(),
depthVec3, depthVec1);
createCapSurface(mid1,quarter1,mid2,quarter2,mid3,quarter3,
depthVec1,depthVec2,depthVec3);
createCapSurface(mid1,quarter1,mid3,quarter3,mid2,quarter2,
depthVec1.flip(),depthVec3.flip(),depthVec2.flip());
if(IRand.percent(80)){ //bend
new LineAgent(pt2, nextDir1, nextAxis1);
}
if(IRand.percent(50)){ //bend the other way
new LineAgent(pt2, nextDir2, nextAxis2);
}
}
}
ISurface createEdgeSurface(IVec pt1, IVec pt2,
IVec pt3, IVec pt4,
IVec offsetDir1,
IVec offsetDir2,
IVec extrudeDir1,
IVec extrudeDir2){
IVec[][] cpts = new IVec[4][4];
cpts[0][0] = pt1.dup().add(extrudeDir1);
cpts[1][0] = pt2.dup().add(extrudeDir1);
cpts[2][0] = pt3.dup().add(extrudeDir2);
cpts[3][0] = pt4.dup().add(extrudeDir2);
cpts[0][1] = pt1.dup().add(offsetDir1).add(extrudeDir1);
cpts[1][1] = pt2.dup().add(offsetDir1).add(extrudeDir1);
cpts[2][1] = pt3.dup().add(offsetDir2).add(extrudeDir2);
cpts[3][1] = pt4.dup().add(offsetDir2).add(extrudeDir2);
cpts[0][2] = pt1.dup().add(offsetDir1).sub(extrudeDir1);
cpts[1][2] = pt2.dup().add(offsetDir1).sub(extrudeDir1);
cpts[2][2] = pt3.dup().add(offsetDir2).sub(extrudeDir2);
cpts[3][2] = pt4.dup().add(offsetDir2).sub(extrudeDir2);
cpts[0][3] = pt1.dup().sub(extrudeDir1);
cpts[1][3] = pt2.dup().sub(extrudeDir1);
cpts[2][3] = pt3.dup().sub(extrudeDir2);
cpts[3][3] = pt4.dup().sub(extrudeDir2);
return new ISurface(cpts, 3, 3);
}
ISurface createCapSurface(IVec pt1, IVec pt2,
IVec pt3, IVec pt4,
IVec pt5, IVec pt6,
IVec shiftDir1,
IVec shiftDir2,
IVec shiftDir3){
IVec[][] cpts = new IVec[4][4];
cpts[0][0] = pt1.dup().add(shiftDir1);
cpts[1][0] = pt1.dup().add(shiftDir1);
cpts[2][0] = pt1.dup().add(shiftDir1);
cpts[3][0] = pt1.dup().add(shiftDir1);
cpts[0][1] = pt2.dup().add(shiftDir1);
cpts[1][1] = pt2.dup().add(shiftDir1);
cpts[2][1] = pt2.dup().add(shiftDir1);
cpts[3][1] = pt2.dup().add(shiftDir1);
cpts[0][2] = pt4.dup().add(shiftDir2);
cpts[1][2] = pt4.mid(pt6).add(shiftDir2.mid(shiftDir3));
cpts[2][2] = pt4.mid(pt6).add(shiftDir2.mid(shiftDir3));
cpts[3][2] = pt6.dup().add(shiftDir3);
cpts[0][3] = pt3.dup().add(shiftDir2);
cpts[1][3] = pt4.dup().add(shiftDir2);
cpts[2][3] = pt6.dup().add(shiftDir3);
cpts[3][3] = pt5.dup().add(shiftDir3);
return new ISurface(cpts, 3, 3);
}
}
 
Surfaces around Agents: 5
import processing.opengl.*;
import igeo.*;
void setup(){
size(480, 360, IG.GL);
IRand.init(3);
IG.duration(30);
//second and third vector needs to be perpendicular
new LineAgent(new IVec(0,0,0), new IVec(1,0,0),
new IVec(0,0,1), true, true).clr(0.4,0,0);
IG.fill();
}
static class LineAgent extends IAgent{
static double length = 2;
static double clearance = 1.99; //less than length
IVec pt1, pt2, axis;
boolean createLeftSrf, createRightSrf;
boolean isColliding=false;
LineAgent(IVec pt, IVec dir, IVec ax,
boolean createLeft, boolean createRight){
pt1 = pt;
pt2 = pt.dup().add(dir.dup().len(length));
axis = ax;
createLeftSrf = createLeft;
createRightSrf = createRight;
}
void interact(ArrayList < IDynamics > agents){
super.interact(agents);
if(time == 0){ //only in the first time
for(int i=0; i < agents.size() && !isColliding; i++){
if(agents.get(i) instanceof LineAgent){
LineAgent lineAgent =
(LineAgent)agents.get(i);
if(lineAgent != this){ //agents include "this"
//checking clearance of end point
if(lineAgent.pt2.dist(pt2) < clearance){
isColliding=true;
}
}
}
}
}
}
void update(){
super.update();
if(isColliding){ del(); }
else if(time == 0){ //if not colliding
new ICurve(pt1,pt2); // center line
IVec dir = pt2.diff(pt1);
// child dir & points
IVec nextDir1 = dir.dup().rot(axis, IRand.get(PI/4,PI/3));
IVec nextDir2 = dir.dup().rot(axis,-IRand.get(PI/4,PI/3));
IVec nextPt1 = pt2.cp(nextDir1);
IVec nextPt2 = pt2.cp(nextDir2);
//midpoints
IVec mid1 = pt1.mid(pt2);
IVec mid2 = pt2.mid(nextPt1);
IVec mid3 = pt2.mid(nextPt2);
//mid of midpoints
IVec quarter1 = pt2.mid(mid1);
IVec quarter2 = pt2.mid(mid2);
IVec quarter3 = pt2.mid(mid3);
//axis of child agents
IVec nextAxis1 =
axis.dup().rot(nextDir1, IRand.get(-PI/4,PI/4));
IVec nextAxis2 =
axis.dup().rot(nextDir2, IRand.get(-PI/4,PI/4));
double offsetWidth = -1.0;
IVec offset1 = dir.cross(axis).len(offsetWidth);
IVec offset2 = nextDir1.cross(nextAxis1).len(offsetWidth);
IVec offset3 = nextDir2.cross(nextAxis2).len(offsetWidth);
double depth = 1.0;
IVec depthVec1 = axis.dup().len(depth);
IVec depthVec2 = nextAxis1.dup().len(depth);
IVec depthVec3 = nextAxis2.dup().len(depth);
if(createLeftSrf){
createEdgeSurface(mid1,quarter1,quarter2,mid2,
offset1, offset2,
depthVec1, depthVec2).clr(clr());
}
if(!createLeftSrf||!createRightSrf){
createEdgeSurface(mid2,quarter2,quarter3,mid3,
offset2.dup().flip(), offset3,
depthVec2, depthVec3).clr(clr());
}
if(createRightSrf){
createEdgeSurface(mid3,quarter3,quarter1,mid1,
offset3.dup().flip(), offset1.dup().flip(),
depthVec3, depthVec1).clr(clr());
}
createCapSurface(mid1,quarter1,mid2,quarter2,mid3,quarter3,
depthVec1,depthVec2,depthVec3).clr(clr());
createCapSurface(mid1,quarter1,mid3,quarter3,mid2,quarter2,
depthVec1.flip(),depthVec3.flip(),depthVec2.flip()).clr(clr());
//child agents color
int r = clr().getRed() + IRand.getInt(-10,10);
int g = clr().getGreen();
int b = clr().getBlue() + IRand.getInt(-10,10);
if(IRand.percent(80)){ //bend
new LineAgent(pt2, nextDir1, nextAxis1,
createLeftSrf,
!createLeftSrf||!createRightSrf).clr(r,g,b);
}
if(IRand.percent(50)){ //bend the other way
new LineAgent(pt2, nextDir2, nextAxis2,
!createLeftSrf||!createRightSrf,
createRightSrf).clr(r,g,b);
}
}
}
ISurface createEdgeSurface(IVec pt1, IVec pt2,
IVec pt3, IVec pt4,
IVec offsetDir1,
IVec offsetDir2,
IVec extrudeDir1,
IVec extrudeDir2){
IVec[][] cpts = new IVec[4][4];
cpts[0][0] = pt1.dup().add(extrudeDir1);
cpts[1][0] = pt2.dup().add(extrudeDir1);
cpts[2][0] = pt3.dup().add(extrudeDir2);
cpts[3][0] = pt4.dup().add(extrudeDir2);
cpts[0][1] = pt1.dup().add(offsetDir1).add(extrudeDir1);
cpts[1][1] = pt2.dup().add(offsetDir1).add(extrudeDir1);
cpts[2][1] = pt3.dup().add(offsetDir2).add(extrudeDir2);
cpts[3][1] = pt4.dup().add(offsetDir2).add(extrudeDir2);
cpts[0][2] = pt1.dup().add(offsetDir1).sub(extrudeDir1);
cpts[1][2] = pt2.dup().add(offsetDir1).sub(extrudeDir1);
cpts[2][2] = pt3.dup().add(offsetDir2).sub(extrudeDir2);
cpts[3][2] = pt4.dup().add(offsetDir2).sub(extrudeDir2);
cpts[0][3] = pt1.dup().sub(extrudeDir1);
cpts[1][3] = pt2.dup().sub(extrudeDir1);
cpts[2][3] = pt3.dup().sub(extrudeDir2);
cpts[3][3] = pt4.dup().sub(extrudeDir2);
return new ISurface(cpts, 3, 3);
}
ISurface createCapSurface(IVec pt1, IVec pt2,
IVec pt3, IVec pt4,
IVec pt5, IVec pt6,
IVec shiftDir1,
IVec shiftDir2,
IVec shiftDir3){
IVec[][] cpts = new IVec[4][4];
cpts[0][0] = pt1.dup().add(shiftDir1);
cpts[1][0] = pt1.dup().add(shiftDir1);
cpts[2][0] = pt1.dup().add(shiftDir1);
cpts[3][0] = pt1.dup().add(shiftDir1);
cpts[0][1] = pt2.dup().add(shiftDir1);
cpts[1][1] = pt2.dup().add(shiftDir1);
cpts[2][1] = pt2.dup().add(shiftDir1);
cpts[3][1] = pt2.dup().add(shiftDir1);
cpts[0][2] = pt4.dup().add(shiftDir2);
cpts[1][2] = pt4.mid(pt6).add(shiftDir2.mid(shiftDir3));
cpts[2][2] = pt4.mid(pt6).add(shiftDir2.mid(shiftDir3));
cpts[3][2] = pt6.dup().add(shiftDir3);
cpts[0][3] = pt3.dup().add(shiftDir2);
cpts[1][3] = pt4.dup().add(shiftDir2);
cpts[2][3] = pt6.dup().add(shiftDir3);
cpts[3][3] = pt5.dup().add(shiftDir3);
return new ISurface(cpts, 3, 3);
}
}
HOME
FOR PROCESSING
DOWNLOAD
DOCUMENTS
TUTORIALS
GALLERY
SOURCE CODE(GitHub)
ABOUT