一 Bresenham 繪直線
使用 Bresenham 算法,可以在顯示器上繪制一直線段。該算法主要思想如下:
1 給出直線段上兩個端點 ,根據端點求出直線在X,Y方向上變化速率
;
2 當 時,X 方向上變化速率快於 Y 方向上變化速率,選擇在 X 方向上迭代,在每次迭代中計算 Y 軸上變化;
當 時,Y 方向上變化速率快於 X 方向上變化速率,選擇在 Y 方向上迭代,在每次迭代中計算 X 軸上變化;
3 現在僅考慮 情形,在
情況下僅需要交換變量即可。直線斜率
,當 d = 0 時,為一條水平直線,當 d > 0 或 d < 0 時,需要分開討論,如下圖:
二 Bresenham 繪圓
使用 Bresenham 繪制圓形,只需要繪制四分之一圓即可,其他部分通過翻轉圖形即可得到。假設圓心位於 (0, 0) 點,半徑為 R,繪制第一象限四分之一圓形,如下圖:
根據圖形可知,從 出發,下一個可能的選擇分別為:
1)水平方向上 ;
2)對角方向上 ;
3)垂直方向上 ;
下面計算,根據差值可判斷大致圓弧位置:
1)當 時,圓環落在
與
之間,進一步計算圓弧到
與
的距離以判斷應該落在哪個點上;
2),
由於 ,
,上式可化簡為,
,將
改寫為
得:
,
已知 ,可根據上式快速求解出
,當
時,下一點落在
上,當
時,下一點落在
上;
3)當 時,圓環落在
與
之間,進一步計算圓弧到
和
的距離以判斷應該落在哪個點上;
4),可化簡為:
,將
改寫為
得:
,
已知 ,可根據上式快速求解出
,當
時,下一點落在
上,當
時,下一點落在
上;
5)以上推導中,已知 可以快速求解
,同時,已知
也可以快速推導出
,以下分類討論:
a. 當 時,有:
,進一步整理得:
;
b. 當 時,有:
,進一步整理得:
;
c. 當 時,有:
,進一步整理得:
。
以下給出 Bresenham 繪圓實現:
1 void Bresenham_Circle(PairS center, int radius, std::vector<PairS>& circle) 2 { 3 PairS start(0, radius); 4 int Delta = (start.x + 1) * (start.x + 1) + 5 (start.y - 1) * (start.y - 1) - radius * radius; 6 7 std::vector<PairS> tmp; 8 tmp.push_back(start); 9 10 while (start.y > 0) 11 { 12 int state = -1; 13 14 if (Delta < 0) 15 { 16 int delta = (Delta + start.y) * 2 - 1; 17 if (delta < 0) 18 { 19 start.x += 1; 20 state = 0; 21 } 22 else 23 { 24 start.x += 1; 25 start.y -= 1; 26 state = 1; 27 } 28 } 29 else 30 { 31 int delta = (Delta - start.x) * 2 - 1; 32 if (delta < 0) 33 { 34 start.x += 1; 35 start.y -= 1; 36 state = 1; 37 } 38 else 39 { 40 start.y -= 1; 41 state = 2; 42 } 43 } 44 45 if (state == 0) 46 Delta = Delta + start.x * 2 + 1; 47 else if (state == 1) 48 Delta = Delta + start.x * 2 - start.y * 2, +2; 49 else if (state == 2) 50 Delta = Delta - start.y * 2 + 1; 51 else 52 break; 53 54 tmp.push_back(start); 55 } 56 57 std::vector<PairS> tmp2; 58 for (int i = 0; i < tmp.size(); ++i) 59 { 60 PairS p(tmp[i].x, tmp[i].y); 61 tmp2.push_back(p); 62 } 63 for (int i = tmp.size() - 1; i >= 0; --i) 64 { 65 PairS p(tmp[i].x, -tmp[i].y); 66 tmp2.push_back(p); 67 } 68 for (int i = 0; i < tmp2.size(); ++i) 69 { 70 PairS p(tmp2[i].x, tmp2[i].y); 71 circle.push_back(p); 72 } 73 74 for (int i = tmp2.size() - 1; i >= 0; --i) 75 { 76 PairS p(-tmp2[i].x, tmp2[i].y); 77 circle.push_back(p); 78 } 79 80 for (int i = 0; i < circle.size(); ++i) 81 { 82 circle[i].x += center.x; 83 circle[i].y += center.y; 84 } 85 }
參考資料 計算機圖形學得算法基礎 David E Rogers