フラクタルサンプル

 フラクタル図形のサンプル的プログラムを集めてみました。

 図形の保存は無いので、直接FormのCanvasに書きこんでいます、その為に、最小化した後、復帰させると作図した図形は失われます。
図形が失われた場合は、再度作図すれば問題はありません、図形が失われないようにする為には、TBittmaを使用してForm.canvasにbitmapを割り付けるか、Timageを使用します。
 フラクタル三角形からPythagoras Tree迄の4個の図形は、作図の工程を分かり易くするために、作図の待ち時間の設定ができるようになっています。
作図時間の値は、作図中でも変更が可能です。
一旦作図を始めると、作図が終了するまでプログラムの終了はできません、待ち時間を大きくしすぎてしまった場合は、作図中でも値を小さくできます。
 


 ピタゴラス Tree と コッホ曲線内回りです。


プログラム

unit FractalU;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls, Vcl.ComCtrls, system.UITypes;

type
  TFormFractal = class(TForm)
    Panel1: TPanel;
    ButtonClose: TButton;
    ButtonClear: TButton;
    ButtonDraw1: TButton;
    EditLevel: TEdit;
    UpDownLevel: TUpDown;
    ButtonDraw2: TButton;
    ButtonDraw3: TButton;
    ButtonDraw4: TButton;
    ButtonDraw5: TButton;
    CheckBox1: TCheckBox;
    ButtonDraw6: TButton;
    ButtonDraw7: TButton;
    ButtonDraw8: TButton;
    Edit1: TEdit;
    UpDown1: TUpDown;
    Label1: TLabel;
    procedure ButtonClearClick(Sender: TObject);
    procedure ButtonDraw1Click(Sender: TObject);
    procedure ButtonCloseClick(Sender: TObject);
    procedure ButtonDraw2Click(Sender: TObject);
    procedure ButtonDraw3Click(Sender: TObject);
    procedure ButtonDraw4Click(Sender: TObject);
    procedure ButtonDraw5Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure ButtonDraw6Click(Sender: TObject);
    procedure ButtonDraw7Click(Sender: TObject);
    procedure ButtonDraw8Click(Sender: TObject);
    procedure UpDown1Click(Sender: TObject; Button: TUDBtnType);
  private
    { Private 宣言 }
    XNow, YNow: extended; // 現在の位
  public
    { Public 宣言 }
    procedure StandBy(X, Y: Integer);       // 出発点を指定する。
    procedure Move(Muki, Kyori: extended);  // Muki 方向に Kyori だけ進む
    procedure Line(Muki, Kyori: extended);  // Muki 方向に Kyori だけ線を引く
    procedure Koch(Level: Byte; Muki, Nagasa: extended);
    procedure DrawKoch(Level: Byte);
    procedure KochThree(Level: Byte);
    procedure Sierpinski;
    procedure DrawTriangle(aCanvas: TCanvas; x, y, size: extended; n: byte);
    procedure drawTree(g: TCanvas; a, b: Tpoint ;n: byte);
    procedure drawDragon(g: TCanvas; a, b: TPoint; n: byte);
    procedure makeTree(ax, ay, bx, by : smallInt; depth : byte);
  end;

var
  FormFractal: TFormFractal;

implementation

{$R *.dfm}

uses system.Math, system.Types;

var waittime : integer;

//------------------------------- Pythagoras tree -----------------------------------
// http://www.davdata.nl/math/pythtree.html
procedure TFormFractal.makeTree(ax, ay, bx, by : smallInt; depth : byte);
var
  cx, cy, dx, dy, ex, ey : smallInt;
  x, y, zx, zy : smallInt;
begin
  x := bx - ax;
  y := ay - by;
  cx := ax - y;
  cy := ay - x;
  dx := bx - y;
  dy := by - x;
  zx := (cx + dx) div 2;
  zy := (cy + dy) div 2;
  ex := zx - (y div 2);
  ey := zy - (x div 2);
  with Canvas do
  begin
    pen.color := $FF0000 + depth;   // 塗りつぶしを正しく行うためのペン色設定
    pen.width := 1;
    moveto(bx, by);                 // 四角形描画
    lineto(ax, ay);
    lineto(cx, cy);
    lineto(dx, dy);
    lineto(bx, by);
    ax := (cx + bx) div 2;          // 塗りつぶし起点座標
    ay := (cy + by) div 2;
    brush.Color := depth * 256 * 16 + $FF;    // 塗りつぶし色
    FloodFill(ax, ay, pen.Color, fsBorder);
    if depth > 0 then
    begin
      maketree(cx, cy, ex, ey, depth - 1);
      maketree(ex, ey, dx, dy, depth - 1);
    end;
  end;
  if waittime > 0 then begin
    sleep(waittime);
    application.ProcessMessages;
  end;
end;

//------------------------------- Dragon --------------------------------------------
procedure TFormFractal.drawDragon(g: TCanvas; a, b: TPoint; n: byte);
var
  c : TPoint;
  xx, yy: integer;
begin
  xx := b.x - a.x;
  yy := -(b.y - a.y);
  c.x := round(a.x + (xx + yy) / 2);
  c.y := round(b.y + (xx + yy) / 2);
  //最後なので、実際に線を引きます
  if n <= 0 then begin
    g.MoveTo(a.x, a.y);  //点Aから点Cへ
    g.LineTo(c.x, c.y);
    g.LineTo(b.x, b.y);  //点cから点bへ
  end
  //最後ではないので、さらにメソッドを呼び出します(再帰処理)
  else begin
    drawDragon(g, a, c, n - 1);    //点Aから点Cへ
    drawDragon(g, b, c, n - 1);    //点Bから点Cへ
  end;
  if waittime > 0 then begin
    sleep(waittime);
    application.ProcessMessages;
  end;
end;

//------------------------------- Tree ----------------------------------------------
procedure TFormFractal.drawTree(g: TCanvas; a, b: TPoint ;n: byte);
const
  STEM_RATIO = 0.25;
  BRANCH_RATIO = 0.6;
var
  c, d, e: Tpoint;
  xsign, xx, yy : integer;
  angle1, angle2, center_length, branch_length: double;
begin
  xx := b.x - a.x;
  yy := -(b.y - a.y);
  if xx <> 0 then begin
    angle1 := arctan(yy / xx) + PI / 3;
    angle2 := arctan(yy / xx) - PI / 3;
  end
  else begin
    angle1 := Pi / 2 + PI / 3;
    angle2 := Pi / 2 - PI / 3;
  end;

  center_length := sqrt(xx * xx + yy * yy) * (1 - STEM_RATIO);
  branch_length := BRANCH_RATIO * center_length;

  //元の直線が右下がりなら符号をマイナスにします
  if xx >= 0 then xsign := 1 else xsign := -1;
  c.x := round((a.x + STEM_RATIO * xx));
  c.y := round((a.y - STEM_RATIO * yy));
  d.x := c.x + xsign * round((branch_length * cos(angle1)));
  d.y := c.y - xsign * round((branch_length * sin(angle1)));
  e.x := c.x + xsign * round((branch_length * cos(angle2)));
  e.y := c.y - xsign * round((branch_length * sin(angle2)));
  //幹の部分は再帰を行わないので、点Aから点Cへ実際に線を引きます
  g.MoveTo(a.x, a.y);
  g.LineTo(c.x, c.y);
  //最後なので、実際に線を引きます
  if n <= 1 then begin
    g.MoveTo(c.x, c.y);
    g.LineTo(b.x, b.y); //中央部(点Cから点Bへ)
    g.MoveTo(c.x, c.y);
    g.LineTo(d.x, d.y); //左の枝(点Cから点Dへ)
    g.MoveTo(c.x, c.y);
    g.LineTo(e.x, e.y); //右の枝(点Cから点Eへ)
  end
  //最後ではないので、更にメソッドを呼び出します(再帰処理)
  else begin
    n := n - 1;
    drawTree(g, c, b, n);   //中央部(点Cから点Bへ)
    drawTree(g, c, d, n);   //左の枝(点Cから点Dへ)
    drawTree(g, c, e, n);   //右の枝(点Cから点Eへ)
  end;
  if waittime > 0 then begin
    sleep(waittime);
    application.ProcessMessages;
  end;
end;

//------------------------------- フラクタル三角形 -----------------------------------------
procedure TFormFractal.DrawTriangle(aCanvas: TCanvas; x, y, size: extended; n: byte);
var
  h: extended;
  w: extended;
  x1, x2, x3, y1, y2, y3: extended;
  px1, px2, px3: integer;
  py1, py2: integer;

  procedure Triangle(xp, yp: extended);   // 三角形
  begin
    px1 := Round(xp);                     // 底辺 左 x
    px2 := Round(xp + w * 2);             // 底辺 右 x 
    px3 := Round(xp + w);                 // 頂点 x
    py1 := Round(yp);                     // 底辺 y
    py2 := Round(yp - h);                 // 頂点 y 
    aCanvas.MoveTo(px1, py1);
    aCanvas.LineTo(px2, py1);
    aCanvas.LineTo(px3, py2);
    aCanvas.LineTo(px1, py1);
  end;

begin
// 三角形3個描画
  w := size;
  h := size * 1.5744;
  // left
  x1 := x;
  y1 := y;
  Triangle(x1, y1);
  // right
  x2 := x1 + w * 2;
  y2 := y1;
  Triangle(x2, y2);
  // top
  x3 := x2 - w;
  y3 := y2 - h;
  Triangle(x3, y3);
// 再帰描画
  if n > 1 then
  begin
    dec(n);
    size := size / 2;
    DrawTriangle(aCanvas, x1, y1, size, n);
    DrawTriangle(aCanvas, x2, y2, size, n);
    DrawTriangle(aCanvas, x3, y3, size, n);
  end;
  if waittime > 0 then begin
    sleep(waittime);
    application.ProcessMessages;
  end;
end;

//--------------------------- シェルピンスキーのギャスケット -------------------
procedure TFormFractal.Sierpinski;
var
  i, count, x, y: integer;
  xcoord, ycoord: array[0..2] of integer;
begin
  xcoord[0] := 275;           // 三角形の頂点X
  ycoord[0] := 40;            // 三角形の頂点y
  xcoord[1] := 40;            // 三角形の底辺左x
  ycoord[1] := 410;           // 三角形の底辺左y
  xcoord[2] := 510;           // 三角形の底辺右x
  ycoord[2] := 410;           // 三角形の底辺右y
  x := 40;                    // 初期値x
  y := 410;                   // 初期値y

  for count:= 0 to 10000 do
  begin
    i := random(3);                 // 乱数0~2 乱数でないと図形は表示されません
    x := (x + xcoord[i]) div 2;
    y := (y + ycoord[i]) div 2;
    case i of
      0: canvas.pixels[x,y] := clred;
      1: canvas.pixels[x,y] := clgreen;
      2: canvas.pixels[x,y] := clblue;
    end;
  end;
end;

//------------------------- コッホ曲線 ------------------------------------------
procedure TFormFractal.StandBy(X, Y: Integer);
begin
  Canvas.MoveTo(X, Y);
  XNow := X;
  YNow := Y;
end;

procedure TFormFractal.Move(Muki, Kyori: extended);
begin
  XNow := XNow + Kyori * Cos(Muki);
  YNow := YNow + Kyori * Sin(Muki);
  Canvas.MoveTo(Round(XNow), Round(YNow));
end;

procedure TFormFractal.Line(Muki, Kyori: extended);
begin
  XNow := XNow + Kyori * Cos(Muki);
  YNow := YNow + Kyori * Sin(Muki);
  Canvas.LineTo(Round(XNow), Round(YNow));
end;

procedure TFormFractal.Koch(Level: Byte; Muki, Nagasa: extended);
begin
  if Level <= 1 then Line(Muki,Nagasa)        // 実際に線を引く
  else begin                                  // 長さ 1/3,Level-1 コッホ曲線を描く
    Koch(Level-1, Muki, Nagasa / 3);          // 指定方向に描く
    Koch(Level-1, Muki - Pi / 3, Nagasa / 3); // 左に 60 ゜方向に描く
    Koch(Level-1, Muki + Pi / 3, Nagasa / 3); // 右に 60 ゜方向に描く
    Koch(Level-1, Muki, Nagasa / 3);          // 指定方向に描く
  end;
end;

procedure TFormFractal.DrawKoch(Level: Byte);
begin
  StandBy(50, 250);     // 始点
  Koch(Level, 0, 400);  // コッホ曲線
end;

procedure TFormFractal.KochThree(Level: Byte);
var
  Leveled: byte;
begin
  canvas.Pen.Color := clBlack;
  Leveled := Level and $0F;
  if Level and $80 = 0 then begin         // 内回り三角
    Koch(Leveled, 0, 300);                // コッホ曲線
    Koch(Leveled,pi * 2 / 3 * 2, 300);    // コッホ曲線
    Koch(Leveled,pi * 2 / 3,     300);    // コッホ曲線
  end
  else begin                              // 外回り三角
    Koch(Leveled, 0, 300);                // コッホ曲線
    Koch(Leveled,-pi * 2 / 3 * 2, 300);   // コッホ曲線
    Koch(Leveled,-pi * 2 / 3,     300);   // コッホ曲線
    Canvas.Brush.Color := clBlue;
    Canvas.FloodFill(250 , 220, clBlack, fsBorder);
  end;
end;

//-------------------------------------------------------------------------------
procedure TFormFractal.ButtonDraw1Click(Sender: TObject);
var
  Level:  byte;
begin
  ButtonDraw1.Enabled := False;
  if checkbox1.Checked = true then ButtonClearClick(nil);
  Level := UpDownLevel.Position;
  DrawKoch(Level);
  ButtonDraw1.Enabled := True;
end;

procedure TFormFractal.ButtonDraw2Click(Sender: TObject);
var
  Level:  byte;
begin
  ButtonDraw2.Enabled := False;
  if checkbox1.Checked = true then ButtonClearClick(nil);
  Level := UpDownLevel.Position;
  StandBy(100, 300);      // 始点
  KochThree(Level);
  ButtonDraw2.Enabled := True;
end;

procedure TFormFractal.ButtonDraw3Click(Sender: TObject);
var
  Level:  byte;
begin
  ButtonDraw3.Enabled := False;
  if checkbox1.Checked = true then ButtonClearClick(nil);
  Level := UpDownLevel.Position;
  StandBy(100, 120);        // 始点
  KochThree(Level or $80);  // 三角形作図方向フラグセット
  ButtonDraw3.Enabled := True;
end;

procedure TFormFractal.ButtonDraw4Click(Sender: TObject);
var
  Level :  byte;
  i     :  byte;
begin
  ButtonDraw4.Enabled := False;
  if checkbox1.Checked = true then ButtonClearClick(nil);
  Level := UpDownLevel.Position;
  for i := 1 to Level do Sierpinski;
  ButtonDraw4.Enabled := True;
end;

procedure TFormFractal.ButtonDraw5Click(Sender: TObject);
var
  Level :  byte;
  size : extended;
  x,y : extended;
begin
  ButtonDraw5.Enabled := False;
  if checkbox1.Checked = true then ButtonClearClick(nil);
  Level := UpDownLevel.Position;
  size := 117.5;
  x := 40;
  y := 410;
  Canvas.Pen.Color := clFuchsia;
  DrawTriangle(Canvas, x, y, size, Level);
  ButtonDraw5.Enabled := True;
end;

procedure TFormFractal.ButtonDraw6Click(Sender: TObject);
var
  Level :  byte;
  B, T: Tpoint;
begin
  ButtonDraw6.Enabled := False;
  if checkbox1.Checked = true then ButtonClearClick(nil);
  Level := UpDownLevel.Position;
  //3対の点を指定します
  B := Point(250, 400);
  T := Point(250, 50);
  //それぞれの対をなす2点間に樹木曲線を描きます
  canvas.Pen.Color := clBlue;
  drawTree(canvas, B, T, Level);
  ButtonDraw6.Enabled := True;
end;

procedure TFormFractal.ButtonDraw7Click(Sender: TObject);
var
  Level :  byte;
  B, T: Tpoint;
begin
  ButtonDraw7.Enabled := False;
  if checkbox1.Checked = true then ButtonClearClick(nil);
  Level := UpDownLevel.Position;
  //出発点となる一対の点を指定します
  B := Point(220, 100);
  T := Point(430, 310);
  //対となる二点の間にドラゴン曲線を描きます
  canvas.Pen.Color := clBlue;
  drawDragon(canvas, B, T, Level);
  ButtonDraw7.Enabled := True;
end;

procedure TFormFractal.ButtonDraw8Click(Sender: TObject);
var
  Level :  byte;
begin
  ButtonDraw8.Enabled := False;
  if checkbox1.Checked = true then ButtonClearClick(nil);
  Level := UpDownLevel.Position;
  // 最初の四角形の底辺の座標を指定します
  makeTree(250, 400, 330, 400, Level);
  ButtonDraw8.Enabled := True;
end;

procedure TFormFractal.ButtonClearClick(Sender: TObject);
begin
  with Canvas do
  begin
    Brush.Color := clBtnface;
    FillRect(ClipRect);
  end;
end;

procedure TFormFractal.UpDown1Click(Sender: TObject; Button: TUDBtnType);
begin
  Waittime := updown1.Position * 10;
end;

procedure TFormFractal.ButtonCloseClick(Sender: TObject);
begin
  close;
end;

procedure TFormFractal.FormCreate(Sender: TObject);
begin
  Clientheight := 500;
  ClientWidth := 743;
end;

end.


download Fractal_V1.zip

  画像処理プログラム 作図 に戻る