Initial commit
This commit is contained in:
commit
be818315f6
258
BMPImage.pas
Normal file
258
BMPImage.pas
Normal file
|
@ -0,0 +1,258 @@
|
||||||
|
unit BMPImage;
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses classes;
|
||||||
|
|
||||||
|
type
|
||||||
|
TColor = object
|
||||||
|
r: byte;
|
||||||
|
g: byte;
|
||||||
|
b: byte;
|
||||||
|
|
||||||
|
procedure set_color(tr: byte; tg: byte; tb: byte);
|
||||||
|
procedure reset();
|
||||||
|
end;
|
||||||
|
|
||||||
|
TPxData = array of array of TColor;
|
||||||
|
|
||||||
|
TBMPImage = object
|
||||||
|
private
|
||||||
|
width, height: integer;
|
||||||
|
|
||||||
|
function get_padding(): integer;
|
||||||
|
public
|
||||||
|
pixel_data: array of array of TColor;
|
||||||
|
|
||||||
|
constructor init();
|
||||||
|
constructor init(w: integer; h: integer; c: TColor);
|
||||||
|
constructor init(px_data: TPxData);
|
||||||
|
destructor done();
|
||||||
|
|
||||||
|
procedure set_pixel_data(px_data: TPxData);
|
||||||
|
procedure set_width(w: integer);
|
||||||
|
procedure set_height(h: integer);
|
||||||
|
|
||||||
|
function get_width(): integer;
|
||||||
|
function get_height(): integer;
|
||||||
|
|
||||||
|
procedure open(path: string);
|
||||||
|
procedure save(path: string; monochrome: boolean);
|
||||||
|
end;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
procedure TColor.reset();
|
||||||
|
begin
|
||||||
|
r := 0;
|
||||||
|
g := 0;
|
||||||
|
b := 0;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TColor.set_color(tr: byte; tg: byte; tb: byte);
|
||||||
|
begin
|
||||||
|
r := tr;
|
||||||
|
g := tg;
|
||||||
|
b := tb;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TBMPImage.set_pixel_data(px_data: TPxData);
|
||||||
|
var
|
||||||
|
i, j: longint;
|
||||||
|
begin
|
||||||
|
width := length(px_data);
|
||||||
|
height := length(px_data[0]);
|
||||||
|
setLength(pixel_data, width, height);
|
||||||
|
|
||||||
|
for i := 0 to width - 1 do begin
|
||||||
|
for j := 0 to height - 1 do begin
|
||||||
|
pixel_data[i][j] := px_data[i][j];
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
constructor TBMPImage.init();
|
||||||
|
begin
|
||||||
|
setLength(pixel_data, 0, 0);
|
||||||
|
width := 0;
|
||||||
|
height := 0;
|
||||||
|
end;
|
||||||
|
|
||||||
|
constructor TBMPImage.init(w: integer; h: integer; c: TColor);
|
||||||
|
var
|
||||||
|
i, j: integer;
|
||||||
|
begin
|
||||||
|
setLength(pixel_data, w, h);
|
||||||
|
width := w;
|
||||||
|
height := h;
|
||||||
|
|
||||||
|
for i := 0 to width - 1 do begin
|
||||||
|
for j := 0 to height - 1 do begin
|
||||||
|
pixel_data[i][j] := c;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
constructor TBMPImage.init(px_data: TPxData);
|
||||||
|
begin
|
||||||
|
set_pixel_data(px_data);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
destructor TBMPImage.done();
|
||||||
|
begin
|
||||||
|
setLength(pixel_data, 0, 0); // not neccesary
|
||||||
|
width := 0;
|
||||||
|
height := 0;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TBMPImage.get_padding(): integer;
|
||||||
|
var
|
||||||
|
bytes_per_row, padding: integer;
|
||||||
|
begin
|
||||||
|
bytes_per_row := width * 3;
|
||||||
|
padding := 4 - bytes_per_row mod 4;
|
||||||
|
if padding = 4 then padding := 0;
|
||||||
|
get_padding := padding;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TBMPImage.set_width(w: integer);
|
||||||
|
var
|
||||||
|
color: TColor;
|
||||||
|
i, j: integer;
|
||||||
|
begin
|
||||||
|
setLength(pixel_data, w, height);
|
||||||
|
if (w > width) then begin
|
||||||
|
for i := width to w - 1 do begin
|
||||||
|
for j := 0 to height - 1 do begin
|
||||||
|
color.set_color(255, 255, 255);
|
||||||
|
pixel_data[i][j] := color;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
width := w;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TBMPImage.set_height(h: integer);
|
||||||
|
var
|
||||||
|
color: TColor;
|
||||||
|
i, j: integer;
|
||||||
|
begin
|
||||||
|
setLength(pixel_data, width, h);
|
||||||
|
if (h > height) then begin
|
||||||
|
for i := 0 to width - 1 do begin
|
||||||
|
for j := height to h - 1 do begin
|
||||||
|
color.set_color(255, 255, 255);
|
||||||
|
pixel_data[i][j] := color;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
height := h;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TBMPImage.get_width(): integer;
|
||||||
|
begin
|
||||||
|
get_width := width;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TBMPImage.get_height(): integer;
|
||||||
|
begin
|
||||||
|
get_height := height;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TBMPImage.open(path: string);
|
||||||
|
var
|
||||||
|
instream: TFileStream;
|
||||||
|
px_data_offset, i, j, k, padding: integer;
|
||||||
|
color: TColor;
|
||||||
|
begin
|
||||||
|
instream := TFileStream.Create(path, fmOpenRead);
|
||||||
|
|
||||||
|
instream.position := 10;
|
||||||
|
px_data_offset := instream.readword();
|
||||||
|
|
||||||
|
instream.position := 18;
|
||||||
|
width := instream.readword();
|
||||||
|
instream.position := 22;
|
||||||
|
height := instream.readword();
|
||||||
|
|
||||||
|
setLength(pixel_data, width, height); // indexes begins with zero
|
||||||
|
|
||||||
|
padding := get_padding();
|
||||||
|
|
||||||
|
instream.position := px_data_offset;
|
||||||
|
k := 1;
|
||||||
|
for i := height - 1 downto 0 do begin
|
||||||
|
for j := 0 to width - 1 do begin
|
||||||
|
color.b := instream.readbyte();
|
||||||
|
color.g := instream.readbyte();
|
||||||
|
color.r := instream.readbyte();
|
||||||
|
|
||||||
|
pixel_data[j][i] := color;
|
||||||
|
|
||||||
|
inc(k);
|
||||||
|
end;
|
||||||
|
instream.position := instream.position + padding;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TBMPImage.save(path: string; monochrome: boolean);
|
||||||
|
var
|
||||||
|
ostream: TFileStream;
|
||||||
|
padding, i, j, cs: integer;
|
||||||
|
color: TColor;
|
||||||
|
buf: array[1..1000000] of byte;
|
||||||
|
k, size: longint;
|
||||||
|
begin
|
||||||
|
ostream := TFileStream.Create(path, fmCreate + fmOpenWrite);
|
||||||
|
|
||||||
|
ostream.writeword(19778); // "BM" - format specifier
|
||||||
|
|
||||||
|
ostream.position := 10;
|
||||||
|
ostream.WriteDWord(54); // pixel data offset is bytes (54)
|
||||||
|
ostream.WriteDWord(40); // second header size in bytes (40, 14 - first header)
|
||||||
|
ostream.WriteDWord(width);
|
||||||
|
ostream.WriteDWord(height);
|
||||||
|
ostream.position := 26;
|
||||||
|
ostream.writeword(1); // must be one
|
||||||
|
// bits per pixel
|
||||||
|
if (monochrome) then ostream.writeword(1) else ostream.writeword(24);
|
||||||
|
|
||||||
|
padding := get_padding();
|
||||||
|
ostream.position := 54;
|
||||||
|
|
||||||
|
size := width * 3 + padding;
|
||||||
|
for k := 1 to size do begin // we need zero bytes to fill padding
|
||||||
|
buf[k] := 0;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if (monochrome) then begin
|
||||||
|
{color := pixel_data[j][i];
|
||||||
|
cs := color.r + color.g + color.b;
|
||||||
|
if (cs > 425) then begin
|
||||||
|
cs := 255;
|
||||||
|
end else begin
|
||||||
|
cs := 0;
|
||||||
|
end;
|
||||||
|
ostream.writebyte(cs);
|
||||||
|
ostream.writebyte(cs);
|
||||||
|
ostream.writebyte(cs);}
|
||||||
|
end else begin
|
||||||
|
for i := height - 1 downto 0 do begin
|
||||||
|
k := 1;
|
||||||
|
for j := 0 to width - 1 do begin
|
||||||
|
color := pixel_data[j][i];
|
||||||
|
|
||||||
|
buf[k + 0] := color.b;
|
||||||
|
buf[k + 1] := color.g;
|
||||||
|
buf[k + 2] := color.r;
|
||||||
|
|
||||||
|
k := k + 3;
|
||||||
|
end;
|
||||||
|
ostream.writebuffer(buf, size);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
begin
|
||||||
|
end.
|
1
build.sh
Normal file
1
build.sh
Normal file
|
@ -0,0 +1 @@
|
||||||
|
fpc gui.pas -Fu/usr/local/Cellar/fpc/3.0.4_1/lib/fpc/3.0.4/units/x86_64-darwin/fv
|
1
generate.sh
Normal file
1
generate.sh
Normal file
|
@ -0,0 +1 @@
|
||||||
|
./main 13 -100 1800
|
8
gui/constants.pas
Normal file
8
gui/constants.pas
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
unit constants;
|
||||||
|
|
||||||
|
interface
|
||||||
|
const cmAbout = 1001;
|
||||||
|
const cmGenerate = 1002;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
end.
|
214
gui/gui.pas
Normal file
214
gui/gui.pas
Normal file
|
@ -0,0 +1,214 @@
|
||||||
|
uses
|
||||||
|
Process, SysUtils,
|
||||||
|
App, Dialogs, Objects, Menus, Drivers, Views, MsgBox,
|
||||||
|
utils, constants;
|
||||||
|
|
||||||
|
type
|
||||||
|
PGenerateData = ^TGenerateData;
|
||||||
|
TGenerateData = record
|
||||||
|
path: string[128];
|
||||||
|
width: string[16];
|
||||||
|
height: string[16];
|
||||||
|
power: string[64];
|
||||||
|
zoom: string[64];
|
||||||
|
centerX: string[64];
|
||||||
|
centerY: string[64];
|
||||||
|
end;
|
||||||
|
|
||||||
|
PGeneratorWindow = ^TGeneratorWindow;
|
||||||
|
TGeneratorWindow = object(TDialog)
|
||||||
|
winRect: TRect;
|
||||||
|
curY: integer;
|
||||||
|
|
||||||
|
constructor Init;
|
||||||
|
procedure addField(caption: string; maxLength: integer);
|
||||||
|
procedure addButton(caption: string; command: integer);
|
||||||
|
end;
|
||||||
|
|
||||||
|
TMSApp = object(TApplication)
|
||||||
|
GeneratorWindow: PGeneratorWindow;
|
||||||
|
|
||||||
|
procedure InitStatusLine; virtual;
|
||||||
|
procedure InitMenuBar; virtual;
|
||||||
|
procedure HandleEvent(var Event: TEvent); virtual;
|
||||||
|
|
||||||
|
procedure NewWindow();
|
||||||
|
procedure GenerateMandelbrotSetImage();
|
||||||
|
procedure ShowAbout();
|
||||||
|
procedure ShowSuccess(fname: string; t: extended);
|
||||||
|
end;
|
||||||
|
|
||||||
|
var
|
||||||
|
MSApp: TMSApp;
|
||||||
|
GenerateData: TGenerateData;
|
||||||
|
|
||||||
|
procedure TMSApp.GenerateMandelbrotSetImage();
|
||||||
|
var
|
||||||
|
s: AnsiString;
|
||||||
|
startTime: int64;
|
||||||
|
success: boolean;
|
||||||
|
begin
|
||||||
|
GeneratorWindow^.GetData(GenerateData);
|
||||||
|
startTime := getTimestamp();
|
||||||
|
|
||||||
|
with GenerateData do begin
|
||||||
|
success := RunCommand('../main', [
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
power,
|
||||||
|
zoom,
|
||||||
|
centerX,
|
||||||
|
centerY,
|
||||||
|
path
|
||||||
|
], s);
|
||||||
|
end;
|
||||||
|
|
||||||
|
if (success) then begin
|
||||||
|
ShowSuccess(s, (getTimestamp() - startTime) / 1000);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TGeneratorWindow.addField(caption: string; maxLength: integer);
|
||||||
|
var
|
||||||
|
il: PInputLine;
|
||||||
|
r: TRect;
|
||||||
|
begin
|
||||||
|
caption := wrapFirstLetter(caption, '~');
|
||||||
|
|
||||||
|
r.assign(14, curY, winRect.b.x - 2, curY + 1);
|
||||||
|
il := New(PInputLine, Init(r, maxLength));
|
||||||
|
Insert(il);
|
||||||
|
r.assign(2, curY, 13, curY + 1);
|
||||||
|
Insert(New(PLabel, Init(r, caption, il)));
|
||||||
|
|
||||||
|
curY := curY + 2;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TGeneratorWindow.addButton(caption: string; command: integer);
|
||||||
|
var
|
||||||
|
r: TRect;
|
||||||
|
begin
|
||||||
|
r.assign(3, curY, winRect.b.x - 1, curY + 1);
|
||||||
|
Insert(New(PButton, Init(r, caption, command, bfNormal)));
|
||||||
|
|
||||||
|
curY := curY + 2;
|
||||||
|
end;
|
||||||
|
|
||||||
|
constructor TGeneratorWindow.Init();
|
||||||
|
var
|
||||||
|
wr: TRect;
|
||||||
|
begin
|
||||||
|
wr.assign(0, 0, 60, 19);
|
||||||
|
inherited Init(wr, 'Generator');
|
||||||
|
Options := Options or ofCentered;
|
||||||
|
HelpCtx := $F000;
|
||||||
|
|
||||||
|
winRect := wr;
|
||||||
|
curY := 2;
|
||||||
|
|
||||||
|
with GenerateData do begin
|
||||||
|
path := './images';
|
||||||
|
width := '512';
|
||||||
|
height := '512';
|
||||||
|
power := '2';
|
||||||
|
zoom := '1';
|
||||||
|
centerX := '0';
|
||||||
|
centerY := '0';
|
||||||
|
end;
|
||||||
|
|
||||||
|
addField('Path:', 128);
|
||||||
|
addField('Width:', 16);
|
||||||
|
addField('Height:', 16);
|
||||||
|
addField('Power:', 64);
|
||||||
|
addField('Zoom:', 64);
|
||||||
|
addField('Center X:', 64);
|
||||||
|
addField('Center Y:', 64);
|
||||||
|
|
||||||
|
addButton('Generate', cmGenerate);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TMSApp.NewWindow();
|
||||||
|
begin
|
||||||
|
GeneratorWindow := New(PGeneratorWindow, Init);
|
||||||
|
GeneratorWindow^.SetData(GenerateData);
|
||||||
|
InsertWindow(GeneratorWindow);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TMSApp.ShowAbout();
|
||||||
|
begin
|
||||||
|
MessageBox(
|
||||||
|
#3'Multibrot Set Generator GUI'#13 +
|
||||||
|
#3'Developed by Artem K.'#13 +
|
||||||
|
#3'MF BMSTU 2019',
|
||||||
|
nil,
|
||||||
|
mfInformation or mfOkButton
|
||||||
|
);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TMSApp.ShowSuccess(fname: string; t: extended);
|
||||||
|
begin
|
||||||
|
MessageBox(
|
||||||
|
#3'Set image was generated!'#13 +
|
||||||
|
'File name: ' + fname + #13 +
|
||||||
|
'Time spent: ' + FloatToStr(t) + ' s',
|
||||||
|
nil,
|
||||||
|
mfInformation or mfOkButton
|
||||||
|
);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TMSApp.HandleEvent(var Event: TEvent);
|
||||||
|
begin
|
||||||
|
inherited HandleEvent(Event);
|
||||||
|
|
||||||
|
if Event.What = evCommand then begin
|
||||||
|
case Event.Command of
|
||||||
|
cmNew: begin
|
||||||
|
NewWindow();
|
||||||
|
ClearEvent(Event);
|
||||||
|
end;
|
||||||
|
cmAbout: begin
|
||||||
|
ShowAbout();
|
||||||
|
ClearEvent(Event);
|
||||||
|
end;
|
||||||
|
cmGenerate: begin
|
||||||
|
GenerateMandelbrotSetImage();
|
||||||
|
ClearEvent(Event);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TMSApp.InitStatusLine();
|
||||||
|
var
|
||||||
|
r: TRect;
|
||||||
|
begin
|
||||||
|
GetExtent(r);
|
||||||
|
r.a.y := r.b.y - 1;
|
||||||
|
New(StatusLine, Init(r,
|
||||||
|
NewStatusDef(0, $EFFF,
|
||||||
|
NewStatusKey('~Alt+X~ Exit', kbAltX, cmQuit,
|
||||||
|
NewStatusKey('~F3~ New', kbF3, cmNew,
|
||||||
|
nil
|
||||||
|
)), nil)
|
||||||
|
));
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TMSApp.InitMenuBar();
|
||||||
|
var
|
||||||
|
r: TRect;
|
||||||
|
begin
|
||||||
|
GetExtent(r);
|
||||||
|
r.b.y := r.a.y + 1;
|
||||||
|
MenuBar := New(PMenuBar, Init(r, NewMenu(
|
||||||
|
NewItem('~N~ew', '', kbNoKey, cmNew, hcNew,
|
||||||
|
NewItem('~A~bout', '', kbNoKey, cmAbout, hcNoContext,
|
||||||
|
NewItem('~E~xit', 'Alt+X', kbAltX, cmQuit, hcExit,
|
||||||
|
nil)))))
|
||||||
|
);
|
||||||
|
end;
|
||||||
|
|
||||||
|
begin
|
||||||
|
MSApp.Init();
|
||||||
|
MSApp.Run();
|
||||||
|
MSApp.Done();
|
||||||
|
end.
|
34
gui/utils.pas
Normal file
34
gui/utils.pas
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
unit utils;
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses SysUtils;
|
||||||
|
|
||||||
|
function wrapFirstLetter(s: string; wrapper: string): string;
|
||||||
|
function getTimestamp(): int64;
|
||||||
|
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
function wrapFirstLetter(s: string; wrapper: string): string;
|
||||||
|
var
|
||||||
|
i: integer;
|
||||||
|
ts: string;
|
||||||
|
begin
|
||||||
|
ts := '';
|
||||||
|
for i := 2 to length(s) do begin
|
||||||
|
ts := ts + s[i];
|
||||||
|
end;
|
||||||
|
s := wrapper + s[1] + wrapper + ts;
|
||||||
|
wrapFirstLetter := s;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function GetTimestamp(): int64;
|
||||||
|
var
|
||||||
|
ts: TTimeStamp;
|
||||||
|
begin
|
||||||
|
ts := DateTimeToTimestamp(Now());
|
||||||
|
GetTimestamp := ts.time + ts.date * 24 * 60 * 60 * 1000;
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
2
images/generated/.gitignore
vendored
Normal file
2
images/generated/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
*
|
||||||
|
!.gitignore
|
BIN
images/k.bmp
Normal file
BIN
images/k.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 247 KiB |
240
main.pas
Normal file
240
main.pas
Normal file
|
@ -0,0 +1,240 @@
|
||||||
|
uses sysutils, BMPImage, ucomplex;
|
||||||
|
|
||||||
|
type
|
||||||
|
TArgs = record
|
||||||
|
width: longint; // TryStrToInt wants longint
|
||||||
|
height: longint;
|
||||||
|
power: longint;
|
||||||
|
zoom: extended;
|
||||||
|
center_x: extended;
|
||||||
|
center_y: extended;
|
||||||
|
out_path: string;
|
||||||
|
end;
|
||||||
|
TPxData = array of array of TColor;
|
||||||
|
|
||||||
|
const save_path = './images/generated/';
|
||||||
|
const help_text = 'Usage: command <width = 512> <height = 512> <power = 2> <zoom = 1> <centerX = 0> <centerY = 0> <out_path = ./images>';
|
||||||
|
|
||||||
|
function get_filename(base_name: string; zoom: extended; center_x: extended; center_y: extended): string;
|
||||||
|
var
|
||||||
|
z, cx, cy: string;
|
||||||
|
begin
|
||||||
|
z := FloatToStr(zoom);
|
||||||
|
cx := FloatToStr(center_x);
|
||||||
|
cy := FloatToStr(center_y);
|
||||||
|
|
||||||
|
get_filename := base_name + '_(z=' + z + ';cx=' + cx + ';cy=' + cy + ').bmp'
|
||||||
|
end;
|
||||||
|
|
||||||
|
type Point2D = object
|
||||||
|
x: extended;
|
||||||
|
y: extended;
|
||||||
|
|
||||||
|
procedure update(px: extended; py: extended);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure Point2D.update(px: extended; py: extended);
|
||||||
|
begin
|
||||||
|
x := px;
|
||||||
|
y := py;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{function f(x: integer): integer;
|
||||||
|
begin
|
||||||
|
f := round(2 * sin(x) + 3);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function check_a(x: integer; y: integer): boolean;
|
||||||
|
begin
|
||||||
|
check_a := sqr(x - 50) + sqr(y - 50) - 6 <= 900;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function fr(x: integer; c: integer): integer;
|
||||||
|
begin
|
||||||
|
fr := sqr(x) + c;
|
||||||
|
end;}
|
||||||
|
|
||||||
|
function fc(x: complex; c: complex; n: integer): complex;
|
||||||
|
begin
|
||||||
|
fc := complex_sum(x.power(n), c);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function translate_point(p: Point2D; width: integer; height: integer): Point2D;
|
||||||
|
var
|
||||||
|
base_zoom: integer;
|
||||||
|
begin
|
||||||
|
base_zoom := round(width * 0.8) div 2;
|
||||||
|
p.update((p.x - width / 2) / base_zoom, (p.y - height / 2) / base_zoom);
|
||||||
|
translate_point := p;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function multibrot_check(x: extended; y: extended; n: integer): integer;
|
||||||
|
// f defined as f(x) = x^2 + c, where c (complex number) is a constant
|
||||||
|
// point (x, y) is in Mandelbrot's set if f(f(...f(0))) converges, c = x + yi
|
||||||
|
var
|
||||||
|
i: integer;
|
||||||
|
v, c: complex;
|
||||||
|
begin
|
||||||
|
i := 0;
|
||||||
|
v.update(0, 0);
|
||||||
|
while (i < 255) and (v.length() <= 2) do begin
|
||||||
|
c.update(x, y);
|
||||||
|
v := fc(v, c, n);
|
||||||
|
inc(i);
|
||||||
|
end;
|
||||||
|
multibrot_check := i;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure setDefaultArgs(var args: TArgs);
|
||||||
|
begin
|
||||||
|
with args do begin
|
||||||
|
width := 512;
|
||||||
|
height := 512;
|
||||||
|
power := 2;
|
||||||
|
zoom := 1;
|
||||||
|
center_x := 0;
|
||||||
|
center_y := 0;
|
||||||
|
out_path := './images';
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function getArgs(var args: TArgs): boolean;
|
||||||
|
var
|
||||||
|
error: boolean;
|
||||||
|
begin
|
||||||
|
error := false;
|
||||||
|
|
||||||
|
if (ParamCount > 7) then begin
|
||||||
|
error := true;
|
||||||
|
end else begin
|
||||||
|
if (ParamCount >= 1) then begin
|
||||||
|
if (not TryStrToInt(ParamStr(1), args.width)) then error := true;
|
||||||
|
end;
|
||||||
|
if (ParamCount >= 2) then begin
|
||||||
|
if (not TryStrToInt(ParamStr(2), args.height)) then error := true;
|
||||||
|
end;
|
||||||
|
if (ParamCount >= 3) then begin
|
||||||
|
if (not TryStrToInt(ParamStr(3), args.power)) then error := true;
|
||||||
|
end;
|
||||||
|
if (ParamCount >= 4) then begin
|
||||||
|
if (not TryStrToFloat(ParamStr(4), args.zoom)) then error := true;
|
||||||
|
end;
|
||||||
|
if (ParamCount >= 5) then begin
|
||||||
|
if (not TryStrToFloat(ParamStr(5), args.center_x)) then error := true;
|
||||||
|
end;
|
||||||
|
if (ParamCount >= 6) then begin
|
||||||
|
if (not TryStrToFloat(ParamStr(6), args.center_y)) then error := true;
|
||||||
|
end;
|
||||||
|
if (ParamCount = 7) then begin
|
||||||
|
args.out_path := ParamStr(7);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
getArgs := not error;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function generateMultibrot(
|
||||||
|
width: integer; height: integer;
|
||||||
|
power: longint; zoom: extended; center_x: extended; center_y: extended
|
||||||
|
): TPxData;
|
||||||
|
var
|
||||||
|
color: TColor;
|
||||||
|
i, j, mb_out: integer;
|
||||||
|
p: Point2D;
|
||||||
|
palette: array[0..255] of TColor;
|
||||||
|
px_data: TPxData;
|
||||||
|
begin
|
||||||
|
setLength(px_data, width, height);
|
||||||
|
|
||||||
|
color.reset();
|
||||||
|
|
||||||
|
for i := 0 to 254 do begin
|
||||||
|
palette[i].set_color(i, abs(64 - i), abs(128 - i));
|
||||||
|
end;
|
||||||
|
palette[255].set_color(0, 0, 0);
|
||||||
|
|
||||||
|
for i := 0 to width - 1 do begin
|
||||||
|
for j := 0 to height - 1 do begin
|
||||||
|
p.update(i, j);
|
||||||
|
p := translate_point(p, width, height);
|
||||||
|
|
||||||
|
p.x := (p.x / zoom) + center_x;
|
||||||
|
p.y := (p.y / zoom) + center_y;
|
||||||
|
|
||||||
|
color.reset();
|
||||||
|
if ((abs(p.x) < 0.000001) or (abs(p.y) < 0.000001)) then begin
|
||||||
|
color.g := 255;
|
||||||
|
end else begin
|
||||||
|
mb_out := multibrot_check(p.x, p.y, power);
|
||||||
|
color := palette[mb_out];
|
||||||
|
end;
|
||||||
|
|
||||||
|
px_data[i][j] := color;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
generateMultibrot := px_data;
|
||||||
|
end;
|
||||||
|
|
||||||
|
var
|
||||||
|
args: TArgs;
|
||||||
|
img: TBMPImage;
|
||||||
|
out_path, fname: string;
|
||||||
|
px_data: TPxData;
|
||||||
|
begin
|
||||||
|
{img.init();
|
||||||
|
img.open('./images/k.bmp');
|
||||||
|
|
||||||
|
// draw sin
|
||||||
|
for i := 0 to img.get_width() - 1 do begin
|
||||||
|
color.set_color(255, 0, 0);
|
||||||
|
img.pixel_data[i][f(i)] := color;
|
||||||
|
end;
|
||||||
|
// convert color
|
||||||
|
for i := 0 to img.get_width() - 1 do begin
|
||||||
|
for j := 0 to img.get_height() - 1 do begin
|
||||||
|
color := img.pixel_data[i][j];
|
||||||
|
new_color.r := color.b;
|
||||||
|
new_color.g := color.g;
|
||||||
|
new_color.b := color.r;
|
||||||
|
img.pixel_data[i][j] := new_color;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
img.set_width(400);
|
||||||
|
img.set_height(400);
|
||||||
|
img.save('./images/generated/k_generic.bmp', false);
|
||||||
|
img.done();}
|
||||||
|
|
||||||
|
setDefaultArgs(args);
|
||||||
|
|
||||||
|
if (getArgs(args)) then begin
|
||||||
|
px_data := generateMultibrot(args.width, args.height, args.power, args.zoom, args.center_x, args.center_y);
|
||||||
|
|
||||||
|
img.init(px_data);
|
||||||
|
|
||||||
|
fname := get_filename('mb' + IntToStr(args.power) + '_set', args.zoom, args.center_x, args.center_y);
|
||||||
|
out_path := args.out_path + '/' + fname;
|
||||||
|
|
||||||
|
img.save(out_path, false);
|
||||||
|
img.done();
|
||||||
|
|
||||||
|
writeln(fname);
|
||||||
|
|
||||||
|
{color.set_color(255, 255, 255);
|
||||||
|
img.init(100, 100, color);
|
||||||
|
color.set_color(0, 255, 0);
|
||||||
|
for i := 0 to img.get_width() - 1 do begin
|
||||||
|
for j := 0 to img.get_height() - 1 do begin
|
||||||
|
if (check_a(i, j)) then begin
|
||||||
|
img.pixel_data[i][j] := color;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
img.save('./images/generated/circle.bmp', false);
|
||||||
|
img.done();}
|
||||||
|
end else begin
|
||||||
|
writeln(help_text);
|
||||||
|
end;
|
||||||
|
end.
|
||||||
|
|
71
ucomplex.pas
Normal file
71
ucomplex.pas
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
unit ucomplex;
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
type complex = object
|
||||||
|
r: extended;
|
||||||
|
i: extended;
|
||||||
|
function length(): extended;
|
||||||
|
function squared(): complex;
|
||||||
|
function mult(a: complex): complex;
|
||||||
|
function power(n: integer): complex;
|
||||||
|
procedure update(re: extended; im: extended);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function complex_sum(a: complex; b: complex): complex;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
procedure complex.update(re: extended; im: extended);
|
||||||
|
begin
|
||||||
|
r := re;
|
||||||
|
i := im;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function complex.length(): extended;
|
||||||
|
begin
|
||||||
|
length := sqrt(r * r + i * i);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function complex.squared(): complex;
|
||||||
|
var
|
||||||
|
res: complex;
|
||||||
|
begin
|
||||||
|
res.r := sqr(r) - sqr(i);
|
||||||
|
res.i := 2 * r * i;
|
||||||
|
squared := res;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function complex.mult(a: complex): complex;
|
||||||
|
var
|
||||||
|
res: complex;
|
||||||
|
begin
|
||||||
|
res.r := r * a.r - i * a.i;
|
||||||
|
res.i := r * a.i + i * a.r;
|
||||||
|
mult := res;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function complex.power(n: integer): complex;
|
||||||
|
var
|
||||||
|
j: integer;
|
||||||
|
c, res: complex;
|
||||||
|
begin
|
||||||
|
c.update(r, i);
|
||||||
|
res.update(r, i);
|
||||||
|
for j := 1 to n - 1 do begin
|
||||||
|
res := res.mult(c);
|
||||||
|
end;
|
||||||
|
power := res;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function complex_sum(a: complex; b: complex): complex;
|
||||||
|
var
|
||||||
|
res: complex;
|
||||||
|
begin
|
||||||
|
res.r := a.r + b.r;
|
||||||
|
res.i := a.i + b.i;
|
||||||
|
complex_sum := res;
|
||||||
|
end;
|
||||||
|
|
||||||
|
begin
|
||||||
|
end.
|
Loading…
Reference in New Issue
Block a user