「The Nature of Code」からばねについて取り上げます。ばねにかかる力を計算して、ばねをシミュレーションします。Processingでプログラムを書いて、動作を確認します。動作を確認できるところがProcessingの楽しいところです。
ばねの描き方
フックの法則に従い、力を計算します。ばねの力は、ばねの伸びに正比例します。
ばねのシミュレーション
以下は、ばねの参考例です。
//A Spring connection Bob bob; Spring spring; void setup() { size(200,200); //バネの起点の座標とバネの自然長 spring = new Spring(width/2, 10, 100); //球の座標 bob = new Bob(width/2, 100); } void draw() { background(255); //重力を適用する PVector gravity = new PVector(0, 2); bob.applyForce(gravity); //球をバネに接続する(バネの力を計算する) spring.connect(bob); //バネの長さを制限する spring.constrainLength(bob, 30, 200); bob.update(); bob.drag(mouseX, mouseY); //図形の描画:バネの起点、バネ、球 spring.displayLine(bob); bob.display(); spring.display(); fill(0); text("click on bob to drag", 10, height-5); } //マウスをクリックしたとき void mousePressed(){ bob.clicked(mouseX, mouseY); } //マウスを離したとき void mouseReleased(){ bob.stopDragging(); }
class Bob { PVector position; PVector velocity; PVector acceleration; float mass = 24; //質量 float damping = 0.98; //速度の減衰量 //マウス操作用 PVector dragOffset; boolean dragging = false; //コンストラクタ Bob(float x, float y) { position = new PVector(x, y); velocity = new PVector(); acceleration = new PVector(); dragOffset = new PVector(); } //値の更新 void update() { velocity.add(acceleration); velocity.mult(damping); position.add(velocity); acceleration.mult(0); } //力を適用する void applyForce(PVector force){ PVector f = force.copy(); f.div(mass); acceleration.add(f); } //球の描画 void display() { stroke(0); strokeWeight(2); fill(175); if(dragging){ fill(50); } ellipse(position.x, position.y, mass*2, mass*2); } //以下、マウス操作 //球がクリックされたか確認する void clicked(int mx, int my){ float d = dist(mx, my, position.x, position.y); if(d < mass){ dragging = true; dragOffset.x = position.x - mx; dragOffset.y = position.y - my; } } void stopDragging(){ dragging = false; } //ドラッグ void drag(int mx, int my){ if(dragging){ position.x = mx + dragOffset.x; position.y = my + dragOffset.y; } } }
class Spring{ PVector anchor; //バネの起点の座標 float len; //バネの自然長の長さ float k = 0.2; //バネ定数 //コンストラクタ Spring(float x, float y, int l){ anchor = new PVector(x, y); len = l; } //バネの力の計算 void connect(Bob b){ PVector force = PVector.sub(b.position, anchor); float dist = force.mag(); float stretch = dist - len; //現在のバネの伸びと自然長の差 //フックの法則より力を計算する //F = k * stretch force.normalize(); force.mult(-1 * k * stretch); b.applyForce(force); } //球とアンカーとの距離を制限する void constrainLength(Bob b, float minlen, float maxlen){ PVector dir = PVector.sub(b.position, anchor); float d = dir.mag(); //短すぎる場合 if(d < minlen){ dir.normalize(); dir.mult(minlen); //位置をリセットして移動を停止(現実的な物理ではない) b.position = PVector.add(anchor, dir); b.velocity.mult(0); }else if(d > maxlen){ //長過ぎる場合 dir.normalize(); dir.mult(maxlen); //位置をリセットして移動を停止(現実的な物理ではない) b.position = PVector.add(anchor, dir); b.velocity.mult(0); } } //バネの起点の描画 void display(){ stroke(0); fill(175); strokeWeight(2); rectMode(CENTER); rect(anchor.x, anchor.y, 10, 10); } //バネの描画 void displayLine(Bob b){ strokeWeight(2); stroke(0); line(b.position.x, b.position.y, anchor.x, anchor.y); } }
まとめ
「The Nature of Code」からばねについて取り上げました。ばねにかかる力を計算して、ばねをシミュレーションしました。引き続き、「The Nature of Code」の内容を勉強します。
参考書籍
※Javaの勉強にもなるので一石二鳥です。