アニメーションによるビジュアライズ

前回まで

航空路上の座標をプロットして空間にデータをビジュアライズした。

今回は

航空路上の座標間を移動する物体をビジュアライズして、アニメーション(動き)のある表現にする。

サンプルコード


「補間」について

データは離散値である。そのため、プロットした点と点の間は連続していない。点と点を線で結ぶことはできるが点間を動くアニメーションを作るには間を補う必要がある。これを補間という。

補間にもいろいろな計算方法があるが、今回は最も単純な「線形補間」で点間の座標を補間する。


lerp()関数

lerp(ラープ)と読む。lerpとは「Linear Interpolation」(線形補間)の略。ある値aと値bの間を補間を計算することができる。

lerp関数には3つのパラメータがある。

 float a = 0;
 flaot b = 100;
 float c = lerp(a, b, 0.5);

この場合、cはaとbのちょうど中間の値(50)となる。第3パラメータは必ず0〜1の間の値を指定する。

サンプル(sketch_001_2points)

float start = 50;
float end = 450;

void setup(){
  size(500,500);
  strokeWeight(10);
}


void draw(){
  background(0);

  stroke(255);
  point(start, height/2);
  point(end, height/2);

  text("press any keys", 10, 15);

  if(keyPressed){
   stroke(255,0,0);

   point( lerp(start, end, 0.2) , height/2 ); //startとendの20%で補完
   point( lerp(start, end, 0.4) , height/2 ); //startとendの40%で補完
   point( lerp(start, end, 0.6) , height/2 ); //startとendの60%で補完
   point( lerp(start, end, 0.8) , height/2 ); //startとendの80%で補完


  }

}

sketch_001_2pointsの実行結果


2点間を移動するアニメーション

drawを実行するごとに、補間するポイントをずらしてアニメーションさせる。

サンプル(sketch_002_2points_animation)

float start = 50;
float end = 450;
float inter = 0; //補間する位置を指定する変数(0〜1に変化させてアニメーションする)

void setup(){
  size(500,500);
  strokeWeight(10);
}


void draw(){
  background(0);

  stroke(255);
  point(start, height/2);
  point(end, height/2);

  text("press any keys", 10, 15);

  if(keyPressed){

   stroke(255,0,0);   
   point( lerp(start, end, inter) , height/2 ); 

   inter+= 0.01; //補間するポイントを0.01(1%)ずつ動かす
   if(inter > 1.0) inter = 0; //1.0になったら0に戻す

  }

}

複数の点間を移動するアニメーション

2点間の補間アニメーションを応用して複数の点の間をアニメーションで繋いでみよう。

まずは、最初の点(点0)と次の点(点1)の間を補間する。点1まで移動したら、点1と点2の間を補間する。ある区間の補間が終わったら次の区間に移動し、最後の区間を補間し終えたら終了する。

サンプル(sketch_003_5points_animation)

float [] x = {50,150,250,350,450};
float [] y = {400,230,80,120,370};

int n = 0; //補間する区間の番号
float inter = 0;

void setup(){
  size(500,500);
  strokeWeight(10);
}


void draw(){
  background(0);

  stroke(255);
  for(int i = 0; i< x.length; i++){
    point(x[i], y[i]);
  }

  text("press any keys", 10, 15);

  if(keyPressed){
    stroke(255,0,0);   
    point( lerp(x[n], x[n+1], inter) , lerp(y[n], y[n+1], inter) ); 

    inter+= 0.01; //補間するポイントを0.01(1%)ずつ動かす
    if(inter > 1.0){ 
      inter = 0;
      n += 1;
      if(n >= x.length -1) n = 0; //最後の区間の補間が終わったらnを0に戻す
    }

    text("n = "+n, 10, 30);
    text("inter = "+inter, 10, 45);
  }

}

アニメーションの速度を調整できるようにしてみる

実行しながら速度を変更できるように、GUIライブラリをインポートして、スライダーから速度を調整できるようにしてみる。

GUIライブラリ「controlP5」

サンプル(sketch_004_animation_speed)

//GUIライブラリ「controlP5」をインポート
//http://www.sojamo.de/libraries/controlP5/#about
import controlP5.*;
ControlP5 gui;

float [] x = {50,150,250,350,450};
float [] y = {400,230,80,120,370};

int n = 0;
float inter = 0;
float animateSpeed = 0.01;

void setup(){
  size(500,500);
  strokeWeight(10);

  //controlP5のインスタンスを作成して、animeteSpeedがスライダーの値を受け取るようにする
  //setPositionはスライダーの表示位置、setRangeはスライダーから受け取りたい最小値と最大値
  gui = new ControlP5(this);
  gui.setAutoDraw(false);
  gui.addSlider("animateSpeed").setPosition(10,50).setRange(0,0.1);
}
void draw(){
  background(0);

  stroke(255);

  //静止している点を描画
  for(int i = 0; i< x.length; i++){
    point(x[i], y[i]);
  }

  //補間して動く点を描画
  stroke(255,0,0);   
  point( lerp(x[n], x[n+1], inter) , lerp(y[n], y[n+1], inter) ); 

  //補間の調整
  inter += animateSpeed; //補間するポイントを動かす量をスライダで変更する
  if(inter > 1.0){ 
    inter = 0;
    n += 1;
    if(n >= x.length -1) n = 0; //最後の点間の補間が終わったらnを0に戻す
  }

  text("n = "+n, 10, 15);
  text("inter = "+inter, 10, 30);

  //GUIの描画
  gui.draw();

}

3次元で点間を移動するアニメーション

peasycamを導入して、3次元空間で点間を移動させてみる。

基本は2次元と同じ。ここでは、PVectorをつかってみる。guiの書き方に少し違う部分がある。

サンプル(sketch_005_animation_speed_3d)を確認してみよう。

PVectorクラスが持つlerp関数を使うパターンも確認してみよう(sketch_006_animation_speed_3d_2)


演習

前回実装した、球面へマッピングした航空路上を移動する航空機をアニメーションで表現してみよう。

解説

前回のサンプルに含まれる「plot_route_earth」をベースにアニメーションに必要な改良を加えていこう。完成版のコードと解説は次の通り。

完成版のコード

1. Positionクラスの改良

まず、のちのちlerp()関数をx,y,zそれぞれに対して実行する手間を考慮して、3次元空間の座標のをx, y, zではなく、PVectorくらすでまとめて管理する方法に変える。具体的には、Postitionクラスを以下のように変更する。

class Position{
  String point;
  float lon; //longitude=経度(東西)
  float lat; //lattidude=緯度(南北)
  float alt; //高度(m)
  PVector coord; // 空間上の座標x,y,zを格納するPVector

  Position(String _line){
    lon = float(_line.split(",")[0]);
    lat = float(_line.split(",")[1]);
    alt = float(_line.split(",")[2]);
    //地球の半径を200pxとする。
    pointToEarth(lon, lat, 200 + alt/2000);
  }

  void pointToEarth(float _lon, float _lat, float _r){
    float x =  _r * sin(PI/2 - radians(_lat)) * sin(radians(_lon));
    float y = -1 * _r * cos(PI/2 - radians(_lat));
    float z = _r * sin(PI/2 - radians(_lat)) * cos(radians(_lon));
    coord = new PVector(x,y,z);
  }


  void draw(){

    vertex(coord.x, coord.y ,coord.z);

  }
}

ポイントは、

  • これまで使用してきたメンバー変数(注)x, y, zをPVector coordにまとめる。

    • x は coord.x
    • y は coord.y
    • z は coord.z

    となる。ちなみに、 coordは「coordinates(座標)」の略。

  • pointToEarth()で計算した結果x,y,xは、coordに入力する。

  • drawの実行にもcoordの座標を用いる。

2. Flightクラスの実装

(解説後日)

完成

results matching ""

    No results matching ""