Mandelbrot集

一,先堆一下概念
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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值