1. 程式人生 > >(4)直線的生成之中點畫線法

(4)直線的生成之中點畫線法

基本原理:
假定直線斜率0<k<1,並且直線上當前已確定一個畫素點為P(xp, yp),則下一個與理想直線最接近的畫素點只能是P點正右方的點P1或右上方的點P2兩者之一。設M為線段P1P2的中點,Q為理想直線與線段P1P2的交點。現需要確定下一個畫素點。


若M在Q上方,則P1離直線更近,應取P1為下一個畫素;
若M在Q下方,則P2離直線更近,應取P2為下一個畫素;
若M與Q重合,則P1或P2任取一點。
這種以中點M作為判別標誌的方法即為中點畫線法。

假設直線段的起點為(x1, y1),終點為(x2, y2)。設直線方程為:F (x, y)= ax + by + c =0
其中:a = y1 - y2,b = x2 - x1,c = x1 y2 - x2 y1

F(x,y)= 0時,則點在直線上;
當F(x,y)> 0時,則點在直線上方;
當F (x,y)< 0時,則點在直線下方。

要判斷M在Q的上方還是下方,只需把M代入F(x, y),並判斷它的符號

構造判別式:
         d=F(M)=F(xp+1, yp+0.5)=a(xp+1)+b(yp+0.5)+c

若d<0,M在直線(Q點)下方,則取右上方的P2點作為下一個畫素;
若d>0,M在直線(Q點)上方,則取正右方的P1點作為下一個畫素;
若d=0,選P1點或P2點均可,約定取正右方P1點。 

d是xp和yp的線性函式,可採用增量計算,以提高運算效率。

當d≥0時,取正右方畫素P1,則再下一個畫素的判別式為:
                d1 = F(xp+2, yp+0.5)= a(xp+2)+b(yp+0.5)+c 
                     = a(xp+1)+b(yp+0.5)+c+a = d + a
所以此時 d 的增量為 a

當d<0時,取右上方畫素P2,則再下一個畫素的判別式為:
                 d2 = F(xp+2, yp+1.5)=a(xp+2)+b(yp+1.5)+c 
                     = a(xp+1)+b(yp+0.5)+c+a+b = d + a + b
所以此時 d 的增量為 a+b

d 的初始值問題:
假設直線的第一個畫素為左端點(x1, y1),則相應的判別式為
                d0 = F(x1+1, y1+0.5)=a(x1+1)+b(y1+0.5)+c
                     = (ax1+by1+c)+a+0.5b = F(x1, y1)+a+0.5b
所以左端點(x1, y1)在直線上
所以 F (x1, y1) = 0,即 d 的初始值 d0 = a+0.5b

中點畫線法的演算法步驟(0≤k≤1):
1. 輸入直線段的兩個端點P1(x1, y1)和P2(x2, y2)。
2. 初始化:a,b,d=a+0.5b,x=x1,y=y1,畫點(x, y)。
3. 若x<x2,則執行下列各步,否則演算法結束。
4. 判斷d的符號;若d<0,則(x, y)更新為(x+1, y+1),d更新為d+a+b;否則(x, y)更新為(x+1, y),d更新為d+a。
5. 畫點(x, y),返回3。

改進:用2d代替d的中點畫線法的演算法步驟(0≤k≤1 )
1. 輸入直線段的兩個端點P1(x1, y1)和P2(x2, y2)。
2. 初始化:a,b,d=2a+b,x=x1,y=y1,畫點(x, y)。
3. 若x<x2,則執行下列各步,否則演算法結束。
4. 判斷d的符號:若d<0,則(x, y)更新為(x+1, y+1),d更新為d+2a+2b;否則(x, y)更新為(x+1, y),d更新為d+2a。
5. 畫點(x, y),返回3。

例:用中點畫線法畫直線段 P1(0, 0)—P2(5, 2)
a=y1-y2=-2      b=x2-x1=5
d0=2a+b=1     d1=2a=-4     d2=2(a+b)=6


程式碼(0<k<1):

void MPLine(int x1,int y1,int x2,int y2,int color){
	int x,y,a,b,c,d,d1,d2;
	a=y1-y2;b=x2-x1;
	y=y1;
	d=2*a+b;d1=2*a;d2=2*(a+b);
	putpixel(x,y,color);
	k=1.0*(y2-y1)/(x2-x1);
	for(x=x1;x<=x2;x++){
		if(d<0){
			y++;
			d+=d2;
		}else{
			d+=d1;
		}
		putpixel(x,y,color);
	}
}