// ----------------------------------------------------------------------------
// Fraktaly v pocitacove grafice
// ----------------------------------------------------------------------------
// application: Morph IFS demo
// author:      Pavel Tisnovsky
// file name:   MorphIFS.java
// directory:   java
// date:        06.07.2006
// description: Demonstracni aplikace pro vytvoreni, zobrazeni a morphovani
//              fraktalniho objektu, ktery je zalozeny na pruniku dvou plosnych
//              systemu iterovanych funkci IFS.
//              Podrobnejsi popis teto demonstracni aplikace je popsan primo
//              v 37 casti serialu o fraktalech v pocitacove grafice.
// ----------------------------------------------------------------------------



// Nasledujici radky jsou urceny pro spusteni appletu v programu AppletViewer:
//
// <applet code="MorphIFS.class" width="640" height="700">
// </applet>
//
// pro kompatibilitu se starsi JVM firmy Microsoft se musi provest preklad
// pomoci prikazu:
// javac -target 1.1 MorphIFS.java



// ----------------------------------------------------------------------------
// seznam importovanych balicku
// ----------------------------------------------------------------------------
import java.util.*;
import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;
import java.applet.Applet;



// ----------------------------------------------------------------------------
// Trida pro aplikaci filtru na zvolenou zdrojovou pixmapu. Vysledek se uklada
// do cilove pixmapy.
// ----------------------------------------------------------------------------
class Filter {
    private int imageWidth;                         // velikost zpracovavanych pixmap
    private int imageHeight;
    private int pixelSrc[];                         // zdrojova pixmapa
    private int pixelDest[];                        // cilova pixmapa



    // ------------------------------------------------------------------------
    // V konstruktoru se nastavi velikost filtru a zdrojova a cilova pixmapa.
    // ------------------------------------------------------------------------
    public Filter(int imageWidth, int imageHeight, int pixelSrc[], int pixelDest[]) {
        this.imageWidth=imageWidth;                 // nastavit velikost pixmapy
        this.imageHeight=imageHeight;
        this.pixelSrc=pixelSrc;                     // nastavit handle zdrojove
        this.pixelDest=pixelDest;                   // a cilove pixmapy
    }



    // ------------------------------------------------------------------------
    // Nastaveni nove sirky zpracovavane pixmapy.
    // ------------------------------------------------------------------------
    public void setImageWidth(int imageWidth) {
        this.imageWidth=imageWidth;
    }



    // ------------------------------------------------------------------------
    // Nastaveni nove vysky zpracovavane pixmapy.
    // ------------------------------------------------------------------------
    public void setImageHeight(int imageHeight) {
        this.imageHeight=imageHeight;
    }



    // ------------------------------------------------------------------------
    // Nastaveni zdrojove pixmapy.
    // ------------------------------------------------------------------------
    public void setSourceImage(int pixelSrc[]) {
        this.pixelSrc=pixelSrc;
    }



    // ------------------------------------------------------------------------
    // Nastaveni cilove pixmapy.
    // ------------------------------------------------------------------------
    public void setDestinationImage(int pixelDest[]) {
        this.pixelDest=pixelDest;
    }



    // ------------------------------------------------------------------------
    // Ziskani sirky zpracovavanych pixmap.
    // ------------------------------------------------------------------------
    public int getImageWidth() {
        return imageWidth;
    }



    // ------------------------------------------------------------------------
    // Ziskani vysky zpracovavanych pixmap.
    // ------------------------------------------------------------------------
    public int getImageHeight() {
        return imageHeight;
    }



    // ------------------------------------------------------------------------
    // Ziskani zdrojove pixmapy.
    // ------------------------------------------------------------------------
    public int[] getSourceImage() {
        return pixelSrc;
    }



    // ------------------------------------------------------------------------
    // Ziskani cilove pixmapy.
    // ------------------------------------------------------------------------
    public int[] getDestinationImage() {
        return pixelDest;
    }



    // ------------------------------------------------------------------------
    // Tato metoda provede filtraci pixmapy s filtrem typu:
    // zadny filtr, pouze kopie zdrojove pixmapy do cilove pixmapy.
    // Blizsi informace o tomto filtru jsou podany v dodatku disertacni prace.
    // ------------------------------------------------------------------------
    public void filterNone() {
        int pos=0;
        for (int j=0; j<imageHeight; j++) {         // pro vsechny radky pixmapy
            for (int i=0; i<imageWidth; i++) {      // pro vsechny pixely na radku
                pixelDest[pos]=pixelSrc[pos];       // provest vymazani pixelu
                pos++;
            }
        }
    }



    // ------------------------------------------------------------------------
    // Tato metoda provede filtraci pixmapy s filtrem typu:
    // rozmazani v bloku 2x2 pixely s vyberem ve tvaru bloku.
    // Blizsi informace o tomto filtru jsou podany v dodatku disertacni prace.
    // ------------------------------------------------------------------------
    public void filter2x2smooth() {
        int pos=0;                                  // index do zdrojove a cilove pixmapy
        int color;                                  // RGBA barvove slozky zakodovane do typu int
        int r, g, b;                                // jednotlive rozkodovane barvove slozky
        filterNone();                               // nejprve pixmapy zkopirovat
        for (int j=0; j<imageHeight-1; j++) {       // pro vsechny radky pixmapy
            for (int i=0; i<imageWidth-1; i++) {    // pro vsechny sloupce na radku pixmapy
                color=pixelSrc[pos];
                r =(color & 0x00ff0000)>>16;
                g =(color & 0x0000ff00)>>8;
                b =(color & 0x000000ff);
                color=pixelSrc[pos+1];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos+imageWidth];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos+imageWidth+1];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                r/=4; g/=4; b/=4;                   // provest filtraci
                pixelDest[pos]=(r<<16) | (g<<8) | b | (0xff<<24);
                pos++;
            }
        }
    }



    // ------------------------------------------------------------------------
    // Tato metoda provede filtraci pixmapy s filtrem typu:
    // rozmazani v bloku 3x3 pixely s vyberem ve tvaru diamantu.
    // Blizsi informace o tomto filtru jsou podany v dodatku disertacni prace.
    // ------------------------------------------------------------------------
    public void filter3x3diamond() {
        int pos=0;                                  // index do zdrojove a cilove pixmapy
        int color;                                  // RGBA barvove slozky zakodovane do typu int
        int r, g, b;                                // jednotlive rozkodovane barvove slozky
        filterNone();                               // nejprve pixmapy zkopirovat
        pos=1+imageWidth;
        for (int j=1; j<imageHeight-1; j++) {       // pro vsechny radky pixmapy
            for (int i=1; i<imageWidth-1; i++) {    // pro vsechny sloupce na radku pixmapy
                color=pixelSrc[pos-imageWidth];
                r =(color & 0x00ff0000)>>16;
                g =(color & 0x0000ff00)>>8;
                b =(color & 0x000000ff);
                color=pixelSrc[pos-1];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos+1];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos+imageWidth];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                r/=4; g/=4; b/=4;                   // provest filtraci
                pixelDest[pos]=(r<<16) | (g<<8) | b | (0xff<<24);
                pos++;
            }
        }
    }



    // ------------------------------------------------------------------------
    // Tato metoda provede filtraci pixmapy s filtrem typu:
    // rozmazani v bloku 3x3 pixely s vyberem ve tvaru osoveho krize.
    // Blizsi informace o tomto filtru jsou podany v dodatku disertacni prace.
    // ------------------------------------------------------------------------
    public void filter3x3cross() {
        int pos=0;                                  // index do zdrojove a cilove pixmapy
        int color;                                  // RGBA barvove slozky zakodovane do typu int
        int r, g, b;                                // jednotlive rozkodovane barvove slozky
        filterNone();                               // nejprve pixmapy zkopirovat
        pos=1+imageWidth;
        for (int j=1; j<imageHeight-1; j++) {       // pro vsechny radky pixmapy
            for (int i=1; i<imageWidth-1; i++) {    // pro vsechny sloupce na radku pixmapy
                color=pixelSrc[pos-imageWidth];
                r =(color & 0x00ff0000)>>16;
                g =(color & 0x0000ff00)>>8;
                b =(color & 0x000000ff);
                color=pixelSrc[pos-1];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos+1];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos+imageWidth];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                r/=5; g/=5; b/=5;                   // provest filtraci
                pixelDest[pos]=(r<<16) | (g<<8) | b | (0xff<<24);
                pos++;
            }
        }
    }



    // ------------------------------------------------------------------------
    // Tato metoda provede filtraci pixmapy s filtrem typu:
    // rozmazani v bloku 3x3 pixelu s vyberem ve tvaru uhlopricneho krize.
    // Blizsi informace o tomto filtru jsou podany v dodatku disertacni prace.
    // ------------------------------------------------------------------------
    public void filter3x3Xcross() {
        int pos=0;                                  // index do zdrojove a cilove pixmapy
        int color;                                  // RGBA barvove slozky zakodovane do typu int
        int r, g, b;                                // jednotlive rozkodovane barvove slozky
        filterNone();                               // nejprve pixmapy zkopirovat
        pos=1+imageWidth;
        for (int j=1; j<imageHeight-1; j++) {       // pro vsechny radky pixmapy
            for (int i=1; i<imageWidth-1; i++) {    // pro vsechny sloupce na radku pixmapy
                color=pixelSrc[pos-imageWidth-1];
                r =(color & 0x00ff0000)>>16;
                g =(color & 0x0000ff00)>>8;
                b =(color & 0x000000ff);
                color=pixelSrc[pos-imageWidth+1];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos+imageWidth-1];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos-imageWidth+1];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                r/=5; g/=5; b/=5;                   // provest filtraci
                pixelDest[pos]=(r<<16) | (g<<8) | b | (0xff<<24);
                pos++;
            }
        }
    }



    // ------------------------------------------------------------------------
    // Tato metoda provede filtraci pixmapy s filtrem typu:
    // rozmazani v bloku 3x3 pixelu s blokovym vyberem.
    // Blizsi informace o tomto filtru jsou podany v dodatku disertacni prace.
    // ------------------------------------------------------------------------
    public void filter3x3block() {
        int pos=0;                                  // index do zdrojove a cilove pixmapy
        int color;                                  // RGBA barvove slozky zakodovane do typu int
        int r, g, b;                                // jednotlive rozkodovane barvove slozky
        filterNone();                               // nejprve pixmapy zkopirovat
        pos=1+imageWidth;
        for (int j=1; j<imageHeight-1; j++) {       // pro vsechny radky pixmapy
            for (int i=1; i<imageWidth-1; i++) {    // pro vsechny sloupce na radku pixmapy
                color=pixelSrc[pos-imageWidth-1];
                r =(color & 0x00ff0000)>>16;
                g =(color & 0x0000ff00)>>8;
                b =(color & 0x000000ff);
                color=pixelSrc[pos-imageWidth];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos-imageWidth+1];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos-1];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos+1];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos+imageWidth-1];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos+imageWidth];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos-imageWidth+1];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                r/=9; g/=9; b/=9;                   // provest filtraci
                pixelDest[pos]=(r<<16) | (g<<8) | b | (0xff<<24);
                pos++;
            }
        }
    }



    // ------------------------------------------------------------------------
    // Tato metoda provede filtraci pixmapy s filtrem typu:
    // rozmazani v bloku 5x5 pixelu s vyberem ve tvaru diamantu.
    // Blizsi informace o tomto filtru jsou podany v dodatku disertacni prace.
    // ------------------------------------------------------------------------
    public void filter5x5diamond() {
        int pos=0;                                  // index do zdrojove a cilove pixmapy
        int color;                                  // RGBA barvove slozky zakodovane do typu int
        int r, g, b;                                // jednotlive rozkodovane barvove slozky
        filterNone();                               // nejprve pixmapy zkopirovat
        pos=2+2*imageWidth;
        for (int j=2; j<imageHeight-2; j++) {       // pro vsechny radky pixmapy
            for (int i=2; i<imageWidth-2; i++) {    // pro vsechny sloupce na radku pixmapy
                color=pixelSrc[pos-2*imageWidth+0];
                r =(color & 0x00ff0000)>>16;
                g =(color & 0x0000ff00)>>8;
                b =(color & 0x000000ff);
                color=pixelSrc[pos-  imageWidth-1];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos-  imageWidth+1];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos-2];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos+2];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos+  imageWidth-1];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos+  imageWidth+1];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos+2*imageWidth+0];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                r/=8; g/=8; b/=8;                   // provest filtraci
                pixelDest[pos]=(r<<16) | (g<<8) | b | (0xff<<24);
                pos++;
            }
        }
    }



    // ------------------------------------------------------------------------
    // Tato metoda provede filtraci pixmapy s filtrem typu:
    // rozmazani v bloku 5x5 pixelu s vyberem ve tvaru osoveho krize.
    // Blizsi informace o tomto filtru jsou podany v dodatku disertacni prace.
    // ------------------------------------------------------------------------
    public void filter5x5cross() {
        int pos=0;                                  // index do zdrojove a cilove pixmapy
        int color;                                  // RGBA barvove slozky zakodovane do typu int
        int r, g, b;                                // jednotlive rozkodovane barvove slozky
        filterNone();                               // nejprve pixmapy zkopirovat
        pos=2+2*imageWidth;
        for (int j=2; j<imageHeight-2; j++) {       // pro vsechny radky pixmapy
            for (int i=2; i<imageWidth-2; i++) {    // pro vsechny sloupce na radku pixmapy
                color=pixelSrc[pos-2*imageWidth+0];
                r =(color & 0x00ff0000)>>16;
                g =(color & 0x0000ff00)>>8;
                b =(color & 0x000000ff);
                color=pixelSrc[pos-  imageWidth+0];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos-2];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos-1];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos+1];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos+2];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos+  imageWidth+0];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos+2*imageWidth+0];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                r/=9; g/=9; b/=9;                   // provest filtraci
                pixelDest[pos]=(r<<16) | (g<<8) | b | (0xff<<24);
                pos++;
            }
        }
    }



    // ------------------------------------------------------------------------
    // Tato metoda provede filtraci pixmapy s filtrem typu:
    // rozmazani v bloku 5x5 pixelu s vyberem ve tvaru uhlopricneho krize.
    // Blizsi informace o tomto filtru jsou podany v dodatku disertacni prace.
    // ------------------------------------------------------------------------
    public void filter5x5Xcross() {
        int pos=0;                                  // index do zdrojove a cilove pixmapy
        int color;                                  // RGBA barvove slozky zakodovane do typu int
        int r, g, b;                                // jednotlive rozkodovane barvove slozky
        filterNone();                               // nejprve pixmapy zkopirovat
        pos=2+2*imageWidth;
        for (int j=2; j<imageHeight-2; j++) {       // pro vsechny radky pixmapy
            for (int i=2; i<imageWidth-2; i++) {    // pro vsechny sloupce na radku pixmapy
                color=pixelSrc[pos-2*imageWidth-2];
                r =(color & 0x00ff0000)>>16;
                g =(color & 0x0000ff00)>>8;
                b =(color & 0x000000ff);
                color=pixelSrc[pos-2*imageWidth+2];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos-  imageWidth-1];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos-  imageWidth+1];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos+  imageWidth-1];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos+  imageWidth+1];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos+2*imageWidth-2];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos+2*imageWidth+2];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                r/=9; g/=9; b/=9;                   // provest filtraci
                pixelDest[pos]=(r<<16) | (g<<8) | b | (0xff<<24);
                pos++;
            }
        }
    }



    // ------------------------------------------------------------------------
    // Tato metoda provede filtraci pixmapy s filtrem typu:
    // rozmazani v bloku 5x5 pixelu s vyberem ve tvaru bloku.
    // Blizsi informace o tomto filtru jsou podany v dodatku disertacni prace.
    // ------------------------------------------------------------------------
    public void filter5x5block() {
        int pos=0;                                  // index do zdrojove a cilove pixmapy
        int color;                                  // RGBA barvove slozky zakodovane do typu int
        int r, g, b;                                // jednotlive rozkodovane barvove slozky
        filterNone();                               // nejprve pixmapy zkopirovat
        pos=2+2*imageWidth;
        for (int j=2; j<imageHeight-2; j++) {       // pro vsechny radky pixmapy
            for (int i=2; i<imageWidth-2; i++) {    // pro vsechny sloupce na radku pixmapy
                color=pixelSrc[pos-2*imageWidth-2];
                r =(color & 0x00ff0000)>>16;
                g =(color & 0x0000ff00)>>8;
                b =(color & 0x000000ff);
                color=pixelSrc[pos-2*imageWidth-1];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos-2*imageWidth+0];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos-2*imageWidth+1];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos-2*imageWidth+2];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos-  imageWidth-2];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos-  imageWidth-1];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos-  imageWidth+0];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos-  imageWidth+1];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos-  imageWidth+2];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos-2];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos-1];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos+1];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos+2];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos+  imageWidth-2];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos+  imageWidth-1];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos+  imageWidth+0];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos+  imageWidth+1];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos+  imageWidth+2];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos+2*imageWidth-2];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos+2*imageWidth-1];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos+2*imageWidth+0];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos+2*imageWidth+1];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos+2*imageWidth+2];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                r/=25; g/=25; b/=25;                // provest filtraci
                pixelDest[pos]=(r<<16) | (g<<8) | b | (0xff<<24);
                pos++;
            }
        }
    }



    // ------------------------------------------------------------------------
    // Tato metoda provede filtraci pixmapy s filtrem typu:
    // horizontalni filtr rozmazani tri pixelu.
    // Blizsi informace o tomto filtru jsou podany v dodatku disertacni prace.
    // ------------------------------------------------------------------------
    public void filter3pixelsH() {
        int pos=0;                                  // index do zdrojove a cilove pixmapy
        int color;                                  // RGBA barvove slozky zakodovane do typu int
        int r, g, b;                                // jednotlive rozkodovane barvove slozky
        filterNone();                               // nejprve pixmapy zkopirovat
        pos=1;
        for (int j=0; j<imageHeight; j++) {         // pro vsechny radky pixmapy
            for (int i=1; i<imageWidth-1; i++) {    // pro vsechny sloupce na radku pixmapy
                color=pixelSrc[pos-1];
                r =(color & 0x00ff0000)>>16;
                g =(color & 0x0000ff00)>>8;
                b =(color & 0x000000ff);
                color=pixelSrc[pos];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos+1];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                r/=3; g/=3; b/=3;                   // provest filtraci
                pixelDest[pos]=(r<<16) | (g<<8) | b | (0xff<<24);
                pos++;
            }
        }
    }



    // ------------------------------------------------------------------------
    // Tato metoda provede filtraci pixmapy s filtrem typu:
    // vertikalni filtr rozmazani tri pixelu.
    // Blizsi informace o tomto filtru jsou podany v dodatku disertacni prace.
    // ------------------------------------------------------------------------
    public void filter3pixelsV() {
        int pos=0;                                  // index do zdrojove a cilove pixmapy
        int color;                                  // RGBA barvove slozky zakodovane do typu int
        int r, g, b;                                // jednotlive rozkodovane barvove slozky
        filterNone();                               // nejprve pixmapy zkopirovat
        pos=imageWidth;
        for (int j=1; j<imageHeight-1; j++) {       // pro vsechny radky pixmapy
            for (int i=0; i<imageWidth; i++) {      // pro vsechny sloupce na radku pixmapy
                color=pixelSrc[pos-imageWidth];
                r =(color & 0x00ff0000)>>16;
                g =(color & 0x0000ff00)>>8;
                b =(color & 0x000000ff);
                color=pixelSrc[pos];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos+imageWidth];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                r/=3; g/=3; b/=3;                   // provest filtraci
                pixelDest[pos]=(r<<16) | (g<<8) | b | (0xff<<24);
                pos++;
            }
        }
    }



    // ------------------------------------------------------------------------
    // Tato metoda provede filtraci pixmapy s filtrem typu:
    // horizontalni filtr rozmazani peti pixelu.
    // Blizsi informace o tomto filtru jsou podany v dodatku disertacni prace.
    // ------------------------------------------------------------------------
    public void filter5pixelsH() {
        int pos=0;                                  // index do zdrojove a cilove pixmapy
        int color;                                  // RGBA barvove slozky zakodovane do typu int
        int r, g, b;                                // jednotlive rozkodovane barvove slozky
        filterNone();                               // nejprve pixmapy zkopirovat
        pos=2;
        for (int j=0; j<imageHeight; j++) {         // pro vsechny radky pixmapy
            for (int i=2; i<imageWidth-2; i++) {    // pro vsechny sloupce na radku pixmapy
                color=pixelSrc[pos-2];
                r =(color & 0x00ff0000)>>16;
                g =(color & 0x0000ff00)>>8;
                b =(color & 0x000000ff);
                color=pixelSrc[pos-1];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos+1];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos+2];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                r/=5; g/=5; b/=5;                   // provest filtraci
                pixelDest[pos]=(r<<16) | (g<<8) | b | (0xff<<24);
                pos++;
            }
        }
    }



    // ------------------------------------------------------------------------
    // Tato metoda provede filtraci pixmapy s filtrem typu:
    // vertikalni filtr rozmazani peti pixelu.
    // Blizsi informace o tomto filtru jsou podany v dodatku disertacni prace.
    // ------------------------------------------------------------------------
    public void filter5pixelsV() {
        int pos=0;                                  // index do zdrojove a cilove pixmapy
        int color;                                  // RGBA barvove slozky zakodovane do typu int
        int r, g, b;                                // jednotlive rozkodovane barvove slozky
        filterNone();                               // nejprve pixmapy zkopirovat
        pos=2*imageWidth;
        for (int j=2; j<imageHeight-2; j++) {       // pro vsechny radky pixmapy
            for (int i=0; i<imageWidth; i++) {      // pro vsechny sloupce na radku pixmapy
                color=pixelSrc[pos-2*imageWidth];
                r =(color & 0x00ff0000)>>16;
                g =(color & 0x0000ff00)>>8;
                b =(color & 0x000000ff);
                color=pixelSrc[pos-  imageWidth];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos+  imageWidth];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                color=pixelSrc[pos+2*imageWidth];
                r+=(color & 0x00ff0000)>>16;
                g+=(color & 0x0000ff00)>>8;
                b+=(color & 0x000000ff);
                r/=5; g/=5; b/=5;                   // provest filtraci
                pixelDest[pos]=(r<<16) | (g<<8) | b | (0xff<<24);
                pos++;
            }
        }
    }
}
// ----------------------------------------------------------------------------
// Konec tridy Filter.
// ----------------------------------------------------------------------------



// ----------------------------------------------------------------------------
// Trida s panelem, na kterem se zobrazuje pixmapa o predem danem rozmeru.
// ----------------------------------------------------------------------------
class ImagePanel extends Canvas {
    int               width;                        // rozmery pixmapy
    int               height;
    public int[]      pixels;                       // pixmapa - zdroj pixelu
    MemoryImageSource imageSource;                  // objekt zaobalujici zdroj pixelu
    Image             image;                        // pixmapa vytvorena nad zdrojem pixelu



    // ------------------------------------------------------------------------
    // V konstruktoru se nastavi velikost panelu a soucasne barva jeho pozadi.
    // ------------------------------------------------------------------------
    public ImagePanel(int width, int height) {
        pixels=new int[width*height];
        for (int j=0; j<height; j++)                // pro vsechny radky pixmapy
            for (int i=0; i<width; i++)             // pro vsechny sloupce pixmapy
                pixels[i+j*width]=0xffffffff;       // vyplnit pixmapu i s alfa kanalem
        imageSource=new MemoryImageSource(width, height, pixels, 0, height);
        image=createImage(imageSource);             // vytvoreni pixmapy
        this.width=width;                           // nastaveni velikosti pixmapy
        this.height=height;
        this.setBackground(Color.white);            // nastaveni vlastnosti panelu
        this.setSize(width, height);
    }



    // ------------------------------------------------------------------------
    // Pristup k jednotlivym pixelum pixmapy.
    // ------------------------------------------------------------------------
    public void putpixel(int x, int y, int r, int g, int b) {
        pixels[x+y*width]=r+(g<<8)+(b<<16)+(255<<24);
    }



    // ------------------------------------------------------------------------
    // Aplikaci dostupne prekresleni celeho panelu s volbou vymazu stare kresby.
    // ------------------------------------------------------------------------
    public void redraw(boolean clear) {
        Graphics g=this.getGraphics();
        if (clear)                                  // premazat starou kresbu
            g.clearRect(0, 0, width, height);
        image.flush();                              // prenest pixely do obrazu
        g.drawImage(image, 0, 0, this);             // a vykreslit obraz s pixmapou
    }



    // ------------------------------------------------------------------------
    // Prekresleni panelu s pixmapou.
    // ------------------------------------------------------------------------
    public void paint(Graphics g) {
        g.drawImage(image, 0, 0, this);             // vykreslit obraz s pixmapou
    }
}
// ----------------------------------------------------------------------------
// Konec tridy ImagePanel.
// ----------------------------------------------------------------------------



// ----------------------------------------------------------------------------
// Trida s kodem pro zobrazeni napovedy.
// ----------------------------------------------------------------------------
class WindowHelp extends Frame implements ActionListener {
    static boolean visible=false;                   // priznak indikujici zobrazeni napovedy



    // ------------------------------------------------------------------------
    // Konstrukce okna s napovedou.
    // ------------------------------------------------------------------------
    public WindowHelp() {
        TextArea text=new TextArea(
            "1. choose first IFS system\n"+
            "2. choose second IFS system\n"+
            "3. adjust number of points\n"+
            "4. adjust start iteration\n"+
            "5. adjust morph ratio between first and second IFS systems\n"+
            "6. then press the 'Recalc' button\n"+
            "7. apply filter with 'Redraw' button"
        );
        visible=true;
        Button buttonOK=new Button("ok");
        Label  label=new Label("How to work with this applet:");
        buttonOK.addActionListener(this);           // po stlaceni tlacitka se ma napoveda zavrit
        this.setSize(320, 240);                     // nastaveni velikosti a rozmeru okna
        this.setLocation(100, 100);
        this.setTitle("Morph IFS - Help");          // zobrazeni titulku
        this.add("Center", text);                   // a pridani vsech ovladacich prvku
        this.add("South", buttonOK);
        this.add("North", label);
        this.setVisible(true);
    }



    // ------------------------------------------------------------------------
    // Reakce na stlaceni tlacitka s textem OK.
    // ------------------------------------------------------------------------
    public void actionPerformed(ActionEvent e) {
        visible=false;
        this.dispose();
    }
}
// ----------------------------------------------------------------------------
// Konec tridy WindowHelp.
// ----------------------------------------------------------------------------



// ----------------------------------------------------------------------------
// Trida s kodem pro zobrazeni informaci o aplikaci.
// ----------------------------------------------------------------------------
class WindowAbout extends Frame implements ActionListener {
    static boolean visible=false;                   // priznak indikujici zobrazeni okna



    // ------------------------------------------------------------------------
    // Konstrukce okna s informaci o aplikaci.
    // ------------------------------------------------------------------------
    public WindowAbout() {
        TextArea text=new TextArea(
            "Morph IFS demo\n\n"+
            "version 1.0\n"+
            "Author: Pavel Tisnovsky\n"+
            "Date: 2004-09-20\n"+
            "http://www.fit.vutbr.cz/~tisnovpa\n"
        );
        visible=true;
        Button buttonOK=new Button("ok");
        Label  label=new Label("About Morph IFS");
        buttonOK.addActionListener(this);           // po stlaceni tlacitka se ma okno zavrit
        this.setSize(320, 240);                     // nastaveni velikosti a rozmeru okna
        this.setLocation(100, 100);
        this.setTitle("Morph IFS - About");
        this.add("Center", text);                   // a pridani vsech ovladacich prvku
        this.add("South", buttonOK);
        this.add("North", label);
        this.setVisible(true);
    }



    // ------------------------------------------------------------------------
    // Reakce na stlaceni tlacitka s textem OK.
    // ------------------------------------------------------------------------
    public void actionPerformed(ActionEvent e) {
        visible=false;
        this.dispose();
    }
}
// ----------------------------------------------------------------------------
// Konec tridy WindowAbout.
// ----------------------------------------------------------------------------



// ----------------------------------------------------------------------------
// Trida s kodem pro zobrazeni informaci o systemu.
// ----------------------------------------------------------------------------
class WindowInfo extends Frame implements ActionListener {
    static boolean visible=false;                   // priznak indikujici zobrazeni okna



    // ------------------------------------------------------------------------
    // Konstrukce okna s informacemi.
    // ------------------------------------------------------------------------
    public WindowInfo() {
        Runtime r=Runtime.getRuntime();             // ziskat objekt s informacemi o aplikaci
        TextArea text=new TextArea("");
        text.append("Total memory: "+r.totalMemory()+"\n");
        text.append("Free memory: "+r.freeMemory()+"\n");
        visible=true;
        Button buttonOK=new Button("ok");
        Label  label=new Label("System informations:");
        buttonOK.addActionListener(this);           // po stlaceni tlacitka se ma okno zavrit
        this.setSize(320, 240);                     // nastaveni velikosti a rozmeru okna
        this.setLocation(100, 100);
        this.setTitle("Morph IFS - Info");          // zobrazeni titulku
        this.add("Center", text);                   // a pridani vsech ovladacich prvku
        this.add("South", buttonOK);
        this.add("North", label);
        this.setVisible(true);
    }



    // ------------------------------------------------------------------------
    // Reakce na stlaceni tlacitka s textem OK.
    // ------------------------------------------------------------------------
    public void actionPerformed(ActionEvent e) {
        visible=false;
        this.dispose();
    }
}
// ----------------------------------------------------------------------------
// Konec tridy WindowInfo.
// ----------------------------------------------------------------------------



// ----------------------------------------------------------------------------
// Rozhrani s tvary bodu.
// ----------------------------------------------------------------------------
interface PointShape {
    int OnePixel=   0,                              // bod ma tvar jednoho pixelu
        Cross3x3=   1,                              // pet pixelu ve tvaru krize
        XCross3x3=  2,                              // pet pixelu ve tvaru uhlopricneho krize
        Diamond3x3= 3,                              // ctyri pixely ve tvaru diamantu
        Block3x3=   4,                              // blok deviti pixelu
        Cross5x5=   5,                              // dtto pro okoli 5x5
        XCross5x5=  6,
        Diamond5x5= 7,
        Block5x5=   8,
        Horizontal3=9,                              // tri pixely vedle sebe
        Horizontal5=10,                             // pet pixelu vedle sebe
        Vertical3=  11,                             // tri pixely pod sebou
        Vertical5=  12;                             // pet pixelu pod sebou
}
// ----------------------------------------------------------------------------
// Konec rozhrani PointShape.
// ----------------------------------------------------------------------------



// ----------------------------------------------------------------------------
// Rozhrani se jmeny filtru.
// ----------------------------------------------------------------------------
interface FilterType {
    int None=       0,                              // zadny filtr
        Smooth2x2=  1,                              // filtr typu 2x2 smooth
        Diamond3x3= 2,                              // filtr typu 3x3 diamond
        Cross3x3=   3,                              // filtr typu 3x3 cross
        XCross3x3=  4,                              // filtr typu 3x3 X cross
        Block3x3=   5,                              // filtr typu 3x3 block
        Diamond5x5= 6,                              // filtr typu 5x5 diamond
        Cross5x5=   7,                              // filtr typu 5x5 cross
        XCross5x5=  8,                              // filtr typu 5x5 X cross
        Block5x5=   9,                              // filtr typu 5x5 block
        Horizontal3=10,                             // filtr typu 3 pixels horizontal
        Horizontal5=11,                             // filtr typu 5 pixels horizontal
        Vertical3=  12,                             // filtr typu 3 pixels vertical
        Vertical5=  13;                             // filtr typu 5 pixels vertical
}
// ----------------------------------------------------------------------------
// Konec rozhrani FilterType.
// ----------------------------------------------------------------------------



// ----------------------------------------------------------------------------
// Rozhrani se jmeny IFS systemu.
// ----------------------------------------------------------------------------
interface IFStype {
    int Binary=     0,                              // nazvy jednotlivych fraktalu
        Coral=      1,                              // jsou prevzaty z programu
        Crystal=    2,                              // FractInt/WinFractInt
        Dragon=     3,
        Dragon2=    4,
        Feathe=     5,
        Fern=       6,
        Ferny=      7,
        Flake=      8,
        Floor=      9,
        Fossil=    10,
        Koch=      11,
        Leaf=      12,
        Leaf2=     13,
        Pincher=   14,
        Pull=      15,
        Spiral=    16,
        Spiral2=   17,
        Swirl=     18,
        Square=    19,
        Telephon=  20,
        Tree=      21,
        Tree2=     22,
        Tree3=     23,
        Triangle=  24,
        Z=         25,
        Zigzag=    26;

}
// ----------------------------------------------------------------------------
// Konec rozhrani IFStype.
// ----------------------------------------------------------------------------



// ----------------------------------------------------------------------------
// V pripade, ze by bylo nutne tento demonstrani program spustit jako Java ap-
// likaci, je mozne odkomentovat metodu "main". V tomto pripade se vsak vytvo-
// ri dalsi soubor .class s anonymni tridou Listener.
// ----------------------------------------------------------------------------
public class MorphIFS extends Applet implements Runnable, ActionListener, ItemListener, AdjustmentListener, FilterType, PointShape {
    static final int ImageWidth=256;                // sirka pixmapy s fraktalem
    static final int ImageHeight=256;               // vyska pixmapy s fraktalem
    static final int DrawingWidth=256;              // sirka kresby pouzivane pro konstrukci fraktalu
    static final int DrawingHeight=256+150;         // vyska kresby pouzivane pro konstrukci fraktalu
    static final int TextBegin=256+10;              // horizontalni zacatek informacniho textu
    static final int TextHeight=120;                // vyska informacniho textu

    int              maxIter=5000;                  // pocet vsech iteraci
    int              startIter=200;                 // pocet startovnich iteraci
    double           morphRatio=0.0;                // morfovani dvou objektu
    int              pointShape=PointShape.OnePixel;// typ vykreslovanych bodu
    int              filterType=FilterType.Cross3x3;// typ pouziteho filtru
    int              firstIFS=IFStype.Fern;         // prvni IFS system
    int              secondIFS=IFStype.Tree;        // druhy IFS system
    static int       putpixelMode=0;                // vykreslovaci rezim

    // vytvoreni vsech panelu pouzitych v appletu
    ImagePanel  morphIfs=            new ImagePanel(ImageWidth, ImageHeight);
    ImagePanel  filteredIfs=         new ImagePanel(ImageWidth, ImageHeight);
    ImagePanel  Ifs1=                new ImagePanel(ImageWidth, ImageHeight);
    ImagePanel  Ifs2=                new ImagePanel(ImageWidth, ImageHeight);
    Panel       panelLeft=           new Panel(new GridLayout(2, 2, 5, 5));
    Panel       panelUp=             new Panel(new GridLayout(2, 5, 5, 5));// horni panel s list-boxy
    Panel       panelDown=           new Panel(new GridLayout(2, 3, 5, 5));// dolni panel s posuvniky
    Panel       panelRight=          new Panel(new GridLayout(8, 1));// pravy panel s tlacitky

    // filtr aplikovany na zdrojovou pixmapu, vysledek je v cilove pixmape
    Filter filter=new Filter(ImageWidth, ImageHeight, morphIfs.pixels, filteredIfs.pixels);

    IFS         ifs=null;

    // vytvoreni vsech textovych navesti pouzitych v appletu
    Label       labelFirstIFS=          new Label("First system");
    Label       labelSecondIFS=         new Label("Second system");
    Label       labelPointShape=        new Label("Point shape");
    Label       labelFilterType=        new Label("Filter");
    Label       labelPutpixelMode=      new Label("Putpixel mode");
    Label       labelMaxIter=           new Label("Iterations: "+String.valueOf(maxIter));
    Label       labelStartIter=         new Label("Start iterations: "+String.valueOf(startIter));
    Label       labelMorph=             new Label("Morph ratio: "+String.valueOf(morphRatio));

    // vytvoreni vsech list-boxu pouzitych v appletu
    Choice      choicePointShape=       new Choice();  // list-box pro vyber tvaru bodu
    Choice      choiceFilter=           new Choice();  // list-box pro vyber aktivniho filtru
    Choice      choiceFirstIFS=         new Choice();
    Choice      choiceSecondIFS=        new Choice();
    Choice      choicePutpixelMode=     new Choice();  // list-box pro vyber vykreslovaciho rezimu

    // vytvoreni vsech tlacitek pouzitych v appletu
    Button      buttonRedraw=           new Button("Redraw");
    Button      buttonRecalc=           new Button("Recalc");
    Button      buttonAbout=            new Button("About");
    Button      buttonInfo=             new Button("Info");
    Button      buttonHelp=             new Button("Help");

    // vytvoreni vsech slideru pouzitych v appletu
    Scrollbar   scrollBarMaxIter=       new Scrollbar(Scrollbar.HORIZONTAL,
                                                      maxIter,
                                                      10000,
                                                      2000,
                                                      100000+10000);
    Scrollbar   scrollBarStartIter=     new Scrollbar(Scrollbar.HORIZONTAL,
                                                      startIter,
                                                      100,
                                                      200,
                                                      1000+100);
    Scrollbar   scrollBarMorphRatio=    new Scrollbar(Scrollbar.HORIZONTAL,
                                                      (int)morphRatio*1000,
                                                      100,
                                                      0,
                                                      1000+100);



    // ------------------------------------------------------------------------
    // Tato metoda provede inicializaci horniho panelu s rolovacimi list-boxy.
    // Metoda je zavolana behem inicializace aplikace ci appletu.
    // ------------------------------------------------------------------------
    private void initPanelUp() {
        panelUp.setBackground(Color.white);         // nastaveni barvy pozadi

        panelUp.add(labelFirstIFS);                 // pridani vsech textovych navesti
        panelUp.add(labelSecondIFS);                // do horniho panelu
        panelUp.add(labelPointShape);
        panelUp.add(labelFilterType);
        panelUp.add(labelPutpixelMode);

        panelUp.add(choiceFirstIFS);
        panelUp.add(choiceSecondIFS);
        panelUp.add(choicePointShape);              // pridani vsech list-boxu
        panelUp.add(choiceFilter);
        panelUp.add(choicePutpixelMode);

        // prace s list-boxem pointShape
        choicePointShape.setEnabled(true);          // naplneni list-boxu texty a povoleni list-boxu
        choicePointShape.add("1 pixel");
        choicePointShape.add("Cross 3x3 pixels");
        choicePointShape.add("X cross 3x3 pixels");
        choicePointShape.add("Diamond 3x3 pixels");
        choicePointShape.add("Block 3x3 pixels");
        choicePointShape.add("Cross 5x5 pixels");
        choicePointShape.add("X cross 3x3 pixels");
        choicePointShape.add("Diamond 5x5 pixels");
        choicePointShape.add("Block 5x5 pixels");
        choicePointShape.add("3 pixels horizontal");
        choicePointShape.add("5 pixels horizontal");
        choicePointShape.add("3 pixels vertical");
        choicePointShape.add("5 pixels vertical");
        choicePointShape.select(pointShape);        // vyber aktivni polozky z list-boxu
        choicePointShape.addItemListener(this);     // nastaveni zpracovani udalosti od list-boxu

        // prace s list-boxem Filter
        choiceFilter.setEnabled(true);              // naplneni list-boxu texty a povoleni list-boxu
        choiceFilter.add("none");
        choiceFilter.add("2x2 smooth");
        choiceFilter.add("3x3 diamond");
        choiceFilter.add("3x3 cross");
        choiceFilter.add("3x3 X cross");
        choiceFilter.add("3x3 block");
        choiceFilter.add("5x5 diamond");
        choiceFilter.add("5x5 cross");
        choiceFilter.add("5x5 X cross");
        choiceFilter.add("5x5 block");
        choiceFilter.add("3 pixels horizontal");
        choiceFilter.add("5 pixels horizontal");
        choiceFilter.add("3 pixels vertical");
        choiceFilter.add("5 pixels vertical");
        choiceFilter.select(filterType);            // vyber aktivni polozky z list-boxu
        choiceFilter.addItemListener(this);         // nastaveni zpracovani udalosti od list-boxu

        // prace s list-boxem FirstIFS
        choiceFirstIFS.setEnabled(true);            // naplneni list-boxu texty a povoleni list-boxu
        choiceFirstIFS.add("Binary");
        choiceFirstIFS.add("Coral");
        choiceFirstIFS.add("Crystal");
        choiceFirstIFS.add("Dragon 1");
        choiceFirstIFS.add("Dragon 2");
        choiceFirstIFS.add("Feathe");
        choiceFirstIFS.add("Fern");
        choiceFirstIFS.add("Ferny");
        choiceFirstIFS.add("Flake");
        choiceFirstIFS.add("Floor");
        choiceFirstIFS.add("Fossil");
        choiceFirstIFS.add("Koch");
        choiceFirstIFS.add("Leaf 1");
        choiceFirstIFS.add("Leaf 2");
        choiceFirstIFS.add("Pincher");
        choiceFirstIFS.add("Pull");
        choiceFirstIFS.add("Spiral 1");
        choiceFirstIFS.add("Spiral 2");
        choiceFirstIFS.add("Swirl");
        choiceFirstIFS.add("Square");
        choiceFirstIFS.add("Telephon");
        choiceFirstIFS.add("Tree 1");
        choiceFirstIFS.add("Tree 2");
        choiceFirstIFS.add("Tree 3");
        choiceFirstIFS.add("Triangle");
        choiceFirstIFS.add("Z");
        choiceFirstIFS.add("Zig-zag");
        choiceFirstIFS.select(firstIFS);            // vyber aktivni polozky z list-boxu
        choiceFirstIFS.addItemListener(this);       // nastaveni zpracovani udalosti od list-boxu

        // prace s list-boxem SecondIFS
        choiceSecondIFS.setEnabled(true);           // naplneni list-boxu texty a povoleni list-boxu
        choiceSecondIFS.add("Binary");
        choiceSecondIFS.add("Coral");
        choiceSecondIFS.add("Crystal");
        choiceSecondIFS.add("Dragon");
        choiceSecondIFS.add("Dragon 2");
        choiceSecondIFS.add("Feathe");
        choiceSecondIFS.add("Fern");
        choiceSecondIFS.add("Ferny");
        choiceSecondIFS.add("Flake");
        choiceSecondIFS.add("Floor");
        choiceSecondIFS.add("Fossil");
        choiceSecondIFS.add("Koch");
        choiceSecondIFS.add("Leaf 1");
        choiceSecondIFS.add("Leaf 2");
        choiceSecondIFS.add("Pincher");
        choiceSecondIFS.add("Pull");
        choiceSecondIFS.add("Spiral 1");
        choiceSecondIFS.add("Spiral 2");
        choiceSecondIFS.add("Swirl");
        choiceSecondIFS.add("Square");
        choiceSecondIFS.add("Telephon");
        choiceSecondIFS.add("Tree 1");
        choiceSecondIFS.add("Tree 2");
        choiceSecondIFS.add("Tree 3");
        choiceSecondIFS.add("Triangle");
        choiceSecondIFS.add("Z");
        choiceSecondIFS.add("Zig-zag");
        choiceSecondIFS.select(secondIFS);          // vyber aktivni polozky z list-boxu
        choiceSecondIFS.addItemListener(this);      // nastaveni zpracovani udalosti od list-boxu

        // prace s list-boxem putpixel mode
        choicePutpixelMode.setEnabled(true);
        choicePutpixelMode.add("draw black pixel");
        choicePutpixelMode.add("add 4");
        choicePutpixelMode.add("add 8");
        choicePutpixelMode.add("add 12");
        choicePutpixelMode.add("add 16");
        choicePutpixelMode.add("add 20");
        choicePutpixelMode.select(putpixelMode);
        choicePutpixelMode.addItemListener(this);
    }



    // ------------------------------------------------------------------------
    // Tato metoda provede inicializaci dolniho panelu se slidery.
    // Metoda je zavolana behem inicializace aplikace ci appletu.
    // ------------------------------------------------------------------------
    private void initPanelDown() {
        panelDown.setBackground(Color.white);       // nastaveni barvy pozadi
        panelDown.add(labelMaxIter);                // pridani vsech textovych navesti
        panelDown.add(labelStartIter);
        panelDown.add(labelMorph);
        panelDown.add(scrollBarMaxIter);            // pridani vsech slideru
        panelDown.add(scrollBarStartIter);
        panelDown.add(scrollBarMorphRatio);
        scrollBarMaxIter.addAdjustmentListener(this);// nastaveni reakci na udalosti slideru
        scrollBarStartIter.addAdjustmentListener(this);
        scrollBarMorphRatio.addAdjustmentListener(this);
    }



    // ------------------------------------------------------------------------
    // Tato metoda provede nastaveni praveho panelu s tlacitky (buttony).
    // Metoda je zavolana behem inicializace aplikace ci appletu.
    // ------------------------------------------------------------------------
    private void initPanelRight() {
        panelRight.setBackground(Color.white);      // nastaveni barvy pozadi
        panelRight.add(buttonRecalc);               // pridani vsech textovych tlacitek
        panelRight.add(buttonRedraw);
        panelRight.add(new Label(""));              // volna polozka pro oddeleni tlacitek
        panelRight.add(buttonAbout);
        panelRight.add(buttonInfo);
        panelRight.add(buttonHelp);
        buttonRedraw.addActionListener(this);       // nastaveni reakce na udalosti od tlacitek
        buttonRecalc.addActionListener(this);
        buttonAbout.addActionListener(this);
        buttonInfo.addActionListener(this);
        buttonHelp.addActionListener(this);
    }



    // ------------------------------------------------------------------------
    // Tato metoda provede nastaveni leveho panelu s obrazky.
    // ------------------------------------------------------------------------
    private void initPanelLeft() {
        panelLeft.setBackground(Color.white);
        panelLeft.add(Ifs1);
        panelLeft.add(Ifs2);
        panelLeft.add(morphIfs);
        panelLeft.add(filteredIfs);
    }



    // ------------------------------------------------------------------------
    // Tato metoda provede inicializaci appletu.
    // Metoda je volana z virtualniho stroje Javy (JVM).
    // ------------------------------------------------------------------------
    public void init() {
        this.setBackground(Color.white);            // nastaveni barvy pozadi
        setLayout(new BorderLayout(5,5));           // nastaveni layoutu aplikace
        initPanelUp();                              // nastavit horni panel
        initPanelDown();                            // nastavit dolni panel
        initPanelRight();                           // nastavit pravy panel
        initPanelLeft();                            // nastavit levy panel
        add("North",  panelUp);                     // pridat horni panel do plochy aplikace
        add("South",  panelDown);                   // pridat dolni panel do plochy aplikace
        add("East",   panelRight);                  // pridat pravy panel do plochy aplikace
        add("West",   panelLeft);
    }



    // ------------------------------------------------------------------------
    // Tato metoda se zavola pri destrukci appletu.
    // Metoda je volana z virtualniho stroje Javy (JVM)
    // ------------------------------------------------------------------------
    public void destroy() {
        remove(panelLeft);
        remove(panelRight);                         // zrusit pravy panel
        remove(panelUp);                            // zrusit horni panel
        remove(panelDown);                          // zrusit dolni panel
        remove(filteredIfs);                        // zrusit centralni panel
    }



    // ------------------------------------------------------------------------
    // Tato metoda se zavola vzdy pri nastartovani appletu.
    // Metoda je volana z virtualniho stroje Javy (JVM).
    // ------------------------------------------------------------------------
    public void start() {
        recalcFractal(true);
    }



    // ------------------------------------------------------------------------
    // Tato metoda se zavola pri kazdem zastaveni appletu.
    // Metoda je volana z virtualniho stroje Javy (JVM).
    // ------------------------------------------------------------------------
    public void stop() {
    }



    // ------------------------------------------------------------------------
    // Tato metoda se zavola pri nastartovani appletu.
    // Metoda je volana z virtualniho stroje Javy (JVM).
    // ------------------------------------------------------------------------
    public void run() {
        repaint();                                  // prvotni vykresleni plochy appletu
    }



    // ------------------------------------------------------------------------
    // Tato metoda se zavola vzdy, kdyz je nutno prekreslit plochu appletu.
    // Metoda je volana z virtualniho stroje Javy (JVM).
    // ------------------------------------------------------------------------
    public void update(Graphics g) {
        paint(g);                                   // povolit prekresleni appletu
    }



    // ------------------------------------------------------------------------
    // Tato metoda se zavola kdyz je potreba prekreslit applet.
    // Metoda je volana z virtualniho stroje Javy (JVM).
    // ------------------------------------------------------------------------
    public void paint(Graphics g) {
    }



    // ------------------------------------------------------------------------
    // Nastaveni vnitrnich okraju v okne appletu.
    // Metoda je volana z virtualniho stroje Javy (JVM).
    // ------------------------------------------------------------------------
    public Insets getInsets() {
        return new Insets(5, 5, 5, 5);
    }



    // ------------------------------------------------------------------------
    // Tato metoda je zavolana v pripade, ze je stlaceno nektere tlacitko
    // umistene na plose appletu.
    // Metoda je volana z virtualniho stroje Javy (JVM).
    // ------------------------------------------------------------------------
    public void actionPerformed(ActionEvent e) {
        Object o=e.getSource();                     // ktere tlacitko je stlaceno?
        if (o==buttonRedraw) {                      // ma se pouze prekreslit fraktal
            morphIfs.redraw(false);
            applyFilter();
            filteredIfs.redraw(false);
        }
        if (o==buttonRecalc) {                      // prepocitani celeho fraktalu
            recalcFractal(true);
        }
        if (o==buttonAbout) {                       // text s informacemi o autorech
            if (!WindowAbout.visible) {
                WindowAbout window=new WindowAbout();
            }
        }
        if (o==buttonHelp) {                        // text s napovedou
            if (!WindowHelp.visible) {
                WindowHelp window=new WindowHelp();
            }
        }
        if (o==buttonInfo) {                        // text s informacemi o aplikaci
            if (!WindowInfo.visible) {
                WindowInfo window=new WindowInfo();
            }
        }
    }



    // ------------------------------------------------------------------------
    // Tato metoda je zavolana v pripade, ze je vybran prvek z list-boxu
    // umisteneho na plose appletu.
    // Metoda je volana z virtualniho stroje Javy (JVM).
    // ------------------------------------------------------------------------
    public void itemStateChanged(ItemEvent e) {
        Object o=e.getSource();                     // ziskat informace, ktery list-box je zmenen
        if (o==choicePointShape) {
            pointShape=choicePointShape.getSelectedIndex();
            recalcFractal(true);
        }
        if (o==choiceFilter) {                      // uzivatel zmenil filtr aplikovany na obrazek
            filterType=choiceFilter.getSelectedIndex();// ziskat index vybraneho filtru
            applyFilter();
            filteredIfs.redraw(false);
        }
        if (o==choiceFirstIFS) {
            firstIFS=choiceFirstIFS.getSelectedIndex();
            recalcFractal(true);
        }
        if (o==choiceSecondIFS) {
            secondIFS=choiceSecondIFS.getSelectedIndex();
            recalcFractal(true);
        }
        if (o==choicePutpixelMode) {
            putpixelMode=choicePutpixelMode.getSelectedIndex();
            recalcFractal(true);
        }
    }



    // ------------------------------------------------------------------------
    // Tato metoda je zavolana v pripade, ze uzivatel zmenil polohu nektereho
    // posuvniku (slideru) umisteneho na plose appletu.
    // Metoda je volana z virtualniho stroje Javy (JVM).
    // ------------------------------------------------------------------------
    public void adjustmentValueChanged(AdjustmentEvent e) {
        Object o=e.getSource();                     // ziskat slider, ktery byl zmenen
        if (o==scrollBarMaxIter) {                  // zmena poctu iteraci
            maxIter=scrollBarMaxIter.getValue();    // ziskat pocet iteraci
            labelMaxIter.setText("Iterations: "+String.valueOf(maxIter));
        }
        if (o==scrollBarStartIter) {                // zmena poctu startovnich iteraci
            startIter=scrollBarStartIter.getValue();// ziskat pocet startovnich teraci
            labelStartIter.setText("Start iterations: "+String.valueOf(startIter));
        }
        if (o==scrollBarMorphRatio) {               // uroven morphingu mezi objekty
            morphRatio=scrollBarMorphRatio.getValue()/1000.0;// ziskat uroven morphingu
            labelMorph.setText("Morph ratio: "+String.valueOf(morphRatio));
            recalcFractal(false);
        }
    }



    // ------------------------------------------------------------------------
    // Tato metoda zmeni aktualni filtr.
    // ------------------------------------------------------------------------
    public void applyFilter() {
        switch (filterType) {
            case FilterType.None:       filter.filterNone();       break; // zadny filtr
            case FilterType.Smooth2x2:  filter.filter2x2smooth();  break; // filtr typu 2x2 smooth
            case FilterType.Diamond3x3: filter.filter3x3diamond(); break; // filtr typu 3x3 diamond
            case FilterType.Cross3x3:   filter.filter3x3cross();   break; // filtr typu 3x3 cross
            case FilterType.XCross3x3:  filter.filter3x3Xcross();  break; // filtr typu 3x3 X cross
            case FilterType.Block3x3:   filter.filter3x3block();   break; // filtr typu 3x3 block
            case FilterType.Diamond5x5: filter.filter5x5diamond(); break; // filtr typu 5x5 diamond
            case FilterType.Cross5x5:   filter.filter5x5cross();   break; // filtr typu 5x5 cross
            case FilterType.XCross5x5:  filter.filter5x5Xcross();  break; // filtr typu 5x5 X cross
            case FilterType.Block5x5:   filter.filter5x5block();   break; // filtr typu 5x5 block
            case FilterType.Horizontal3:filter.filter3pixelsH();   break; // filtr typu 3 pixels horizontal
            case FilterType.Horizontal5:filter.filter5pixelsH();   break; // filtr typu 5 pixels horizontal
            case FilterType.Vertical3:  filter.filter3pixelsV();   break; // filtr typu 3 pixels vertical
            case FilterType.Vertical5:  filter.filter5pixelsV();   break; // filtr typu 5 pixels vertical
            default:                                               break; // tato volba by nemela nikdy nastat
        }
    }



    // ------------------------------------------------------------------------
    // Tato metoda provede prepocet fraktalu.
    // ------------------------------------------------------------------------
    private void recalcFractal(boolean bfilter) {
        if (ifs!=null) {
            if (ifs.isAlive())
                return;
        }
        ifs=new IFS();                              // vytvorit novy generator fraktalu
        ifs.setPixels(morphIfs.pixels);             // nastavit jeho parametry
        ifs.setSize(ImageWidth, ImageHeight);
        ifs.setMaxIter(maxIter);
        ifs.setStartIter(startIter);
        ifs.setPointShape(pointShape);
        ifs.setMorphRatio(morphRatio);
        ifs.setFirstIFS(firstIFS);
        ifs.setSecondIFS(secondIFS);
        ifs.setObject(this);
        ifs.setFilter(bfilter);
        ifs.setPutpixelMode(putpixelMode);
        ifs.start();                                // a spustit ho
        if (bfilter) {
            IFS ifs1=new IFS();
            ifs1.setPixels(Ifs1.pixels);
            ifs1.setSize(ImageWidth, ImageHeight);
            ifs1.setMaxIter(maxIter);
            ifs1.setStartIter(startIter);
            ifs1.setPointShape(pointShape);
            ifs1.setMorphRatio(0.0f);
            ifs1.setFirstIFS(firstIFS);
            ifs1.setSecondIFS(firstIFS);
            ifs1.setObject(this);
            ifs1.setFilter(false);
            ifs1.setPutpixelMode(putpixelMode);
            ifs1.runInSingleThread();
            Ifs1.redraw(false);
            IFS ifs2=new IFS();
            ifs2.setPixels(Ifs2.pixels);
            ifs2.setSize(ImageWidth, ImageHeight);
            ifs2.setMaxIter(maxIter);
            ifs2.setStartIter(startIter);
            ifs2.setPointShape(pointShape);
            ifs2.setMorphRatio(0.0f);
            ifs2.setFirstIFS(secondIFS);
            ifs2.setSecondIFS(secondIFS);
            ifs2.setObject(this);
            ifs2.setFilter(false);
            ifs2.setPutpixelMode(putpixelMode);
            ifs2.runInSingleThread();
            Ifs2.redraw(false);
        }
    }



    /*
    // -----------------------------------------------------------------------
    // Metoda main, ktera neni v appletu vyuzita.
    // Muze se definovat v pripade, ze se ma vytvorit samostatne spustitelna
    // aplikace interpretovana virtualnim strojem jazyja Java, nikoli applet.
    // -----------------------------------------------------------------------
    public static void main(String[] args) {
        Frame frame=new Frame("Morph IFS demo");
        Applet applet=new MorphIFS();
        frame.add(applet);
        applet.init();
        frame.setSize(640, 480);
        frame.setVisible(true);
        frame.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
            }
        );
    }
    */
}
// ----------------------------------------------------------------------------
// Konec tridy MorphIFS.
// ----------------------------------------------------------------------------



// ----------------------------------------------------------------------------
// Trida, ve krere je implementovan algoritmus generovani IFS fraktalu.
// ----------------------------------------------------------------------------
class IFS extends Thread {
    Frame      frame=null;                          // okno pro vypis prubehu prace
    Label      label=null;                          // do tohoto labelu se bude provadet vypis
    int        pixelSrc[];                          // pixmapa pro vykreslovani
    int        width;                               // velikost pixmapy
    int        height;
    int        maxIter;
    int        startIter;
    int        pointShape;                          // typ vykreslovych bodu
    int        firstIFS;
    int        secondIFS;
    int        putpixelMode;
    boolean    bfilter;
    double     morphRatio;                          // pomer mezi prvnim a druhym IFS systemem
    MorphIFS  object;                               // objekt s panely, do kterych se kresli
    static final double data[][]={
        // binary
        { 0.500000, 0.000000, 0.000000, 0.500000,-2.563477,-0.000003, 0.333333},
        { 0.500000, 0.000000, 0.000000, 0.500000, 2.436544,-0.000003, 0.333333},
        { 0.000000,-0.500000, 0.500000, 0.000000, 4.873085, 7.563492, 0.333333},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},

        // coral
        { 0.307692,-0.531469,-0.461538,-0.293706, 5.401953, 8.655175, 0.400000},
        { 0.307692,-0.076923, 0.153846,-0.447552,-1.295248, 4.152990, 0.150000},
        { 0.000000, 0.545455, 0.692308,-0.195804,-4.893637, 7.269794, 0.450000},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},

        // crystal
        { 0.696970,-0.481061,-0.393939,-0.662879, 2.147003,10.310288, 0.747826},
        { 0.090909,-0.443182, 0.515152,-0.094697, 4.286558, 2.925762, 0.252174},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},

        // dragon
        { 0.824074, 0.281482,-0.212346, 0.864198,-1.882290,-0.110607, 0.787473},
        { 0.088272, 0.520988,-0.463889,-0.377778, 0.785360, 8.095795, 0.212527},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},

        // dragon2
        { 0.824074, 0.281481,-0.212346, 0.864197,-1.772710, 0.137795, 0.771268},
        {-0.138580, 0.283951,-0.670062,-0.279012, 2.930991, 7.338924, 0.228732},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},

        // feathe
        { 0.870370, 0.074074,-0.115741, 0.851852,-1.278016, 0.070331, 0.798030},
        {-0.162037,-0.407407, 0.495370, 0.074074, 6.835726, 5.799174, 0.201970},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},

        // fern
        { 0.850000, 0.040000,-0.040000, 0.850000, 0.000000, 1.600000, 0.850000},
        { 0.200000,-0.260000, 0.230000, 0.220000, 0.000000, 1.600000, 0.070000},
        {-0.150000, 0.280000, 0.260000, 0.240000, 0.000000, 0.440000, 0.070000},
        { 0.000000, 0.000000, 0.000000, 0.160000, 0.000000, 0.000000, 0.010000},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},

        // ferny
        {-0.160000,-0.640000, 0.433846,-0.110769, 5.264632, 8.111285, 0.321070},
        { 0.603077, 0.335385,-0.280000, 0.880000,-2.757524,-0.799133, 0.678930},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},

        // flake
        {-0.250000, 0.750000, 0.250000, 0.250000,-3.412025, 5.797619, 0.333333},
        {-0.250000, 0.750000, 0.250000, 0.250000,-6.939442, 2.270202, 0.333333},
        {-0.250000, 0.750000, 0.250000, 0.250000, 0.115392, 2.270202, 0.333333},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},

        // floor
        { 0.000000,-0.500000, 0.500000 ,0.000000,-1.732366, 3.366182, 0.333333},
        { 0.500000, 0.000000, 0.000000 ,0.500000,-0.027891, 5.014877, 0.333333},
        { 0.000000, 0.500000,-0.500000 ,0.000000, 1.620804, 3.310401, 0.333333},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},

        // fossil
        {-0.017641, 0.637128, 0.352000, 0.008000,-2.464790, 8.587118, 0.264315},
        { 0.603077, 0.335385,-0.280000, 0.880000,-1.759852,-0.659994, 0.735685},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},

        // koch
        { 0.307692, 0.000000, 0.000000, 0.294118, 4.119164, 1.604278, 0.151515},
        { 0.192308,-0.205882, 0.653846, 0.088235,-0.688840, 5.978916, 0.253788},
        { 0.192308, 0.205882,-0.653846, 0.088235, 0.668580, 5.962514, 0.253788},
        { 0.307692, 0.000000, 0.000000, 0.294118,-4.136530, 1.604278, 0.151515},
        { 0.384615, 0.000000, 0.000000,-0.294118,-0.007718, 2.941176, 1.000000},

        // leaf
        { 0.242424,-0.640152,-0.909091,-0.318182, 4.613705, 5.570360, 0.698795},
        {-0.090909,-0.556818,-0.484848, 0.155303,-1.103621, 5.655663, 0.301205},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},

        // leaf2
        { 0.424242,-0.651515,-0.484848,-0.344697, 3.449256, 2.891322, 0.622449},
        { 0.030303,-0.439394,-0.636364,-0.022727,-1.396520, 6.437606, 0.377551},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},

        // pincher
        { 0.771144,-0.484577,-0.418906,-0.724378, 2.136904, 7.581400, 0.868575},
        {-0.259304,-0.109453,-0.136119, 0.171144, 5.871343, 0.808450, 0.067604},
        { 0.308657, 0.125373, 0.265075,-0.073632,-5.649287, 8.277147, 0.063821},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},

        // pull
        { 0.227195,-0.466437, 0.688468, 0.647160, 0.187642, 1.466229, 0.572632},
        { 0.450947,-0.456110, 0.325301, 0.445783, 4.939965, 4.050190, 0.427368},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},

        // spiral
        { 0.787879,-0.424242, 0.242424, 0.859848, 1.758647, 1.408065, 0.895652},
        {-0.121212, 0.257576, 0.151515, 0.053030,-6.721654, 1.377236, 0.052174},
        { 0.181818,-0.136364, 0.090909, 0.181818, 6.086107, 1.568035, 0.052174},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},

        // spiral2
        { 0.826500,-0.475000, 0.475000, 0.826500, 0.000000, 0.000000, 0.400000},
        { 0.500000, 0.000000, 0.000000, 0.500000,-1.000000, 0.000000, 0.200000},
        { 0.500000, 0.000000, 0.000000, 0.500000, 1.000000, 0.000000, 0.200000},
        { 0.500000, 0.000000, 0.000000, 0.500000, 0.000000, 1.000000, 0.200000},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},

        // swirl
        { 0.745455,-0.459091, 0.406061, 0.887121, 1.460279, 0.691072, 0.912675},
        {-0.424242,-0.065152,-0.175758,-0.218182, 3.809567, 6.741476, 0.087325},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},

        // square
        { 0.500000, 0.000000, 0.000000, 0.500000,-1.000000, 0.000000, 0.250000},
        { 0.500000, 0.000000, 0.000000, 0.500000, 1.000000, 0.000000, 0.250000},
        { 0.500000, 0.000000, 0.000000, 0.500000, 0.000000,-1.000000, 0.250000},
        { 0.500000, 0.000000, 0.000000, 0.500000, 0.000000, 1.000000, 0.250000},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},

        // telephon
        { 0.824074, 0.281481,-0.212346, 0.864198,-2.274768,-0.147052, 0.876993},
        {-0.072222, 0.422222, 0.246296, 0.059259, 3.631163, 7.337541, 0.123007},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},

        // tree
        { 0.000000, 0.000000, 0.000000, 0.500000, 0.000000, 0.000000, 0.050000},
        { 0.420000,-0.420000, 0.420000, 0.420000, 0.000000, 0.200000, 0.400000},
        { 0.420000, 0.420000,-0.420000, 0.420000, 0.000000, 0.200000, 0.400000},
        { 0.100000, 0.000000, 0.000000, 0.100000, 0.000000, 0.200000, 0.150000},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},

        // tree 2
        { 0.000000, 0.000000, 0.000000, 0.600000, 0.013606,-0.454544, 0.443441},
        { 0.363636, 0.581818,-0.454545, 0.472727,-0.114619, 3.329175, 0.278280},
        {-0.363636,-0.581818,-0.454545, 0.472727, 0.141832, 3.329175, 0.278280},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},

        // tree 3
        { 0.000000, 0.000000, 0.000000, 0.600000,-0.159095, 0.670061, 0.445008},
        { 0.363636, 0.481818,-0.454545, 0.386061,-0.908361, 4.762463, 0.190237},
        {-0.363636,-0.481818,-0.454545, 0.392727, 0.590171, 4.708041, 0.191520},
        {-0.545455, 0.027273, 0.000000,-0.600000,-0.291561, 5.924281, 0.173235},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},

        // triangle
        { 0.500000, 0.000000, 0.000000, 0.500000,-0.500000, 0.000000, 0.333333},
        { 0.500000, 0.000000, 0.000000, 0.500000, 0.500000, 0.000000, 0.333333},
        { 0.500000, 0.000000, 0.000000, 0.500000, 0.000000, 0.860000, 0.333334},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},

        // z
        {-0.548060,-0.181095, 0.257313,-1.015920, 0.818014, 10.578471, 0.844961},
        {-0.135124,-0.432836, 0.147065,-0.348259, 2.110459, 3.261798, 0.155039},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},

        // zigzag
        {-0.632407,-0.614815,-0.545370, 0.659259, 3.840822, 1.282321, 0.888128},
        {-0.036111, 0.444444, 0.210185, 0.037037, 2.071081, 8.330552, 0.111872},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
        { 1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 1.000000},
    };



    // -----------------------------------------------------------------------
    // Konstruktor, ve kterem se nastavi vhodne implicitni hodnoty.
    // -----------------------------------------------------------------------
    public IFS() {
        pixelSrc=null;
        width=height=100;
        maxIter=1000;
        startIter=100;
        pointShape=0;
        bfilter=false;
    }



    // -----------------------------------------------------------------------
    // Nastaveni pixmapy, do ktere se bude provadet vykreslovani
    // -----------------------------------------------------------------------
    public void setPixels(int pixels[]) {
        pixelSrc=pixels;
    }



    // -----------------------------------------------------------------------
    // Nastaveni rozmeru generovane pixmapy.
    // -----------------------------------------------------------------------
    public void setSize(int width, int height) {
        this.width=width;
        this.height=height;
    }



    // -----------------------------------------------------------------------
    // Nastaveni maximalniho poctu bodu v pixmape.
    // -----------------------------------------------------------------------
    public void setMaxIter(int maxIter) {
        this.maxIter=maxIter;
    }



    // -----------------------------------------------------------------------
    // Nastaveni startovniho poctu iteraci.
    // -----------------------------------------------------------------------
    public void setStartIter(int startIter) {
        this.startIter=startIter;
    }



    // -----------------------------------------------------------------------
    // Nastaveni tvaru, ktery se bude ukladat do pracovni bitmapy.
    // -----------------------------------------------------------------------
    public void setPointShape(int pointShape) {
        this.pointShape=pointShape;
    }



    // -----------------------------------------------------------------------
    // Nastaveni urovne morfovani prvniho objektu do objektu druheho.
    // -----------------------------------------------------------------------
    public void setMorphRatio(double morphRatio) {
        this.morphRatio=morphRatio;
    }



    // -----------------------------------------------------------------------
    // Predani reference hlavniho GUI objektu.
    // -----------------------------------------------------------------------
    public void setObject(MorphIFS o) {
        object=o;
    }



    // -----------------------------------------------------------------------
    // Predani cisla prvniho IFS systemu.
    // -----------------------------------------------------------------------
    public void setFirstIFS(int firstIFS) {
        this.firstIFS=firstIFS;
    }



    // -----------------------------------------------------------------------
    // Predani cisla druheho IFS systemu.
    // -----------------------------------------------------------------------
    public void setSecondIFS(int secondIFS) {
        this.secondIFS=secondIFS;
    }



    // -----------------------------------------------------------------------
    // Povoleni ci zakazani filtrace.
    // -----------------------------------------------------------------------
    public void setFilter(boolean bfilter) {
        this.bfilter=bfilter;
    }


    // -----------------------------------------------------------------------
    // Nastaveni zpusobu vykresleni pixelu
    // -----------------------------------------------------------------------
    public void setPutpixelMode(int putpixelMode) {
        this.putpixelMode=putpixelMode;
    }



    // -----------------------------------------------------------------------
    // Vytvoreni a zobrazeni pomocneho okna, ve kterem se zobrazuje prubeh prace.
    // -----------------------------------------------------------------------
    private void prepareGUI() {
        frame=new Frame("Computing IFS");
        label=new Label("Points:");
        frame.add(label);
        label.setAlignment(Label.CENTER);           // vlastnosti napisu
        label.setVisible(true);
        frame.setSize(200, 100);                    // vlastnosti okna
        frame.setVisible(true);
    }



    // -----------------------------------------------------------------------
    // Tato metoda se zavola po dokonceni generovani fraktalu.
    // -----------------------------------------------------------------------
    private void finishGUI() {
        if (bfilter)
            label.setText("Filtering bitmaps");
        object.morphIfs.redraw(false);
        if (bfilter) {
            object.applyFilter();                   // aplikace filtru na bitmapu
            object.filteredIfs.redraw(false);
        }
        frame.setVisible(false);                    // a zruseni pomocneho okna
        frame.dispose();
    }



    // -----------------------------------------------------------------------
    // Vytvoreni a inicializace pixmapy.
    // -----------------------------------------------------------------------
    private void initPixmap() {
        for (int p=0; p<width*height; p++) {
            pixelSrc[p]=0xffffffff;
        }
    }



    // -----------------------------------------------------------------------
    // Vykresleni jednoho pixelu podle nastaveneho rezimu
    // -----------------------------------------------------------------------
    private void putPixel(int x, int y) {
        switch (putpixelMode) {
            case 0:
                pixelSrc[x+y*width]=0xff000000;
                break;
            case 1:
                if (pixelSrc[x+y*width]>0xff040404)
                    pixelSrc[x+y*width]-=0x00040404;
                break;
            case 2:
                if (pixelSrc[x+y*width]>0xff080808)
                    pixelSrc[x+y*width]-=0x00080808;
                break;
            case 3:
                if (pixelSrc[x+y*width]>0xff0c0c0c)
                    pixelSrc[x+y*width]-=0x000c0c0c;
                break;
            case 4:
                if (pixelSrc[x+y*width]>0xff101010)
                    pixelSrc[x+y*width]-=0x00101010;
                break;
            case 5:
                if (pixelSrc[x+y*width]>0xff141414)
                    pixelSrc[x+y*width]-=0x00141414;
                break;
            default:
                break;
        }
    }



    // -----------------------------------------------------------------------
    // Vykresleni jednoho bodu do pixmapy
    // -----------------------------------------------------------------------
    private void putPoint(int x, int y) {
        if (x<4) x=4;
        if (x>=width-3) x=width-4;
        if (y<4) y=4;
        if (y>=height-3) y=height-4;
        y=height-1-y;
        if (pointShape!=PointShape.Diamond3x3 &&
            pointShape!=PointShape.Diamond5x5) {
            putPixel(x, y);                         // prostredni pixel
        }
        if (pointShape==PointShape.Cross3x3 ||
            pointShape==PointShape.Diamond3x3 ||
            pointShape==PointShape.Block3x3 ||
            pointShape==PointShape.Cross5x5 ||
            pointShape==PointShape.Block5x5 ||
            pointShape==PointShape.Horizontal3 ||
            pointShape==PointShape.Horizontal5) {
            putPixel(x-1,y);                        // pixel nalevo
            putPixel(x+1,y);                        // pixel napravo
        }
        if (pointShape==PointShape.Horizontal5 ||
            pointShape==PointShape.Cross5x5 ||
            pointShape==PointShape.Diamond5x5 ||
            pointShape==PointShape.Block5x5) {
            putPixel(x-2,y);                        // druhy pixel nalevo
            putPixel(x+2,y);                        // druhy pixel napravo
        }
        if (pointShape==PointShape.Cross3x3 ||
            pointShape==PointShape.Diamond3x3 ||
            pointShape==PointShape.Block3x3 ||
            pointShape==PointShape.Cross5x5 ||
            pointShape==PointShape.Block5x5 ||
            pointShape==PointShape.Vertical3 ||
            pointShape==PointShape.Vertical5) {
            putPixel(x, y-1);                       // pixel nahore
            putPixel(x, y+1);                       // pixel dole
        }
        if (pointShape==PointShape.Vertical5 ||
            pointShape==PointShape.Cross5x5 ||
            pointShape==PointShape.Diamond5x5 ||
            pointShape==PointShape.Block5x5) {
            putPixel(x, y-2);                       // druhy pixel nahore
            putPixel(x, y+2);                       // druhy pixel dole
        }
        if (pointShape==PointShape.XCross3x3 ||
            pointShape==PointShape.Block3x3 ||
            pointShape==PointShape.XCross5x5 ||
            pointShape==PointShape.Diamond5x5 ||
            pointShape==PointShape.Block5x5) {
            putPixel(x-1, y-1);                     // diagonalni pixely
            putPixel(x-1, y+1);
            putPixel(x+1, y-1);
            putPixel(x+1, y+1);
        }
        if (pointShape==PointShape.XCross5x5 ||
            pointShape==PointShape.Block5x5) {
            putPixel(x-2, y-2);
            putPixel(x-2, y+2);
            putPixel(x+2, y-2);
            putPixel(x+2, y+2);
        }
        if (pointShape==PointShape.Block5x5) {
            putPixel(x-1, y-2);
            putPixel(x-1, y+2);
            putPixel(x+1, y-2);
            putPixel(x+1, y+2);
            putPixel(x-2, y-1);
            putPixel(x-2, y+1);
            putPixel(x+2, y-1);
            putPixel(x+2, y+1);
        }
    }



    // -----------------------------------------------------------------------
    // Vlastni aplikace algoritmu IFS
    // -----------------------------------------------------------------------
    private void generateIFS(double data1[][],      // predavana data prvniho IFS systemu
                             double data2[][],      // predavana data druheho IFS systemu
                             int maxIter,           // maximalni pocet iteraci
                             int startIter,         // pocet startovnich iteraci
                             int width,             // horizontalni rozliseni obrazku
                             int height) {          // vertikalni rozliseni obrazku
        double x1=0, y1=0, x2=0, y2=0;              // generovane souradnice
        double xmin=1e10, xmax=-1e10;               // obdelnik opsany IFS fraktalu
        double ymin=1e10, ymax=-1e10;
        int    x, y, k;
        double pp, sum;
        double delitel=1.0;

        Random r=new Random(0);                     // generator nahodnych cisel
        double a[][]=new double [5][7];             // matice s koeficienty IFS systemu

        for (int j=0; j<5; j++) {                   // prenos koeficientu IFS systemu
            for (int i=0; i<7; i++) {               // a smichani prvniho a druheho systemu
                a[j][i]=(1.0-morphRatio)*data1[j+firstIFS*5][i]
                       +(morphRatio)*data2[j+secondIFS*5][i];
            }
        }
        for (int i=0; i<maxIter; i++) {             // pro vsechny iterace
            int counter=0;
            pp=r.nextDouble();
            sum=0;                                  // na zaklade nahodneho cisla
            for (k=0; sum<=pp; k++)                 // najit transformaci
                sum+=a[k][6];
            k--;
            x2=x1*a[k][0] + y1*a[k][1] + a[k][4];   // aplikovat transformaci
            y2=x1*a[k][2] + y1*a[k][3] + a[k][5];
            x1=x2; y1=y2;
            if (i>startIter) {                      // pokud byl prekrocen pocet
                x2=(x1-xmin)*(double)width/delitel; // startovnich iteraci
                y2=(y1-ymin)*(double)height/delitel;
                x=(int)x2; y=(int)y2;               // vypocitat a zobrazit pozice pixelu
                putPoint(x, y);
            }
            else {                                  // pokud se jedna o startovni iterace
                if (x1<xmin) xmin=x1;               // provest vypocet opsaneho obdelnika
                if (y1<ymin) ymin=y1;
                if (x1>xmax) xmax=x1;
                if (y1>ymax) ymax=y1;
            }
            if (i==startIter) {                     // zafixovat opsany obdelnik
                xmin*=1.1;
                xmax*=1.1;
                ymin*=1.1;
                ymax*=1.1;
                delitel=(xmax-xmin);
                if (ymax-ymin>xmax-xmin) delitel=ymax-ymin;
            }
            counter++;
            /*
            if (counter==100) {                     // prubezne vypisovat prubeh operaci
                label.setText("Points: "+String.valueOf(i)); // na rychlych pocitacich neni zapotrebi
                counter=0;
            }
            */
        }
    }



    // -----------------------------------------------------------------------
    // Funkce, ktera rozbehne cele vypocetni vlakno.
    // -----------------------------------------------------------------------
    public void run() {
        prepareGUI();                               // vytvoreni vsech GUI prvku
        label.setText("Initializing");
        initPixmap();                               // inicializace pixmapy
        generateIFS(data, data, maxIter, startIter, width, height); // vlastni vygenerovani IFS fraktalu
        label.setText("Finishing");
        finishGUI();                                // fitrace a zavreni pomocneho okna
    }



    // -----------------------------------------------------------------------
    // Vypocet IFS v jednom vypocetnim vlaknu.
    // -----------------------------------------------------------------------
    public void runInSingleThread() {
        initPixmap();                               // inicializace pixmapy
        generateIFS(data, data, maxIter, startIter, width, height); // vlastni vygenerovani IFS fraktalu
    }
}
// ----------------------------------------------------------------------------
// Konec tridy IFS.
// ----------------------------------------------------------------------------



// ----------------------------------------------------------------------------
// finito
// ----------------------------------------------------------------------------