La presentazione è in caricamento. Aspetta per favore

La presentazione è in caricamento. Aspetta per favore

L' algoritmo di Bresenham. GRAFICA INCREMENTALE come si disegna un segmento di retta su un reticolo di pixel senza prodotto ne' divisione: l' algoritmo.

Presentazioni simili


Presentazione sul tema: "L' algoritmo di Bresenham. GRAFICA INCREMENTALE come si disegna un segmento di retta su un reticolo di pixel senza prodotto ne' divisione: l' algoritmo."— Transcript della presentazione:

1 l' algoritmo di Bresenham

2 GRAFICA INCREMENTALE come si disegna un segmento di retta su un reticolo di pixel senza prodotto ne' divisione: l' algoritmo di Bresenham risale al 1961, pubblicato nel 1965

3 Introduzione alla Grafica Digitale - tracciare un segmento schermo a raggi catodici, disegno di tipo vettoriale (vedi Tektronix, history...) una linea era tracciata sullo schermo comandando direttamente la posizione del pennello luminoso da una posizione iniziale (x1,y1) ad una posizione finale (x2,y2), il segmento P1--P2 e' un vettore (spazio 2D) ovvero una coppia di punti orientata ovvero un punto + una direzione ed una lunghezza: P1(x1,y1) P2(x1,y1)

4 Introduzione alla Grafica Digitale - tracciare un segmento per il plotter o tracciatore meccanico si pone il problema di come tracciare una linea con una penna comandata da due motori incrementali passo passo (uno per il tamburo porta carta l'altro per il carrello porta penna) i motori sono essenzialmente digitali, capaci di far avanzare la penna di un passo (fisso) nel senso delle x o nel senso delle y, o in entrambi (diagonale esatta) carrello porta penna tamburo porta carrello

5 problema su un plotter o tracciatore meccanico (i plotter sono ancora in uso... anni ) di come tracciare una linea con una penna (varie tecnologie, dalla biro, ai pennini in china, al pennello, all;ink-jet, alla carta termica ecc) comandata da due motori incrementali (digitali!) che fanno muovere la penna di un passo fisso nel senso delle x, delle y, o entrambi (diagonale esatta); sulla pagina seguente un "home made plotter" (un plotter e il suo driver sono stati fatti da due studenti del corso di Calcolatori elettronici 2 (Architettura di..) per hobby e poi presentati come tesina per l'esame;

6 come si vede dalla foto, era fatto con il gioco "FisherTechnik"

7 Introduzione alla Grafica Digitale - tracciare un segmento il problema di come tracciare una linea con una penna che puo' avanzare di un passo (fisso) nel senso delle x o nel senso delle y, o in entrambi (diagonale esatta) si ripropone comunque sugli schermi a reticolo dagli stessi anni 60 in poi, (primi schermi grafici 1960) schermi grafici a reticolo a basso costo (300 x 200 circa (*) (Apple2,1977,1300$ con 4kbyte), schermi a tubo vettoriali a immagine persistente a fosfori verdi (Tektronix anni 70-80), "super" schermi di oggi (2007) (3840x2400) (*) 280x192 a 4 colori

8 Introduzione alla Grafica Digitale - tracciare un segmento (da Wikipedia) (*) IBM 1401 calcolatore commerciale usato spesso come controller per plotter, (*)

9 Introduzione alla Grafica Digitale - tracciare un segmento Una linea disegnata con un plotter oppure su uno schermo a reticolo (sul monitor posso disegnare un "punto" di dimensione fissa = pixel ) diventa una linea spezzata: con il plotter devo disegnare una linea approssimante, perche' la penna puo' avanzare solo di un passo fisso: nel senso delle x (orizzontale) o nel senso delle y (verticale) o in entrambi i sensi - diagonale esatta richiesta la linea blu orizzontale dx diagonale dx,dy verticale dy

10 Introduzione alla Grafica Digitale - tracciare un segmento Una linea su uno schermo a reticolo (posso disegnare un "punto" di dimensione fissa = pixel ) diventa una successione di pixel come in figura (linea spezzata) : coordinate schermo: x e y sono interi

11 Introduzione alla Grafica Digitale - tracciare un segmento segmento da un punto P1(x1,y1) - a un punto P2(x2,y2) nota: punto dato in coordinate schermo, con due interi x1,y1 ** x valore da xmin (in genere zero) a xmax (larghezza dello schermo in pixel), ** y da ymin a ymax (y=0 bordo in basso / in alto dello schermo) non posso tracciare il segmento geometrico astratto, devo tracciare una sequenza di pixel con posizioni x1,y1,... x2,y2, dove si incrementa x ad ogni passo se l' inclinazione del segmento e' minore o uguale a 45 0, oppure incremento y se il segmento ha inclinazione maggiore di 45 0

12 Introduzione alla Grafica Digitale - tracciare un segmento segmento da un punto P1(x1,y1) - a un punto P2(x2,y2) punto dato in coordinate schermo, con due interi x1,y1 ** x va da xmin a xmax (da zero a larghezza schermo in pixel), ** y da ymin a ymax (da 0 a altezza dello schermo) devo tracciare una sequenza di pixel con posizioni x1,y1, xa,ya, xb,yb,... x2,y2, dove se l' inclinazione del segmento e' minore o uguale a 45 0 e quindi vi sono piu' xk diversi che yk diversi, e si procede incrementando x ad ogni passo oppure se il segmento ha inclinazione maggiore di 45 0 e allora vi saranno piu' y distinte che x distinte, e si procede incrementando y ad ogni passo

13 Introduzione alla Grafica Digitale - tracciare un segmento quindi: y = m * x + b per disegnare un segmento da P1 a P2 devo controllare l'inclinazione m : se m<=1, procedo a passi fissi (un pixel) lungo le x - la y viene incrementata di un passo dy minore di un pixel, e quindi arrotondata (fig. a destra sopra) per una retta con m>1 vado a passo fisso lungo le y, e la x sara' arrotondata, come nella figura a destra sotto, k k+2 k+1k+3 y=k k+5 k+3 k+7 k+4 k+1 k+4 x x y y m<=1 m>1 x=

14 Introduzione alla Grafica Digitale - tracciare un segmento kk+2 k+1k+3 k+7 k+4 x y // versione semplice 1, // con aritmetica float float a,b,x,y;..dx=xend-xstart; dy=yend-ystart;.. if( fabs(dx) >= fabs(dy) ){ m = dy / dx; // m<=1 // dove y= m*x+b; dy= m*dx b= ystart - m * xstart; x= xstart; // si parte da qui do{ y = m*x+b; // (*) nota putpix( (int)x, (int)y ); x=x+1; // sempre unitario! } while( x<= xend ); } else... pagina seguente (*) nota: ad ogni passo c'e' da fare un prodotto e una somma

15 Introduzione alla Grafica Digitale - tracciare un segmento //vers.semplice 1, aritm.float float a,b,x,y;..dx=xend-xstart; dy=yend-ystart;... else { // fabs(dy) > fabs(dx) mre = dx/dy; // mre < 1 // dove x= mre*y+b; dy= m*dx b= xstart - mre * ystart; y= ystart; // si parte da qui do{ x = mre * y + b; putpix( (int)x, (int)y ); y=y+1; //sempre unitario! } while( y<= yend ); } // if ( fabs(dx).. k+2 k k+5 k+3 k+4 k+1 x y

16 Introduzione alla Grafica Digitale - tracciare un segmento kk+2 k+1k+3 k+7 k+4 x y //versione semplice 2, aritmetica float float x=xstart, y=ystart, ddx,ddy,fsteps; dx=xend-xstart; dy=yend-ystart; if( fabs(dx) > fabs(dy) ){ // m<1 steps=fabs(dx); fsteps=(float)steps; ddx= dx/fsteps; ddy= dy/fsteps; putpix( round(x),round(y) ); for(k=0; k

17 Introduzione alla Grafica Digitale - tracciare un segmento //vers. semplice 2, in float, parte else... float x=xstart, y=ystart, ddx,ddy,fsteps; dx=xend-xstart; dy=yend-ystart;... } else { // ( fabs(dx) 1 steps=fabs(dy); // dx,dy interi fsteps=(float)steps; ddx= dx/fsteps; ddy= dy/fsteps; putpix ( round(x),round(y) ); for(k=0; kfabs(dy)..else k+2 k k+5 k+3 k+4 k+1 x y

18 tracciare un segmento versione semplice 2, aritmetica float... float x=xstart, y=ystart, ddx, ddy, fsteps; dx=xend-xstart; dy=yend-ystart; if( fabs(dx) > fabs(dy) ){ // m<1(m=dy/dx) steps=fabs(dx); fsteps=(float)steps; ddx= dx/fsteps; ddy= dy/fsteps; putpix(round(x),round(y)); for(k=0; k

19 tracciare un segmento: algoritmo di Bresenham algoritmo di Bresenham per tracciare un segmento con solo uso di aritmetica intera (Bresenham, J.E., "Algorithm for Computer Control of a Digital plotter", IBM Systems Journal, 4(1), pp.25-30, 1965) esso si basa su un criterio di scelta del pixel da tracciare che usa solo interi: kk+1k+4k+2 x y k+3 consideriamo il caso con m<1, cioe' xstart

20 tracciare un segmento: algoritmo di Bresenham tracciato il pixel al passo k, dobbiamo decidere dove mettere il pixel al passo k+1; e a tal fine si ricorda l' equazione della retta che passa per P1 e P2: y=m*x+b, con yst=m*xst+b, e yend=m*xend+b; per x k : y k = m*x k + b, e, ricordando che x k+1 = x k + 1 per x k+1 : y = m*x k+1 + b = m * (x k +1) +b... y non e' int ! X k X k+1 x y al passo k+1 si decide tra il pixel (x k+1,y k ) e (x k+1,y k+1 ) a seconda se y(x k+1 ) e' piu' vicino a y k+1 oppure a y k : d upp =y k+1 -y =(y k +1)-m*(x k +1)-b d low = y - y k = m * (x k +1)+b - y k d lo -d up =2*m*(x k +1)+2b-y k -y k -1 P1 P2 y k y k+1 y d upper d lower

21 tracciare un segmento: algoritmo di Bresenham linea P1(xst,yst)-P2(xend,yend); per x k e' y k = m*x k +b, per x k+1 ho: y = m*x k+1 +b = m*(x k +1)+b; devo decidere tra (x k+1,y k ) e (x k+1,y k+1 ), cioe' (y non e'intero!) tra y k+1 e y k d upp =y k+1 -y =(y k +1) - m*(x k +1) - b d low = y - y k = m * (x k +1)+b - y k d lo -d up =2*m*(x k +1)+2b-y k -y k -1 come criterio di decisione si usa p k = dx* ( d lo -d up ) con dx=xend-xstart e m = dy/dx nota che p k e' un intero, e nota il segno di d lo -d up : se d lo d up allora p k e' positivo, e si sceglie il pixel sopra ! X k X k+1 x y P1 P2 y k y k+1 y d upper d lower

22 tracciare un segmento: algoritmo di Bresenham yst=m*xst+b; yend=m*xend+b; per x k e' y k = m*x k +b, per x k+1 e' y k+1 =m*x k+1 +b = m*(x k +1)+b ; d upp = y k+1 -y = (y k +1) - m*(x k +1)-b ; d low = y - y k = m *(x k +1)+b - y k ; d low -d upp = 2*m*(x k +1)+2b-y k - y k -1; il criterio di decisione p k per scegliere y k+1 o y k+1 e' dato dal p k-1 : X k X k+1 x y p k = dx* ( d low -d upp ), dove se dx=xend-xstart e m = dy/dx : p k = dx*(2*m*(x k +1)+2b-y k - y k -1) p k = 2*dy*(x k +1) -2*dx*y k +c (c = 2*dy+dx*(2*b-1) sara' eliminato nel calcolo di p k+1 da p k ) p k+1 =2*dy*(x k+1 +1) -2*dx*y k+1 +c p k+1 -p k =2*dy*(x k+1 -x k )-2*dx*(y k+1 -y k ) P1 P2 y k y k+1 y d upper d lower p k+1 = p k + 2*dy*(x k+1 -x k ) -2*dx*(y k+1 -y k ) dove x k+1 -x k e' 1 e dove z = y k+1 -y k e' 0 se p k < 0, altrimenti z = 1: p k+1 = p k + 2*dy - 2*dx*z ; e con il valore iniziale p 0 = 2*dy - dx; Bresenham: il calcolo di p k da p k-1 si puo' fare senza prodotti e solo con int !!! da cui l'algoritmo di B.->

23 tracciare un segmento: algoritmo di Bresenham X k X k+1 x y ricordiamo: p k+1 = p k + 2*dy -2*dx * z, dove se p k e'negativo, allora z = 0 altrimenti 1, e p 0 = 2*dy - dx; ==>> da cui algoritmo (versione 1) dati (x1,y1) e (x2,y2), con x1

24 tracciare un segmento: algoritmo di Bresenham da cui infine: void BresenhamX(int x1, int y1, int x2, int y2) { int x=x1, y=y1; // only octant ENE, m dy int dx = x2 - x1, dy = y2 - y1; int Two_dy = 2*dy, TwoDyMinusDx=2*(dy-dx); int error = Two_dy - dx; // prima era pk putpix(x,y); // *** starting point while (x 0, go up one y: y = y + 1; error = error + TwoDyMinusDx; } // if error putpix(x,y); // *** on new x,y } // while x } // Bresenham nota: nel ciclo solo un test e due somme di interi

25 o, in forma leggermente diversa: struct tPunto{ int x; int y; };... void bresenham( tPuntoI a, tPuntoI b){ // deve essere a.x < b.x e 0 < H/W < 1, // quadrante x>0,y>0, m<1 int y = a.y, W = b.x-a.x, H = b.y-a.y; //dx,dy int E = 2*H-W; // criterio errore for(int x=a.x; x<=b.x; x++) { // ciclo pixel setPixel(x,y); // ad ogni passo x++, per y: if(E<0) E += 2*H; // per il prossimo pixel else { y++; // si sale di un pixel E += 2*( H-W); } // if } // for x } // bresenham tracciare un segmento: algoritmo di Bresenham

26 Introduzione alla Grafica Digitale - tracciare un segmento la versione completa dell'algoritmo di Bresenham per tracciare una linea e' un po' piu' lunga, perche' deve considerare i vari casi che possono presentarsi: ** caso di linea molto inclinata (m>1, ovvero dy>dx) ** caso di punto di inizio "invertito" rispetto il punto di fine, ovvero: (m 1) yend1 si risolve scambiando le x con le y, il caso m xend si risolve scambiando il punto di inizio con il punto di fine; riportiamo la versione completa, dall'esercizio OGL...Bresenham

27 void LineBres(int xstart,int ystart,int xend,int yend) { int i,tmp,x,y,dx,dy,Signdx,Signdy,Two_dx,Two_dy,Swap,error; if(abs(xstart-xend)<2) { // vertical: y=ystart; if (ystart < yend) dy=1; else dy=-1; do { setPixel(xstart,y); y=y+dy; } while( abs(yend-y)>1); return; } // if verticale if(xstart>xend){scamb(&xstart,&xend);scamb(&ystart,¥d);} x=xstart; y=ystart; dx=xend-xstart; dy=yend-ystart; Signdx = isign(dx); Signdy = isign(dy); dx = abs(dx); dy = abs(dy); if (dy>dx) { tmp=dx;dx=dy; dy=tmp; Swap=1; } else Swap = 0; Two_dx = 2*dx; Two_dy = 2*dy; error = Two_dy - dx; for (i=1; i<=dx; i++) { setPixel(x,y); if (error > 0) { if( Swap ) x = x + Signdx; else y = y + Signdy; error = error - Two_dx; } if ( Swap ) y = y + Signdy; else x = x + Signdx; error = error + Two_dy; } // for setPixel(x,y); } // LineBres

28 traccia un segmento di linea retta algoritmo di Bresenham, programma EGD_2A_D

29 Introduzione alla Grafica Digitale - tracciare un segmento Le librerie core (GL) lib, GLU (GL Utility lib), GLUT (GL utility Toolkit lib) hanno definiti vari oggetti, tra cui le curve di Bezier (core), le superfici quadriche (GLU), vari solidi (cono,cubo,sfera, ottaedro, icosaedro, toro, la tea-pot, ma non hanno il cerchio e l'ellisse, (che si ottengono come casi particolari dagli oggetti sopramenzionati); cerchio e ellisse si possono/devono tracciare con algoritmi discreti DDA; non riportiamo lo sviluppo, (bibliogr) ; si veda ad es. il OGL6B (algor.di Bresenham per cerchio)

30 nel caso del cerchio, si calcola un ottavo del cerchio, e poi si tracciano le altre sette parti per simmetria: // il primo punto : setP(xc+dx, yc+dy); // 1 // a gli altri: // 1) cambia segno setP(xc-dx, yc+dy); // 3 setP(xc+dx, yc-dy); // 4 setP(xc-dx, yc-dy); // 2 // 2) per simmetria: setP(xc+dy, yc+dx); // 8 setP(xc-dy, yc+dx); // 5 setP(xc+dy, yc-dx); // 6 setP(xc-dy, yc-dx); // 7

31 Bresenham per il cerchio vedi pagina seguente: Bibliografia: Hearn,D., Baker,M.P., "Computer Graphics with OpenGL", Pearson Prentice-Hall, 2004, 3.rd ed., par.3-5, pp Bresenham,J.E., "Algorithm for Computer Control of a Digital Plotter", IBM Systems Journal, 4(1), pp.25-30, 1965 Bresenham,J.E., "A Linear Algorithm for Incrementing Digital Display of Circular Arcs", Communication of the ACM, 20(2), pp

32 void DDACircle (int xc,int yc, int radius) { // vedi bibliografia per la // derivazione del procedimento int dx,dy; // circle point int p = 1-radius; dx=0; dy=radius; // point at alfa=90degr, on top of circle set8Pixel( xc,yc, dx, dy ); while( dx

33 void set8Pixel(int xc,int yc, int dx,int dy, double r, double g, double b ) /* replicate 8 times symmetrically in the 8 octants */ { setPixel(xc+dx, yc+dy, r,g,b ); setPixel(xc-dx, yc+dy, r,g,b ); setPixel(xc+dx, yc-dy, r,g,b ); setPixel(xc-dx, yc-dy, r,g,b ); setPixel(xc+dy, yc+dx, r,g,b ); setPixel(xc-dy, yc+dx, r,g,b ); setPixel(xc+dy, yc-dx, r,g,b ); setPixel(xc-dy, yc-dx, r,g,b ); } /* set8Pixel */

34 cerchio disegnato con l'algoritmo di Bresenham (programma EGD_22_CIRCLE)

35 I programmi dimostrativi degli algoritmi di Bresenham riportati nel secondo capitolo EGD_07_2D_2_3 usano "pixel" grandi, ovvero rettangoli di una matrice di rettangoli: /* the simulated 1 bit raster memory */ int RasterMem[RASTERxSIZE][RASTERySIZE];... void plotpix(int x,int y, td r, td g, td b ) { RasterMem[x][y] = 1; glColor3f(r,g,b ); glRecti( PixelSizeX * x, PixelSizeY * y, PixelSizeX * (x+1), PixelSizeY * (y+1) ); } /* plotpix */... void Simple(int x1,int y1,int x2,int y2){ float a,b,x,y,dx,dy;..dy=y2-y1; dx=x2-x1; a=dy/dx; b=y1-a*x1; /*y=a*x+b;->b=y-a*x;*/ x=x1; do{ y = a*x+b; plotpix( (int)x, (int)y, 1.0,1.0,1.0); x=x+1; } while( x<= x2 );...

36

37 Oggi l'algoritmo di Bresenham e' realizzato a livello hardware, nell'unita' di processo grafica, e viene ricordato per il suo valore storico (si pensi che al tempo (1961) i calcolatori spesso non avevano un'unita' aritmetica completa, ma sapevano solo sommare due interi positivi - il prodotto era quindi realizzato a software, con una procedura ad hoc, e l'evitare il prodotto velocizzava l'algoritmo di molto.


Scaricare ppt "L' algoritmo di Bresenham. GRAFICA INCREMENTALE come si disegna un segmento di retta su un reticolo di pixel senza prodotto ne' divisione: l' algoritmo."

Presentazioni simili


Annunci Google