TlačiťTlačiť Slovenčina English Hľadať RSS

© 2005 – 2024 Roman Horváth, všetky práva vyhradené. Dnes je 25. 4. 2024.

Stránka sa načítava, prosím čakajte…

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.

obrázok obrázok
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 otvárané v novom okne
(obvykle ide o externý odkaz) 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.

obrázok |obrázok

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 otvárané v novom okne
(obvykle ide o externý odkaz) 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 otvárané v novom okne
(obvykle ide o externý odkaz) stačí na začiatok kódu pridať:

~

import knižnica.*;