Improved Mandelbrot Applet
|
Here is our new and improved Mandelbrot applet. It now computes the picture in an
off-screen area and displays it in the visible area after each vertical pass.
Make sure you click on the Control button to change parameters. Notice that the
computation will start over as soon as you click on the Apply button.
Also, switch to the previous page, wait a few seconds, then return to this page. You
should notice that the computation goes on in the background even when you are not looking
at the page. |
The source code consists of three classes: the main
applet, a control dialog, and the drawing canvas. The three classes are listed
below:
Main Applet
import java.applet.*;
import java.awt.*;
public class TmpMandel extends Applet
{
private Image offImage = null;
private Button button = new Button("Controls");
private TmpMandelCanvas drawing;
private TmpMandelControl control;
/* =========================================================== */
public void init()
{
setLayout(new BorderLayout());
Panel bottomRow = new Panel(); bottomRow.setLayout(new FlowLayout());
bottomRow.add(button);
add("South", bottomRow);
int w = super.size().width;
int h = super.size().height - bottomRow.preferredSize().height;
offImage = createImage(width, height);
drawing = new TmpMandelCanvas (offImage,w, h, -2, 2, -2, 2, 50, 2);
control = new TmpMandelControl(this,-2,2,-2,2,50,2);
add("Center", drawing);
}
/* =========================================================== */
public void setDrawingParams(double xMin, double xMax,
double yMin, double yMax,
int iter, int pixel)
{
drawing.stop();
drawing.setParams(xMin,xMax,yMin,yMax,iter,pixel);
drawing.start();
}
/* =========================================================== */
public boolean action(Event e, Object arg)
{
if (e.target == button)
{
control.show(); control.toFront();
return true;
}
else
return false;
}
}
Control Dialog
import java.awt.*;
public class TmpMandelControl extends Frame
{
private double xMin, xMax, yMin, yMax;
private int iter, pixel;
private NumberFieldPlus xMinField = new NumberFieldPlus(-2.0,9),
xMaxField = new NumberFieldPlus(2.0,9),
yMinField = new NumberFieldPlus(-2.0,9),
yMaxField = new NumberFieldPlus(2.0,9),
iterField = new NumberFieldPlus(40,5),
pixelField = new NumberFieldPlus(2,5),
Private Button Okay = new Button("Okay"),
Cancel = new Button("Cancel"),
Apply = new Button("Apply");
Private TmpMandel master;
public TmpMandelControl(TmpMandel _master, double _xMin, double _xMax,
double _yMin, double _yMax, int _iter, int _pixel)
{
super("Mandelbrot Controls");
master = _master;
xMinField.setDelta(0.2); xMaxField.setDelta(0.2);
yMinField.setDelta(0.2); yMaxField.setDelta(0.2);
setParams(_xMin,_xMax,_yMin,_yMax,_iter,_pixel);
Panel ButtonRow = new Panel();
ButtonRow.setLayout(new FlowLayout());
ButtonRow.add(Okay); ButtonRow.add(Apply); ButtonRow.add(Cancel);
Panel Params = new Panel();
Params.setLayout(new GridLayout(6,2));
Params.add(new Label("xMin:")); Params.add(xMinField);
Params.add(new Label("xMax:")); Params.add(xMaxField);
Params.add(new Label("yMin:")); Params.add(yMinField);
Params.add(new Label("yMax:")); Params.add(yMaxField);
Params.add(new Label("iterations:")); Params.add(iterField);
Params.add(new Label("Pixel Size:")); Params.add(pixelField);
setLayout(new BorderLayout());
add("Center", Params); add("South", ButtonRow);
validate(); pack(); resize(preferredSize());
}
/* =========================================================== */
public void setParams(double _xMin, double _xMax,
double _yMin, double _yMax,
int _iter, int _pixel)
{
xMin = _xMin; xMax = _xMax; yMin = _yMin; yMax = _yMax;
iter = _iter; pixel = _pixel;
xMinField.setText (String.valueOf(_xMin));
xMaxField.setText (String.valueOf(_xMax));
yMinField.setText (String.valueOf(_yMin));
yMaxField.setText (String.valueOf(_yMax));
iterField.setText (String.valueOf(_iter));
pixelField.setText(String.valueOf(_pixel));
}
/* =========================================================== */
private void handleOkay()
{
xMin = xMinField.getDouble(); xMax = xMaxField.getDouble();
yMin = yMinField.getDouble(); yMax = yMaxField.getDouble();
iter = iterField.getInteger(); pixel = pixelField.getInteger();
master.setDrawingParams(xMin,xMax,yMin,yMax,iter,pixel);
}
/* =========================================================== */
public boolean handleEvent(Event e)
{
if (e.id == Event.WINDOW_DESTROY)
{
hide();
return true;
}
else
return super.handleEvent(e);
}
/* =========================================================== */
public boolean action(Event e, Object arg)
{
if (e.target == Okay)
{
handleOkay(); hide(); return true;
}
else if (e.target == Apply)
{
handleOkay(); return true;
}
if (e.target == Cancel)
{
hide(); return true;
}
else
return false;
}
}
Drawing Canvas
import java.awt.*;
public class TmpMandelCanvas extends Canvas implements Runnable
{
private double xMin, xMax, yMin, yMax;
private int iter, pixel;
private int width, height;
private boolean newImage;
private Thread thread = null;
private Image offImage = null;
private Graphics offGraph = null;
public TmpMandelCanvas(Image _offImage, int _width, int _height,
double _xMin, double _xMax, double _yMin, double _yMax,
int _iter, int _pixel)
{
super();
offImage = _offImage;
setParams(_xMin,_xMax, _yMin, _yMax, _iter, _pixel);
width = _width; height = _height;
resize(width,height);
offGraph = offImage.getGraphics();
start();
}
public void start()
{
if (thread == null)
{
offGraph.setColor(Color.white); offGraph.fillRect(0,0,width,height);
thread = new Thread(this); thread.setPriority(2); thread.start();
}
}
public void stop()
{
if (thread != null)
{
thread.stop();
thread = null;
}
}
public void setParams(double _xMin, double _xMax, double _yMin, double _yMax,
int _iter, int _pixel)
{
xMin = _xMin; xMax = _xMax; yMin = _yMin; yMax = _yMax;
iter = _iter; pixel = _pixel;
}
static double toWorld(int i, int iMax, double min, double max)
{
return (max - min) / iMax * ((double)i - iMax) + max;
}
static int toScreen(double x, int iMax, double min, double max)
{
return (int)Math.round( iMax / (max - min) * (x - max) + iMax);
}
public Color computeColor(double a, double b, int maxIter)
{
int iter = 0;
double x = 0, y = 0, tmp = 0;
boolean escaped = false;
while ((iter < maxIter) && (!escaped))
{
tmp = x*x - y*y + a;
y = 2*x*y + b;
x = tmp;
if ( (Math.abs(x) + Math.abs(y)) >= 5.0)
escaped = true;
iter++;
}
if (escaped)
return new Color((20*iter) % 255, 0, 0);
else
return Color.blue;
}
public void run()
{
for (int ix = 0; ix < width; ix += pixel)
{
for (int iy = 0; iy < height; iy +=pixel)
{
double a = toWorld(ix, width,xMin,xMax);
double b = toWorld(iy, height, yMax, yMin);
offGraph.setColor(computeColor(a,b,iter));
offGraph.fillRect(ix,iy,pixel,pixel);
}
repaint();
}
stop();
}
public void update(Graphics g)
{
paint(g);
}
public void paint(Graphics g)
{
g.drawImage(offImage,0,0,null);
}
}
(bgw)