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;yid≥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;yie≥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 算法是一种经典的直线光栅化算法, 使用了最小的计算量,使得单点生成算法已经没有改进的余地。
参考 《计算几何算法与实现》孔令德