- 開発技術
【Processing】コードで木を描く
- その他
はじめに
【エンジニア募集中】フルリモート可◎、売上/従業員数9年連続UP、平均残業8時間、有給取得率90%、年休124日以上 etc. 詳細はこちらから>
この記事ではProcessingで木を描く方法をご紹介します。実際に作成された画像はこちらになります。パラメータを変えて実行することでさまざまな木を描くことができます。
Processingとは
Processingはビジュアルプログラミングのためのオープンソースの開発環境です。言語はJavaをベースとしていますが、シンプルな構造でJavaの知識がなくても直感的にコードを書くことができます。また、Pythonモード(Python Mode for Processing)やWebブラウザ上で動かせるJavaScriptライブラリ(p5.js)も存在します。
IDEについて
公式サイトからIDEをダウンロードできます。リアルタイムにコードがチェックされ、エラー内容はコンソールに出力されます。
木の描画処理の流れ
今回は再帰処理を用いて木の描画処理を実装します。大まかな処理の流れは下記のようになります。(サンプルコードは記事の最後にあります)
枝描画処理(N回)
①枝描画
②N>0のとき③~④の処理を行う
③右側の枝描画処理(N-1回)呼び出し
④左側の枝描画処理(N-1回)呼び出し
関数の説明
コード内で使用されている関数をいくつかご紹介します。詳細は公式リファレンスをご参照ください。
- setup():
初期設定を行う関数。プログラム開始時に呼び出される。 - settings():
ほとんどのプログラムでは必要ないが、size()のパラメータに変数を指定したい場合などに使用される。 - draw():
描画処理を行う関数。setup()の直後に呼び出され、プログラムが停止されるかnoLoop()が呼び出されるまで繰り返し実行される。 - redraw():
draw()内のコードを1回実行する。 - translate(float x, float y):
指定された移動量だけオブジェクトを移動する。 - rotate(float angle):
指定された角度(ラジアン)だけ原点を中心にオブジェクトを回転する。 - pushMatrix(), popMatrix():
translate()やrotate()による変換は後続の処理にも影響するため、変換の範囲を制限したい場合にこれらの関数を用いる。現在の変換行列を保存する場合はpushMatrix()を使用し、復元する場合はpopMatrix()を使用する。 - random(float high):
[0, high)の範囲で乱数を生成する。 - random(float low, float high):
[low, high) の範囲で乱数を生成する。
サンプルコード
画面クリックで再描画、Sキー押下で画像の保存ができるようになっています。パラメータを変えて色々試してみてください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
import java.text.SimpleDateFormat; import java.util.Date; // 再帰呼び出し回数 final int RECURSIVE_CALLS = 10; // 画面サイズ final int WINDOW_WIDTH = 800; final int WINDOW_HEIGHT = 800; // 背景色 final color BACKGROUND_COLOR = color(0, 0, 0); // 先端の枝の太さ final float MIN_STROKE_WEIGHT = 1; // 枝の長さ final float MIN_BRANCH_LEN = 20; final float MAX_BRANCH_LEN = 150; // 枝の回転角度 final float MIN_ANGLE_RAD = radians(5); final float MAX_ANGLE_RAD = radians(30); // 画像保存先のパス final String DIR_PATH = sketchPath() + "\\"; // 画像のファイル名 final String IMG_NAME = "tree"; // 初期設定 void settings() { size(WINDOW_WIDTH, WINDOW_HEIGHT); } // 描画処理 void draw() { // 背景色を設定 background(BACKGROUND_COLOR); // 幹の根元に移動 translate(width / 2, height); // 枝の描画処理呼び出し drawBranch(MAX_BRANCH_LEN, RECURSIVE_CALLS); // draw処理を停止 noLoop(); } // 枝描画処理 void drawBranch(float branchLen, int n) { // 枝の色を設定 stroke(random(256), random(256), random(256)); // 枝の太さを設定 strokeWeight(MIN_STROKE_WEIGHT * (n + 1)); // 枝を描画 line(0, 0, 0, -branchLen); // 枝の先に移動 translate(0, -branchLen); if (n > 0) { // 右側の枝の描画処理呼び出し callDrawBranch(random(MIN_ANGLE_RAD, MAX_ANGLE_RAD), branchLen, n); // 左側の枝の描画処理呼び出し callDrawBranch(-random(MIN_ANGLE_RAD, MAX_ANGLE_RAD), branchLen, n); } } // drawBranch()呼び出し処理 void callDrawBranch(float angle, float branchLen, int n) { // 座標を保存 pushMatrix(); // 次の枝を描く方向に回転 rotate(angle); // 右側の枝の描画処理呼び出し drawBranch(random(MIN_BRANCH_LEN, branchLen), n - 1); // 座標を復元 popMatrix(); } // マウス押下時の処理 void mousePressed() { // 再描画 redraw(); } // キー押下時の処理 void keyPressed() { // Sキー押下で画像を保存する if (key == 's') { saveImg(); } } // 画像保存処理 void saveImg() { final SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS"); final String timestamp = sdf.format(new Date()); final String imgPath = DIR_PATH + IMG_NAME + "_" + timestamp + ".png"; save(imgPath); // コンソール出力 println("Image saved to: " + imgPath); } |
【エンジニア募集中】フルリモートも◎(リモート率85.7%)、平均残業8時間、年休124日以上、有給取得率90% etc. 詳細はこちらから>