Graphics Primitives: line
Pixel Position
Line-Scan Conversion Algorithms Line scan conversion: determine the nearest pixel position (integer) along the line between the two endpoints and store the color for each position in the frame buffer. Three common algorithms DDA Midpoint Bresenham
Line Equations The Cartesian slope-intercept equation ((x 0,y 0 )(x end,y end )) Y=mx+b
Naive Idea void NaiveLine(int x 0,int y 0,int x end,int y end,int color) int x ; float y, m, b; m=(y end -y 0 )/(x end -x 0 ); b = y0 – m*x0; for (x=x 0 ; x x end ; x++) drawpixel (x, int(y+0.5), color); y=m*x+b; Costly floating point computations !! Multiplications, additions, roundings
DDA (Digital Differential Analyzer ) ALGORITHMDigital Differential Analyzer The digital differential analyzer (DDA) samples the line at unit intervals in one coordinate corresponding integer values nearest the line path of the other coordinate. The following is the basic scan-conversion(DDA) algorithm for line drawing (sample at unit x intervals ) for x from x0 to xend Compute y=mx+b Draw_fn(x, round(y)) How to improve???
Reuse Previous Value Increment For Start from x=x 0 and y=y 0, every position (x,y) can be computed by incrementation, x by 1 and y by m.
void DDALine(int x 0,int y 0,int x end,int y end,int color) int x ; float dx, dy, y, m; d x = x end -x 0, d y =y end -y 0 ; m=dy/dx; y=y 0 +m drawpixel (x 0, y 0, color); for (x=x 0 +1; x x end ; x++) drawpixel (x, int(y+0.5), color); y=y+m; No more multiplications, but still have fp additions, roundings
Example : draw segment x y int(y+0.5) round
DDA Illustration (x i, Round(y j )) (x i +1, y j +m) (x i, y j ) (x i +1, Round(y j +m)) Desired Line x1x2 y2 y1
The above DDALine only suit the condition that x end >x 0 and 0 < m < 1 (octant #1) How about the other cases? |m| > 1 x end < x 0 ?
Octant#2: x end >x 0 and 1 < m < ∞ Octant#3: x end <x 0 and -∞ < m < -1 Octant#4: x end <x 0 and -1 < m < 0 Octant#5: x end <x 0 and 0 < m < 1 Octant#6: x end <x 0 and 1 < m < ∞ Octant#7: x end >x 0 and -∞ < m < -1 Octant#8: x end >x 0 and -1 < m < 0 m=1 m=-1 m=∞ m=0 #1#1 #2#2 #3#3 #4#4 #5#5 #6#6#7#7 #8#8
Octant#2 and #3: reverse the role of x as iterator by y and increment x by 1/m Octant#4: reverse the end points octant#8 Octant#5: reverse the end points octant#1 Octant#6: reverse the end points octant#2 Octant#7: reverse the end points octant#4 Octant#8: Just same DDA algorithm for octant#1
Major deficiency in the above approach : Uses floats Has rounding operations the accumulation of error
Midpoint Algorithm Basic thought( 0 < m < 1) M PTPT PBPB P=(x,y) Q P i (x i,y i ) M(x i+1,y i+0.5 ) According the position of M and Q, choose the next point P t or P b
Line equation ( (x 0,y 0 ), (x end,y end ) ) For any point (x, y): F(x,y) = 0 (x,y) is on the line F(x,y) > 0 (x,y) is above the line F(x,y) < 0 (x,y) is beneath the line
Discriminant Function d P2P2 P1P1 M P=(x,y) Q P i (x i,y i ) d < 0, M is beneath Q, P2 is next point; d > 0, M is above Q, P1 is the next point; d = 0, P1 or P2 is right, commonly P1 The function is made by using the midpoint M:
Is it (computing the d) costly? No! We can use the idea in the DDA: use previous d value to compute next one.
Incrementation thought If d 0 , then choose the next point: P 1 (x p +1, y p ), In order to judge the next point successively , calculate increment of d is a If d<0 , then choose the next point: P 2 (x p +1, y p +1) 。 In order to judge the next point successively,calculate increment of d is a + b
Initial value of d In each of iteration Else if d < 0 If d >= 0
Improve again: integer calculations?
Substitute 2d for d Initial value of d In each of iteration Implementation issue: the quantities (2a) and (2a+2b) can be precomputed to be two constants. If d >= 0 Else if d<0
Example Drawing a line from (0,0) to (5.2) ixiyid
void MidpointLine (int x 0,int y 0,int x end, int y end,int color) { int a, b, incre_d 1, incre_d 2, d, x, y; a=y 0 -y end, b=x end -x 0, d=2*a+b; incre_d 1 =2*a, incre_d 2 =2* (a+b); x=x 0, y=y 0 ; drawpixel(x, y, color); while (x<x 1 ) { if (d<0) {x++, y++, d+=incre_d 2 ; } else {x++, d+=incre_d 1 ;} drawpixel (x, y, color); } /* while */ } /* mid PointLine */
Bresenham’s Line Algorithm An accurate, efficient raster line drawing algorithm developed by Bresenham, scan converts lines using only incremental integer calculations that can be adapted to display circles and other curves.
Bresenham Line Algorithm (cont) The difference between these 2 separations is the pixel at (x k,y k ) is to be displayed, the next point will be chosen from (x k +1, y k ) and (x k +1, y K +1) d lower = y – y k = m(x k + 1) + b – y k d upper = (y k + 1) – y = y k + 1- m(x k + 1) – b d lower -d upper = 2m(x k + 1) – 2 y k + 2b – 1
Bresenham ’ s Line Algorithm Define discriminant P k = Δx ( d lower -d upper ) = 2Δyx k -2 Δxy k + c The sign of P k is the same as the sign of d lower -d upper, since Δx > 0. Parameter c is a constant and has the value 2Δy + Δx(2b-1) (independent of pixel position) If p k <0, the next point is (x k +1,y k ); Else the next point is (x k +1,y k +1)
Bresenham ’ s algorithm (cont) Increment thought: At step k + 1, the decision parameter can be evaluated as, p k+1 = 2Δyx k+1 - 2Δxy k+1 + c Taking the difference of p k+ 1 and p k we get the following. p k+1 – p k = 2Δy(x k+1 - x k )-2Δx(y k+1 – y k ) But, x k+1 = x k +1, so that p k+1 = p k + 2Δy - 2 Δx(y k+1 – y k ) Where the term y k+1 -y k is either 0 or 1, depending on the sign of parameter p k If pk<0,p k+1 =p k +2 Δy Else p k+1 =p k +2(Δy -2 Δx)
Bresenham ’ s Line Algorithm Initial value of p 0 The first parameter p 0 is directly computed p 0 = 2 Δyx Δxy 0 + c = 2 Δyx 0 – 2 Δxy 0 + [2Δy + Δx(2b-1)] Since (x 0,y 0 ) satisfies the line equation, we also have y 0 = Δy/ Δx * x 0 + b Combining the above 2 equations, we will have p 0 = 2Δy – Δx
Bresenham ’ s Line Algorithm void BresenhamLine (int x 0,int y 0,int x end, int y end,int color) { int dx,dy, incre_p 1, incre_p 2, p, x, y; dy=y end- y 0, dx=x end -x 0 ; incre_p 1 =2*dy, incre_p 2 =2* (dy-dx); x=x 0, y=y 0 ; p=2*dy-dx; drawpixel(x, y, color); while (x<x 1 ) { if (p<0) {x++, p+=incre_d 1 ; } else {x++, y++,p+=incre_d 2 ;} drawpixel (x, y, color); } /* while */ } /* Bresenham */