チュートリアル | (トピック一覧へ戻る) |
張力ベクトルの計算と、2つのパーティクルへの適用は interactメソッドでなされます。 差ベクトルdifがまず計算され、tensionが それに乗算されます。 そしてpushメソッドとpullメソッドを用いて 力がそれぞれ別方向に適用されます。
import processing.opengl.*; import igeo.*; void setup(){ size(480, 360, IG.GL); IG.duration(20); MyParticle pt1 = new MyParticle(IG.v(-80,80,0),IG.v(0,0,0)); MyParticle pt2 = new MyParticle(IG.v(80,-80,0),IG.v(0,0,0)); pt1.clr(0); pt2.clr(1.0,0,0); new MyTension(pt1, pt2, 3.0); } class MyTension extends IAgent{ MyParticle particle1, particle2; double tension; // proportial coefficient MyTension(MyParticle p1, MyParticle p2, double t){ particle1 = p1; particle2 = p2; tension = t; } void interact(ArrayList < IDynamics > agents){ IVec dif = particle2.pos().dif(particle1.pos()); dif.mul(tension); particle1.push(dif); particle2.pull(dif); //opposite force } } class MyParticle extends IParticle{ MyParticle(IVec pos, IVec vel){ super(pos,vel); } void update(){ new IPoint(pos.cp()).clr(clr()); // putting point every frame } }
import processing.opengl.*; import igeo.*; void setup(){ size(480, 360, IG.GL); IG.duration(15); MyParticle pt1 = new MyParticle(IG.v(-80,80,0),IG.v(0,0,0)); MyParticle pt2 = new MyParticle(IG.v(80,-80,0),IG.v(0,0,0)); pt1.clr(0); pt2.clr(1.0,0,0); new MyTension(pt1, pt2, 3.0).clr(1,0.5,0); } class MyTension extends IAgent{ MyParticle particle1, particle2; double tension; // proportial coefficient ICurve line; MyTension(MyParticle p1, MyParticle p2, double t){ particle1 = p1; particle2 = p2; tension = t; } void interact(ArrayList < IDynamics > agents){ IVec dif = particle2.pos().dif(particle1.pos()); dif.mul(tension); particle1.push(dif); particle2.pull(dif); //opposite force } void update(){ if(line==null){ line = new ICurve(particle1.pos(),particle2.pos()).clr(clr()); } else{ line.updateGraphic(); } } } class MyParticle extends IParticle{ MyParticle(IVec pos, IVec vel){ super(pos,vel); } void update(){ new IPoint(pos.cp()).clr(clr()); // putting point every frame } }
import processing.opengl.*; import igeo.*; void setup(){ size(480, 360, IG.GL); IG.duration(15); MyParticle pt1 = new MyParticle(IG.v(-80,80,0),IG.v(0,0,0)); MyParticle pt2 = new MyParticle(IG.v(80,-80,0),IG.v(0,0,0)); pt1.clr(0); pt2.clr(1.0,0,0); new ITensionLine(pt1, pt2, 3.0).clr(1,0.5,0); } class MyParticle extends IParticle{ MyParticle(IVec pos, IVec vel){ super(pos,vel); } void update(){ new IPoint(pos.cp()).clr(clr()); // putting point every frame } }
import processing.opengl.*; import igeo.*; void setup(){ size(480, 360, IG.GL); IG.duration(800); MyParticle pt1 = new MyParticle(IG.v(-80,80,0),IG.v(0,0,0)); MyParticle pt2 = new MyParticle(IG.v(80,-80,0),IG.v(0,0,0)); MyParticle pt3 = new MyParticle(IG.v(0,-80,0),IG.v(0,0,0)); pt1.clr(0); pt2.clr(1.0,0,0); pt3.clr(0.5,0,1); new ITensionLine(pt1, pt2, 3.0).clr(1,0.5,0); new ITensionLine(pt2, pt3, 3.0).clr(1,0.5,0); } class MyParticle extends IParticle{ IVec prevPos; MyParticle(IVec pos, IVec vel){ super(pos,vel); } void update(){ IVec curPos = pos().cp(); if(prevPos != null){ new ICurve(prevPos,curPos).clr(clr()); } prevPos = curPos; } }
二つめの例では、片方の張力係数を小さくしています。
import processing.opengl.*; import igeo.*; void setup(){ size(480, 360, IG.GL); IG.duration(600); MyParticle pt1 = new MyParticle(IG.v(-80,80,0),IG.v(0,0,0)); MyParticle pt2 = new MyParticle(IG.v(80,-80,0),IG.v(0,0,0)); MyParticle pt3 = new MyParticle(IG.v(0,-80,0),IG.v(0,0,0)); pt1.clr(0); pt2.clr(1.0,0,0); pt3.clr(0.5,0,1); new ITensionLine(pt1, pt2, 3.0).clr(1,0.5,0); new ITensionLine(pt2, pt3, 1.5).clr(1,0.5,0); } class MyParticle extends IParticle{ IVec prevPos; MyParticle(IVec pos, IVec vel){ super(pos,vel); } void update(){ IVec curPos = pos().cp(); if(prevPos != null){ new ICurve(prevPos,curPos).clr(clr()); } prevPos = curPos; } }
三つめの例では再び張力係数は同じですが、 一つのパーティクルにX方向の初期速度が与えられています。
import processing.opengl.*; import igeo.*; void setup(){ size(480, 360, IG.GL); IG.duration(1200); MyParticle pt1 = new MyParticle(IG.v(-80,80,0),IG.v(0,0,0)); MyParticle pt2 = new MyParticle(IG.v(80,-80,0),IG.v(0,0,0)); MyParticle pt3 = new MyParticle(IG.v(0,-80,0),IG.v(50,0,0)); pt1.clr(0); pt2.clr(1.0,0,0); pt3.clr(0.5,0,1); new ITensionLine(pt1, pt2, 3.0).clr(1,0.5,0); new ITensionLine(pt2, pt3, 3.0).clr(1,0.5,0); } class MyParticle extends IParticle{ IVec prevPos; MyParticle(IVec pos, IVec vel){ super(pos,vel); } void update(){ IVec curPos = pos().cp(); if(prevPos != null){ new ICurve(prevPos,curPos).clr(clr()); } prevPos = curPos; } }
この例ではfric()メソッドを用いて パーティクルに摩擦度が指定されています。 fric()の引数に入れる摩擦度は0から1のdouble型の値で、 0の時は摩擦が無く速度は全く減衰せず、 1は最大の摩擦で、速度は常にゼロに戻されています。
また、パーティクルがその位置で固定されて動かなくなるようにするメソッド fix()も用いられています。 一度固定されたパーティクルはunfix()メソッドで また動けるようにできます。
import processing.opengl.*; import igeo.*; void setup(){ size(480, 360, IG.GL); IG.duration(800); int num = 10; MyParticle[][] pts = new MyParticle[num+1][num+1]; for(int i=0; i <= num; i++){ for(int j=0; j <= num; j++){ pts[i][j] = new MyParticle(IG.v(10*i,10*j,0), IG.v(0,0,0)); pts[i][j].fric(0.01); //friction if(i > 0){ //tension line in X new ITensionLine(pts[i-1][j], pts[i][j],1).clr(0); } if(j > 0){ //tension line in Y new ITensionLine(pts[i][j-1], pts[i][j],1).clr(0); } } } pts[0][0].fix().clr(0.5,0,0); //fix the corner particle pts[num][0].fix().clr(0.5,0,0); //fix the corner particle pts[0][num].fix().clr(0.5,0,0); //fix the corner particle pts[num][num].fix().clr(0.5,0,0); //fix the corner particle } class MyParticle extends IParticle{ IVec prevPos; MyParticle(IVec pos, IVec vel){ super(pos,vel); } }
次の例では、格子線の張力ネットワークに 斜めの張力線を追加しています。 更に、格子点上のパーティクルと 張力線の生成を確率的にコントロールすることにより 格子線ネットワークの上に、穴が空くような状況をつくりだし、 そのネットワークが張力によってどのように変形するかを 観察しています。
import processing.opengl.*; import igeo.*; void setup(){ size(480, 360, IG.GL); IG.duration(500); int num = 30; MyParticle[][] pts = new MyParticle[num+1][num+1]; for(int i=0; i <= num; i++){ for(int j=0; j <= num; j++){ if(IRand.pct(87)){ pts[i][j] = new MyParticle(IG.v(10*i,10*j,0), IG.v(0,0,0)); pts[i][j].fric(0.01); //friction if(i > 0 && pts[i-1][j]!=null){ new ITensionLine(pts[i-1][j], pts[i][j],1).clr(0); } if(j > 0 && pts[i][j-1]!=null){ new ITensionLine(pts[i][j-1], pts[i][j],1).clr(0); } if(i > 0 && j > 0 && pts[i-1][j-1]!=null){ new ITensionLine(pts[i-1][j-1], pts[i][j],1).clr(0); } if(i==0 || j==0 || i==num || j==num){ // edge pts[i][j].fix().clr(0.5,0,0); } } } } } class MyParticle extends IParticle{ IVec prevPos; MyParticle(IVec pos, IVec vel){ super(pos,vel); } }
import processing.opengl.*; import igeo.*; void setup(){ size(480, 360, IG.GL); IG.duration(2000); int num = 30; MyParticle[][] pts = new MyParticle[num+1][num+1]; for(int i=0; i <= num; i++){ for(int j=0; j <= num; j++){ if(IRand.pct(75)){ pts[i][j] = new MyParticle(IG.v(10*i,10*j,0), IG.v(0,0,0)); pts[i][j].fric(0.01); //friction if(i > 0 && pts[i-1][j]!=null){ new ITensionLine(pts[i-1][j], pts[i][j],1).clr(0); } if(j > 0 && pts[i][j-1]!=null){ new ITensionLine(pts[i][j-1], pts[i][j],1).clr(0); } if(i > 0 && j > 0 && pts[i-1][j-1]!=null){ new ITensionLine(pts[i-1][j-1], pts[i][j],1).clr(0); } if(i==0 || j==0 || i==num || j==num){ // edge pts[i][j].fix().clr(0.5,0,0); } } } } new MyGravity(IG.v(0,0,-10)); } class MyGravity extends IAgent{ IVec gravity; MyGravity(IVec g){ gravity=g; } void interact(IDynamics agent){ if(agent instanceof MyParticle){ MyParticle particle = (MyParticle)agent; particle.push(gravity); } } } class MyParticle extends IParticle{ IVec prevPos; MyParticle(IVec pos, IVec vel){ super(pos,vel); } }
次の例では、斥力エージェントRepulsionAgentを作成し、多く配置することによって 張力格子で形成される形状を膨らませるような形で変形しています。
import processing.opengl.*; import igeo.*; void setup(){ size(480, 360, IG.GL); IG.duration(1000); int num = 30; MyParticle[][] pts = new MyParticle[num+1][num+1]; for(int i=0; i <= num; i++){ for(int j=0; j <= num; j++){ if(IRand.pct(75)){ pts[i][j] = new MyParticle(IG.v(10*i,10*j,0), IG.v(0,0,0)); pts[i][j].fric(0.01); //friction if(i > 0 && pts[i-1][j]!=null){ new ITensionLine(pts[i-1][j], pts[i][j],1).clr(0); } if(j > 0 && pts[i][j-1]!=null){ new ITensionLine(pts[i][j-1], pts[i][j],1).clr(0); } if(i > 0 && j > 0 && pts[i-1][j-1]!=null){ new ITensionLine(pts[i-1][j-1], pts[i][j],1).clr(0); } if(i==0 || j==0 || i==num || j==num){ // edge pts[i][j].fix().clr(0.5,0,0); } } } } for(int i=0; i < 10; i++){ new RepulsionAgent(IRand.pt(-50,-50,-10,350,350,-10)).clr(1.,0,0); } } class RepulsionAgent extends IPointAgent{ double threshold = 100; double minDist = 1.0; double repulsion = 400; RepulsionAgent(IVec v){ super(v); } void interact(IDynamics agent){ if(agent instanceof MyParticle){ MyParticle particle = (MyParticle)agent; IVec dif = particle.pos().dif(pos()); //force from here to particle double dist = dif.len(); if(dist < threshold){ if(dist < minDist){ dist = minDist; } double strength = repulsion/dist; //the closer the larger IVec force = dif.len(strength); particle.push(force); } } } } class MyParticle extends IParticle{ IVec prevPos; MyParticle(IVec pos, IVec vel){ super(pos,vel); } }