1. 程式人生 > >圖形學--(中點畫線法+Bresenham畫線算法)

圖形學--(中點畫線法+Bresenham畫線算法)

麻煩 .com etc 線上 += 相減 -s 像素點 ima

編程環境:codeblocks+EGE庫

用到的函數:putpixel(int x1,int y1,int color) 用某種顏色打亮一個坐標點。

這倆種算法都是用來在計算機上畫一條直線的,那麽我們為什麽不直接用直線方程分別帶點再打亮呢,這是因為,計算機中每個坐標點都是整數,而直線是由一個個像素點組合而成的,那麽,直接將坐標點再進行四舍五入整數化就好了啊,的確,這是一種方法,但計算機中進行浮點數的四舍五入會使運算效率變差,因此真正畫直線時是用到上邊這倆種方法的。

1、中點畫線法

只考慮當直線的斜率|k|<1時的情況,假設現在有一條直線(x1,y1,x2,y2),那麽第一個點一定是(x1,y1)無疑,下一個點的x坐標為x1+1,y坐標要麽為y1要麽為y1+。關鍵在於每次取下一個點時,是取前一個的y1呢,還是y1+1,這時一定是取直線上點最靠近的那個了,而判斷取哪個點就用到了中點,我們將中點代入直線中 d=F(x1+1,y1+0.5)=a*(x1+1)+b*(y1+0.5)+c。

(1)如果直線d>=0,則取下邊的點也就是(x1+1,y1)。 (2)如果直線d<0,則取上邊的點也就是(x1+1,y1+1)。

它的實際過程就是這樣每次根據前邊的點判斷下一個點在哪,然後進行打亮,但這樣每次判斷的時候都得代入直線方程計算太麻煩了,我們將這倆種情況分別代入直線方程中可以找出規律:

(1)當直線>=0時,經過化解得d1=d+a;

(2)當直線<0時,經過化解得d2=d+a+b;

(3)初始值d0=a+0.5b。

也就是說每次的增量要麽為a,要麽為a+b,那麽這樣判斷的時候就簡單多了,因為我們每次只是判斷它的正負。所以給等式同時乘2,將其中浮點數0.5化為整數,這樣硬件操作時無疑更快了。

代碼:

 1 #include <iostream>
 2 #include <graphics.h>
 3 using namespace std;
 4 //中點畫線法
 5 void line1(int x1,int y1,int x2,int y2){
 6 
 7      int x,y,d0,d1,d2,a,b;
 8      y=y1;             
 9      a=y1-y2;          //直線方程中的a的算法
10      b=x2-x1;          //直線方程中的b的算法
11      d0=2*a+b;         //
增量初始值 12 d1=2*a; //當>=0時的增量 13 d2=2*(a+b); //當<0時的增量 14 for(x=x1;x<=x2;x++){ 15 putpixel(x,y,GREEN); //打亮 16 if(d0<0){ 17 y++; 18 d0+=d2; 19 }else{ 20 21 d0+=d1; 22 } 23 24 } 25 } 26 //Bresenham畫線算法 27 void line2(int x1,int y1,int x2,int y2){ 28 29 int x,y,dx,dy,d; 30 y=y1; 31 dx=x2-x1; 32 dy=y2-y1; 33 d=2*dy-dx; //增量d的初始值 34 for(x=x1;x<=x2;x++){ 35 putpixel(x,y,GREEN); //打亮 36 if(d<0){ 37 d+=2*dy; 38 }else{ 39 y++; 40 d+=2*dy-2*dx; 41 } 42 43 44 45 } 46 47 } 48 int main() 49 { 50 initgraph(640,480); //打開EGE初始化 51 line1(200,160,400,400); //畫線 52 getch(); //等待用戶操作 53 closegraph(); //關閉圖形 54 return 0; 55 }

2、Bresenham畫線算法

這種畫線算法的思想和中點畫線的一致,只是在判斷取哪個點時,不是看它位於中點的上邊還是下邊,而是將這倆個點到直線上那個點的距離相減,判斷其正負,如果下邊的點到直線實際點距離遠則的d1-d2>=0那麽取上邊的點y1+1,同樣也是代入直線化解可以得出下面結論:

(1)當d1-d2<0時,d=d+2*dy.

(2)當d1-d2>=0時,d=d+2*dy-2*dx.

(3)d的初始值為 d=2*dy-dx.

其代碼如上所示。運行截圖如下:

技術分享

圖形學--(中點畫線法+Bresenham畫線算法)