GRAFIKA KOMPUTEROWA - Ćwiczenia Laboratoryjne 

 


 

Zajęcia I

Ćwiczenia

Utworzenie standardowego projektu w aplikacji JCreator

Zapoznanie się z podstawami obsługi środowiska programistycznego JCreator

Utworzenie własnej funkcji odrysowującej zawartość okienka paint(Graphics)

Zapoznanie się z podstawowymi klasami języka Java

Zapoznanie się z podstawowymi funkcjami klasy Graphics

Zadania

1) Narysowanie w funkcji paint podstawowych figur geometrycznych:

-    prostokąty, kwadraty, elipsy, okręgi, wersje 2D i 3D

-    narysowanie siatki

-    zmiana wielkości oczek siatki

 


 

 

Zajęcia II

 

Ćwiczenia

 

Kontynuowanie opracowania programów z Zajęć I.

 

Uruchomienie aplikacji demonstrującej obsługę zdarzeń pochodzących od myszy

 

Uruchomienie standardowej aplikacji obsługującej zdarzenia pochodzące od myszy

 

Utworzenie własnej aplikacji obsługującej zdarzenia pochodzące od myszy

 

Modyfikacje aplikacji obsługującej zdarzenia pochodzące od myszy

 

Zadanie

Obsługa zdarzeń pochodzących od myszy

-    zmiana koloru siatki

-    zmiana rozmiaru oczek siatki

-    odrysowywanie zaznaczanych myszą kwadratów siatki

 

Zadanie

Napisać program odrysowujący zaznaczany myszą prostokąt.

Użytkownik wciska mysz, punkt zostaje zapamiętany i następnie w trakcie przesuwania wskaźnika myszy zostaje odrysowywany dynamicznie prostokąt.

 

Zadanie

Napisać program odrysowujący na ekranie siatkę n x m (prostokątów).

W trakcie przesuwania myszy nad konkretnym prostokątem, prostokąt nad którym aktualnie znajduje się mysz powinien być zaznaczony wybranym kolorem.

Możliwość modyfikacji monitorowanego obiektu: zmiana koloru i rozmiaru punktu przecięcia, jedynie koloru boków zaznaczanego prostokąta.

 

Zadanie

Napisać program odrysowujący okrąg. Po pierwszym wciśnięciu przycisku myszy odrysowywany jest okrąg o promieniu obliczonym na podstawie aktualnej pozycji myszy.

 

Zadanie

Napisać programy odrysowujące elipsy, trójkąty, romby itp...

 

Zadanie

Napisać program odrysowujący w postaci łamanej kolejne zaznaczane punkty.

 

 

Program

1. Aplikacja bazowa GraphicsProject.java

2. Aplikacja bazowa GUI GraphicsProjectDemo.java

3. Aplikacje GUI z LayoutManager: BorderLayoutDemo, BoxLayoutDemo, CardLayoutDemo, GridBagLayoutDemo, GridLayoutDemo

 


 

 

Zajęcia III

 

Ćwiczenia

 

Kontynuowanie opracowania programów z Zajęć I i Zajęć II.

 

Implementacja siatki.

 

Implementacja siatki w postaci obiektu

 

Implementacja wykresu funkcji

 

Zadanie

 

    Implementacja siatki

 

    Parametry siatki:

        -    iX, iY - odległość lewego górnego oczka siatki względem lewego górnego punktu obszaru roboczego

        -    dX, dY - długość i szerokość oczka siatki

        -    cX, cY - liczba oczek odpowiednio w pionie i poziomie

   

 

Zadanie

 

    Implementacja siatki z punktami przecięcia w postaci okręgów lub kwadratów

 

    Oprócz odrysowania siatki należy dodatkowo odrysowywać w miejscu przecięcia linii (do wyboru):

        -    okręgi

        -    kwadraty

 

    Parametry siatki:

        -    iX, iY - odległość lewego górnego oczka siatki względem lewego górnego punktu obszaru roboczego

        -    dX, dY - długość i szerokość oczka siatki

        -    cX, cY - liczba oczek odpowiednio w pionie i poziomie

 

        -    enum eFlag:

            -    0    ==  bez dodatkowego odrysowania

            -    1    ==  odrysowywany zostaje okrąg

            -    2    == odrysowywany zostaje kwadrat

       

 

Zadanie - Implementacja siatki z punktami przecięcia w postaci okręgów lub kwadratów o dynamicznych parametrach

 

    Oprócz odrysowania siatki należy dodatkowo odrysowywać w miejscu przecięcia linii (do wyboru):

        -    okręgi

        -    kwadraty

 

    Parametry siatki:

        -    iX, iY - odległość lewego górnego oczka siatki względem lewego górnego punktu obszaru roboczego

        -    dX, dY - długość i szerokość oczka siatki

        -    cX, cY - liczba oczek odpowiednio w pionie i poziomie

 

        -    enum eFlag:

            -    0    ==  bez dodatkowego odrysowania

            -    1    ==  odrysowywany zostaje okrąg

            -    2    == odrysowywany zostaje kwadrat

 

        -    eX, eY - odpowiednio:

            -    długość i szerokość odrysowywanego prostokąta w miejscu przecięcia

            -    promienie odrysowywanej elipsy

 

Zadanie

 

    Implementacja siatki z punktami przecięcia w postaci okręgów lub kwadratów o dynamicznych parametrach wraz z opcją wyboru kolorów

 

    Oprócz odrysowania siatki należy dodatkowo odrysowywać w miejscu przecięcia linii (do wyboru):

        -    okręgi (elipsy)

        -    kwadraty (prostokaty)

 

    Dodane powinny zostać opcje wyboru kolorów:

    

 

    Parametry siatki:

        -    iX, iY - odległość lewego górnego oczka siatki względem lewego górnego punktu obszaru roboczego

        -    dX, dY - długość i szerokość oczka siatki

        -    cX, cY - liczba oczek odpowiednio w pionie i poziomie

       

        -    xColour, yColour - kolor linii pionowych i poziomych

 

     

        -    enum eFlag:

            -    0    ==  bez dodatkowego odrysowania

            -    1    ==  odrysowywany zostaje okrąg

            -    2    == odrysowywany zostaje kwadrat

 

        -    eX, eY - odpowiednio:

            -    długość i szerokość odrysowywanego prostokąta w miejscu przecięcia

            -    promienie odrysowywanej elipsy

 

        -    eColour - kolor elips lub prostokątów

 

Zadanie

 

    Implementacja siatki z punktami przecięcia w postaci okręgów lub kwadratów o dynamicznych parametrach wraz z opcją wyboru kolorów oraz ukryciem  linii siatki

 

    Oprócz odrysowania siatki należy dodatkowo odrysowywać w miejscu przecięcia linii (do wyboru):

        -    okręgi (elipsy)

        -    kwadraty (prostokąty)

 

    Dodane powinny zostać opcje wyboru kolorów wraz z możliwością ukrycia linii siatki.

    

    Parametry siatki:

        -    iX, iY - odległość lewego górnego oczka siatki względem lewego górnego punktu obszaru roboczego

        -    dX, dY - długość i szerokość oczka siatki

        -    cX, cY - liczba oczek odpowiednio w pionie i poziomie

       

        -    xColour, yColour - kolor linii pionowych i poziomych

 

        -    enum pFlag:

            -    0    ==  odrysowywane zostają linie pionowe i poziome

            -    1    ==  odrysowywane zostają jedynie linie poziome

            -    2    ==  odrysowywane zostają jedynie linie pionowe

            -    3    ==  linie pionowe i poziome nie są odrysowywane

 

        -    enum eFlag:

            -    0    ==  bez dodatkowego odrysowania

            -    1    ==  odrysowywany zostaje okrąg

            -    2    == odrysowywany zostaje kwadrat

 

        -    eX, eY - odpowiednio:

            -    długość i szerokość odrysowywanego prostokąta w miejscu przecięcia

            -    promienie odrysowywanej elipsy

 

        -    eColour - kolor elips lub prostokątów

 

      

 

 

Zadanie

 

    Implementacja siatki z zaznaczaniem aktywnego oczka

 

    Parametry siatki:

        -    iX, iY - odległość lewego górnego oczka siatki względem lewego górnego punktu obszaru roboczego

        -    dX, dY - długość i szerokość oczka siatki

        -    cX, cY - liczba oczek odpowiednio w pionie i poziomie

        -    xColour, yColour - kolor linii pionowych i poziomych

 

 

 

        -    aX, aY - numer oczka aktywnego liczony w pionie i poziomie

       

Zadanie

 

    Implementacja siatki z zaznaczaniem aktywnych oczek

 

    Parametry siatki:

        -    iX, iY - odległość lewego górnego oczka siatki względem lewego górnego punktu obszaru roboczego

        -    dX, dY - długość i szerokość oczka siatki

        -    cX, cY - liczba oczek odpowiednio w pionie i poziomie

        -    aX[ ], aY[ ] - tablice z numerami oczek aktywnych liczonych w pionie i poziomie

 


 

 

Zajęcia IV

 

Ćwiczenia

 

    Kontynuowanie opracowania programów z poprzednich zajęć.

 

    Implementacja siatki w postaci obiektu Grid

 

    Funkcjonalność aplikacji bazowej:

        -    okno dialogowe FileOpen (klasa FileDialog)

        -    okno dialogowe JColorChooser

        -    obsługa zdarzeń z klawiatury - KeyListener

        -    obsługa zdarzeń pochodzących od komponentu ComponentListener

        -    odczyt plików jpg, gif

               

 

    Wiadomości wprowadzające do formatów plików graficznych na przykładzie plików ppm.

 

    Analiza programu odczytującego pliki w formacie ppm.

 

    Materiał do projektów:

 

        Implementacja wykresu funkcji.

 

        Implementacja klas odrysowujących podstawowe figury geometryczne.

 

        Analiza przeglądarki plików bmp, gif, jpg.   

 

 

Zadanie

 

    Implementacja siatki w postaci obiektu Grid

   

    Analiza przykładowej szkieletowej aplikacji z obiektem Grid

 

Zadanie

 

    Implementacja metody setCell, setPixel dla klasy Grid.

 

    Wyświetlenie plików jpg oraz gif w obiekcie siatki

 

 

Info: format ppm: PPM Format Specification.htm

        formaty graficzne: The Graphics File Format Page (2D specs)

       

 

Programy:

1. Aplikacja szkieletowa z obiektem Grid: GraphicsProjectGrid, GraphicsProjectGrid.zip

2. Aplikacja przeglądarka plików ppm: ppm_project, Aplikacja pliki ppm i skala szarości: ppm_project_gray.zip

3. Aplikacja przeglądarka plików bmp: GraphicsProjectViewer

4. Aplikacja Demo: Java2Demo

 

 

 

    class Grid extends Object {


            int iX = 150;
            int iY = 150;
            int dX = 20;
            int dY = 20;
            int cX = 15;
            int cY = 15;

            // rozmiar (promień dla okręgu) oczka siatki
            int nodeDim = 5;

            // kolor węzłów siatki
            Color nodeColor = new Color(255,0,0);

            // kolor linii siatki
            Color gridColor = new Color(0,0,0);

            // współrzędne lewego górnego rogu okna
            Point pCenter = new Point(130,52);

            // zmienna flag opisuje:
            // 0 - siatka nie reaguje na zmianę wielkości komponentu nadrzędnego
            // 1 - siatka zwiększa lub zmniejsza ilość kratek tak by wypełniały obszar komponentu nadrzędnego
            // 2 - siatka zwiększa lub zmniejsza długość i szerokość kratek tak by wypełniały obszar komponentu nadrzędnego
            // 3 - siatka jest położona centralnie w komponencie nadrzędnym

            int flag = 3;

            // określa wygląd oczek sieci
            // 0 - bez odrysowywania oczek
            // 1 - okręgi
            // 2 - kwadraty

               
int nodeFlag = 2;

            // rodzaj obrzeża
            int borderType = 0;
            Color borderColor = new Color(0,0,255);

            // do implementacji
            // 0 - bez odrysowania siatki
            // 1 - odrysowanie linii poziomych
            // 2 - odrysowanie linii pionowych
            // 3 - odrysowanie linii pionowych i poziomych
            int gridFlag = 3;

            // Obiekt Graphics, operacje odrysowania w komponencie nadrzędnym
            private Graphics G;

            // tablica kolorów dla poszczególnych komórek siatki
            private int[][] rgb = null;

            // Obiekt nadrzędny
            Component gp;

            
// konstruktor
                Grid(Component gp) {

                // wywołanie konstruktora nadklasy
                super();

                this.gp = gp;

                resize_rgb();

            };

            // zmiana flagi obiektu
            public void changeFlag() {

                flag++;
                if(flag >= 4) flag = 0;
                resizeObject();
            }

            // zmiana ilości komórek siatki
            public void adCellCount(int delta) {

                // zmiana jedynie przy fladze centrowania (flag = 4) lub braku reakcji na zmianę wielkości komponentu nadrzędnego (flag = 0)
                if(flag == 1 || flag == 2) return;
                cX += delta;
                cY += delta;

                if(cX < 1) cX = 1;
                if(cY < 1) cY = 1;

                resize_rgb();
                resizeObject();

            }


            // zmiana flagi odrysowania siatki: bez odrysowania, poziome, pionowe, obie
            public void adGridFlag() {

                gridFlag++;
                if(gridFlag > 3) gridFlag = 0;
            }


            // zmiana długości i szerokości komórek sieci
            public void adGridSize(int delta) {

                dX += delta;
                dY += delta;

                if(dX <= 0) dX = 1;
                if(dY <= 0) dY = 1;

                resizeObject();

            }

            // flaga monitorująca odrysowanie obrzeża, ustawienie
            public void adNodeType() {

                nodeFlag++;
                if(nodeFlag > 2) nodeFlag = 0;
            }


            // flaga monitorująca odrysowanie obrzeża, ustawienie
            public void adBorderType() {

            borderType++;
            if(borderType > 1) borderType = 0;

            }


            // operacje wykonywane w przypadku zmiany wielkości obiektu nadrzędnego
            // oraz w przypadku zmiany flagi obiektu
            public void resizeObject() {

                // bez zmian, return
                if(flag == 0) return;

                Dimension d = gp.getSize();

                // zmiana ilości w pionie i poziomie komórek
                if(flag == 1) {

                    cX = (d.width - iX) / dX;
                    cY = (d.height - iY) / dY;
                    resize_rgb();
                }
 

                // zmiana rozmiaru komórek, dopełnienie do prawej krawędzi komponentu nadrzędnego,
                else if(flag == 2) {

                    dX = (d.width - iX) / cX;
                    dY = (d.height - iY) / cY;
                            resize_rgb();
                }

 

                // centrowanie (resize_rgb nie musi być wywołane)
                else if(flag == 3) {

                int width = cX * dX;
                int height = cY * dY;

                iX = pCenter.x + (d.width - width - pCenter.x) / 2;
                if(iX < pCenter.x) iX = pCenter.x;

                iY = pCenter.y + (d.height - height - pCenter.y) / 2;
                if(iY < pCenter.y) iY = pCenter.y;

                }

            }

            private void resize_rgb() {

                rgb = new int[cX][cY];

                for(int i = 0; i < cY; i++)
                for(int j = 0; j < cX; j++)
                rgb[j][i] = 0xffffffff;

                // przykładowe rysowanie linii, tymczasowe, należy usunąć podczas własnej implementacji
                // zastępując metodą setCell
                if(cY <= 10) return;

                Color C = new Color(0,255,0);
                for(int i = 0; i < cX; i++)
                rgb[i][10] = C.getRGB();

            }

        public void setCell(int x, int y, int C) {

        }

        // odrysowuje linie siatki
        public void drawGrid() {

        if(gridFlag == 0) return;

            G.setColor(gridColor);


            if(gridFlag == 1 || gridFlag == 3)
            for(int i = 0; i <= cY; i++)

            G.drawLine(iX,iY + i*dY,iX + dX*cX,iY + i*dY);

            if(gridFlag == 2 || gridFlag == 3)
            for(int i = 0; i <= cX; i++)

            G.drawLine(iX + i*dX,iY,iX + i*dX,iY + cY*dY);

        }

        // Name: drawNodes
        // Desc: odrysowuje węzły siatki w postaci okręgów, elips lub pozostawia bez odrysowania
        public void drawNodes() {

            int offset = nodeDim / 2;
            G.setColor(nodeColor);

            if(nodeFlag == 0) return;

            if(nodeFlag == 1)

            for(int i = 0; i < cY; i++)
            for(int j = 0; j < cX; j++) {
                G.fillOval(iX + dX*j - offset,iY + dY*i - offset,nodeDim,nodeDim);
            }
        else if(nodeFlag == 2)

            for(int i = 0; i < cY; i++)
            for(int j = 0; j < cX; j++) {
                G.fillRect(iX + dX*j - offset,iY + dY*i - offset,nodeDim,nodeDim);
        }



    }

        // odrysowuje komórki siatki
        public void drawCells() {

        for(int i = 0; i < cY; i++)
        for(int j = 0; j < cX; j++)
        {
        G.setColor(new Color(rgb[j][i]));
        G.fillRect(iX + dX*j,iY + dY*i,dX,dY);
        }

}

        // odrysowuje obrzeże siatki
        public void drawBorder() {

            if(borderType == 0) return;

            G.setColor(borderColor);

            // utworzenie bardziej rozbudowanego obiektu do rysowania grafiki - Graphics2D
            Graphics2D gDC = (Graphics2D)G;

            // ustawienie szerokości linii (pióra)
            Stroke pen = new BasicStroke(3);
            gDC.setStroke(pen);

            G.drawRect(iX - 1, iY - 1, dX * cX + 1, dY * cY + 1);

            }

            public void drawObject(Graphics g) {

               G = g;

                drawCells();
                drawGrid();
                drawNodes();
        drawBorder();

        };
      };

 

 


 

 

Zajęcia V

 

Programy:

1. Aplikacja szkieletowa:     GraphicsProjectPack.zip

2. Aplikacja odrysowująca zadany odcinek: Bresenham.java

 

 

Ćwiczenia

 

W celu modyfikacji wyświetlanego pliku graficznego wczytanego do obiektu Image, należy dodać następujący kod:

 

    class ImageCanvas extends JLabel {

            private Image image;
            private Icon iIcon;

            BufferedImage bImage;

            public int cx = 0, cy = 0;

            public ImageCanvas(Icon i) {

                super(i);
                image = ((ImageIcon)i).getImage();
                cx = image.getWidth(this);
                cy = image.getHeight(this);

                InitBuffer();
        }

    public void InitBuffer() {

            bImage = new BufferedImage(cx,cy, BufferedImage.TYPE_INT_ARGB);

            Graphics gDC = (Graphics)bImage.getGraphics();
            gDC.drawImage(image, 0, 0, null);

            int px[] = bImage.getRGB(0,0,cx,cy, null, 0, cx);

            for(int i = 0; i < cx*cy; i++)
            {
            int color = 0xf0f0f000;
            px[i] += color;
            }
            bImage.setRGB(0,0,cx,cy,px,0,cx);
        }


        public void paint(Graphics g) {
            g.drawImage(bImage, 0, 0, null);
        }

}

 

Zagadnienia

1. Implementacja algorytmu odrysowującego linię łączącą dwa zadane punkty (wykład).

2. Implementacja metody odrysowującej linię łączącą dwa zadane punkty w obiekcie siatki Grid.

3. Implementacja klasy GraphicsContext z metodą odrysowują linię łączącą dwa zadane punkty w obiekcie siatki Grid

 

 

 

Zagadnienie

 

 

Zagadnienie

Generowanie obrazów ze skalą szarości

 

Klasa implementująca operację przejścia do skali szarości:

 

class ImageConvert extends Object {

    public void color_to_gray_uniform(BufferedImage new_img, BufferedImage org_img) {

        int row, col; /*loop counting*/
        int cur_pxl; /*current pixel*/

        int cy = (org_img).getHeight();
        int cx = (org_img).getWidth();

        int rgb[] = (org_img).getRGB(0,0,cx,cy,null,0,cx);

        /*Starting with the top row...*/
        for(row = cy - 1; row >= 0; row--)
        for(col = 0; col < cx - 1; col++)
        {
            cur_pxl = rgb[row*cx + col]; /*more readable*/

            /*convert each RGB to the average of the original*/

            int b = (cur_pxl & 0x000000ff);
            int g = ((cur_pxl >> 8) & 0x000000ff);
            int r = ((cur_pxl >> 16) & 0x000000ff);

            int c = ((int)(r + g + b) / 3);

            cur_pxl = c | c << 8 | c << 16 | 0xff << 24;

            new_img.setRGB(col, row, cur_pxl);

        }

    }

 

 

Zagadnienie

 

Kod implementujący wykonywanie operacji na punktach (pikselach) klasy BufferedImage:

-    wykorzystywane są klasy Kernel oraz ConvolveOp

 

public void EffectImage() {

        // Convert
        Kernel sharpKernel = new Kernel(3, 3, new float[] {
                0.0f, -1.0f, 0.0f,
                -1.0f, 5.0f, -1.0f,
                0.0f, -1.0f, 0.0f
        });


        ConvolveOp convolveOp = new ConvolveOp(
            sharpKernel, ConvolveOp.EDGE_NO_OP, null);


        int width = gContext.image.getWidth(this);
        int height = gContext.image.getHeight(this);

        BufferedImage output = new BufferedImage(
                    width, height, BufferedImage.TYPE_INT_ARGB);
                    convolveOp.filter((BufferedImage)gContext.image, output);

        gContext.bImage = output;
        G.readImage(gContext);
        repaint();

}
 

 

Zadanie

Implementacja opcji rysowania myszą zaznaczanych punktów (wraz z łączeniem linią prostą).

Wprowadzane punkty powinny być zapamiętane w tablicy punktów.

 

 

 

Zadanie

 Implementacja metody obracającej obraz siatki o 90, 180, 270 stopni.

 Algorytm powinien poprawnie działać zarówno dla punktów zapisanych w tablicy rgb jak i w obiekcie bImage siatki Grid.

 

 

Zadanie

 

 

 

Zadanie

 Implementacja komendy wyświetlającej w obrazie siatki poszczególne składowe (channels) RGB.

 

 Utworzenie okienka dialogowego z polami wyboru:

    -    Channel R

    -    Channel G

    -    Channel B

 

W zależności od zaznaczonych składowych wyświetlane są jedynie te wybrane.

 

 

 

Zadanie

 Przeanalizować kod komendy Effects programu bazowego GraphicsProjectPack.

 Dodatkowo: przemyśleć i zaimplementować sparametryzowanie poszczególnych parametrów klas ConvolvOp oraz Kernel.

 

Zadanie

 Utworzenie własnego komponentu wyboru kolorów dziedziczącego z klasy Grid.

 

 


 

 

Zajęcia VI

 

 

Zagadnienie

Metoda zwiększania kontrastu Stretch Min-Max.

1. Określenie minimalnej oraz maksymalnej wartości w poszczególnych składowych R, G, B

2. Określenie ogólnej minimalnej i maksymalnej globalnej wartości składowych.

3. Rozciągnięcie min. wartości do 0, max. wartości do 255, pośrednie wartości zmieniamy proporcjonalnie.

 

Aplikacja - GraphicsProjectApp

 

 

 

Zadanie

Implementacja zwiększenia kontrastu dla wyliczonych wartości min. i max.

 

Zadanie

Implementacja zwiększenia kontrastu dla zadanych (wprowadzonych w okienku dialogowym wartości min. i max.).

 

Zadanie

 Implementacja komendy wyświetlającej w obrazie siatki poszczególne składowe (channels) RGB.

 

 Utworzenie okienka dialogowego z polami wyboru:

    -    Channel R

    -    Channel G

    -    Channel B

 

W zależności od zaznaczonych składowych wyświetlane są jedynie te wybrane.

 

Dodatkowo zdefiniowanie filtru dla poszczególnych składowych.

W polu tekstowym definiujemy:

    -    Channel R 0-100%

    -    Channel G 0-100%

    -    Channel B 0-100%

 

W klasie ImageConvert definiujemy nową metodę ChannelFiltering.

Metoda ChannelFiltering wartości składowej (R,G,B) przemnaża przez wprowadzoną wartość procentową i standardowo

zapisuje w obiekcie klasy BufferedImage, który zostaje następnie wyświetlony.

 

 

Zagadnienie

Przezroczystość, kanał alpha.

 

     private AlphaComposite makeComposite(float alpha) {
            int type = AlphaComposite.SRC_OVER;
            return(AlphaComposite.getInstance(type, alpha));
    }


    public void drawObject(Graphics g) {

        G = g;
        Graphics2D g2d = (Graphics2D)g;

        if(bImage != null) {

            Composite originalComposite = g2d.getComposite();
            g2d.setComposite(makeComposite(alpha));
            g2d.drawImage(bImage, iX, iY, cX*dX, cY*dY, gp);
            g2d.setComposite(originalComposite);
        }
        else
        drawCells();
        drawGrid();
        drawNodes();
        drawBorder();
    };


 

Zagadnienie

Zapoznanie się z biblioteką graficzną JIMI.

Utworzenie własnego projektu wykorzystującego funkcje biblioteki JIMI.

 

Programy:

    1. Aplikacja bazowa (wykorzystuje JIMI): GraphicsProjectPacks.java

    2. Biblioteka JIMI: JimiProClasses.zip

 

 

 


 

 

Zajęcia VII

 

 

Program:

    1. Aplikacja demonstracyjna: GraphicsProject2D.java

    2. Aplikacja: GraphicsProject2Di.java

 

 

Zagadnienie

    Tworzenie gradientu.

    Edycja gradientu...

    Tworzenie ścieżki - path

 

     Wykorzystanie klasy GradientPaint

 

            Paint paint = new GradientPaint(0,0, Color.red, 140, 100, Color.green);
            g2d.setPaint(paint);
            g2d.fill(p);
 

 

Zagadnienie

 

Narysować podstawowe figury 2D: prostokat, elipsę, łuk przy zastosowaniu transformacji 2D

 

 

Deklaracje:

 

private BufferedImage bImage = null;
                private int cx = 600, cy = 600;

                private AffineTransform af = null;
                private GeneralPath p = null;

                private AffineTransform afe = null;
                private GeneralPath q = null;

                private AffineTransform aff = null;
                private GeneralPath r = null;

 

Określenie wartości tramsformacji 2D (afinicznych):

 

 

             bImage = new BufferedImage(cx,cy, BufferedImage.TYPE_INT_ARGB);

            af = new AffineTransform();
            af.setToIdentity();
            af.scale(2,2);
            af.translate(45,55);

            p = new GeneralPath(new Rectangle(10,10,80,80));

            afe = new AffineTransform();
            afe.setToIdentity();
            afe.scale(2,2);
            afe.translate(45,45);

            q = new GeneralPath(new Ellipse2D.Double(10,10,55,55));

            aff = new AffineTransform();
            aff.setToIdentity();
            aff.scale(2.0,2.0);
            aff.translate(45,45);

            r = new GeneralPath(new Arc2D.Double(10,10,10,10, 100, 250, Arc2D.OPEN));

 

Wyświetlenie figur podanych transformacjom 2D:

 

public void paint(Graphics g) {

                        // g.drawImage(bImage, 0, 0, null);

                        Graphics2D g2d = (Graphics2D)g;

                        g2d.setTransform(af);
                        g2d.draw(p);

                        g2d.setTransform(afe);
                        g2d.draw(q);

                        g2d.setTransform(aff);
                g2d.draw(r);
}
 

 

Ponadto można bezpośrednio poddawać transformacjom obiekt Graphics2D:

 

    /*
    // Możliwa jest również bezpośrednia transformacja na obiekcie Graphics2D
    //
    //
    public void paint(Graphics g) {

                Graphics2D g2d = (Graphics2D)g;

                g2d.translate(90, 90);
                g2d.draw(p);
    }

    */
 

Zagadnienie

Narysować podstawowe figury geometryczne z wykorzystaniem transformacji.

Utworzyć własne obiekty figur takich jak elipsa, prostokąt, wielokąt.

    -    RoundRectangle2D

    -    Line2D

    -    Polygon

W obiekcie zapamiętać wartości translacji, skalowania i translacji oddzielnie dla każdego obiektu.

 

 


 

Zajęcia VIII

 

Program:

    1. Animacja: GraphicsProjectAnim.java

     2. Aplikacja bazowa: GraphicsProject2Dk.java

 

Zagadnienie

 

    Bezpośredni zapis i renderowanie do obiektu BufferedImage:

 

                 bImage = new BufferedImage(cx,cy, BufferedImage.TYPE_INT_ARGB);

                Graphics2D gx = bImage.createGraphics();
                gx.setColor(Color.black);
                gx.drawOval(100,100,150,150);
                gx.fillRect(100,150,50,50);
 

 

Zagadnienie

 

Animacja wykorzystująca transformacje afiniczne 2D.

 

Zagadnienie

 

Implementacja abstrakcyjnej klasy bazowej figure

 

    abstract class figure extends Object{


            private int xT, yT;
            private double xS, yS;
            private double xR;

            AffineTransform af = null;
            GeneralPath p = null;
            int state = 0;

            abstract void drawObject(Graphics2D g2d);

            abstract void mouseClicked(Point2D p2d);

                figure() {
                .........................                   
                }

            boolean containsPoint(Point2D pt) {
                    ........................
            }

 

Zagadnienie

 

Implementacja klasy polygon dziedziczącej z klasy figure:

 

//------------------------------------------------------------------------------
// Nazwa: klasa polygon
//------------------------------------------------------------------------------

    class polygon extends figure {

        // na początku obiekt nie posiada odcinków krzywej
        int parts = 0;

        polygon() {

                super();
                p = new GeneralPath();
                af = new AffineTransform();
                af.setToIdentity();
        }
       

        void drawObject(Graphics2D g2d) {

        g2d.setTransform(af);
        g2d.draw(p);
        }

        void mouseClicked(Point2D p2d) {

            if(state == 0) {
                    p.moveTo((float)p2d.getX(), (float)p2d.getY());
                    state = 1;
            }
            else if(state == 1) {
                p.lineTo((float)p2d.getX(), (float)p2d.getY());
            }
    }

}
 

Zagadnienie

 

Utworzenie listy obiektów sceny:

 

ArrayList objects = new ArrayList();
                figure aObject = null;

 

Tworzenie nowych obiektów wraz z dodawaniem do listy:

 

                //-------------------------------------------------------------------
                // Name: ObjectCreate
                // Desc:
                //-------------------------------------------------------------------

                public void PolygonObjectCreate() {
                polygon poly = new polygon();
                objects.add(poly);
                aObject = poly;
                }

 

Obsługa dodawania nowych punktów obiektu polygon przy użyciu myszy:

(konieczne jest wcześniejsze ustawienie obiektu jako obiekt aktywny)

 

                 public void mouseClicked(MouseEvent e) {

                        int mX, mY;

                        mX = e.getX();
                        mY = e.getY();

                        if(aObject != null)

                            aObject.mouseClicked(new Point2D.Double(mX, mY));
                            repaint();
                }

 

Zagadnienie

 

W funkcji renderującej, możliwe jest podanie szczegółowych parametrów renderingu

 

           

                void paint(Graphics g) {

 

                Graphics2D g2d = (Graphics2D)g;

                // ustawienie parametrów renderingu
                RenderingHints qualityHints = new RenderingHints
                    (RenderingHints.KEY_ANTIALIASING,
                    RenderingHints.VALUE_ANTIALIAS_ON);
                qualityHints.put(RenderingHints.KEY_RENDERING,
                    RenderingHints.VALUE_RENDER_QUALITY);
                g2d.setRenderingHints(qualityHints);
 

                    }

 

 


 

Zajęcia IX

 

Program:

 

    1. Modelowanie krzywych Bezier: GraphicsProject2Dak.java

 

Zagadnienie

 

Utworzenie dodatkowych obiektów: trójkąt, kolejne wielokąty foremne

 

Zagadnienie

 

Wyświetlanie obiektów sceny w okienku dialogowym w liście.

 

Zagadnienie

 

    Wybór aktywnego obiektu poprzez zaznaczenie myszą.

    Aktywny obiekt powinien być odrysowany w czerwonym kolorze.

    Dodatkowo w przypadku obiektu polygon w wierzchołkach należy odrysować okręgi.

 

Zagadnienie

 

    Implementacja przesuwania myszą wierzchołków obiektu polygon (w trybie edycji - jak obiekt został zaznaczony jako aktywny)

 

Zagadnienie

 

    Implementacja właściwości odrysowywanych linii, poprzez wprowadzenie odpowiednich wartości w okienku dialogowym.

 

 

//----------------------------------------------------------------------------
// Nazwa:
// Opis: Wyświetla dialog właściowści pióra // BasicStroke
//----------------------------------------------------------------------------

    class PenObjectDialogBox extends Dialog {


            GraphicsProject mw = null;

            // właściwości CAP, lista
            java.awt.List LB = null;

            // właściwości JOIN, lista
            java.awt.List jLB = null;

            // właściwości rozmiar, lista
            java.awt.List sLB = null;

            public PenObjectDialogBox(GraphicsProject p,figure f,String T) {
                super(p,T);
                setSize(200, 380);
                setBackground(Color.gray);

                setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));

                mw = p;
                JButton btn, dbtn;

                LB = new java.awt.List(4);
                LB.add ("CAP BUTT");
                LB.add ("CAP ROUND");
                LB.add ("CAP SQUARE");
                add(LB);

                jLB = new java.awt.List(4);
                jLB.add ("JOIN BEVEL");
                jLB.add ("JOIN MITER");
                jLB.add ("JOIN ROUND");
                add(jLB);

                sLB = new java.awt.List(4);
                for(int i = 0; i < 10; i++)
                    sLB.add (Integer.toString(i));
                add(sLB);



                btn = new JButton("Select Properties");
                btn.setAlignmentX(Component.CENTER_ALIGNMENT);
                add(btn);

          btn.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {


                int icap = LB.getSelectedIndex ();

                int ijoin = jLB.getSelectedIndex ();

                int size = sLB.getSelectedIndex ();

                int cap = 0;
                int join = 0;

                if(icap == 0) cap = BasicStroke.CAP_BUTT;
                else if(icap == 1) cap = BasicStroke.CAP_ROUND;
                else if(icap == 2) cap = BasicStroke.CAP_SQUARE;

                if(ijoin == 0) ijoin = BasicStroke.JOIN_BEVEL;
                else if(ijoin == 1) join = BasicStroke.JOIN_MITER;
                else if(ijoin == 2) join = BasicStroke.JOIN_ROUND;


                mw.aObject.bstroke = new BasicStroke(size,cap,join);

                mw.repaint ();
        }
       });


        addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
            dispose();
            }
        });
}
}

 

 

 


 

 

Zajęcia X

 

1. Aplikacja: GraphicsProject2Dc.java

 

//------------------------------------------------------------------------------
// Nazwa: klasa quadcurve
//------------------------------------------------------------------------------

class quads extends figure {

    // na początku obiekt nie posiada odcinków krzywej
    int parts = 0;

    GeneralPath GP = null;
    PathIterator S = null;

    float x1, y1, x2, y2;

    quads() {

        super();
        p = new GeneralPath();
        af = new AffineTransform();
        af.setToIdentity();
    }

    void drawObject(Graphics2D g2d) {

        g2d.setStroke (bstroke);
        g2d.setTransform(af);

        double b[] = new double[6];
        PathIterator pi = p.getPathIterator(af);
 

        while(pi.isDone() != true) {

            int op = pi.currentSegment (b);

                if(op == PathIterator.SEG_MOVETO) {
 

                    g2d.fillOval ((int)b[0], (int)b[1], 5,5);

                }
                else if(op == PathIterator.SEG_QUADTO) {

                    g2d.setColor (Color.red);
                    g2d.fillOval ((int)b[0], (int)b[1], 5,5);
                    g2d.setColor (Color.black);

                    g2d.fillOval ((int)b[2], (int)b[3], 5,5);

            }

            pi.next ();
        }

        g2d.setColor (Color.black);
        g2d.draw(p);
    }


        void change_Node(int node_index, Point2D p2d) {

                GeneralPath gp = new GeneralPath();

                double X = p2d.getX();
                double Y = p2d.getY();

                double b[] = new double[6];
                PathIterator pi = p.getPathIterator(af);

                int index = 0;
                while(pi.isDone() != true) {

                int op = pi.currentSegment (b);
                       

                if(op == PathIterator.SEG_MOVETO) {

                        index++;
                        gp.moveTo((float)b[0], (float)b[1]);
                       

                        if(index == node_index) {

                            gp.moveTo((float)X, (float)Y);

                        }
                }
                else if(op == PathIterator.SEG_QUADTO) {
 

                    index++;

                    if(index == node_index) {

                        b[0] = X;
                        b[1] = Y;

                    }
 

                    index++;

                    if(index == node_index) {

                        b[2] = X;
                        b[3] = Y;
                    }

                    gp.quadTo((float)b[0], (float)b[1],(float)b[2], (float)b[3]);
            }

            pi.next ();
        }


            p = gp;

            return;

    }


    int mouseClicked_OnNode(Point2D p2d) {

            double X = p2d.getX();
            double Y = p2d.getY();

            double b[] = new double[6];

            PathIterator pi = p.getPathIterator(af);

            int index = 0;

            while(pi.isDone() != true) {

                int op = pi.currentSegment (b);

                if(op == PathIterator.SEG_MOVETO) {

                    index++;
                    if(X >= b[0] - 3 && X <= b[0] + 3 && Y >= b[1] - 3 && Y <= b[1] + 3) return index;

                }
                else if(op == PathIterator.SEG_QUADTO) {
               

                    index++;
   
                    if((X >= b[0] - 3 && X <= b[0] + 3) && (Y >= b[1] - 3 && Y <= b[1] + 3)) return index;
                    index++;

                    if((X >= b[2] - 3 && X <= b[2] + 3) && (Y >= b[3] - 3 && Y <= b[3] + 3)) return index;

            }

            pi.next ();
            }

        return 0;

    }



        void mouseClicked(Point2D p2d) {

                if(state == 0) {
                    p.moveTo((float)p2d.getX(), (float)p2d.getY());
                    state = 1;
                }
                else if(state == 1) {
                S = p.getPathIterator(af);
            GP = new GeneralPath(p);

            x1 = x2 = (float)p2d.getX ();
            y1 = y2 = (float)p2d.getY ();
            p.quadTo((float)p2d.getX(), (float)p2d.getY(),(float)p2d.getX(), (float)p2d.getY());
           state = 2;
            }
            else if(state == 3) {

                S = p.getPathIterator(af);
                GP = new GeneralPath(p);

                x1 = x2 = (float)p2d.getX ();
                y1 = y2 = (float)p2d.getY ();

                p.quadTo((float)p2d.getX(), (float)p2d.getY(),(float)p2d.getX(), (float)p2d.getY());

            }
        }


        void mouseDragged(Point2D p2d) {

            int index = 0;

            index = mouseClicked_OnNode(p2d);

            if(index == 0) return;

            if(state == 2 || state == 3) {

            change_Node(index, p2d);
        }
    }


void mouseReleased(Point2D p2d) {

        if(state == 2) state = 3;

    }


}
 

 

Zadanie

Implementacja obiektów:

    triangle

    rectangle

    arc

    polygon

    scribble

    quad

    Bezier (następne zajęcia)

 

Zadanie

Wybór obiektu aktywnego

 

Zadanie

Odrysowywanie aktualnie edytowanego segmentu obiektu quad w zadanym kolorze.

 

 


 

Zajęcia XI

 

Odrysowywanie pojedynczych segmentów:

    -    CubicCurve2D.Double

    -    QuadCurve2D.Double

 

Zadanie

 

    Segment Quad

    Program umożliwia wprowadzenie przez użytkownika dwu punktów (początkowego i końcowego), trzeci punkt kontrolny jest wybierany automatycznie.

    Wyświetlenie segmentu Quad jako obiektu QuadCurve2D.Double

 

    int state = 0;

 

    // punkt początkowy, końcowy i kontrolny

    Point2D.Double S, E, C;

 

    QuadCurve2D.Double qs = null;

   

    qs = new QuadCurve2D.Double();

 

 

    void mouseClicked(MouseEvent e) {

 

int mX, mY;

                mX = e.getX();
                mY = e.getY();

       

                if(state == 0) {

 

                    S = new Point2D.Double(mX, mY);

                    state = 1;

                }

                else if(state == 1) {

 

                    E = new Point2D.Double(mX, mY);

 

                    state = 2;

              }               

               else if(state == 2) {

 

               

                    C = new Point2D.Double(mX, mY);

 

                    qs.setCurve(S, C, E);

 

                    state = 3;

                   

            }

 

    }

 

        public void paint(Graphics g) {

 

                Graphics2D g2d = (Graphics2D)g;

 

                if(state == 3) g2d.draw(qs);

   

                if(state == 1) g2d.drawOval(S, 5, 5);

 

                if(state == 2) {

 

                    g2d.drawOval(S, 5, 5);

                    g2d.drawOval(E, 5, 5);

 

                }

 

        }

 

Zadanie

 

    Zmiana przy wykorzystaniu myszy wprowadzonych przez użytkownika punktów: początkowego (S), końcowego (E) i kontrolnego (C)

 

    int mouseOverNode(int, int) {

 

        return 0, 1, 2 lub 3

 

    }

 

 

    mouseDragged(MouseEvent e) {

 

int mX, mY;

                mX = e.getX();
                mY = e.getY();

 

                int index = mouseOverNode();

 

                // zmiana

                if(index == 0) mysz nie znajduje się nad żadnym z węzłów

       

                if(index == 1) mysz nad punktem początkowym, zmienić

 

                if(index == 2) mysz nad punktem końcowym, zmienić

 

                if(index == 3) mysz nad punktem kontrolnym, zmienić

 

 

    }

 

Zadanie

 

    Użytkownik wprowadza punkt początkowy, końcowy oraz kontrolny krzywej Quad. Możliwość zmiany przyciskiem myszy tych trzech punktów.

 

Zadanie

 

    Użytkownik wprowadza punkt początkowy, końcowy oraz dwa punkty kontrolne krzywej Bezier. Możliwość zmiany przyciskiem myszy tych czterech punktów.

 

Zadanie

 

Implementacja obiektu BezierPath.

Wykorzystanie następujących metod klasy GeneralPath:

 

 void curveTo(float x1, float y1, float x2, float y2, float x3, float y3)
          Adds a curved segment, defined by three new points, to the path by drawing a Bézier curve that intersects both the current coordinates and the coordinates (x3, y3), using the specified points (x1, y1) and (x2, y2) as Bézier control points.

 

Wykorzystanie następujących metod PathIterator:

 

currentSegment

int currentSegment(double[] coords)
Returns the coordinates and type of the current path segment in the iteration. The return value is the path-segment type: SEG_MOVETO, SEG_LINETO, SEG_QUADTO, SEG_CUBICTO, or SEG_CLOSE. A double array of length 6 must be passed in and can be used to store the coordinates of the point(s). Each point is stored as a pair of double x,y coordinates. SEG_MOVETO and SEG_LINETO types returns one point, SEG_QUADTO returns two points, SEG_CUBICTO returns 3 points and SEG_CLOSE does not return any points.

 

Parameters:
coords - an array that holds the data returned from this method
Returns:
the path-segment type of the current path segment.
See Also:
	SEG_MOVETO, SEG_LINETO, SEG_QUADTO, SEG_CUBICTO, SEG_CLOSE
 

 


 

Zajęcia XII

 

Wykorzystywanie wątków w aplikacjach graficznych.

 

Aplikacja - GraphicsProjectAnims.java

 

 

Zagadnienie

Implementacja wątku aplikacji

 

        class FrameWatcher implements Runnable {


                    Thread runner;

                    GraphicsProject mf = null;

                    FrameWatcher(GraphicsProject mf) {


                    this.mf = mf;

                    if(runner == null) {

                            runner = new Thread(this);
                            runner.start();

                    }
            }

 

       public void run() {

                while(true) {

                    mf.moveFrame();
                    mf.repaint();
            try {
                    Thread.sleep(1000);
            }catch (InterruptedException e){};

        }
    }
};
 

 

Zagadnienie

Poprzednie zajęcia - implementacja klasy Rectangle w własnym projekcie.

Dodanie możliwości animacji:

            -    translacja, skalowanie, obrót

    dla obiektu Rectangle

Implementacja sposobu wypełniania obszaru obiektu Rectangle - GradientPaint

Implementacja przezroczystości - AplphaComposite

 

 

public void paint(Graphics g) {

                        Graphics2D g2d = (Graphics2D)g;

                        gPaint = new GradientPaint(g1,g2,new Color(100,200,50),g3,g4, new Color(100,0,50));

                        cComp = AlphaComposite.getInstance (AlphaComposite.SRC_OVER, c1);

                        g2d.setComposite (cComp);

                        g2d.setPaint(gPaint);

                        g2d.setTransform(af);

                        g2d.fill (p);

                        g2d.draw(p);
 

            }

 

             public void moveFrame() {

                    xt = xt + 5.0;
                    yt = yt + 5.0;

                    af = new AffineTransform();
                    af.setToIdentity();
                    af.scale(2,2);
                    af.translate(xt,yt);

                    g1 += 1.5;
                    g2 += 2.5;
                    g3 = g1 + g2;
                    g4 = g2 - g1;

                    c1 = (c1 + e);

                    if(c1 > 1.0) {
                        e = - 0.1f;
                        c1 = (c1 + e);
                    }
                    else if(c1 < 0.0) {
                        e = 0.1f;
                        c1 = (c1 + e);
                }
            }

 

    Zadania

    1) Odrysowanie prostokąta, obrót wokół środka prostokąta.

    2) Poruszanie się prostokąta po okręgu.

    3) Utworzenie dwóch wątków, każdy z tych wątków powinien odrysowywać oddzielny prostokąt.

        Pierwszy prostokąt porusza się po okręgu, drugi podąża za pierwszym prostokątem.

    4) Pierwszy prostokąt ustawiany jest przy wykorzystaniu myszy, drugi podąża za pierwszym.

 

 


 

Zajęcia XIII

 

 

Aplikacja - GraphicsProject2Dcd.java

Aplikacja - GraphicsProject2Dcde.java

 

Zagadnienie

    Implementacja n-kątów foremnych

 

Zagadnienie

    Wybór obiektu aktywnego:

        -    zaznaczenie myszą

        -    wybór z okienka dialogowego

 

Zagadnienie

    Odrysowanie krzywych:

 

            Asteroida

            Hypocykloida

            Kardioida

 

            Teoria:

                1. Astroid.doc

                2. Hypocycloid.doc               

                3. Cardioid Catacaustic.doc

 

Zagadnienie

 

Przeglądarka plików ppm i skala szarości: ppm_project_gray.zip

 


 

Zajęcia XIV

 

 Projekt edytora figur, specyfikacja wymagań:

 

1. Klasy obiektów:

    -    prostokąt

    -    elipsa

    -    łuk

    -    scribble

    -    quad

    -    polygon

    -    Bezier

    -    quadric

    -    astroid, hypocycloid

    -    n-kąt foremny

 

2. Wybór obiektu aktywnego: mysz, okienko dialogowe

3. Wybór koloru tła

4. Wypełnianie figury kolorem, gradient

5. Obsługa przezroczystości

6. Nakładanie tekstury wypełnienia

7. Określenie sposobu odrysowania linii

 

8. Transfomacje obiektu aktywnego - translacje, obroty, skalowanie - klawiatura, mysz

9. Zaznaczanie kilku obiektów aktywnych wraz z możliwością wykonywania podstawowych operacji

10. Animacje obiektu / obiektów aktywnych

 


 

Zajęcia XV

 

    Zdanie projektów

    Wystawienie ocen.

    Zaliczenie przedmiotu.

 


 

 

Forma zaliczenia przedmiotu:

 

Warunkiem zaliczenia pracowni specjalistycznej z przedmiotu Grafika komputerowa jest zdanie dwu projektów:

1) Projekt I, Zajęcia 7 - 8

2) Projekt II, Zajęcia 14-15

Projekty (programy) powinny odnosić się do materiału i algorytmów prezentowanych na wykładzie.

 

 

 


 

Materiały:

 

1. Java Documenation - class Graphics

2  Java Documentation - class Graphics2.

3  Java Documentation - class Event.

4. Strona Sun Microsystems - java.sun.com

5. Java Documentation - class jsdk_doc_awt_geom

6. Java Documentation - class ImageConsumer

7. Java Documentation - class ImageProducer

 

 

8. Grafika - podstawy: Podstawy Grafiki

 

Pozycje książkowe

 

1. Java2 dla każdego, L. Lemay, R. Cadenhead, Helion

2. Java 3, Jan Bielecki, Helion

3. Java 4 Swing, t.I i t. II, Jan Bielecki, Helion