zoukankan      html  css  js  c++  java
  • 【C++】Mandelbrot集绘制(生成ppm文件)

    曼德勃罗特集是人类有史以来做出的最奇异,最瑰丽的几何图形.曾被称为“上帝的指纹”。 这个点集均出自公式:Zn+1=(Zn)^2+C。(此处Z、C均为复数)所有使得该公式无限迭代后的结果能保持有限数值的复数C的集合,构成曼德勃罗集。

    曼德勃罗集:

    看起来十分美丽和神秘,接下来就让我们用程序来绘制它。


    在编写代码之前,我们先要了解这个图片中不同颜色所代表的含义。
    首先注意到的自然是占面积最大的中央黑色。黑色代表在迭代次数达到上限后其模仍小于某固定值(这里为2)的所有点。
    周围的渐变色则是由点的发散速度决定的,即经过了多少次迭代,其模值开始大于2。

    程序主体分为以下四个方面

    1. 计算迭代次数,也就是它的发散速度。迭代次数越少,其发散速度越快。

    int k=0;
    for (; k < 1000; k++)
    {
    	if (z.get_mod2() > 4.0)	break;
    	z = z * z + c;
    }
    

    2. 对坐标系统进行一定的缩放来与显示区域的坐标系统相匹配.

    假设显示高度为disp_height,宽度为disp_width.而点在显示区域中的位置为(x, y).如果显
    示复数平面的这个窗口具有最小值(real_min, imag_min)和最大值(real_max, imag_max),则每
    个点需用以下系数加以缩放.

    c.real = real_min + x * (real_max - real_min) / disp_width;
    c.imag = imag_min + y * (imag_max - imag_min) / disp_height;
    

    3. 配色

    为了使得绘制出的图形更漂亮,一个好的配色方案是少不了的。这里我使用的是以下函数生成的配色:

    void InitColor()
    {
    	// 使用 HSL 颜色模式产生角度 h1 到 h2 的渐变色
    	int h1 = 240, h2 = 30;
    	for (int i = 0; i<MAXCOLOR / 2; i++)
    	{
    		Color[i] = HSLtoRGB((float)h1, 1.0f, i * 2.0f / MAXCOLOR);
    		Color[MAXCOLOR - 1 - i] = HSLtoRGB((float)h2, 1.0f, i * 2.0f / MAXCOLOR);
    	}
    }
    
    

    4. ppm文件的格式

    文件头部分

    image << "P6
    "  //PPM magic number
    	   << width << ' '  //width, in ASCII decimal
    	   << height << '
    '  //height, in ASCII decimal
    	   << 255<<'
    ';  //maximum color value, in ASCII decimal
    

    第一行是P2/P3/P6
    第二行是图像的大小,先是行像素数,后是列像素数,中间有一个空格
    第三行是一个介于1和65535之间的整数,而且必须是文本的,用来表示每一个像素的一个分量用几个比特表示。
    图象数据部分
    P6格式,图象数据以字节格式存储,每个色彩成分(R,G,B)一个字节,3个字节为一个像素点。

    参考代码:

    #include<iostream>
    #include<string>
    #include<fstream>
    using namespace std;
    
    struct pixel  //单个像素
    {
    	char r, g, b;
    };
    
    class Complex
    {
    public:
    	Complex(double real = 0, double imag = 0) :real(real), imag(imag){}
    	Complex(Complex& com) :real(com.real), imag(com.imag){}
    	double& operator[](int i){ return i == 0 ? real : imag; }
    	double get_mod2(){ return pow(real, 2) + pow(imag, 2); }
    	Complex& operator=(Complex& com){ real = com.real; imag = com.imag; return *this; }
    	Complex operator+(Complex& com){ return Complex(real + com.real, imag + com.imag); }
    	Complex operator*(Complex& com){ return Complex(real*com.real - imag*com.imag, real*com.imag + imag*com.real); }
    
    private:
    	double real, imag;
    };
      
    class Mandelbrot
    {
    public:
    	Mandelbrot(int _width=640, int _height=480)
    		:path(path), width(_width), height(_height){}
    	~Mandelbrot(){}
    public:
    	void set_path(string path)
    	{
    		this->path = path;
    	}
    	void draw(double from_x,double to_x,double from_y,double to_y) //图片保存路径
    	{
    		create_image();
    		write_head();
    
    		for (int y = 0; y < height; y++)
    		{
    			Complex c(0, from_y + (to_y - from_y) * y / (double)height);
    			for (int x = 0; x < width; x++)
    			{
    				c[0] = from_x + (to_x - from_x) * x / (double)width;
    				Complex z(0, 0);
    				int k;
    				for (k = 0; k < 1000; k++)
    				{
    					if (z.get_mod2() > 4.0)	break;
    					z = z * z + c;
    				}
    				pixel p = { Color[k % 64].b, Color[k % 64].g,
    					Color[k % 64].r
    				};
    				pixel q = { 0, 0, 0 };
    				if (k == 1000) //收敛
    				{
    					image.write((char*)&q,sizeof(q));
    				}
    				else //发散
    				{
    					image.write((char*)&p,sizeof(p));
    				}
    			}
    		}
    		image.close();
    	}
    	void get_color(string path)
    	{
    		color.open(path,ios::binary);
    		for (int i = 0; i < 64; ++i)
    		{
    			color.read((char*)&Color[i], sizeof(pixel));
    		}
    		color.close();
    	}
    	int get_fileSize(){ return height*width*sizeof(pixel) / 1024; }  //KB
    private:
    	ofstream image;
    	ifstream color;
    	void create_image()
    	{
    		image.open(path,ios::binary);
    	}
    	void write_head() //文件头
    	{
    		image << "P6
    "
    			<< "#Mandelbrot Set
    "
    			<< width << ' '
    			<< height << '
    '
    			<< 255<<'
    ';
    	}
    	
    	int width, height; //图片尺寸
    	pixel Color[64];
    	string path;
    };
    
    
    
    int main()
    {
    
    	Mandelbrot test;
    	test.set_path("Mandelbrot.ppm");
    	test.get_color("color.dat"); //从文件中读取颜色数据
    	cout << test.get_fileSize()<<"KB";
    	test.draw(-2.1, 1.1, -1.2, 1.2);
    	
    	return 0;
    }
    

    ---参考自:http://codebus.easyx.cn/yw80/post/zoomable-mandelbrot-set

  • 相关阅读:
    Beta 阶段计划
    alpha阶段总结
    冲刺第十天 12.6 THU
    冲刺第九天 12.5 WED
    冲刺第八天 12.4 TUE
    冲刺第七天 12.3 MON
    冲刺第六天 11.30 FRI
    正弦交流电有效值系数sqrt(2)的推导
    关于STM32官方FOC库函数扇区分析中’131072’系数的解释
    闭环系统零、极点位置对时间响应性能指标的影响
  • 原文地址:https://www.cnblogs.com/cknightx/p/6840365.html
Copyright © 2011-2022 走看看