Home : Course Map : Chapter 11 : Java : Tech :
Fractal Generation with Images
JavaTech
Course Map
Chapter 11

Introduction
Image Class
Image Loading
  Demo 1 Demo 2  
Pixels/Transparency
  Demo 3
Pixel Handling
  Demo 4  
Demo 5
Exercises

    Supplements
Java 2D Imaging
BufferedImage
Creating Buf.Image
Pixel Handling
  Demo 1 Demo 2
Filters
  Convolutions
     Demo 3
  AffineTransforms
     Demo 4
  LookupTable
     Demo 5 Demo 6
  Rescale
     Demo 7
  Color Conversion
     Demo 8
  Custom
     Demo 9
Exercises
Java Adv Imaging
AWT Flicker:
  Override Update
     Demo 1  Demo 2
  Clipping
     Demo 3
  Double Buffer
     Demo 4

     About JavaTech
     Codes List
     Exercises
     Feedback
     References
     Resources
     Tips
     Topic Index
     Course Guide
     What's New

In the previous fractal demonstration program we drew each point of the display with the graphics context methods. This involves invocations of the drawLine() method for every point in the fractal display area. We demonstrate a faster technique here in which the pixels for a BufferedImage are modified directly and then the image is displayed in a single method invocation. If you compare the performance of the demonstration applet below with the previous applet, you should see a considerable improvement.

The codes are very similar to the preceding case. FractalsImgApplet differs from FractalsApplet only in the list of algorithms. The algorithm classes also are very similar to the classes for the draw demo except that they modify a pixel in a BufferedImage object rather than invoke drawLine().


Demo: Fractals displayed via pixel handling in a BufferedImage

FractalsImgApplet.java - similar to FractalsApplet except that it selects from instances of the following DrawFunction classes to display the fractal patterns.

+ New Classes:
DrawBifurcationImg.java - DrawFunction subclass that creates a fractal pattern with the Bifurcation algorithm using the pixels of an image and then draws the image.
DrawJuliaSetImg.java - DrawFunction subclass that creates a fractal pattern with the Julia Set algorithm using the pixels of an image and then draws the image.
DrawJuliaSetNewtonImg.java - DrawFunction subclass that creates a fractal pattern with the Julia Set via Newton's method algorithm using the pixels of an image and then draws the image.
DrawMandlebrotImg.java - DrawFunction subclass that creates a fractal pattern with the Mandlebrot algorithm using the pixels of an image and then draws the image.

+ Previous classes:
FractalController.java, FractalPanel.java,
MousePlotPanel.java
, MouseHandler.java
Chapter 6:Tech: PlotPanel.java, PlotFormat.java

Chapter 6:Tech: DrawFunction.java
Chapter 4:Tech: Complex.java

 

// Begin from StarterJApplet11

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.event.*;


/**
  *  Demonstrate various fractal algorithms. User selects
  *  from a list of algorithms. Graphical output of the
  *  algorithm is displayed within a plot frame using a
  *  subclass of MousePlotPanel, which in turn is a subclass
  *  of PlotPanel.

  *
  *  The fractal algorithms are included in DrawFunction
  *  subclasses. They create the fractal patterns by modifying
  *  image pixel data and then drawing the image with the
  *  graphics context object passed to it.

  *
  *  The user can drag the cursor to outline a rectangle
  *  whose dimensions are used for a rescaled graph. The
  *  MousePlotPanel provides the mouse event information.

  *
  *  The class implement the FractalController interface so that the
  *  FractalPanel object can call back to send new dimensions
  *  for the graph area. It also calls back to indicate when
  *  fractal generation is happening so that the controls
  *  can be put into a busy state and not interfere with the
  *  operation.
 **/
public class FractalsImgApplet extends JApplet
       implements ActionListener, ListSelectionListener,
                  FractalController
{
  // Flag to indicate if the applet is in a browser
  // or running as an application via the main () method.
  boolean fInBrowser = true;

  // Fractal panel can display different algorithms by
  // passing to it a new DrawFractal object.
  FractalPanel fOutputPanel;

  // A text field for input strings
  JTextField fFieldXLeft, fFieldXRite, fFieldYTop, fFieldYBot;

  // Parameters for the algorithms.
  double fParam0 = 0.0;
  double fParam1 = 0.0;

  // Text fields to input the algorithm parameters
  JTextField fFieldParam0;
  JTextField fFieldParam1;

  // Labels for the parameters
  JLabel fLabelParam0, fLabelParam1;

  // A number to indicate the selected algorithm.
  int fAlgorithm = ALG_BIFURCATION;

  // Define a set of constants to specify a given algorithm
  final static int ALG_BIFURCATION   = 0;
  final static int ALG_JULIASET      = 1;
  final static int ALG_JULIASET_NEWT = 2;
  final static int ALG_MANDLEBROT    = 3;

  // Default dimensions according to the algorithm
  double [][] fXYDef =
      {
         {-2.0, 2.0, -2.0, 2.0}, // Bifurcation
         {-2.0, 2.0, -2.0, 2.0}, // Julia set
         {-3.0, 3.0, -3.0, 3.0}, // Julia set from Newton's method
         {-2.5, 2.5, -2.5, 2.5}  // Mandlebrot
      };

  // Hold the default algorithm parameters in this 2-d array.
  double [][] fAlgorithmParams = {
                                  {0.0,  0.0}, // Bifurcation
                                  {0.36, 0.25},// Julia set
                                  {0.0,  0.0}, // Julia set from Newton's method
                                  {0.0,  0.0}  // Mandlebrot
                                 };

  // List component for the algorithms.
  JList fAlgorithmJList;
  String [] fAlgorithmList = {"Bifurcation",
                              "Julia Set",
                              "Julia Set- Newton's",
                              "Mandlebrot"
                             };


  // Keep an array of the fractal generators
  DrawFunction [] drawFractals = new DrawFunction[4];

  // Need a button to return to the default dimensions.
  JButton fResetButton;

   /**
     * Create a User Interface with four fields that show the
     * current dimensions of the fractal graphing area.
     * The interface also includes a JList with the
     * list of algorithms. Selecting one will initiate the
     * algorithm. A "Reset" button will return the dimensions to
     * the default values and redraw the graph.
    **/
  public void init () {

    JPanel panel = new JPanel (new BorderLayout ());

    // When user hits reset button, the graph will be
    // redrawn with default dimensions.
    fResetButton = new JButton ("Reset");
    fResetButton.addActionListener (this);

    // Use a textfield for an input parameter.
    fFieldXLeft = new JTextField (Double.toString (fXYDef[0][0]), 6);
    fFieldXRite = new JTextField (Double.toString (fXYDef[0][1]), 6);
    fFieldYBot  = new JTextField (Double.toString (fXYDef[0][2]), 6);
    fFieldYTop  = new JTextField (Double.toString (fXYDef[0][3]), 6);

    // Use a GridLayout to show the dimensions
    JPanel dim_labels_panel = new JPanel (new GridLayout (2,1));
    dim_labels_panel.add (new JLabel ("X = ", SwingConstants.RIGHT));
    dim_labels_panel.add (new JLabel ("Y = ", SwingConstants.RIGHT));

    JPanel dimensions_panel = new JPanel (new GridLayout (2,2));
    dimensions_panel.add (fFieldXLeft);
    dimensions_panel.add (fFieldXRite);
    dimensions_panel.add (fFieldYBot);
    dimensions_panel.add (fFieldYTop);

    // Parameters fields
    fFieldParam0 = new JTextField (Double.toString (fParam0),6);
    fFieldParam1 = new JTextField (Double.toString (fParam1),6);
    JPanel parameters_panel = new JPanel (new GridLayout (2,2));
    fLabelParam0 = new JLabel ("P0 = ", SwingConstants.RIGHT);
    parameters_panel.add (fLabelParam0);
    parameters_panel.add (fFieldParam0);
    fLabelParam1 = new JLabel ("P1 = ", SwingConstants.RIGHT);
    parameters_panel.add (fLabelParam1);
    parameters_panel.add (fFieldParam1);

    // Combine the panels for the dimensions, their labels
    // and parameters  onto one panel.
    JPanel dim_param_panel = new JPanel ();
    dim_param_panel.add (dim_labels_panel);
    dim_param_panel.add (dimensions_panel);
    dim_param_panel.add (parameters_panel);

    // Create a JList for the algorithms.
    fAlgorithmJList = new JList (fAlgorithmList);

    // Show only the current algorithm
    fAlgorithmJList.setVisibleRowCount (2);

    // Allow only one of the items to be selected.
    fAlgorithmJList.setSelectionMode (
      ListSelectionModel.SINGLE_SELECTION);

    // Select initially the top item.
    fAlgorithmJList.setSelectedIndex (ALG_BIFURCATION);

    // Send selection events to this object.
    fAlgorithmJList.addListSelectionListener (this);

    // Add the list to a JScrollPane so that we can
    // scroll to view other items.
    JScrollPane list_scroll_pane = new JScrollPane (fAlgorithmJList);

    // Create a panel to hold the controls.
    JPanel control_panel = new JPanel ();
    control_panel.add (dim_param_panel);
    control_panel.add (list_scroll_pane);
    control_panel.add (fResetButton);

    // And combine it with the FractalPanel.
    panel.add (control_panel,"South");

    // Create the bifurcation algorithm as the first choice.
    drawFractals[ALG_BIFURCATION] = new DrawBifurcationImg ();

    // Only need one parameter for the bifurcation algorithm
    fLabelParam1.setEnabled (false);
    fFieldParam1.setEnabled (false);

    // Add the algorithm panel here.
    fOutputPanel = new FractalPanel (this, drawFractals[0],
                                     fXYDef[fAlgorithm][0],
                                     fXYDef[fAlgorithm][1],
                                     fXYDef[fAlgorithm][2],
                                     fXYDef[fAlgorithm][3]);

    panel.add (fOutputPanel,"Center");

    // Then add this panel to the applet.
    add (panel);

  } // init

  /**
    * Implementation of FractalController interface: This method
    * provides for callbacks from the FractalPanel with the new
    * dimensions for the area to plot.
    *
    **/
  public void setFractalParameters (double x_min, double x_max,
                                    double y_min, double y_max) {
    // Reset dimensions to defaults.
    fFieldXLeft.setText (PlotFormat.getFormatted (x_min, 100.0, 1000.0, 3));
    fFieldXRite.setText (PlotFormat.getFormatted (x_max, 100.0, 1000.0, 3));
    fFieldYBot.setText  (PlotFormat.getFormatted (y_min, 100.0, 1000.0, 3));
    fFieldYTop.setText  (PlotFormat.getFormatted (y_max, 100.0, 1000.0, 3));
  } // setFractalParameters


  /**
    * Implementation of FractalController interface: This method
    * provides the values in the text fields for the parameters
    * needed by a given algorithm.
   **/
  public void getFractalParameters (double [] parameters) {

    if (fAlgorithm == ALG_BIFURCATION) {
       try {
         fParam0 = Double.valueOf (fFieldParam0.getText ());
       } catch (NumberFormatException nfe) {
         fParam0 = fAlgorithmParams[ALG_BIFURCATION][0];
         fFieldParam0.setText ("0.0");
       }
       parameters[2] = fParam0;

    } else
    if (fAlgorithm == ALG_JULIASET) { // Julia Set
       try {
         fParam0 = Double.valueOf (fFieldParam0.getText ());
         fParam0 = Double.valueOf (fFieldParam0.getText ());
       } catch (NumberFormatException nfe) {
         fParam0 = fAlgorithmParams[ALG_JULIASET][0];
         fParam1 = fAlgorithmParams[ALG_JULIASET][1];
         fFieldParam0.setText (Double.toString (fParam0));
       }
       parameters[2] = fParam0;
       parameters[3] = fParam1;
    } else
    if (fAlgorithm == ALG_JULIASET_NEWT ||
        fAlgorithm == ALG_MANDLEBROT ) { // Julia Set - Newton's method
                                         // or Mandlebrot
    }

  } // getFractalParameters


  /**
    * Implementation of FractalController interface: This method
    * turns off controls while fractal generation runs. It turns
    * them back on when the generation is done.
   **/
  public void setBusy (boolean flag) {

    if (flag) {
        fResetButton.setEnabled (false);
        fAlgorithmJList.setEnabled (false);
        if (fAlgorithm == ALG_BIFURCATION ||
            fAlgorithm == ALG_JULIASET) {
           fFieldParam0.setEnabled (false);
           fLabelParam0.setEnabled (false);
        }
        if (fAlgorithm == ALG_JULIASET) {
            fFieldParam1.setEnabled (false);
            fLabelParam1.setEnabled (false);
        }
        fResetButton.setText ("BUSY");
    } else {
        fResetButton.setEnabled (true);
        fAlgorithmJList.setEnabled (true);
        if (fAlgorithm == ALG_BIFURCATION ||
            fAlgorithm == ALG_JULIASET) {
           fFieldParam0.setEnabled (true);
           fLabelParam0.setEnabled (true);
        }
        if (fAlgorithm == ALG_JULIASET) {
            fFieldParam1.setEnabled (true);
            fLabelParam1.setEnabled (true);
        }
        fResetButton.setText ("Reset");
    }
  } // setBusy


  /**
    * Reset button will reset the drawing area back to
    * the default dimensions.
   **/
  public void actionPerformed (ActionEvent e)
  {
    Object source = e.getSource ();
    if (source == fResetButton) {
        // Reset dimensions to defaults
        resetDefaultFrame ();
        fOutputPanel.setRange (fXYDef[fAlgorithm][0],
                               fXYDef[fAlgorithm][1],
                               fXYDef[fAlgorithm][2],
                               fXYDef[fAlgorithm][3]);
    }
  } // actionPerformed


  /** Reset the frame to the default dimensions. **/
  public void resetDefaultFrame ()
  {
     // Reset dimensions to defaults
    fFieldXLeft.setText (Double.toString (fXYDef[fAlgorithm][0]));
    fFieldXRite.setText (Double.toString (fXYDef[fAlgorithm][1]));
    fFieldYBot.setText  (Double.toString (fXYDef[fAlgorithm][2]));
    fFieldYTop.setText  (Double.toString (fXYDef[fAlgorithm][3]));
  } // resetDefaultFrame


  /**
    * User selects an algorithm from the JList.
   **/
  public void valueChanged (ListSelectionEvent evt)  {

    // Get the reference to the JList object
    JList source =  (JList)evt.getSource ();

    // and get an array of the selected items.
    Object [] values = source.getSelectedValues ();

    // In this case only one value can be selected
    // so just look at first item in array.
    String algorithm_selected =  (String)values[0];

    // Set the title accordingly
    fOutputPanel.setTitle (algorithm_selected);

    // For the selected algorithm, pass it to the FractalPanel
    // and also set up the parameter elements on the user interface.

    if (algorithm_selected.equals (fAlgorithmList[ALG_BIFURCATION])) {
        // Only need one parameter for the bifurcation algorithm
        fLabelParam1.setEnabled (false);
        fFieldParam1.setEnabled (false);
        fAlgorithm = ALG_BIFURCATION;
        fParam0 = fAlgorithmParams[fAlgorithm][0];
        fFieldParam0.setText (Double.toString (fParam0));
        fFieldParam1.setText (" ");
    } else
    if (algorithm_selected.equals (fAlgorithmList[ALG_JULIASET])) {
        // Need two parameters for the Julia set algorithm
        fLabelParam1.setEnabled (true);
        fFieldParam1.setEnabled (true);
        fAlgorithm = ALG_JULIASET;
        fParam0 = fAlgorithmParams[fAlgorithm][0];
        fParam1 = fAlgorithmParams[fAlgorithm][1];
        fFieldParam0.setText (Double.toString (fParam0));
        fFieldParam1.setText (Double.toString (fParam1));
        // Reset back to the default frame scale
        resetDefaultFrame ();
        // Get the algorithm
        if (drawFractals[fAlgorithm] == null)
           drawFractals[fAlgorithm] = new DrawJuliaSetImg ();
    } else
    if (algorithm_selected.equals (fAlgorithmList[ALG_JULIASET_NEWT])) {
        // No parameters used for the Julia set from Newton's method
        fLabelParam0.setEnabled (false);
        fFieldParam0.setEnabled (false);
        fLabelParam1.setEnabled (false);
        fFieldParam1.setEnabled (false);
        fAlgorithm = ALG_JULIASET_NEWT;
        fFieldParam0.setText (" ");
        fFieldParam1.setText (" ");
        // Reset back to the default frame scale
        resetDefaultFrame ();
        // Get the algorithm
        if (drawFractals[fAlgorithm] == null)
           drawFractals[fAlgorithm] = new DrawJuliaSetNewtonImg ();
    } else
    if (algorithm_selected.equals (fAlgorithmList[ALG_MANDLEBROT])) {
        // No parameters used for the Mandlebrot algorithm
        fLabelParam0.setEnabled (false);
        fFieldParam0.setEnabled (false);
        fLabelParam1.setEnabled (false);
        fFieldParam1.setEnabled (false);
        fAlgorithm = ALG_MANDLEBROT;
        fFieldParam0.setText (" ");
        fFieldParam1.setText (" ");
        // Reset back to the default frame scale
        resetDefaultFrame ();
        // Get the algorithm
        if (drawFractals[ALG_MANDLEBROT] == null)
           drawFractals[ALG_MANDLEBROT] = new DrawMandlebrotImg ();
    }

    // Reset back to the default frame scale
    resetDefaultFrame ();
    // Pass the new algorithm to the panel
    fOutputPanel.setAlgorithm (drawFractals[fAlgorithm]);
    // Reseting the range will cause the panel to redraw
    // itself with the new algorithm.
    fOutputPanel.setRange (fXYDef[fAlgorithm][0],
                           fXYDef[fAlgorithm][1],
                           fXYDef[fAlgorithm][2],
                           fXYDef[fAlgorithm][3]);

  } // valueChanged

  /** Optional application mode. **/
  public static void main (String[] args)  {
    // Frame size.
    int frame_width  = 550;
    int frame_height = 300;

    // Add an instance of this applet to the frame
    FractalsImgApplet applet = new FractalsImgApplet ();
    applet.fInBrowser = false;
    applet.init ();

    // Following anonymous class used to close window & exit program
    JFrame f = new JFrame ("Fractal Demo with Images");
    f.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);

    // Add applet to the frame
    f.add (applet);
    f.setSize (new Dimension (frame_width,frame_height));
    f.setVisible (true);

  } // main

} // class FractalsImgApplet

  
import java.awt.*;
import java.awt.image.*;

/**
  * Create patterns with the bifurcation algorithm on the drawing context
  * passed to it. The draw() method modifies the pixels in an image object
  * and then draws that image.
  *
  * The program follows the algorithm as given in "Java Number Cruncher"
  * by R. Mak.
  *
  * Use a BufferedImage to create the plot.
**/
public class DrawBifurcationImg extends DrawFunction
{
  private static final int MAX_ITERATIONS   = 200;
  private static final int SKIP_INTERATIONS =  50;

  /**
    *  Create fractal patterns with the bifurcation algorithm.
    *  Modify the pixels of a BufferedImage object and then
    *  draw the image with the given graphics context.
    *
    *  @param g graphics context
    *  @param frame_width display area width in pixels.
    *  @param frame_height display area height in pixels.
    *  @param frame_start_x horizontal point on display where
    *    drawing starts in pixel number.
    *  @param frame_start_y vertical point on display where
    *    drawing starts in pixel number.
    *  @param x_scale 2 dimensional array holding lower and
    *    upper values of the function input scale range.
    *  @param y_scale 2 dimensional array holding lower and
    *    upper values of the function output scale range.
   **/
  public void draw (Graphics g,
                   int frame_start_x, int frame_start_y,
                   int frame_width, int frame_height,
                   double [] x_scale, double [] y_scale) {

    // Check if ready to draw
    if (fParameters == null) return;

    // Create an image on which to create the plot.
    // Size the image to fit within the frame
    int img_width  = frame_width  - 1;
    int img_height = frame_height - 1;
    int numPixels = img_width * img_height;
    int [] pixels = new int [numPixels];

    // Coordinates in pixel scale
    int row = 0;
    int col = 0;
    int ipx = 0;

    // Fill the image with the background color
    int gray = 0xBB;
    int bg_color = (gray << 16) | (gray << 8 ) | gray;
    for (row = 0; row < img_height; row++) {
      for (col = 0; col < img_width; col++) {
        ipx = col + row * img_width; // pixel pointer
        pixels[ipx] = bg_color;
      }
    }

    int y_max_index = y_scale.length - 1;

    // Get conversion factors from data scale to frame pixels
    double x_scale_factor = fParameters[0]/frame_width;
    double y_scale_factor = fParameters[1]/frame_height;


    // Outer loop steps through the c value along the horizontal axis.
    for (col = 0; col < img_width; col++) {
        // Change from pixel scale to the data scale
        double c = x_scale[0] + col * x_scale_factor;
        double z = fParameters[2]; // Pass the starting value.

        // Now on this column, plot z along the vertical axis as determined
        // by the function:
        //   z = z*z + c
        // Plot it for MAX_ITERATIONS number of times. However, don't start
        // plotting until after SKIP_ITERATIONS number of times so as to
        // reach the orbit behavior of the function.
        int red = 0xff << 16;
        for (int i=0; i < MAX_ITERATIONS; i++) {
            z = z*z + c;
            if (i >= SKIP_INTERATIONS) {
                // Convert from data scale to pixel scale
                row = (int)Math.round ((y_scale[y_max_index] -
                          z)/y_scale_factor);
                if (row < img_height && row >= 0) {
                   ipx = col + row * img_width; // pixel pointer
                   pixels[ipx] = red;
                }
            }
        }
    }
    // Create a BufferedIamge of the RGB type.
    BufferedImage buf_img =
       new BufferedImage (img_width, img_height, BufferedImage.TYPE_INT_RGB);

    // Pass the image the pixel array.
    buf_img.setRGB (0,0,img_width,img_height,pixels,0,img_width);

    g.drawImage (buf_img, frame_start_x+1, frame_start_y+1, null);

  } // draw

} // class DrawBifurcationImg

  
import java.awt.*;
import java.awt.image.*;

/**
  * Draw the Julia set algorithm onto the PlotPanel.
  * Follows the algorithm as given in "Java Number Cruncher"
  * by R. Mak.
  *
  * Use a BufferedImage to create the plot.
**/
public class DrawJuliaSetImg extends DrawFunction
{
  private static final int MAX_ITERATIONS   = 32;
  private static final int ESCAPE_MAGNITUDE =  2;

  /**
    *  Execute the Julia set algorithm onto the PlotPanel.
    *
    *  @param g graphics context
    *  @param frame_width display area width in pixels.
    *  @param frame_height display area height in pixels.
    *  @param frame_start_x horizontal point on display where
    *    drawing starts in pixel number.
    *  @param frame_start_y vertical point on display where
    *    drawing starts in pixel number.
    *  @param x_scale 2 dimensional array holding lower and
    *    upper values of the function input scale range.
    *  @param y_scale 2 dimensional array holding lower and
    *    upper values of the function output scale range.
   **/
  public void draw (Graphics g,
                   int frame_start_x, int frame_start_y,
                   int frame_width, int frame_height,
                   double [] x_scale, double [] y_scale) {

    // Check if ready to draw the line
    if (fParameters == null) return;

    int y_max_index = y_scale.length - 1;

    // Create an image on which to create the plot.
    // Size the image to fit within the frame
    int img_width  = frame_width  - 1;
    int img_height = frame_height - 1;
    int numPixels = img_width * img_height;
    int [] pixels = new int [numPixels];

    // Get conversion factors from data scale to frame pixels
    double x_scale_factor = fParameters[0]/frame_width;
    double y_scale_factor = fParameters[1]/frame_height;

    // Obtain the complex constant from the user interface.
    Complex c = new Complex (fParameters[2], fParameters[3]);
    Complex z = new Complex (0.0,0.0);

    // Coordinates in pixel scale
    int row = 0;
    int col = 0;
    int ipx = 0;

    // Outer loop steps through the c value along the horizontal axis.
    for (row = 0; row < img_height; row++) {
        // Change from pixel scale to the data scale
        double y_beg = y_scale[y_max_index] - row * y_scale_factor;

        for (col = 0; col < img_width; col++) {
          ipx = col + row * img_width; // pixel pointer
          double x_beg = x_scale[0] + col * x_scale_factor;
          z.real = x_beg; z.img = y_beg; // Set the starting value.

          boolean escaped = false;
          int iter   = 0;
          double x   = x_beg;
          double y   = y_beg;
          double mag = 0.0;

          // Iterate the function:
          //   z = z*z + c
          do {
              z.multiply (z);
              z.add (c);
              mag = z.modulus ();
              escaped = mag > ESCAPE_MAGNITUDE;
              ++iter;
          } while (iter < MAX_ITERATIONS && (!escaped));

          // If escaped, then set color to a shade of gray
          // proportional to the number of interations. The
          // more iterations, the darker
          if (escaped) {
              int gray = 0xFF - (0xFF*iter)/MAX_ITERATIONS;
              gray = Math.min (gray, 240);
              pixels[ipx] = (gray << 16) | (gray << 8 ) | gray;

          } else {

          // Did not escape so relate the color instead to the
          // final magnitude of z.

              int i = ((int)(100*mag)) / ESCAPE_MAGNITUDE + 1;
              int red = (425*i) & 0xFF;
              int grn = (375*i) & 0xFF;
              int blu = (325*i) & 0xFF;

              pixels[ipx] = (red << 16) | (grn << 8 ) | blu;
          }
        }
    }
    // Create a BufferedIamge of the RGB type.
    BufferedImage buf_img =
       new BufferedImage (img_width, img_height, BufferedImage.TYPE_INT_RGB);

    // Pass the image the pixel array.
    buf_img.setRGB (0,0,img_width,img_height,pixels,0,img_width);

    g.drawImage (buf_img, frame_start_x+1, frame_start_y+1, null);

  } // draw

} // class DrawJuliaSetImg

  
import java.awt.*;
import java.awt.image.*;

/**
  * Draw the Julia set algorithm onto the PlotPanel.
  * Follows the algorithm given in "Java Number Cruncher"
  * by R. Mak for solving f(z) = z^3 -1 with Newton's
  * algorithm.
  *
  * Use a BufferedImage to create the plot.
**/
public class DrawJuliaSetNewtonImg extends DrawFunction
{
  private static final int MAX_ITERATIONS   = 100;

  // Create two complex constants needed in the algorthm.
  private static final Complex Z_ONE   = new Complex (1,0);
  private static final Complex Z_THREE = new Complex (3,0);

  // Create a pool of complex numbers to use in the algorithm
  private Complex fZ0 = new Complex (0.0, 0.0);
  private Complex fZ2 = new Complex (0.0, 0.0);
  private Complex fZ3 = new Complex (0.0, 0.0);

  /**
    *
    *  Create fractal patterns with the Julia set via
    *  Newton's method algorithm.
    *  Modify the pixels of a BufferedImage object and then
    *  draw the image with the given graphics context.
    *
    *  @param g graphics context
    *  @param frame_width display area width in pixels.
    *  @param frame_height display area height in pixels.
    *  @param frame_start_x horizontal point on display where
    *    drawing starts in pixel number.
    *  @param frame_start_y vertical point on display where
    *    drawing starts in pixel number.
    *  @param x_scale 2 dimensional array holding lower and
    *    upper values of the function input scale range.
    *  @param y_scale 2 dimensional array holding lower and
    *    upper values of the function output scale range.
   **/
  public void draw (Graphics g,
                   int frame_start_x, int frame_start_y,
                   int frame_width, int frame_height,
                   double [] x_scale, double [] y_scale) {

   // Check if ready to draw the line
    if (fParameters == null) return;

    int y_max_index = y_scale.length - 1;

    // Create an image on which to create the plot.
    // Size the image to fit within the frame
    int img_width  = frame_width  - 1;
    int img_height = frame_height - 1;
    int numPixels = img_width * img_height;
    int [] pixels = new int [numPixels];

    // Get conversion factors from data scale to frame pixels
    double x_scale_factor = fParameters[0]/frame_width;
    double y_scale_factor = fParameters[1]/frame_height;

    // Create our complex variable for the algorithm.
    Complex z  = new Complex (0.0,0.0);

    // Coordinates in pixel scale
    int row = 0;
    int col = 0;
    int ipx = 0;

    // Outer loop steps through the c value along the horizontal axis.
    for (row = 0; row < img_height; row++) {
        // Change from pixel scale to the data scale
        double y_beg = y_scale[y_max_index] - row * y_scale_factor;

        for (col = 0; col < img_width; col++) {
          ipx = col + row * img_width; // pixel pointer
          double x_beg = x_scale[0] + col * x_scale_factor;

          // Create the z for this point on the complex plane
          z.real = x_beg; z.img = y_beg; // Set the starting value.

          int iter   = 0;

          // Iterate the function:
          //   z = z*z*z - 1
          do {
              // Use the pool complex objects to hold intermediate values
              fZ0.real = z.real; fZ0.img = z.img; // save z in fZ0
              z.multiply (z);  // z = z * z
              fZ2.real = z.real; fZ2.img = z.img; // save z*z in fZ2
              z.multiply (fZ0);// z = z * z * z
              fZ3.real = z.real; fZ3.img = z.img; // save z*z*z in fZ3

              // Now comute the iteration formula from Newton's method.
              //     (z^3 -1.0)/(3.0 * z^2)
              fZ3.subtract (Z_ONE); // fZ3 = z*z*z - 1
              fZ2.multiply (Z_THREE); // fZ2 = 3.0 * z*z
              z.real = fZ3.real; z.img = fZ3.img;
              z.divide (fZ2); // z = (z^3 - 1.0)/(3.0 * z^2)

              ++iter;
          } while (iter < MAX_ITERATIONS && (!z.equals (fZ0)) );

          // Set color proportional to the number of interations.
          int colorComp = 20 * (iter%10);

          if (z.real > 0.0) { // root = 1
              pixels[ipx] =
                (colorComp << 16) | (colorComp << 8 ) | 0xFF;
          } else
          if (z.img > 0.0) { // root ~= -0.5 + .9i
              pixels[ipx] =
                (colorComp << 16) | (0xFF << 8 ) | colorComp;
          } else { // root ~= -0.5 - 0.9i
              pixels[ipx] =
                (0xFF << 16) | (colorComp << 8 ) | colorComp;
          }
        }
    }

    // Create a BufferedIamge of the RGB type.
    BufferedImage buf_img =
       new BufferedImage (img_width, img_height, BufferedImage.TYPE_INT_RGB);

    // Pass the image the pixel array.
    buf_img.setRGB (0,0,img_width,img_height,pixels,0,img_width);

    g.drawImage (buf_img, frame_start_x+1, frame_start_y+1, null);

  } // draw

} // class DrawJuliaSetNewtonImg

  
import java.awt.*;
import java.awt.image.*;

/**
  * Create a fractal pattern with the Mandlebrot method on
  * the pixels of a BufferedImage. Then draw this image.
  * Follows the algorithm given in "Java Number Cruncher"
  * by R. Mak for solving f(z) = z^3 -1 with Newton's
  * algorithm.
  *
  * Use a BufferedImage to create the plot.
**/
public class DrawMandlebrotImg extends DrawFunction
{
  private static final int MAX_ITERATIONS   = 32;
  private static final int ESCAPE_MAGNITUDE =  2;

  // Create two complex constants needed in the algorthm.
  private static final Complex Z_ONE   = new Complex (1,0);
  private static final Complex Z_THREE = new Complex (3,0);

  // Create a pool of complex numbers to use in the algorithm
  private Complex fZ0 = new Complex (0.0, 0.0);
  private Complex fZ2 = new Complex (0.0, 0.0);
  private Complex fZ3 = new Complex (0.0, 0.0);

  /**
    *
    *  Create fractal patterns with the Mandlebrot algorithm.
    *  Modify the pixels of a BufferedImage object and then
    *  draw the image with the given graphics context.
    *
    *  @param g graphics context
    *  @param frame_width display area width in pixels.
    *  @param frame_height display area height in pixels.
    *  @param frame_start_x horizontal point on display where
    *    drawing starts in pixel number.
    *  @param frame_start_y vertical point on display where
    *    drawing starts in pixel number.
    *  @param x_scale 2 dimensional array holding lower and
    *    upper values of the function input scale range.
    *  @param y_scale 2 dimensional array holding lower and
    *    upper values of the function output scale range.
   **/
  public void draw (Graphics g,
                   int frame_start_x, int frame_start_y,
                   int frame_width, int frame_height,
                   double [] x_scale, double [] y_scale) {

    // Check if ready to draw
    if (fParameters == null) return;

    // Create an image on which to create the plot
    // Size the image to fit within the frame
    int img_width  = frame_width  - 1;
    int img_height = frame_height - 1;
    int numPixels = img_width * img_height;
    int [] pixels = new int [numPixels];

    int y_max_index = y_scale.length - 1;

    // Get conversion factors from data scale to frame pixels
    double x_scale_factor = fParameters[0]/frame_width;
    double y_scale_factor = fParameters[1]/frame_height;

    // Create our complex variable for the algorithm.
    Complex z  = new Complex (0.0,0.0);
    Complex c  = new Complex (0.0,0.0);

    // Coordinates in pixel scale
    int row = 0;
    int col = 0;
    int ipx = 0;

    // Outer loop steps through the c value along the horizontal axis.
    for (row = 0; row < img_height; row++) {
        // Change from pixel scale to the data scale
        double y_beg = y_scale[y_max_index] - row * y_scale_factor;

        for (col = 0; col < img_width; col++) {
          ipx = col + row * img_width; // pixel pointer
          double x_beg = x_scale[0] + col * x_scale_factor;

          // Create the c for this point on the complex plane
          c.real = x_beg; c.img = y_beg; // Set the complex constant
          z.real = 0.0;   z.img = 0.0;   // Initialize z to 0 + 0i.

          boolean escaped = false;
          int iter   = 0;
          double x   = x_beg;
          double y   = y_beg;
          double mag = 0.0;

          // Iterate the function:
          //   z = z*z + c
          do {
              z.multiply (z);
              z.add (c);
              mag = z.modulus ();
              escaped = mag > ESCAPE_MAGNITUDE;
              ++iter;
          } while (iter < MAX_ITERATIONS && (!escaped));

          // If escaped, then set color to a shade of gray
          // proportional to the number of interations. The
          // more iterations, the darker
          if (escaped) {
              int gray = 0xFF - (0xFF*iter)/MAX_ITERATIONS;
              gray = Math.min (gray, 240);
              pixels[ipx] = (gray << 16) | (gray << 8 ) | gray;
          } else {

          // Did not escape so relate the color instead to the
          // final magnitude of z.

              int i = ((int)(100*mag)) / ESCAPE_MAGNITUDE + 1;
              int red = (100*i) & 0xFF;
              int grn = (150*i) & 0xFF;
              int blu = (200*i) & 0xFF;

              pixels[ipx] = (red << 16) | (grn << 8 ) | blu;
           }
        }
    }
    // Create a BufferedIamge of the RGB type.
    BufferedImage buf_img =
       new BufferedImage (img_width, img_height, BufferedImage.TYPE_INT_RGB);

    // Pass the image the pixel array.
    buf_img.setRGB (0,0,img_width,img_height,pixels,0,img_width);

    g.drawImage (buf_img, frame_start_x+1, frame_start_y+1, null);

  } // draw

} // class DrawMandlebrotImg

  

 

References & Web Resources

 

Most recent update: June 24, 2005

              Tech
Fractals
Fractal Drawing
   Demo 1
Fractal Draw Code
Fractal Images
  Demo 2
Image Processing
  Demo 3
Histogram Image
  Demo 4
Exercises

           Physics
Calibration/SysError
SimWithCal/SysErr
  Demo 1
Analysis
  Demo 2
Examples

Exercises

  Part I Part II Part III
Java Core 1  2  3  4  5  6  7  8  9  10  11  12 13 14 15 16 17
18 19 20
21
22 23 24
Supplements

1  2  3  4  5  6  7  8  9  10  11  12

Tech 1  2  3  4  5  6  7  8  9  10  11  12
Physics 1  2  3  4  5  6  7  8  9  10  11  12

Java is a trademark of Sun Microsystems, Inc.