Tutorials | (back to the list of tutorials) |
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()); } } } }
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()); } } } }
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); } } } }
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.
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); } }
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); } }
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); } }
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); } }