Last active
February 17, 2016 04:21
-
-
Save TonyMooori/c5ff1da9ba9516d008db to your computer and use it in GitHub Desktop.
一筆書きのデータをcsvで読み込んでフーリエ級数展開し描画するコードです
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class FourierPlotter { | |
int n_data; // データの個数 | |
int n_approx; // 近似次数 | |
float[][] radius; // 半径 | |
float[] data; // データ | |
float centerX; // 中心X座標 | |
float centerY; // 中心Y座標 | |
float phase; // 位相のズレ | |
public float x; // 先端部分のX座標 | |
public float y; // 先端部分のY座標 | |
// コンストラクタ | |
FourierPlotter(float[] data, int n_approx, | |
float centerX, float centerY, float phase) { | |
// 引数をメンバ変数に代入した後,フーリへ級数展開 | |
this.data = data; | |
this.n_data = data.length; | |
this.n_approx = n_approx; | |
this.phase = phase; | |
this.centerX = this.x = centerX; | |
this.centerY = this.y = centerY; | |
this.calcRadius(); | |
} | |
// フーリエ級数展開を計算する関数 | |
void calcRadius() { | |
// フーリエ級数の係数は半径に当たる | |
this.radius = new float[2][this.n_approx]; | |
float dt = 2.0*PI / this.n_data; // 微小長さdt | |
// バイアス項(0次の項)は無視している | |
for ( int i = 1; i < this.n_approx; i++ ) { | |
for (int j = 0; j < this.n_data; j++ ) { | |
float t = 2.0*PI*j/this.n_data; | |
// 普通に矩形積分する | |
this.radius[0][i] += sin(i*t)*this.data[j]*dt/PI; | |
this.radius[1][i] += cos(i*t)*this.data[j]*dt/PI; | |
} | |
} | |
} | |
// 描画を行う関数 | |
void visualize(float theta) { | |
// x,y座標をとりあえず中心に持ってくる | |
this.x = this.centerX; | |
this.y = this.centerY; | |
float tempX, tempY; | |
for (int i = 0; i < this.n_approx; i++ ) { | |
for (int j= 0; j<2; j++) { | |
// 円を描く | |
ellipse(x, y, 2.0*this.radius[j][i], 2.0*this.radius[j][i]); | |
tempX = x; | |
tempY = y; | |
// 先端部分の位置座標を計算(j=1の時,余弦なので位相がPI/2ずれる) | |
x += this.radius[j][i]*cos(i*theta+PI*j/2 + this.phase); | |
y += this.radius[j][i]*sin(i*theta+PI*j/2 + this.phase); | |
line(x, y, tempX, tempY); // 各円の中心をを直線で結ぶ | |
} | |
} | |
} | |
} | |
class Fourier2d { | |
float[][] points; // 過去に通った座標 | |
int n_data; // データ数 | |
FourierPlotter fpX; // FourierPlotterクラスX方向 | |
FourierPlotter fpY; // FourierPlotterクラスY方向 | |
int count; // ループカウンタ | |
int centerX; | |
int centerY; | |
// コンストラクタ | |
Fourier2d(String filename,int centerX,int centerY) { | |
float[][] data = load_data(filename); | |
this.n_data = data[0].length; | |
this.points = new float[2][n_data]; | |
this.count = 0; | |
this.centerX = centerX; | |
this.centerY = centerY; | |
this.fpX = new FourierPlotter(data[0], n_data, centerX+150, centerY+150, -PI/2); | |
this.fpY = new FourierPlotter(data[1], n_data, centerX-150, centerY-150, 0); | |
} | |
// x,yのデータを読み込む関数 | |
float[][] load_data(String path) { | |
// 文字列を読み込む | |
String lines[] = loadStrings(path); | |
FloatList x = new FloatList(); | |
FloatList y = new FloatList(); | |
// 先頭行(ヘッダー)は読み飛ばすので1始まり | |
for (int i=1; i < lines.length; i++) { | |
// コンマで区切って2つ以上の要素があったらリストに加える | |
String [] element =split(lines[i], ','); | |
if (element.length >= 2 ) { | |
x.append(parseFloat(element[0])); | |
y.append(parseFloat(element[1])); | |
} | |
} | |
float[][] data = new float[2][x.size()]; | |
data[0] = x.array(); | |
data[1] = y.array(); | |
return data; | |
} | |
void visualize( ) { | |
float theta = this.count * 2*PI / this.n_data; | |
fill(0, 0, 0, 0); | |
strokeWeight(3); | |
// 円を描画 | |
stroke( 0, 255, 0); | |
this.fpX.visualize(theta); | |
stroke( 255, 0, 0); | |
this.fpY.visualize(theta); | |
// 色を変える | |
stroke(0, 255, 255); | |
fill(0, 255, 255); | |
strokeWeight(1); | |
// 円の先端からの直線を描画 | |
line(fpX.x, fpX.y, fpX.x, fpY.y); | |
line(fpY.x, fpY.y, fpX.x, fpY.y); | |
rect(fpX.x, fpY.y, 1, 1); | |
// 軌跡を描画 | |
stroke(255, 255, 255); | |
fill(255, 255, 255); | |
strokeWeight(3); | |
this.points[0][this.count%n_data] = fpX.x; | |
this.points[1][this.count%n_data] = fpY.y; | |
for (int i = 0; i < min(this.n_data, this.count) - 1; i++ ) | |
line(points[0][i], points[1][i], points[0][i+1], points[1][i+1]); | |
this.count+=1; // stepをすすめる | |
} | |
} | |
float scale = 0.75; // 拡大率 | |
float dx=0.0; // x方向の移動 | |
float dy=-0.0; // y方向の移動 | |
Fourier2d f1; // 描画クラス | |
void setup() { | |
size(640, 480); | |
// ここでデータを読み込むので同一フォルダにcsvファイルが必要 | |
f1 = new Fourier2d("best_order.csv", -100, 100); | |
} | |
void draw() { | |
background(0); | |
translate(width/2-dx, height/2-dy); // 原点を中心に移動 | |
scale(scale, scale); | |
// 描画 | |
f1.visualize(); | |
//saveFrame("./frames/#####.png"); | |
} | |
void keyPressed() { | |
// キー操作による拡大・移動 | |
if (key == CODED) { | |
if (keyCode == UP) { | |
dy -= 10; | |
} else if (keyCode == DOWN) { | |
dy += 10; | |
} else if (keyCode == LEFT) { | |
dx -= 10; | |
} else if (keyCode == RIGHT) { | |
dx += 10; | |
} | |
} else if (key == '+') { | |
scale *= 1.05; | |
} else if (key=='-') { | |
scale /= 1.05; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment