1965 年,Bresenham 為數字繪圖儀開發了一種繪制直線的算法,該算法同樣使用于光柵掃描顯示器,被稱為 Bresenham 算法。
原理
算法的目標是選擇表示直線的最佳光柵位置。Bresenhan 算法在主位移方向上每次遞增一個單位。另一個方向的增量為 0 或 1,取決于理想直線于最近網格點的距離,這一距離稱為誤差項,誤差項用 d 表示。
當 x x x 方向遞增一個單位,有 d = d + k d = d+ k d=d+k; 則
y i + 1 = { y i + 1 ; d ≥ 0.5 y i d < 0.5 y_{i+1} = \begin{cases} y_i + 1; &\quad d \geq 0.5\\ y_i &\quad d < 0.5 \end{cases} yi+1?={yi?+1;yi??d≥0.5d<0.5?
誤差項初始值 d 0 = 0 d_0 = 0 d0?=0, 如果 d ≥ 0.5 d \geq 0.5 d≥0.5, y y y 方向遞增一個單位并且將 d d d 減 1.
消除 0.5 的影響
令 e = d ? 0.5 e = d -0.5 e=d?0.5. 當 x x x 方向走一步,有 e = e + k e = e + k e=e+k, 則
y i + 1 = { y i + 1 ; e ≥ 0 y i e < 0.5 y_{i+1} = \begin{cases} y_i + 1; &\quad e \geq 0\\ y_i &\quad e < 0.5 \end{cases} yi+1?={yi?+1;yi??e≥0e<0.5?
e 0 = ? 0.5 e_0 = -0.5 e0?=?0.5 , 如果 e ≥ 0 e \geq 0 e≥0, 則 e = e ? 1 e = e -1 e=e?1
消除浮點數的影響,斜率和 e e e, 進行整數化
當 0 ≤ k ≤ 1 0 \leq k \leq 1 0≤k≤1, Δ x \Delta x Δx 為正
e = 2 Δ x e = 2 Δ x ( d ? 0.5 ) = ? Δ x + 2 Δ x d e = 2 \Delta x e = 2 \Delta x (d-0.5) = -\Delta x + 2 \Delta x d e=2Δxe=2Δx(d?0.5)=?Δx+2Δxd
初始值 e 0 = ? Δ x e_0 = -\Delta x e0?=?Δx
當 x 方向走一步,有 e + = 2 Δ y e += 2 \Delta y e+=2Δy
如果 e ≥ 0 e \geq 0 e≥0 有
e = 2 Δ x ( e ? 1 ) = 2 Δ x e ? 2 Δ x e ? = 2 Δ x e = 2 \Delta x (e-1) = 2 \Delta x e - 2 \Delta x \\ e -= 2 \Delta x e=2Δx(e?1)=2Δxe?2Δxe?=2Δx
算法
- 設置像素點的顏色
- 讀入直線的兩個端點坐標
- 取 e e e 的初始值為 e 0 = ? 0.5 e_0 = -0.5 e0?=?0.5
- 從起點開始,沿著 x x x 軸方向每遞增一個單位,有 e + = 2 Δ y e += 2 \Delta y e+=2Δy
- 當 ≥ 0 \geq 0 ≥0 時,下一個像素更新為 ( x i + 1 , y i + 1 ) (x_i + 1, y_i + 1) (xi?+1,yi?+1), 同時將 e e e 更新為 e ? = 2 Δ x e -= 2 \Delta x e?=2Δx, 否則,下一個像素更為 ( x i + 1 , y i + 1 ) (x_i + 1, y_i +1) (xi?+1,yi?+1)
- 繪制像素點,執行 x + + x++ x++ 操作到終點
void BresenhamLine(CDC* pDC, CPoint P0, CPoint P1)
{COLORREF crColor = RGB(0, 0, 0);int dx = P1.x - P0.x;int dy = P1.y - P0.y;int e = - dx;for (int x=P0.x, y=P0.y; x < P1.x; x++) {pDC->SetPixelV(x, y, crColor);e += 2 * dy;if (e >= 0) {y++;e -= 2 * dx;}}
}
整數 Bresenham 算法是一種經典的直線光柵化算法, 使用了最小的計算量,使得單點生成算法已經沒有改進的余地。
參考 《計算幾何算法與實現》孔令德