这是本人之前用C语言代码写的Mandelbrot Set的复平面分形的可视化实现。尽管这次的作业并不难,但是我觉得仍然值得记录。
叠甲:本人不才,代码水平有限,只是单纯的记录。
项目介绍
项目目的
用C语言实现mandelbrot集,将其通过静态图片、动态视频等进行可视化展现,使用多线程并行计算加速。
实现功能
- mandelbrot集的总体静态图片展现
- mandelbrot集的局部动态视频展现
- 多线程并行计算加速
使用方法
- make video或者make后输入./mandelbrot来编译运行程序,可生成mandelbrot集bmp静态图片和mp4动态视频
- make doc生成项目报告pdf文档
- make clean-all清除除了动态视频和说明文档外所有生成的文件
- make clean-rest清除动态视频和说明文档
依赖关系
- ffmpeg用于生成动态视频
- math库
- OpenMP库
代码实现
.h文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| # include <stdio.h> # include <stdlib.h> # include <math.h> # include <complex.h> # include <ctype.h> # include <unistd.h>
typedef struct { double x_min; double x_max; double y_min; double y_max; int max_iter; int width; int height; int **iter_count; }mandelbrot;
void mandelbrot_init(mandelbrot *m, double x_min, double x_max, double y_min, double y_max, int max_iter, int width, int height);
void mandelbrot_save_bmp(const mandelbrot *m,const char *filename);
void mandelbrot_free(mandelbrot *m);
|
.c文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
| # include <stdio.h> # include <stdlib.h> # include <math.h> # include <complex.h> # include "mandelbrot.h" # define M_PI 3.14159265358979323846
#pragma pack(push, 1) struct BMPfileheader { unsigned short bftype; unsigned int bfsize; unsigned short bfreserved1; unsigned short bfreserved2; unsigned int bfoffbits; };
struct BMPinfoheader { unsigned int bisize; int biwidth; int biheight; unsigned short bipplanes; unsigned short bitcount; unsigned int bicompression; unsigned int bisizeimage; int bixpelspermeter; int biypelspermeter; unsigned int bicolor_used; unsigned int bicolor_important; }; #pragma pack(pop)
void mandelbrot_init(mandelbrot *m, double x_min, double x_max, double y_min, double y_max, int max_iter, int width, int height) { m->x_min = x_min; m->x_max = x_max; m->y_min = y_min; m->y_max = y_max; m->max_iter = max_iter; m->width = width; m->height = height; m->iter_count = (int **)malloc(sizeof(int*) * m->width); for(int i = 0; i < m->width; i++) { m->iter_count[i] = (int*)malloc(sizeof(int) * m->height); } double dx = (m->x_max - m->x_min) / m->width; double dy = (m->y_max - m->y_min) / m->height; #pragma omp parallel for schedule(dynamic) for(int i = 0; i < m->width; i++) { for(int j = 0; j < m->height; j++) { complex z = 0 + 0 * I; complex c = m->x_min + i * dx + (m->y_min + j * dy) * I; m->iter_count[i][j] = m->max_iter; for(int iter_num = 0; iter_num < m->max_iter; iter_num++) { z = z * z + c; if(cabs(z) > 2.0) { m->iter_count[i][j] = iter_num; break; } } } } }
void mandelbrot_save_bmp(const mandelbrot *m,const char *filename) { FILE *fp = fopen(filename,"wb"); if(fp == NULL) return; int width_size = m->width * 3; int filler = (4 - (width_size % 4)) % 4; width_size += filler; #pragma pack(push, 1) struct BMPfileheader fileheader; struct BMPinfoheader infoheader; fileheader.bftype = 0x4d42; fileheader.bfsize = 54 + width_size * m->height; fileheader.bfreserved1 = 0; fileheader.bfreserved2 = 0; fileheader.bfoffbits = 54; infoheader.bisize = 40; infoheader.biwidth = m->width; infoheader.biheight = m->height; infoheader.bipplanes = 1; infoheader.bitcount = 24; infoheader.bicompression = 0; infoheader.bisizeimage = width_size * m->height; infoheader.bixpelspermeter = 0; infoheader.biypelspermeter = 0; infoheader.bicolor_used = 0; infoheader.bicolor_important = 0; #pragma pack(pop) fwrite(&fileheader, sizeof(fileheader), 1, fp); fwrite(&infoheader, sizeof(infoheader), 1, fp); for(int j = m->height - 1; j >= 0; j--) { for(int i = 0; i < m->width; i++) { int iter = m->iter_count[i][j]; double ratio = (iter == m->max_iter) ? 0.0 : (double)iter / m->max_iter; ratio = pow(ratio, 0.3); unsigned char red = 255 * 0.5 * (sin(2.0 * M_PI * ratio)) + 128; unsigned char green = 255 * 0.5 * (sin(2.0 * M_PI * ratio + 2.0 * M_PI / 3)) + 128; unsigned char blue = 255 * 0.5 * (sin(2.0 * M_PI * ratio + 4.0 * M_PI / 3)) + 128; fwrite(&blue, 1, 1, fp); fwrite(&green, 1, 1, fp); fwrite(&red, 1, 1, fp); } for(int k = 0; k < filler; k++) fputc(0, fp); } fclose(fp); }
void mandelbrot_free(mandelbrot *m) { for(int i = 0; i <m->width; i++) {free(m->iter_count[i]);} free(m->iter_count); }
|
测试文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| #include <stdio.h> #include "mandelbrot.h"
int main() { mandelbrot m; int max_iter = 1000; int width = 800; int height = 600; int frames = 90; double center_x = -0.743643887; double center_y = 0.131825911; double zoom = 0.95; double x0_min = -1.5; double x0_max = 1.5; double y0_min = -1.0; double y0_max = 1.0; mandelbrot_init(&m, -1.5, 1.5, -1.0, 1.0, max_iter, width, height); const char *filename = "mandelbrot.bmp"; mandelbrot_save_bmp(&m, filename); printf("已将mandelbrot集图像保存为 %s\n", filename); mandelbrot_free(&m); for(int i = 0; i < frames; i++) { int current_max_iter = max_iter + i * 100; double decay = pow(zoom, i); double x_min = center_x - (center_x - x0_min) * decay; double x_max = center_x + (x0_max - center_x) * decay; double y_min = center_y - (center_y - y0_min) * decay; double y_max = center_y + (y0_max - center_y) * decay; mandelbrot_init(&m, x_min, x_max, y_min, y_max, current_max_iter, width, height); char filename[100]; sprintf(filename, "mandelbrot%03d.bmp", i); mandelbrot_save_bmp(&m, filename); mandelbrot_free(&m); } return 0; }
|
运行结果
Makefile和report.tex就不放了
静态图片

动态视频