Mandelbrot集

来源:互联网 发布:电脑看电视直播软件 编辑:程序博客网 时间:2024/05/22 07:47

一,先堆一下概念
Mandelbrot集合是在复平面上组成分形的点的集合,它正是以数学家Mandelbrot命名。
Mandelbrot集合可以用复二次多项式。

从数学上来讲,Mandelbrot集合是一个复数的集合。一个给定的复数c或者属于Mandelbrot集合M,或者不属于。比如,取c = 1,那么这个序列就是(0, 1, 2, 5, 26, …),显然它的值会趋于无穷大;而如果取c = i,那么序列就是(0, i, -1+i, -i, -1+i, -i,…),它的值会一直停留在有限半径的圆盘内。

事实上,一个点属于Mandelbrot集合当且仅当它对应的序列(由上面的二项式定义)中的任何元素的模都不大于2。这里的2就是上面提到的“有限半径”。
参考:http://www.cnblogs.com/anderslly/archive/2008/10/10/mandelbrot-set-by-fsharp.html

二,曼德布罗特集合有什么实际意义?
这里就要提出分形的概念了。
数学上认为分形有以下几个特点:
1. 具有无限精细的结构;
2. 比例自相似性;
3. 一般它的分数维大于它的拓扑维数;
4. 可以由非常简单的方法定义,并由递归、迭代产生。
分形(Fractal)一词,是曼德勃罗创造出来的,其原意是不规则、支离破碎的意思,所以分形几何学是一门以非规则几何形态为研究对象的几何学。按照分形几何学的观点,一切复杂对象虽然看似杂乱无章,但他们具有相似性,简单地说,就是把复杂对象的某个局部进行放大,其形态和复杂程度与整体相似。
分形往往由递归、迭代产生,但是我们在纸上做出的图只能作有限次的递归、迭代。所以,下面的代码,绘图的核心就是一个递归。
有兴趣可以去搜索一下:麦田圈密码;谢尔宾斯基地毯;科契雪花曲线。

三,代码实现(Java版)

package Mandelbrot;import java.awt.*;import java.awt.event.*;import javax.swing.*;import java.util.Timer;import java.util.TimerTask;public class Mandelbrot extends JApplet {Display canvas;  // Display:每个swt程序在最开始都必须创建一个Display对象。它负责swt和操作系统之间的通信。JButton stopButton, startButton;  // 启动按钮被按下时计算将开始,直到它完成计算或用户按下“停止”按钮。JTextField jtfTime; //定义一个文本框public void init() {       // 初始化程序通过创建 canvas and button并将它们添加到applet的内容窗格。   this.setSize(900, 600); //把窗口设置的稍微大一点好看   setBackground(Color.gray);//背景设置为灰色   canvas = new Display();//创建一个Display对象   getContentPane().add(canvas, BorderLayout.CENTER); //在窗口面板canvas上面添加控件,添加在布局的中间CENTER   JPanel bottom = new JPanel(); //创建button面板   JPanel bottom_up = new JPanel(); //创建bottom_up面板   bottom.setBackground(Color.gray);//设置button背景色为灰色   startButton = new JButton("Start");//创建一个名字为startButton的按钮控件   startButton.addActionListener(canvas); //注册事件监听器,作用是将startButton的事件处理交给canvas对象去处理   bottom.add(startButton); //Jpanel类的实例化对象bottom上 添加 JButton类的实例化对象startButton;在窗口面板上添加控件   stopButton = new JButton("Stop");   stopButton.addActionListener(canvas);   bottom.add(stopButton);   stopButton.setEnabled(false); //stopButton初始化时候设置为不可操作   JLabel label_left = new JLabel("computation time is:");   bottom_up.add(label_left);   jtfTime = new JTextField("                  ");   jtfTime.setEnabled(false);   jtfTime.setSize(15, 15);   bottom_up.add(jtfTime);   JLabel label_right = new JLabel("seconds");   bottom_up.add(label_right);   getContentPane().add(bottom, BorderLayout.NORTH);//在窗口面板bottom上面添加控件,添加在布局的上边NORTH。   getContentPane().add(bottom_up, BorderLayout.SOUTH);//在窗口面板bottom_up上面添加控件,添加在布局的下边SOUTH。} // end init();/*调用此方法时由系统applet将暂时或永久停止。画布停止计算线程,如果它正在运行。*/public void stop() {   canvas.stopRunning();}/*下面的嵌套类代表了applet的绘图层并做所有的工作*/ class Display extends JPanel implements ActionListener, Runnable {   Image OSI;    // 抽象类Image是所有表示图形图像类的父类。图像保存了曼德尔勃特集合的照片。这是复制到绘图表面,如果它存在。它是由计算的线程创建的。   Graphics OSG;   // Graphics类提供基本绘图方法。在Image OSI 上draw的图形上下文。   Thread runner;    // 计算线程的声明   boolean running;  // running的布尔类型声明   double xmin = -2.5;   // The ranges of x and y coordinates that   double xmax = 1;      //    are represented by this drawing surface   double ymin = -1.25;   double ymax = 1.25;    //由系统调用图显示面。如果离屏图像存在,则把离屏图像复制到屏幕上。如果离屏图像不存在,它只把表面画成黑色的。   public void paintComponent(Graphics g) {      if (OSI == null) {         g.setColor(Color.black);   //【设置前景色】的方法是属于【Graphics】的,即设置Graphics的绘图色。语法为:g.setColor(Color对象);         g.fillRect(0,0,getWidth(),getHeight()); //fillRect(int x,int y,int width,int height):是【用预定的颜色填充一个矩形】,得到一个着色的矩形块。      }      else {         g.drawImage(OSI,0,0,null);      }   }   //当用户单击“starting”或“ stopping”按钮时将调用此函数。它通过starting or stopping响应动画。   public void actionPerformed(ActionEvent evt) {      String command = evt.getActionCommand(); //为了避免冲突,给同一个JFrame里每个按钮设置不同的ActionCommand,监听时用这个做条件区分事件,以做不同的响应。      if (command.equals("Start"))      {         startRunning();         time_clock();      }      else if (command.equals("Stop"))         stopRunning();   }   void startRunning() {      if (running)         return;      runner = new Thread(this); // 创建一个线程,该线程将在this显示类中执行run()方法。      running = true;      runner.start();   }   /*做一个定时器,计算绘图的时间*/   void time_clock()   {      Timer timer = new Timer();      timer.schedule(new MyTask(), 0, 1000);   }   class MyTask extends TimerTask   {      int i = 0;      @Override      public void run()       {        i++;        String s = String.valueOf(i);        jtfTime.setText(s);        if( running == false)        {            jtfTime.setText("0                 ");            i = 0;        }      }   }   void stopRunning()    { // 停止计算线程的方法。是通过设置变量running的值来完成的。【线程定期检查这个值】,当running为false时将终止运行。      running = false;   }   //算出迭代计数的值count,以便后面用。   int countIterations(double x, double y)    {        //曼德尔勃特集合在while循环结束前,根据迭代的数量,通过每一个点(x,y)上着色来表示。        //曼德尔勃特的集合点,实际上是,或非常接近它,计数将达到最大值80.这些点将变成紫色。所有其他颜色代表点绝对不是集合点。      int count = 0;      double zx = x;      double zy = y;      while (count < 80 && Math.abs(x) < 100 && Math.abs(zy) < 100) {         double new_zx = zx*zx - zy*zy + x;         zy = 2*zx*zy + y;         zx = new_zx;         count++;      }      return count;   }   int i,j;   // 一个正方形的中心像素需要绘画。 这些变量是设置在Display类的run()方法中,在run()方法中用于painter对象的。这同样适用于接下来的两个变量。   int size;  // 要画的正方形的大小   int colorIndex;  //1和80之间的数字,用于决定正方形的颜色。   Runnable painter = new Runnable() {            // Runnable对象的工作是:画一个square在离屏canvas,然后复制square到屏幕上。            //当run方法被调用时候它将这样运行。square上的数据是由前面的四个变量决定的。         public void run() {            int left = i - size/2;            int top = j - size/2;            OSG.setColor( Color.getHSBColor(colorIndex/100.0F,1F,1F) );            OSG.fillRect(left,top,size,size);            paintImmediately(left,top,size,size);         }     };   public void run()    { //这是计算线程的run方法。它在一连串增加分辨率的方式下,绘出曼德尔勃特集合。在每一次,它填充applet、给方块着色来代表了曼德尔勃特集合。squares的大小在每次通过减少一半。      startButton.setEnabled(false);  // Disable "Start" button      stopButton.setEnabled(true);    //    and enable "Stop" button                                      //    while thread is running.      int width = getWidth();   // Current size of this canvas.      int height = getHeight();      OSI = createImage(getWidth(),getHeight());   //getWidth、getHeight():得到当前层的宽度与高度。          // Create the off-screen image where the picture will          // be stored, and fill it with black to start.      OSG = OSI.getGraphics();  //可以理解为在OSI上绘画      OSG.setColor(Color.black);      OSG.fillRect(0,0,width,height);      for (size = 64; size >= 1 && running; size = size/2) {            //外循环执行一遍,填充图像与给定大小的方块。这是给定的像素大小。注意如果running为false,则所有循环立即结束。         double dx,dy;  // 实际坐标轴的方块尺寸         dx = (xmax - xmin)/width * size;         dy = (ymax - ymin)/height * size;         double x = xmin + dx/2;  // x-坐标 of center of square.         for (i = size/2; i < width+size/2 && running; i += size) {               // First nested for loop draws one column of squares.第一个嵌套循环了一列的方块。            double y = ymax - dy/2; // y-坐标 of center of square            for (j = size/2; j < height+size/2 && running; j += size) {                    //内层for循环了一个方块,通过计算迭代确定应该是什么颜色,然后调用"painter"对象画出实际的square。                colorIndex = countIterations(x,y); //调用countIterations函数                try {                   SwingUtilities.invokeAndWait(painter);  //将对象排到事件派发线程的队列中                }                catch (Exception e) {                }                y -= dy;            }            x += dx;            Thread.yield();  // Give other threads a chance to run.         }      }      running = false;  // 线程即将结束,因为计算已完成或因为running已设置为false。 在前一种情况下,我们必须设置 running= false来表明线程不再运行。      startButton.setEnabled(true);  // Reset states of buttons.      stopButton.setEnabled(false);   } // end run()} // end nested class Display} // end class Mandelbrot
0 0
原创粉丝点击