Prezentowane materiały są przeznaczone dla uczniów szkół ponadgimnazjalnych. Autor artykułu: mgr Jerzy Wałaszek, wersja1.0 |
©2010 mgr
Jerzy Wałaszek |
Zanim przystąpisz do tej lekcji, zapoznaj się z poprzednimi lekcjami:
Wstęp do grafiki - biblioteki SDL i newgfx
Opis
biblioteki newgfx
Dzisiaj zajmiemy się rysowaniem linii, z których będziemy stopniowo tworzyć różne figury geometryczne. Uruchom środowisko Code::Blocks i utwórz w nim projekt SDL z szablonu - jak to zrobić, dokładnie opisaliśmy w poprzedniej lekcji i nie będziemy tych wiadomości więcej powtarzać.
Na początek stworzymy taki oto rysunek:
Rysunek ten tworzy pęk linii, które wychodzą z lewego górnego narożnika ekranu i biegną do punktów leżących na dolnej krawędzi. Punktów tych jest N i są one w równych odległościach od siebie. Pierwszym problemem będzie wyznaczenie współrzędnych tych punktów. Posłużymy się w tym celu prostą proporcją:
gdzie:
n | - liczba wszystkich punktów |
i | - numer punktu, i = 0,1,...,n-1 |
w | - szerokość okna graficznego w pikselach |
xi | - współrzędna x i-tego punktu |
Zatem i-ta linia biegnie od punktu 0,0 (lewy górny narożnik okna graficznego) do punktu xi,h-1, gdzie h to wysokość okna graficznego w pikselach.
Wpisz do szablonu następujący fragment programu (pod komentarzem):
// tutaj wstawiamy program graficzny const Sint32 N = 20; // liczba punktów Sint32 i, x; for(i = 0; i < N; i++) { x = i * (screen->w - 1) / (N - 1); gfxLine(screen, 0, 0, x, screen->h - 1, 0xffffff); } |
Zmodyfikuj program, aby otrzymać następującą grafikę:
A teraz tak:
Poeksperymentuj z kolorem (składowe koloru można zmieniać w zależności od i - tutaj również przydaje się proporcja).
// tutaj wstawiamy program graficzny const Sint32 N = 20; // liczba punktów Sint32 i, x, r, g, b, c; for(i = 0; i < N; i++) { x = i * (screen->w - 1) / (N - 1); // współrzędna xi r = i * 255 / (N - 1); // składowa czerwona g = 255 - i * 255 / (N - 1); // składowa zielona b = 255; // składowa niebieska c = (r << 16) | (g << 8) | b; // kolor linii gfxLine(screen, 0, 0, x, screen->h - 1, c); gfxLine(screen, screen->w-1, 0, x, screen->h - 1, c); gfxLine(screen, 0, screen->h-1, x, 0, c); gfxLine(screen, screen->w-1, screen->h-1, x, 0, c); } |
Zamiast funkcji gfxLine() wykorzystaj funkcję gfxWuLine(). Działa ona identycznie. Różnica polega na tym, iż gfxWuLine() używa algorytmu wygładzania opracowanego przez profesora Xiaolin Wu. Linie wyglądają dużo lepiej.
Kolejna grafika powinna wyglądać następująco:
Na pierwszy rzut oka wygląda to dosyć skomplikowanie. A robimy to tak:
Wzdłuż lewej i dolnej krawędzi ekranu wyznaczamy n punktów. Wykorzystujemy do tego znaną nam proporcję:
gdzie:
n | - liczba wszystkich punktów |
i | - numer punktu, i = 0,1,...,n-1 |
w | - szerokość okna graficznego w pikselach |
h | - wysokość okna graficznego w pikselach |
xi | - współrzędna x i-tego punktu |
yi | - współrzędna y i-tego punktu |
Następnie łączymy odcinkami kolejno pierwszy punkt na lewej krawędzi z pierwszym punktem na krawędzi dolnej, drugi punkt na lewej krawędzi z drugim punktem na krawędzi dolnej itd:
// tutaj wstawiamy program graficzny const Sint32 N = 20; // liczba punktów Sint32 i, x, y; for(i = 0; i < N; i++) { x = i * (screen->w - 1) / (N - 1); y = i * (screen->h - 1) / (N - 1); gfxLine(screen, 0, y, x, screen->h - 1, 0xffffff); } |
Zmodyfikuj program, tak aby otrzymać kolejno poniższe grafiki:
Problem rysowania kwadratów i prostokątów rozwiązuje nasza biblioteka, w której mamy odpowiednią do tego celu funkcję:
gfxRect(s, r, c)
s - wskaźnik do struktury SDL_Surface
r - wskaźnik do struktury SDL_Rect
c - kolor prostokąta
Struktura SDL_Rect definiuje prostokąt i ma następującą postać:
typedef struct { Sint16 x, y; // współrzędne lewego, górnego narożnika prostokąta Uint16 w, h; // szerokość i wysokość prostokąta w pikselach } SDL_Rect;
Poniższy program rysuje ramkę o rozmiarze okna graficznego:
// tutaj wstawiamy program graficzny SDL_Rect * r = new SDL_Rect; r->x = r->y = 0; r->w = screen->w; r->h = screen->h; gfxRect(screen, r, 0xffffff); |
Przez prostą modyfikację tego programu można uzyskać ciekawy efekt:
// tutaj wstawiamy program graficzny SDL_Rect * r = new SDL_Rect; Sint32 c,i; r->x = r->y = 0; r->w = screen->w; r->h = screen->h; for(i = 1; i < screen->h; i += 2) { c = 255 - i * 255 / (screen->h - 1); c = (c << 16) | (c << 8) | c; gfxRect(screen, r, c); r->x++; r->y++; r->w -= 2; r->h -= 2; } |
Napisz samodzielnie programy, które rysują następujące grafiki:
Rysowanie wielokątów rozwiązujemy następująco za pomocą funkcji gfxMoveTo() i gfxLineTo():
Wyznaczamy współrzędne kolejnych wierzchołków.
Pierwszy wierzchołek jest wierzchołkiem startowym. Przekazujemy go do funkcji gfxMoveTo(), która zapamiętuje jego współrzędne.
Kolejne wierzchołki przekazujemy do funkcji gfxLineTo(), która rysuje linie od poprzedniego punktu do punktu otrzymanego jako parametr. Poprzedni punkt jest punktem przekazanym do gfxMoveTo() lub do gfxLineTo().
Od ostatniego wierzchołka rysujemy linię do wierzchołka pierwszego.
Poniższy program rysuje trójkąt:
// tutaj wstawiamy program graficzny gfxMoveTo(0,screen->h-1); // pierwszy wierzchołek gfxLineTo(screen,screen->w/2,0,0xffffff); // drugi wierzchołek gfxLineTo(screen,screen->w-1,screen->h-1,0xffffff); // trzeci wierzchołek gfxLineTo(screen,0,screen->h-1,0xffffff); // pierwszy wierzchołek |
Wielokąty foremne otrzymujemy w sposób następujący:
Bierzemy okrąg o promieniu r i środku w punkcie xs,ys.
Na obwodzie okręgu wyznaczamy w równych od siebie odległościach n punktów.
Punkty łączymy liniami wg zasad opisanych powyżej. Podstawowym problemem jest tutaj wyznaczenie współrzędnych tych punktów. Zadanie to rozwiążemy prosto wykorzystując podstawowe wiadomości z geometrii. Na początek załóżmy, że środek okręgu jest w początku układu współrzędnych.
Dla każdego punktu leżącego na takim okręgu zachodzą następujące zależności:
gdzie
αP | - kąt pomiędzy osią OX, a promieniem r poprowadzonym do punktu P |
r | - promień okręgu |
xP | - współrzędna x punktu P |
yP | - współrzędna y punktu P |
Znając kąt αP, możemy bez problemów wyznaczyć współrzędne punktu:
Jeśli punkty są umieszczone na obwodzie okręgu w równych odległościach, to kąty pomiędzy ich promieniami są również równe i wynoszą:
Mając dany kąt αP dla pierwszego punktu, pozostałe kąty obliczymy dodając kolejno nasze α. Zatem wzory na współrzędne kolejnych punktów są następujące:
gdzie i = 0,1,...,n-1
Współrzędne te odnoszą się do przypadku, gdy środek okręgu znajduje się w środku układu współrzędnych. Jeśli środek okręgu jest w innym punkcie, to po prostu do wyliczonych współrzędnych dodajemy współrzędne środka okręgu. Nasze wzory przyjmują ostateczną postać:
W poniższym programie należy dołączyć na początku plik nagłówkowy cmath (dla funkcji trygonometrycznych). Program rysuje wielokąty foremne z punktów na obwodzie okręgu o promieniu równym połowie wysokości okna graficznego. Środek okręgu jest umieszczony w środku tego okna. Kat αP przyjmujemy zerowy i nie uwzględniamy go we wzorach (zrobimy to za chwilę w innym programie).
#include <cmath> ... // tutaj wstawiamy program graficzny const Sint32 N = 3; // określa liczbę wierzchołków wielokąta Sint32 i,x,y,xp,yp,r; xp = screen->w / 2; yp = screen->h / 2; r = screen->h / 2; for(i = 0; i <= N; i++) { x = xp + r * cos(i * 6.283185 / N); y = yp + r * sin(i * 6.283185 / N); if(!i) gfxMoveTo(x,y); // pierwszy punkt else gfxLineTo(screen,x,y,0xffffff); } |
Zmieniając stałą N otrzymujemy różne wielokąty foremne. Zwróć uwagę, iż ze wzrostem N figura coraz bardziej przypomina okrąg.
N = 3 | N = 4 | N = 5 |
N = 6 | N = 8 | N = 12 |
Manipulując promieniem r możemy otrzymywać ciekawe efekty graficzne:
#include <cmath> ... // tutaj wstawiamy program graficzny const Sint32 N = 3; // określa liczbę wierzchołków wielokąta Sint32 i,x,y,xp,yp,r; xp = screen->w / 2; yp = screen->h / 2; for(r = 8; r <= screen->h / 2; r += 8) for(i = 0; i <= N; i++) { x = xp + r * cos(i * 6.283185 / N); y = yp + r * sin(i * 6.283185 / N); if(!i) gfxMoveTo(x,y); // pierwszy punkt else gfxLineTo(screen,x,y,0xffffff); } |
N = 3 | N = 6 | N = 15 |
Jeśli w trakcie rysowania kolejnych figur będziemy dodatkowo zmieniali kat pierwszego punktu, to otrzymamy bardzo ciekawy efekt graficzny:
#include <cmath> ... // tutaj wstawiamy program graficzny const Sint32 N = 3; // określa liczbę wierzchołków wielokąta Sint32 i,x,y,xp,yp,r; double alpha; xp = screen->w / 2; yp = screen->h / 2; for(r = 8; r <= screen->h / 2; r += 8) { alpha = 3.1415 * r / (screen->h / 2); for(i = 0; i <= N; i++) { x = xp + r * cos(alpha + i * 6.283185 / N); y = yp + r * sin(alpha + i * 6.283185 / N); if(!i) gfxMoveTo(x,y); // pierwszy punkt else gfxLineTo(screen,x,y,0xffffff); } } |
N = 3 | N = 4 | N = 5 |
Kolejna możliwość to cykliczne wyznaczanie punktów wielokąta, jednakże przy każdym punkcie zwiększamy (zmniejszamy) promień r. W rezultacie otrzymujemy spiralę.
#include <cmath> ... // tutaj wstawiamy program graficzny const Sint32 N = 3; // okresla liczbę wierzchołków wielokata Sint32 i,x,y,xp,yp,r; xp = screen->w / 2; yp = screen->h / 2; i = 0; for(r = 1; r <= screen->h / 2; r += 4) { x = xp + r * cos(i * 6.283185 / N); y = yp + r * sin(i * 6.283185 / N); if(!i) gfxMoveTo(x,y); // pierwszy punkt else gfxLineTo(screen,x,y,0xffffff); i++; } |
N = 3 | N = 4 | N = 9 |
Skoki tych spiral zależą od ilości wierzchołków w wielokącie - im jest ich więcej, tym szybciej rośnie promień r i skok się zwiększa. Zastanów się nad takim przerobieniem algorytmu, aby spirale posiadały zadaną liczbę zwoi. Sprawdź również wygląd figur, gdy funkcję gfxLineTo() zamieni się na gfxWuLineTo(), która rysuje linie wygładzone.
I Liceum Ogólnokształcące |
Pytania proszę przesyłać na adres email: i-lo@eduinf.waw.pl
W artykułach serwisu są używane cookies. Jeśli nie chcesz ich otrzymywać,
zablokuj je w swojej przeglądarce.
Informacje dodatkowe