Skip to content

Instantly share code, notes, and snippets.

@TonyMooori
Last active February 17, 2016 04:21
Show Gist options
  • Save TonyMooori/c5ff1da9ba9516d008db to your computer and use it in GitHub Desktop.
Save TonyMooori/c5ff1da9ba9516d008db to your computer and use it in GitHub Desktop.
一筆書きのデータをcsvで読み込んでフーリエ級数展開し描画するコードです
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