(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);
}
}