[Processing]円状隣接グラフを描いてみた

カテゴリ: processing / author: uechoco / 2008年02月07日 12:22:00
この記事を読む時間:79くらい

さきほどFlickrの

※クリックしてLightboxで拡大
flickr: everyone knows everyone from flickr

http://flickr.com/photos/eskimoblood/2111672366/

の画像をみて、「描きたいっ」と思って、Processingで描いてみました。「Circular Adjacency Graph」。「円状隣接グラフ」って勝手に呼んでいます。プログラム的にそういうことをしているので。全く同じものを作ったわけではないですが、自分の中では同じようなものなので満足しています。

※カーブ率 = 1のグラフ(クリックで別ウィンドウに原寸表示)

processing_CircularAdjacencyGraph.jpg

※カーブ率 = 0.3のグラフ(クリックで別ウィンドウに原寸表示)

processing_CircularAdjacencyGraph2.jpg

[p5code]size(600, 600);
colorMode(HSB, 100);
background(100);
noFill();
smooth();

// 定数定義
int max = 30; // 最大数
int radius = 220; // 半径
int cx = width / 2; // 中心x座標
int cy = height / 2; // 中心y座標
float adjRate = 0.3; // 隣接する確率
float curveRate = 0.3; // カーブ率

// 変数定義
Point[] points = new Point[max]; // 円周上の点の集合の定義
int[] hues = new int[max]; // 円周上の点のカラー(色相)
int[] adj = new int[max * max]; // 隣接行列の定義

// 円周上に点を配置
for (int i = 0; i < max; i++) {
float angle = random(360);
float x = cx + cos(radians(angle)) * radius;
float y = cy - sin(radians(angle)) * radius;
points[i] = new Point();
points[i].setLocation(x, y);
// 色をランダムに定義
hues[i] = (int)random(100);
}

// 隣接行列を作成
for (int i = 0; i < max; i++) {
for (int j = 0; j < max; j++) {
if (i >= j) {
adj[i * max + j] = 0;
} else {
adj[i * max + j] = (random(1) < adjRate ? 1 : 0);
}
}
}

// 円
strokeWeight(1);
stroke(70);
ellipseMode(CENTER_RADIUS);
ellipse(cx, cy, radius, radius);
// 点の配置
for (int i = 0; i < max; i++) {
strokeWeight(8);
stroke(hues[i], 60, 100, 60);
point(points[i].x, points[i].y);
// 隣接点を結ぶ
strokeWeight(1);
for (int j = 0; j < max; j++) {
// 隣接していなければ次へ
if (adj[i * max + j] == 0) continue;
// 点を再定義(利便性)
int x1 = points[i].x;
int y1 = points[i].y;
int x2 = points[j].x;
int y2 = points[j].y;
// 2点間の距離を求める(2倍にして補間点を増やす)
int x21 = x2 - x1;
int y21 = y2 - y1;
float r = sqrt(x21 * x21 + y21 * y21) * 2;
for (int k = 0; k < r; k++) {
// 進行度
float rate = k / r;
// 点の色を調整
stroke(hues[i] + (hues[j] - hues[i]) * rate, 60, 100, 60);
// まずは2点を直線で結んだときの現在点を求める
float x = x1 + (x21 * rate);
float y = y1 + (y21 * rate);
// 重心の設定をするための比率(値域は0?curveRateまで)
float cRate = sin(PI * rate) * curveRate;
// 円の中心と現在点に比率をかけて、描画点を求める
x = (x + cx * cRate) / (cRate + 1);
y = (y + cy * cRate) / (cRate + 1);
point(x, y);
}
}
}

// 署名
PFont font = loadFont("Impact-18.vlw");
fill(0);
textFont(font, 18);
textAlign(RIGHT);
text("Circular Adjacency Graph\n2008 uechoco", width - 20, height - 40); [/p5code]

円周上の点同士をline()命令を使って直線で結ぶのは簡単なのですが、上のFlickrの画像を見ると、中心に向かってカーブしています。これをどうやって再現するのかが悩みました。最初は円の中心と2点を結ぶ直線を漸近線とみたてて、双曲線を描こうとしたのですが、数式を調べたりそれを実装したりするのが面倒だと思って、即却下。代替案として、直線の個々の点と円の中心との重心をなぞる方法にしました。2点間の中心に近づくほど、円の中心に近づくようにサインカーブを調整しています。またカーブ率を低くすることで、重心を円周側に寄せられるので、なめらかなカーブになります。

いやぁーこんなのまで描けるんですね。楽しさ無限大!


コメントはまだありません »

コメントはまだありません。

この投稿へのコメントの RSS フィード。 TrackBack URI

コメントする

Copyright © 2014 うえちょこ@ぼろぐ. WP Theme created by Web Top.