2012年8月15日水曜日

[ドリトル] 放物線の反射

放物線を描いてみよう。y=x

VALUE_RANGE = 5.  // x = -5 to + 5
RESOLUTION = 100.
DRAW_SCALE = 200.
OFFSET_Y = -200.

t1 = Turtle ! create.
t1 ! 1 linewidth (blue) linecolor.
t1 ! penup.
[ | n ; x y |
  x = (n - RESOLUTION / 2) / RESOLUTION * VALUE_RANGE. 
  y = x * x.
  t1 ! (DRAW_SCALE * x) (DRAW_SCALE * y + OFFSET_Y) moveto.
  t1 ! pendown.
  t1 ! makeFigure.
] ! (RESOLUTION) repeat.

放物線に平行線を反射させると焦点に集まる。
ということでタートルを反射させてみる。

上のプログラムでわざわざ1ステップごとに makeFigure していたのは実はこのため。
反射の精度を上げるために 0.1 scale をしておく。

VALUE_RANGE = 5.  // x = -5 to + 5
RESOLUTION = 300.
DRAW_SCALE = 200.
OFFSET_Y = -200.

t1 = Turtle ! create.
t1 ! 1 linewidth (blue) linecolor.
t1 ! penup.
[ | n ; x y |
  x = (n - RESOLUTION / 2) / RESOLUTION * VALUE_RANGE. 
  y = x * x.
  t1 ! (DRAW_SCALE * x) (DRAW_SCALE * y + OFFSET_Y) moveto.
  t1 ! pendown.
  t1 ! makeFigure.
] ! (RESOLUTION) repeat.

t1 ! (red) lineColor 0.1 scale.
t1:collision = t1:bounce.

[ | n ; x | 
  x = (n-11) * 25.
  t1 ! penup (x) 200 moveto pendown.
  t1 ! 270 direction.
  [ t1 ! 1 forward. ] ! 450 repeat.
] ! 21 repeat.

確かに焦点に集まった。
反射する際に放物線の精度が低いとうまく集まらないので今回は300分割して描いてある。
運が悪いと変な跳ね返りをすることもあるのでその場合には分割数を少し変えるとうまくいく。



せっかくなのでアニメーション化してみよう。

VALUE_RANGE = 5.  // x = -5 to + 5
RESOLUTION = 300.
DRAW_SCALE = 200.
OFFSET_Y = -200.

// 放物線を描く

t1 = Turtle ! create.
t1 ! 1 linewidth (blue) linecolor.
t1 ! penup.
[ | n ; x y shape |
  x = (n - RESOLUTION / 2) / RESOLUTION * VALUE_RANGE. 
  y = x * x.
  t1 ! (DRAW_SCALE * x) (DRAW_SCALE * y + OFFSET_Y) moveto.
  t1 ! pendown.
  shape = t1 ! makeFigure.
  shape:type = "wall".
] ! (RESOLUTION) repeat.
t1 ! hide.

// 反射タートルプロトタイプ定義

bounceTurtle = Turtle ! create hide.
bounceTurtle:init = [
  self ! show (red) lineColor 1 linewidth 0.2 scale.
  self:viewTurtle = Turtle ! create penup 0.7 scale.

].
bounceTurtle:forward = [ | n ; forward |
  ! (n) forward.
  viewTurtle ! (! xPosition?) ( ! yPosition?) moveTo.
  self].

bounceTurtle:moveTo = [ | x y ; moveTo |
  ! (x) (y) moveTo.
  viewTurtle ! (! xPosition?) ( ! yPosition?) moveTo.
  self].

bounceTurtle:direction = [ | th ; direction |
  ! (th) direction.
  viewTurtle ! (! direction?) direction.
  self].

bounceTurtle:collision = [ | object moveself |
   [object:type == "wall"] ! then [
     self ! (object) (moveself) bounce.
     viewTurtle ! (! direction?) direction.
     viewTurtle ! (! xPosition?) ( ! yPosition?) moveTo.
   ] execute.
].

// 反射タートル群作成

turtles = Array ! create.
[ | n ; x aTurtle | 
  x = (n-11) * 25.
  aTurtle = bounceTurtle ! create.
  aTurtle ! init.
  aTurtle ! penup (x) 200 moveto 270 direction pendown.
  turtles ! ( aTurtle) add.
] ! 21 repeat.

// 反射実行

timer1 = Timer ! create.
timer1 ! 0.01 interval 1000 Times.
timer1 ! [
  turtles ! [ | aTurtle | 
   aTurtle ! 1 forward.
  ] foreach.
] execute.

「大科学実験」みたいになった。
本当は2回反射したらまた垂直に戻っていかないといけないのだがさすがにこのあたりが限界か。

裏側から当てると今度は放射状に散るようになる。

...
OFFSET_Y = 0.
...
  y = -1 * x * x.
...

反射方向が逆になるので当たり前といえば当たり前なのだが綺麗に円弧状になって散っていった。

だからやってみなくちゃわからない。



0 件のコメント:

コメントを投稿