Feature: function generation added to GUI

This commit is contained in:
KoroLion 2020-05-22 18:18:34 +03:00
parent 1f4577657e
commit c55277b590
9 changed files with 179 additions and 98 deletions

2
.gitignore vendored
View File

@ -1,3 +1,5 @@
images/*
*.o *.o
*.ppu *.ppu
*.exe *.exe

View File

@ -1,9 +1,15 @@
rm generator.exe rm multibrot_imaging.exe
rm function_imaging.exe
rm gui.exe rm gui.exe
cd src cd src
fpc mandelbrot_imaging.pas fpc mandelbrot_imaging.pas
mv mandelbrot_imaging.exe ../generator.exe mv mandelbrot_imaging.exe ../multibrot_imaging.exe
fpc function_imaging.pas
mv function_imaging.exe ../function_imaging.exe
cd gui cd gui
fpc gui.pas fpc gui.pas
mv gui.exe ../../gui.exe mv gui.exe ../../gui.exe

1
multibrot_images/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*.bmp

View File

@ -106,6 +106,7 @@ begin
pxData[x][y].set_color(255, 255, 255); pxData[x][y].set_color(255, 255, 255);
end; end;
end else begin end else begin
fParser.expression := stringReplace(fParser.expression, '=', '-', []);
fRes1 := fParser.evaluate().resFloat; fRes1 := fParser.evaluate().resFloat;
// finding derivative of a function at this point (numeric) // finding derivative of a function at this point (numeric)

View File

@ -2,7 +2,10 @@ unit constants;
interface interface
const cmAbout = 1001; const cmAbout = 1001;
const cmGenerate = 1002; const cmMbGenerate = 1002;
const cmFnGenerate = 1003;
const cmMbNew = 1004;
const cmFnNew = 1005;
implementation implementation
end. end.

View File

@ -4,8 +4,8 @@ uses
utils, constants; utils, constants;
type type
PGenerateData = ^TGenerateData; PMbGenerateData = ^TMbGenerateData;
TGenerateData = record TMbGenerateData = record
path: string[128]; path: string[128];
width: string[16]; width: string[16];
height: string[16]; height: string[16];
@ -15,46 +15,72 @@ type
centerY: string[64]; centerY: string[64];
end; end;
PFnGenerateData = ^TFnGenerateData;
TFnGenerateData = record
path: string[128];
width: string[16];
height: string[16];
fn: string[255];
zoom: string[64];
centerX: string[64];
centerY: string[64];
end;
PGeneratorWindow = ^TGeneratorWindow; PGeneratorWindow = ^TGeneratorWindow;
TGeneratorWindow = object(TDialog) TGeneratorWindow = object(TDialog)
pGeneratingBtn: PButton; pGeneratingBtn: PButton;
winRect: TRect; winRect: TRect;
curY: integer; curY: integer;
constructor Init;
procedure addField(caption: string; maxLength: integer); procedure addField(caption: string; maxLength: integer);
function addButton(caption: string; command: integer): PButton; function addButton(caption: string; command: integer): PButton;
end; end;
PMbGeneratorWindow = ^TMbGeneratorWindow;
TMbGeneratorWindow = object(TGeneratorWindow)
constructor Init;
end;
PFnGeneratorWindow = ^TFnGeneratorWindow;
TFnGeneratorWindow = object(TGeneratorWindow)
constructor Init;
end;
TMSApp = object(TApplication) TMSApp = object(TApplication)
GeneratorWindow: PGeneratorWindow; MbGeneratorWindow: PMbGeneratorWindow;
FnGeneratorWindow: PFnGeneratorWindow;
procedure InitStatusLine; virtual; procedure InitStatusLine; virtual;
procedure InitMenuBar; virtual; procedure InitMenuBar; virtual;
procedure HandleEvent(var Event: TEvent); virtual; procedure HandleEvent(var Event: TEvent); virtual;
procedure NewWindow(); procedure NewMbWindow();
procedure GenerateMandelbrotSetImage(); procedure NewFnWindow();
procedure GenerateMultibrotSetImage();
procedure GenerateFunctionImage();
procedure ShowAbout(); procedure ShowAbout();
procedure ShowSuccess(fname: string; t: extended); procedure ShowSuccess(fname: string; t: extended);
end; end;
var var
MSApp: TMSApp; MSApp: TMSApp;
GenerateData: TGenerateData; MbGenerateData: TMbGenerateData;
FnGenerateData: TFnGenerateData;
procedure TMSApp.GenerateMandelbrotSetImage(); procedure TMSApp.GenerateMultibrotSetImage();
var var
s: AnsiString; s: AnsiString;
startTime: int64; startTime: int64;
success: boolean; success: boolean;
begin begin
GeneratorWindow^.GetData(GenerateData); MbGeneratorWindow^.GetData(MbGenerateData);
startTime := getTimestamp(); startTime := getTimestamp();
GeneratorWindow^.pGeneratingBtn^.show(); MbGeneratorWindow^.pGeneratingBtn^.show();
with GenerateData do begin with MbGenerateData do begin
success := RunCommand('./generator', [ success := RunCommand('./multibrot_imaging', [
width, width,
height, height,
power, power,
@ -64,7 +90,42 @@ begin
path path
], s); ], s);
end; end;
GeneratorWindow^.pGeneratingBtn^.hide(); MbGeneratorWindow^.pGeneratingBtn^.hide();
if (success) then begin
ShowSuccess(s, (getTimestamp() - startTime) / 1000);
end else begin
MessageBox(
#3'Error'#13 +
#3'Unable to execute generator!'#13,
nil,
mfInformation or mfOkButton
);
end;
end;
procedure TMSApp.GenerateFunctionImage();
var
s: AnsiString;
startTime: int64;
success: boolean;
begin
FnGeneratorWindow^.GetData(FnGenerateData);
startTime := getTimestamp();
FnGeneratorWindow^.pGeneratingBtn^.show();
with FnGenerateData do begin
success := RunCommand('./function_imaging', [
width,
height,
fn,
zoom,
centerX,
centerY,
path
], s);
end;
FnGeneratorWindow^.pGeneratingBtn^.hide();
if (success) then begin if (success) then begin
ShowSuccess(s, (getTimestamp() - startTime) / 1000); ShowSuccess(s, (getTimestamp() - startTime) / 1000);
@ -108,20 +169,20 @@ begin
addButton := pbtn; addButton := pbtn;
end; end;
constructor TGeneratorWindow.Init(); constructor TMbGeneratorWindow.Init();
var var
r: TRect; r: TRect;
begin begin
r.assign(0, 0, 60, 19); r.assign(0, 0, 60, 19);
inherited Init(r, 'Mandelbrot generator'); inherited Init(r, 'Multibrot generator');
Options := Options or ofCentered; Options := Options or ofCentered;
HelpCtx := $F000; HelpCtx := $F000;
winRect := r; winRect := r;
curY := 2; curY := 2;
with GenerateData do begin with MbGenerateData do begin
path := './generated_images'; path := './multibrot_images';
width := '512'; width := '512';
height := '512'; height := '512';
power := '2'; power := '2';
@ -138,17 +199,60 @@ begin
addField('Center X:', 64); addField('Center X:', 64);
addField('Center Y:', 64); addField('Center Y:', 64);
addButton('Generate', cmGenerate); addButton('Generate', cmMbGenerate);
curY := curY - 2; curY := curY - 2;
pGeneratingBtn := addButton('Generating...', 0); pGeneratingBtn := addButton('Generating...', 0);
pGeneratingBtn^.hide(); pGeneratingBtn^.hide();
end; end;
procedure TMSApp.NewWindow(); constructor TFnGeneratorWindow.Init();
var
r: TRect;
begin begin
GeneratorWindow := New(PGeneratorWindow, Init); r.assign(0, 0, 60, 19);
GeneratorWindow^.SetData(GenerateData); inherited Init(r, 'Function generator');
InsertWindow(GeneratorWindow); Options := Options or ofCentered;
HelpCtx := $F000;
winRect := r;
curY := 2;
with FnGenerateData do begin
path := './function_images';
width := '512';
height := '512';
fn := 'sin(x*x*x * y*y) = cos(x*x * y*y*y)';
zoom := '10';
centerX := '0';
centerY := '0';
end;
addField('Path:', 128);
addField('Width:', 16);
addField('Height:', 16);
addField('Function:', 255);
addField('Zoom:', 64);
addField('Center X:', 64);
addField('Center Y:', 64);
addButton('Generate', cmFnGenerate);
curY := curY - 2;
pGeneratingBtn := addButton('Generating...', 0);
pGeneratingBtn^.hide();
end;
procedure TMSApp.NewFnWindow();
begin
FnGeneratorWindow := New(PFnGeneratorWindow, Init);
FnGeneratorWindow^.SetData(FnGenerateData);
InsertWindow(FnGeneratorWindow);
end;
procedure TMSApp.NewMbWindow();
begin
MbGeneratorWindow := New(PMbGeneratorWindow, Init);
MbGeneratorWindow^.SetData(MbGenerateData);
InsertWindow(MbGeneratorWindow);
end; end;
procedure TMSApp.ShowAbout(); procedure TMSApp.ShowAbout();
@ -165,7 +269,7 @@ end;
procedure TMSApp.ShowSuccess(fname: string; t: extended); procedure TMSApp.ShowSuccess(fname: string; t: extended);
begin begin
MessageBox( MessageBox(
#3'Set image was generated!'#13 + #3'Image was generated!'#13 +
'File name: ' + fname + #13 + 'File name: ' + fname + #13 +
'Time spent: ' + FloatToStr(t) + ' s', 'Time spent: ' + FloatToStr(t) + ' s',
nil, nil,
@ -179,16 +283,24 @@ begin
if Event.What = evCommand then begin if Event.What = evCommand then begin
case Event.Command of case Event.Command of
cmNew: begin cmMbNew: begin
NewWindow(); NewMbWindow();
ClearEvent(Event);
end;
cmFnNew: begin
NewFnWindow();
ClearEvent(Event); ClearEvent(Event);
end; end;
cmAbout: begin cmAbout: begin
ShowAbout(); ShowAbout();
ClearEvent(Event); ClearEvent(Event);
end; end;
cmGenerate: begin cmMbGenerate: begin
GenerateMandelbrotSetImage(); GenerateMultibrotSetImage();
ClearEvent(Event);
end;
cmFnGenerate: begin
GenerateFunctionImage();
ClearEvent(Event); ClearEvent(Event);
end; end;
end; end;
@ -204,7 +316,7 @@ begin
New(StatusLine, Init(r, New(StatusLine, Init(r,
NewStatusDef(0, $EFFF, NewStatusDef(0, $EFFF,
NewStatusKey('~Alt+X~ Exit', kbAltX, cmQuit, NewStatusKey('~Alt+X~ Exit', kbAltX, cmQuit,
NewStatusKey('~F3~ New', kbF3, cmNew, NewStatusKey('~F3~ New', kbF3, cmMbNew,
nil nil
)), nil) )), nil)
)); ));
@ -217,10 +329,11 @@ begin
GetExtent(r); GetExtent(r);
r.b.y := r.a.y + 1; r.b.y := r.a.y + 1;
MenuBar := New(PMenuBar, Init(r, NewMenu( MenuBar := New(PMenuBar, Init(r, NewMenu(
NewItem('~M~andelbrot', '', kbNoKey, cmNew, hcNew, NewItem('~M~ultibrot', '', kbNoKey, cmMbNew, hcNew,
NewItem('~F~unctions', '', kbNoKey, cmFnNew, hcNew,
NewItem('~A~bout', '', kbNoKey, cmAbout, hcNoContext, NewItem('~A~bout', '', kbNoKey, cmAbout, hcNoContext,
NewItem('~E~xit', 'Alt+X', kbAltX, cmQuit, hcExit, NewItem('~E~xit', 'Alt+X', kbAltX, cmQuit, hcExit,
nil))))) nil))))))
); );
end; end;

View File

@ -1,10 +1,14 @@
uses sysutils, BMPImage, ucomplex, utils; uses sysutils, BMPImage, ucomplex, utils;
// todo: generalize get_filename function
// todo: camelCase
// todo: multibrot fraction power
type type
TArgs = record TArgs = record
power: longint;
width: longint; // TryStrToInt wants longint width: longint; // TryStrToInt wants longint
height: longint; height: longint;
power: longint;
zoom: extended; zoom: extended;
center_x: extended; center_x: extended;
center_y: extended; center_y: extended;
@ -12,23 +16,24 @@ type
end; end;
const save_path = './images/generated/'; 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>'; const help_text = 'Usage: command <power = 2> <width = 512> <height = 512> <zoom = 1> <centerX = 0> <centerY = 0> <out_path = ./multibrot_images>';
{function f(x: integer): integer; 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;
function f(x: integer): integer;
begin begin
f := round(2 * sin(x) + 3); f := round(2 * sin(x) + 3);
end; 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; function fc(x: complex; c: complex; n: integer): complex;
begin begin
fc := complex_sum(x.power(n), c); fc := complex_sum(x.power(n), c);
@ -63,9 +68,9 @@ end;
procedure setDefaultArgs(var args: TArgs); procedure setDefaultArgs(var args: TArgs);
begin begin
with args do begin with args do begin
power := 2;
width := 512; width := 512;
height := 512; height := 512;
power := 2;
zoom := 1; zoom := 1;
center_x := 0; center_x := 0;
center_y := 0; center_y := 0;
@ -157,30 +162,6 @@ var
out_path, fname: string; out_path, fname: string;
px_data: TPxData; px_data: TPxData;
begin 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); setDefaultArgs(args);
if (getArgs(args)) then begin if (getArgs(args)) then begin
@ -195,19 +176,6 @@ begin
img.done(); img.done();
writeln(fname); 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 end else begin
writeln(help_text); writeln(help_text);
end; end;

View File

@ -12,8 +12,6 @@ type
procedure update(px: extended; py: extended); procedure update(px: extended; py: extended);
end; end;
function get_filename(base_name: string; zoom: extended; center_x: extended; center_y: extended): string;
implementation implementation
procedure Point2D.update(px: extended; py: extended); procedure Point2D.update(px: extended; py: extended);
@ -22,16 +20,5 @@ begin
y := py; y := py;
end; end;
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;
begin begin
end. end.