1. 程式人生 > >Bresenham 畫直線演算法

Bresenham 畫直線演算法

Bresenham's畫線演算法作圖如下:

 


給定兩個點起點P1(x1, y1), P2(x2, y2),如何畫它們直連的直線呢,即是如何得到上圖所示的藍色的點。假設直線的斜率0<k>0,直線在第一象限,Bresenham演算法的過程如下:
1.畫起點(x1, y1).
2.準備畫下一個點,X座標加1,判斷如果達到終點,則完成。否則找下一個點,由圖可知要畫的點要麼為當前點的右鄰接點,要麼是當前點的右上鄰接點。
  2.1.如果線段ax+by+c=0與x=x1+1的交點y座標大於(y+*y+1))/2則選右上那個點
  2.2.否則選右下那個點。
3.畫點
4.跳回第2步
5.結束
  

具體的演算法如下,原理就是比較目標直線與x+1直線交點的縱座標,哪個離交點近就去哪個

 void Bresenhamline(int x0, int y0, int x1, int y1)
{
  int x, y, dx, dy;
  float k, e;
  dx = x1 -x0;//x偏移量
  dy = y1 -y0;//y偏移量
  k = dy / dx;//斜率
  e = -0.5;
  x = x0;
  y = y0;
  for (x= x0;x < x1; x++)
  {
    printf("%d,%d\n",x,y);//需要的折線上的點
    e = e + k; 
    if (e > 0)//y超過半格就去右上的點(否則就是右下的點)
    {
      y++;
      e = e -1;
    }
  }
}


上述Bresenham演算法在計算直線斜率與誤差項時用到小數與除法。可以改用整數以避免除法。等式兩邊同時乘以2*dx, 將e統一乘以2*dx即變成了整數的Bresenhan演算法了.

void DrawBresenhamline(int x0, int y0, int x1, int y1)
{ 
	int dx = x1 - x0;//x偏移量
	int dy = y1 - y0;//y偏移量
	int dx2 = dx <<1;//x偏移量乘2
	int dy2 = dy <<1;//y偏移量乘2
	int e = -dx; //e = -0.5 * 2 * dx,把e 用2 * dx* e替換
	int x = x0;//起點x座標
	int y = y0;//起點y座標
	for (x = x0; x < x1;x++)
	{
		printf ("%d,%d\n",x, y);
		e=e + dy2;//來自 2*e*dx= 2*e*dx + 2dy  (原來是 e = e + k)
		if (e > 0)//e是整數且大於0時表示要取右上的點(否則是右下的點) 
		{ 
		 	y++; 
			e= e - dx2;//2*e*dx = 2*e*dx - 2*dx  (原來是 e = e -1)
		}
	}
}
 

最後,包含所有象限的程式碼如下:

void DrawBresenhamline(int x0, int y0, int x1, int y1)
{ 
	int dx = x1 - x0;//x偏移量
	int dy = y1 - y0;//y偏移量
	int ux = dx >0 ?1:-1;//x伸展方向
	int uy = dx >0 ?1:-1;//y伸展方向
	int dx2 = dx <<1;//x偏移量乘2
	int dy2 = dy <<1;//y偏移量乘2
	if(abs(dx)>abs(dy))
	{//以x為增量方向計算
		int e = -dx; //e = -0.5 * 2 * dx,把e 用2 * dx* e替換
		int x = x0;//起點x座標
		int y = y0;//起點y座標
		for (x = x0; x < x1;x+=ux)
		{
			printf ("%d,%d\n",x, y);
			e=e + dy2;//來自 2*e*dx= 2*e*dx + 2dy  (原來是 e = e + k)
			if (e > 0)//e是整數且大於0時表示要取右上的點(否則是右下的點) 
			{ 
			 	y += uy; 
				e= e - dx2;//2*e*dx = 2*e*dx - 2*dx  (原來是 e = e -1)
			}
		}
	}
	else
	{//以y為增量方向計算
		int e = -dy; //e = -0.5 * 2 * dy,把e 用2 * dy* e替換
		int x = x0;//起點x座標
		int y = y0;//起點y座標
		for (y = y0; y < y1;y += uy)
		{
			printf ("%d,%d\n",x, y);
			e=e + dx2;//來自 2*e*dy= 2*e*dy + 2dy  (原來是 e = e + k)
			if (e > 0)//e是整數且大於0時表示要取右上的點(否則是右下的點) 
			{ 
			 	x += ux; 
				e= e - dy2;//2*e*dy = 2*e*dy - 2*dy  (原來是 e = e -1)
			}
		}
	}
}