Grafika Komputerowa i wizualizacja Algorytmy rastrowe
Wprowadzenie W urządzeniu rastrowym obraz (kartka, ekran monitora i inne) składa się ze skończonej liczby podstawowych elementów nazywanych pikselami. Elementy te uporządkowane tworzą siatkę prostokątną. Wielkość lxk określa rozdzielczość danego urządzenia graficznego, a odległość między środkami sąsiednich pikseli w poziomie do odległości w pionie określa wartość aspektu danego urządzenia. Np. dla karty CGA aspekt=22/25, a dla karty EGA=4/5. Każdy rysunek rysowany na urządzeniu rastrowym tworzy się przez wyświetlenie (zaznaczenie) skończonej liczby pikseli. Problemem staje się wtedy wybór dyskretnego zbioru pikseli odwzorowującego np. krzywą ciągłą na płaszczyźnie.
Rysowanie odcinka – algorytm Bresenhama - założenia W większości zastosowań praktycznych dysponujemy współrzędnymi rzeczywistymi. Aby narysować odcinek we współrzędnych rastrowych musimy przejść do współrzędnych całkowitoliczbowych. Będzie rozważany zbiór pikseli ośmiospójny. Załóżmy, że x0<xk, 0<dy/dx/=1.
Rysowanie odcinka – algorytm Bresenhama - algorytm Zaczynamy od piksela P(x0,y0). Ponieważ kąt nachylenia odcinka jest mniejszy od 45 stopni to następny piksel wybieramy pośród Si+1=(xi+1,yi) i Ti+1=(xi+1,yi+1). Wielkości s i t występujące na rysunku określone są wzorami: s=dy/dx(xi+1-x0)-yi-y0, t=(yi+1-y0)-dy/dx(xi+1-x0).
Rysowanie odcinka – algorytm Bresenhama - algorytm Odejmując od siebie stronami oraz mnożąc przez dxi oznaczając ta wielkość przez di mamy: di=(s-t)dx=2dy(xi-x0)-2dx(yi-y0)+2dy-dx. Ponieważ dx>0, to znak di określa, która z wielkości s i t jest większa. Jeżeli di>0, to s>t i za Pi+1 przyjmiemy piksel Ti+1, w przeciwnym przypadku jeżeli di<0, to wybierzemy Si+1. Jeżeli di=0, to oba piksele leżą w tej samej odległości i możemy założyć, że wybieramy np. Pi+1=Ti+1.
Rysowanie odcinka – algorytm Bresenhama - algorytm Dalej możemy zmniejszyć koszt obliczeń badając zachowanie wzoru na di dla i+1. Mamy: di+1=2dy(xi+1-x0)-2dx(yi+1-y0)+2dy-dx. Po odjęciu od siebie stronami mamy: di+1-di=2dy(xi+1-xi)-2dx(yi+1-yi). Stąd, ponieważ xi+1-xi=1, zachodzi: di+1=di+2dy-2dx(yi+1-yi).
Rysowanie odcinka – algorytm Bresenhama - algorytm Jeżeli di>0 (wybieramy Pi+1=Ti+1) to zależność powyższa upraszcza się do postaci: di+1=di+2(dy-dx), a jeżeli di<0 to ponieważ yi+1=yi mamy: di+1=di+2dy. Aby zależności rekurencyjne działały określamy wartość di dla i=0: d0=2dy-dx.
Podsumowanie – algorytm końcowy (jedna z możliwych implementacji) Zadanie: narysować odcinek łączący P0(x0,y0) z Pk(xk,yk) przy założeniu: dx=xk-x0>0, dy=yk-y0>0, 0<dy/dx<=1. Rysujemy P0=(round(x0), round(y0)), d0=2dy-dx i=0, 1,…,k di <=0 =>di+1= di + 2dy, di >0 =>di+1= di + 2(dy-dx) di+1<0=>Si+1, di+1>0=> Ti+1, gdy di+1=0, to losowy
Rysowanie odcinka – algorytm Bresenhama - podsumowanie Ostatecznie widać, że algorytm ogranicza się do działania na liczbach całkowitych. Zgodnie z przyjętymi oznaczeniami i założeniami możemy oznaczyć wybór punktu Ti+1 jako T, a Si+1 jako S. Rysowanie odcinka możemy zapisać jako ciąg S i T, np. SSSTTTSSSTTT itd. lub (SSSTTT)^2 lub (S^3T^3)^2. Umożliwia to kompresję danych.
Rysowanie okręgu – algorytm Bresenhama W przypadku rysowania okręgu wartość aspektu jest ważna. Dlatego przyjmujemy, że mając dany układ rzeczywisty OXY i pikselowy oxy związki między tymi układami są następujące: X=ax, Y=y. Uprościmy rysowanie okręgu do okręgu w środku układu i do promienia całkowitoliczbowego. Zadanie polega więc na przybliżeniu krzywej wybranym układem pikseli: X2+Y2=R2 lub we współrzędnych ekranowych (ax)2+y2=R2.
Rysowanie okręgu – algorytm von Akenema Przyjmijmy, że a=p/q, a stąd mamy powyższą zależność możemy zapisać w postaci funkcyjnej: f(x,y)=p2x2+q2y2-q2R2=0. Stosujemy układ ośmiokierunkowy (ośmiopikselowy) i ze względu na symetrię ograniczymy się do pierwszej ćwiartki. Zaczynamy od piksela P0(0,R). Punkt, w którym współczynnik kierunkowy wektora stycznego: dy/dx=-fx/fy=-2p2x/(2q2y)=-1 dzieli ćwiartkę okręgu na dwa fragmenty. W pierwszym fragmencie, dla którego zachodzi p2x<q2y (rysunek powyżej) zwiększamy kolejno wartości x o jeden i wybieramy spośród pikseli oznaczonych jako A i B. W drugim fragmencie (rysunek obok) wybieramy między pikselami C i B. O wyborze będzie decydować wartość funkcji w punkcie S (algorytm Van Akenema). W pierwszym przypadku obliczamy: fsi=f(xi+1,yi-1/2).
Rysowanie okręgu – algorytm von Akenema Jeżeli fsi=f(xi+1,yi-1/2)>0 to punkt S leży na zewnątrz okręgu i wtedy jako Pi+1 wybieramy punkt B. Jeżeli fsi=f(xi+1,yi-1/2)<0 to S leży wewnątrz okręgu i wybieramy wtedy punkt A. Dla drugiego przypadku obliczamy fsi=f(xi+1/2,yi-1) i wybieramy Pi+1=C, gdy fsi>0 i Pi+1=B gdy fsi<0.
Rysowanie okręgu – algorytm von Akenema Jeżeli fsi=0, to wybieramy dowolny punkt. Dla startowego piksela P0(0,R) mamy: fs0=f(x0+1,y0-1/2)=p2(0+1)2+q2(R-1/2)2-q2R2=p2-q2R+q2/4 Dla pierwszego wariantu (p2x<q2y) mamy. Przy przejściu od Pi do Pi+1=A mamy xi+1=xi+1, yi+1=yi i stąd: f(xi+1+1,yi+1-1/2)=p2(xi+1+1)2+q2(yi+1-1/2)2-q2R2= p2(xi+1+1)2+q2(yi-1/2)2-q2R2 = =f(xi+1,yi-1/2)+2p2xi+1+p2 lub krócej na podstawie fsi=f(xi+1,yi-1/2) fsi+1=fsi+2p2xi+1+p2.
Rysowanie okręgu – algorytm von Akenema W drugim przypadku (przy przejściu od Pi do Pi+1=B) mamy xi+1=xi+1, yi=yi-1 i zachodzi: f(xi+1+1,yi+1-1/2)=p2(xi+1+1)2+q2(yi-1/2-1)2-q2R2=f(xi+1,yi-1/2)+2p2xi+1+p2-2q2yi+1 lub krócej fsi+1=fsi+2p2xi+1+p2-2q2yi+1. Dla drugiego wariantu możemy przeprowadzić podobne rozważania otrzymamy wtedy: dla przejścia od Pi do Pi+1=B (xi+1=xi+1, yi+1=yi-1) mamy f(xi+1+1,yi+1-1/2)=p2(xi+1+1)2+q2(yi-1-1/2)2-q2R2=f(xi+1,yi-1/2)+2p2xi+1+p2-2q2yi+1 A po uproszczeniach dla przejścia od Pi do Pi+1=C (xi+1=xi, yi+1=yi-1) mamy fsi+1=fsi-2q2yi+1+q2.
Rysowanie okręgu – inne algorytmy W przypadku, gdy chcemy wyznaczyć punkty okręgu niekoniecznie wszystkie piksele sąsiednie można skorzystać z innej metody. Polega ona na tym ,że okrąg możemy zapisać we współrzędnych biegunowych następująco: X=Rcos, Y=Rsin, Gdzie <0,360). Łatwo otrzymujemy: dX/d=-Rsin=-Y, dY/d=Rcos=X z warunkami początkowymi: X(0)=R, Y(0)=0. Taki układ możemy rozwiązać np. z krokiem h=360/(N+1)np. metodą Eulera lub niejawną metodą Eulera, np. X0=R, Y0=0 Xi+1=Xi-hYi, Yi+1=Yi+hXi+1. Dla i=0,1,...,N.