7章 再帰を用いた作図(2)

                 ☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆

7−1 C曲線

n次のC曲線は(n-1)次のC曲線と、90度回転させた(n-1)次のC曲線とで構成される。

    

出力例: 8次のC曲線(左)と10次のC曲線(右)

                           

                 ☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆

プログラム)

(先頭部分省略)



var

  Form1: TForm1;

  pi : real = 3.1415;
  len : real = 5;
  xs, ys, yc : integer;

  procedure ccurv( n : integer; angle: real );

  implementation

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);

var  n : integer;
     angle : real;

begin

    xs := 200; ys := 50;
    yc := 350;

    n := StrToInt(Edit1.Text);

    angle := 0;

    ccurv( n, angle );

end;

procedure ccurv( n : integer; angle: real );

var  th : real;
     x2, y2 : integer;

begin

    if  n = 0  then  begin

        th := pi * angle / 180;
        x2 := xs + round( len * cos(th) );
        y2 := ys + round( len * sin(th) ); //→三角比の計算は8章で

        Form1.Canvas.MoveTo( xs, yc - ys );
        Form1.Canvas.LineTo( x2, yc - y2 );

        xs := x2;
        ys := y2;

    end else begin

        ccurv( n-1, angle );
        angle := angle + 90;

        ccurv( n-1, angle );
        angle := angle - 90;

    end;

end;

end.

                 ☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆

補足説明1:  手続きccurvでは、引数の値がになったときにのみ一本の線を描く。

          

                 ☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆

補足説明2:  再帰の処理の流れ(n=2の場合)を以下に示す。引数で受取るの値がになるまで、手続きccurvは自分自身を呼び出し続けることに注意。

        

                 ☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆

7−2 コッホ曲線

コッホ曲線は、数学者のコッホ(Koch)によって発見されたもので、次のような手続きによって描かれる。

(1) 0次のコッホ曲線は長さLの直線である。

(2) 1次のコッホ曲線は、1辺の長さがL/3の大きさの正三角形の突起を出す。

(3) 2次のコッホ曲線は、1次のコッホ曲線の各辺(4個)に対して、1辺の長さがL/9の正三角形の突起を出す。

    以上を無限回繰り返せば、無限小の長さの線分が無限本つながった曲線となる。

         

出力例: 7次のコッホ曲線

            

プログラム)



var

  Form1: TForm1;

  pi : real = 3.1415;
  angle, xs, ys : real;
  xc , yc : integer;

  procedure koch( n: integer; len: real );

implementation

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
var
    i, n : integer;
   len : real;

begin

    xc := 50; yc := 300;
    xs := 0; ys := 0;
    angle := 0;

    n := StrToInt(Edit1.Text);

    len := 450;
    for i := 1 to n do len := len / 3;

    koch( n, len );

end;

procedure koch( n: integer; len: real );
var
    th : real;
   x2, y2 : real;

begin

    if n = 0 then
    begin

        th := pi * angle / 180;
        x2 := xs + len * cos(th);
        y2 := ys + len * sin(th);

        Form1.Canvas.MoveTo( xc + round(xs), yc - round(ys) );
        Form1.Canvas.LineTo( xc + round(x2), yc - round(y2) );

        xs := x2;
        ys := y2;

    end else
    begin

        koch( n-1, len );

        angle := angle + 60;
        koch( n-1, len );

        angle := angle - 120;
        koch( n-1, len );

        angle := angle + 60;
        koch( n-1, len );

    end;

end;

end.

                 ☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆

補足説明1: 手続きkochにおいて、正三角形の突起を出すときに、傾き角が最初は60増加し、次に120度減少し、もとにもどるときに60度増加する。下図を参照して対応付けを確認すること。

procedure koch( n: integer; len: real );

           . . .       . . .

    begin

        koch( n-1, len );

        angle := angle + 60;
        koch( n-1, len );

        angle := angle - 120;
        koch( n-1, len );

        angle := angle + 60;
        koch( n-1, len );

    end;

end;

                 ☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆

7−3 コッホ島

       コッホ曲線 -120度の角度をなして3個つなげると、雪の結晶のような形をした、コッホ島

       と呼ばれる図形を描くことが出来る。

          例)1次のコッホ島

                            

出力例: 3次のコッホ島(左)と5次のコッホ島(右)

                  

                 ☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆

プログラム)

ボタンのイベントハンドラの部分を以下のように変更すると、コッホ島を描くことができる。



procedure TForm1.Button1Click(Sender: TObject);

var  i, n, k : integer;
      len, th, xe, ye : real;

begin

    xc := 150; yc := 150;
    xs := 0; ys := 0;
    angle := 0;

    n := StrToInt(Edit1.Text);

    for k := 1 to 3 do  begin

        len := 200;

        th := pi * angle / 180;
        xe := xs +  len * cos(th) ;
        ye := ys +  len * sin(th) ;

        for i := 1 to n do len := len / 3;

        koch( n, len );

        xs := xe;  ys := ye;
        angle := angle - 120;

    end;

end;

                 ☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆

補足説明2: 

コッホ島は、3本のコッホ曲線の集まりである。上記のプログラムで、手続きkoch3回呼び出す際に、作図の開始点と、曲線の傾きが下図のように変化している。

         

                 ☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆

7−4 クロスステッチ

     (1) 0次のクロスステッチは、長さLの直線である。

(2) 1次のクロスステッチは、1辺の長さがL/3の正方形の突起を出す。

(3) 2次のクロスステッチは、1次のクロスステッチの各辺(5個)に対して、1辺の長さがL/9の正方形の突起を出す。

    以上を、無限回繰り返せば、無限小の長さの線分が無限本つながったクロスステッチが出来る。

         

     上記のクロスステッチを90度ずつ傾けて4個つなげると下図に示すような模様が出来上がる。

                           

出力例:  3次のクロスステッチ模様

                      

出力例: 4次のクロスステッチの模様

                   

                 ☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆

プログラム:

(先頭部分省略)



var

  Form1: TForm1;

  pi : real = 3.1415;
  angle, th, xs, ys, x2, y2 : real;
  xc, yc : integer;

  procedure  stitch( n:integer; len:real );

implementation

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);

var  i, k, n : integer;
     len : real;

begin

    angle := 0;
    xs := 0; ys := 0;

    xc := 150; yc := 150;

    n := StrToInt(Edit1.Text);

    len := 150;

    for i := 1 to n do len := len / 3;

    for k := 1 to 4 do begin

        stitch( n, len );

        angle := angle - 90;

    end;

end;

procedure  stitch( n:integer; len:real );

begin

    if  n=0 then begin

        th := pi * angle / 180;

        x2 := xs + len * cos(th);
        y2 := ys + len * sin(th);

        Form1.Canvas.MoveTo( xc + round(xs), yc - round(ys) );
        Form1.Canvas.LineTo( xc + round(x2), yc - round(y2) );

        xs := x2;  ys := y2;

    end else begin

        stitch( n-1, len );
        angle := angle + 90;

        stitch( n-1, len );
        angle := angle - 90;

        stitch( n-1, len );
        angle := angle - 90;

        stitch( n-1, len );
        angle := angle + 90;

        stitch( n-1, len );

    end;

end;

end.

☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆

補足説明1:

下図は0次から2次までのクロスステッチを重ね合わせて描いた図である。4個のクロスステッチを、始点と終点の位置をずらせながら、90度ずつ負の方向に傾けて描いている。0次から2次に至るいずれの場合にも、クロスステッチの始点と終点は同じであることに注意。

              

このとき、手続きを呼び出す側は以下のように作図の繰返しを指定している。


procedure TForm1.Button1Click(Sender: TObject);

{. . .       . . .}

begin

    angle := 0;

{. . .   . . .}

    len := 150;                        //(線分の長さの指定)

    for i := 1 to n do len := len / 3; //(次数に対応して線分の長さを計算)

    for k := 1 to 4 do                 //(4回繰返し)
    begin
        stitch( n, len );
        angle := angle - 90;           //(負の方向に90度傾ける)
    end;

end;

☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆

出力例: 5次のクロスステッチ模様を2つ組合わせたもの

                   

    注)開始位置線分の長さを変え、手続きstitchを呼び出して重ね描きを行なう。

              →解説へ

☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆

出力例: 5次のクロスステッチ模様を3個組み合わせたもの。

            

☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆

7−5 再帰を用いた簡単な作図例(図形の座標系から画面座標系への変換)

以下の例で、図形の原点と画面上の原点との対応付けを復習しておこう。

        

この図を描くためのプログラムは次の通りである。

(先頭部分省略)


var

  Form1: TForm1;

  xc, yc : integer; //(作図の中心位置)

  procedure rectangle_draw(xs, ys: integer; len:real);//(長方形を描く手続きの宣言)

implementation

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
var
    len : real;
    xs, ys : integer;

begin

    xc := 300;
    yc := 300;

    len := 200;
    xs := 0;
    ys := 0;

    rectangle_draw(xs, ys, len);

end;

procedure rectangle_draw(xs, ys : integer; len:real);

var  xe, ye, w : integer;

begin

    w := round(len);
    xe := xs + w;
    ye := ys + w;

    if ( len > 3 ) then begin

        Form1.Canvas.Rectangle(xs+xc,yc-ys,xe+xc,yc-ye);

        len := len / 2;

        rectangle_draw(xs,ys,len);

    end;

end;

end.

  ※ Canvas.Rectangle座標の与え方が、前回の例とは異なっていることに注意しよう。

       →解説へ