invbuddha.java

/*
 *   Invbuddha applet
 *
 *   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 invbuddha extends Applet implements Runnable,MouseListener,MouseMotionListener {
    private int tmpBuffer_r[];
    private int tmpBuffer_g[];
    private int tmpBuffer_b[];
    private int hist_r[], hist_g[], hist_b[];
    private int vmax_r, vmax_g, vmax_b;
    private Image ofsImage;
    private Graphics ofsG;
    private volatile Thread paintThread = null;
 
    private int width;
    private int height;
    private int wh;
 
    private final int MAXITER=5000;
 
    private double gc_x;
    private double gc_y;
    private double gd_x;
    private double gd_y;
    private double gv_x;
    private double gv_y;
 
    private int select_x0;
    private int select_y0;
    private int select_x1;
    private int select_y1;
    private int last_x1;
    private int last_y1;
 
    public static void main (String args[])
    {
        System.out.println ("Run this program in a browser or in AppletViewer");
    }
 
    public void init()
    {
        gc_x=-0.6134;
        gc_y=0;
        gd_x=4;
        gd_y=3;
 
        select_x0=0; select_y0=0; select_x1=0; select_y1=0;
 
        width = getSize().height;
        height = getSize().width;
 
        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;
 
        gv_x=gd_x/(double)width;
        gv_y=gd_y/(double)height;
 
        wh = width * height;
 
        tmpBuffer_r = new int[wh];
        tmpBuffer_g = new int[wh];
        tmpBuffer_b = new int[wh];
        ofsImage = createImage (height, width);
        ofsG = ofsImage.getGraphics();
 
        for (int y = 0 ; y < height; y++) {
            for (int x = 0 ; x < width; x++) {
                tmpBuffer_r[x + y*width] = 0;
                tmpBuffer_g[x + y*width] = 0;
                tmpBuffer_b[x + y*width] = 0;
            }
        }
        vmax_r=vmax_g=vmax_b = 0;
        hist_r=hist_g=hist_b=null;
        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) {
        int x=e.getY();
        int y=e.getX();
        select_x0=x;
        select_y0=y;
        select_x1=x;
        select_y1=y;
        last_x1=x;
        last_y1=y;
        e.consume();
    }
 
    public void mouseMoved(MouseEvent e) {
    }
 
    public void mouseDragged(MouseEvent e) {
        int x=e.getY();
        int y=e.getX();
        Graphics g = getGraphics();
        if (x != select_x1 || y != select_y1) {
            int x0 = Math.min(select_x0, select_x1);
            int y0 = Math.min(select_y0, select_y1);
            int dx=Math.abs(select_x1 - select_x0);
            int dy=Math.abs(select_y1 - select_y0);
            g.setXORMode(getBackground());
            if (dx>0 || dy>0) g.drawRect(y0, x0, dy, dx);
            select_x1=x;
            select_y1=y;
            dx=Math.abs(select_x1 - select_x0);
            dy=Math.abs(select_y1 - select_y0);
            if (dx < dy * width / height) {
                dx = dy * width/height;
                if (select_x1 < select_x0) select_x1 = select_x0 - dx;
                else select_x1=select_x0 + dx;
            }
            else if (dy < dx * height / width) {
                dy = dx * height/width;
                if (select_y1 < select_y0) select_y1 = select_y0 - dy;
                else select_y1=select_y0 + dy;
            }
            x0 = Math.min(select_x0, select_x1);
            y0 = Math.min(select_y0, select_y1);
            if (dx>0 || dy>0) g.drawRect(y0, x0, dy, dx);
        }
        e.consume();
    }
 
    public void mouseReleased(MouseEvent e)
    {
        int x=e.getY();
        int y=e.getX();
        select_x1=x;
        select_y1=y;
        int dx=Math.abs(select_x1 - select_x0);
        int dy=Math.abs(select_y1 - select_y0);
        if (e.isMetaDown()) {
            gd_x *= 2;
            gd_y *= 2;
        } else if (dx == 0 && dy == 0) {
            gc_x += gd_x * ((double)(select_x0 - width/2) / (double)width);
            gc_y += gd_y * ((double)((height-1-select_y0) - height/2) / (double)height);
            gd_x /= 2;
            gd_y /= 2;
        } else {
            if (dx < (dy * width) / height) {
                dx = (dy * width) / height;
                if (select_x1 < select_x0) select_x1 = select_x0 - dx;
                else select_x1=select_x0 + dx;
            }
            else if (dy < (dx * height) / width) {
                dy = (dx * height) / width;
                if (select_y1 < select_y0) select_y1 = select_y0 - dy;
                else select_y1=select_y0 + dy;
            }
            double x0 = Math.min(select_x0, select_x1);
            double y0 = Math.max(select_y0, select_y1);
            gc_x += gd_x * ((double)(x0 + dx/2 - width/2) / (double)width);
            gc_y += gd_y * ((double)((height-1-y0) + dy/2 - height/2) / (double)height);
            gd_x *= (double)dx/(double)width;
            gd_y *= (double)dy/(double)height;
        }
        gv_x=gd_x/(double)width;
        gv_y=gd_y/(double)height;
 
        select_x0=0; select_y0=0; select_x1=0; select_y1=0;
        for (int i = 0 ; i < wh; i++) {
            tmpBuffer_r[i] = 0;
            tmpBuffer_g[i] = 0;
            tmpBuffer_b[i] = 0;
        }
        vmax_r=vmax_g=vmax_b = 0;
        hist_r=hist_g=hist_b=null;
        paintThread = new Thread(this, "Paint");
        paintThread.start();
        e.consume();
    }
 
    public void paint(Graphics g)
    {
        super.paint(g);
 
        int hival_r;
        int hival_g;
        int hival_b;
        int i, j;
 
        //      synchronized(this) {
            for (i=0; i<width*height; i++) {
                double col_r=0, col_g=0, col_b=0;
                for (hival_r = vmax_r; hival_r > 0 && hist_r[hival_r]<=1; hival_r--);
                for (hival_g = vmax_g; hival_g > 0 && hist_g[hival_g]<=1; hival_g--);
                for (hival_b = vmax_b; hival_b > 0 && hist_b[hival_b]<=1; hival_b--);
                if (hival_r > 0) col_r=(double)(tmpBuffer_r[i])/(double)hival_r;
                if (hival_g > 0) col_g=(double)(tmpBuffer_g[i])/(double)hival_g;
                if (hival_b > 0) col_b=(double)(tmpBuffer_b[i])/(double)hival_b;
 
                double v1 = Math.floor(col_r); col_r -= v1;
                v1 = Math.floor(col_g); col_g -= v1;
                v1 = Math.floor(col_b); col_b -= v1;
 
                ofsG.setColor(new Color((int)(255*col_r), (int)(255*col_g), (int)(255*col_b)));
                ofsG.drawLine((int)(i / width), i % width, (int)(i / width), i % width);
            }
            if (select_x1 != select_x0 && select_y1 != select_y0) {
                int x0 = Math.min(select_x0, select_x1);
                int x1 = Math.max(select_x0, select_x1);
                int y0 = Math.min(select_y0, select_y1);
                int y1 = Math.max(select_y0, select_y1);
                int dx=x1-x0;
                int dy=y1-y0;
                ofsG.drawRect(y0, x0, dy, dx);
            }
            //  }
        g.drawImage( ofsImage, 0, 0, this);
    }
 
    boolean mandel(double cx, double cy) {
        int i=MAXITER, xpos, ypos;
        boolean didchange=false;
        double
            zx=cx,
            zy=cy,
            y,
            zx2=cx*cx,
            zy2=cy*cy;
 
        while((i > 0) && (zx2 + zy2 < 4.0)) {
            zy=2*zx*zy + cy;
            zx=zx2-zy2 + cx;
            zx2=zx*zx;
            zy2=zy*zy;
            i--;
        }
        int n=i;
        i=MAXITER;
        zx=cx;
        zy=cy;
        zx2=cx*cx;
        zy2=cy*cy;
        while((i > 0) && (zx2 + zy2 < 4.0)) {
            zy=2*zx*zy + cy;
            zx=zx2-zy2 + cx;
            zx2=zx*zx;
            zy2=zy*zy;
            i--;
            xpos=(int)((zx - (gc_x - gd_x/2))/gv_x);
            ypos=(int)((zy - (gc_y - gd_y/2))/gv_x);
            if (xpos >= 0 && xpos < width && ypos >= 1 && ypos < height) {
                didchange=true;
                int arpos=xpos + width * (height - 1 - ypos);
                if (n==0) {
                    tmpBuffer_r[arpos]++;
                    if (tmpBuffer_r[arpos] > vmax_r) {
                        int hist2[]=new int[tmpBuffer_r[arpos]+1];
                        if (vmax_r > 0)
                            System.arraycopy(hist_r, 0, hist2, 0, vmax_r+1);
                        hist_r=hist2;
                        for (int j=vmax_r+1; j<=tmpBuffer_r[arpos]; j++) hist_r[j]=0;
                        vmax_r=tmpBuffer_r[arpos];
                    }
                    hist_r[tmpBuffer_r[arpos]]++;
                } else {
                    tmpBuffer_b[arpos]++;
                    if (tmpBuffer_b[arpos] > vmax_b) {
                        int hist2[]=new int[tmpBuffer_b[arpos]+1];
                        if (vmax_b > 0)
                            System.arraycopy(hist_b, 0, hist2, 0, vmax_b+1);
                        hist_b=hist2;
                        for (int j=vmax_b+1; j<=tmpBuffer_b[arpos]; j++) hist_b[j]=0;
                        vmax_b=tmpBuffer_b[arpos];
                    }
                    hist_b[tmpBuffer_b[arpos]]++;
                }
            }
        }
        /*      if (n==0) {
            xpos=(int)((cx - (gc_x - gd_x/2))/gv_x);
            ypos=(int)((cy - (gc_y - gd_y/2))/gv_x);
            if (xpos >= 0 && xpos < width && ypos >= 1 && ypos < height) {
                didchange=true;
                int arpos=xpos + width * (height - 1 - ypos);
                tmpBuffer_r[arpos]++;
                if (tmpBuffer_r[arpos] > vmax_r) vmax_r=tmpBuffer_r[arpos];
            }
            }*/
        return didchange;
    }
 
    public void run() {
        Thread myThread = Thread.currentThread();
        int n=10;
        while (true) {
            if (paintThread != myThread) return;
            double cx=Math.random()*4-2;
            double cy=Math.random()*4-2;
            if (mandel(cx, cy)) {
                if (n-- == 0) {
                    repaint();
                    n=10;
                }
            }
        }
    }
 
    public void stop() {
        paintThread = null;
    }
 
    public void update ( Graphics g ){
        paint(g);
    }
}