一、首先說明:
- 這是啥? —— 這是利用C#FORM寫的一個用來演示計算機圖形學中 ①Bresenham直線掃描算法(即:連點成線);②種子填充法(即:填充多邊形);③掃描線填充法
- 有啥用? —— 無論是連點成線還是區域填充在高級編程中基本上都提供很高效的庫函數來調用。這里拿出這些算法一方面有利於大家理解那些封裝的函數底層是實現;另一方面是方便嵌入式TFT屏幕底層驅動開發時借鑒的。
- 是啥樣? —— 如下面的操作,不言而喻。
二、進入正題:
2-1、直線的掃描轉換
圖形的掃描轉換實質就是在光柵等數字設備上確定一個最佳逼近於圖形的像素集的過程。
對於直線掃描轉換其實就是確定最佳逼近於該直線的一組像素,然后按照掃描線的順序對這些像素進行寫操作。三種比較常用的算法是:①數值微分法(DDA);②中點畫線法;③Bresenham算法。這里主要講第三個算法,因為這個效率高且易於硬件實現。
Bresenham算法:由於顯示直線的象素點只能取整數值坐標,可以假設直線上第i個象素點坐標為(xi,yi) ,它是直線上點(xi,yi)的最佳近似,並且xi=xi(假設m<1),如下圖所示。那么,直線上下一個象素點的可能位置是(xi+1,yi) 或(xi+1,yi+1)。
而實際的點為紅色的點,可以計算可能點與實際點的偏差的差,即:d1-d2=2m(xi+1)-2yi+ 2b-1。這樣根據這個差就能判斷下一點的坐標,然后一直向前推進就能求出所有的點。此外由於考慮硬件對浮點數處理的速度要比對整數處理的速度慢許多的情況,在該算法里會對該式子做一些變換(其實就是放大使其變為整數,同時保證下一點求法正確)。由於網上資料很多,這里就不細講了~
Bresenham算法偽代碼:[條件:0<=m<=1且x1<x2]
①輸入線段的兩個端點坐標和畫線顏色:x1,y1,x2,y2,color;
②設置象素坐標初值:x=x1,y=y1;
③設置初始誤差判別值:p=2·Δy-Δx;
④分別計算:Δx=x2-x1、Δy=y2-y1;
⑤循環實現直線的生成:
1 for(x=x1;x<=x2;x++) 2 { 3 putpixel(x,y,color); 4 if(p>=0) 5 { 6 y=y+1; 7 p=p+2*(Δy-Δx); 8 } 9 else 10 { 11 p=p+2*Δy; 12 } 13 }
顯然,上述算法是帶有一定限制條件的,下面我們將其推廣到所有斜率的情況,實現各種線的繪制。容易證明:當線段處於①、④、⑧、⑤區域時,以|Δx|和|Δy|代替前面公式中的Δx和Δy;當線段處於②、③、⑥、⑦區域時,把|Δx|和|Δy|對換。下面是工程中用於連點成線的基於Bresenham算法的函數:
1 /// <summary> 2 /// Bresenham畫線算法,給出兩個點a,b 3 /// </summary> 4 /// PS:這里XiangSu是光柵的最小距離,因為我是在高分辨率的窗口中模擬低分辨率效果, 5 /// 所以用這個XiangSu來控制模擬的光柵最小單元格的邊的大小,實際運用中XiangSu=1 6 /// <param name="a"></param> 7 /// <param name="b"></param> 8 void Bresenhamline(Point a, Point b) 9 { 10 int x, y, dx, dy, s1, s2, p, temp, interchange, i; 11 x = a.X; 12 y = a.Y; 13 dx = Math.Abs(b.X - a.X); 14 dy = Math.Abs(b.Y - a.Y); 15 if (b.X > a.X) 16 s1 = XiangSu; 17 else 18 s1 = -XiangSu; 19 if (b.Y > a.Y) 20 s2 = XiangSu; 21 else 22 s2 = -XiangSu; 23 if (dy > dx) 24 { 25 temp = dx; 26 dx = dy; 27 dy = temp; 28 interchange = 1; 29 } 30 else 31 interchange = 0; 32 p = 2 * dy - dx; 33 for (i = 1; i <= dx; i += XiangSu) 34 { 35 tempp.X = x; 36 tempp.Y = y; 37 tempP.Add(tempp); 38 Vram[x + y * 600] = true;//把該片內存置為邊界標記 39 if (p >= 0) 40 { 41 if (interchange == 0) 42 y = y + s2; 43 else 44 x = x + s1; 45 p = p - 2 * dx; 46 } 47 if (interchange == 0) 48 x = x + s1; 49 else 50 y = y + s2; 51 p = p + 2 * dy; 52 } 53 }
由於版面受限,請鏈接到第二節,更加精彩,哈哈:http://www.cnblogs.com/zjutlitao/p/4117223.html
兩篇鏈接:
[計算機圖形學] 基於C#窗口的Bresenham直線掃描算法、種子填充法、掃描線填充法模擬軟件設計(一)
[計算機圖形學] 基於C#窗口的Bresenham直線掃描算法、種子填充法、掃描線填充法模擬軟件設計(二)