Newsletter sign-up
View all newsletters

Enterprise Java Newsletter
Stay up to date on the latest tutorials and Java community news posted on JavaWorld

Sponsored Links

Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs

Java Fun and Games: Explore the geometry of nature

Journey into the realm of fractals

  • Print
  • Feedback

Page 6 of 7

Listing 6. An excerpt of the Mandelbrot Set applet

public void paintComponent (Graphics g)
{
     // The following increments make it possible to accurately map
     // floating-point numbers in the complex plane to integers on this
     // component's display surface.

     double imInc = (imMax-imMin)/getHeight ();
     double reInc = (reMax-reMin)/getWidth ();

     double dist = 0.0, im, re, tim, tre, zim, zre;

     int iter, x, y;

     // Generate Mandelbrot set. Each (re, im) combination corresponds
     // to point c on the complex plane.

     for (im = imMin, y = 0; im <= imMax; im += imInc, y++)
          for (re = reMin, x = 0; re <= reMax; re += reInc, x++)
          {
               // The (zre, zim) combination corresponds to complex
               // number z.

               zim = 0.0;
               zre = 0.0;

               for (iter = 1; iter < palette.length; iter++)
               {
                    // Calculate z*z.

                    tim = (zre+zre)*zim;
                    tre = zre*zre-zim*zim;

                    // Add c to z*z.

                    zim = tim+im;
                    zre = tre+re;

                    // Calculate distance squared.

                    dist = zre*zre+zim*zim;

                    // If distance squared exceeds 4.0, point is outside
                    // Mandelbrot set, so color point to a non-black
color.

                    if (dist > 4.0)
                    {
                        g.setColor (palette [iter]);
                        g.drawLine (x, y, x, y);
                        break;
                    }
               }

               // If distance squared is less than or equal to 4.0, point
               // is inside Mandelbrot set, so color point black.

               if (dist <= 4.0)
               {
                   g.setColor (Color.black);
                   g.drawLine (x, y, x, y);
               }
          }
}

I've included extensive comments in the above method, so I won't bother to further discuss the source code. One thing to note, however, is that I've dispensed with the time-consuming square-root operation, thus speeding up the generation of the Mandelbrot set. I could do this because comparing the square of the distance between a point and the set's origin with 4 is equivalent to comparing the distance with 2.

Zooming in and out

The MS applet presents a GUI that consists of MSPane and label components. The former component presents the Mandelbrot set at a specific zoom level; the label component displays this zoom level (starting at 0, no zoom) and the mouse coordinates at the time you click the mouse to zoom into the fractal by 50%. These coordinates are handy for creating an animated tour, such as the one revealed in Figure 7.

Zooming into the Mandelbrot set.

Figure 7. Zooming into the Mandelbrot set.

The logic for zooming into and out of the Mandelbrot set is contained within a pair of anonymous classes that listen for mouse-click and mouse-move events. These listener classes are registered with the MSPane component from within its constructor, as shown in Listing 7.

Listing 7. Registering listener classes with MSPane

MSPane (final JLabel lblStatus)
{
     addMouseListener (new MouseAdapter ()
                       {
                           public void mouseClicked (MouseEvent e)
                           {
                              int x = e.getX ();
                              int y = e.getY ();

                              if (!e.isShiftDown () && level < 31)
                              {
                                  double re =
reMin+x*(reMax-reMin)/getWidth ();
                                  double im =
imMin+y*(imMax-imMin)/getHeight ();

                                  complexNum cn = new complexNum ();
                                  cn.re = re;
                                  cn.im = im;
                                  stack.push (cn);

                                  reMax += re;
                                  reMin += re;
                                  imMax += im;
                                  imMin += im;
                                  reMax /= 2.0;
                                  reMin /= 2.0;
                                  imMax /= 2.0;
                                  imMin /= 2.0;

                                  level++;
                                  lblStatus.setText ("Level: "+level+
                                                     ", x: "+x+", y:  
"+y);
                              }
                              else
                              if (e.isShiftDown () && level != 0)
                              {
                                  complexNum cn = (complexNum) stack.pop
();
                                  double re = cn.re;
                                  double im = cn.im;

                                  reMax *= 2.0;
                                  reMin *= 2.0;
                                  imMax *= 2.0;
                                  imMin *= 2.0;
                                  reMax -= re;
                                  reMin -= re;
                                  imMax -= im;
                                  imMin -= im;

                                  level--;
                                  lblStatus.setText ("Level: "+level+
                                                     ", x: "+x+", y:  
"+y);
                              }

                              repaint ();
                           }
                       });

     addMouseMotionListener (new MouseMotionAdapter ()
                             {
                                 public void mouseMoved (MouseEvent e)
                                 {
                                    int x = e.getX ();
                                    int y = e.getY ();
                                    lblStatus.setText ("Level: "+level+
                                                       ", x: "+x+", y:
"+y);
                                 }
                             });
}

The zoom-in effect is accomplished by dividing the values in the reMax, reMin, imMax and imMin variables by 2. In contrast, zoom out multiplies these values by 2. Prior to the zoom in, and after the zoom out, these values are translated by the complex equivalent of the component location that was clicked. Doing this keeps the clicked area visible at the next zoom level.

  • Print
  • Feedback

Resources