algorytm.org

Implementacja w Delphi/Pascal



Baza Wiedzy
wersja offline serwisu przeznaczona na urządzenia z systemem Android
Darowizny
darowiznaWspomóż rozwój serwisu
Nagłówki RSS
Artykuły
Implementacje
Komentarze
Forum
Bookmarki






Sonda
Implementacji w jakim języku programowania poszukujesz?

Fraktale Newtona - Implementacja w Delphi/Pascal
Ocena użytkownikóww: *****  / 1
SłabyŚwietny
Nadesłany przez Tomasz Lubiński, 19 stycznia 2009 01:00
Kod przedstawiony poniżej przedstawia główną część rozwiązania problemu.
Pobierz pełne rozwiązanie.

Jeżeli nie odpowiada Ci sposób formatowania kodu przez autora skorzystaj z pretty printer'a i dostosuj go automatycznie do siebie.

Fraktale Newtona - Delphi/Newton.pas:
// Fraktale Newtona
// www.algorytm.org
// Tomasz Lubinski (c) 2009

unit Newton;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ExtCtrls, Math, Grids;

type
  TForm1 = class(TForm)
    Fractal: TImage;
    Label1: TLabel;
    Label2: TLabel;
    Selection: TShape;
    Label3: TLabel;
    minx: TEdit;
    maxx: TEdit;
    miny: TEdit;
    maxy: TEdit;
    Button1: TButton;
    Label6: TLabel;
    Label5: TLabel;
    Button2: TButton;
    Label7: TLabel;
    Label8: TLabel;
    aArray: TStringGrid;
    aRe: TEdit;
    aIm: TEdit;
    colorIteration: TRadioButton;
    colorSet: TRadioButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FractalMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure FractalMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure FractalMouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

//type for complex numbers
type complex_t = record
    real: Extended;
    imaginary: Extended;
end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

var
//---------------------------------------------------------------------------
//Describes places to render
ratioX, ratioY :Extended;
min_X, min_Y, max_X, max_Y :Extended;
downX, downY: Integer;
//colors
colors: array[1..100] of TColor;
//result sets
results: array[1..10] of complex_t;
resultsCnt: Integer;
//how to color fractal
cSet: boolean;
//---------------------------------------------------------------------------

//for HSV colors
procedure hsv2rgb(hue: double; sat: double; val: double; var red: double; var grn: double; var blu: double);
var
        i, f, p, q, t: double;
begin
        red := 0;
        grn := 0;
        blu := 0;
        if val=0 then
                begin
                        red := 0;
                        grn := 0;
                        blu := 0;
                end
        else
                begin
                        hue := hue/60;
                        i := floor(hue);
                        f := hue-i;
                        p := val*(1-sat);
                        q := val*(1-(sat*f));
                        t := val*(1-(sat*(1-f)));
                        if i=0 then begin red:=val; grn:=t; blu:=p; end
                        else if i=1 then begin red:=q; grn:=val; blu:=p; end
                        else if i=2 then begin red:=p; grn:=val; blu:=t; end
                        else if i=3 then begin red:=p; grn:=q; blu:=val; end
                        else if i=4 then begin red:=t; grn:=p; blu:=val; end
                        else if i=5 then begin red:=val; grn:=p; blu:=q; end;
                end;
end;

procedure initializeColors();
var
        i: Integer;
        r, g, b: double;
begin
        for i:=low(colors) to high(colors) do
        begin
                HSV2RGB(2.5*i, 0.85, 0.8, r, g, b);
                colors[i] :=  Round((r*255) + (Round(g*255) shl 8) + (Round(b*255) shl 16));
        end;
        colors[100] := 0;
end;

//calculate squared modus of given complex c
function complexModSq(c: complex_t): Extended;
begin
        Result := c.real*c.real + c.imaginary*c.imaginary;
end;

//complex addition
function add(a: complex_t; b: complex_t ): complex_t;
begin
        Result.real :=  a.real + b.real;
        Result.imaginary := a.imaginary + b.imaginary;
end;

//complex substraction
function sub(a: complex_t; b: complex_t): complex_t;
begin
        Result.real :=  a.real - b.real;
        Result.imaginary := a.imaginary - b.imaginary;
end;

//complex multiplication
function mul(a: complex_t; b: complex_t): complex_t;
begin
        Result.real :=  a.real*b.real - a.imaginary*b.imaginary;
        Result.imaginary := a.real*b.imaginary + a.imaginary*b.real;
end;

//complex divide
function divide(a: complex_t; b: complex_t): complex_t;
var
        x: Extended;
begin
        x := b.real*b.real + b.imaginary*b.imaginary;

        Result.real :=  (a.real*b.real + a.imaginary*b.imaginary) / x;
        Result.imaginary := (a.imaginary*b.real - a.real*b.imaginary) / x;
end;

//function f(p)=p
function f(p: complex_t): complex_t;
begin
        Result := p;
end;

//function g(z) = z^2 + c
function g(z: complex_t; c: complex_t): complex_t;
begin
        Result.real := z.real*z.real - z.imaginary*z.imaginary + c.real;
        Result.imaginary := 2*z.real*z.imaginary + c.imaginary;
end;

//func = a[0] + a[1]*z^1 + a[2]*z^2 + ... a[n]*z^2
function func(z: complex_t; a: Array of complex_t): complex_t;
var
        i: Integer;
begin
        Result.real := 0;
        Result.imaginary := 0;

        for i:=high(a) downto low (a) do
                Result := add(a[i], mul(Result, z));
end;

function findResult(a: complex_t): Integer;
var
        i: Integer;
begin
        for i:=1 to resultsCnt do
              if (complexModSq(sub(a, results[i])) < 0.1) then
              begin
                 Result := i;
                 Exit;
              end;

        results[resultsCnt] := a;
        resultsCnt := resultsCnt + 1;
        Result := resultsCnt;
end;

//value is inside set in the returned level
function levelSet(a: complex_t; p: complex_t; w: Array of complex_t; d: Array of complex_t): Integer;
var
        z, z_prev: complex_t;
        iteration: Integer;
begin

        iteration := 0;
        z := p;

        repeat
                z_prev := z;
                z := sub(z, mul(a, divide(func(z, w), func(z, d))));
                iteration := iteration + 1;
        until ((complexModSq(sub(z_prev,z)) <= 0.0001) or (iteration >= 100));

        Result := iteration;

        if (cSet = true) and (iteration < 100) then
                Result := 10*findResult(z);
end;


procedure TForm1.Button1Click(Sender: TObject);
var
        i, j, level: Integer;
        p, a: complex_t;
        w: Array[0..5] of complex_t;
        d: Array[0..4] of complex_t;
begin
        min_X := StrToFloat(minx.Text);
        min_Y := StrToFloat(miny.Text);
        max_X := StrToFloat(maxx.Text);
        max_Y := StrToFloat(maxy.Text);

        for i:=low(w) to high(w) do
        begin
                w[i].real := StrToFloat(aArray.Cells[1, i+1]);
                w[i].imaginary := StrToFloat(aArray.Cells[2, i+1]);
        end;

        for i:=low(d) to high(d) do
        begin
                d[i].real := StrToFloat(aArray.Cells[1, i+2])*(i+1.0);
                d[i].imaginary := StrToFloat(aArray.Cells[2, i+2])*(i+1.0);
        end;

        a.real := StrToFloat(aRe.Text);
        a.imaginary := StrToFloat(aIm.Text);

        ratioX := (max_X - min_X) / Fractal.Width;
        ratioY := (max_Y - min_Y) / Fractal.Height;

        resultsCnt := 0;
        cSet := colorSet.Checked;

        for i:=0 to Fractal.Height-1 do
        begin
                p.imaginary := i*ratioY + min_Y;
                for j:=0 to Fractal.Width-1 do
                begin
                        p.real := j*ratioX + min_X;
                        level := levelSet(a, p, w, d);
                        Fractal.Canvas.Pixels[j, i] :=  colors[level];
                end;

        end;
        Fractal.Refresh();

end;

procedure TForm1.FormCreate(Sender: TObject);
begin
        minx.Text := FloatToStr(-1.5);
        maxx.Text := FloatToStr(1.5);
        miny.Text := FloatToStr(-1.5);
        maxy.Text := FloatToStr(1.5);

        aRe.Text := FloatToStr(1.0);
        aIm.Text := FloatToStr(0.0);

        aArray.Cells[1,0] := 'p(Re)^n';
        aArray.Cells[2,0] := 'p(Im)^n';
        aArray.Cells[0,0] := 'n';
        aArray.Cells[0,1] := '0';
        aArray.Cells[0,2] := '1';
        aArray.Cells[0,3] := '2';
        aArray.Cells[0,4] := '3';
        aArray.Cells[0,5] := '4';
        aArray.Cells[0,6] := '5';

        aArray.Cells[1,1] := FloatToStr(-1.0);
        aArray.Cells[1,2] := FloatToStr(0.0);
        aArray.Cells[1,3] := FloatToStr(0.0);
        aArray.Cells[1,4] := FloatToStr(1.0);
        aArray.Cells[1,5] := FloatToStr(0.0);
        aArray.Cells[1,6] := FloatToStr(0.0);

        aArray.Cells[2,1] := FloatToStr(0.0);
        aArray.Cells[2,2] := FloatToStr(0.0);
        aArray.Cells[2,3] := FloatToStr(0.0);
        aArray.Cells[2,4] := FloatToStr(0.0);
        aArray.Cells[2,5] := FloatToStr(0.0);
        aArray.Cells[2,6] := FloatToStr(0.0);

        min_X := StrToFloat(minx.Text);
        min_Y := StrToFloat(miny.Text);
        max_X := StrToFloat(maxx.Text);
        max_Y := StrToFloat(maxy.Text);

        ratioX := (max_X - min_X) / Fractal.Width;
        ratioY := (max_Y - min_Y) / Fractal.Height;

        //initialize colors
        initializeColors();

        //render new fractal
        Button1Click(Sender);
end;

procedure TForm1.FractalMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
        downX := X;
        downY := Y;

        Selection.Width := 0;
        Selection.Height := 0;
        Selection.Visible := true;
end;

procedure TForm1.FractalMouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
        //remove selection
        Selection.Visible := false;

        //get new range to render
        minx.Text := FloatToStr(min(downX, X)*ratioX + min_X);
        maxx.Text := FloatToStr(max(downX, X)*ratioX + min_X);
        miny.Text := FloatToStr(min(downY, Y)*ratioY + min_Y);
        maxy.Text := FloatToStr(max(downY, Y)*ratioY + min_Y);

        min_X := StrToFloat(minx.Text);
        min_Y := StrToFloat(miny.Text);
        max_X := StrToFloat(maxx.Text);
        max_Y := StrToFloat(maxy.Text);

        //render new fractal
        Button1Click(Sender);
end;

procedure TForm1.FractalMouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin
        //if left mouse button is held then draw selection
        if (ssLeft in Shift) then
        begin
                Selection.Width := abs(downX - X);
                Selection.Height := abs(downY - Y);
                Selection.Left := Fractal.Left + min(downX, X);
                Selection.Top := Fractal.Top + min(downY, Y);
        end;
end;

end.
Dodaj komentarz