import java.applet.Applet;
import java.awt.*;
import java.awt.image.ColorModel;
import java.awt.image.MemoryImageSource;

/**
* Mandelbrot Set Java Applet,
* (c) 2004 <a href=http://fractals.nsu.ru/>http://fractals.nsu.ru/</a> <br>
* It's a heavily documented example of a simple java applet, which
* calculates the Mandebrot Set fractal image in memory, and displays it.
* @author Aleksey
*
* JavaDoc documentation can be generated by running command:
*   javadoc -d doc Mandelbrot.java
*/
public class Mandelbrot extends Applet implements Runnable
{
    Thread runner; // working thread, used to calculate the image
    Image img; // the image to calculate

    // The number of iterations. The greater it is,
    // the more accurate image will be calculated
    int iterations;

    int method; // Method used to paint the image, see calcPointColor()

    /**
    * Called by the browser or applet viewer to inform this applet that it
    * has been loaded into the system.
    * The init() method reads applet parameters 'iterations' and 'method'
    * from html APPLET tag.
    * Then the working thread is created to start image calculation.
    */
    public void init() {
	iterations = 200;
	method = 0;

	// initialize applet parameters
    	try {
	    String param = getParameter("ITERATIONS");
	    if (param != null) {
		iterations = Integer.parseInt(param, 10);
	    }
	    param = getParameter("METHOD");
	    if (param != null) {
		method = Integer.parseInt(param, 10) & 1;
	    }
	} catch (Exception e) {
	    e.printStackTrace();
	}

	// create working thread, the created thread will call run() method
        runner = new Thread(this);
        runner.start();
    }

    /**
    * Called by the browser or applet viewer to inform this applet that it
    * is being destroing and that it should free resources it has allocated.
    */
    public void destroy() {
	if(runner!=null && runner.isAlive()) {
	    Thread th = runner;
	    // notify working thread to stop
    	    runner = null;
	    try {
		th.join(100); // wait 100ms for the working thread to die.
	    } catch(InterruptedException e) {}
	}
    }

    static String calcString = "Calculating...";

    /**
    * Called when applet window needs to be repainted
    */
    public void paint(Graphics g) {
	int w = getSize().width;
	int h = getSize().height;

	if (img == null) {
	    // if img image is not calculated yet, call parent's paint method
	    super.paint(g);
	    // and print the string "Calculating..."
	    g.setColor(Color.black);
	    FontMetrics fm = g.getFontMetrics();
	    int x = (w - fm.stringWidth(calcString))/2;
	    int y = h/2;
	    g.drawString(calcString, x, y);
	} else {
            g.drawImage(img, 0, 0, w, h, this);
        }
    }

    /**
    * The run() method is called by the working thread, just after
    * the working thread is created in the {@link #init()} method
    */
    public void run() {
	// calculate the image of Mandelbrot set
        img = calculateImage();
	// and notify interface thread to repain th applet
        if (img != null && runner == Thread.currentThread())
	    repaint();
    }

    /**
     * Calculates and returns the Mandelbrot set image.
     * Halts calculation and returns null if the Applet is stopped
     */
    Image calculateImage() {
        Thread me = Thread.currentThread();

	int width  = getSize().width;
	int height = getSize().height;
        int pixels[] = new int[width * height];
        int index = 0;
        for (int j = 0; j < height; j++) {
            for (int i = 0; i < width; i++) {
                // poll once per pixel to see if we've been told to stop.
		if(runner!=me) return null;

                double cx=3.5/width*(i-width/2)-.75;
                double cy=3.5/width*(j-height/2);
		// set pixel color
		pixels[index++] = calcPointColor(cx,cy);
            }
        }

	// convert array of pixels to the Image class
        return createImage(new MemoryImageSource(width, height,
                      ColorModel.getRGBdefault(), pixels, 0, width));
    }

    /**
     * Calculates the color of a complex point cx+i*cy.
     * The color is white if the point belongs to the Mandelbrot set.
     * @param cx - real part of the complex point
     * @param cx - real imaginary part of the complex point
     * @returns the point color
     */ 
    int calcPointColor(double cx, double cy) {
        double x=cx, y=cy, ex=cx, ey=cy;
        for(int n=0; n<iterations && runner!=null; n++) {
	    // complex assigment Z1=Z^2+C
            double x1=x*x-y*y+cx;
            double y1=2*x*y+cy;
            x=x1;
	    y=y1;
            double r2=x*x+y*y; // abs(x+i*y)^2
            if(r2>10000) {
		// the point cx+i*cy found to be outside the Mandelbrot set,
		// so we can calculate its color
                x1=(ex*x+ey*y)/r2;
                y1=(ey*x-ex*y)/r2;
                ex=x1;
                ey=y1;
		
		// use arg(z) if method==1, or abs(z) otherwise
		double hue = (method==1 ?
		    .69-Math.abs(Math.atan2(ey, ex))/18 : // arctan of ey/ex
		    .69-Math.sqrt(ex*ex+ey*ey)/10); // abs(ex+i*ey)
		
		// calculate the color using continuous function HSBtoRGB()
		return Color.HSBtoRGB( (float)hue, 0.9f, 0.7f );
            }
            x1=ex*x-ey*y;
            y1=ey*x+ex*y;
            ex=x1;
            ey=y1;
        }
	// return white color if the point belongs to the Mandelbrot set
	return 0xFFFFFFFF;
    }
};


syntax highlighted by Code2HTML, v. 0.9.1