キューブ群の中を走る01

3D空間内を奥に進みながら、道の周辺にキューブを置いていきます。


int line_num;
int box_num;

float px, py, pz;
float dx, dy, dz;

float ampx, ampy, ampz;

float pn_time;

float offsetx;
float offsety;
float offsetz;

float tlx, tly, tlz;
float stx, sty, stz;
float enx, eny, enz;
float dtx, dty, dtz;

ArrayList<LineObject> lines = new ArrayList<LineObject> ();
ArrayList<BoxObject> boxes = new ArrayList<BoxObject> ();

void setup () {

	size (1920, 1080, P3D);
	colorMode (RGB, 256);
	background (200);

	line_num = 600;
	box_num = 600;

	offsetx = width / 2;
	offsety = height / 2;
	offsetz = 0.0;

	px = offsetx;
	py = offsety;
	pz = offsetz;

	ampx = 0.0;
	ampy = 0.0;
	ampz = 4000.0;

	pn_time = 0.0;

}

void draw () {

	background (200);
	
	//lights ();
	ambientLight (102, 102, 102);
	lightSpecular (204, 204, 204);
	directionalLight (102, 102, 102, 0, 0, -1);
	
	pz -= 40.0;
	px = ampz * noise (pz / 200000.0, pn_time);
	py = 0.0;

	dx = px + random (-1000, 1000);
	dy = py + random (-1000, 1000);
	dz = pz;

	pn_time += 0.01;

	lines.add (new LineObject (px, py, pz, dx, dy, dz));

	if (lines.size () > line_num) {
		lines.remove (0);
	}

	if (lines.size () > 80){

		tlx = offsetx;
		tly = offsety;
		tlz = offsetz;

		float pcamx = lines.get (lines.size () - 60).px;
		float pcamy = lines.get (lines.size () - 60).py;
		float pcamz = lines.get (lines.size () - 60).pz;

		float ncamx = lines.get (lines.size () - 20).px;
		float ncamy = lines.get (lines.size () - 20).py;
		float ncamz = lines.get (lines.size () - 20).pz;

		camera (pcamx + offsetx, pcamy + offsety - 60, pcamz + offsetz,
				ncamx + offsetx, ncamy + offsety - 60, ncamz + offsetz,
				0.0, 1.0, 1.0);

		translate (tlx, tly, tlz);

		for (int i = 0; i < lines.size () - 1; i++) {
			if (i > 0) {
				stroke (100);
				strokeWeight (1);
				stx = lines.get (i).px;
				sty = lines.get (i).py;
				stz = lines.get (i).pz;
				enx = lines.get (i - 1).px;
				eny = lines.get (i - 1).py;
				enz = lines.get (i - 1).pz;
				dtx = lines.get (i).dx;
				dty = lines.get (i).dy;
				dtz = lines.get (i).dz;
				beginShape ();
				vertex (stx - 10, sty, stz);
				vertex (enx - 10, eny, enz);
				vertex (enx + 10, eny, enz);
				vertex (stx + 10, sty, stz);
				endShape ();
			}
		}

		strokeWeight (1);

		stroke (180);
		line (-10000, -20, pz - 1000, 10000, -20, pz - 1000);
		stroke (140);
		line (-10000, 0, pz - 1000, 10000, 0, pz - 1000);
		stroke (180);
		line (-10000, 20, pz - 1000, 10000, 20, pz - 1000);

		for (int i = 0; i < 10; i++) {
			color c = color (random (256), random (256), random (256));
			boxes.add (new BoxObject (px + random (-300, 300), py + random (-300, 300), pz, 0, random (10, 60), random (10, 60), random (10, 60), c));
		}

		for (BoxObject b: boxes) {
			b.drawBox ();
		}

		if (boxes.size () > box_num) {
			for (int i = 0; i < 10; i++) {
				boxes.remove (0);
			}
		}

	}

	//saveFrame ();

}

class LineObject {

	float px, py, pz;
	float dx, dy, dz;

	LineObject (float px, float py, float pz, float dx, float dy, float dz) {

		this.px = px;
		this.py = py;
		this.pz = pz;
		this.dx = dx;
		this.dy = dy;
		this.dz = dz;

	}

}

class BoxObject {

	float alpha;

	float box_sizex;
	float box_sizey;
	float box_sizez;
	float box_locx;
	float box_locy;
	float box_locz;

	color col;

	BoxObject (float x, float y, float z, float a, float sx, float sy, float sz, color c) {

		alpha = a;

		box_sizex = sx;
		box_sizey = sy;
		box_sizez = sz;
		box_locx = x;
		box_locy = y;
		box_locz = z;

		col = c;

	}

	void drawBox () {

		alpha += 3.2;

		fill (col, alpha * 1.8);
		stroke (0, alpha);
		strokeWeight (alpha / 140);

		pushMatrix ();
		translate (box_locx, box_locy, box_locz);
		box (box_sizex, box_sizey, box_sizez);
		popMatrix ();

	}

}

並木道を走る

3D空間内を奥に進みながら、道の周辺に木を植えていきます。


int line_num;
int count;

float px, py, pz;
float dx, dy, dz;

float ampx, ampy, ampz;

float pn_time;

float offsetx;
float offsety;
float offsetz;
float offsetd;

float tlx, tly, tlz;
float stx, sty, stz;
float enx, eny, enz;
float dtx, dty, dtz;

ArrayList<LineObject> lines = new ArrayList<LineObject> ();
ArrayList<BranchGrow> trees = new ArrayList<BranchGrow> ();

void setup () {

	size (1920, 1080, P3D);
	colorMode (RGB, 256);
	background (200);

	line_num = 2000;

	offsetx = width / 2;
	offsety = height / 2;
	offsetz = 0.0;
	offsetd = -90.0;

	px = offsetx;
	py = offsety;
	pz = offsetz;

	ampx = 0.0;
	ampy = 0.0;
	ampz = 4000.0;

	pn_time = 0.0;

	count = 0;

}

void draw () {

	background (200);
	
	pz -= 40.0;
	px = ampz * noise (pz / 200000.0, pn_time);
	py = 0.0;

	dx = px + random (-1000, 1000);
	dy = py + random (-1000, 1000);
	dz = pz;

	pn_time += 0.01;

	lines.add (new LineObject (px, py, pz, dx, dy, dz));

	if (lines.size () > line_num) {
		lines.remove (0);
	}

	if (lines.size () > 80){

		tlx = offsetx;
		tly = offsety;
		tlz = offsetz;

		float pcamx = lines.get (lines.size () - 60).px;
		float pcamy = lines.get (lines.size () - 60).py;
		float pcamz = lines.get (lines.size () - 60).pz;

		float ncamx = lines.get (lines.size () - 20).px;
		float ncamy = lines.get (lines.size () - 20).py;
		float ncamz = lines.get (lines.size () - 20).pz;

		camera (pcamx + offsetx, pcamy + offsety - 60, pcamz + offsetz,
				ncamx + offsetx, ncamy + offsety - 60, ncamz + offsetz,
				0.0, 1.0, 1.0);

		translate (tlx, tly, tlz);

		for (int i = 0; i < lines.size () - 1; i++) {
			if (i > 0) {
				stroke (100);
				strokeWeight (1);
				stx = lines.get (i).px;
				sty = lines.get (i).py;
				stz = lines.get (i).pz;
				enx = lines.get (i - 1).px;
				eny = lines.get (i - 1).py;
				enz = lines.get (i - 1).pz;
				dtx = lines.get (i).dx;
				dty = lines.get (i).dy;
				dtz = lines.get (i).dz;
				beginShape ();
				vertex (stx - 10, sty, stz);
				vertex (enx - 10, eny, enz);
				vertex (enx + 10, eny, enz);
				vertex (stx + 10, sty, stz);
				endShape ();
				stroke (100);
				strokeWeight (4);
				//point (dtx, dty, dtz);
			}
		}

		strokeWeight (1);

		stroke (180);
		line (-10000, -20, pz - 1000, 10000, -20, pz - 1000);
		stroke (140);
		line (-10000, 0, pz - 1000, 10000, 0, pz - 1000);
		stroke (180);
		line (-10000, 20, pz - 1000, 10000, 20, pz - 1000);

		count += 1;

		if (count % 2 == 0) {
			trees.add (new BranchGrow (px + random (-300, 300), py, pz, 0));
		}

		for (BranchGrow b: trees) {
			b.drawTree ();
		}

		if (trees.size () > 30) {
			trees.remove (0);
		}

	}

	//saveFrame ();

}

class LineObject {

	float px, py, pz;
	float dx, dy, dz;

	LineObject (float px, float py, float pz, float dx, float dy, float dz) {

		this.px = px;
		this.py = py;
		this.pz = pz;
		this.dx = dx;
		this.dy = dy;
		this.dz = dz;

	}

}

class BranchGrow {

	int count;

	int step;

	float alpha;

	float tr_scale;
	float tr_angle;
	float tr_length;
	float tr_startd;
	float tr_startx;
	float tr_starty;
	float tr_startz;

	int[] c;
	int[] w;

	float[] nx;
	float[] ny;
	float[] nz;
	float[] px;
	float[] py;
	float[] pz;

	BranchGrow (float x, float y, float z, float a) {

		count = 0;

		step = 10;

		alpha = a;

		tr_scale = 0.98;
		tr_angle = 32.0;
		tr_length = 30.0;
		tr_startd = 0.0;
		tr_startx = x;
		tr_starty = y;
		tr_startz = z;

		c = new int[int (pow (2, step)) * 2];
		w = new int[int (pow (2, step)) * 2];

		nx = new float[int (pow (2, step)) * 2];
		ny = new float[int (pow (2, step)) * 2];
		nz = new float[int (pow (2, step)) * 2];
		px = new float[int (pow (2, step)) * 2];
		py = new float[int (pow (2, step)) * 2];
		pz = new float[int (pow (2, step)) * 2];

		createTree (tr_startx, tr_starty, tr_startz, tr_length, tr_startd, step);

	}

	void createTree (float x01, float y01, float z01, float len, float deg, int n) {

		int c = int (500 / (n + 1));
		int w = int ((n + 1) / 3);

		float x02 = x01 + len * cos (radians (deg + offsetd));
		float y02 = y01 + len * sin (radians (deg + offsetd));
		float z02 = z01 + random (-30, 30);

		savePoints (x02, y02, z02, x01, y01, z01, c, w);

		if (n > 0) {

			float deg01 = random (-tr_angle, tr_angle);
			float scl01 = random (random (10, 20), len * tr_scale);
			createTree (x02, y02, z02, scl01, deg + deg01, n - 1);

			float deg02 = random (-tr_angle, tr_angle);
			float scl02 = random (random (10, 20), len * tr_scale);
			createTree (x02, y02, z02, scl02, deg + deg02, n - 1);

		}

	}

	void savePoints (float x01, float y01, float z01, float x02, float y02, float z02, int c, int w) {

		this.c[count] = c;
		this.w[count] = w;

		nx[count] = x02;
		ny[count] = y02;
		nz[count] = z02;
		px[count] = x01;
		py[count] = y01;
		pz[count] = z01;

		count += 1;

	}

	void drawTree () {

		alpha += 3.2;

		for (int i = 0; i < count; i++) {

			stroke (c[i], alpha);
			strokeWeight (w[i]);

			line (nx[i], ny[i], nz[i], px[i], py[i], pz[i]);

		}

	}

}


アプリケーションを起動する

processingの実行中に何かのタイミングでPC内の
別のアプリケーションを起動したい場合があります。
processingの実行と同時にGoogle Chromeが
起動するようにしてみました。


import java.io.IOException;

Runtime rt;

void setup () {

	size (800, 800);

	try {
		rt = Runtime.getRuntime ();
		rt.exec ("C:/Program Files (x86)/Google/Chrome/Application/chrome.exe");
	} catch (IOException ex) {
		ex.printStackTrace ();
    }

}

void draw () {
	
}

配列のシャッフル

これが正しい方法かどうかわかりませんが、
processingで配列をシャッフルしてみました。


//ベースの配列
String[] base_arr = {"aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg"};
//シャッフルした配列
String[] rand_arr = new String[base_arr.length];
//いろいろ操作用配列
String[] temp_arr;
//乱数格納用変数
int num = 0;

for (int i = 0; i < rand_arr.length; i++) {

	//要素1個の仮配列を作成
	temp_arr = new String[1];
	//ベース配列のサイズから乱数を作成
	num = int (random (base_arr.length));

	//出来た乱数のインデックスの要素を抜き出して仮配列に入れる
	temp_arr = subset (base_arr, num, 1);
	//シャッフル配列に仮配列0番目を代入
	rand_arr[i] = temp_arr[0];
	//上2行について
	//rand_arr[i] = subset (base_arr, num, 1);
	//としたいところだが、
	//文字 = 配列(エラー)
	//となる(抜き出した要素が1個でもあくまでも配列)ので
	//一旦要素1個の仮配列に入れる

	//次にベース配列より1個少ないサイズの仮配列を作成
	temp_arr = new String[base_arr.length - 1];
	//仮インデックス用の変数
	int count = 0;
	//ベース配列のサイズ分だけループして
	for (int j = 0; j < base_arr.length; j++) {
		//先ほど出た乱数以外の要素をベース配列から抽出
		if (j != num) {
			temp_arr[count] = base_arr[j];
			count += 1;
		}
	}
	//ベース配列と要素が1個抜けた仮配列を入れ替え
	//(ベース配列はサイズが1個減り、抜き出された要素は無くなる)
	base_arr = temp_arr;
}

println (rand_arr);

PDFの書き出し

Processingではスケッチの内容をPDFとして書き出すことができます。
setup()関数でbeginRecordを実行して、保存したいところでendRecordを
実行すればいいのですが、書き出されたイメージの色がおかしくなる場合が
あります。その場合はcolorModeを設定する前にbeginrecordを実行する
ことで解消されます。


void setup () {
	size (640, 480);
	beginRecord (PDF, "test.pdf");
	colorMode (HSB, 256);
}

void draw () {
	ellipse (random (width), random (height), 10, 10);
}

void mousePressed () {
	endRecord ();
	exit ();
}

SimpleOpenNIについて

Kinectなどを制御するためのProcessing用ライブラリ「SimpleOpenNI」を使って
Mac用のアプリケーションにエクスポートしたところ、
実行すると何も画面に表示されないのでちょっと調べてみました。
どうも「SimpleOpenNI」ライブラリをそのままMacのルートディレクトリに
コピーすれば動くようです。原因は今のところ不明・・・。

2次元配列のソート

Processingで1次元配列をソートする関数は用意されているのですが、
2次元配列の2次元目のデータでソートしたかったのでちょっと調べてみました。

Comparatorインターフェースを実装したクラスを作って(その際、2次元目の
どのインデックスでソートするかを指定)、そのオブジェクトと元の配列を
Arrays.sort()に渡せばソートされました。


import java.util.*;

int[][] num = new int[10][2];

void setup () {

	size (400, 400);

	num[0][0] = 5;
	num[1][0] = 8;
	num[2][0] = 1;
	num[3][0] = 3;
	num[4][0] = 9;
	num[5][0] = 7;
	num[6][0] = 6;
	num[7][0] = 2;
	num[8][0] = 4;
	num[9][0] = 10;

	num[0][1] = 10;
	num[1][1] = 4;
	num[2][1] = 6;
	num[3][1] = 8;
	num[4][1] = 5;
	num[5][1] = 2;
	num[6][1] = 7;
	num[7][1] = 3;
	num[8][1] = 1;
	num[9][1] = 9;


	for (int i = 0; i < num.length; i++) {
		println (num[i][0], num[i][1]);
	}

	//Comparatorインターフェイスを実装したクラスを作成
	Comp comp = new Comp ();

	//2次元目のインデックス0番でソート
	comp.set_index (0);
	//Arraysクラスのsort()を実行する
	Arrays.sort (num, comp);
	//ソート後のデータを出力
	for (int i = 0; i < num.length; i++) {
		println (num[i][0], num[i][1]);
	}

	//2次元目のインデックス1番でソート
	comp.set_index (1);
	//Arraysクラスのsort()を実行する
	Arrays.sort (num, comp);
	//ソート後のデータを出力
	for (int i = 0; i < num.length; i++) {
		println (num[i][0], num[i][1]);
	}

}

void draw () {
}

class Comp implements Comparator {

	int index = 0;

	void set_index (int i) {
		index = i;
	}

	int compare (Object a, Object b) {
		int[] int_a = (int[]) a;
		int[] int_b = (int[]) b;
		return (int_a[index] - int_b[index]);
	}
	
}

端末から画像を印刷

画像を保存して、さらに印刷したいということで本来なら
Processingから直接プリンタにジョブを送りたいところですが、
ちょっと時間も無く裏技的に・・・。
プリンタがEPSONだったので以下の流れになりました。

1. Android端末にEPSONの無料プリントアプリ「EPSON iPrint」を入れる。

2. Processingから画像のシェアを要求。

3. シェアのリストから「EPSON iPrint」を選んで印刷。


import android.view.MotionEvent;
import android.content.Intent;
import android.net.Uri;
import android.os.Environment;
import android.app.Activity;

Intent intent;

void setup () {
	size (displayWidth, displayHeight, JAVA2D);
  	colorMode (RGB, 256);
	background (255);
	//Android端末のファイル保存環境を取得
	intent = new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + Environment.getExternalStorageDirectory()));
}

void draw () {
	fill (random (256), random (256), random (256));
	ellipse (random (width), random (height), 20, 20);
}

void mouseReleased () {
	//Android端末に画像を保存
	save_image ();
}

void save_image () {
	String img_name = Environment.getExternalStorageDirectory() + "/test_image.png";
	save (img_name);
	sendBroadcast (intent);
	//保存した後プリントアウト
	print_out (img_name);
}

void print_out (String img_path) {
	Intent shareIntent = new Intent (Intent.ACTION_SEND);
	shareIntent.setType ("image/png");
	shareIntent.putExtra (Intent.EXTRA_STREAM, Uri.fromFile (new File (img_path)));
	startActivity (shareIntent);
}

端末に画像を保存

かなり久しぶりの投稿です。

最近Android端末で動くドローイングツールをProcessingで作って、
描いた絵を端末のギャラリーに保存する方法を調べてみたのでまとめてみました。


import android.view.MotionEvent;
import android.content.Intent;
import android.net.Uri;
import android.os.Environment;
import android.app.Activity;

Intent intent;

void setup () {
	size (displayWidth, displayHeight, JAVA2D);
  	colorMode (RGB, 256);
	background (255);
	//Android端末のファイル保存環境を取得
	intent = new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + Environment.getExternalStorageDirectory()));
}

void draw () {
	fill (random (256), random (256), random (256));
	ellipse (random (width), random (height), 20, 20);
}

void mouseReleased () {
	String img_name = Environment.getExternalStorageDirectory() + "/test_image.png";
	save (img_name);
	sendBroadcast (intent);
}

セル・オートマトン

20150529

2次元のセル・オートマトンは、画面上を格子状に分割し、各セルが隣接する8つの
セルの状態によって自分の状態を変化させるという最もシンプルな自律エージェントの
システムです。隣接するセルのどういう状態によって、自分がどう変化するかは、
与える条件によって様々です。最も有名なのはライフゲーム。


Cell[][] cell_array;
int cell_size = 10;;
int numx, numy;

void setup () {

	size (800, 600);
	numx = floor (width / cell_size);
	numy = floor (height / cell_size);

	restart ();

}

void restart () {

	cell_array = new Cell[numx][numy];

	for (int x = 0; x < numx; x++) {
		for (int y = 0; y < numy; y++) {
			Cell new_cell = new Cell (x, y);
			cell_array[x][y] = new_cell;
		}
	}

	for (int x = 0; x < numx; x++) {
		for (int y = 0; y < numy; y++) {
			int above = y - 1;
			int below = y + 1;
			int left = x - 1;
			int right = x + 1;
			if (above < 0) {
				above = numy - 1;
			}
			if (below == numy) {
				below = 0;
			}
			if (left < 0) {
				left = numx - 1;
			}
			if (right == numx) {
				right = 0;
			}
			cell_array[x][y].addNeighbour (cell_array[left][above]);
			cell_array[x][y].addNeighbour (cell_array[left][y]);
			cell_array[x][y].addNeighbour (cell_array[left][below]);
			cell_array[x][y].addNeighbour (cell_array[x][below]);
			cell_array[x][y].addNeighbour (cell_array[right][below]);
			cell_array[x][y].addNeighbour (cell_array[right][y]);
			cell_array[x][y].addNeighbour (cell_array[right][above]);
			cell_array[x][y].addNeighbour (cell_array[x][above]);
		}
	}

}

void draw () {

	background (200);

	for (int x = 0; x < numx; x++) {
		for (int y = 0; y < numy; y++) {
			cell_array[x][y].calcNextState ();
		}
	}

	translate (cell_size / 2, cell_size / 2);

	for (int x = 0; x < numx; x++) {
		for (int y = 0; y < numy; y++) {
			cell_array[x][y].drawMe ();
		}
	}

}

void mousePressed () {

	restart ();

}

class Cell {

	float x, y;
	boolean state;
	boolean nextState;
	Cell[] neighbors;

	Cell (float ex, float why) {

		x = ex * cell_size;
		y = why * cell_size;

		if (random (2) > 1) {
			nextState = true;
		} else {
			nextState = false;
		}
		state = nextState;
		neighbors = new Cell[0];

	}

	void addNeighbour (Cell cell) {

		neighbors = (Cell[])append (neighbors, cell);

	}

	void calcNextState () {

		int liveCount = 0;

		for (int i = 0; i < neighbors.length; i++) {
			if (neighbors[i].state == true) {
				liveCount++;
			}
		}

		if (state == true) {
			if (liveCount == 2 || liveCount == 3) {
				nextState = true;
			} else {
				nextState = false;
			}
		} else {
			if (liveCount == 3) {
				nextState = true;
			} else {
				nextState = false;
			}
		}

	}

	void drawMe () {

		state = nextState;
		stroke (0);
		if (state == true) {
			fill (0);
		} else {
			fill (255);
		}
		ellipse (x, y, cell_size, cell_size);

	}

}