/* Fractal Dimension of Galaxies
A Java program to calculate the Fractal Dimension of Galaxies. This program reads the galaxy from a gif file and then calculates the fractal dimension for each contour. Slide the bar to select the intensity contour for which you want to calculate the fractal dimension.
*/
import java.lang.*;
import java.applet.*;
import java.awt.*;
import java.awt.image.*;

public class F3 extends Applet {
  Image orig, contour;  // the original and contour versions of the image
  int scrollint=0;
  int scrollintold=0;
  Timer timer= new Timer(this);
  Scrollbar s = new Scrollbar(Scrollbar.HORIZONTAL,10,10,0,255);
  int width=256,height=256;
  int decimal=0,fract=0,cont=0;
  int[] box1 = new int [256];
  int[] box2 = new int [256];
  int[] box3 = new int [256];


  /**
   * Load the image.  Create a new image that is a contour version of it, using
   * a FilteredImageSource, ImageProducer and a the ContourFilter class, below.
   */
  public void init() {
    setLayout(new BorderLayout() );
    orig = this.getImage(this.getCodeBase(), "galax.gif");
    ImageFilter filter = new ContourFilter(20);
    ImageProducer producer = new FilteredImageSource(orig.getSource(), filter);
    contour = this.createImage(producer);
    add("North",s);
    timer.start();
    fractInit(orig);
  }

  public void step() {
   scrollintold=scrollint;
   scrollint=s.getValue();
   if(scrollint != scrollintold) {
   ImageFilter filter = new ContourFilter(scrollint);
    ImageProducer producer = new FilteredImageSource(orig.getSource(), filter);
    contour = this.createImage(producer);
    fractDim(scrollint);
    repaint();
    }
   }

  public void fractDim(int i) {
    double bbb;
    bbb=(double) box2[i]/((double) box3[i]);
    bbb=Math.log(bbb)/Math.log(2);
    decimal=(int) bbb;
    bbb=( (bbb-(double) decimal)*100.+0.5);
    fract= (int) bbb;
    cont=i;
  }



public void fractInit(Image im) {
   try {
    //grab pixels and precompute for fractDim
     int[] pgPixels = new int [width*height];
     PixelGrabber pg = new PixelGrabber(im,0,0,
                          width,height,pgPixels,0,width);

   if(pg.grabPixels() && ((pg.status() & ImageObserver.ALLBITS) !=0))
    {
     int level=0;

     int max3,max2,max1,min3,min2,min1;
     int x,y;


     for(int iiii=0;iiii<(width>>3);iiii++){
      for(int jjjj=0;jjjj<(height>>3);jjjj++){
       min3=256;max3=0;
     for(int iii=0;iii<=1;iii++){
      for(int jjj=0;jjj<=1;jjj++){
       min2=256;max2=0;

       for(int ii=0;ii<=1;ii++){
        for(int jj=0;jj<=1;jj++){
         min1=256;max1=0;

            for(int i=0;i<=1;i++){
             for(int j=0;j<=1;j++){
               x=i+(ii<<1)+(iii<<2)+(iiii<<3);
               y=width*(j+(jj<<1)+(jjj<<2)+(jjjj<<3));
               level=pgPixels[x+y]&0xff;
               max1=Math.max(max1,level);
               min1=Math.min(min1,level);
//             System.out.println(" "+level); 
//             System.out.println(" "+x+" "+y+" "+level); 
             }
            }

//          System.out.println(">"+max1+" "+min1); 
           for(int m = min1; m<=max1;m++){ 
              box1[m]++;
           }
         max2=Math.max(max1,max2);
         min2=Math.min(min1,min2);
         }
        }

         max3=Math.max(max3,max2);
         min3=Math.min(min3,min2);
           for(int m=min2;m<=max2;m++){
            box2[m]++;
           }
 //         System.out.println(">>"+max2+" "+min2); 
       }
      }
           for(int m=min3;m<=max3;m++){
            box3[m]++;
           }

     }
      }
     }
   
     }catch (InterruptedException e) {e.printStackTrace();}

   return;
}

/* override update to reduce flickering */
  public void update(Graphics g){
    g.setColor(getBackground());
    g.fillRect(300,282,556,300);
    g.setColor(getForeground());
    paint(g);
    }

  public void paint(Graphics g) {
    g.drawImage(orig, 25, 25, this);
    g.drawImage(contour, 300, 25, this);
    g.drawString("Fractal Dimension = "+decimal+"."+fract+"  level= "+cont
                   ,300,300);
  }
}

/** Filter an image by averaging its colors */
class ContourFilter extends RGBImageFilter {
  static int ilevel;
  public ContourFilter(int ilev) { canFilterIndexColorModel = true;ilevel=ilev; }
  public int filterRGB(int x, int y, int rgb) {
    int a = rgb & 0xff000000;
    int r = rgb & 0xff0000;
    int g = rgb & 0x00ff00;
    int b = rgb & 0x0000ff;
    int avg=((r>>16)+(g>>8)+b)/3;
    r=0;
    g=0;
    b=0;
    if(avg>ilevel) r=255<<16;
    if(avg==ilevel) g=255<<8;
    if(ilevel>avg) b=255;
    return a | r | g | b;
  }
}

class Timer extends Thread {
  F3 myapplet;

  public Timer(F3 myapplet){
    this.myapplet=myapplet ;
    setPriority(MIN_PRIORITY);
    }
   public void run() {
   for(;;){
     myapplet.step();
     yield();
     try{sleep(100L);} catch(InterruptedException e){;}
     }
   }
}
/*
*/