narzędzia |
Algorytm Bresenhama
Algorytm Bresenhama to algorytm służący do rasteryzacji krzywych 2D, czyli do jak najlepszego przybliżenia matematycznych krzywych na siatce pikseli.
[edytuj] Algorytm konwencji odcinka[edytuj] Założenia
[edytuj] Algorytm i jego działanieZałóżmy że krzywa w przedziale [xi, xk] spełnia w/w założenia Pierwszy piksel stawiamy w punkcie P(xi, yi). Drugi natomiast ogranicza się jedynie do dwóch możliwości: Si+1 = (xi+1, yi) lub Ti+1(xi+1, yi+1). Przyrost w kierunku osi OX (osi wiodącej) jest stały - jeden piksel. Korzystając z równania kierunkowego prostej
di = dx(s − t) = 2dy(xi − xo) − 2dx(yi − yo) + 2dy − dx Ponieważ dx > 0 di określa, która z odległości s i t jest większa. Jeżeli di > 0, to s > t za punkt Pi+1 przyjmujemy piksel Ti+1, jeżeli di < 0, wybieramy piksel Si+1. Wartość di = 0 oznacza, że oba piksele leżą w tej samej odległości i arbitralnie przyjmujemy, ze następny piksel to Ti+1. Policzmy jeszcze wartość di+1
oraz różnice di+1 − di
czyli
gdyż xi+1 = xi + 1. Jeżeli di 0, to yi+1 = yi + 1 (wybieramy piksel Ti+1), co pozwala na uproszczenie obliczeń di+1
Analogicznie, gdy di < 0 mamy yi+1 = yi (wybieramy piksel Si+1), i wzór na di+1 ma postać
Z uwagi na rekurencyjną postać wzoru na obliczanie współczynnika di, nazywanego także zmienna decyzyjna, należy jeszcze policzyć wartość początkową d0. Podstawiając xi = x0 oraz yi = y0 do równania
otrzymujemy wzór na d0
[edytuj] ImplementacjaImplementacja algorytmu Bresenhama musi oczywiście uwzględniać inne możliwe położenia odcinka względem osi OX. Jednak w każdej sytuacji można zastosować opisany wyżej schemat, w razie potrzeby traktując oś OY jako oś wiodącą [edytuj] Rysowanie odcinka algorytmem Bresenhama// x1 , y1 − współrzędne początku odcinka // x2 , y2 − współrzędne konca odcinka void BresenhamLine(const int x1, const int y1, const int x2, const int y2) { // zmienne pomocnicze int d, dx, dy, ai, bi, xi, yi; int x = x1, y = y1; // ustalenie kierunku rysowania if (x1 < x2) { xi = 1; dx = x2 - x1; } else { xi = -1; dx = x1 - x2; } // ustalenie kierunku rysowania if (y1 < y2) { yi = 1; dy = y2 - y1; } else { yi = -1; dy = y1 - y2; } // pierwszy piksel glVertex2i(x, y); // oś wiodąca OX if (dx > dy) { ai = (dy - dx) * 2; bi = dy * 2; d = bi - dx; // pętla po kolejnych x while (x != x2) { // test współczynnika if (d > 0) { x += xi; y += yi; d += ai; } else { d += bi; x += xi; } glVertex2i(x, y); } } // oś wiodąca OY else { ai = ( dx - dy ) * 2; bi = dx * 2; d = bi - dy; // pętla po kolejnych y while (y != y2) { // test współczynnika if (d > 0) { x += xi; y += yi; d += ai; } else { d += bi; y += yi; } glVertex2i(x, y); } } } Rysowanie linii (odcinka) przechodząca przez dwa punkty o współrzędnych P1(x1,y1) i P2(x2,y2) procedura w języku Pascal Procedure Linia(x1,y1,x2,y2,Kolor : integer); var c,i : integer; sx,sy,y,x : real; begin { if x2<x1 then {ten warunek nie pozwala rysowac linii 'wygladajacej jak funkcja rosnaca'!!!} begin c:=x1; x1:=x2; x2:=c; end; if y2<y1 then begin c:=y2; y2:=y1; y1:=c; end; } if (x2-x1)>(y2-y1) then begin sy:=(y2-y1)/(x2-x1); y:=y1; for i:=x1 to x2 do begin putpixel(i,round(y),Kolor); y:=y+sy; end; end else begin sx:=(x2-x1)/(y2-y1); x:=x1; for i:=y1 to y2 do begin putpixel(round(x),i,Kolor); x:=x+sx; end; end; end; [edytuj] Algorytm Bresenhama dla okręgu[edytuj] Założenia
[edytuj] Algorytm i jego działanieO wyborze piksela decydować będzie wartość funkcji F(x, y) w punkcie środkowym M położonym pomiędzy alternatywnymi pikselami. Gdy osią wiodąca jest OX oblicza się
Jeżeli F (M) > 0, to punkt M leży na zewnątrz elipsy i wybieramy piksel Pi+1 = SE. Natomiast, gdy F (M)<= 0, to punkt M leży wewnątrz elipsy lub na jej brzegu i wybieramy piksel Pi+1 = E. Gdy osią wiodąca jest OY oblicza się
Jeżeli F (M) > 0, to punkt M leży poza elipsa i wybieramy piksel Pi+1 = S. Natomiast, gdy F (M) <= 0, to punkt M leży wewnątrz elipsy lub na jej brzegu i wybieramy piksel Pi+1 = SE. Zgodnie z przyjętymi założeniami elipsę zaczynamy rysować w punkcie (0, b). Ponieważ osią wiodącą jest wówczas OX policzymy wartość zmiennej decyzyjnej d dla piksela startowego P0 = (x0, y0) = (0, b)
Jeżeli następnym pikselem jest Pi+1 = E (xi+1 = xi + 1, yi+1 = yi), to wartość zmiennej decyzyjnej wynosi:
Jeżeli następnym pikselem jest Pi+1 = SE (xi+1 = xi+1, yi+1 = yi−1), to wartość zmiennej decyzyjnej wynosi:
Przy zmianie osi wiodącej na OY należy także zmienić wartość zmiennej decyzyjnej. Różnica miedzy „nowa” i „stara” zmienna wynosi:
Teraz wyliczymy rekurencyjne równania opisujące zmienna decyzyjna, gdy osią wiodąca jest OY . Jeżeli następny piksel jest Pi+1 = SE (xi+1 = xi + 1, yi+1 = yi − 1), to wartość zmiennej decyzyjnej wynosi
Przy wyborze następnego piksela Pi+1 = S (xi+1 = xi, yi+1 = yi−1) wartość zmiennej decyzyjnej wynosi:
[edytuj] Linki zewnętrzne: |