元Webデザイナー兼コーダーの備忘録

ウェブデザインやプログラミング、ブログのカスタマイズなどについてアウトプットしています。

 メニュー

» HTML入門のまとめはこちらです。

Processing:流体の抗力

The Nature of Code(PDF版)から流体の抗力について取り上げます。PVectorを用いて、流体の抗力について学びます。Processingでプログラムを書いて、動作を確認します。動作を確認できるところがProcessingの楽しいところです。

流体の抗力を示す式

流体の抗力を示す式は、以下のようになるそうです。

Fd = \frac{1}{2} * ρ * v^2 * A * Cd

  • Fd:抗力
  • ρ:流体の密度
  • v:物体と流体の相対速度
  • A:投影面積
  • Cd:抗力係数

この式をベクトルを使い、以下のように表します。

Fd = - \frac{1}{2} * ρ * v^2 * A * Cd * \hat{v}

2次元の世界でそれっぽく見えれば良いので、式を以下のように簡略化して考えます。

Fd = ||v||^2 * Cd * \hat{v} * (-1)

  • Fd:抗力
  • ||v||:物体と流体の相対速度の大きさ
  • Cd:抗力係数
  • \hat{v}:速度の単位ベクトル(=velocity.normalize())

式から抜け落ちたρとAは、以下のように扱うこととします。

  • ρ:1とする
  • A:オブジェクトが球体なので無視することにする

この式を向きと大きさに分解して考えます。

  • 向き
    • -\hat{v}:速度の単位ベクトルの-1倍
    • 抗力は速度(移動方向)と逆方向
  • 大きさ
    • ||v||^2:物体と流体の相対速度の2乗
    • Cd:任意の値

流体の抗力を適用する例

以下は、流体の抗力を適用したプログラムの参考例です。ボールが液体内にあれば、ボールに流体の抗力を適用します。ここでは、液体部分をグレーに色付けしています。

class Mover {
  PVector location;
  PVector velocity;
  PVector acceleration;
  float mass;  //質量

  //コンストラクタ
  Mover() {
    location = new PVector(30,30);
    velocity = new PVector(0,0);
    acceleration = new PVector(0,0);
    mass = 1;
  }
  Mover(float m, float x, float y) {
    location = new PVector(x,y);
    velocity = new PVector(0,0);
    acceleration = new PVector(0,0);
    mass = m;
  }

  //力を足し合わせる(力の蓄積)
  void applyForce(PVector force) {
    PVector f = PVector.div(force,mass);
    acceleration.add(f);
  }

  //ボールの位置の更新
  void update() {
    velocity.add(acceleration);
    location.add(velocity);
    acceleration.mult(0);  //力の蓄積をリセットする
  }

  //ボールの描画
  void display() {
    stroke(0);
    strokeWeight(2);
    fill(0, 127);
    ellipse(location.x,location.y,mass*16,mass*16);
  }

  //ボールがバウンドしたときの処理
  void checkEdges() {
    if (location.y > height) {
      velocity.y *= -0.9;
      location.y = height;
    }
  }
}
class Liquid{
  float x,y,w,h;
  float c;  //抗力の係数

  //コンストラクタ
  Liquid(float x, float y, float w, float h, float c){
    this.x = x;
    this.y = y;
    this.w = w;
    this.h = h;
    this.c = c;
  }

  //ボールが液体内にあるか判定する
  boolean contains(Mover m){
    PVector l = m.location;
    if(l.x > x && l.x < x+w && l.y > y && l.y < y+h){
      return true;
    }else{
      return false;
    }
  }

  //液体の抗力を計算する
  PVector drag(Mover m){
    //大きさを計算する
    float speed = m.velocity.mag();
    float dragMagnitude = c * speed * speed;

    //力の向きを求める
    PVector dragForce = m.velocity.copy();
    dragForce.mult(-1);
    dragForce.normalize();
    dragForce.mult(dragMagnitude);
    return dragForce;  //抗力を返す
  }

  //液体の描画
  void display(){
    noStroke();
    fill(175);
    rect(x, y, w, h);
  }
}
//Fluid Resistance
Mover[] movers = new Mover[11];
Liquid liquid;

void setup() {
  size(800,200);
  randomSeed(1);
  smooth();

  //液体の生成
  liquid = new Liquid(0, height/2, width, height/2, 0.1);

  //ボールの生成
  for(int i = 0 ; i < movers.length; i++){
    movers[i] = new Mover(random(0.5,3), 40+i*70,0);
  }
}

void draw() {
  background(255);

  liquid.display();

  //ボールに対しての処理
  for(int i = 0; i < movers.length; i++){
    if(liquid.contains(movers[i])){  //ボールが液体内にあるか判定する
      PVector dragForce = liquid.drag(movers[i]);
      movers[i].applyForce(dragForce);  //液体の抗力を適用する
    }

    float m = 0.1 * movers[i].mass;
    PVector gravity = new PVector(0,m);  //重力
    movers[i].applyForce(gravity);

    movers[i].update();
    movers[i].display();
    movers[i].checkEdges();
  }
}

プログラムを実行して確認することをおすすめします。

プログラムの解説

Liquidクラスのdrag()メソッドで流体の抗力を計算します。抗力の大きさと向きを計算し、流体の抗力を求めます。

PVector drag(Mover m){
  //大きさを計算する
  float speed = m.velocity.mag();
  float dragMagnitude = c * speed * speed;

  //力の向きを求める
  PVector dragForce = m.velocity.copy();
  dragForce.mult(-1);
  dragForce.normalize();
  dragForce.mult(dragMagnitude);
  return dragForce;  //抗力を返す
}

draw()メソッド内でボールが液体内にあるか判定します。ボールが液体内にあれば、ボールに流体の抗力を適用します。

void draw() {
  ...
  for(int i = 0; i < movers.length; i++){
    if(liquid.contains(movers[i])){  //ボールが液体内にあるか判定する
      PVector dragForce = liquid.drag(movers[i]);
      movers[i].applyForce(dragForce);  //液体の抗力を適用する
    }
    ...
  }
}

メモ

  • copy():ベクトルのコピーを取得し、PVectorを返す
  • saveFrame():画像に保存する
//画像として保存する
if (frameCount % 20 == 0) saveFrame("frames/####.png");

まとめ

The Nature of Code(PDF版)から流体の抗力について取り上げました。今回は、PVectorを用いて流体の抗力について学びました。引き続き、The Nature of Code(PDF版)の内容を勉強します。

参考サイト

» HTML入門のまとめはこちらです。