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

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);

	}

}

Arduinoテスト02

前回のArduinoの続きです。光センサーの光の量をsin波の振幅にマッピングして
音を鳴らしてみました。ちょっとテルミン風になりました。

Arduino側


#define NUM 1

int sensors[NUM];
int in_txt;

void setup () {
  Serial.begin (9600);
  for (int i = 0; i < NUM; i++) {
    sensors[i] = 0;
  }
  in_txt = 0;
  establishContact ();
}

void loop () {
  if (Serial.available () > 0) {
    in_txt = Serial.read ();
    for (int i = 0; i < NUM; i++) {
      sensors[i] = analogRead (i);
      Serial.print (sensors[i]);
      if (i < NUM - 1) {
        Serial.print (",");
      } else {
        Serial.print ('\n');
      }
    }
  }
}

void establishContact () {
  while (Serial.available () <= 0) {
    Serial.println ("0,0");
    delay (300);
  }
}

PC側


import processing.serial.*;
import ddf.minim.*;
import ddf.minim.signals.*;

int NUM = 1;
int count;
int[] sensors = new int[NUM];

Serial port;

color[] colors = new color[6];

Minim minim;
AudioOutput out;
SineWave sine;

float tx, ty;
float px, py;

float freq;

ArrayList<PGraphics> text_pg = new ArrayList<PGraphics> ();
ArrayList<PGraphics> line_pg = new ArrayList<PGraphics> ();

void setup() {
  size (800, 400);

  for (int i = 0; i < Serial.list ().length; i++) {
  	println (Serial.list ()[i]);
  }

  port = new Serial (this, Serial.list ()[5], 9600);
  port.bufferUntil ('\n');

  tx = 0;
  ty = height;
  px = 0;
  py = height;

  for (int i = 0; i < NUM; i++) {
  	text_pg.add (createGraphics (width, height));
  	line_pg.add (createGraphics (width, height));
  }

  init_graph ();

  minim = new Minim (this);
  out = minim.getLineOut (minim.STEREO);
  sine = new SineWave (440, 0.5, out.sampleRate ());
  out.addSignal (sine);
}

void draw () {
	//background (0);

	for (int i = 0; i < NUM; i++) {
		tx = map (count, 0, width, 0, width);
		ty = map (sensors[i] * sensors[i], 0, 1046529, height, 0);

		text_pg.get (i).beginDraw ();
		text_pg.get (i).background (47);
		for (int j = 20; j < height; j += 20) {
			text_pg.get (i).beginDraw ();
			text_pg.get (i).stroke (70);
			text_pg.get (i).line (0, j, width, j);
			text_pg.get (i).endDraw ();
		}
		text_pg.get (i).fill (100);
		text_pg.get (i).text ("intensity = 1024", 10, 20);
		text_pg.get (i).text ("intensity = 512", 10, 200);
		text_pg.get (i).text ("intensity = 0", 10, 380);
		text_pg.get (i).fill (255);
		text_pg.get (i).text ("intensity = " + sensors[i], tx + 8, ty + 4);
		text_pg.get (i).endDraw ();
		image (text_pg.get (i), 0, 0);

		line_pg.get (i).beginDraw ();
		line_pg.get (i).stroke (colors[i]);
		line_pg.get (i).line (tx, ty, px, py);
		line_pg.get (i).endDraw ();
		image (line_pg.get (i), 0, 0);

		px = tx;
		py = ty;

		freq = ty * 4;
	}
	if (count > width) {
		px = 0;
  		py = ty;
		init_graph ();
	}

	sine.setFreq (freq);

	count++;

}

void init_graph () {
	for (int i = 0; i < NUM; i++) {
		line_pg.get (i).clear ();
	}

	count = 0;

	colors[0] = color (255, 127, 31);
	colors[1] = color (31, 255, 127);
	colors[2] = color (127, 31, 255);
	colors[3] = color (31, 127, 255);
	colors[4] = color (127, 255, 31);
	colors[5] = color (127);
}

void serialEvent (Serial port) {
	String st = port.readStringUntil ('\n');

	st = trim (st);

	sensors = int (split (st, ','));

	port.write("A");
}

Arduinoテスト01

久しぶりにArduinoで遊んでみました。ボードに光りセンサーと抵抗器を指して、
光の量による電圧の変化をアナログ信号で捉えます。

光の量を円の大きさにマッピングするとこんな感じです。

Arduino側は、デフォルトで用意されている「Standart Firmata」を書き込み。
Processing側は「Arduino(Firmata)」ライブラリをインポート。


import processing.serial.*;
import cc.arduino.*;

Arduino arduino;

int input = 0;
int led_pin = 9;
 
void setup() {
  size (400, 400);
  arduino = new Arduino (this, Arduino.list ()[2], 57600);
  arduino.pinMode (led_pin, Arduino.OUTPUT);
}

void draw () {
	background (0);
	fill (255);

	int analog = arduino.analogRead (input);

	arduino.analogWrite (led_pin, int (map (analog, 0, 1023, 255, 0)));

	text ("input = " + analog, 10, 20);
	ellipseMode (CENTER);
	ellipse (200, 200, analog / 4, analog / 4);
}