From aaa64e36cd5ac1cc6077d38505c645f4c316b78e Mon Sep 17 00:00:00 2001 From: JP Appel Date: Fri, 26 Apr 2024 14:47:56 -0400 Subject: add cli args for degree, constant, radius --- src/fractals.c | 134 ++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 105 insertions(+), 29 deletions(-) (limited to 'src/fractals.c') diff --git a/src/fractals.c b/src/fractals.c index 395ccdb..f994265 100644 --- a/src/fractals.c +++ b/src/fractals.c @@ -10,12 +10,14 @@ #include "precision.h" #include "fractals.h" +#define EXIT_BAD_ARGUMENT 2 + #ifndef NUM_RUNS #define NUM_RUNS 5 #endif void print_usage(FILE* file, const char* program_name){ - fprintf(file, "Usage: %s [-v] [-i iterations] [-x x_res] [-y y_res] [-z magnification] [-l lower_left] [-u upper_right] [-o output_grid] -f fractal\n", program_name); + fprintf(file, "Usage: %s [-v] [-i iterations] [-x x_res] [-y y_res] [-z magnification] [-d degree] [-c constant] [-r radius] [-l lower_left] [-u upper_right] [-o output_grid] -f fractal\n", program_name); } void print_help(){ @@ -23,15 +25,20 @@ void print_help(){ " -i, --iterations the number of iterations (default: 100)\n" " -x, --x-res the horizontal resolution (default: terminal width)\n" " -y, --y-res the vertical resolution (default: terminal height)\n" - " -l, --lower-left Set the lower left corner of the fractal area (default: -2-2i)\n" - " -u, --upper-right Set the upper right corner of the fractal area (default: 2+2i)\n" + " -l, --lower-left Set the lower left corner of the fractal area (default: -2.0+-2.0i)\n" + " -u, --upper-right Set the upper right corner of the fractal area (default: 2.0+2.0i)\n" " -z, --magnification Set the magnification factor (default: 1)\n" + " -d, --degree Set the degree for fractals that use it (default: 1)\n" + " -c, --constant Set the constant for fractals that use it (default: 0+0i)\n" + " -r, --radius Set the radius for fractals that use it (default: 2)\n" " -o, --output the output filename (default: fractal.grid)\n" " -f, --fractal the fractal type (default: mandelbrot)\n" " supported fractals: mandelbrot, tricorn, multibrot, multicorn, burning_ship, julia\n" " -p, --performance print performance info\n" " -v, --verbose verbose output\n" - " -h, --help prints this help message\n"); + " -h, --help prints this help message\n" + "\ndegree is mutually exclusive with constant and radius\n" + "\nExits with a status code of 1 if the program encounters an error, exits with 2 if an argument is incorrect\n"); } void print_info(const char* program_name){ @@ -53,6 +60,13 @@ double time_fractal(fractal_generator generator, grid_t* grid, grid_gen_params* return (end.tv_sec - start.tv_sec + (end.tv_nsec - start.tv_nsec) * 1.0e-9) / NUM_RUNS; } +static inline void parse_complex(const char* string, complex_t* z){ + if(sscanf(string, CFORMAT "+" CFORMAT "i", &z->re, &z->im) != 2){ + fprintf(stderr, "Failed while parsing complex number: %s , is it formatted correctly?\n", string); + exit(EXIT_FAILURE); + }; +} + int main(const int argc, char *argv[]) { struct winsize w; ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); @@ -66,11 +80,24 @@ int main(const int argc, char *argv[]) { CBASE magnification = 1; bool verbose = false; bool performance = false; - grid_gen_params* params = NULL; + + //degree is mutually exclusive with constant and radius + bool param_is_degree = false; + bool param_is_cr = false; + CBASE degree = 1; + complex_t constant = { .re = 0, .im = 0}; + double radius = 2; + char* fractal_name = "mandelbrot"; fractal_generator generator = mandelbrot_grid; char* output_filename = "fractal.grid"; + grid_gen_params* params = malloc(sizeof(grid_gen_params)); + if(!params){ + fprintf(stderr, "Failed to allocate memory: %zu bytes\n", sizeof(grid_gen_params)); + exit(EXIT_FAILURE); + } + static struct option long_options[] = { {"iterations", required_argument, NULL, 'i'}, {"x-res", required_argument, NULL, 'x'}, @@ -78,6 +105,9 @@ int main(const int argc, char *argv[]) { {"lower-left", required_argument, NULL, 'l'}, {"upper-right", required_argument, NULL, 'u'}, {"magnification", required_argument, NULL, 'z'}, + {"degree", required_argument, NULL, 'd'}, + {"constant", required_argument, NULL, 'c'}, + {"radius", required_argument, NULL, 'r'}, {"output", required_argument, NULL, 'o'}, {"verbose", no_argument, NULL, 'v'}, {"performance", no_argument, NULL, 'p'}, @@ -88,7 +118,7 @@ int main(const int argc, char *argv[]) { //parse command line arguments int opt; - while((opt = getopt_long(argc, argv, "i:x:y:l:u:z:o:vphf:", long_options, NULL)) != -1){ + while((opt = getopt_long(argc, argv, "i:x:y:l:u:z:d:c:r:o:vphf:", long_options, NULL)) != -1){ switch(opt){ case 'i': iterations = strtoull(optarg, NULL, 10); @@ -100,56 +130,94 @@ int main(const int argc, char *argv[]) { y_res = strtoull(optarg, NULL, 10); break; case 'l': - sscanf(optarg, CFORMAT"+"CFORMAT"i", &lower_left.re, &lower_left.im); + parse_complex(optarg, &lower_left); break; case 'u': - sscanf(optarg, CFORMAT"+"CFORMAT"i", &upper_right.re, &upper_right.im); + parse_complex(optarg, &upper_right); break; case 'o': output_filename = optarg; break; + case 'd': + param_is_degree = true; + if(param_is_cr){ + fprintf(stderr, "--degree and --constant --radius are mutually exclusive, exiting\n"); + exit(EXIT_BAD_ARGUMENT); + } + if(sscanf(optarg, CFORMAT, °ree) != 1){ + fprintf(stderr, "Failed to parse degree: %s, exitting\n", optarg); + exit(EXIT_BAD_ARGUMENT); + } + break; + case 'c': + if(param_is_degree){ + fprintf(stderr, "--degree and --constant --radius are mutually exclusive, exiting\n"); + exit(EXIT_BAD_ARGUMENT); + } + parse_complex(optarg, &constant); + param_is_cr = true; + break; + case 'r': + if(param_is_degree){ + fprintf(stderr, "--degree and --constant --radius are mutually exclusive, exiting\n"); + exit(EXIT_BAD_ARGUMENT); + } + if(sscanf(optarg, CFORMAT, &radius) != 1){ + fprintf(stderr, "Failed to parse radius: %s, exitting\n", optarg); + exit(EXIT_BAD_ARGUMENT); + } + param_is_cr = true; + break; case 'f': if(strncmp(optarg, "mandelbrot", strlen("mandelbrot")) == 0) { fractal_name = "mandelbrot"; generator = mandelbrot_grid; } else if(strncmp(optarg, "tricorn", strlen("tricorn")) == 0) { - fractal_name = "tricorn"; - generator = tricorn_grid; + fractal_name = "tricorn"; + generator = tricorn_grid; } else if(strncmp(optarg, "multibrot", strlen("multibrot")) == 0) { - fractal_name = "multibrot"; - generator = multibrot_grid; - params = malloc(sizeof(grid_gen_params)); - params->degree = 3; + if(param_is_cr){ + fprintf(stderr, "multibrot requires a degree, not constant and radius, exitting\n"); + exit(EXIT_BAD_ARGUMENT); + } + fractal_name = "multibrot"; + generator = multibrot_grid; } else if(strncmp(optarg, "multicorn", strlen("multicorn")) == 0) { - fractal_name = "multicorn"; - generator = multicorn_grid; - params = malloc(sizeof(grid_gen_params)); - params->degree = 3; + if(param_is_cr){ + fprintf(stderr, "multicorn requires a degree, not constant and radius, exitting\n"); + exit(EXIT_BAD_ARGUMENT); + } + fractal_name = "multicorn"; + generator = multicorn_grid; } else if(strncmp(optarg, "burning_ship", strlen("burning_ship")) == 0) { - fractal_name = "burning ship"; - generator = burning_ship_grid; + fractal_name = "burning ship"; + generator = burning_ship_grid; } else if(strncmp(optarg, "julia", strlen("julia")) == 0) { - fractal_name = "julia"; - generator = julia_grid; - params = malloc(sizeof(grid_gen_params)); - params->cr.radius = 100; - params->cr.constant = (complex_t){ .re = 0.285, .im = 0.01 }; + if(param_is_degree){ + fprintf(stderr, "julia requires a constant and a radius, not a degree, exitting\n"); + exit(EXIT_BAD_ARGUMENT); + } + fractal_name = "julia"; + generator = julia_grid; } else { fprintf(stderr, "Invalid fractal type: %s, see --help for a list of supported fractals\n", optarg); - return 1; + exit(EXIT_BAD_ARGUMENT); } break; case 'z': - sscanf(optarg, CFORMAT, &magnification); + if(sscanf(optarg, CFORMAT, &magnification) != 1){ + fprintf(stderr, "Failed to parse magnification: %s, exitting\n", optarg); + exit(EXIT_BAD_ARGUMENT); + } if(magnification <= 0){ fprintf(stderr, "Invalid magnification "CFORMAT", exitting\n", magnification); - return 1; + exit(EXIT_BAD_ARGUMENT); } break; case 'v': @@ -164,10 +232,18 @@ int main(const int argc, char *argv[]) { return 0; default: print_usage(stderr, argv[0]); - return 1; + return 2; } } + if(param_is_degree){ + params->degree = degree; + } + else { + params->cr.constant = constant; + params->cr.radius = radius; + } + grid_t* grid = create_grid(x_res, y_res, iterations, lower_left, upper_right); if(!grid) return 1; -- cgit v1.2.3