Tutorials | (back to the list of tutorials) |
Line Agent on A SurfaceThe example below shows how to re-write the line branching agents shown before (without collision detection) to have them on a surface.
![]()
![]()
![]()
![]()
import processing.opengl.*;
import igeo.*;
void setup() {
size(480, 360, IG.GL);
IG.duration(120);
IG.open("surface13.3dm");
ISurface srf = IG.surface(0);//first surface in the server
srf.del();
for (int i=0; i < 120; i++) {
new LineAgentOnSurface(new IVec(IRandom.get(),0,0),//random only in x
new IVec(0,0.01,0),//direction is y. length is less than 1.0
srf).clr(0);
}
}
class LineAgentOnSurface extends IAgent {
IVec pos;
IVec dir;
ISurface surf;
LineAgentOnSurface(IVec pt, IVec dir, ISurface s) {
pos = pt;
this.dir = dir;
surf = s;
}
public void update() {
if(pos.x < 0 || pos.x > 1.0){ //out of u-v boundary
del();
return;
}
IVec pos2 = pos.dup().add(dir);
IVec srfPt = surf.pt(pos.x, pos.y);
IVec srfPt2 = surf.pt(pos2.x, pos2.y);
new ICurve(srfPt, srfPt2).clr(clr());
for (int i=0; i < 2; i++) {
if (IRandom.percent(50)) {
IVec dir2 = dir.dup();
double angle = IRandom.get(-PI/20, PI/20);
dir2.rot(new IVec(0, 0, 1), angle);
int r = clr().getRed() + IRandom.getInt(-10, 10);
int g = clr().getGreen() + IRandom.getInt(-10, 10);
int b = clr().getBlue() + IRandom.getInt(-10, 10);
new LineAgentOnSurface(pos2, dir2, surf).clr(r,g,b);
}
}
del();
}
}
The below is the input surface to put the agents on. The file of the surface used in this example is this file.
This is the result of the agents running on the input surface.
at the line of
if(pos.x < 0 || pos.x > 1.0){
it checks if the x position of the agent is inside the boundary of
u-v parameter of the surface ( 0.0 - 1.0 ) and if it's outside, it deletes itself.
Then at these two lines,
IVec srfPt = surf.pt(pos.x, pos.y);
IVec srfPt2 = surf.pt(pos2.x, pos2.y);
The position of the agent is interpreted as u-v parameter of the surface and
mapped onto the 3 dimensional location (IVec) on the surface.
Another thing to be noted is that in the setup() method at the constructor
of LineAgentOnSurface class,
   
new LineAgentOnSurface(new IVec(IRandom.get(),0,0),
                   
               
             
new IVec(0,0.01,0),
srf)
the first argument is a vector variable to specify the starting
location of the agent and it's set to be bottom of v direction on the surface.
The second argument is another vector variable to specify the direction and the
length of the line and the length is set to be smaller than 1.0
because the full range of the v parameter on the surface is 1.0.
And at the third argument, it passes the base surface into the agent.
Box Agent on A SurfaceThe input surface used in the code is this file.
![]()
![]()
![]()
![]()
import processing.opengl.*;
import igeo.*;
void setup() {
size(480, 360, IG.GL);
IG.duration(300);
IG.open("surface1.3dm");
ISurface srf = IG.surface(0);//first surface in the server
for (int i=0; i < 20; i++) {
new MyAgent(new IVec(IRandom.get(),0,0),0.5,srf).clr(0);
}
IG.transparent(); //transparent graphic mode
}
class MyAgent extends IAgent {
IVec pos;
double size;
ISurface surf;
MyAgent(IVec pt, double sz, ISurface s) {
pos = pt;
size = sz;
surf = s;
}
public void update() {
IVec surfPt = surf.pt(pos.x, pos.y);
new IBox(surfPt, size).clr(this.clr());
IVec nextPos = pos.dup();
double move=0.01; //less than 1.0
//random direction
double dir=IRandom.getInt(0, 2);
if (dir==0) nextPos.add(move, 0, 0); //right
else if (dir==1) nextPos.add(-move, 0, 0); //left
else if (dir==2) nextPos.add(0, move, 0); //up
// slightly chaning the color
int r = clr().getRed() + IRandom.getInt(-10, 10);
int g = clr().getGreen() + IRandom.getInt(-10, 10);
int b = clr().getBlue() + IRandom.getInt(-10, 10);
new MyAgent(nextPos, size, surf).clr(r,g,b);
del();
}
}
Mapping Agents with U, V Tangent and Normal![]()
![]()
![]()
![]()
import processing.opengl.*;
import igeo.*;
void setup() {
size(480, 360, IG.GL);
IG.duration(300);
IG.open("surface1.3dm");
ISurface surf = IG.surface(0);
for (int i=0; i < 20; i++) {
new MyAgent(new IVec(IRandom.get(),0,0),0.01,surf).clr(0);
}
IG.transparent(); //transparent graphic mode
}
class MyAgent extends IAgent {
IVec pos;
double size;
ISurface surf;
MyAgent(IVec pt, double sz, ISurface s) {
pos = pt;
size = sz;
surf = s;
}
public void update() {
IVec utan = surf.utan(pos.x, pos.y);
IVec vtan = surf.vtan(pos.x, pos.y);
IVec nml = surf.nml(pos.x, pos.y);
IVec surfPt = surf.pt(pos.x, pos.y);
utan.mul(size); //original length of u tangent vector is almost full width of surface in u.
vtan.mul(size); //original length of v tangent vector is almost full height of surface in v.
nml.mul(size*size); //original length of normal vector is multiplication of u tangent and v tangent
new IBox(surfPt,utan,vtan,nml).clr(this.clr());
IVec nextPos = pos.dup();
//random direction
double dir=IRandom.getInt(0, 2);
if (dir==0) nextPos.add(size, 0, 0); //right
else if (dir==1) nextPos.add(-size, 0, 0); //left
else if (dir==2) nextPos.add(0, size, 0); //up
// slightly chaning the color
int r = clr().getRed() + IRandom.getInt(-10, 10);
int g = clr().getGreen() + IRandom.getInt(-10, 10);
int b = clr().getBlue() + IRandom.getInt(-10, 10);
new MyAgent(nextPos, size, surf).clr(r, g, b);
del();
}
}
Another Example of Mapping Agent on A Surface![]()
![]()
![]()
![]()
import processing.opengl.*;
import igeo.*;
void setup(){
size(480, 360, IG.GL);
IG.duration(200);
IG.open("surface13.3dm");
ISurface surf = IG.surface(0);
surf.del();
new LineAgent(new IVec(0,0,0), new IVec(1,0,0),surf);
}
static class LineAgent extends IAgent{
static double length = 0.01; //length in u-v space, less than 1.0
static double clearance = 0.0099; //less than length
IVec pt1, pt2;
boolean isColliding=false;
ISurface surf;
LineAgent(IVec pt, IVec dir, ISurface s){
pt1 = pt;
pt2 = pt.dup().add(dir.dup().len(length));
surf = s;
}
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(){
// is inside surface?
if(pt2.x < 0.0||pt2.x > 1.0||pt2.y < 0.0||pt2.y > 1.0){
isColliding = true;
}
if(isColliding){
del();
}
else if(time == 0){ //if not colliding
IVec surfPt1 = surf.pt(pt1.x, pt1.y);
IVec surfPt2 = surf.pt(pt2.x, pt2.y);
new ICurve(surfPt1,surfPt2).clr(0);
IVec dir = pt2.dif(pt1);
if(IRandom.percent(40)){ //bend
new LineAgent(pt2,dir.dup().rot(IG.zaxis,PI/3),surf);
}
if(IRandom.percent(40)){ //bend the other way
new LineAgent(pt2,dir.dup().rot(IG.zaxis,-PI/3),surf);
}
if(IRandom.percent(80)){ //straight
new LineAgent(pt2,dir.dup(),surf);
}
}
}
}
The code below creates a fin surface instead of line. It gets offset points on the surface in a specified depth to get two more points out of the two end points of the line. Additionally, color differentiation algorithm in gray scale is also inserted.
![]()
![]()
![]()
![]()
import processing.opengl.*;
import igeo.*;
void setup(){
size(480, 360, IG.GL);
IG.duration(200);
IG.open("surface13.3dm");
ISurface surf = IG.surface(0);
surf.del();
new LineAgent(new IVec(0,0,0), new IVec(1,0,0),surf).clr(0.2);
}
static class LineAgent extends IAgent{
static double length = 0.01; //length in u-v space, less than 1.0
static double clearance = 0.0099; //less than length
IVec pt1, pt2;
boolean isColliding=false;
ISurface surf;
LineAgent(IVec pt, IVec dir, ISurface s){
pt1 = pt;
pt2 = pt.dup().add(dir.dup().len(length));
surf = s;
}
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(){
// is inside surface?
if(pt2.x < 0.0||pt2.x > 1.0||pt2.y < 0.0||pt2.y > 1.0){
isColliding = true;
}
if(isColliding){
del();
}
else if(time == 0){ //if not colliding
IVec surfPt1 = surf.pt(pt1.x, pt1.y);
IVec surfPt2 = surf.pt(pt2.x, pt2.y);
double offsetDepth = 1;
IVec surfPt1d = surf.pt(pt1.x, pt1.y, offsetDepth);
IVec surfPt2d = surf.pt(pt2.x, pt2.y, offsetDepth);
new ISurface(surfPt1,surfPt2,surfPt2d,surfPt1d).clr(clr());
// slightly chaning the gray color
int gray = (clr().getRed()+clr().getGreen()+clr().getBlue())/3;
gray += IRandom.getInt(-10, 10);
IVec dir = pt2.dif(pt1);
if(IRandom.percent(40)){ //bend
new LineAgent(pt2,dir.dup().rot(IG.zaxis,PI/3),surf).clr(gray);
}
if(IRandom.percent(40)){ //bend the other way
new LineAgent(pt2,dir.dup().rot(IG.zaxis,-PI/3),surf).clr(gray);
}
if(IRandom.percent(80)){ //straight
new LineAgent(pt2,dir.dup(),surf).clr(gray);
}
}
}
}
The code below combines the code above and the geometric technique to put continous curvature keeping the same tangency shown in this section. The surface is created taking 3 by 2 control points and 3 of them are midpoint of the current agent, end point of the current agent and midpoint of the next agent. Other 3 are offset points of those 3 points on the surface. Additionally, the offset depth of the second control point of the first 3 points is controlled by the agent too. It alternates the value making it smaller or larger than the offset depth of the end points.
![]()
![]()
![]()
![]()
import processing.opengl.*;
import igeo.*;
void setup(){
size(480, 360, IG.GL);
IG.duration(200);
IG.open("surface13.3dm");
ISurface surf = IG.surface(0);
surf.del();
new LineAgent(new IVec(0,0,0),new IVec(1,0,0),surf,0.5,0.1).clr(0.5);
}
static class LineAgent extends IAgent{
static double length = 0.01; //length in u-v space, less than 1.0
static double clearance = 0.0099; //less than length
IVec pt1, pt2;
boolean isColliding=false;
ISurface surf;
double offsetDepth1, offsetDepth2;
LineAgent(IVec pt, IVec dir, ISurface s,
double depth1, double depth2){
pt1 = pt;
pt2 = pt.dup().add(dir.dup().len(length));
surf = s;
offsetDepth1 = depth1;
offsetDepth2 = depth2;
}
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(){
// is inside surface?
if(pt2.x < 0.0||pt2.x > 1.0||pt2.y < 0.0||pt2.y > 1.0){
isColliding = true;
}
if(isColliding){
del();
}
else if(time == 0){ //if not colliding
//midpoint of the current agent
IVec mid = pt1.mid(pt2);
IVec surfPt1 = surf.pt(mid.x, mid.y);
IVec surfPt1d = surf.pt(mid.x, mid.y, offsetDepth1);
//end point of the current agent
IVec surfPt2 = surf.pt(pt2.x, pt2.y);
IVec surfPt2d = surf.pt(pt2.x, pt2.y, offsetDepth2);
double nextDepth = 0;
//alternating offsetDepth2
if(offsetDepth2 > offsetDepth1){
nextDepth = offsetDepth1-(offsetDepth2-offsetDepth1);
}
else{
nextDepth = offsetDepth1+(offsetDepth1-offsetDepth2);
}
// slightly chaning the color
int r = clr().getRed() + IRandom.getInt(-10, 10);
int g = clr().getGreen() + IRandom.getInt(-10, 10);
int b = clr().getBlue() + IRandom.getInt(-10, 10);
IVec dir = pt2.dif(pt1);
if(IRandom.percent(40)){ //bend
IVec nextDir = dir.dup().rot(IG.zaxis,PI/3);
//midpoint of the next agent
IVec mid2 = pt2.cp(nextDir.dup().len(length/2));
IVec surfPt3 = surf.pt(mid2.x,mid2.y);
IVec surfPt3d = surf.pt(mid2.x,mid2.y,offsetDepth1);
//3 by 2 control points
IVec[][] cpts = new IVec[3][2];
cpts[0][0] = surfPt1; cpts[0][1] = surfPt1d;
cpts[1][0] = surfPt2; cpts[1][1] = surfPt2d;
cpts[2][0] = surfPt3; cpts[2][1] = surfPt3d;
//u degree 2, v degree 1 surface
new ISurface(cpts, 2, 1).clr(clr());
new LineAgent(pt2,nextDir,surf,offsetDepth1,nextDepth).clr(r,g,b);
}
if(IRandom.percent(40)){ //bend the other way
IVec nextDir = dir.dup().rot(IG.zaxis,-PI/3);
//midpoint of the next agent
IVec mid2 = pt2.cp(nextDir.dup().len(length/2));
IVec surfPt3 = surf.pt(mid2.x,mid2.y);
IVec surfPt3d = surf.pt(mid2.x,mid2.y,offsetDepth1);
//3 by 2 control points
IVec[][] cpts = new IVec[3][2];
cpts[0][0] = surfPt1; cpts[0][1] = surfPt1d;
cpts[1][0] = surfPt2; cpts[1][1] = surfPt2d;
cpts[2][0] = surfPt3; cpts[2][1] = surfPt3d;
//u degree 2, v degree 1 surface
new ISurface(cpts, 2, 1).clr(clr());
new LineAgent(pt2,nextDir,surf,offsetDepth1,nextDepth).clr(r,g,b);
}
if(IRandom.percent(80)){ //straight
IVec nextDir = dir;
//midpoint of the next agent
IVec mid2 = pt2.cp(nextDir.dup().len(length/2));
IVec surfPt3 = surf.pt(mid2.x,mid2.y);
IVec surfPt3d = surf.pt(mid2.x,mid2.y,offsetDepth1);
IVec[][] cpts = new IVec[3][2];
//3 by 2 control points
cpts[0][0] = surfPt1; cpts[0][1] = surfPt1d;
cpts[1][0] = surfPt2; cpts[1][1] = surfPt2d;
cpts[2][0] = surfPt3; cpts[2][1] = surfPt3d;
//u degree 2, v degree 1 surface
new ISurface(cpts, 2, 1).clr(clr());
new LineAgent(pt2,nextDir,surf,offsetDepth1,nextDepth).clr(r,g,b);
}
}
}
}
Cellular Automaton on A Surface![]()
![]()
![]()
![]()
import processing.opengl.*;
import igeo.*;
void setup(){
size(480, 360, IG.GL);
IG.duration(60);
IG.open("surface13.3dm");
ISurface surf = IG.surface(0);
// put automaton as panel
int unum=50, vnum=50;
double uinc=1.0/unum, vinc=1.0/vnum;
MyAutomaton[][] automata = new MyAutomaton[unum][vnum];
for(int i=0; i < unum; i++){
for(int j=0; j < vnum; j++){
automata[i][j] =
new MyAutomaton(new IVec(i*uinc, j*vinc, 0),
uinc, vinc, -1, surf);
}
}
//connecting adjacent automata
for(int i=0; i < unum; i++){
for(int j=0; j < vnum; j++){
if(i > 0){ automata[i][j].left=automata[i-1][j]; }
if(i < unum-1){ automata[i][j].right=automata[i+1][j]; }
if(j > 0){ automata[i][j].down=automata[i][j-1]; }
if(j < vnum-1){ automata[i][j].up=automata[i][j+1]; }
if(i==0){ automata[i][j].state = 1; } // activated
}
}
surf.del();
IG.fill();
}
class MyAutomaton extends IAgent{
IVec pos;
double width, height, depth;
int state=0;
int lst=0, rst=0, dst=0, ust=0;
IBox box;
ISurface surf;
MyAutomaton left, right, up, down;
MyAutomaton(IVec pt, double w, double h, double d,
ISurface s){
pos = pt; width = w; height = h; depth = d;
surf = s;
}
void interact(ArrayList< IDynamics > agents){
// reset states
lst=0; rst=0; dst=0; ust=0;
if(left!=null){ lst = left.state; }
if(right!=null){ rst = right.state; }
if(down!=null){ dst = down.state; }
if(up!=null){ ust = up.state; }
}
void update(){
if(state==0 && box!=null){
synchronized(IG.lock){ // to suppress flickering of display update
box.del();
box = null;
}
}
else if(state==1 && box==null){
IVec[][][] boxPts = new IVec[2][2][2];
boxPts[0][0][0] = surf.pt(pos.x, pos.y);
boxPts[1][0][0] = surf.pt(pos.x+width, pos.y);
boxPts[0][1][0] = surf.pt(pos.x, pos.y+height);
boxPts[1][1][0] = surf.pt(pos.x+width, pos.y+height);
boxPts[0][0][1] = surf.pt(pos.x, pos.y, depth);
boxPts[1][0][1] = surf.pt(pos.x+width, pos.y, depth);
boxPts[0][1][1] = surf.pt(pos.x, pos.y+height, depth);
boxPts[1][1][1] = surf.pt(pos.x+width, pos.y+height, depth);
box = new IBox(boxPts);
}
// automaton update rule table
if(lst==0 && rst==0 && dst==0 && ust==0){ state=0; }
else if(lst==1 && rst==0 && dst==0 && ust==0){ state=1; }
else if(lst==0 && rst==1 && dst==0 && ust==0){ state=1; }
else if(lst==1 && rst==1 && dst==0 && ust==0){ state=1; }
else if(lst==0 && rst==0 && dst==1 && ust==0){ state=1; }
else if(lst==1 && rst==0 && dst==1 && ust==0){ state=0; }
else if(lst==0 && rst==1 && dst==1 && ust==0){ state=0; }
else if(lst==1 && rst==1 && dst==1 && ust==0){ state=0; }
else if(lst==0 && rst==0 && dst==0 && ust==1){ state=0; }
else if(lst==1 && rst==0 && dst==0 && ust==1){ state=0; }
else if(lst==0 && rst==1 && dst==0 && ust==1){ state=0; }
else if(lst==1 && rst==1 && dst==0 && ust==1){ state=0; }
else if(lst==0 && rst==0 && dst==1 && ust==1){ state=0; }
else if(lst==1 && rst==0 && dst==1 && ust==1){ state=1; }
else if(lst==0 && rst==1 && dst==1 && ust==1){ state=1; }
else if(lst==1 && rst==1 && dst==1 && ust==1){ state=0; }
}
}
The code above had interact method with the longer version of interact(ArrayList< IDynamics >). This is because the state variables of lst, rst, dst, ust are updated only once at the whole system update process. If you use interact(IDynamics), they are updated unnecessarily as many as the number of total agents in the system.
The code below shows an example to put diferent type of geometries on an automaton from a box. When the state of the automaton is 0, it puts simple rectangular panel, but when the state is 1, it puts a surface with an aperture whose size and depth corresponds the time length of the state being 1, by the integer variable count.
![]()
![]()
![]()
![]()
import processing.opengl.*;
import igeo.*;
void setup() {
size(480, 360, IG.GL);
IG.duration(60);
IG.open("surface13.3dm");
ISurface surf = IG.surface(0);
// put automaton as panel
int unum=50, vnum=50;
double uinc=1.0/unum, vinc=1.0/vnum;
MyAutomaton[][] automata = new MyAutomaton[unum][vnum];
for (int i=0; i < unum; i++) {
for (int j=0; j < vnum; j++) {
automata[i][j] =
new MyAutomaton(new IVec(i*uinc, j*vinc, 0),
uinc, vinc, 1, surf);
}
}
//connecting adjacent automata
for (int i=0; i < unum; i++) {
for (int j=0; j < vnum; j++) {
if(i > 0){ automata[i][j].left=automata[i-1][j]; }
if(i < unum-1){ automata[i][j].right=automata[i+1][j]; }
if(j > 0){ automata[i][j].down=automata[i][j-1]; }
if(j < vnum-1){ automata[i][j].up=automata[i][j+1]; }
if(i==0){ automata[i][j].state = 1; }
}
}
surf.del();
IG.fill();
}
class MyAutomaton extends IAgent {
IVec pos;
double width, height, depth;
int state=0;
ISurface panelSurf;
ISurface surf;
int lst=0, rst=0, ust=0, dst=0;
MyAutomaton left, right, up, down;
int count=0;
MyAutomaton(IVec pt, double w, double h, double d,
ISurface s) {
pos = pt; width = w; height = h; depth = d;
surf = s;
}
void interact(ArrayList< IDynamics > agents) {
// reset states
lst=0; rst=0; dst=0; ust=0;
if(left!=null){ lst = left.state; }
if(right!=null){ rst = right.state; }
if(down!=null){ dst = down.state; }
if(up!=null){ ust = up.state; }
}
void update() {
int prevState = state;
if(lst==0 && rst==0 && dst==0 && ust==0){ state=0; }
else if(lst==1 && rst==0 && dst==0 && ust==0){ state=1; }
else if(lst==0 && rst==1 && dst==0 && ust==0){ state=1; }
else if(lst==1 && rst==1 && dst==0 && ust==0){ state=1; }
else if(lst==0 && rst==0 && dst==1 && ust==0){ state=1; }
else if(lst==1 && rst==0 && dst==1 && ust==0){ state=0; }
else if(lst==0 && rst==1 && dst==1 && ust==0){ state=0; }
else if(lst==1 && rst==1 && dst==1 && ust==0){ state=0; }
else if(lst==0 && rst==0 && dst==0 && ust==1){ state=0; }
else if(lst==1 && rst==0 && dst==0 && ust==1){ state=0; }
else if(lst==0 && rst==1 && dst==0 && ust==1){ state=0; }
else if(lst==1 && rst==1 && dst==0 && ust==1){ state=0; }
else if(lst==0 && rst==0 && dst==1 && ust==1){ state=0; }
else if(lst==1 && rst==0 && dst==1 && ust==1){ state=1; }
else if(lst==0 && rst==1 && dst==1 && ust==1){ state=1; }
else if(lst==1 && rst==1 && dst==1 && ust==1){ state=0; }
if(state!=prevState){ // state change
synchronized(IG.lock){ // to suppress flickering of display update
if(panelSurf!=null) panelSurf.del();
if(state==0){
// just rectangular panel
IVec[][] panelPts = new IVec[2][2];
panelPts[0][0] = surf.pt(pos.x, pos.y);
panelPts[1][0] = surf.pt(pos.x+width, pos.y);
panelPts[0][1] = surf.pt(pos.x, pos.y+height);
panelPts[1][1] = surf.pt(pos.x+width, pos.y+height);
panelSurf = new ISurface(panelPts).clr(count*0.02);
}
else if(state==1){
//4 by 3 control points
IVec[][] panelPts = new IVec[4][3];
//rectangular border
panelPts[0][0] = surf.pt(pos.x, pos.y);
panelPts[1][0] = surf.pt(pos.x+width, pos.y);
panelPts[2][0] = surf.pt(pos.x+width, pos.y+height);
panelPts[3][0] = surf.pt(pos.x, pos.y+height);
//rotated central opening
double angle = count*PI*0.0025;
double factor = count*0.015;
IVec center = surf.pt(pos.x+width/2, pos.y+height/2);
IVec nml = surf.nml(pos.x+width/2, pos.y+height/2);
panelPts[0][1] = panelPts[0][0].dup().scale(center, factor).rot(center, nml, angle);
panelPts[1][1] = panelPts[1][0].dup().scale(center, factor).rot(center, nml, angle);
panelPts[2][1] = panelPts[2][0].dup().scale(center, factor).rot(center, nml, angle);
panelPts[3][1] = panelPts[3][0].dup().scale(center, factor).rot(center, nml, angle);
//rotated and pushed central opening
IVec shift = nml.dup().len(depth*count*0.02);
panelPts[0][2] = panelPts[0][1].dup().add(shift).rot(center, nml, angle);
panelPts[1][2] = panelPts[1][1].dup().add(shift).rot(center, nml, angle);
panelPts[2][2] = panelPts[2][1].dup().add(shift).rot(center, nml, angle);
panelPts[3][2] = panelPts[3][1].dup().add(shift).rot(center, nml, angle);
// u degree 1, v degree 2, closed in u, open in v
panelSurf = new ISurface(panelPts,1,2,true,false).clr(count*0.02);
}
}
}
if(state>0) count++; // count time of state being positive
}
}
HOME
FOR PROCESSING
DOWNLOAD
DOCUMENTS
TUTORIALS (Java /
Python)
GALLERY
SOURCE CODE(GitHub)
PRIVACY POLICY
ABOUT/CONTACT