WOJSKOWA AKADEMIA TECHNICZNA
Laboratorium z przedmiotu
Grafika komputerowa
SPRAWOZDANIE
Laboratorium nr 1
Wykonanie: Justyna Kozon
Grupa: I9X5S1
Data wykonania ćwiczenia:18.11.2010
Treść wykonywanych zadań.
Zestaw 15.
1. Napisać algorytm sterujący generatorem adresu odczytu w celu uzyskania efektu
przesuwania obrazu wzdłuż przekątnej ekranu w kierunku dolnego prawego
wierzchołka.
2. Napisać algorytm sterujący generatorem adresu odczytu w celu uzyskania efektu
zasłaniania poziomego obrazu w kierunku lewej krawędzi ekranu.
3. Napisać algorytm sterujący generatorem adresu odczytu w celu uzyskania efektu
przesuwania obrazu wzdłuż przekątnej ekranu w kierunku dolnego lewego wierzchołka.
Wstęp teoretyczny.
Aby rozwiązać to zadanie należy wiedzieć w jaki sposób działa urządzenie rastrowe. Generuje ono piksele obrazu nie w dowolnej kolejności, ani nawet w takiej w jakiej życzyłby sobie użytkownik lub programista, ale w kolejności wcześniej ustalonej i niezmiennej. Mianowicie obraz generowany jest piksel po pikselu od lewej strony do prawej i wierszami w kierunku dolnej krawędzi ekranu. Gdy zostanie wygenerowany ostatni piksel (w prawym dolnym rogu) następuje przejście do początku wyświetlania i rozpoczyna się proces tworzenia kolejnej klatki. Programista może jedynie sterować generatorem adresu odczytu i dzięki temu decydować jakiej barwy piksel pojawi się na kolejnym miejscu, które będzie wyświetlało urządzenie rastrowe.
W dostępnym dla nas symulatorze efektów mamy dostępne dwie funkcje, które umożliwiały nam wykonanie przeznaczonych dla nas zadań:
-ReadPixel(i, j); - wybiera piksel o współrzędnych (i, j) z mapy obrazu wczytanego do programu
-ReadTlo(N); - rysuje piksel czarny.
Mapa obrazu jest mapą bitową i posiada następujące współrzędne:
j → <1;L> - numer wiersza
i → <1;K> - numer kolumny.
Odczytywanie przykładowego piksela wygląda w następujący sposób:
W programie używamy także zmiennej p, która jest aktualnym przesunięciem obrazu (w każdej klatce obraz przesunięty jest o p pikseli w daną stronę). Gdy p=0 mamy do czynienia z obrazem niezmienionym. Z każdą klatką p jest zwiększane o 1 i obraz powoli się przesuwa.
Sposoby rozwiązania zadań i kody źródłowe.
-- algorytm sterujący generatorem adresu odczytu w celu uzyskania efektu
przesuwania obrazu wzdłuż przekątnej ekranu w kierunku dolnego prawego
wierzchołka.
W rozwiązaniu tego zadania przydatny będzie rysunek pomocniczy:
Mamy na nim wyróżnione 4 obszary: A, B, C i D. Obszary A i B symbolizują nasz obraz, który przesuwamy, natomiast obszary C i D fragmenty tła.
Analizę najłatwiej rozpocząć od obszaru A. Musimy określić jego wielkość oraz wartości pikseli, które zostaną odczytane z pamięci obrazu i wyświetlone. Jak widać poziomo obszar A zajmuje K-p pikseli (czyli jest to ilość wszystkich pikseli w linii minus te już przesunięte). Odczytywać będziemy od 1 piksela obrazu, gdyż lewy górny róg obszaru A jest lewym górnym rogiem obrazu z pamięci. Podobnie wygląda sytuacja w pionie, z jedną tylko różnicą, że zajmuje on w pionie L-p pikseli (L jest liczbą wierszy obrazu).
Następnie przechodzimy do analizy obszaru B. Jest to przesunięta część obrazu z pamięci. Zajmuje ona obszar o rozmiarze p x p. Aby określić odczytywane piksele w pionie musimy sobie wyobrazić, który to będzie fragment naszego rysunku.
Widać teraz, że w poziomie odczytywane piksele zaczynają się od miejsca zakończenia odczytywania pikseli w poziomie obszaru A, a kończą wraz z końcem linii. Analogiczna jest sytuacja w pionie. Wynika z tego, że poziomo granice B wyglądają następująco: K-p+1→K, a pionowo L-p+1→L.
Kolejny obszar to obszar C. Widać z rysunku pomocniczego, że poziomo jego granice wyglądają tak jak granice poziome obszaru A, a pionowo tak jak granice pionowe obszaru B. Jednak dla ułatwienia granicę poziomą możemy określić jako 1→p, ponieważ wiemy, że taką wysokość mają obszary B i C (ze względu na to, że odczytywać będziemy piksele tła mniej ważne jest, z których pikseli obrazu zostaną odczytane, ważna jest ich ilość).
W przypadku obszaru D widzimy, że ma on taką wysokość jak obszar A i szerokość p. Rysunek pomocniczy z naniesionymi granicami obszarów wygląda następująco:
W tym momencie mamy już wszystko, aby określić odpowiednio nasze pętle for, którymi będziemy się posługiwać do zrealizowania postawionego zadania. Zewnętrzna pętla związana będzie z wierszami, a wewnętrzne z obszarami ograniczonymi danymi wierszami. Kod źródłowy wygląda następująco:
public void Efekt1()
{ //efekt: przewijanie obrazu wzdłuż przekątnej w kierunku dolnego prawego wierzchołka
if (p >= L) p = 0;
for (int j = L - p + 1; j <= L; j++)
{
for (int i = K - p + 1; i <= K; i++)
ReadPixel(i, j);
for (int i = 1; i <= K - p; i++)
ReadTlo(N);
}
for (int j = 1; j <= L - p; j++)
{
for (int i = 1; i <= p; i++)
ReadTlo(N);
for (int i = 1; i <= K - p; i++)
ReadPixel(i, j);
}
}
Efekty wykonania kodu:
- algorytm sterujący generatorem adresu odczytu w celu uzyskania efektu
zasłaniania poziomego obrazu w kierunku lewej krawędzi ekranu.
Rysunek pomocniczy:
Obszar A jest to nasz obraz w pamięci i w tym przypadku nie będzie się on poruszał. Zwiększać się będzie jedynie obszar B, który będzie „nachodził” z lewej strony na obszar A. W tym przypadku analiza obszarów jest prostsza.
Obszar A pionowo zajmuje wszystkie piksele obrazu zatem od 1→L. Taką samą wysokość na obszar B. Poziomo widać, że A zajmuje od 1→K-p pikseli i w miarę zwiększania p zmniejsza się. Obszar B poziomo zajmuje p pikseli.
Obraz z naniesionymi granicami wygląda następująco:
Konstruując pętle for możemy zwrócić uwagę, że można odrobinę skrócić kod programu określając obszary w poziomie za pomocą instrukcji if(); Zgodnie z tą myślą mamy: jeśli współrzędna ‘i’ jest mniejsza lub równa K-p odczytujemy obrazek, w przeciwnym wypadku odczytujemy piksele tła. Oto kod źródłowy programu:
public void Efekt2()
{
//efekt: zasłanianie poziome obrazu w kierunku lewej krawędzi
if (p >= L) p = 0;
for (int j = 1; j <= L; j++)
{
for (int i = 1; i <= K; i++)
{
if (i <= K - p) ReadPixel(i, j);
else ReadTlo(N);
}
}
}
Efekty wykonania kodu:
- algorytm sterujący generatorem adresu odczytu w celu uzyskania efektu
przesuwania obrazu wzdłuż przekątnej ekranu w kierunku dolnego lewego wierzchołka.
Rysunek pomocniczy:
Tym razem przydatne jest podzielenie obrazu na 3 części. W obszarze A mamy tylko piksele tła. Jego wysokość jest równa przesunięciu p, a szerokość ilości pikseli w poziomie, czyli K.
Kolejny obszar B jest to przesunięty obraz z bitmapy. Można zauważyć, że prawy górny róg obszaru pokrywa się z prawym górnym rogiem obrazu w pamięci. Zatem porównując do oryginalnego obrazu z lewej strony i od dołu brakuje po p pikseli, które zostały usunięte w wyniku przesunięcia obrazu. Dlatego też odczytywanie obrazu z pamięci powinniśmy zacząć w pionie od 1 i skończyć na L-p, a w poziomie od p+1 do K.
Obszar C jak widać ma tę samą wysokość co część B, a szerokość równą p.
Wszystkie te wnioski dla ułatwienia możemy umieścić na rysunku:
Teraz pozostaje już tylko odpowiednio zapisać pętle. Gotowy kod źródłowy wygląda następująco:
public void Efekt3()
{
//efekt: przesuwanie wzdłuż przekątnej ekranu w kierunku dolnego lewego wierzchołka
if (p >= L) p = 0;
for (int j = 1; j <= p; j++)
{
for (int i = 1; i <= K; i++)
ReadTlo(N);
}
for (int j = 1; j <= L - p; j++)
{
for (int i = p + 1; i <= K; i++)
ReadPixel(i, j);
for (int i = 1; i <= p; i++)
ReadTlo(N);
}
}
Efekty wykonania kodu:
Wnioski:
Wszystkie zadania zostały wykonane w poprawny sposób. Przy tworzeniu algorytmów sterujących generatorem adresu odczytu należy zwracać dużą uwagę na liczbę pikseli odczytywanych w jednej linii, gdyż zdublowanie jakiegoś piksela lub pominięcie sprawia, że na ekranie pojawiają się błędy i obraz nie zostaje wyświetlany w poprawny sposób (co wynika z generowania pikseli zgodnie z zasadami działania urządzenia rastrowego). Zadania pokazały, że za pomocą tylko pętli for oraz instrukcji if(); można w prosty sposób wykonać wiele różnych efektów na obrazie.