Tutorials | (back to the list of tutorials) |
Pipes 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));
}
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(IDynamics agent){
if(time == 0){ //only in the first time
if(agent instanceof LineAgent){
LineAgent lineAgent = (LineAgent)agent;
// checking clearance of end point
if(lineAgent.pt2.dist(pt2) < clearance){
isColliding=true;
}
}
}
}
void update(){
if(isColliding){
del();
}
else if(time == 0){ //if not colliding
IG.squarePipe(pt1,pt2,.2).clr(IRandom.gray());
IVec dir = pt2.dif(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(IDynamics agent){
if(time == 0){ //only in the first time
if(agent instanceof LineAgent){
LineAgent lineAgent = (LineAgent)agent;
// checking clearance of end point
if(lineAgent.pt2.dist(pt2) < clearance){
isColliding=true;
}
}
}
}
void update(){
if(isColliding){
del();
}
else if(time == 0){ //if not colliding
IVec dir = pt2.dif(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(IDynamics agent){
if(time == 0){ //only in the first time
if(agent instanceof LineAgent){
LineAgent lineAgent = (LineAgent)agent;
//checking clearance of end point
if(lineAgent.pt2.dist(pt2) < clearance){
isColliding=true;
}
}
}
}
void update(){
if(isColliding){ del(); }
else if(time == 0){ //if not colliding
IVec dir = pt2.dif(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(IDynamics agent){
if(time == 0){ //only in the first time
if(agent instanceof LineAgent){
LineAgent lineAgent = (LineAgent)agent;
//checking clearance of end point
if(lineAgent.pt2.dist(pt2) < clearance){
isColliding=true;
}
}
}
}
void update(){
if(isColliding){ del(); }
else if(time == 0){ //if not colliding
new ICurve(pt1,pt2); // center line
IVec dir = pt2.dif(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(IDynamics agent){
if(time == 0){ //only in the first time
if(agent instanceof LineAgent){
LineAgent lineAgent = (LineAgent)agent;
//checking clearance of end point
if(lineAgent.pt2.dist(pt2) < clearance){
isColliding=true;
}
}
}
}
void update(){
if(isColliding){ del(); }
else if(time == 0){ //if not colliding
new ICurve(pt1,pt2); // center line
IVec dir = pt2.dif(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(IDynamics agent){
if(time == 0){ //only in the first time
if(agent instanceof LineAgent){
LineAgent lineAgent = (LineAgent)agent;
//checking clearance of end point
if(lineAgent.pt2.dist(pt2) < clearance){
isColliding=true;
}
}
}
}
void update(){
if(isColliding){ del(); }
else if(time == 0){ //if not colliding
new ICurve(pt1,pt2); // center line
IVec dir = pt2.dif(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(IDynamics agent){
if(time == 0){ //only in the first time
if(agent instanceof LineAgent){
LineAgent lineAgent = (LineAgent)agent;
//checking clearance of end point
if(lineAgent.pt2.dist(pt2) < clearance){
isColliding=true;
}
}
}
}
void update(){
if(isColliding){ del(); }
else if(time == 0){ //if not colliding
new ICurve(pt1,pt2); // center line
IVec dir = pt2.dif(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(IDynamics agent){
if(time == 0){ //only in the first time
if(agent instanceof LineAgent){
LineAgent lineAgent = (LineAgent)agent;
//checking clearance of end point
if(lineAgent.pt2.dist(pt2) < clearance){
isColliding=true;
}
}
}
}
void update(){
if(isColliding){ del(); }
else if(time == 0){ //if not colliding
new ICurve(pt1,pt2); // center line
IVec dir = pt2.dif(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(IDynamics agent){
if(time == 0){ //only in the first time
if(agent instanceof LineAgent){
LineAgent lineAgent = (LineAgent)agent;
//checking clearance of end point
if(lineAgent.pt2.dist(pt2) < clearance){
isColliding=true;
}
}
}
}
void update(){
if(isColliding){ del(); }
else if(time == 0){ //if not colliding
new ICurve(pt1,pt2); // center line
IVec dir = pt2.dif(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(IDynamics agent){
if(time == 0){ //only in the first time
if(agent instanceof LineAgent){
LineAgent lineAgent = (LineAgent)agent;
//checking clearance of end point
if(lineAgent.pt2.dist(pt2) < clearance){
isColliding=true;
}
}
}
}
void update(){
if(isColliding){ del(); }
else if(time == 0){ //if not colliding
new ICurve(pt1,pt2); // center line
IVec dir = pt2.dif(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(4);
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(IDynamics agent){
if(time == 0){ //only in the first time
if(agent instanceof LineAgent){
LineAgent lineAgent = (LineAgent)agent;
//checking clearance of end point
if(lineAgent.pt2.dist(pt2) < clearance){
isColliding=true;
}
}
}
}
void update(){
if(isColliding){ del(); }
else if(time == 0){ //if not colliding
new ICurve(pt1,pt2); // center line
IVec dir = pt2.dif(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 (Java /
Python)
GALLERY
SOURCE CODE(GitHub)
PRIVACY POLICY
ABOUT/CONTACT