7章 再帰を用いた作図(2)
☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
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では、引数nの値が0になったときにのみ一本の線を描く。
☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
補足説明2: 再帰の処理の流れ(n=2の場合)を以下に示す。引数で受取るnの値が0になるまで、手続きccurvは自分自身を呼び出し続けることに注意。
☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
コッホ曲線は、数学者のコッホ(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;
☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
コッホ曲線を -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本のコッホ曲線の集まりである。上記のプログラムで、手続きkochを3回呼び出す際に、作図の開始点と、曲線の傾きが下図のように変化している。
☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
(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の座標の与え方が、前回の例とは異なっていることに注意しよう。