ラベル proce55ing の投稿を表示しています。 すべての投稿を表示
ラベル proce55ing の投稿を表示しています。 すべての投稿を表示

2009/10/07

(追記)郵便局で作る日本全国の光の地図

これは前回の記事
住所一覧からマックと吉野家の光の地図を作ってみた
の続きです。今回はデータとして、郵便局の住所一覧を用いました。
また、データは『全国郵便局名一覧』からダウンロードしました。ありがとうございます。


















当たり前ですけど、郵便局はやっぱり多いですね。解析にまる3,4日くらいかかったような気がします。
しかも日本全国に散らばっているあたり、郵政事業がいかに重要なのか思い知らされます。

2009/10/04

住所一覧からマックと吉野家の光の地図を作ってみた

おひさしぶりです。

お久しぶりです。どうやら巷ではアクセスアップのコツとして「内容よりも一日の更新頻度を上げたほうが人気が出る」らしいですが、ここはそんなこと全く気にせずにのんびりと更新していきます。(かと言って質が高いかと言えば疑問ですが…)

さて、更新してみようと思い立ったきっかけはこんな記事からでした。
「マックまでの近さ」が光で表された米国地図 | WIRED JAPAN
この地図を作成したのは、Steven Von Worley氏。ロサンゼルス盆地の、本当に何もないようなところで目にしたマクドナルドに刺激されてこの地図の作成を思い立ったという。
で、ブックマークのコメントを見たらこんなものが。
はてなブックマーク - 「マックまでの近さ」が光で表された米国地図 | WIRED VISION
Layzie food, ネタ 東と西でクッキリ分れてるねえ。誰か、日本で「吉野家」バージョンで作らないだろうか。
やってみようじゃないの。

というわけでちょっとした思いつきで吉野家地図の日本版を作ってみました。ちなみに本家ではきちんと距離を計算してそこからの最短距離で色を作っているらしいですが、そんなことしても面倒くさい割にそんな役に立たないので単純な加算処理にしてあります。

工程は後述するとして、画像は以下。

これが吉野家の光…

東京や大阪、京都の大都市は吉野家が密集していることが伺えます。また各種国道や高速自動車道をなぞるように点在しているようですね(*1)。しかし海岸沿いなどにはほとんどなく、東北地方、特に札幌を除く北海道は悲惨です。これが地方格差ってやつか。

ついでにマクドナルドの地図も作って見ました。結果の画像は以下。

やっぱり吉野家と比べると明るいですね。でも吉野家の光の密度が多くなったような感じで、全体的な傾向としてはあまり変わらないような気がします。
ちなみに2つとも画像映えを良くするために少しのグロー効果も入れてあります。

メイキング

作った流れとしては以下のような感じです。
  1. まずマックのすべての店舗の住所一覧を取得する。
  2. 住所から経度と緯度のペアに変換する。
  3. Proce55ingにデータを読み込ませ、パーティクルとして処理する。
店舗一覧はマックの場合は47都道府県すべてを検索し、電話番号などの不要なデータを消去し住所だけを抜き出すpythonスクリプトを組んで対応。吉野家は件数が少ないのでコピペと手動で対応しました。

住所から経度、緯度のペアに変換する手順では、今回はGoogleのウェブAPIサービスを利用しました。住所のデータを投げればXML形式で返ってくるので、ペアから経度と緯度部分だけを抜きだし、csv形式で保存するスクリプトを組みました(*2)。

最後にProce55ingを用いてデータを読み込ませ、経度、緯度を単なるXY座標のデータとして処理させました。ただし、座標軸の違いによりこのままでは日本が上下反対になってしまうので、単純に-1をかけて反転させてあります。
あとは見やすいように座標変換を行って、完成です。

ソースコード

今回のスクリプトをcodereposのリポジトリ上にアップしました。
svn checkout http://svn.coderepos.org/share/lang/java/misc/light
でチェックアウトしてください。

外部ライブラリに依存していないので単純にproce55ingを使えば動くと思います。ついでにpythonスクリプトも同様にアップしてみました(trans.py)。参考までに。
ちなみに使い方ですが、座標が書いてあるCSVファイルを指定した後はProce55ing側が勝手に読み取ってプロットしてくれます。

ドラッグで見たい場所を移動できます(Google Mapsと同じ)。
'f'キーでズームイン、'g'キーでズームアウトを行います。マウスポインタを中心としてズームを行います。
'j'キーでパーティクルサイズを大きく、'h'キーでパーティクルサイズを小さくします。
's'キーでフレームを保存します。

(ズームして分かる、東京都のマックの様子)

'b'キーで日本地図(Thanks http://www.freemap.jp/)をバックに表示します。

まぁ、おまけ機能です。なんで位置合わせしないかというと、そこまでするときちんと経度、緯度を座標変換しなきゃなんなくて面倒だからです。

終わりに

作業時間としては大体3日間くらいかかりました。そんなに難しくありませんが、いろんな知識が複合的に絡んでいたのでそれなりに面白かったです。
ちなみに、郵便局バージョンでも作れないかと今住所一覧を経度、緯度に変換しているんですがこれ3万件くらいあってすごい時間かかるんですよね…現在2日間くらい回してるんですがまだ1万件しか処理できていません。できたらちゃんと報告します。

*1 個人的に、国道にはよく吉野家が点在しているイメージがあります。
*2 もちろんこのままではサーバに過負荷(単なるDoS攻撃になってしまう)がかかってしまうので5秒のスリープを入れてあります。

追記
typo ×吉野屋 ○吉野家 

2008/09/12

Flight404のソースコードを読み解く part4


パーティクルを放出させる

旅行から帰ってきましたので、ようやっと更新することができました。まだまだ飽きてはいませんよ。
前回はエミッタを放出させるところまで行ったので、今回はパーティクルを等速で放出させるところまでやっていきます。

今回のソースは以下。相変わらず_gl.pdeは変わっていないので省略。新しくparticle.pdeを加えました。

Particle3.pde(draw()の関数だけ変更されているので、その部分だけ記載。)

void draw(){
background( 0.0 );
perspective( PI/3.0, (float)width/(float)height, 1, 5000 );

gl.glDepthMask(false);
gl.glEnable( GL.GL_BLEND );
gl.glBlendFunc( GL.GL_SRC_ALPHA, GL.GL_ONE );

pgl.beginGL();
emitter.exist();
pgl.endGL();

if( mousePressed ){
emitter.addParticles(20);
}

}

emitter.pde

class Emitter {
Vec3D loc;
Vec3D vel;
Vec3D velToMouse;

color myColor;

ArrayList particles;

Emitter(){
loc = new Vec3D();
vel = new Vec3D();
velToMouse = new Vec3D();

myColor = color( 1, 1, 1 );

particles = new ArrayList();
}

void exist(){
setVelToMouse();
findVelocity();
setPosition();

//rendering Emitter
gl.glEnable( GL.GL_TEXTURE_2D ); //Enable texture mapping
iterateListExist();
render();
gl.glDisable( GL.GL_TEXTURE_2D );
}

void setVelToMouse(){
velToMouse.set( mouseX - loc.x, mouseY - loc.y, 0 );
}

void findVelocity(){
vel.interpolateToSelf( velToMouse, 0.2 );
}

void setPosition(){
loc.addSelf( vel );
}

void iterateListExist(){
pgl.bindTexture( particleImg );

for( Iterator it = particles.iterator(); it.hasNext(); ){
Particle p = (Particle)it.next();
if(!p.ISDEAD){
p.exist();
} else {
it.remove();
}
}
}

void render(){
pgl.bindTexture( emitterImg );
renderImage( loc, 200, myColor, 1.0 );
}

void addParticles( int _amt ){
for( int i=0; i<_amt; i++ ){
particles.add( new Particle( loc, vel) );
}
}
}

particle.pde

class Particle {
int len;
Vec3D[] loc;
Vec3D startLoc;
Vec3D vel;

float radius;
float age;
int lifeSpan;
float agePer;
boolean ISDEAD;

Particle( Vec3D _loc, Vec3D _vel ){
radius = random( 20, 60 );
len = (int)radius;
loc = new Vec3D[len];

startLoc = new Vec3D( _loc.add( new Vec3D().randomVector().scaleSelf( random(5.0) ) ) );

for( int i=0; i
loc[i] = new Vec3D( startLoc );
}

vel = new Vec3D( _vel.scale( 0.5 ).addSelf( new Vec3D().randomVector().scaleSelf( random( 10.0 ) ) ) );

age = 0;
lifeSpan = (int)radius;
agePer = 1.0;
}

void exist(){
setPosition();
render();
setAge();
}

void setPosition(){
for ( int i=len-1; i>0; i-- ){
loc[i].set(loc[i-1]);
}
loc[0].addSelf( vel );
}

void render(){
color c = color( agePer, agePer*0.75, 1.0 - agePer );
renderImage( loc[0], radius*agePer, c, 1.0 );
}

void setAge(){
age++;

if( age > lifeSpan ){
ISDEAD = true;
}else{
agePer = 1.0 - age/(float)lifeSpan;
}
}
}

emitter.pdeの中で特に注目すべきなのは、iterateListExist()の追加。これによって各パーティクルのレンダリング処理を行い、死んだパーティクルをリストから除外している。

particle.pde の中で特によくわかんなかったのが、loc[]の存在について。別に1個だけでいいじゃんと思っていたが、これは後に尻尾というか、パーティクルの軌跡を描画するために使うようだ。loc[0]に一番最新のパーティクルの位置が格納されていて、時が経つごとに順次入れ替えを行っている。

次によくわかんないというか、感覚的じゃないなと思ったのが、new Vec3D( _loc.add( new Vec3D().randomVector().scaleSelf( random(5.0) ) ) )などのベクトル処理。
randomVector() はベクトルをランダムな単位ベクトルに変更するメソッドで、いろいろと便利。scaleSelf()は文字通り、ベクトルを拡大したり縮小したりするメソッド。この返り値を_locベクトルに加算させていることは理解できるのだが、いかんせん感覚的じゃないのが困り者。vec1+vec2とか出来れば理解しやすいのにとか思うけど、javaは演算子のオーバーロードをサポートしていないから仕様がないのか。

2008/09/03

Flight404のソースコードを読み解く part3

エミッタを表示させる

前回は前準備の段階で終わったので、次はパーティクルを放出させるエミッタを表示してみる。エミッタはマウスに追随するようにばね運動をする。_gl.pdeは前回と変わっていないので省略する。コードは以下。

Particle2.pde

import toxi.geom.*;
import processing.opengl.*;
import javax.media.opengl.*;

// Settings about OPENGL
PGraphicsOpenGL pgl;
GL gl;

// Settings about Emitter
Emitter emitter;

// Settings about images
PImage particleImg;
PImage emitterImg;

void setup(){
size( 600, 600, OPENGL );
colorMode( RGB, 1.0);

hint( ENABLE_OPENGL_4X_SMOOTH );

pgl = (PGraphicsOpenGL) g;
gl = pgl.gl;
gl.setSwapInterval(1);

initGL();

particleImg = loadImage( "particle.png" );
emitterImg = loadImage( "emitter.png");

emitter = new Emitter();
}

void draw(){
background( 0.0 );
perspective( PI/3.0, (float)width/(float)height, 1, 5000 );

gl.glDepthMask(false);
gl.glEnable( GL.GL_BLEND );
gl.glBlendFunc( GL.GL_SRC_ALPHA, GL.GL_ONE );

pgl.beginGL();
emitter.exist();
pgl.endGL();
}

emitter.pde

class Emitter {
Vec3D loc;
Vec3D vel;
Vec3D velToMouse;

color myColor;

Emitter(){
loc = new Vec3D();
vel = new Vec3D();
velToMouse = new Vec3D();

myColor = color( 1, 1, 1 );
}

void exist(){
setVelToMouse();
findVelocity();
setPosition();

//rendering Emitter
gl.glEnable( GL.GL_TEXTURE_2D ); //Enable texture mapping
render();
gl.glDisable( GL.GL_TEXTURE_2D );
}

void setVelToMouse(){
velToMouse.set( mouseX - loc.x, mouseY - loc.y, 0 );
}

void findVelocity(){
vel.interpolateToSelf( velToMouse, 0.2 );
}

void setPosition(){
loc.addSelf( vel );
}

void render(){
pgl.bindTexture( emitterImg );
renderImage( loc, 200, myColor, 1.0 );
}
}

Particle2.pdeについては、Emitterクラスと画像の初期化、並びにemitter.exist()メソッドを付け加えただけ。主な処理はemitter.pdeで行っている。

実際のレンダリングはrender()が担当している。まずbindTexture()で貼り付けるテクスチャを指定して、_gl.pdeで定義したrenderImage()で描画している。その他のメソッドではエミッタの位置をマウスに追随させるようにしている。

interpolateToSelf()はtoxi.geom.Vec3Dで定義されている、自身のベクトルを他のベクトルに置き換えるメソッド。要はvelToMouseを0.2倍したベクトルに置き換えているだけ。この処理によって、エミッタはマウスの周辺でばね運動のような動きをする。

おーし次からが本番だ。

2008/09/02

Flight404のソースコードを読み解く part2

何も表示されないアプリケーションを作る

Flight404のサンプルではOpenGLを使用して平面に別途用意したパーティクルの画像を貼り付けて、表示するという手法をとっている。そのためP3Dと比べて、非常に高速で高精度な3D画像を描画できるのだが、その分生のOpenGLを叩かないといけないため、コードはいささか面倒になってくる。そこでとりあえずソースコードの中から何も表示されないアプリケーションを作って、コードの流れについて調べてみることにした。コードは以下。

particle1.pde

import toxi.geom.*;
import processing.opengl.*;
import javax.media.opengl.*;

// Settings about OPENGL
PGraphicsOpenGL pgl;
GL gl;

// Settings about some functions

void setup(){
size( 600, 600, OPENGL );
colorMode( RGB, 1.0);

hint( ENABLE_OPENGL_4X_SMOOTH );

pgl = (PGraphicsOpenGL) g;
gl = pgl.gl;
gl.setSwapInterval(1);

initGL();
}

void draw(){
background( 0.0 );
perspective( PI/3.0, (float)width/(float)height, 1, 5000 );

gl.glDepthMask(false);
gl.glEnable( GL.GL_BLEND );
gl.glBlendFunc( GL.GL_SRC_ALPHA, GL.GL_ONE );

pgl.beginGL();
// write something...
pgl.endGL();
}

_gl.pde

int squareList;

void initGL(){
pgl.beginGL();
squareList = gl.glGenLists(1);
gl.glNewList(squareList, GL.GL_COMPILE);
gl.glBegin(GL.GL_POLYGON);
gl.glTexCoord2f(0, 0); gl.glVertex2f(-0.5, -0.5);
gl.glTexCoord2f(1, 0); gl.glVertex2f( 0.5, -0.5);
gl.glTexCoord2f(1, 1); gl.glVertex2f( 0.5, 0.5);
gl.glTexCoord2f(0, 1); gl.glVertex2f(-0.5, 0.5);
gl.glEnd();
gl.glEndList();
pgl.endGL();
}

void renderImage( Vec3D _loc, float _diam, color _col, float _alpha){
gl.glPushMatrix();
gl.glTranslatef( _loc.x, _loc.y, _loc.z );
gl.glScalef( _diam, _diam, _diam );
gl.glColor4f( red(_col), green(_col), blue(_col), _alpha );
gl.glCallList( squareList );
gl.glPopMatrix();
}

まずhint( ENABLE_OPENGL_4X_SMOOTH )を指定して、4xのオーバーサンプリングを許可。setSwapInterval()については、主に画面がちらつく現象を防ぐ目的のようだ。その後initGL()を呼び出して、_gl.pdeで書いたOpenGL周辺のセットアップを開始する。

initGL()では、正方形のポリゴンを作って画像を貼り付けるという作業が何回も繰り返されるので、ディスプレイリストの機能を利用する。テクスチャのUV座標と頂点をそれぞれglTexCoord2fとgl.glVertex2fで指定して、正方形を描画している。

renderImage()で実際に画像の描画を行う。glPushMatrix()とglPopMatrix()で行列スタックを取得、開放し、その間に平行移動やスケールをもってくることで、ローカル座標が狂わないようにしているようだ。

次にdraw()の項を見てみる。glDepthMask(false)で陰線消去を行わないようにして、glBlendFunc( GL.GL_SRC_ALPHA, GL.GL_ONE )で画像の加算処理を指定している。そしてbeginGL()とendGL()の間にOpenGLの描画命令を組み込むことで、実際にOpenGLで描画処理が行われるようになるという次第。

Flight404のソースコードを読み解く part1

概要

Processing(Proce55ing)界で知らない人は皆無と言われる(と勝手に思っている)Flight404のRobert Hodgin。とりあえず彼のことについて説明しますと、こんな感じの映像をProcessingで作ってしまうような人です↓

Weird Fishes: Arpeggi from flight404 on Vimeo.
(悔しいことに、ルックスもイケメンだ!)

で、実は彼はブログで「簡単」な(彼にとっては簡単なだけで他の人にとっては難しいです)Proce55ingのソースコードを公開しています。が、ワールドワイドではともかく、日本語のブログで彼のコードについて言及しているサイトやブログが全くない。それで自分の丁度いい勉強にもなりますんで、適当にFlight404SRC: Particle Emitterで気づいたことを書き留めておくことにします。

もしかしたら飽きて、中途半端なところでやめるかもしれませんが、とりあえずそんときはそんときで。てきとーにやっていきます。

2008/08/30

Processing(Proce55ing)と流体力学


タイトルほどそんな大層なことはしていないんですが、Proce55ingと流体力学を使用して、川のような流れの中にまるーい物体を入れたときの水流の動きをアートっぽく可視化してみました。結構綺麗な模様ができて、自分としては満足です。

左から右に水が流れているもんだと思ってください。こんな感じに水流は円柱を避けて進んでいきます。

今度は円柱が時計回りに回転して、渦が発生しているようなときの水流の流れ。この渦の流れが強くなっていくと…

こんな感じにどんどんねじ曲がっていって…

最終的にはこんなかんじの、歪んだ水流になってしまいました。
本当は上の画像、アニメーションしてもっと面白い感じの映像になるんですけど、動画のキャプチャの仕方が分からないのでとりあえず画像だけ。

コードはhTakaさんのStreamDrawingの速度場を流体力学のに書き換えただけですし、しかもめっちゃ汚いのでとりあえず非公開です。興味のある方はそちらのコードを参照してください。hTakaさん、どうも有難う御座います。

それにしてもProce55ingはぱぱぱっといろんなことが出来て面白いです。なんかこれ使ってもっと有り得ないような映像できないかな。