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

Written by uechoco 2月 07
この記事を読む時間:79くらい

さきほどFlickrの

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

の画像をみて、「描きたいっ」と思って、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点間の中心に近づくほど、円の中心に近づくようにサインカーブを調整しています。またカーブ率を低くすることで、重心を円周側に寄せられるので、なめらかなカーブになります。

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

No Responses to “[Processing]円状隣接グラフを描いてみた”

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

Comments RSS rss うえちょこ@ぼろぐ TrackBack Identifier URI rss うえちょこ@ぼろぐ

コメントをどうぞ