| Here are the DrawFunction 
              subclasses used to create and draw the fractal patterns for the 
               FractalsApplet 
              demonstration program. The algorithms 
              were described earlier.  The key features of the draw() 
              method in DrawBifurcation 
              are the three loops. The outer loop cycles through the columns (i.e. 
              the x horizontal 
              coordinate) of the plot. The first inner loop sets all the points 
              on each column to a fixed background color. The second inner loop 
              implements the heart of the algorithm. The given formula is interated 
              for MAX_ITERATIONS 
              number of times. After skipping an initial set of interations so 
              as to reach the orbit behavior of the iterated values, a color is 
              draw for each row (i.e. point on the y 
              axis) obtained from a scaling of the iterated variable z. The draw() 
              methods for the other three algorithms also eacj include three key 
              loops but the structure differs. The outer loop cycles over the 
              rows (i.e.  x 
              values) and a second nested loop cycles through the columns (i.e. 
               y 
              values). A third loop iterates the function starting from a value 
              determined by the current column, row point (i.e. x_beg, 
               y_beg). 
              After the loop either finishes or "escapes", the final 
              iterated value determines the color at the column, row (i.e. x,y) 
              point. In all four cases, the drawLine() 
              method in Graphics 
              is used to draw each point of the pattern. This involves many invocatins 
              of drawLine() 
              and an alternative method involving the modification of pixel values 
              in an image is used instead in the next demonstration 
              program to speed up the display. Note that for the complex numbers, 
              we use the Complex.java 
              class from Chapter 4: Tech. 
              Unlike the immutable complex class discussed in Chapter 
              5: Tech, this class allows direct access to the real and imaginary 
              data variables. Since the processing here is quite intensive, we 
              decided to take advantage of this capability to obtain faster performance. 
              The immutable class requires method invocations to access the real 
              and imaginary data and also require that new objects be created 
              for every new complex value. These all take up some amount of time, 
              which may or may not be noticable depending on the processor.  
              
                 
                  | Fractal 
                      Algorithm Classes used in FractalsApplet
  
                      DrawBifurcation.java 
                          - DrawFunction subclass that draws fractal pattern generated 
                        with the Bifurcation algorithm. DrawJuliaSet.java
  - DrawFunction subclass that draws fractal pattern generated 
                        with the Julia Set algorithm. DrawJuliaSetNewton.java
  - DrawFunction subclass that draws fractal generated pattern 
                        with the Julia Set via Newton's method algorithm. DrawMandlebrot.java
  - DrawFunction subclass that draws fractal pattern generated 
                        with the Mandlebrot algorithm. + 
                        Previous class: Chapter 
                        4:Tech: Complex.java
 
 |  
                  | import 
                      java.awt.*;
 /**
 * Draw patterns with the bifurcation algorithm 
                      on a graphics
 * context passed to it.
 *
 * It follows the algorithm as given in "Java 
                      Number Cruncher"
 * by R. Mak.
 **/
 public class DrawBifurcation extends DrawFunction
 {
 private static final int MAX_ITERATIONS   
                      = 200;
 private static final int SKIP_INTERATIONS =  50;
 
 /**
 *  Execute the bifurcation 
                      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) {
 
 Color save_color = g.getColor ();
 int y_max_index = y_scale.length 
                      - 1;
 
 // Don't draw outside of the frame.
 g.setClip (frame_start_x+1, frame_start_y+1, 
                      frame_width-1, frame_height-1);
 
 // Check if ready to draw the line
 if (fParameters == null) return;
 
 // 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;
 
 // Coordinates in pixel scale
 int row = 0;
 int col = 0;
 
 // Outer loop steps through the 
                      c values along the horizontal axis.
 for (col = 0; col < frame_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.
 
 // Draw 
                      the background color for each column.
 g.setColor 
                      (fColor);
 for (row=0; 
                      row < frame_height; row++) {
 g.drawLine 
                      (col+frame_start_x, row+frame_start_y,
 col+frame_start_x, 
                      row+frame_start_y);
 }
 
 // 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.
 g.setColor 
                      (Color.RED);
 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);
 
 // 
                      Use the drawLine method to plot a point.
 g.drawLine 
                      (col+frame_start_x, row+frame_start_y,
 col+frame_start_x, 
                      row+frame_start_y);
 }
 }
 }
 g.setColor (save_color);
 
 } // draw
 
 } // class DrawBifurcation
 
 
   |   
                  | /** * Draw patterns with the Julia set algorithm on 
                    a graphics
 * context passed to it.
 *
 * The class follows the algorithm as given in 
                    "Java Number Cruncher"
 * by R. Mak.
 **/
 public class DrawJuliaSet extends DrawFunction
 {
 private static final int MAX_ITERATIONS   
                    = 32;
 private static final int ESCAPE_MAGNITUDE =  2;
 
 /**
 *  Draw fractal patterns 
                    with the Julia set algorithm.
 *
 *  @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) {
 
 Color save_color = g.getColor ();
 int y_max_index = y_scale.length - 
                    1;
 
 // Don't draw outside of the frame.
 g.setClip (frame_start_x+1, frame_start_y+1, 
                    frame_width-1, frame_height-1);
 
 // Check if ready to draw the line
 if (fParameters == null) return;
 
 // 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;
 
 // Outer loop steps through the c 
                    value along the horizontal axis.
 for (row = 0; row < frame_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 < frame_width; col++) {
 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);
 g.setColor 
                    (new Color (gray, gray, gray));
 g.drawLine 
                    (col+frame_start_x, row+frame_start_y,
 col+frame_start_x, row+frame_start_y);
 
 } 
                    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;
 
 g.setColor 
                    (new Color (red,grn,blu));
 // 
                    Use the drawLine method to plot a point.
 g.drawLine 
                    (col+frame_start_x, row+frame_start_y,
 col+frame_start_x, 
                    row+frame_start_y);
 }
 }
 }
 g.setColor (save_color);
 
 } // draw
 
 } // class DrawJuliaSet
 
 
   |   
                  | import 
                    java.awt.*; 
 /**
 * Draw patterns with the Julia set via Newton's 
                    method.
 
 *
 * Follow the algorithm given in "Java Number Cruncher"
 * by R. Mak for solving f(z) = z^3 - 1 with Newton's 
                    algorithm.
 *
 **/
 public class DrawJuliaSetNewton 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 from Newton's
 *  method algorithm and 
                    draw them with the 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) {
 
 Color save_color = g.getColor ();
 int y_max_index = y_scale.length - 
                    1;
 
 // Don't draw outside of the frame.
 g.setClip (frame_start_x+1, frame_start_y+1, 
                    frame_width-1, frame_height-1);
 
 // Check if ready to draw the line
 if (fParameters == null) return;
 
 // 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;
 
 // Outer loop steps through the c 
                    value along the horizontal axis.
 for (row = 0; row < frame_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 < frame_width; col++) {
 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
 g.setColor 
                    (new Color (colorComp, colorComp, 0xFF));
 g.drawLine 
                    (col+frame_start_x, row+frame_start_y,
 col+frame_start_x, 
                    row+frame_start_y);
 } 
                    else
 if 
                    (z.img > 0.0) { // root ~= -0.5 + .9i
 g.setColor 
                    (new Color (colorComp, 0xFF, colorComp));
 g.drawLine 
                    (col+frame_start_x, row+frame_start_y,
 col+frame_start_x, 
                    row+frame_start_y);
 } 
                    else { // root ~= -0.5 - 0.9i
 g.setColor 
                    (new Color (0xFF, colorComp, colorComp));
 g.drawLine 
                    (col+frame_start_x, row+frame_start_y,
 col+frame_start_x, 
                    row+frame_start_y);
 }
 }
 }
 g.setColor (save_color);
 } // draw
 
 } // class DrawJuliaSetNewton
 
 
   |   
                  | import 
                    java.awt.*; 
 /**
 * Draw patterns with the Mandlebrot algorithm.
 
 *
 * Follows the algorithm given in "Java Number 
                    Cruncher"
 * by R. Mak for solving f(z) = z^3 -1 with Newton's
 * algorithm.
 **/
 public class DrawMandlebrot 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 and draw them 
                    with the 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) {
 
 Color save_color = g.getColor ();
 int y_max_index = y_scale.length - 
                    1;
 
 // Don't draw outside of the frame.
 g.setClip (frame_start_x+1, frame_start_y+1, 
                    frame_width-1, frame_height-1);
 
 // Check if ready to draw the line
 if (fParameters == null) return;
 
 // 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;
 
 // Outer loop steps through the c 
                    value along the horizontal axis.
 for (row = 0; row < frame_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 < frame_width; col++) {
 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);
 g.setColor 
                    (new Color (gray, gray, gray));
 g.drawLine 
                    (col+frame_start_x, row+frame_start_y,
 col+frame_start_x, 
                    row+frame_start_y);
 
 } 
                    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;
 
 g.setColor 
                    (new Color (red,grn,blu));
 // 
                    Use the drawLine method to plot a point.
 g.drawLine 
                    (col+frame_start_x, row+frame_start_y,
 col+frame_start_x, 
                    row+frame_start_y);
 }
 }
 }
 g.setColor (save_color);
 } // draw
 
 } // class DrawMandlebrot
 
 
   |    
                 Most recent update: June 25, 2005 |