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 podstawowych prymitywów GK Punkt (piksel) Odcinek, Okrąg, Krzywe. Punkt AL = Color, BH = Page Number, CX = x, DX = y - MOVE INT 10H
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: si=dy/dx(xi+1-x0)-yi-y0, ti=(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: dx/dy=-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.