- 2008-06-21 (土)
- library/systems
L-system(Lindenmayer system)は、成長過程をモデルする為に使用される、ルールとシンボルのセットである。
http://en.wikipedia.org/wiki/L-system
L-systemは自然では再帰的(recursive in nature)である。これは、全体が「全体と同様な小さなパーツ」で作られることを意味する。
例えば、一本の木は、小さな枝の成長からできた大きな枝だと言える。
それぞれの小さな枝はまた成長し、小さな枝をつけたりする。
一つの枝がどのようになるかを知っていれば、我々は木全体をモデルすることが出来る。
また、再帰ルールに基ずくエレガントは環境は、ContextFreeを見よ。
http://www.contextfreeart.org/
NodeBoxのL-systemライブラリは再帰とルールセットにより簡単に動作する。
Frederik De Bleser と Mark Meyer によるコードを基にしている。
(ギャラリーにあるDryadとMark Meyer's L-systemを見よ。)
http://www.nodebox.net/code/index.php/Dryad
http://www.nodebox.net/code/index.php/Mark_Meyer_|_L-system
Download
略
Documentation
How to get the library up and running
NodeBoxのスクリプトが探すことが出来るように、lsystemライブラリフォルダをスクリプトと同じフォルダに入れる。
また、~/Library/Application Support/NodeBox/に置くことも出来る。
lsystem = ximport("lsystem")
Creating a new L-system
create(angle=20, segmentlength=40, rules={}, root=None)
create()コマンドは新しいL-systemオブジェクトを返す。オブジェクトは与えられたx, yポジションからキャンバス上を育つ。
オブジェクトはプロパティを持つ。
- lsystem.angle: +と-ルール シンボルに使用される回転のアングル
- lsystem.segmentlength: 単セグメントの長さ、もしくはサイズ
- lsystem.decrease: システムの成長におけるセグメントの減少量(0.7 がデフォルト)
- lsystem.threshold: この値より小さくなった場合にセグメントの描画を停止する(3.0 がデフォルト)
- lsystem.root: 成長の為の最初のルール (ルール key "1" がデフォルト)
- lsystem.rules: DNAシステムの辞書のルール
- lsystem.commands: カスタムコマンド シンボルの辞書
- lsystem.cost: 単セグメントの描画にかかる時間 (0.25 がデフォルト)
L-systemオブジェクトは描画の為の2つのメソッドを持つ。
lsystem.draw(x, y, generation, time=None, ease=None)
lsystem.segment(length, generation, time=None, id=None)
lsystem.draw()メソッドは与えられた位置での成長パターンを描画する。
generation(世代)パラメータは、どれだけ深くパターンが続くかを決定する。
我々の「木は大きな枝である」の例題では、世代 3 は以下を意味する。:
一本の枝(1)を描き、枝(1)を伸ばしたものが、全て育成し枝々(3)になる。
たくさんのセグメントが世代が終るまで、もしくはlsystem.thresholdより小くなるまで育成する。
timeパラメータはアニメーション内で使用出来る。
セグメントが描画されると、lsystem.costと等しい少しの時間を少しずつ崩す。
アニメーション内でゼロからtimeが始まり、徐々に増大すると、セグメントはより大きくなり、それらのより大きなものは描画される。
(costを支払うより多くのtimeがあるので)
2番目のオプションパラメータ easeはアングルの回転を進展させる為に使用出来る。
通常は4から20の数値で、つぼみが開く(unfold)成長パターンを使用できる。
lsystem.segment()メソッドは単セグメントを描画するためのコードを含む。
あなた自身が(葉のような)カスタムセグメントを欲しい時、このメソッドを再定義する必要がある。
後に書くであろう。
lsystem.segments(generation, time=None)
lsystem.duration(generation)
lsystem.segments()メソッドは与えられた世代数(そして時間)を育てる為のセグメントの数を返す。
lsystem.duration()全てのセグメントを描画するのに必要なトータルの時間を計算する。
現在のlsystem.costを基にする。
Growing rules
L-systemの形は、ルールの設定に依存する。
ルールは事前定義されたsymbolsの文字列であり、それぞれが変化コマンドを表す。(scale()やrotate()のように)
それで、一つのルールはNodeBoxコードの断片を表すDNAストリングのような小片である。
以下全てのシンボルである。:
- F : systemがここにセグメントを描画する(矩形がデフォルト)
- f : 描画せずに次のポジションへ移動する
- + : lsystem.angleにより反時計回りに回転する
- _ : lsystem.angleにより時計回りに回転する
- | : 180度回転する
- [ : push()コマンドのように動作する。サブブランチの開始
- ] : pop()コマンドのように動作する。サブブランチの終了
- ! : 回転アングルを反転する
- ( : 回転アングルを110%増加する
- ) : 回転アングルを90%に減少する
- < : セグメントの長さを110%増加
- > : セグメントの長さを90%減少
いくつかsymbolを試してみよう!
ルールはシンプルだ:
3つのセグメントを描画する。
tree = lsystem.create()
tree.rules["1"] = "FFF"
tree.draw(50, 150, 1)
2つのセグメントを描画し、時計回りに回転させ、別のセグメントを描画する。
tree = lsystem.create()
tree.rules["1"] = "FF-F"
tree.draw(50, 150, 1)
ルール:( 2つのセグメントを描画し、時計回りに回転する)を描画する。
我々がより多くの世代において生産出来るようにシンボル文字列からルールのキーを参照するように注意せよ。
これが再帰の典型的な例である。
http://en.wikipedia.org/wiki/Recursion
tree = lsystem.create()
tree.rules["1"] = "FF-1"
tree.draw(50, 150, 6)
再帰のポイントで枝が生成され、反時計回りに回転し、セグメントを描画、反時計回りに回転、別のセグメントを描画。
tree = lsystem.create()
tree.rules["1"] = "FF-[1]++F+F"
tree.draw(50, 150, 6)
枝でより多く再帰する
tree = lsystem.create()
tree.rules["1"] = "FF-[1]++F+F+1"
tree.draw(50, 150, 6)
独立した枝々でより複雑なルールセット
tree = lsystem.create(segmentlength=20) tree.rules = { "1" : "FF[-2]3[+3]", "2" : "FF+F-F-F[FFF3][+3]-F-F3", "3" : "FF-F+F+F[2][-2]+F+F2" } tree.draw(50, 150, 6)
Custom segments
デフォルトでは、systemはセグメントの為に線により結合された矩形である。
新しい外観を得るために、自分でセグメントコマンドを書かなければならない。
デフォルトのセグメントコマンドはこのようになる。:
def segment(self, length, generation, time=None, id=None):
push()
line(0, 0, 0, -length)
scale(0.65)
rect(-length/2, -length, length, length)
pop()
L-systemは、セグメントからセグメントへ移動する為にcorner-mode translate()コマンドを使う。
つづく