multijulia.java

/*
 *   Multijulia Java applet
 *   Mandelbrot graph colouring algorithm based on More Than Usual
 *   information
 *
 *   See http://hans.liss.pp.se/multijulia.html for more info on this
 *
 *   This program is free software; you can redistribute it and/or
 *   modify it under the terms of the GNU General Public License
 *   as published by the Free Software Foundation; either version
 *   2 of the License, or (at your option) any later version.
 *
 *   Hans Liss <Hans@Liss.pp.se>
 *   http://hans.liss.pp.se
 *
 */
 
import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;
import java.applet.*;
import java.io.*;
 
public class multijulia extends Applet implements Runnable,MouseListener,MouseMotionListener {
    private int tmpBuffer[];
    private Image ofsImage;
    private Graphics ofsG;
    private volatile Thread paintThread = null;
 
    private int width;
    private int height;
    private int wh;
    private int maxpos;
 
    private int MAXITER=65535;
    private double angle;
    private double speed;
    private int col_r;
    private int col_g;
    private int col_b;
 
    private double gc_x;
    private double gc_y;
    private double gd_x;
    private double gd_y;
 
    private double gcc_x;
    private double gcc_y;
 
    public static void main (String args[])
    {
        System.out.println ("Run this program in a browser or in AppletViewer");
    }
 
    public void init()
    {
        gc_x=0;
        gc_y=0;
        gd_x=4.00;
        gd_y=4.00;
        gcc_x=0.5;
        gcc_y=0.5;
 
        width = getSize().width;
        height = getSize().height;
 
        int tmpw=(int)((double)height * gd_x / gd_y);
        int tmph=(int)((double)width * gd_y / gd_x);
        if (tmpw < width)
            width=tmpw;
        else if (tmph < height)
            height=tmph;
 
        wh = width * height;
 
        tmpBuffer = new int[wh];
        ofsImage = createImage (width, height);
        ofsG = ofsImage.getGraphics();
 
        for (int y = 0 ; y < height; y++) {
            for (int x = 0 ; x < width; x++) {
                int r = (int)(Math.random() * 0);
                int g = (int)(Math.random() * 128);
                int b = (int)(Math.random() * 256);
 
                ofsG.setColor(new Color(r, g, b));
                ofsG.drawLine(x, y, x, y);
                tmpBuffer[x + y*width] = -1;
            }
        }
        addMouseMotionListener( this );
        addMouseListener( this );
    }
 
    public void start() {
        if (paintThread == null) {
            paintThread = new Thread(this, "Paint");
            paintThread.start();
        }
    }
 
    public void mouseClicked(MouseEvent e) {
    }
 
    public void mouseEntered(MouseEvent e) {
    }
 
    public void mouseExited(MouseEvent e) {
    }
 
    public void mousePressed(MouseEvent e) {
    }
 
    public void mouseMoved(MouseEvent e) {
    }
 
    public void mouseDragged(MouseEvent e) {
    }
 
    public void mouseReleased(MouseEvent e)
    {
        int x=e.getX();
        int y=e.getY();
        gcc_x=gc_x + gd_x * ((double)x / (double)width) - gd_x/2;
        gcc_y=gc_y + gd_y * ((double)(height-1-y) / (double)height) - gd_y/2;
        paintThread = new Thread(this, "Paint");
        paintThread.start();
        e.consume();
    }
 
    public void paint(Graphics g)
    {
        super.paint(g);
 
        int cpos=maxpos;
 
        for (int i=0; i<=cpos; i++) {
            if (tmpBuffer[i] != -1) {
                ofsG.setColor(new Color((tmpBuffer[i] & 0xFF0000) >> 16, (tmpBuffer[i] & 0xFF00) >> 8, tmpBuffer[i] & 0xFF));
                ofsG.drawLine(i % width, (int)(i / width), i % width, (int)(i / width));
            }
        }
 
        String info1="[(x,y)=("+gc_x+","+gc_y+")";
        String info2="(cx,cy)=("+gcc_x+","+gcc_y+")";
        String info3="dx="+gd_x+"]";
        ofsG.setColor(Color.black);
        ofsG.setFont(new Font("Helvetica", Font.PLAIN, 12));
        //      ofsG.setXORMode(getBackground());
        ofsG.drawString(info1, 20, 20);
        ofsG.drawString(info2, 20, 32);
        ofsG.drawString(info3, 20, 44);
        g.drawImage( ofsImage, 0, 0, this);
    }
 
    int julia(double x, double y, double cx, double cy) {
        int i=MAXITER;
        double
            zx=x,
            zy=y,
            zx2=x*x,
            zy2=y*y,
            ox=x,
            oy=y,
            ccx=cx,
            ccy=cy;
        while((i > 0) && (zx2 + zy2 < 4.0)) {
            ox=zx;
            oy=zy;
            zy=2*zx*zy + ccy;
            zx=zx2-zy2 + ccx;
            zx2=zx*zx;
            zy2=zy*zy;
            i--;
        }
        speed=Math.sqrt((zx-ox)*(zx-ox)+(zy-oy)*(zy-oy));
        angle=Math.atan2((zx-ox),(zy-oy))+3.141592;
        return i;
    }
 
    public void hsv2rgb(double H,double S,double V) {
        int i;
        double f,p,q,t;
        H = H*6;
        if (H>=6)
            H-=6;
        i=(int)H;
        f=H-(double)i;
        p=V*(1.0-S);
        q=V*(1.0-(S*f));
        t=V*(1.0-(S*(1.0-f)));
 
        switch(i) {
        case 0: col_r=(int)(V*255); col_g=(int)(t*255); col_b=(int)(p*255); break;
        case 1: col_r=(int)(q*255); col_g=(int)(V*255); col_b=(int)(p*255); break;
        case 2: col_r=(int)(p*255); col_g=(int)(V*255); col_b=(int)(t*255); break;
        case 3: col_r=(int)(p*255); col_g=(int)(q*255); col_b=(int)(V*255); break;
        case 4: col_r=(int)(t*255); col_g=(int)(p*255); col_b=(int)(V*255); break;
        case 5: col_r=(int)(V*255); col_g=(int)(p*255); col_b=(int)(q*255); break;
        }
    }
 
    public void run() {
        Thread myThread = Thread.currentThread();
        for (int y=height-1; y >=0; y--) {
            for (int x=0; x < width; x++) {
                if (paintThread != myThread) return;
                double cx=gd_x * ((double)x/(double)width) + gc_x - (gd_x/2);
                double cy=gd_y * ((double)y/(double)height) + gc_y - (gd_y/2);
                double h, s, v;
                int intgr;
                int val=julia(cx, cy, gcc_x, gcc_y);
                h=angle/6.28320;
                intgr=(int)h;
                h-=(double)intgr;
                s=(double)val / (double)MAXITER;
                v=speed/3;
                intgr=(int)v;
                v-=(double)intgr;
                if (s < 0.5)
                    s=1-s;
                if (v < 0.5)
                    v=1-v;
                hsv2rgb(h,s,v);
 
                maxpos=(height-1-y)*width+x;
                tmpBuffer[maxpos] = ((col_r << 16) + (col_g << 8) + col_b);
            }
            repaint();
        }
    }
    public void stop() {
        paintThread = null;
    }
 
    public void update ( Graphics g ){
        paint(g);
    }
}