// ----------------------------------------------------------------------------
// Demonstracni priklad k serialu "Fraktaly v pocitacove grafice"
// ----------------------------------------------------------------------------
// application: Linear IFS (L-IFS) demo
// author:      Pavel Tisnovsky
// file name:   LinearIFS.java
// directory:   java
// date:        28.06.2006
// description: Demonstracni aplikace pro vytvoreni, editaci a zobrazeni
//              fraktalu zalozenych na linearizovanych systemech IFS (L-IFS).
//              Podrobnejsi popis teto demonstracni aplikace je popsan primo
//              v clanku.
// ----------------------------------------------------------------------------



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



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



// ----------------------------------------------------------------------------
// Vsechny metody tohoto appletu jsou napsany pouze v jedine tride tak, aby se
// vygeneroval pouze jeden soubor .class, coz ulehci a zrychli praci interneto-
// veho prohlizece, protoze se nebude zbytecne otevirat vice sitovych spojeni.
// 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 LinearIFS extends Applet implements Runnable, ActionListener, ItemListener, AdjustmentListener {
    static final int ImageWidth=384;                // sirka bitmapy s fraktalem
    static final int ImageHeight=384;               // vyska bitmapy s fraktalem
    static final int DrawingWidth=ImageWidth;       // sirka kresby pouzivane pro konstrukci fraktalu
    static final int DrawingHeight=ImageHeight+150; // vyska kresby pouzivane pro konstrukci fraktalu
    static final int TextBegin=ImageWidth+10;       // horizontalni zacatek informacniho textu
    static final int TextHeight=120;                // vyska informacniho textu

    static final int ShowHelp=1;                    // priznak, ze se ma na plochu appletu vypisovat napoveda
    static final int ShowInfo=2;                    // priznak, ze se maji na plochu appletu vypisovat informace o pameti
    static final int ShowAbout=3;                   // priznak, ze se maji na plochu appletu vypisovat informace o aplikaci

    static final int QuickFractalIterations=1000;   // pocet iteraci pri rychlem prekreslovani fraktalu
    static final int QuickFractalStartIterations=10;// pocet startovnich iteraci pri rychlem prekreslovani fraktalu

    // pole specifikujici maximalni pocet iteraci pro vsechny zabudovane modely
    static final int    MaxIterations[]=  { 50000, 50000, 50000, 50000, 50000, 50000, 50000, 50000,
                                            50000, 50000, 50000, 50000, 50000, 50000, 50000, 50000};

    // pole specifikujici pocet startovnich iteraci pro vsechny zabudovane modely
    static final int    StartIterations[]={   100,   203,   100,   100,    94,   100,   100,   100,
                                              100,   100,   100,   100,    76,   94,    100,     1};

    // pole specifikujici pocet pouzitych vertexu pro vsechny zabudovane modely
    static final int    MaxVertexes[]=    {     3,     4,     5,     6,     7,     8,     5,     6,
                                                7,     7,     8,     8,     8,     7,     8,     6};

    // pole specifikujici index filtru pro vsechny zabudovane modely
    static final int    Filters[]=        {     5,     5,     5,     5,     1,     5,     5,     5,
                                                5,     5,     5,     5,     1,     1,     0,     0};

    // pole specifikujici rozdeleni usecky ve smeru x-ove osy pro vsechny zabudovane modely
    static final double XFractions[]=     { 0.500, 0.594, 0.600, 0.650, 0.629, 0.662, 0.600, 0.600,
                                            0.630, 0.630, 0.667, 0.587, 0.587, 0.626, 0.500, 0.015};

    // pole specifikujici rozdeleni usecky ve smeru y-ove osy pro vsechny zabudovane modely
    static final double YFractions[]=     { 0.500, 0.583, 0.600, 0.650, 0.640, 0.666, 0.600, 0.600,
                                            0.640, 0.640, 0.669, 0.583, 0.583, 0.623, 0.500, 0.019};

    // pole pozice vertexu pro vsechny zabudovane modely
    static final int    Vertexes[][]=   {
        {194, 107,  74, 314, 314, 314, 314, 314, 127, 127, 255, 127, 127, 255, 255, 255},// sierpinsky triangle
        {194, 107,  74, 314, 314, 314, 194, 238, 127, 127, 255, 127, 127, 255, 255, 255},// snowflake 4 vertices
        {192, 312, 306, 229, 262,  95, 122,  95,  78, 229, 255, 127, 127, 255, 255, 255},// snowflake 5 vertices
        {132, 295, 252, 295, 312, 192, 252,  88, 132,  88,  72, 192, 127, 255, 255, 255},// snowflake 6 vertices
        {132, 295, 252, 295, 312, 192, 252,  88, 132,  88,  72, 192, 191, 191, 255, 255},// snowflake 7 vertices
        {311, 191, 275, 275, 191, 311, 107, 275,  71, 191, 107, 107, 191,  71, 275, 107},// snowflake 8 vertices
        {192, 312, 306, 229, 262,  95, 122,  95,  78, 229, 255, 127, 127, 255, 255, 255},// star 5 vertices
        {132, 295, 252, 295, 312, 192, 252,  88, 132,  88,  72, 192, 127, 255, 255, 255},// star 6 vertices
        {132, 295, 252, 295, 312, 192, 252,  88, 132,  88,  72, 192, 191, 191, 255, 255},// star 7 vertices version A
        {132, 295, 252, 295, 312, 192, 252,  88, 132,  88,  72, 192, 191, 191, 255, 255},// star 7 vertices version B
        {311, 191, 275, 275, 191, 311, 107, 275,  71, 191, 107, 107, 191,  71, 275, 107},// star 8 vertices
        { 69,  69, 314,  69,  69, 314, 314, 314, 129, 123, 257, 123, 129, 251, 257, 251},// rectangle version 1
        { 69,  69, 314,  69,  69, 314, 314, 314, 104, 105, 163, 106, 103, 164, 171, 163},// rectangle version 2
        { 75, 305, 185, 283, 303, 193, 303,  79, 190,  79,  96, 194, 100, 282, 255, 255},// rocket
        { 69,  69, 314,  69,  69, 314, 314, 314, 127, 127, 255, 127, 127, 255, 255, 255},// base
        {132, 295, 252, 295, 312, 192, 252,  88, 132,  88,  72, 192, 127, 255, 255, 255},// bomb
    };

    // pole matice posloupnosti transformaci pro vsechny zabudovane modely
    static final int Restrictions[][]={
        {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
        {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
        {0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
        {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
        {1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1},
        {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
        {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
        {0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
        {0,1,1,0,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,1,1,0,1,1,0,1,1,0,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
        {0,1,1,0,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,1,1,0,1,1,0,1,1,0,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1},
        {0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0},
        {1,1,1,0,1,1,1,0,1,1,0,1,1,1,0,1,1,0,1,1,1,0,1,1,0,1,1,1,0,1,1,1,1,1,1,0,1,1,1,0,1,1,0,1,1,1,0,1,1,0,1,1,1,0,1,1,0,1,1,1,0,1,1,1},
        {1,1,1,0,1,1,1,0,1,1,0,1,1,1,0,1,1,0,1,1,1,0,1,1,0,1,1,1,0,1,1,1,1,1,1,0,0,0,0,0,1,1,0,1,0,0,0,0,1,0,1,1,0,0,0,0,0,1,1,1,0,0,0,0},
        {1,1,0,0,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1},
        {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
        {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
    };

    int              iterations=5000;               // pocet vsech iteraci
    int              startIterations=500;           // pocet startovnich iteraci
    int              filterType=3;                  // typ pouziteho filtru
    double           xFraction=0.5;                 // deleni usecky ve smeru x-ove osy
    double           yFraction=0.5;                 // deleni usecky ve smeru y-ove osy
    int              activeVertexes=3;              // pocet aktivnich vrcholu
    int              selectedVertex=8;              // cislo vybraneho vrcholu
    int[]            vertexX=new int[8];            // pole x-ovych souradnic vrcholu
    int[]            vertexY=new int[8];            // pole y-ovych souradnic vrcholu
    boolean[][]      restrictions=new boolean[8][8];// pole s prvky matice posloupnosti transformaci
    int              drawingMode=ShowAbout;         // druh vykreslovanych informaci
    boolean          fractalNeedsRedraw=true;       // priznak, zda se ma prekreslit cely fraktal
    static int       putpixelMode=0;                // vykreslovaci rezim

    // vytvoreni vsech panelu pouzitych v appletu
    Panel       panelUp=             new Panel(new GridLayout(2, 4, 5, 5));// horni panel s list-boxy
    Panel       panelDown=           new Panel(new GridLayout(2, 4, 5, 5));// dolni panel se slidery
    Panel       panelRight=          new Panel(new GridLayout(8, 1));// pravy panel s tlacitky
    Panel       panelCenter=         new Panel();   // centralni panel s vykreslovanym fraktalem
    Canvas      drawing=             new Canvas();  // vykreslovaci platno pro konstrukci fraktalu

    // vytvoreni vsech textovych navesti pouzitych v appletu
    Label       labelModel=          new Label("Model");
    Label       labelVertexes=       new Label("Vertex count");
    Label       labelFilter=         new Label("Filter");
    Label       labelPutpixelMode=   new Label("Putpixel mode");
    Label       labelIterations=     new Label("Iterations: "+String.valueOf(iterations));
    Label       labelStartIterations=new Label("Start iterations: "+String.valueOf(startIterations));
    Label       labelXFraction=      new Label("X-fraction: "+String.valueOf(xFraction));
    Label       labelYFraction=      new Label("Y-fraction: "+String.valueOf(yFraction));

    // vytvoreni vsech list-boxu pouzitych v appletu
    Choice      choiceModel=         new Choice();  // list-box pro vyber modelu
    Choice      choiceVertexes=      new Choice();  // list-box pro vyber poctu aktivnich vertexu
    Choice      choiceFilter=        new Choice();  // list-box pro vyber aktivniho filtru
    Choice      choicePutpixelMode=  new Choice();  // list-box pro vyber vykreslovaciho rezimu

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

    // vytvoreni vsech slideru pouzitych v appletu
    Scrollbar   scrollBarIterations=     new Scrollbar(Scrollbar.HORIZONTAL, iterations, 1000, 100, 100000+1000);
    Scrollbar   scrollBarStartIterations=new Scrollbar(Scrollbar.HORIZONTAL, startIterations, 500, 100, 5000+500);
    Scrollbar   scrollBarXFraction=      new Scrollbar(Scrollbar.HORIZONTAL, (int)(1000.0*xFraction), 100, 0, 1000+100);
    Scrollbar   scrollBarYFraction=      new Scrollbar(Scrollbar.HORIZONTAL, (int)(1000.0*yFraction), 100, 0, 1000+100);

    MemoryImageSource imageSource;                  // zdroj pixelu pro bitmapu
    Image       image;                              // vlastni vykreslovana bitmapa
    int[]       pixelSrc=       new int[ImageWidth*ImageHeight]; // vytvoreni bitmap pro praci
    int[]       pixelDest=      new int[ImageWidth*ImageHeight]; // s fraktalem a filtraci



    // ------------------------------------------------------------------------
    // 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(labelModel);                    // pridani vsech textovych navesti
        panelUp.add(labelVertexes);                 // do horniho panelu
        panelUp.add(labelFilter);
        panelUp.add(labelPutpixelMode);
        panelUp.add(choiceModel);                   // pridani vsech list-boxu
        panelUp.add(choiceVertexes);
        panelUp.add(choiceFilter);
        panelUp.add(choicePutpixelMode);

        // prace s list-boxem Model
        choiceModel.setEnabled(true);               // povoleni list-boxu
        choiceModel.add("Sierpinsky triangle");     // a naplneni list-boxu textem
        choiceModel.add("Snowflake 3 vertexes");
        choiceModel.add("Snowflake 5 vertexes");
        choiceModel.add("Snowflake 6 vertexes");
        choiceModel.add("Snowflake 7 vertexes");
        choiceModel.add("Snowflake 8 vertexes");
        choiceModel.add("Star 5 vertexes");
        choiceModel.add("Star 6 vertexes");
        choiceModel.add("Star 7 vertexes A");
        choiceModel.add("Star 7 vertexes B");
        choiceModel.add("Star 8 vertexes");
        choiceModel.add("Rectangle A");
        choiceModel.add("Rectangle B");
        choiceModel.add("Rocket");
        choiceModel.add("Base");
        choiceModel.add("Bomb");
        choiceModel.select(1);                      // vyber aktivni polozky z list-boxu
        choiceModel.addItemListener(this);          // nastaveni zpracovani udalosti od list-boxu

        // prace s list-boxem Vertexes
        choiceVertexes.setEnabled(true);            // naplneni list-boxu texty a povoleni list-boxu
        choiceVertexes.add("three");
        choiceVertexes.add("four");
        choiceVertexes.add("five");
        choiceVertexes.add("six");
        choiceVertexes.add("seven");
        choiceVertexes.add("eight");
        choiceVertexes.select(3);                   // vyber aktivni polozky z list-boxu
        choiceVertexes.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 putpixel mode
        choicePutpixelMode.setEnabled(true);
        choicePutpixelMode.add("draw white 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(labelIterations);             // pridani vsech textovych navesti
        panelDown.add(labelStartIterations);
        panelDown.add(labelXFraction);
        panelDown.add(labelYFraction);
        panelDown.add(scrollBarIterations);         // pridani vsech slideru
        panelDown.add(scrollBarStartIterations);
        panelDown.add(scrollBarXFraction);
        panelDown.add(scrollBarYFraction);
        scrollBarIterations.addAdjustmentListener(this);// nastaveni reakci na udalosti slideru
        scrollBarStartIterations.addAdjustmentListener(this);
        scrollBarXFraction.addAdjustmentListener(this);
        scrollBarYFraction.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(buttonRedraw);               // pridani vsech textovych tlacitek
        panelRight.add(buttonAbout);
        panelRight.add(buttonInfo);
        panelRight.add(buttonHelp);
        buttonRedraw.addActionListener(this);       // nastaveni reakce na udalosti od tlacitek
        buttonAbout.addActionListener(this);
        buttonInfo.addActionListener(this);
        buttonHelp.addActionListener(this);
    }



    // ------------------------------------------------------------------------
    // Tato metoda provede nastaveni centralniho panelu s vyslednym fraktalem.
    // Metoda je zavolana behem inicializace aplikace ci appletu.
    // ------------------------------------------------------------------------
    private void initPanelCenter() {
        panelCenter.setBackground(Color.white);     // nastaveni barvy pozadi
        for (int j=0; j<ImageHeight; j++)           // pro vsechny radky bitmapy
            for (int i=0; i<ImageWidth; i++)        // pro vsechny sloupce bitmapy
                pixelDest[i+(j<<8)]=i+(j<<8)+((i-j)<<16)+(255<<24);// vyplnit bitmapu i s alfa kanalem
        imageSource=new MemoryImageSource(ImageWidth, ImageHeight, pixelDest, 0, ImageHeight);
        image=createImage(imageSource);             // vytvoreni bitmapy
    }



    // ------------------------------------------------------------------------
    // Tato metoda provede inicializaci leveho pole pro zobrazeni konstrukce
    // L-IFS systemu.
    // ------------------------------------------------------------------------
    private void initDrawing() {
        drawing.setSize(DrawingWidth+10, DrawingHeight+10);// nastveni velikosti pole
        drawing.setBackground(Color.white);         // nastaveni barvy pozadi
    }



    // ------------------------------------------------------------------------
    // 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
        initPanelCenter();                          // nastavit centralni panel
        initDrawing();                              // nastavit levou kreslici plochu
        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("Center", panelCenter);                 // pridat centralni panel do plochy aplikace
        add("West",   drawing);                     // pridat levou kreslici plochu do plochy aplikace
        initModel(1);                               // inicializace prvniho modelu
    }



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



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



    // ------------------------------------------------------------------------
    // 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) {
        redrawFractal();                            // prekreslit fraktal
        redrawDrawing();                            // prekreslit kresbu (navrh L-IFS systemu)
        switch (drawingMode) {                      // vyber informace, ktera se ma vypsat
            case ShowHelp:
                redrawHelp();
                break;                              // zobrazeni napovedy
            case ShowInfo:
                redrawInfo();
                break;                              // zobrazeni stavovych informaci
            case ShowAbout:
                redrawAbout();
                break;                              // zobrazeni informaci o aplikaci
            default:
                break;
        }
    }



    // ------------------------------------------------------------------------
    // 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
            repaint();                              // prekreslit cely applet
        }
        if (o==buttonAbout) {                       // text s informacemi o autorech
            drawingMode=ShowAbout;                  // nastavit rezim prekreslovani textu
            repaint();                              // prekreslit cely applet
        }
        if (o==buttonHelp) {                        // text s napovedou
            drawingMode=ShowHelp;                   // nastavit rezim prekreslovani textu
            repaint();                              // prekreslit cely applet
        }
        if (o==buttonInfo) {                        // text s informacemi o aplikaci
            drawingMode=ShowInfo;                   // nastavit rezim prekreslovani textu
            repaint();                              // prekreslit cely applet
        }
    }



    // ------------------------------------------------------------------------
    // 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==choiceModel) {                       // uzivatel zmenil aktivni model
            initModel(choiceModel.getSelectedIndex());// inicializace modelu
            repaint();                              // prekresleni celeho appletu
        }
        if (o==choiceFilter) {                      // uzivatel zmenil filtr aplikovany na obrazek
            filterType=choiceFilter.getSelectedIndex();// ziskat index vybraneho filtru
            recalcFractal();                        // prepocet fraktalu
            repaint();                              // prekresleni celeho appletu
        }
        if (o==choiceVertexes) {                    // uzivatel zmenil pocet aktivnich vertexu
            int i=choiceVertexes.getSelectedIndex();// ziskat pocet vertexu
            activeVertexes=i+3;
            recalcFractal();                        // prepocet fraktalu
            repaint();                              // prekresleni celeho appletu
        }
        if (o==choicePutpixelMode) {
            putpixelMode=choicePutpixelMode.getSelectedIndex();
            recalcFractal();
            repaint();
        }
    }



    // ------------------------------------------------------------------------
    // 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==scrollBarIterations) {               // zmena poctu iteraci
            iterations=scrollBarIterations.getValue();// ziskat pocet iteraci
            labelIterations.setText("Iterations: "+String.valueOf(iterations));
        }
        if (o==scrollBarStartIterations) {          // zmena poctu startovnich iteraci
            startIterations=scrollBarStartIterations.getValue();// ziskat pocet startovnich iteraci
            labelStartIterations.setText("Start iterations: "+String.valueOf(startIterations));
        }
        if (o==scrollBarXFraction) {                // zmena deleni usecky ve smeru x-ove osy
            int i=scrollBarXFraction.getValue();    // ziskat hodnotu deleni
            xFraction=(double)i/1000.0;
            labelXFraction.setText("X-fraction "+String.valueOf(xFraction));
        }
        if (o==scrollBarYFraction) {                // zmena deleni usecky ve smeru y-ove osy
            int i=scrollBarYFraction.getValue();    // ziskat hodnotu deleni
            yFraction=(double)i/1000.0;
            labelYFraction.setText("Y-fraction "+String.valueOf(yFraction));
        }
        recalcFractal();                            // prepocet celeho fraktalu
        repaint();                                  // a prekresleni appletu
    }



    // ------------------------------------------------------------------------
    // Metoda pro zpracovani udalosti generovanych praci uzivatele.
    // Tato metoda je volana z virtualniho stroje jazyka Java (JVM).
    // ------------------------------------------------------------------------
    public boolean handleEvent(Event e) {
        boolean result;
        switch (e.id) {                             // zjistit identifikator udalosti
            case Event.MOUSE_DOWN:                  // udalost vznikla stlacenim tlacitka mysi
                if (e.metaDown())                   // jedna se o prave tlacitko mysi
                    onMouseRightButtonDown(e.x, e.y);// zavolat prislusnou callback metodu
                else                                // jedna se o leve tlacitko mysi
                    onMouseLeftButtonDown(e.x, e.y);// zavolat prislusnou callback metodu
                result=true;
                break;
            case Event.MOUSE_UP:                    // udalost vznikla pustenim tlacitka mysi
                if (e.metaDown())                   // jedna se o prave tlacitko mysi
                    onMouseRightButtonUp(e.x, e.y); // zavolat prislusnou callback metodu
                else                                // jedna se o leve tlacitko mysi
                    onMouseLeftButtonUp(e.x, e.y);  // zavolat prislusnou callback metodu
                result=true;
                break;
            case Event.MOUSE_MOVE:                  // udalost vznikla pohybem mysi bez stlaceneho tlacitka
                onMouseMove(e.x, e.y);              // zavolat prislusnou callback metodu
                result=true;
                break;
            case Event.MOUSE_DRAG:                  // udalost vznikla pohybem mysi se stlacenym tlacitkem
                if (e.metaDown())                   // jedna se o prave tlacitko mysi
                    onMouseRightDrag(e.x, e.y);     // zavolat prislusnou callback metodu
                else                                // jedna se o leve tlacitko mysi
                    onMouseLeftDrag(e.x, e.y);      // zavolat prislusnou callback metodu
                result=true;
                break;
            default:                                // dalsi udalosti, ktere se neosetruji
                result=false;                       // se mohou poslat dale do systemu
                break;
        }
        return result;
    }



    // ------------------------------------------------------------------------
    // Tato callback metoda se zavola v pripade, ze uzivatel pustil leve
    // tlacitko mysi.
    // Metoda je volana po zpracovani udalosti v metode handleEvent().
    // ------------------------------------------------------------------------
    private void onMouseLeftButtonUp(int x, int y) {
        if (fractalNeedsRedraw) {                   // pokud je zapotrebi prekreslit fraktal
            fractalNeedsRedraw=false;
            recalcFractal();                        // prepocet fraktalu
            repaint();                              // a prekresleni celeho appletu
        }
    }



    // ------------------------------------------------------------------------
    // Tato callback metoda se zavola v pripade, ze uzivatel stlacil leve
    // tlacitko mysi.
    // Metoda je volana po zpracovani udalosti v metode handleEvent().
    // ------------------------------------------------------------------------
    private void onMouseLeftButtonDown(int x, int y) {
        Point p=new Point(drawing.getLocation());   // ziskat souradnice kresby
        x-=p.x;                                     // posun souradnic kurzoru mysi do souradnic
        y-=p.y;                                     // kresby
        if (x>=150 && x<=150+8*12 && y>=265+ImageHeight-256 && y<=265+8*12+ImageHeight-256) {
            x=x-150; x/=12; if (x>7) x=7;           // kurzor je v tabulce posloupnosti transformaci
            y=y-265-ImageHeight+256; y/=12; if (y>7) y=7;
            restrictions[x][y]=!restrictions[x][y]; // zmena tabulky transformaci
            recalcFractal();                        // prepocet fraktalu
            repaint();                              // a prekresleni celeho appletu
        }
        int min=100000;                             // minimalni vzdalenost kurzoru
        int minVertex=0;                            // mysi od vertexu a cislo vertexu
        int i;
        if (x>=0 && x<=ImageWidth-1 && y>=0 && y<=ImageHeight-1) { // kurzor je v kresbe
            for (i=0; i<activeVertexes; i++) {      // projit vsechny vertexy
                int xv=vertexX[i];                  // souradnice vertexu
                int yv=vertexY[i];
                int length=Math.abs(x-xv)+Math.abs(y-yv);// vzdalenost kurzoru mysi od vertexu
                if (length<min) {                   // jsme bliz nez pri predchozich vertexech
                    min=length;
                    minVertex=i;
                }
            }
            if (min>40) selectedVertex=-1;          // pokud je kurzor prilis daleko od vsech vertexu
            else        selectedVertex=minVertex;
            recalcFractal();                        // prepocet fraktalu
            repaint();                              // a prekresleni celeho appletu
        }
    }



    // ------------------------------------------------------------------------
    // Tato callback metoda se zavola v pripade, ze uzivatel pustil prave
    // tlacitko mysi.
    // Metoda je volana po zpracovani udalosti v metode handleEvent().
    // ------------------------------------------------------------------------
    private void onMouseRightButtonUp(int x, int y) {
        return;                                     // v soucasnosti neprovadime zadnou cinnost
    }



    // ------------------------------------------------------------------------
    // Tato callback metoda se zavola v pripade, ze uzivatel stlacil prave
    // tlacitko mysi.
    // Metoda je volana po zpracovani udalosti v metode handleEvent().
    // ------------------------------------------------------------------------
    private void onMouseRightButtonDown(int x, int y) {
        return;                                     // v soucasnosti neprovadime zadnou cinnost
    }



    // ------------------------------------------------------------------------
    // Tato callback metoda se zavola v pripade, ze uzivatel pohnul s kurzorem
    // mysi.
    // Metoda je volana po zpracovani udalosti v metode handleEvent().
    // ------------------------------------------------------------------------
    private void onMouseMove(int x, int y) {
        return;                                     // v soucasnosti neprovadime zadnou cinnost
    }



    // ------------------------------------------------------------------------
    // Tato callback metoda se zavola v pripade, ze uzivatel pohnul kurzorem
    // mysi se stlacenym levym tlacitkem.
    // Metoda je volana po zpracovani udalosti v metode handleEvent().
    // ------------------------------------------------------------------------
    private void onMouseLeftDrag(int x, int y) {
        if (selectedVertex==-1) return;             // pokud neni vybrany zadny vertex
        if (selectedVertex>activeVertexes) return;  // pokud je vybrany vertex mimo aktivni vertexy
        Point p=new Point(drawing.getLocation());
        x-=p.x;                                     // posun souradnic kurzoru mysi do souradnic
        y-=p.y;                                     // obrazku
        if (x>=0 && x<=ImageWidth-1 && y>=0 && y<=ImageHeight-1) { // kurzor je v kresbe
            vertexX[selectedVertex]=x;              // posun vybraneho bodu
            vertexY[selectedVertex]=y;
            fractalNeedsRedraw=true;                // nastaveni priznaku, ze je potreba vykreslit cely fraktal
            recalcFractalQuick();                   // rychly prepocet fraktalu
            repaint();                              // a prekresleni celeho appletu
        }

    }



    // ------------------------------------------------------------------------
    // Tato callback metoda se zavola v pripade, ze uzivatel pohnul kurzorem
    // mysi se stlacenym pravym tlacitkem.
    // Metoda je volana po zpracovani udalosti v metode handleEvent().
    // ------------------------------------------------------------------------
    private void onMouseRightDrag(int x, int y) {
        return;                                     // v soucasnosti neprovadime zadnou cinnost
    }



    // ------------------------------------------------------------------------
    // Tato metoda provadi inicializaci nastaveneho modelu fraktalu.
    // ------------------------------------------------------------------------
    private void initModel(int model) {
        xFraction=XFractions[model];                // ziskat pomer deleni usecek ve
        yFraction=YFractions[model];                // smeru obou os
        iterations=MaxIterations[model];            // ziskat maximalni pocet iteraci
        startIterations=StartIterations[model];     // ziskat pocet startovnich iteraci
        activeVertexes=MaxVertexes[model];          // ziskat index aktivniho vertexu
        filterType=Filters[model];                  // ziskat index vybraneho filtru
        for (int i=0; i<8; i++) {                   // smycka pres vsechny vertexy
            vertexX[i]=Vertexes[model][i*2];        // kopie hodnot
            vertexY[i]=Vertexes[model][i*2+1];
        }
        for (int j=0; j<8; j++) {                   // kopie hodnot prvnu z matice
            for (int i=0; i<8; i++) {               // posloupnosti transformaci
                restrictions[j][i]=Restrictions[model][i+(j<<3)]!=0;
            }
        }
        choiceVertexes.select(activeVertexes-3);    // nastaveni list-boxu
        choiceFilter.select(filterType);
        scrollBarIterations.setValue(iterations);   // nastaveni slideru
        scrollBarStartIterations.setValue(startIterations);
        scrollBarXFraction.setValue((int)(xFraction*1000.0));
        scrollBarYFraction.setValue((int)(yFraction*1000.0));
        labelIterations.setText("Iterations: "+String.valueOf(iterations));// nastaveni textovych navesti
        labelStartIterations.setText("Start iterations: "+String.valueOf(startIterations));
        labelXFraction.setText("X-fraction "+String.valueOf(xFraction));
        labelYFraction.setText("Y-fraction "+String.valueOf(yFraction));
        recalcFractal();                            // prepocet fraktalu
    }



    // ------------------------------------------------------------------------
    // Tato metoda provadi prekresleni informaci o systemu.
    // Metoda je volana z metody paint() pokud je drawingMode==ShowInfo.
    // ------------------------------------------------------------------------
    private void redrawInfo() {
        drawingMode=ShowInfo;                       // nastavit rezim prekreslovani
        Graphics g=panelCenter.getGraphics();       // ziskat graficky kontext
        Runtime r=Runtime.getRuntime();             // ziskat objekt s informacemi o aplikaci
        g.setColor(Color.white);
        g.fillRect(0, TextBegin, DrawingWidth, TextHeight);
        g.setColor(Color.blue);
        g.drawString("Info", 10, TextBegin+20);
        g.setColor(Color.black);                    // vypsani informaci o pameti
        g.drawString("Total memory: "+r.totalMemory(), 10, TextBegin+40);
        g.drawString("Free memory: "+r.freeMemory(), 10, TextBegin+60);
    }



    // ------------------------------------------------------------------------
    // Tato metoda provadi prekresleni napovedy.
    // Metoda je volana z metody paint() pokud je drawingMode==ShowHelp.
    // ------------------------------------------------------------------------
    private void redrawHelp() {
        drawingMode=ShowHelp;                       // nastavit rezim prekreslovani
        Graphics g=panelCenter.getGraphics();       // ziskat graficky kontext
        g.setColor(Color.white);
        g.fillRect(0, TextBegin, DrawingWidth, TextHeight);
        g.setColor(Color.blue);
        g.drawString("Help", 10, TextBegin+20);
        g.setColor(Color.black);                    // vykresleni kratke napovedy
        g.drawString("1. select from model list box", 10, TextBegin+40);
        g.drawString("2. change vertex position", 10, TextBegin+60);
        g.drawString("3. change restriction matrix", 10, TextBegin+80);
        g.drawString("4. change global fractal parameters", 10, TextBegin+100);
    }



    // ------------------------------------------------------------------------
    // Tato metoda provadi prekresleni informaci o aplikaci.
    // Metoda je volana z metody paint() pokud je drawingMode==ShowAbout.
    // ------------------------------------------------------------------------
    private void redrawAbout() {
        drawingMode=ShowAbout;                      // zmenit rezim prekreslovani
        Graphics g=panelCenter.getGraphics();       // ziskat graficky kontext
        g.setColor(Color.white);
        g.fillRect(0, TextBegin, DrawingWidth, TextHeight);
        g.setColor(Color.blue);
        g.drawString("About", 10, TextBegin+20);
        g.setColor(Color.red);
        g.drawString("LinearIFS   version 2.0 Java", 10, TextBegin+40);
        g.setColor(Color.black);                    // vypsani retezcu s informacemi o aplikaci
        g.drawString("Author: Pavel Tisnovsky", 10, TextBegin+60);
        g.drawString("Idea: Petr Petyovsky", 10, TextBegin+80);
        g.setColor(Color.blue);
        g.drawString("http://www.root.cz/serialy/fraktaly-v-pocitacove-grafice", 10, TextBegin+100);
    }



    // ------------------------------------------------------------------------
    // Tato metoda provadi prekresleni kresby s navrhem fraktalu.
    // Metoda je volana z metody paint().
    // ------------------------------------------------------------------------
    private void redrawDrawing() {
        Graphics g=drawing.getGraphics();           // ziskat graficky kontext
        g.clearRect(0, 0, DrawingWidth, DrawingHeight+10);       // prekreslit pouze horni cast kresby
        g.setClip(0, 0, DrawingWidth, DrawingHeight);// nastaveni orezani
        g.setColor(Color.blue);

        // kod vykreslujici spojnice vertexu
        for (int j=0; j<activeVertexes; j++) {      // vykreslit spojnice vertexu
            for (int i=0; i<activeVertexes; i++) {
                if ((i!=j) && restrictions[i][j]) { // pokud je dana posloupnost transformaci povolena
                    g.drawLine(vertexX[i], vertexY[i], vertexX[j], vertexY[j]);
                }
            }
        }

        // kod vykreslujici vsechny aktivni vertexy
        for (int i=0; i<activeVertexes; i++) {      // vykreslit vsechny aktivni vertexy
            g.setColor(Color.white);
            g.fillOval(vertexX[i]-8, vertexY[i]-8, 16, 16);
            if (i!=selectedVertex) g.setColor(Color.black);// vybrany vertex vykreslit jinou barvou
            else                   g.setColor(Color.red);// nez ostatni vertexy
            g.drawOval(vertexX[i]-8, vertexY[i]-8, 16, 16);
            g.drawString(String.valueOf(i), vertexX[i]-3, vertexY[i]+5);// vypsat cisla vertexu
        }

        // kod vykreslujic informace o fraktalu
        g.setColor(Color.green);                    // informace okolo tabulky s matici posloupnosti transformaci
        g.fillRect(60, 303+ImageHeight-256, 10, 10);
        g.setColor(Color.red);
        g.fillRect(60, 319+ImageHeight-256, 10, 10);
        g.setColor(Color.gray);
        g.fillRect(60, 319+16+ImageHeight-256, 10, 10);
        g.setColor(Color.black);
        g.drawRect(60, 303+ImageHeight-256, 10, 10);
        g.drawRect(60, 319+ImageHeight-256, 10, 10);
        g.drawRect(60, 319+16+ImageHeight-256, 10, 10);
        g.drawString("Restriction", 60, 280+ImageHeight-256);       // informacni text o matici posloupnosti transformaci
        g.drawString("matrix", 60, 296+ImageHeight-256);
        g.drawString("on", 80, 312+ImageHeight-256);
        g.drawString("off", 80, 328+ImageHeight-256);
        g.drawString("not used", 80, 344+ImageHeight-256);

        // kod vykreslujici prvky matice posloupnosti transformaci
        for (int j=0; j<8; j++) {                   // vykresleni tabulky s prvky matice posloupnosti transformaci
            for (int i=0; i<8; i++) {
                g.setColor(Color.gray);             // sede pozadi
                g.fillRect(i*12+150, j*12+265+ImageHeight-256, 10, 10);
                g.setColor(Color.black);            // cerny ramecek
                g.drawRect(i*12+150, j*12+265+ImageHeight-256, 10, 10);
            }
        }

        // kod pro vykresleni nastavenych prvku matice posloupnosti transformaci
        for (int j=0; j<activeVertexes; j++) {      // vyplneni policek v tabulce podle zadanych podminek
            g.setColor(Color.black);
            g.drawString(String.valueOf(j), 140, j*12+265+10+ImageHeight-256);
            g.drawString(String.valueOf(j), 152+j*12, 372+ImageHeight-256);
            for (int i=0; i<activeVertexes; i++) {  // pouze pro aktivni vertexy, ostatni zustanou sede
                if (restrictions[i][j])             // nastaveni barvy podle hodnoty prvku
                    g.setColor(Color.green);        // v matici posloupnosti transformaci
                else
                    g.setColor(Color.red);
                g.fillRect(i*12+150, j*12+265+ImageHeight-256, 10, 10);// vykresleni policka barvou pozadi
                g.setColor(Color.black);            // vykresleni okraje cernou barvou
                g.drawRect(i*12+150, j*12+265+ImageHeight-256, 10, 10);
            }
        }
    }



    // ------------------------------------------------------------------------
    // Tato metoda provede prekresleni fraktalu.
    // Metoda je volana z funkce paint().
    // ------------------------------------------------------------------------
    private void redrawFractal() {
        Graphics g=panelCenter.getGraphics();       // ziskat graficky kontext
        g.drawImage(image, 0, 0, this);             // provedeni BitBlt
    }



    // ------------------------------------------------------------------------
    // Tato metoda provede filtraci bitmapy s filtrem typu:
    // zadny filtr, pouze kopie bitmapy
    // ------------------------------------------------------------------------
    private void filterNone() {
        int pos=0;
        for (int j=0; j<ImageHeight; j++) {         // pro vsechny radky bitmapy
            for (int i=0; i<ImageWidth; i++) {      // pro vsechny pixely na radku
                pixelDest[pos]=pixelSrc[pos];       // provest kopii pixelu
                pos++;
            }
        }
    }



    // ------------------------------------------------------------------------
    // Tato metoda provede filtraci bitmapy s filtrem typu:
    // rozmazani v bloku 2x2 pixely s vyberem ve tvaru bloku
    // ------------------------------------------------------------------------
    private void filter2x2smooth() {
        int pos=0;                                  // index do zdrojove a cilove bitmapy
        int color;                                  // RGBA barvove slozky zakodovane do typu int
        int r, g, b;                                // jednotlive rozkodovane barvove slozky
        for (int j=0; j<ImageHeight; j++)           // vymazani cilove bitmapy
            for (int i=0; i<ImageWidth; i++)
                pixelDest[pos++]=0xff<<24;          // cerna nepruhledna barva
        pos=0;
        for (int j=0; j<ImageHeight-1; j++) {       // pro vsechny radky bitmapy
            for (int i=0; i<ImageWidth-1; i++) {    // pro vsechny sloupce na radku bitmapy
                color=pixelSrc[pos];              r =(color & 0xff0000)>>16; g =(color & 0x00ff00)>>8; b =(color & 0x0000ff);
                color=pixelSrc[pos+1];            r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos+ImageWidth];   r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos+ImageWidth+1]; r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                r/=4; g/=4; b/=4;                   // provest filtraci
                pixelDest[pos]=(r<<16) | (g<<8) | b | (0xff<<24);
                pos++;
            }
        }
    }



    // ------------------------------------------------------------------------
    // Tato metoda provede filtraci bitmapy s filtrem typu:
    // rozmazani v bloku 3x3 pixely s vyberem ve tvaru diamantu
    // ------------------------------------------------------------------------
    private void filter3x3diamond() {
        int pos=0;                                  // index do zdrojove a cilove bitmapy
        int color;                                  // RGBA barvove slozky zakodovane do typu int
        int r, g, b;                                // jednotlive rozkodovane barvove slozky
        for (int j=0; j<ImageHeight; j++)           // vymazani cilove bitmapy
            for (int i=0; i<ImageWidth; i++)
                pixelDest[pos++]=0xff<<24;          // cerna nepruhledna barva
        pos=1+ImageWidth;
        for (int j=1; j<ImageHeight-1; j++) {       // pro vsechny radky bitmapy
            for (int i=1; i<ImageWidth-1; i++) {    // pro vsechny sloupce na radku bitmapy
                color=pixelSrc[pos-ImageWidth];   r =(color & 0xff0000)>>16; g =(color & 0x00ff00)>>8; b =(color & 0x0000ff);
                color=pixelSrc[pos-1];            r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos+1];            r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos+ImageWidth];   r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                r/=4; g/=4; b/=4;                   // provest filtraci
                pixelDest[pos]=(r<<16) | (g<<8) | b | (0xff<<24);
                pos++;
            }
        }
    }



    // ------------------------------------------------------------------------
    // Tato metoda provede filtraci bitmapy s filtrem typu:
    // rozmazani v bloku 3x3 pixely s vyberem ve tvaru osoveho krize
    // ------------------------------------------------------------------------
    private void filter3x3cross() {
        int pos=0;                                  // index do zdrojove a cilove bitmapy
        int color;                                  // RGBA barvove slozky zakodovane do typu int
        int r, g, b;                                // jednotlive rozkodovane barvove slozky
        for (int j=0; j<ImageHeight; j++)           // vymazani cilove bitmapy
            for (int i=0; i<ImageWidth; i++)
                pixelDest[pos++]=0xff<<24;          // cerna nepruhledna barva
        pos=1+ImageWidth;
        for (int j=1; j<ImageHeight-1; j++) {       // pro vsechny radky bitmapy
            for (int i=1; i<ImageWidth-1; i++) {    // pro vsechny sloupce na radku bitmapy
                color=pixelSrc[pos-ImageWidth];   r =(color & 0xff0000)>>16; g =(color & 0x00ff00)>>8; b =(color & 0x0000ff);
                color=pixelSrc[pos-1];            r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos];              r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos+1];            r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos+ImageWidth];   r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                r/=5; g/=5; b/=5;                   // provest filtraci
                pixelDest[pos]=(r<<16) | (g<<8) | b | (0xff<<24);
                pos++;
            }
        }
    }



    // ------------------------------------------------------------------------
    // Tato metoda provede filtraci bitmapy s filtrem typu:
    // rozmazani v bloku 3x3 pixelu s vyberem ve tvaru uhlopricneho krize
    // ------------------------------------------------------------------------
    private void filter3x3Xcross() {
        int pos=0;                                  // index do zdrojove a cilove bitmapy
        int color;                                  // RGBA barvove slozky zakodovane do typu int
        int r, g, b;                                // jednotlive rozkodovane barvove slozky
        for (int j=0; j<ImageHeight; j++)           // vymazani cilove bitmapy
            for (int i=0; i<ImageWidth; i++)
                pixelDest[pos++]=0xff<<24;          // cerna nepruhledna barva
        pos=1+ImageWidth;
        for (int j=1; j<ImageHeight-1; j++) {       // pro vsechny radky bitmapy
            for (int i=1; i<ImageWidth-1; i++) {    // pro vsechny sloupce na radku bitmapy
                color=pixelSrc[pos-ImageWidth-1]; r =(color & 0xff0000)>>16; g =(color & 0x00ff00)>>8; b =(color & 0x0000ff);
                color=pixelSrc[pos-ImageWidth+1]; r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos];              r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos+ImageWidth-1]; r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos-ImageWidth+1]; r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                r/=5; g/=5; b/=5;                   // provest filtraci
                pixelDest[pos]=(r<<16) | (g<<8) | b | (0xff<<24);
                pos++;
            }
        }
    }



    // ------------------------------------------------------------------------
    // Tato metoda provede filtraci bitmapy s filtrem typu:
    // rozmazani v bloku 3x3 pixelu s blokovym vyberem
    // ------------------------------------------------------------------------
    private void filter3x3block() {
        int pos=0;                                  // index do zdrojove a cilove bitmapy
        int color;                                  // RGBA barvove slozky zakodovane do typu int
        int r, g, b;                                // jednotlive rozkodovane barvove slozky
        for (int j=0; j<ImageHeight; j++)           // vymazani cilove bitmapy
            for (int i=0; i<ImageWidth; i++)
                pixelDest[pos++]=0xff<<24;          // cerna nepruhledna barva
        pos=1+ImageWidth;
        for (int j=1; j<ImageHeight-1; j++) {       // pro vsechny radky bitmapy
            for (int i=1; i<ImageWidth-1; i++) {    // pro vsechny sloupce na radku bitmapy
                color=pixelSrc[pos-ImageWidth-1]; r =(color & 0xff0000)>>16; g =(color & 0x00ff00)>>8; b =(color & 0x0000ff);
                color=pixelSrc[pos-ImageWidth];   r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos-ImageWidth+1]; r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos-1];            r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos];              r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos+1];            r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos+ImageWidth-1]; r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos+ImageWidth];   r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos-ImageWidth+1]; r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                r/=9; g/=9; b/=9;                   // provest filtraci
                pixelDest[pos]=(r<<16) | (g<<8) | b | (0xff<<24);
                pos++;
            }
        }
    }



    // ------------------------------------------------------------------------
    // Tato metoda provede filtraci bitmapy s filtrem typu:
    // rozmazani v bloku 5x5 pixelu s vyberem ve tvaru diamantu
    // ------------------------------------------------------------------------
    private void filter5x5diamond() {
        int pos=0;                                  // index do zdrojove a cilove bitmapy
        int color;                                  // RGBA barvove slozky zakodovane do typu int
        int r, g, b;                                // jednotlive rozkodovane barvove slozky
        for (int j=0; j<ImageHeight; j++)           // vymazani cilove bitmapy
            for (int i=0; i<ImageWidth; i++)
                pixelDest[pos++]=0xff<<24;          // cerna nepruhledna barva
        pos=2+2*ImageWidth;
        for (int j=2; j<ImageHeight-2; j++) {       // pro vsechny radky bitmapy
            for (int i=2; i<ImageWidth-2; i++) {    // pro vsechny sloupce na radku bitmapy
                color=pixelSrc[pos-2*ImageWidth+0]; r =(color & 0xff0000)>>16; g =(color & 0x00ff00)>>8; b =(color & 0x0000ff);
                color=pixelSrc[pos-  ImageWidth-1]; r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos-  ImageWidth+1]; r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos-2];              r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos+2];              r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos+  ImageWidth-1]; r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos+  ImageWidth+1]; r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos+2*ImageWidth+0]; r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                r/=8; g/=8; b/=8;                   // provest filtraci
                pixelDest[pos]=(r<<16) | (g<<8) | b | (0xff<<24);
                pos++;
            }
        }
    }



    // ------------------------------------------------------------------------
    // Tato metoda provede filtraci bitmapy s filtrem typu:
    // rozmazani v bloku 5x5 pixelu s vyberem ve tvaru osoveho krize
    // ------------------------------------------------------------------------
    private void filter5x5cross() {
        int pos=0;                                  // index do zdrojove a cilove bitmapy
        int color;                                  // RGBA barvove slozky zakodovane do typu int
        int r, g, b;                                // jednotlive rozkodovane barvove slozky
        for (int j=0; j<ImageHeight; j++)           // vymazani cilove bitmapy
            for (int i=0; i<ImageWidth; i++)
                pixelDest[pos++]=0xff<<24;          // cerna nepruhledna barva
        pos=2+2*ImageWidth;
        for (int j=2; j<ImageHeight-2; j++) {       // pro vsechny radky bitmapy
            for (int i=2; i<ImageWidth-2; i++) {    // pro vsechny sloupce na radku bitmapy
                color=pixelSrc[pos-2*ImageWidth+0]; r =(color & 0xff0000)>>16; g =(color & 0x00ff00)>>8; b =(color & 0x0000ff);
                color=pixelSrc[pos-  ImageWidth+0]; r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos-2];              r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos-1];              r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos];                r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos+1];              r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos+2];              r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos+  ImageWidth+0]; r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos+2*ImageWidth+0]; r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                r/=9; g/=9; b/=9;                   // provest filtraci
                pixelDest[pos]=(r<<16) | (g<<8) | b | (0xff<<24);
                pos++;
            }
        }
    }



    // ------------------------------------------------------------------------
    // Tato metoda provede filtraci bitmapy s filtrem typu:
    // rozmazani v bloku 5x5 pixelu s vyberem ve tvaru uhlopricneho krize
    // ------------------------------------------------------------------------
    private void filter5x5Xcross() {
        int pos=0;                                  // index do zdrojove a cilove bitmapy
        int color;                                  // RGBA barvove slozky zakodovane do typu int
        int r, g, b;                                // jednotlive rozkodovane barvove slozky
        for (int j=0; j<ImageHeight; j++)           // vymazani cilove bitmapy
            for (int i=0; i<ImageWidth; i++)
                pixelDest[pos++]=0xff<<24;          // cerna nepruhledna barva
        pos=2+2*ImageWidth;
        for (int j=2; j<ImageHeight-2; j++) {       // pro vsechny radky bitmapy
            for (int i=2; i<ImageWidth-2; i++) {    // pro vsechny sloupce na radku bitmapy
                color=pixelSrc[pos-2*ImageWidth-2]; r =(color & 0xff0000)>>16; g =(color & 0x00ff00)>>8; b =(color & 0x0000ff);
                color=pixelSrc[pos-2*ImageWidth+2]; r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos-  ImageWidth-1]; r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos-  ImageWidth+1]; r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos];                r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos+  ImageWidth-1]; r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos+  ImageWidth+1]; r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos+2*ImageWidth-2]; r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos+2*ImageWidth+2]; r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                r/=9; g/=9; b/=9;                   // provest filtraci
                pixelDest[pos]=(r<<16) | (g<<8) | b | (0xff<<24);
                pos++;
            }
        }
    }



    // ------------------------------------------------------------------------
    // Tato metoda provede filtraci bitmapy s filtrem typu:
    // rozmazani v bloku 5x5 pixelu s vyberem ve tvaru bloku
    // ------------------------------------------------------------------------
    private void filter5x5block() {
        int pos=0;                                  // index do zdrojove a cilove bitmapy
        int color;                                  // RGBA barvove slozky zakodovane do typu int
        int r, g, b;                                // jednotlive rozkodovane barvove slozky
        for (int j=0; j<ImageHeight; j++)           // vymazani cilove bitmapy
            for (int i=0; i<ImageWidth; i++)
                pixelDest[pos++]=0xff<<24;          // cerna nepruhledna barva
        pos=2+2*ImageWidth;
        for (int j=2; j<ImageHeight-2; j++) {       // pro vsechny radky bitmapy
            for (int i=2; i<ImageWidth-2; i++) {    // pro vsechny sloupce na radku bitmapy
                color=pixelSrc[pos-2*ImageWidth-2]; r =(color & 0xff0000)>>16; g =(color & 0x00ff00)>>8; b =(color & 0x0000ff);
                color=pixelSrc[pos-2*ImageWidth-1]; r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos-2*ImageWidth+0]; r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos-2*ImageWidth+1]; r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos-2*ImageWidth+2]; r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos-  ImageWidth-2]; r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos-  ImageWidth-1]; r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos-  ImageWidth+0]; r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos-  ImageWidth+1]; r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos-  ImageWidth+2]; r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos-2];              r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos-1];              r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos];                r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos+1];              r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos+2];              r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos+  ImageWidth-2]; r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos+  ImageWidth-1]; r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos+  ImageWidth+0]; r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos+  ImageWidth+1]; r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos+  ImageWidth+2]; r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos+2*ImageWidth-2]; r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos+2*ImageWidth-1]; r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos+2*ImageWidth+0]; r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos+2*ImageWidth+1]; r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos+2*ImageWidth+2]; r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                r/=25; g/=25; b/=25;                // provest filtraci
                pixelDest[pos]=(r<<16) | (g<<8) | b | (0xff<<24);
                pos++;
            }
        }
    }



    // ------------------------------------------------------------------------
    // Tato metoda provede filtraci bitmapy s filtrem typu:
    // horizontalni filtr rozmazani tri pixelu
    // ------------------------------------------------------------------------
    private void filter3pixelsH() {
        int pos=0;                                  // index do zdrojove a cilove bitmapy
        int color;                                  // RGBA barvove slozky zakodovane do typu int
        int r, g, b;                                // jednotlive rozkodovane barvove slozky
        for (int j=0; j<ImageHeight; j++)           // vymazani cilove bitmapy
            for (int i=0; i<ImageWidth; i++)
                pixelDest[pos++]=0xff<<24;          // cerna nepruhledna barva
        pos=1;
        for (int j=0; j<ImageHeight; j++) {         // pro vsechny radky bitmapy
            for (int i=1; i<ImageWidth-1; i++) {    // pro vsechny sloupce na radku bitmapy
                color=pixelSrc[pos-1];            r =(color & 0xff0000)>>16; g =(color & 0x00ff00)>>8; b =(color & 0x0000ff);
                color=pixelSrc[pos];              r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos+1];            r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                r/=3; g/=3; b/=3;                   // provest filtraci
                pixelDest[pos]=(r<<16) | (g<<8) | b | (0xff<<24);
                pos++;
            }
        }
    }



    // ------------------------------------------------------------------------
    // Tato metoda provede filtraci bitmapy s filtrem typu:
    // vertikalni filtr rozmazani tri pixelu
    // ------------------------------------------------------------------------
    private void filter3pixelsV() {
        int pos=0;                                  // index do zdrojove a cilove bitmapy
        int color;                                  // RGBA barvove slozky zakodovane do typu int
        int r, g, b;                                // jednotlive rozkodovane barvove slozky
        for (int j=0; j<ImageHeight; j++)           // vymazani cilove bitmapy
            for (int i=0; i<ImageWidth; i++)
                pixelDest[pos++]=0xff<<24;          // cerna nepruhledna barva
        pos=ImageWidth;
        for (int j=1; j<ImageHeight-1; j++) {       // pro vsechny radky bitmapy
            for (int i=0; i<ImageWidth; i++) {      // pro vsechny sloupce na radku bitmapy
                color=pixelSrc[pos-ImageWidth];   r =(color & 0xff0000)>>16; g =(color & 0x00ff00)>>8; b =(color & 0x0000ff);
                color=pixelSrc[pos];              r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos+ImageWidth];   r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                r/=3; g/=3; b/=3;                   // provest filtraci
                pixelDest[pos]=(r<<16) | (g<<8) | b | (0xff<<24);
                pos++;
            }
        }
    }



    // ------------------------------------------------------------------------
    // Tato metoda provede filtraci bitmapy s filtrem typu:
    // horizontalni filtr rozmazani peti pixelu
    // ------------------------------------------------------------------------
    private void filter5pixelsH() {
        int pos=0;                                  // index do zdrojove a cilove bitmapy
        int color;                                  // RGBA barvove slozky zakodovane do typu int
        int r, g, b;                                // jednotlive rozkodovane barvove slozky
        for (int j=0; j<ImageHeight; j++)           // vymazani cilove bitmapy
            for (int i=0; i<ImageWidth; i++)
                pixelDest[pos++]=0xff<<24;          // cerna nepruhledna barva
        pos=2;
        for (int j=0; j<ImageHeight; j++) {         // pro vsechny radky bitmapy
            for (int i=2; i<ImageWidth-2; i++) {    // pro vsechny sloupce na radku bitmapy
                color=pixelSrc[pos-2];              r =(color & 0xff0000)>>16; g =(color & 0x00ff00)>>8; b =(color & 0x0000ff);
                color=pixelSrc[pos-1];              r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos];                r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos+1];              r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos+2];              r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                r/=5; g/=5; b/=5;                   // provest filtraci
                pixelDest[pos]=(r<<16) | (g<<8) | b | (0xff<<24);
                pos++;
            }
        }
    }



    // ------------------------------------------------------------------------
    // Tato metoda provede filtraci bitmapy s filtrem typu:
    // vertikalni filtr rozmazani peti pixelu
    // ------------------------------------------------------------------------
    private void filter5pixelsV() {
        int pos=0;                                  // index do zdrojove a cilove bitmapy
        int color;                                  // RGBA barvove slozky zakodovane do typu int
        int r, g, b;                                // jednotlive rozkodovane barvove slozky
        for (int j=0; j<ImageHeight; j++)           // vymazani cilove bitmapy
            for (int i=0; i<ImageWidth; i++)
                pixelDest[pos++]=0xff<<24;          // cerna nepruhledna barva
        pos=2*ImageWidth;
        for (int j=2; j<ImageHeight-2; j++) {       // pro vsechny radky bitmapy
            for (int i=0; i<ImageWidth; i++) {      // pro vsechny sloupce na radku bitmapy
                color=pixelSrc[pos-2*ImageWidth]; r =(color & 0xff0000)>>16; g =(color & 0x00ff00)>>8; b =(color & 0x0000ff);
                color=pixelSrc[pos-  ImageWidth]; r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos];              r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos+  ImageWidth]; r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                color=pixelSrc[pos+2*ImageWidth]; r+=(color & 0xff0000)>>16; g+=(color & 0x00ff00)>>8; b+=(color & 0x0000ff);
                r/=5; g/=5; b/=5;                   // provest filtraci
                pixelDest[pos]=(r<<16) | (g<<8) | b | (0xff<<24);
                pos++;
            }
        }
    }



    // ------------------------------------------------------------------------
    // Tato metoda zmeni aktualni filtr.
    // ------------------------------------------------------------------------
    private void applyFilter() {
        switch (filterType) {
            case 0:  filterNone();        break;    // zadny filtr
            case 1:  filter2x2smooth();   break;    // filtr typu 2x2 smooth
            case 2:  filter3x3diamond();  break;    // filtr typu 3x3 diamond
            case 3:  filter3x3cross();    break;    // filtr typu 3x3 cross
            case 4:  filter3x3Xcross();   break;    // filtr typu 3x3 X cross
            case 5:  filter3x3block();    break;    // filtr typu 3x3 block
            case 6:  filter5x5diamond();  break;    // filtr typu 5x5 diamond
            case 7:  filter5x5cross();    break;    // filtr typu 5x5 cross
            case 8:  filter5x5Xcross();   break;    // filtr typu 5x5 X cross
            case 9:  filter5x5block();    break;    // filtr typu 5x5 block
            case 10: filter3pixelsH();    break;    // filtr typu 3 pixels horizontal
            case 11: filter5pixelsH();    break;    // filtr typu 5 pixels horizontal
            case 12: filter3pixelsV();    break;    // filtr typu 3 pixels vertical
            case 13: filter5pixelsV();    break;    // filtr typu 5 pixels vertical
            default:                      break;    // tato volba by nemela nikdy nastat
        }
    }



    // ------------------------------------------------------------------------
    // Tato metoda provede rozhodnuti, zda je matice posloupnosti
    // transformaci korektni pro generovani fraktalu.
    // ------------------------------------------------------------------------
    private boolean isValidFractal() {
        boolean columnOK;
        for (int i=0; i<activeVertexes; i++) {      // projit vsemi aktivnimi vertexy
            columnOK=false;
            for (int j=0; j<activeVertexes; j++)    // najit alespon jednu povolenou transformaci
                if (restrictions[i][j]) columnOK=true;
            if (!columnOK) return false;            // zadna povolena transformace se nenasla
        }
        return true;
    }



    // ------------------------------------------------------------------------
    // Tato metoda provede prepocet fraktalu.
    // ------------------------------------------------------------------------
    private void recalcFractal() {
        double  xo=5.0, yo=5.0;                     // stara pozice bodu
        double  x1, y1, x2, y2;                     // nova pozice bodu
        double  xf1, yf1, xf2, yf2;                 // pomer deleni usecky
        int     newTransform=0;                     // transformace
        int     oldTransform=0;
        int     x, y;

        if (!isValidFractal()) return;              // zkontrolovat, zda jsou transformace v poradku
        Random r=new Random(0);

        for (int i=0; i<ImageWidth*ImageHeight; i++)// smazat obrazek, kam bude fraktal vygenerovan
            pixelSrc[i]=0xff << 24;

        xf1=xFraction; xf2=1.0-xf1;                 // vypocet koeficientu deleni usecky
        yf1=yFraction; yf2=1.0-yf1;

        // vnejsi iteracni smycka
        for (int i=0; i<iterations; i++) {          // iteracni smycka

            // vnitrni smycka pro nalezeni transformace odpovidajici matici posloupnosti transformaci
            do {                                    // najit novou transformaci
                newTransform=(int)(r.nextDouble()*activeVertexes);
            } while (!restrictions[oldTransform][newTransform]);

            x1=vertexX[newTransform];               // ziskat polohu vybraneho ridiciho bodu
            y1=vertexY[newTransform];
            x2=xo;
            y2=yo;
            xo=x1*xf1+x2*xf2;                       // vypocet nove pozice bodu
            yo=y1*yf1+y2*yf2;
            if ((xo>=0) && (xo<=ImageWidth) &&      // pokud se novy bod nachazi uvnitr obrazku
                (yo>=0) && (yo<=ImageHeight) &&
                (i>=startIterations)) {             // a prekrocili jsme pocet startovnich iteraci
                x=(int)xo;
                y=(int)yo;
                switch (putpixelMode) {             // vykreslit novy bod do obrazku
                    case 0:
                        pixelSrc[x+y*ImageWidth]=0xffffffff;
                        break;
                    case 1:
                        pixelSrc[x+y*ImageWidth]+=0x00040404;
                        break;
                    case 2:
                        pixelSrc[x+y*ImageWidth]+=0x00080808;
                        break;
                    case 3:
                        pixelSrc[x+y*ImageWidth]+=0x000c0c0c;
                        break;
                    case 4:
                        pixelSrc[x+y*ImageWidth]+=0x00101010;
                        break;
                    case 5:
                        pixelSrc[x+y*ImageWidth]+=0x00141414;
                        break;
                    default:
                        break;
                }
            }
            oldTransform=newTransform;
        }
        applyFilter();                              // aplikace vybraneho filtru
        image.flush();                              // a vykresleni obrazku na plochu appletu
    }



    // ------------------------------------------------------------------------
    // Tato metoda provede "rychly" prepocet fraktalu - pouze prvnich tisic bodu.
    // ------------------------------------------------------------------------
    private void recalcFractalQuick() {
        double  xo=5.0, yo=5.0;                     // stara pozice bodu
        double  x1, y1, x2, y2;                     // nova pozice bodu
        double  xf1, yf1, xf2, yf2;                 // pomer deleni usecky
        int     newTransform=0;                     // transformace
        int     oldTransform=0;
        int     x, y;

        if (!isValidFractal()) return;              // zkontrolovat, zda jsou transformace v poradku
        Random r=new Random(0);

        for (int i=0; i<ImageWidth*ImageHeight; i++)// smazat obrazek, kam bude fraktal vygenerovan
            pixelDest[i]=0xff << 24;
        xf1=xFraction; xf2=1.0-xf1;                 // vypocet koeficientu deleni usecky
        yf1=yFraction; yf2=1.0-yf1;

        // vnejsi iteracni smycka
        for (int i=0; i<QuickFractalIterations; i++) {// iteracni smycka

            // vnitrni smycka pro nalezeni transformace odpovidajici matici posloupnosti transformaci
            do {                                    // najit novou transformaci
                newTransform=(int)(r.nextDouble()*activeVertexes);
            } while (!restrictions[oldTransform][newTransform]);

            x1=vertexX[newTransform];               // ziskat polohu vybraneho ridiciho bodu
            y1=vertexY[newTransform];
            x2=xo;
            y2=yo;
            xo=x1*xf1+x2*xf2;                       // vypocet nove pozice bodu
            yo=y1*yf1+y2*yf2;
            if ((xo>=0) && (xo<=ImageWidth) &&      // pokud se novy bod nachazi uvnitr obrazku
                (yo>=0) && (yo<=ImageHeight) &&
                (i>=QuickFractalStartIterations)) { // a prekrocili jsme startovnich iteraci pro "rychle" generovani
                x=(int)xo;
                y=(int)yo;
                pixelDest[x+y*ImageWidth]=0xffffffff;// vykreslit novy bod obrazku
            }
            oldTransform=newTransform;
        }
        image.flush();                              // vykresleni obrazku na plochu appletu
    }



    /*
    // -----------------------------------------------------------------------
    // 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.
    // V tomto pripade se vsak vytvori dalsi soubor .class s anonymni tridou
    // se jmenem Listener.
    // -----------------------------------------------------------------------
    public static void main(String[] args) {
        Frame frame=new Frame("Linear IFS");
        Applet applet=new LinearIFS();
        frame.add(applet);
        applet.init();
        frame.setSize(640, 480);
        frame.setVisible(true);
        frame.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
            }
        );
    }
    */
}



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