アルゴリズム図形の描画
|
52 |
AlgorithmGraphic |
動作確認 |
Delphi2007 |
更新日 |
2008/01/30(水) |
アルゴリズムの書籍にのっていた奇妙な図形を
Delphiで再現してみました。
リサージュ図形
ヒルベルト曲線
シェルピンスキー曲線
C曲線
ドラゴン曲線
非再帰版ドラゴン曲線
樹木曲線
不思議な三角形
3次元曲線
マンデルブロ集合
これらの図形が描画されます。
ソース内の定数を変えるとサイズや描画のパターンがいろいろ変化します
Imageを Width=500 Height=400 程度にして
10個のButtonイベントを以下のように記述してみてください。
────────────────────
//-------------------------------
//半径Rの正円を描く関数
//Rは正負どちらでも同じ
procedure Circle(Canvas: TCanvas; X, Y, R: Integer);
begin
Canvas.Ellipse(X-R, X-R, X+R, X+R);
end;
//-------------------------------
//半径Rx,Ryで指定した楕円を描く関数
//Rx,Ryは正負どちらでも同じ
procedure EllipseRadius(Canvas: TCanvas; X, Y, RX, RY: Integer);
begin
Canvas.Ellipse(X-RX, Y-RY, X+RX, Y+RY);
end;
//-------------------------------
//線を引く関数
procedure DrawLine(Canvas: TCanvas; X1, Y1, X2, Y2: Integer);
begin
Canvas.MoveTo(X1, Y1);
Canvas.LineTo(X2, Y2);
end;
//-------------------------------
//相対座標指定で移動
procedure MoveToRelative(Canvas: TCanvas; X, Y: Integer);
begin
X := Canvas.PenPos.X + X;
Y := Canvas.PenPos.Y + Y;
Canvas.MoveTo(X, Y);
end;
//-------------------------------
//相対座標指定で直線を引く
procedure LineToRelative(Canvas: TCanvas; X, Y: Integer);
begin
X := Canvas.PenPos.X + X;
Y := Canvas.PenPos.Y + Y;
Canvas.LineTo(X, Y);
end;
//-------------------------------
//四捨五入
function Roundoff(X: Extended): Longint;
begin
if x >= 0 then Result := Trunc(x + 0.5)
else Result := Trunc(x - 0.5);
end;
//-------------------------------
//リサージュ図形
procedure TForm1.Button1Click(Sender: TObject);
const
Size = 100;
var
i: Integer;
A: real;
begin
Image1.Canvas.FillRect(Image1.Canvas.ClipRect);
with Image1.Canvas do
begin
MoveTo(Size*2, Size);
for i := 1 to 360 do
begin
A := Pi*i /180;
LineTo(Roundoff(Size * (cos(3*A)+1)), Roundoff(Size * (sin(5*A)+1)));
end;
end;
end;
//-------------------------------
//ヒルベルト曲線
procedure TForm1.Button2Click(Sender: TObject);
const
Order = 5; Size = 300;
var
i, H: Integer;
procedure RUL; forward;
procedure DLU; forward;
procedure LDR; forward;
procedure URD; forward;
procedure RUL;
begin
if I > 0 then
begin
i := I - 1;
with Image1.Canvas do
begin
URD; LineToRelative(Image1.Canvas, H, 0);
RUL; LineToRelative(Image1.Canvas, 0, H);
RUL; LineToRelative(Image1.Canvas,-H, 0);
DLU;
i := i +1;
end;
end;
end;
procedure DLU;
begin
if I > 0 then
begin
i := I - 1;
with Image1.Canvas do
begin
LDR; LineToRelative(Image1.Canvas, 0,-H);
DLU; LineToRelative(Image1.Canvas,-H, 0);
DLU; LineToRelative(Image1.Canvas, 0, H);
RUL;
i := i +1;
end;
end;
end;
procedure LDR;
begin
if I > 0 then
begin
i := I - 1;
with Image1.Canvas do
begin
DLU; LineToRelative(Image1.Canvas,-H, 0);
LDR; LineToRelative(Image1.Canvas, 0,-H);
LDR; LineToRelative(Image1.Canvas, H, 0);
URD;
i := i +1;
end;
end;
end;
procedure URD;
begin
if I > 0 then
begin
i := I - 1;
with Image1.Canvas do
begin
RUL; LineToRelative(Image1.Canvas, 0, H);
URD; LineToRelative(Image1.Canvas, H, 0);
URD; LineToRelative(Image1.Canvas, 0,-H);
LDR;
i := i +1;
end;
end;
end;
begin
Image1.Canvas.FillRect(Image1.Canvas.ClipRect);
H := 1; for i := 2 to Order do H := H*2 +1;
H := Size div H; I := Order;
Image1.Canvas.MoveTo(0, 0);
MoveToRelative(Image1.Canvas, 0,0); RUL;
end;
//-------------------------------
//シェルピンスキー曲線
procedure TForm1.Button3Click(Sender: TObject);
const
Order = 5; Size = 300;
var
i, H: Integer;
procedure URD; forward;
procedure LUR; forward;
procedure DLU; forward;
procedure RDL; forward;
procedure URD;
begin
if I > 0 then
begin
i := I - 1;
with Image1.Canvas do
begin
URD; LineToRelative(Image1.Canvas, H, H);
LUR; LineToRelative(Image1.Canvas,2*H, 0);
RDL; LineToRelative(Image1.Canvas, H, -H);
URD;
i := i +1;
end;
end;
end;
procedure LUR;
begin
if I > 0 then
begin
i := I - 1;
with Image1.Canvas do
begin
LUR; LineToRelative(Image1.Canvas, -H, H);
DLU; LineToRelative(Image1.Canvas, 0,2*H);
URD; LineToRelative(Image1.Canvas, H, H);
LUR;
i := i +1;
end;
end;
end;
procedure DLU;
begin
if I > 0 then
begin
i := I - 1;
with Image1.Canvas do
begin
DLU; LineToRelative(Image1.Canvas, -H, -H);
RDL; LineToRelative(Image1.Canvas,-2*H, 0);
LUR; LineToRelative(Image1.Canvas, -H, H);
DLU;
i := i +1;
end;
end;
end;
procedure RDL;
begin
if I > 0 then
begin
i := I - 1;
with Image1.Canvas do
begin
RDL; LineToRelative(Image1.Canvas, H, -H);
URD; LineToRelative(Image1.Canvas, 0,-2*H);
DLU; LineToRelative(Image1.Canvas, -H, -H);
RDL;
i := i +1;
end;
end;
end;
begin
Image1.Canvas.FillRect(Image1.Canvas.ClipRect);
H := 6; for i := 2 to Order do H := H*2 + 2;
H := Size div H; I := Order;
Image1.Canvas.MoveTo(0, 0);
MoveToRelative(Image1.Canvas, H, 0);
URD; LineToRelative(Image1.Canvas, H, H);
LUR; LineToRelative(Image1.Canvas, -H, H);
DLU; LineToRelative(Image1.Canvas, -H,-H);
RDL; LineToRelative(Image1.Canvas, H,-H);
end;
//-------------------------------
//C曲線
procedure TForm1.Button4Click(Sender: TObject);
const
MaxLength = 3.20;
procedure C(X, Y: real);
begin
if sqr(X) + sqr(Y) <= sqr(MaxLength) then
begin
LineToRelative(Image1.Canvas, Roundoff(X), Roundoff(Y))
end else
begin
C((X+Y)/2, (Y-X)/2);
C((X-Y)/2, (Y+X)/2);
end;
end;
begin
Image1.Canvas.FillRect(Image1.Canvas.ClipRect);
MoveToRelative(Image1.Canvas, 0,0);
Image1.Canvas.MoveTo(150, 200);
C(200, 0);
end;
//-------------------------------
//ドラゴンカーブ
procedure TForm1.Button5Click(Sender: TObject);
const
MaxLength = 10;
procedure Dragon(X, Y: real; Sign: Integer);
begin
if sqr(X) + sqr(Y) <= sqr(MaxLength) then
begin
LineToRelative(Image1.Canvas, Roundoff(X), Roundoff(Y))
end else
begin
Dragon((X-Sign*Y)/2, (Y+Sign*X)/2, 1);
Dragon((X+Sign*Y)/2, (Y-Sign*X)/2,-1);
end;
end;
begin
Image1.Canvas.FillRect(Image1.Canvas.ClipRect);
Image1.Canvas.MoveTo(150, 200);
Dragon(200, 0, 1);
end;
//-------------------------------
//非再帰版ドラゴンカーブ
procedure TForm1.Button6Click(Sender: TObject);
const
Order = 8;
var
K, I, P, Q, X, Y, NewX, NewY: Integer;
Fold: array[0..1023] of (Right, Left);
begin
Image1.Canvas.FillRect(Image1.Canvas.ClipRect);
Image1.Canvas.MoveTo(200, 200);
X := 0; Y := 2;
LineToRelative(Image1.Canvas, 4*X, 4*Y);
P := 0;
for K := 1 to Order do
begin
Fold[P] := Left;
Q := 2*P;
for i := P to Q do
begin
case Fold[Q-I] of
Right: begin
Fold[I] := Left;
NewX := -Y; NewY := X;
end;
Left: begin
Fold[I] := Right;
NewX := Y; NewY := -X;
end;
else
NewX := 0; NewY := 0;
Assert(False,'エラー');
end;
LineToRelative(Image1.Canvas, X + NewX, Y + NewY);
LineToRelative(Image1.Canvas, 4 * NewX, 4 * NewY);
X := NewX;
Y := NewY;
end;
P := Q + 1;
end;
end;
//-------------------------------
//樹木曲線
procedure TForm1.Button7Click(Sender: TObject);
const
Factor = 0.7; Turn = 0.6;
procedure Tree(N: Integer; Length, Angle: real);
var
DX, DY: real;
begin
DX := Length* sin(Angle);
DY := Length* cos(Angle);
LineToRelative(Image1.Canvas, Roundoff(DX), Roundoff(DY));
if N > 1 then
begin
Tree(N - 1, Length * Factor, Angle + Turn);
Tree(N - 1, Length * Factor, Angle - Turn);
end;
MoveToRelative(Image1.Canvas, Roundoff(-DX), Roundoff(-DY));
end;
begin
Image1.Canvas.FillRect(Image1.Canvas.ClipRect);
Image1.Canvas.MoveTo(200, 0);
Tree(6, 100, 0);
end;
//-------------------------------
//不思議な三角形
procedure TForm1.Button8Click(Sender: TObject);
procedure DrawSquare(I, J: Integer);
const
Side = 5;
begin
Image1.Canvas.MoveTo(Side * i, Side * j);
LineToRelative(Image1.Canvas, Side, 0);
LineToRelative(Image1.Canvas, 0, Side);
LineToRelative(Image1.Canvas,-Side, 0);
LineToRelative(Image1.Canvas, 0,-Side);
end;
const
N = 50; TwoN = 100;
var
I, J: Integer;
A, B: array[0..TwoN] of Boolean;
begin
Image1.Canvas.FillRect(Image1.Canvas.ClipRect);
for i := 0 to TwoN do A[I] := false;
A[N] := true;
for j := N-1 downto 1 do
begin
for i := 1 to TwoN - 1 do if A[i] then DrawSquare(I, J);
for i := 1 to TwoN - 1 do B[i] := (A[i-1] <> A[i+1]);
for i := 1 to TwoN - 1 do A[I] := B[i];
end;
end;
//-------------------------------
//3次元曲線
procedure TForm1.Button9Click(Sender: TObject);
function DrawFunc(X, Z: real): real;
begin
Result := cos(10 * sqrt(sqr(X) + sqr(Z)));
end;
const
Xmin = -1; Xmax = 1; Zmin = -1; Zmax = 1; YScale =10;
var
X, Z: real;
I, Ix, Iz, Px, Py: Integer;
Ok, LastOk: boolean;
LowerHorizon, UpperHorizon: array[0..240] of Integer;
begin
Image1.Canvas.FillRect(Image1.Canvas.ClipRect);
for i := 0 to 240 do
begin
LowerHorizon[i] := MaxInt; UpperHorizon[i] := - MaxInt;
end;
for Iz := 0 to 20 do
begin
Z := Zmin + (Zmax - Zmin) * Iz / 20; LastOk := False;
for Ix := 0 to 200 do
begin
X := Xmin + (Xmax - Xmin) * Ix /200;
I := Ix + 2 * (20-Iz); Px := 1 * I;
Py := Roundoff(YScale * DrawFunc(X, Z)) + 2 * Iz + 100;
Ok := false;
if Py < LowerHorizon[I] then
begin
LowerHorizon[I] := Py; Ok := true;
end;
if Py > UpperHorizon[I] then
begin
UpperHorizon[I] := Py; Ok := true;
end;
if Ok and LastOk then Image1.Canvas.LineTo(Px, Py)
else Image1.Canvas.MoveTo(Px, Py);
LastOk := Ok;
end;
end;
end;
//-------------------------------
//マンデルブロ集合
procedure TForm1.Button10Click(Sender: TObject);
const
Max = 255; Min = 50; Imax = 100; Jmax = 100; Scale = 3;
Xmin = 0.2691; Ymin = 0.0043; Step = 0.000002;
var
I, J, Count: Integer;
X, Y, A, B, A2, B2: real;
begin
Image1.Canvas.FillRect(Image1.Canvas.ClipRect);
for i := 0 to Imax do
begin
X := Xmin + step * I;
for j := 0 to Jmax do
begin
Y := Ymin + Step * J;
A := X; B:= Y; A2 := sqr(A); B2 := sqr(B); Count := 0;
while (A2 + B2 <= 4) and (Count < Max) do
begin
B := 2 * A * B + Y; A := A2 - B2 + X;
A2 := sqr(A); B2 := sqr(B); Count := Count + 1;
end;
if COunt > Min then
begin
Image1.Canvas.MoveTo(I * Scale, J * Scale);
LineToRelative(Image1.Canvas, 0, roundoff(Scale * (Count -Min) / (Max - Min)) );
end;
end;
end;
end;
|