pythagoras.jpg


ピタゴラスツリーを描画する

 ピタゴラスの定理、三平方の定理とも言いますが、直角三角形の三辺の長さに以下の関係があるという定理です。

pyt_fig1.png

 この定理の証明に、以下のような補助線を追加した図が用いられる場合があります。

pyt_fig2.png

 直角三角形の各辺を一辺とする正方形を3つ書き加えた図です。今回は、ピタゴラスの定理の証明がテーマ、ではなく、この図を使って「自己相似図形(フラクタル)を書いてみよう」が、テーマです。

ジェネレータ

 「ドラゴン曲線を描画する」では、1本の線分に対して、2本の線分を直角に配置したジェネレータを使いました。今回は、定理の証明に使われる補助線付きの図をそのままジェネレータにしてしまいます。

pyt_fig3.png

 ドラゴン曲線では、赤い線分から青い線分を作り出しましたが、今回は、赤い正方形から2つの青い正方形を作り出します。さらに、ドラゴン曲線の時と違っているのは、青い正方形を生じさせた赤い正方形は消さずにそのまま残しておきます。
 結果、再帰レベル2の形状は以下図の様になります。

pyt_lv2.png

 後は、繰り返しですので省略しますが、後ほどリンクするXi-TRACEのデータを使うと、指定したレベルで作図可能ですので、お試しください。
 手続きpythagorasで、再帰しながら正方形を描画しています。再帰レベル8まで描画を進めると、以下図の様になります。

pyt_lv8.png

 「木」の様に見えることから、ピタゴラスツリーなんて呼ばれます。上のツリーを描画した時の直角三角形の辺の長さは、a=1、b=√3、c=2、の、例のやつです。直角以外の2頂点の角度が30°と60°になる直角三角形。sin(30°)とかcos(60°)の値でお世話になりませんでしたか?

 辺の長さの比を変えると、また違った絵柄になります。ピタゴラスの定理により、直角三角形の三辺の長さには関係式があるので、データ上では、直角を挟む二辺a、bの長さをパラメータとして設定するようにしてあります。a=bの直角二等辺三角形にしてみると、こんな感じ(↓)。

pyt_aeqb.png

 「ドラゴン曲線を描画する」で描画したC曲線にも、どことなく似ているような……。

 あぁ、懐かしの三角定規は、この2種類でしたね。今の学校でも使っているのかしら??

ジェネレータの計算

 さて、先ほどのジェネレータの図(下図)に戻ってみます。この絵をスクリプトで描画しなければなりません。

pyt_fig3.png

 オブジェクトは正方形なので、描画は簡単そうに見えますが、再帰していくと回転と縮小変換がかかって、そこそこ大変そうです。正方形を描画するためのパラメータとして、まず、中心座標p=(p.x, p.y)と一辺の長さ2*lenで指定することにします。さらに、回転変換がかかるので、「上」の方向を示すベクタv=(v.x, v.y)を指定する必要があります。
 手続きpythagorasで再帰してツリーを描いて行きますが、pythagorasに渡すのは赤い正方形のp、len、vとします。手続きpythagorasの中で、赤い正方形を描画した上で、2つの青い正方形の座標を計算し、手続きpythagorasを再帰的に呼び出していきます。

 青い正方形の座標計算ですが、下図の様に考えると、Xi-TRACEの一次変換命令が使えるので、楽が出来そうです。

pyt_fig4.png

 まず、上図の様に、全ての正方形を積んでしまってから、RA点を中心に、□Aを反時計回りに∠ACだけ回転させます。同様に、RB点を中心として、□Bを今度は時計回りに∠BCだけ回転すると、作図したかった図形になります。□Aと□Bの中心座標(pa、pb)や上方向ベクタ(va、vb)も、計算が楽な上の図で生成しておいてから、Xi-TRACEの一次変換命令で一緒に回転させてしまえば、面倒な予備計算がほとんど必要なくなります。

 赤い正方形のパラメータ、p、len、vを使って、上図状態の青い正方形(□A)のパラメータ、pa、len_a、vaを作ってみましょう。

  pa=p+(−len+len_a)×u+(len+len_a)×v
  len_a=len×a/c
  va=v

 uは、上方向を示すベクタvと直角なベクタ。画像は2D(二次元)なので、紙面に垂直な方向は関係ないのだけど、紙面に垂直なベクタをw=(0,0,1)とすると、ベクタu=v*w(*はベクタ積)で計算できるので、以下の通り。

  // u軸を計算する:u=v*w, w=(0,0,1)
  var u.x=v.y;
  var u.y=-v.x;

 あとは、回転の中心をRA点に設定して、反時計回りに∠ACだけ回転すると、ジェネレータの図になります。

  cos(∠AC)=a/c ……より、
  ∠AC=acos(a/c)

 正方形(□A)の回転変換は以下の様に記述できます。

  model
  {
    rotz ∠AC;
    linear pa.x,pa.y,pa.z;
    linear va.x,va.y,va.z;
  }


 画像は2Dなので、紙面に垂直な方向(z軸)の座標値は使いませんが、Xi-TRACEの一次変換命令を流用するため、便宜的にz座標を扱う変数(pa.z、va.z)を定義して、値を0に設定しています。後は、紙面に垂直なz軸の周りに∠ACだけ回転(rotz)した座標をlinear命令で変換して求めます。
 linear命令は、3つの変数名(x, y, z)を渡し、各変数に代入されている値を三次元座標値と見なし、linear命令が実行された時点で設定されている一次変換を施し、結果を元の変数(x, y, z)に戻す命令です。

  linear x, y, z;  // x, y, z は変数名

    (x', y', z')=[一次変換行列]×(x, y, z)
    (x', y', z')を変数(x, y, z)に戻す。

 一次変換は、一度実行すると、実行した場所より後ろのブロック内に影響を与えてしまうため、回転変換とlinear命令をブロック(model { })で括って、影響をブロック内に隠ぺいします。

 もう一つ正方形(□B)がありますが、同様に計算して手続きpythagorasを再帰呼び出しします。

3Dに格上げ

 レイトレーシングの題材にしたいので、3Dに格上げして行きます。まずは、正方形→立方体ですね。
 立方体を定義するのに、中心座標p、上方向ベクタv、一辺の長さ2*len、だけだと、立方体を確定できません。このパラメータだけだと、ベクタvの周りに、自由に回転できてしまうためです。3D化しているので、もう一つパラメータで抑えないと立方体を確定できませんね。そこで、もう一軸、立方体の水平方向を示すベクタuを追加します。
 後は2Dの計算と大差ないので、省略です。

 動きとしては、再帰レベル毎に花が咲くように伸びていくオープニングと、ダイナミックに直角三角形の辺の比を変化してみるパートで構成しています。


完成動画

 完成したデータと動画です。

Xi-TRACEデータ pythagoras_2d.xitr
Xi-TRACEデータ pythagoras.xitr

 pythagoras_2d.xitrの方は、このページで使った図の作成に使用したスクリプトです。レイトレーシングはしません。"_2d"のついていない方でレイトレーシングした動画がこちら(↓)。



 直角三角形の辺の長さの比をダイナミックに変えると、わっさわっさと、ちょっと面白い映像になりました。必見です。


home

download

gallery