Korytnačia grafika

Čo je korytnačia grafika

Doteraz sme do grafickej plochy kreslili príkazmi:

MoveTo(X, Y);
LineTo(X, Y);
Rectangle(X1, Y1, X2, Y2);
Ellipse(X1, Y1, X2, Y2);

Tie pracovali s absolútnymi súradnicami. Dá sa kresliť aj iným - relatívnym spôsobom. Na kreslenie použijeme špeciálne grafické pero - korytnačku. Predstave si korytnačku, ktorá sa prechádza po piesočnatej pláži a v piesku zanecháva stopu. To, čo korytnačka v piesku nakreslí, uvidíme na obrazovke. Korytnačka sa hýbe dopredu a občas sa otočí vľavo alebo vpravo.

Grafickú korytnačku možno:

* otáčať o zadaný uhol smerom vľavo alebo vpravo
* presúvať dopredu o určenú vzdialenosť v smere, v ktorom je práve natočená.

Príklad: Nasledujúce príkazy nakreslia štvorec:

Dopredu(100); // choď dopredu 100 krokov
Vlavo(90); // otoč sa vľavo o 90 stupňov
Dopredu(100);
Vlavo(90);
Dopredu(100);
Vlavo(90);
Dopredu(100);

To isté dosiahneme aj cyklom:

for (int i=0; i<4; i++) {
Dopredu(100);
Vlavo(90);
}


Korytnačia knižnica

Príkazy korytnačej grafiky nie sú štandardnou súčasťou C++, a preto ich musíme naprogramovať. Korytnačku zadefinujeme ako objektovú triedu. Budeme ju často používať, a preto vytvoríme vlastnú knižnicu s názvom Kor.cpp. V programoch ju použijeme podobne, ako iné knižnice - príkazom #include "Kor.cpp".

1. Vytvoríme nový "C-éčkový" súbor (príkazom z hlavnej ponuky C++Buildera: File | New ... | CPP file ) a uložíme ho pod názvom Kor.cpp.

2. V ňom naprogramujeme triedu TKor:
#include <vcl.h>
#include <math.h>

class TKor {
private:
float Smer; // smer natočenia korytnačky (0 stupňov je hore)
float X, Y; // poloha korytnačky v obrázku
TImage * Image; // obrázok, do ktorého korytnačka kreslí
public:
void Inic(TImage * nImage); // inicializácia korytnačky
void ZmenSmer(float nSmer); // absolútna zmena smeru korytnačky
void ZmenXY(float nX, float nY); // absolútna zmena polohy
void Vlavo(float Uhol); // otočí korytnačku vľavo o zadaný uhol
void Vpravo(float Uhol); // otočí korytnačku vpravo o zadaný uhol
void Dopredu(float Dlzka); // pohne korytnačku dopredu o určenú dĺžku
void vl(float Uhol); // skratka príkazu Vlavo
void vp(float Uhol); // skratka príkazu Vpravo
void dp(float Dlzka); // skratka príkazu Dopredu
};

3. Korytnačka sa inicializuje tak, aby bola umiestnená v strede grafickej plochy a otočená smerom nahor:

void TKor::Inic(TImage * nImage) {
Image=nImage;
Smer=0;
X=Image->Width/2;
Y=Image->Height/2;
}

Metóda ZmenSmer nastaví smer korytnačky. Chceme, aby Smer Î <-180,180>:

void TKor::ZmenSmer(float nSmer) {
if (Smer==nSmer) return;
Smer=nSmer;
while (Smer<-180) Smer=Smer+360;
while (Smer>+180) Smer=Smer-360;
}

Metóda ZmenXY presunie korytnačku na nové súradnice na obrazovke. Navyše, ak korytnačka kreslí čiary (pero je dolu), ZmenXY nakreslí čiaru do tohto nového bodu:

void TKor::ZmenXY(float nX, float nY) {
if (X==nX && Y==nY) return;
Image->Canvas->MoveTo(X+0.5, Y+0.5);
Image->Canvas->LineTo(nX+0.5, nY+0.5);
X=nX;
Y=nY;
}

V premenných X, Y sú reálne čísla, ale príkazy MoveTo a LineTo pracujú s celými číslami. Ak sa má vykonať LineTo(1.8, 1.1), koniec úsečky bude ležať v bode (1, 1) a nie v bode (2, 1), ktorý je k uvedeným súradniciam "bližšie". Pripočítaním +0.5 získame zaokrúhlené celé číslo (1.8+0.5=2.3 ... po konverzii konverzii =2, zatiaľ čo 1.1+0.5=1.6 ... po konverzii konverzii =1). Pozor, táto "finta" funguje iba pre kladné čísla.

4. Nasledujúcimi metódami riadime relatívny pohyb korytnačky:

void TKor::Vlavo(float Uhol) {
ZmenSmer(Smer-Uhol);
}

void TKor::Vpravo(float Uhol) {
ZmenSmer(Smer+Uhol);
}

void TKor::Dopredu(float Dlzka) {
float a;
a=Smer/180*M_PI;
ZmenXY(X+Dlzka*sin(a), Y-Dlzka*cos(a));
}

5. Korytnačku "naučíme" aj príkazové skratky - napríklad, príkaz Vlavo bude mať skratku vl:
void TKor::vl(float Uhol) {
Vlavo(Uhol);
};
Pretože tieto metódy sú jednoduché, ich telá môžeme napísať aj priamo v definícii triedy:
class TKor {
private:
...
public:
...
void vl(float Uhol) {Vlavo(Uhol);};
void vp(float Uhol) {Vpravo(Uhol);};
void dp(float Dlzka) {Dopredu(Dlzka);};
};

Programovanie metód priamo v definícii triedy robievame v C++ iba výnimočne a obozretne, pretože tým môžeme skomplikovať čitateľnosť programu.

6. V kompletnej knižnici Kor.cpp má trieda TKor nasledujúce vylepšenia:

* metóda ZmenHrubku(int nHrubka) nastaví hrúbku čiary, ktoré korytnačka kreslí;
* metóda ZmenFarbu(TColor nFarba) nastaví farbu čiary
* metóda PeroHore() korytnačka prestane kresliť (až pokým nezavoláme PeroDolu);
* metóda PeroDolu() korytnačka položí pero na papier a pri pohybe bude kresliť čiary;
* metóda Smerom(float aX, float aY) vráti uhol k bodu aX, aY;
* vlastnosť Smer;
* vlastnosti X, Y.


Príklady s korytnačkou

Keď potrebujeme v projekte používať korytnačiu grafiku, skopírujeme súbor Kor.cpp do adresára (priečinku) projektu a kompilátoru oznámime, že používame našu knižnicu Kor.cpp:

#include <vcl.h>
#pragma hdrstop

#include "Unit.h"
#include "Kor.cpp"
//-------------------------------------- ----------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;

//-------------------------------------- ----------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//-------------------------------------- ----------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
TKor k;
k.Inic(Image1);
int i;
for (i=0; i<3; i++) {
k.dp(100);
k.vl(120);
}
}

Pre pokročilých:

*

Príkazom #include "Kor.cpp" oznámime kompilátoru, že programe používa knižnicu Kor.cpp, ktorá je umiestnená v rovnakom adresári ako projekt.
*

Potom, pri kompilácii programu, sa v pamäti počítača nahradí #include "Kor.cpp" (aj ostatné #include...) textom zo súboru Kor.cpp. To má za úlohu špeciálna časť prekladača, ktorá sa nazýva preprocesor. Až potom sa celý, takto zostavený program, skompiluje.
* Profesionálni programátori vytvárajú knižnice aj iným spôsobom:
o

namiesto celého "C-čkového" programu z knižnice sa príkazom #include vloží iba hlavičkový súbor (anglicky: header) knižnice. Hlavičkový súbor máj koncovku *.h a väčšinou obsahujú iba definície štruktúr, hlavičky funkcií (tzv. prototypy funkcií) a definície tried.
o

Naprogramované telá funkcií a metód sú uložené v samostatnom súbore s koncovkou *.cpp. Pri prvej kompilácii projektu sa skompilujú všetky *.cpp súbory prislúchajúce jednotlivým knižniciam, z ktorých vzniknú *.obj súbory. Pri ďalších kompiláciách sa *.cpp súbory už nekompilujú (teda, pokým sa nezmenil ich obsah), čim sa šetrí čas potrebný na kompilovanie celého programu.

ukážka programu s profesionálnou knižnicou.


Ďalšie príklady s korytnačkou

Zmením telo funkcie FormCreate:

1. Uhádnite, čo sa nakreslí:

for (int i=1; i<=6; i++) {
k.dp(50);
k.vp(60);
}

2. Uhádnite, čo sa nakreslí:

for (i=1; i<=360; i++) {
k.dp(1);
k.vl(1);
}

NDÚ: Nakreslite pravidelný n uholník s dĺžkou strany a.

4. Kreslenie s viacerými korytnačkami:

TKor k[10];
int i, n;
for (i=0; i<10; i++) {
k[i].Inic(Image1);
k[i].ZmenSmer(i*360/10);
}
for (n=1; n<=20; n++)
for (i=0; i<10; i++) {
k[i].dp(n);
k[i].vl(n);
}