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
|