diff --git a/build.bat b/build.bat index fc8b8e2..5a24833 100644 --- a/build.bat +++ b/build.bat @@ -2,8 +2,8 @@ rm generator.exe rm gui.exe cd src -fpc main.pas -mv main.exe ../generator.exe +fpc mandelbrot_imaging.pas +mv mandelbrot_imaging.exe ../generator.exe cd gui fpc gui.pas mv gui.exe ../../gui.exe diff --git a/src/BMPImage.pas b/src/BMPImage.pas index 850dc62..4d5831a 100644 --- a/src/BMPImage.pas +++ b/src/BMPImage.pas @@ -13,7 +13,7 @@ type procedure set_color(tr: byte; tg: byte; tb: byte); procedure reset(); end; - + TPxData = array of array of TColor; TBMPImage = object @@ -37,6 +37,7 @@ type function get_height(): integer; procedure open(path: string); + procedure save(path: string); procedure save(path: string; monochrome: boolean); end; @@ -196,6 +197,11 @@ begin end; end; +procedure TBMPImage.save(path: string); +begin + save(path, false); +end; + procedure TBMPImage.save(path: string; monochrome: boolean); var ostream: TFileStream; diff --git a/src/function_imaging.pas b/src/function_imaging.pas new file mode 100644 index 0000000..8bb1345 --- /dev/null +++ b/src/function_imaging.pas @@ -0,0 +1,152 @@ +{$MODE OBJFPC} + +uses fpexprpars, sysutils, + BMPImage, utils; + +type + TArgs = record + width: longint; + height: longint; + f: string; + zoom: extended; + centerX: extended; + centerY: extended; + outPath: string; + end; + +procedure setDefaultArgs(var args: TArgs); +begin + with args do begin + width := 512; + height := 512; + f := 'sin(x) - y'; + zoom := 10; + centerX := 0; + centerY := 0; + outPath := './function_images'; + end; +end; + +procedure getArgs(var args: TArgs); +var + param: string; +begin + try + args.width := strToInt(ParamStr(1)); + args.height := strToInt(ParamStr(2)); + args.f := ParamStr(3); + args.zoom := StrToFloat(ParamStr(4)) * 10; + args.centerX := StrToFloat(ParamStr(5)); + args.centerY := StrToFloat(ParamStr(6)); + + param := ParamStr(7); + if (length(param) > 0) then begin + args.outPath := param; + end; + except + end; +end; + +function getFilename(args: TArgs): string; +var + fname: string; + fn: string; +begin + fname := '{f}_(z={z},cx={cx},cy={cy},WxH={w}x{h}).bmp'; + + fn := stringReplace(args.f, ' ', '', [rfReplaceAll]); + fname := StringReplace(fname, '{f}', fn, []); + fname := StringReplace(fname, '{z}', floatToStr(args.zoom), []); + fname := StringReplace(fname, '{cx}', floatToStr(args.centerX), []); + fname := StringReplace(fname, '{cy}', floatToStr(args.centerY), []); + fname := StringReplace(fname, '{w}', intToStr(args.width), []); + fname := StringReplace(fname, '{h}', intToStr(args.height), []); + + getFilename := fname; +end; + +function getPxData(args: TArgs): TPxData; +var + pxData: TPxData; + fParser: TFPExpressionParser; + argX, argY: TFPExprIdentifierDef; + x, y, intense: integer; + convX, convY, fRes: extended; + ineq: boolean; +begin + setLength(pxData, args.width, args.height); + fParser := TFPExpressionParser.create(nil); + + try + fParser.builtIns := [bcMath]; + argX := fParser.identifiers.addFloatVariable('x', 0.0); + argY := fParser.identifiers.addFloatVariable('y', 0.0); + //fParser.expression := 'sin(x*x*x * y*y) - cos(x*x * y*y*y)'; + fParser.expression := args.f; + + ineq := (pos('>', fParser.expression) <> 0) or (pos('>=', fParser.expression) <> 0) or (pos('<', fParser.expression) <> 0) or (pos('<=', fParser.expression) <> 0); + + for y := 0 to args.height - 1 do begin + for x := 0 to args.width - 1 do begin + convX := ((x - args.width / 2) / args.zoom) + args.centerX; + convY := -(y - args.height / 2) / args.zoom + args.centerY; + + if (abs(convX) < (1 / args.zoom)) or (abs(convY) < (1 / args.zoom)) then begin + pxData[x][y].set_color(0, 255, 0); + end else begin + try + argX.asFloat := convX; + argY.asFloat := convY; + if (ineq) then begin + if (fParser.evaluate().resBoolean) then begin + pxData[x][y].set_color(0, 0, 0); + end else begin + pxData[x][y].set_color(255, 255, 255); + end; + end else begin + fRes := fParser.evaluate().resFloat; + + if (abs(fRes) > (1 / args.zoom)) then begin + pxData[x][y].set_color(255, 255, 255); + end else begin + intense := round(abs(fRes) / (1 / args.zoom)); + pxData[x][y].set_color(intense, intense, intense); + end; + end; + except + pxData[x][y].set_color(255, 255, 255); + end; + end; + end; + end; + finally + fParser.free(); + end; + + getPxData := pxData; +end; + +var + args: TArgs; + outPath: string; + filename: string; + + img: TBMPImage; + color: TColor; + pxData: TPxData; +begin + setDefaultArgs(args); + getArgs(args); + + pxData := getPxData(args); + + color.set_color(255, 255, 255); + img.init(args.width, args.height, color); + img.set_pixel_data(pxData); + + filename := getFilename(args); + outPath := args.outPath + '/' + filename; + img.save(outPath); + + writeln('Image generated and saved at ' + outPath); +end. \ No newline at end of file diff --git a/src/main.pas b/src/mandelbrot_imaging.pas similarity index 90% rename from src/main.pas rename to src/mandelbrot_imaging.pas index 760bfb8..585e51a 100644 --- a/src/main.pas +++ b/src/mandelbrot_imaging.pas @@ -1,4 +1,4 @@ -uses sysutils, BMPImage, ucomplex; +uses sysutils, BMPImage, ucomplex, utils; type TArgs = record @@ -10,35 +10,10 @@ type center_y: extended; out_path: string; end; - TPxData = array of array of TColor; const save_path = './images/generated/'; const help_text = 'Usage: command '; -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); diff --git a/src/utils.pas b/src/utils.pas new file mode 100644 index 0000000..a5b07dc --- /dev/null +++ b/src/utils.pas @@ -0,0 +1,37 @@ +unit utils; + +interface + +uses sysutils; + +type + Point2D = object + x: extended; + y: extended; + + procedure update(px: extended; py: extended); + end; + +function get_filename(base_name: string; zoom: extended; center_x: extended; center_y: extended): string; + +implementation + +procedure Point2D.update(px: extended; py: extended); +begin + x := px; + y := py; +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 +end. \ No newline at end of file