Commit 52b67c7a authored by Marek Trtik's avatar Marek Trtik
Browse files

iteration-10 assignment

parent 3d0e4044
Loading
Loading
Loading
Loading
+49 −37
Original line number Diff line number Diff line
## Zadání iterace 09

**Cvičení je zaměřené na práci s výjimkami a vnořenými kolekcemi.**

1.  Vytvořte výjimky v balíčku `cz.muni.fi.pb112.project.exception`:
    *   `TransparentColorException` je _kontrolovaná_ (checked) výjimka při kreslení stejnou barvou na stejném pozadí, např. bílou tužkou na bílý papír.
    *   `EmptyDrawableException` je _kontrolovaná_ výjimka, pokud na kreslicím objektu není nic namalováno.
    *   `MissingVerticesException` představuje _**nekontrolovanou**_ (unchecked) výjimku v případě, že v kolekci není dostatek vrcholů.

    Všechny výjimky budou mít alespoň dva konstruktory, které:
    *   umožňují nastavit **řetězec** s chybovou zprávou,
    *   umožňují nastavit **řetězec** a **příčinu** (cause) výjimky: výjimku, která byla bezprostřední příčinou této výjimky.

2. Upravte konstruktor `SimplePolygon` tak, aby vyhazoval `MissingVerticesException`, pokud pole obsahuje méně než tři vrcholy.
   > Hlavičky metod, které vyhazují kontrolované výjimky, musí obsahovat `throws`.

3. Upravte třídu `Paper` následovně:
    *   Metoda `eraseAll()` volaná na čistém (prázdném) papíře vyhodí `EmptyDrawableException`.
    *   Metoda `drawPolygon` vyhodí `TransparentColorException` při kreslení bílou barvou.
        Výjimka bude obsahovat textový popis s názvem barvy.
    *   `Paper` bude implementovat rozhraní `PolygonFactory`.
    *   Metoda `Polygon tryToCreatePolygon(List<Vertex2D>)` se pokusí vytvořit `CollectionPolygon` ze seznamu vrcholů.
        *   Pokud je vstupní argument `null`, metoda vyhodí `NullPointerException`.
        *   Metoda zkopíruje vstupní kolekci (nebude měnit původní kolekci).
        *   Pokud během vytváření polygonu dojde k chybě `IllegalArgumentException`, metoda výjimku pohltí, odstraní všechny `null` vrcholy z kolekce a zkusí to znovu. Výjimku `MissingVerticesException` metoda nechá projít dál.
            > Poznámka: Požadované chování porušuje princip používání výjimek. Logičtější a jednodušší by bylo nejprve zkontrolovat a odstranit null vrcholy. To by také zabránilo zbytečnému vyhazování výjimky konstruktorem třídy CollectionPolygon. Požadované chování slouží pouze k procvičení práce s výjimkami.

    *   Metoda `void tryToDrawPolygons(List<List<Vertex2D>>)` přijímá seznam seznamů vrcholů
        (tj. seznam polygonů uložených jako kolekce vrcholů).
        *   Metoda se pokusí z každé kolekce vytvořit polygon (`tryToCreatePolygon`) a následně jej vykreslit (`drawPolygon`).
        *   Pokud při kreslení polygonu dojde k výjimce `TransparentColorException`, ostatní polygony budou vykresleny černou barvou.
        *   Pokud během vytváření dojde k výjimce `MissingVerticesException` nebo `NullPointerException`, metoda výjimku zachytí a pokusí se vytvořit a vykreslit další polygon. Pokud **se nepodaří vykreslit žádný polygon**, vyhodí se `EmptyDrawableException` s příčinou **poslední** chyby.
    *   Přidejte metodu `Collection<Polygon> getPolygonsWithColor(Color color)`, která vrátí všechny polygony s barvou `color`. Můžete použít lambda streamy, konkrétně `filter`, `map`, `collect`.

3. Spuštěním třídy `Draw` se vykreslí černobílý domeček.  
    ![](images/draw09.png)
## Zadání iterace 10

**Cvičení je zaměřené na práci se vstupem a výstupem.**

Upravte třídu `LabeledPolygon.Builder` tak, aby implementovala rozhraní `PolygonReadable`.
Upravte třídu `LabeledPolygon` tak, aby implementovala rozhraní `PolygonWritable`.

1.  Metoda `read(InputStream)` přijímá otevřený vstupní proud obsahující pojmenované vrcholy, načte vrcholy a přidá je ke stávajícím vrcholům polygonu.
    Při jakékoli chybě vstupu/výstupu nebo chybě formátu vstupních dat musí metoda atomicky selhat a vyhodit `IOException`. (atomicky = buď se načte vše, nebo nic)
    Formát vstupních dat je následující:
    *   Vstup je textový.
    *   Každý vrchol je na jednom řádku.
    *   Každý řádek je ve formátu _„x y název vrcholu“_, tj. nejprve souřadnice vrcholu oddělené mezerou
        a poté název vrcholu (název může obsahovat mezery).
        Viz například soubor `polygon-ok.txt`.

2.  Metoda `write(OutputStream)` zapisuje vrcholy do zadaného výstupního proudu.
    Výstupní formát je stejný jako u předchozí metody.

3.  Metody `write(File)` a `read(File)` budou fungovat stejně jako dříve,
    nicméně budou pracovat se souborem místo I/O proudu.
    Vyhněte se duplicitě kódu!

4.  Vytvořte metodu `writeJson(OutputStream os)`, která zapíše mapu ve formátu JSON do výstupního proudu.
    *   Použijte externí knihovnu [gson](https://github.com/google/gson).
        Pro Maven je potřeba přidat závislost do souboru `pom.xml` v sekci `<dependencies>`.
    *   Přečtěte si dokumentaci třídy _Gson_.
    *   Podle [dokumentace použijte tzv. _pretty print_](https://github.com/google/gson/blob/master/UserGuide.md#compact-vs-pretty-printing-for-json-output-format).
    *   Objekt typu _Gson_ lze znovu použít, takže jej stačí vytvořit pouze jednou.

6.  Upravte třídu `Demo` následovně:
    *   Metoda `main` bude vyhazovat `IOException`. 
    *   Třída vytvoří `LabeledPolygon` ze souboru `polygon-ok.txt`.
    *   Polygon bude také obsahovat vrchol s názvem `vertex x` se souřadnicemi `[123, 456]`.
    *   Zapište výstup do výstupního proudu `System.out` ve formátu JSON.
    *   Pro ověření, že výstupní proud je stále otevřený, poté vytiskněte `Hello World!`.

5.  Spuštěním třídy `Draw` se načte `polygon-ok.txt` a vykreslí se na obrazovku toto.  
    ![](images/draw10.png)

### Nápověda

- Zavřete pouze ty proudy/soubory, které jste sami otevřeli.
- Použijte _try with resources_.
- Prostudujte metody `Writer#flush()`, `Reader#ready()`.
- Vytvoření souboru: `new File("soubor.txt")`.
- `Demo.main` může vyhazovat `IOException`.
- Místo `\n` použijte univerzální oddělovač řádků `System.lineSeparator()`. 
- Testy vytvářejí soubor `polygon-out.txt`.

polygon-error.txt

0 → 100644
+4 −0
Original line number Diff line number Diff line
-1.0 1.0 vrchol f
-1.0 vrchol g
-1,0 1,0 vrchol g
vrchol g -1.0 1.0

polygon-ok.txt

0 → 100644
+6 −0
Original line number Diff line number Diff line
0.0 -100.0 vertex b
-100.0 0.0 vertex a
0.0 100.0 vertex c
-100.0 100.0 vertex d
-100.0 200.0 vertex d
-100.0 200.0 vertex e
+35 −107
Original line number Diff line number Diff line
package cz.muni.fi.pb112.project.demo;

import cz.muni.fi.pb112.project.exception.EmptyDrawableException;
import cz.muni.fi.pb112.project.geometry.ColoredPolygon;
import cz.muni.fi.pb112.project.geometry.Paper;
import cz.muni.fi.pb112.project.geometry.LabeledPolygon;
import cz.muni.fi.pb112.project.geometry.Polygon;
import cz.muni.fi.pb112.project.geometry.Vertex2D;

import javax.swing.JFrame;
import javax.swing.JPanel;
@@ -12,8 +9,8 @@ import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
import java.awt.Color;
import java.awt.Graphics;
import java.util.Arrays;
import java.util.List;
import java.io.FileInputStream;
import java.io.IOException;

/**
 * Class drawing 2D objects.
@@ -27,62 +24,10 @@ public final class Draw extends JFrame {
    private static final int HALF_WIDTH = PANEL_WIDTH / 2;
    private static final int HALF_HEIGHT = PANEL_HEIGHT / 2;

    private static final Color POLYGON_COLOR = Color.MAGENTA;

    private static final List<Vertex2D> WALLS = LList.of(
            new Vertex2D(-150, -150),
            new Vertex2D(150, -150),
            new Vertex2D(150, 150),
            new Vertex2D(-150, 150)
    );

    private static final int A = 45;
    private static final int B = 100;

    private static final List<Vertex2D> WINDOW_LEFT = LList.of(
            new Vertex2D(-A, A),
            new Vertex2D(-B, A),
            new Vertex2D(-B, B),
            new Vertex2D(-A, B)
    );

    private static final List<Vertex2D> WINDOW_RIGHT = LList.of(
            new Vertex2D(A, A),
            new Vertex2D(B, A),
            new Vertex2D(B, B),
            new Vertex2D(A, B)
    );

    private static final List<Vertex2D> DOOR = LList.of(
            new Vertex2D(-30, -150),
            new Vertex2D(30, -150),
            new Vertex2D(30, -20),
            new Vertex2D(-30, -20)
    );

    private static final List<Vertex2D> ROOF = LList.of(
            new Vertex2D(-150, 150),
            new Vertex2D(150, 150),
            new Vertex2D(0, 250)
    );

    private static final List<List<Vertex2D>> COLLECTION = LList.of(
            WALLS,
            WINDOW_LEFT,
            WINDOW_RIGHT,
            Arrays.asList(new Vertex2D(0, 0), null, null),
            DOOR,
            ROOF);
    private static final String POLYGON_OK_TXT = "polygon-ok.txt";

    private Graphics graphics;

    private static class LList {
        @SafeVarargs
        static<E> List<E> of(E... elements) {
            return Arrays.asList(elements);
        }
    }

    /**
     * Draws 2D objects.
     *
@@ -110,16 +55,20 @@ public final class Draw extends JFrame {

    private void paintScene(Graphics g) {
        graphics = g;
        Paper paper = new Paper();

        try {
            paper.tryToDrawPolygons(COLLECTION);
        } catch (EmptyDrawableException e) {
        LabeledPolygon.Builder builder = new LabeledPolygon.Builder();

        try(FileInputStream fis = new FileInputStream(POLYGON_OK_TXT)) {
            builder.read(fis);
        } catch (IOException e) {
            System.out.println("Exception was thrown!");
            e.printStackTrace();
            return;
        }


        paintCross();
        paintPaper(paper);
        paintPolygon(builder.build());
    }

    private void paintCross() {
@@ -128,55 +77,34 @@ public final class Draw extends JFrame {
        graphics.drawLine(HALF_WIDTH, 0, HALF_WIDTH, PANEL_HEIGHT);
    }

    private void paintPaper(Paper paper) {
        for (ColoredPolygon cp : paper.getAllDrawnPolygons()) {
            paintColoredPolygon(cp);
        }
    }
    private void paintPolygon(Polygon polygon) {

        int[] yVertex = new int[polygon.getNumVertices() + 1];
        int[] xVertex = new int[polygon.getNumVertices() + 1];

    private void paintColoredPolygon(ColoredPolygon coloredPolygon) {
        paintPolygon(coloredPolygon.getPolygon(), convertColor(coloredPolygon.getColor()));
        for (int i = 0; i <= polygon.getNumVertices(); i++) {
            xVertex[i] = PANEL_WIDTH - ((int) Math.rint(HALF_WIDTH -
                    polygon.getVertex(i % polygon.getNumVertices()).getX()));
            yVertex[i] = (int) Math.rint(HALF_HEIGHT - polygon.getVertex(i % polygon.getNumVertices()).getY());
        }

    private void paintPolygon(Polygon polygon, Color color) {
        int arraySize = polygon.getNumVertices() + 1;
        int[] yVertex = new int[arraySize];
        int[] xVertex = new int[arraySize];
        graphics.setColor(Color.BLUE);
        graphics.drawPolygon(xVertex, yVertex, polygon.getNumVertices() + 1);

        for (int i = 0; i < arraySize; i++) {
            Vertex2D vertex = polygon.getVertex(i);
            xVertex[i] = PANEL_WIDTH - ((int) Math.rint(HALF_WIDTH - vertex.getX()));
            yVertex[i] = (int) Math.rint(HALF_HEIGHT - vertex.getY());
        }
        if (polygon instanceof LabeledPolygon) {
            LabeledPolygon labeledPolygon = (LabeledPolygon) polygon;

        graphics.setColor(color);
        graphics.drawPolygon(xVertex, yVertex, arraySize);
            graphics.setColor(Color.RED);
            int j = 0;
            int labelDistance = 15;
            for (String label : labeledPolygon.getLabels()) {
                int x = xVertex[j];
                int y = (j % 2 == 0) ? yVertex[j] : yVertex[j] + labelDistance;
                graphics.drawString(label, x, y);
                j++;
            }

    /**
     * Converts enum Color to real color enum.
     *
     * @param color enum specific type
     * @return converted color type
     */
    private Color convertColor(cz.muni.fi.pb112.project.geometry.Color color) {
        switch (color) {
            case WHITE:
                return Color.WHITE;
            case YELLOW:
                return Color.YELLOW;
            case ORANGE:
                return Color.ORANGE;
            case RED:
                return Color.RED;
            case BLUE:
                return Color.BLUE;
            case GREEN:
                return Color.GREEN;
            case BLACK:
                return Color.BLACK;
            default:
                return POLYGON_COLOR;
        }

    }

}
+33 −0
Original line number Diff line number Diff line
package cz.muni.fi.pb112.project.geometry;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;

/**
 * Interface for data import.
 * <p>
 * Data is in the format <code>x y name</code>.
 *
 * @author Radek Oslejsek, Marek Sabo
 */
public interface PolygonReadable {

    /**
     * Read polygon data from input stream.
     *
     * @param is input stream
     * @return the object reading the data
     * @throws IOException on read error
     */
    PolygonReadable read(InputStream is) throws IOException;

    /**
     * Read polygon data from file.
     *
     * @param file input file
     * @return the object reading the data
     * @throws IOException on read error
     */
    PolygonReadable read(File file) throws IOException;
}
Loading