diff options
| author | JP Appel <jeanpierre.appel01@gmail.com> | 2024-04-20 23:49:21 -0400 |
|---|---|---|
| committer | JP Appel <jeanpierre.appel01@gmail.com> | 2024-04-20 23:49:21 -0400 |
| commit | 7516add571888d32d3d33364a35cd8148ed3bff6 (patch) | |
| tree | 181d183354f69dc096aaba1e4e6172a862b7f981 /src | |
| parent | d68fafdb137a52384d5b405ee288e79bff9f9e8a (diff) | |
add zoom feature to grids and shifted code around
Diffstat (limited to 'src')
| -rw-r--r-- | src/fractals.c | 49 | ||||
| -rw-r--r-- | src/fractals.h | 7 | ||||
| -rw-r--r-- | src/grids.c | 78 | ||||
| -rw-r--r-- | src/grids.h | 3 | ||||
| -rw-r--r-- | src/serial-fractals.c | 36 |
5 files changed, 151 insertions, 22 deletions
diff --git a/src/fractals.c b/src/fractals.c index 80ff32e..a2a43db 100644 --- a/src/fractals.c +++ b/src/fractals.c @@ -8,16 +8,21 @@ #include "grids.h" #include "fractals.h" - int main(const int argc, char *argv[]) { //default values size_t iterations = 1000; size_t x_res = 100; size_t y_res = 100; + double re_lower_left = -2; + double im_lower_left = -2; + double re_upper_right = 2; + double im_upper_right = 2; + double magnification = 1; + bool verbose = false; //parse command line arguments int opt; - while((opt =getopt(argc, argv, "i:x:y:")) != -1){ + while((opt = getopt(argc, argv, "vhi:x:y:l:u:z:")) != -1){ switch(opt){ case 'i': iterations = strtoull(optarg, NULL, 10); @@ -28,26 +33,46 @@ int main(const int argc, char *argv[]) { case 'y': y_res = strtoull(optarg, NULL, 10); break; + case 'l': + sscanf(optarg, "%lf+%lfi", &re_lower_left, &im_lower_left); + break; + case 'u': + sscanf(optarg, "%lf+%lfi", &re_upper_right, &im_upper_right); + break; + case 'z': + sscanf(optarg, "%lf", &magnification); + if(magnification <= 0){ + fprintf(stderr, "Invalid magnification %f, exitting\n", magnification); + return 1; + } + break; + case 'v': + verbose = true; + break; + case 'h': + fprintf(stderr, "Usage: %s [-v] [-i iterations] [-x x_res] [-y y_res] [-z magnification] [-l lower_left] [-u upper_right]\n", argv[0]); + return 0; default: - fprintf(stderr, "Usage: %s [-i iterations] [-x x_res] [-y y_res]\n", argv[0]); + fprintf(stderr, "Usage: %s [-v] [-i iterations] [-x x_res] [-y y_res] [-z magnification] [-l lower_left] [-u upper_right]\n", argv[0]); return 1; } } + const double complex lower_left = re_lower_left + im_lower_left * I; + const double complex upper_right = re_upper_right + im_upper_right * I; - const double complex lower_left = -2 + -2*I; - const double complex upper_right = 2 + 2*I; grid_t* grid = create_grid(x_res, y_res, lower_left, upper_right); if(!grid) return 1; - const size_t size = grid->size; - size_t* data = grid->data; - for(size_t i = 0; i < size;i++){ - data[i] = multibrot(grid_to_complex(grid, i), iterations, 3); + if(magnification != 1){ + if(verbose) printf("Magnification: %f\n", magnification); + zoom_grid(grid, magnification); } - for(size_t i = 0; i < size; i++){ - printf("%zu%s", data[i], (i % x_res == x_res - 1) ? "\n" : "\t"); - } + + mandelbrot_grid(grid, iterations); + + if(verbose)print_grid_info(grid); + print_grid(grid, iterations); } diff --git a/src/fractals.h b/src/fractals.h index 60d9013..dc6783e 100644 --- a/src/fractals.h +++ b/src/fractals.h @@ -3,7 +3,12 @@ #include <complex.h> #include <stddef.h> #include <stdint.h> +#include "grids.h" size_t mandelbrot(const double complex z0, const size_t max_iterations); -size_t multibrot(const double complex z0, const size_t max_iterations, const uintmax_t d); +void mandelbrot_grid(grid_t* grid, const size_t max_iterations); + +size_t multibrot(const double complex z0, const size_t max_iterations, const double d); +void multibrot_grid(grid_t* grid, const size_t max_iterations, const double d); + size_t julia(const double R, const double complex z0, const double complex c, const size_t max_iterations); diff --git a/src/grids.c b/src/grids.c index a6d35df..89347db 100644 --- a/src/grids.c +++ b/src/grids.c @@ -1,3 +1,4 @@ +#include <complex.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -26,6 +27,7 @@ grid_t* create_grid(const size_t x, const size_t y, double complex lower_left, d *grid = (grid_t){ .x = x, .y = y, + .size = x*y, .lower_left = lower_left, .upper_right = upper_right, .data = data @@ -120,6 +122,23 @@ double complex grid_to_complex(const grid_t* grid, const size_t index) { } /* + * Zoom a grid in or out based on its current center + * + * Resets all grid values to 0 + */ +void zoom_grid(grid_t* grid, const double magnification){ + set_grid(grid, 0); + const double complex upper_right = grid->upper_right; + const double complex lower_left = grid->lower_left; + + const double complex center = (lower_left + upper_right) / 2.0; + const double complex offset = (upper_right - lower_left) / magnification; + + grid->lower_left = center - offset; + grid->upper_right = center + offset; +} + +/* * Writes a grid to a file in the .grid format * * Returns 0 on success @@ -157,6 +176,65 @@ int write_grid(FILE* restrict file, const grid_t *grid){ } /* + * Prints info about a grid to stdout + */ +void print_grid_info(const grid_t* grid){ + if(!grid){ + printf("Grid is NULL!\n"); + return; + } + + printf("x\t%zu\n", grid->x); + printf("y\t%zu\n", grid->y); + printf("size\t%zu\n", grid->size); + printf("lower_left\t%f + %fI\n", creal(grid->lower_left), cimag(grid->lower_left)); + printf("upper_right\t%f + %fI\n", creal(grid->upper_right), cimag(grid->upper_right)); + + printf("Data is %s NULL\n", grid->data ? "not" : ""); +} + +/* + * Attempts an ASCII print of the grid + */ +void print_grid(const grid_t* grid, const size_t iterations){ + const size_t size = grid->size; + const size_t x_res = grid->x; + const size_t* data = grid->data; + + // char* output_buffer = malloc(size); + // if(!output_buffer){ + // fprintf(stderr, "Failed to allocate output buffer for %zu points\n"); + // return; + // } + + const char point_types[] = { ' ', '.', '*', '%', '#'}; + size_t bin_width = iterations/3; + size_t last_bin = iterations - bin_width; + char point; + + //TODO: set values in output buffer rather than multiple printf calls + for(size_t i = 0; i < size; i++){ + const size_t value = data[i]; + if(value == iterations){ + point = point_types[4]; + } + else if(value == 0){ + point = point_types[0]; + } + else if(value <= bin_width){ + point = point_types[1]; + } + else if(value >= last_bin){ + point = point_types[3]; + } + else { + point = point_types[2]; + } + printf("%c%s", point, (i % x_res == x_res - 1) ? "\n" : ""); + } +} + +/* * Creates a grid from a .grid file, reading the amount of data as specified by the file * For more details on the .grid format see write_grid * diff --git a/src/grids.h b/src/grids.h index 8c9db91..bba6f68 100644 --- a/src/grids.h +++ b/src/grids.h @@ -28,6 +28,9 @@ bool grid_equal(const grid_t* grid1, const grid_t* grid2); bool grid_allclose(const grid_t* grid1, const grid_t* grid2, const size_t max_error); double complex grid_to_complex(const grid_t* grid, const size_t index); +void zoom_grid(grid_t* grid, const double magnification); +void print_grid_info(const grid_t* grid); +void print_grid(const grid_t* grid, const size_t iterations); int write_grid(FILE* restrict file, const grid_t* grid); grid_t* read_grid(FILE* restrict file); diff --git a/src/serial-fractals.c b/src/serial-fractals.c index a5f9841..9f4013d 100644 --- a/src/serial-fractals.c +++ b/src/serial-fractals.c @@ -1,4 +1,5 @@ #include "fractals.h" +#include "grids.h" /* * Computes the number of iterations it takes for a point z0 to diverge * if the return value is equal to max_iterations, the point lies within the mandelbrot set @@ -15,28 +16,45 @@ size_t mandelbrot(const double complex z0, const size_t max_iterations) { return iteration; } +/* + * Fills a grid with mandelbrot values + */ +void mandelbrot_grid(grid_t* grid, const size_t max_iterations){ + const size_t size = grid->size; + size_t* data = grid->data; + + for(size_t i = 0; i < size; i++){ + data[i] = mandelbrot(grid_to_complex(grid, i), max_iterations); + } +} /* * Computes the number of iterations it takes for a point z0 to diverge * if the return value is equal to max_iterations, the point lies within the multibrot set - * This is implementation closely matches mandelbrot - * Note, only positive integer powers are supported + * This is implementation closely matches mandelbrot, but uses cpow which might degrade performance. */ -size_t multibrot(const double complex z0, const size_t max_iterations, const uintmax_t d){ +size_t multibrot(const double complex z0, const size_t max_iterations, const double d){ double complex z = z0; - double complex ztemp; size_t iteration = 0; while(cabs(z) <= 2 && iteration < max_iterations){ - ztemp = z; - for(size_t i = 0; i < d; i ++){ - ztemp *= ztemp; - } - z = ztemp + z0; + z = cpowl(z, d) + z0; iteration++; } return iteration; } + +/* + * Fills a grid with multibrot values + */ +void multibrot_grid(grid_t* grid, const size_t max_iterations, const double d){ + const size_t size = grid->size; + size_t* data = grid->data; + for(size_t i = 0; i < size; i ++){ + data[i] = multibrot(grid_to_complex(grid, i), max_iterations, d); + } +} + /* * Computes ????? for a julia set * implementation of https://en.wikipedia.org/wiki/Julia_set#Pseudocode |
