Stránka sa načítava, prosím čakajte…
© 2005 – 2024 Roman Horváth, všetky práva vyhradené. Dnes je 4. 5. 2024.
Dátum: 22. 2. 2013, pred viacerými rokmi, aktualizované: 31. 7. 2020, pred štyrmi rokmi
Zadanie
Vyriešte kreslenie dvoch alternatív obrázka paprade alebo kreslenie vločky a praskliny podľa predlohy s pomocou rekurzie.
a) | b) |
Obrázok a) zobrazuje papraď bez akýchoľvek úprav. Na obrázku b) je použitý špeciálny efekt, ktorého vytvorenie ukazuje tento príklad.
Papraď nakreslíme s pomocou rekurzívnej metódy ako strom, ktorá vo svojom tele tri razy spustí samú seba (to na dosiahnutie vetvenia paprade, ktoré zabezpečíme tak, aby vetvy boli kreslené s miernym odstupom od seba, aby sme sa priblížili botanike papradí). Tajomstvo je vo vhodnom zvolení uhlov, poklesu dĺžky a úpravy hrúbky čiary v závislosti od stupňa rekurzie (určeného dĺžkou).
~
public class Papraď extends GRobot { private Papraď() { // Úvodné nastavenia sveta: super(300, 500, "Papraď"); Svet.zbaľ(); Svet.nekresli(); // Nastavenia robota: skry(); skoč(-30, -230); // Nastavenie farby na mierne priesvitný tmavozelený odtieň // (červená zložka = 0, zelená = 100, modrá = 20, priesvitnosť = 250, // čo znamená asi 98 % z úplnej nepriehľadnosti farby): farba(0, 100, 20, 250); // O zvyšok sa postará rekurzia: segment(60); Svet.kresli(); } private void segment(double dĺžka) { if (dĺžka > 2) { hrúbkaČiary(dĺžka / 8); dopredu(dĺžka * 0.9); doprava(30); segment(dĺžka / 2); doľava(30); hrúbkaČiary(dĺžka / 8); dopredu(dĺžka * 0.1); doľava(30); segment(dĺžka / 2); doprava(30); doprava(4 - dĺžka / 10); segment(dĺžka * 0.88); doľava(4 - dĺžka / 10); dozadu(dĺžka); } } public static void main(String[] args) { new Papraď(); } }
Poznámka (31. 7. 2020): Na to, aby bol tento kód funkčný aj s najnovšou verziou programovacieho rámca GRobot stačí na začiatok kódu pridať:
~
import knižnica.*;
Všetky zmeny vykonáme v konštruktore.
~
private Papraď() { super(300, 500, "Papraď"); Svet.zbaľ(); Svet.nekresli(); skry(); skoč(-30, -230); // Do tohto miesta zostal konštruktor bezo zmien. // Teraz budeme opakovane kresliť celú papraď a vzápätí // vrstviacu sa kresbu rozmazávať. // Tým dosiahneme efekt „žiary“ okolo paprade. Kesliť // budeme zelenou farbou s priehľadnosťou úrovne 40 (čo // je asi 16 %). farba(0, 100, 20, 40); // Potom osemkrát zopakujeme nakreslenie paprade // a rozmazanie obsahu plátna. Rozmazanie sa bude // v každej iterácii kumulovať. Tak vznikne efekt // podobný žiare… (Ak by sme po tomto cykle program // zastavili, videli by sme niečo ako rozmazanú // papraď. To sme chceli dosiahnuť.) for (int i = 0; i < 8; ++i) { segment(60); podlaha.rozmaž(3); } // Nakoniec nakreslíme poslednú nerozmazanú papraď. // K detailom a vernejšiemu rastlinnému vzhľadu stonky // (i celej paprade) prispeje úroveň priesvitnosti 150 // (čo je asi 60 %). V tomto prípade si môžeme dovoliť // takto znížiť úroveň priehľadnosti, pretože na plátne // už je prítomná kresba vytvorená z viacerých // priehľadných papradí. K nej sa táto posledná // kresba paprade s výhodou pridá. Vďaka tomu budú // zároveň miesta, kde sa dve čiastočne priehľadné // čiary prekryjú tmavšie. farba(0, 100, 20, 150); segment(60); Svet.kresli(); }
Nasledujúci obrázok a) zobrazuje vločku, ktorú môžeme vnímať ako dokonale symetrickú „prasklinu,“ ale je prakticky nulová šanca, že by niekde vo vesmíre taká prasklina vznikla – určite nie na prirodzene vytvorenom materiáli. Obrázok b) ukazuje prasklinu nakreslenú tým istým algoritmom ako vločka, len s pridaním náhodnosti.
|
a) | b) |
Vločka bude pozostávať zo šiestich cípov (segmentov).
~
public class Vločka extends GRobot { // Počiatočné definície konštánt private final static double uhol1 = 55; private final static double uhol2 = 20; private final static double posuv = 2; // Konštruktor public Vločka() { // Úvodné nastavenia super(450, 450); Svet.zbaľ(); Svet.nekresli(); skry(); // Nastavenie vhodnej farby farba(40, 40, 40, 200); // Kreslenie cípov (segmentov) for (int i = 0; i < 6; ++i) { segment(110); doprava(60); } Svet.kresli(); } // Rekurzívna metóda public void segment(int fáza) { if (fáza > 0) { zdvihniPero(); dopredu(posuv); if (0 == fáza % 2) { doprava(uhol1); segment(fáza - 1); doprava(uhol2); segment(fáza / 6); doľava(uhol2); doľava(uhol1); } else { doľava(uhol1); segment(fáza - 1); doľava(uhol2); segment(fáza / 6); doprava(uhol2); doprava(uhol1); } položPero(); dozadu(posuv); } } public static void main(String[] args) { new Vločka(); } }
Poznámka (31. 7. 2020): Na to, aby bol tento kód funkčný aj s najnovšou verziou programovacieho rámca GRobot stačí na začiatok kódu pridať:
~
import knižnica.*;
Prasklinu nakreslíme tým istým algoritmom ako vločku, ibaže uhly a posun budú náhodné. (Samozrejme, že z toho vyplýva, že výsledok bude pri každom spustení iný a obrázok vyššie je len jednou z nekonečného množstva variánt.)
~
public class Prasklina extends GRobot { public Prasklina() { // Úvodné nastavenia super(450, 450); Svet.zbaľ(); Svet.nekresli(); skry(); // Nastavenie vhodnej farby farba(80, 40, 0, 40); // Kreslenie cípov (segmentov) for (int i = 0; i < 6; ++i) { segment(110); doprava(60); } Svet.kresli(); } // Rekurzívna metóda public void segment(int fáza) { if (fáza > 0) { // Náhodné čísla pre uhly a posun musíme vygenerovať vopred // a zapamätať si ich pre každé spustenie tejto metódy zvlášť // (preto sú tieto premenné definované lokálne)! Inak by sme sa // nevedeli vrátiť na správnu pozíciu a otočiť naspäť o správny // uhol! double uhol1 = Svet.náhodnéReálneČíslo(55, 65); double uhol2 = Svet.náhodnéReálneČíslo(20, 30); double posuv = Svet.náhodnéReálneČíslo(1.5, 3.0); hrúbkaČiary(1.5); dopredu(posuv); if (0 == fáza % 2) { doprava(uhol1); segment(fáza - 1); doprava(uhol2); segment((int)Svet.náhodnéCeléČíslo(0, fáza / 4)); doľava(uhol2); doľava(uhol1); } else { doľava(uhol1); segment(fáza - 1); doľava(uhol2); segment((int)Svet.náhodnéCeléČíslo(0, fáza / 4)); doprava(uhol2); doprava(uhol1); } hrúbkaČiary(1); dozadu(posuv); } } public static void main(String[] args) { new Prasklina(); } }
Poznámka (31. 7. 2020): Na to, aby bol tento kód funkčný aj s najnovšou verziou programovacieho rámca GRobot stačí na začiatok kódu pridať:
~
import knižnica.*;