2012年7月5日木曜日

[ドリトル] 再起呼び出しでフラクタル図形を描く

Dolittleで定義するメソッドは再起呼び出しをすることができる。
ということで早速フラクタることにする。まずはコッホ曲線
t1 = Turtle!create.
t1:koch = [
  | level width ; newWidth |
  [level <= 0 ] ! then [
     self ! (width) forward.
    ] else [
     newWidth = width / 3.
     self ! (level - 1) (newWidth) koch.
     self ! 60 leftturn.
     self ! (level - 1) (newWidth) koch.
     self ! 120 rightturn.
     self ! (level - 1) (newWidth) koch.
     self ! 60 leftturn.
     self ! (level - 1) (width - 2 * newWidth) koch.
   ] execute. 
].
t1 ! 2 500 koch.
...
t1 ! 6 500 koch.

おお。

ここでポイントになるのは
 | level width ; newWidth | の部分。

 | level width
ここまではブロックのパラメータ部分。

  ; newWidth |
ここで宣言されている変数 newWidth は、このブロック内でのみ有効なローカル変数であることを表している。この宣言を忘れるとt1オブジェクトのインスタンス変数扱いになるので、再帰呼び出し内で変数値が上書きされてしまい大変残念な結果になってしまう。
別にこのプログラムであればローカル変数なしでも書けるのけどあえて使ってみた。

次は樹木曲線。
t1 = Turtle!create.
t1:tree = [
  | level scale width |
  [level > 0 ] ! then [
     self ! (width) forward.
     self ! 30 leftturn.
     self ! (level - 1) (scale) (width * scale) tree.
     self ! 60 rightturn.
     self ! (level - 1) (scale) (width * scale) tree.
     self ! 30 leftturn.
     self ! (width) back.
   ] execute. 
].
t1 ! penup 90 rightturn 150 forward 180 rightturn pendown 1 linewidth.
t1 ! 10 0.7 100 tree.
冬虫夏草??
深さ、木の枝の短くなる比率、幹の長さがパラメータになっている。

t1 ! penup 90 rightturn 150 forward 180 rightturn pendown 1 linewidth.

この部分はいったんペン上げしてタートルを初期位置に持ってきている。Dolittleは 同一オブジェクトに対するメソッドをこのようにつなげた形で書くことができる。
まとまった処理を書くときにはなかなか便利。

次はレヴィー曲線(C曲線)
コッホ曲線は線分を三分割して三角形を挿入したが、レヴィー曲線は線分を2分割して単に「V」字型にしただけでロジックはよりシンプル。
t1 = Turtle!create.
r2 = 1.41421356.
t1:levy = [
  | level width |
  [level <= 0 ] ! then [
     self ! (width) forward.
  ] else [
     self ! 45 leftturn.
     self ! (level -1 ) (width / r2) levy.
     self ! 90 rightturn.
     self ! (level -1 ) (width / r2) levy.
     self ! 45 leftturn.
   ] execute. 
].
t1 ! penup 200 back pendown 1 linewidth.
t1 ! 15 200.0 levy.
t1 ! 5 200.0 levy.
t1 ! 15 200.0 levy.


ドラゴン曲線
レヴィー曲線と同じだが、右側の線を逆に描く。Dolittle的には後半部分はペン上げして進んでから、逆方向に描いて、再度ペン上げして進む感じになる。

t1 = Turtle!create.
r2 = 2 ! sqrt.
t1:dragon = [
  | level width ; newWidth |
  [level <= 0 ] ! then [
     self ! (width) forward.
  ] else [
     newWidth = width / r2.
     self ! 45 leftturn.
     self ! (level -1 ) (newWidth) dragon.
     self ! 90 rightturn penup (newWidth) forward 180 leftturn pendown.
     self ! (level -1 ) (newWidth) dragon.
     self ! 180 leftturn penup (newWidth) forward pendown.
     self ! 45 leftturn.
   ] execute. 
].

t1 ! penup 200 back pendown 1 linewidth.
t1 ! 14 200.0 dragon.
t1 ! 5 200.0 dragon.
t1 ! 14 200.0 dragon.

最後に、ピタゴラスの木。四角形の上に45度づつ傾けた1/√2サイズの四角形を乗せていく。左側と右側が左右対称の描き方になるので、四角形を右回りで描くのか左回りで描くのかを示すフラグ(lr、値は1または-1)を渡すようにする。

t1 = Turtle!create.
r2 = 2 ! sqrt.
t1:pythagoras = [
  | level width lr; newWidth |
  [level > 0 ] ! then [
     newWidth = width / r2.
     self ! (width) forward.
     self ! (lr * 45) leftturn.
     self ! (level -1 ) (newWidth) (lr) pythagoras.
     self ! (lr * 135) rightturn.
     self ! (width) forward.
     self ! (lr * 45) leftturn.
     self ! (level -1 ) (newWidth) (-1 * lr) pythagoras.
     self ! (lr * 135) rightturn.
     self ! (width) forward.
     self ! (lr * 90) rightturn.
     self ! (width) forward.
     self ! (lr * 90) rightturn.
   ] execute. 
].

t1 ! 1 linewidth 90 leftturn.
t1 ! 14 100.0 1 pythagoras.
t1 ! 4 100.0 1 pythagoras.
t1 ! 14 100.0 1 pythagoras.

出来上がりはほとんどレヴィー曲線に似た形になる。

0 件のコメント:

コメントを投稿