čtvrtek 19. května 2011

ASCII elipsa

Před několika dny mě @xerno_cz poprosil o pomoc s úkolem do školy pro jeho kamarádku. Bohužel se jednalo o program v Delphi, ale řekl jsem si, že to přeci jen zkusím, úkol nebyl těžký a kdysi jsem se učil programovat v Pascalu, takže jsem žádné větší problémy se syntaxí neočekával.


Zadání

Vytvořte program na naplnění a tisk matice znaků o rozměru 25*70. Automatickým plněním vhodnými znaky do matice znázorníte kruh o průměru 1.

Vstup: žádný
Výstup: Tisk matice s pseudografickým obrazem kruhu:


Teorie
Vzhledem k rozměrům matice (70x25) nepůjde tak úplně o kruh, ale spíše o elipsu. Vzorec pro elipsu je v analytické geometrii:






Střed umístíme do středu naší matice, takže bude v matici na souřadnicích [35,12] s tím, že parametry budou a=30 a b=12 (na obrázku to asi přesně takhle není, ale takhle se nám to taky hezky do výpisu vejde).
Pro "vybarvení" i vnitřku elipsy bude stačit, když místo "=" použijeme "<=" - všechny body splňující tuto nerovnici jsou totiž uvnitř elipsy.

Řešení

Nejprve si vytvoříme třídu obsahující všechny proměnné, které budeme potřebovat, společně s konstruktorem. Proměnné centreX a centreY obsahují souřadnice středu, a a b jsou hlavní a vedlejší poloosy elipsy, dvourozměrné pole matrix je samotná matice, do které budeme elipsu vypisovat, a dále tu jsou jen konstanty velikostí matice a RADIUS, abychom ve vzorci elipsy neměli magická čísla.


class AsciiEllipse {
    int centreX, centreY, a, b;
    String[][] matrix;
    final int SIZE_X = 70;
    final int SIZE_Y = 25;
    final int RADIUS = 1;
    
    public AsciiEllipse(){
        this.centreX = 35;
        this.centreY = 12;
        this.a = 30;
        this.b = 12;
        this.matrix = new String[SIZE_Y][SIZE_X];
    }
}


Dále si vytvoříme metodu pro vyplnění celé matice tečkami (kromě prostředního řádku, který bude vyplněn mínusem jako osa). Pokud změníme souřadnice středu, tak se nám osa x bude vždy vypisovat na stejném řádku se středem, pokud tomu chceme zabránit, stačí si na začátku definovat další konstantu označující číslo řádku a místo this.centreY bychom porovnávali proměnnou i s touto konstantou.


public void emptyMatrix(){
    for(int i = 0; i < this.matrix.length; i++)
        for(int j = 0; j < this.matrix[i].length; j++)
            if(i == this.centreY)
                matrix[i][j] = "-";
            else matrix[i][j] = ".";
}


Následně si napíšeme metodu pro vlastní vyplnění obrazce elipsy do matice - stačí dodržet vzorec elipsy, použijeme typy double, protože jsou v tomto případě přesnější než typ int (porovnáváme s jedničkou).


public void fillEllipse(){
    for(int i = 0; i < SIZE_Y; i++){
        for(int j = 0; j < SIZE_X; j++){
            double first = (double)((j - this.centreX) * (j - this.centreX)) / ((this.a) * (this.a));
            double second = (double)((i - this.centreY) * (i - this.centreY)) / ((this.b) * (this.b));
            if((first + second) <= RADIUS)
                this.matrix[i][j] = "+";
        }
    }
}


A teď už zbývá jen metoda pro výpis celé matice - procházíme matici po řádcích  a vypisujeme jednotlivé znaky. Pokud se dostaneme na konec řádku, vypíšeme konec řádku a pokračujeme dalším:


public void drawEllipse(){
    for(int i = 0; i < SIZE_Y; i++){
        for(int j = 0; j < SIZE_X; j++)
            System.out.print(this.matrix[i][j]);
        System.out.println();
    }
}


A nakonec samotná aplikace, která vytváří objekt třídy AsciiEllipse a volá její metody:


public class AsciiEllipseApplication {
    public static void main(String[] args){
        AsciiEllipse elipse = new AsciiEllipse();
        elipse.emptyMatrix();
        elipse.fillEllipse();
        elipse.drawEllipse();
    }
}


Tento program by se dal určitě vylepšit například vypisováním elipsy "zrcadlově" podle středu - pak by stačilo projít jen polovinu cyklu, a nikoli celý cyklus, nebo ještě lépe, vypsat jen čtvrtinu a tu zrcadlově otočit - tím bychom měli vypsánu celou polovinu elipsy. Tu bychom opět zrcadlově otočili a elipsa by byla celá, zbývalo by jen do okolí doplnit tečky..

A už by chybělo jen vypisovat souřadnice a osy, což je jednoduché, každý řádek má určité číslo, které stačí vypsat ještě před samotným řádkem - buď úpravou metody na výpis matice, nebo třeba vytvořením o kus větší matice, kde by tyto souřadnice byly, a do zbytku bychom vložili již námi vytvořenou elipsu..

Žádné komentáře:

Okomentovat