フラクタル補間

 このプログラムは、C言語辞典アルゴリズムにあるフラクタル補間をdelphi xe用に変換したものです。
かなり古いサンプルプログラムらしく、元は、Pascalでその後、「C言語による最新アルゴリズム辞典」として出版された様です。
サンプルプログラムは『C言語による最新アルゴリズム事典』からもダウンロードできます algo.lzh をダウンロードしてください。
 C言語は Turbo C でPCは、NECの9801 又は IBM PC/AT Basicなので、グラフィック画面表示が、現在のWindowsとは互換性がないので、グラフィック部分の変更には注意が必要です。
グラフィックを使用しなければ、C++Builderのコンソール C のプログラムとして、そのまま実行することが可能ですが、フラクタル補間は、グラフィックを使用しないと、計算結果の確認は出来ません。
C++Builderを起動し、新規作成->その他->コンソールアプリケーション->ソースの種類 C->File1.c削除->プロジェクトに目的のCファイル追加 です。

 Turbo C embarcadero からダウンロード可能ですがダウンロード用ユーザー登録が必要です。
Turbo Cで、9801用とDos/V互換機用両方のプログラムが開発出来たと記憶していますが、此処でのC サンプルのは9801用で、Dos/V(PC/AT)用のものも用意されていますが、IBM PC 画面サイズ640x480の基本機種でしか動作不可です、CPU 8086のレジスターを直接使用するルーチンが含まれている為です。

 左図は、四点指定して、フラクタル補間をしたものです。
黒の折れ線が元の値で、赤の線が、各点の間をフラクタル補間したもので、各点の間が、全体の値と補間係数の値で保管されています。
赤い線になって見えますが、実際には点のつながりです。


 プログラムは、四点座標となっていますがプログラムを修正すれば増やせます、その時には、補間係数dの値の数も増やす必要があります(N-1)。
赤い線は実際には、点の繋がりなので、プロット数の値を小さくすれば確認できます。




C プログラム

/***********************************************************
	fracint.c -- フラクタル補間
***********************************************************/
#include "window.c"  /* ラージモデルでコンパイル */         /* window.c 9801 Pc/AT用 *1

double left = 0, bottom = 0, right = 100, top = 100,       /* 座標の範囲 */
        x[] = { 0, 30, 60, 100 }, y[] = { 0, 50, 40, 10 };  /* 各点の座標 */

#define N (sizeof x / sizeof x[0] - 1)

int main()
{
    int i, j;
    double p, q, a[N], c[N], d[N], e[N], f[N];

    /* アフィン変換を求める */
    q = x[N] - x[0];
    for (i = 0; i < N; i++) {
        printf("d[%d] = ", i);  scanf("%lf", &d[i]);
        a[i] = (x[i+1] - x[i]) / q;
        e[i] = (x[N] * x[i] - x[0] * x[i+1]) / q;
        c[i] = (y[i+1] - y[i] - d[i] * (y[N] - y[0])) / q;
        f[i] = (x[N] * y[i] - x[0] * y[i+1] -
                d[i] * (x[N] * y[0] - x[0] * y[N])) / q;
    }
    /* アトラクタをプロットする */
    gr_on();                                          /* 9801 又は PC/ATグラフィックの起動 */
    gr_window(left, bottom, right, top, 0, 0);    /* 9801の640x400 又は PC/AT 640*480 の画面がこの値に設定されます */
    p = x[0];  q = y[0];
    for (i = 0; i < 5000; i++) {
        j = rand() / (RAND_MAX / N + 1);              /* 0~N-1の乱数 */
        q = c[j] * p + d[j] * q + f[j];
        p = a[j] * p            + e[j];
        gr_wdot(p, q, WHITE);                         /* x座標 p y座標 q で白ドットプロット */
    }
    hitanykey();
    return EXIT_SUCCESS;
}

Delphi Xeプログラム

unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Image1: TImage;
    GroupBox1: TGroupBox;
    x1: TLabeledEdit;
    y4: TLabeledEdit;
    x4: TLabeledEdit;
    x2: TLabeledEdit;
    x3: TLabeledEdit;
    y3: TLabeledEdit;
    y2: TLabeledEdit;
    y1: TLabeledEdit;
    GroupBox2: TGroupBox;
    d3: TLabeledEdit;
    d1: TLabeledEdit;
    d2: TLabeledEdit;
    Button1: TButton;
    LabeledEdit1: TLabeledEdit;
    LabeledEdit2: TLabeledEdit;
    procedure Button1Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

uses system.Math;

procedure TForm1.Button1Click(Sender: TObject);
const
  N = 3;     // 0~3
  xb = 50;
  yb = 350;
var
  x , y : array of integer;
  a, c, d, e, f : array of double;
  p, q, kc  : double;
  i, j, k : integer;
  xi, yi  : integer;
  ch      : integer;
  ct      : integer;
  cp      : Tcomponent;
  mes     : pchar;
begin
  setlength(d, N);
  for k := 0 to N - 1 do begin
    cp := Findcomponent('d' + inttostr(k + 1));
    val(Tlabelededit(cp).Text, d[k], ch);
    if ch <> 0 then begin
      mes := Pchar('d' + intTostr(k + 1) + 'の値に間違いがあります。');
      application.MessageBox(mes,'注意',0);
      exit;
    end;
  end;
  setlength(x, N + 1);
  setlength(y, N + 1);
  for k := 0 to N do begin
    cp := Findcomponent('x' + inttostr(k + 1));
    val(Tlabelededit(cp).Text, x[k], ch);
    if ch <> 0 then begin
      mes := Pchar('x' + intTostr(k + 1) + 'の値に間違いがあります。');
      application.MessageBox(mes,'注意',0);
      exit;
    end;
  end;
  for k := 0 to N do begin
    cp := Findcomponent('y' + inttostr(k + 1));
    val(Tlabelededit(cp).Text, y[k], ch);
    if ch <> 0 then begin
      mes := Pchar('y' + intTostr(k + 1) + 'の値に間違いがあります。');
      application.MessageBox(mes,'注意',0);
      exit;
    end;
  end;
  for i := 0 to N - 1 do begin
    if x[i] > x[i + 1] then begin
      application.MessageBox('xの値の並びに間違いがあります。','注意',0);
      exit;
    end;
  end;
  val(Labelededit1.Text, ct, ch);
  if ch <> 0 then begin
    application.MessageBox('繰り返し回数の値に間違いがあります。','注意',0);
    exit;
  end;
  if ct < 100 then begin
    application.MessageBox('繰り返し回数の値が小さすぎます。','注意',0);
    exit;
  end;
  if ct > 1000000 then begin
    application.MessageBox('繰り返し回数の値が大きすぎます。','注意',0);
    exit;
  end;
  val(Labelededit2.Text, kc, ch);
  if ch <> 0 then begin
    application.MessageBox('作図倍率の値に間違いがあります。','注意',0);
    exit;
  end;
  if kc <= 0 then begin
    application.MessageBox('作図倍率の値をゼロ以上にしてください。','注意',0);
    exit;
  end;
  button1.Enabled := False;
  application.ProcessMessages;
  Image1.canvas.Brush.Color := clBtnface;
  Image1.canvas.fillrect(rect(0, 0, image1.Width, image1.height));

//  d[0] := 0.1;  d[1] := 0.4;  d[2] := -0.2;

//  x[0] := 0;  x[1] := 30;  x[2] := 60;  x[3] := 100;
//  y[0] := 0;  y[1] := 50;  y[2] := 40;  y[3] := 10;
  // xyグラフ
  Image1.canvas.Pen.Color := clBlack;
  yi := yb - round(y[0] * kc);
  xi := xb + round(x[0 ]* kc);
  Image1.canvas.MoveTo(xi, yi);
  for i := 1 to N do begin
    yi := yb - round(y[i] * kc);
    xi := xb + round(x[i] * kc);
    Image1.canvas.LineTo(xi, yi);
  end;

  setlength(a, N);
  setlength(c, N);
  setlength(e, N);
  setlength(f, N);

// アフィン変換
  q := x[N] - x[0];
  for i := 0 to N - 1 do  begin
    a[i] := (x[i + 1] - x[i]) / q;
    e[i] := (x[N] * x[i] - x[0] * x[i + 1]) / q;
    c[i] := (y[i + 1] - y[i] - d[i] * (y[N] - y[0])) / q;
    f[i] := (x[N] * y[i] - x[0] * y[i + 1] - d[i] * (x[N] * y[0] - x[0] * y[N])) / q;
  end;
//  アトラクタプロット
  p := x[0];
  q := y[0];
  Image1.canvas.Brush.Color := clRed;
  for i := 0 to  ct do begin
    j := random(N);
    q := c[j] * p + d[j] * q + f[j];
    p := a[j] * p + e[j];
    yi := yb - round(q * kc);
    xi := xb + round(p * kc);
    Image1.canvas.fillrect(rect(xi, yi, xi + 1, yi + 1));
  end;
  button1.Enabled := True;
end;

end.


download Fractal_V0.zip

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