布雷森汉姆直线演算法

布雷森汉姆直线演算法（Bresenham's line algorithm）是用来描绘由两点所决定的直线的演算法，它会算出一条线段在n维点阵图上最接近的点。这个演算法只会用到较为快速的整数加法、减法和位元移位，常用于绘制电脑画面中的直线。是计算机图形学中最先发展出来的演算法。
经过少量的延伸之后，原本用来画直线的演算法也可用来画圆。且同样可用较简单的算术运算来完成，避免了计算二次方程式或三角函数，或递归地分解为较简单的步骤。
以上特性使其仍是一种重要的演算法，并且用在绘图仪、绘图卡中的绘图晶片，以及各种图形程式库。这个演算法非常的精简，使它被实作于各种装置的韧体，以及绘图晶片的硬体之中。
「Bresenham」至今仍经常作为一整个演算法家族的名称，即使家族中绝大部份演算法的实际开发者是其他人。该家族的演算法继承了Bresenham的基本方法并加以发展，详见参考资料。

**演算方法**
Bresenham直线演算法描绘的直线。
假设我们需要由(x0, y0)这一点，绘画一直线至右下角的另一点(x1, y1)，x,y分别代表其水平及垂直坐标，并且x1 - x0 > y1 - y0。在此我们使用电脑系统常用的坐标系，即x坐标值沿x轴向右增长，y坐标值沿y轴向下增长。
因此x及y之值分别向右及向下增加，而两点之水平距离为且垂直距离为。由此得之，该线的斜率必定介乎于0至1之间。而此算法之目的，就是找出在与之间，第x行相对应的第y列，从而得出一像素点，使得该像素点的位置最接近原本的线。
对于由(x0, y0)及(x1, y1)两点所组成之直线，公式如下：

因此，对于每一点的x，其y的值是

因为x及y皆为整数，但并非每一点x所对应的y皆为整数，故此没有必要去计算每一点x所对应之y值。反之由于此线之斜率介乎于1至0之间，故此我们只需要找出当x到达那一个数值时，会使y上升1，若x尚未到此值，则y不变。至于如何找出相关的x值，则需依靠斜率。斜率之计算方法为。由于此值不变，故可于运算前预先计算，减少运算次数。
要实行此算法，我们需计算每一像素点与该线之间的误差。于上述例子中，误差应为每一点x中，其相对的像素点之y值与该线实际之y值的差距。每当x的值增加1，误差的值就会增加m。每当误差的值超出0.5，线就会比较靠近下一个映像点，因此y的值便会加1，且误差减1。
下列伪代码是这算法的简单表达（其中的plot(x,y)绘画该点，abs返回的是绝对值）。虽然用了代价较高的浮点运算，但很容易就可以改用整数运算（详见最佳化一节）：
function line(x0, x1, y0, y1)
int deltax := x1 - x0
int deltay := y1 - y0
real error := 0
real deltaerr := deltay / deltax    // 假设deltax != 0（非垂直线），
// 注意：需保留除法运算结果的小数部份
int y := y0
for x from x0 to x1
plot(x,y)
error := error + deltaerr
if abs (error) ≥ 0.5 then
y := y + 1
error := error - 1.0

**一般化**
虽然以上的演算法只能绘画由左下至右上，且斜率小于或等于1的直线，但我们可以扩展此演算法，使之可绘画任何的直线。第一个扩展是绘画反方向，即由右上至左下的直线。这可以简单地透过在x0 > x1时交换起点和终点来做到。第二个扩展是绘画斜率为负的直线，可以检查y0 1是否成立；若该不等式成立，误差超出0.5时y的值改为加-1。最后，我们还需要扩展该演算法，使之可以绘画斜率绝对值大于1的直线。要做到这点，我们可以利用大斜率直线对直线y=x的反射是一条小斜率直线的事实，在整个计算过程中交换 x 和 y，并一并将plot的参数顺序交换。扩展后的伪代码如下：
function line(x0, x1, y0, y1)
boolean steep := abs(y1 - y0) > abs(x1 - x0)
if steep then
swap(x0, y0)
swap(x1, y1)
if x0 > x1 then
swap(x0, x1)
swap(y0, y1)
int deltax := x1 - x0
int deltay := abs(y1 - y0)
real error := 0
real deltaerr := deltay / deltax
int ystep
int y := y0
if y0 error与deltaerr的计算是浮点运算。此外，error的值经过多次浮点数加法之后，可能有累积误差。使用整数运算可令演算法更快、更准确。只要将所有以上的分数数值乘以deltax，我们就可以用整数来表示它们。唯一的问题是程序中的常数0.5—我们可以透过改变error的初始方法，以及将error的计算由递增改为递减来解决。新的程序如下：
xk * deltaerr >= 0.5;
xk * deltay/deltax >= 0.5;
deltax/2 - xk*deltay 
function line(x0, x1, y0, y1)
boolean steep := abs(y1 - y0) > abs(x1 - x0)
if steep then
swap(x0, y0)
swap(x1, y1)
if x0 > x1 then
swap(x0, x1)
swap(y0, y1)
int deltax := x1 - x0
int deltay := abs(y1 - y0)
int error := deltax / 2
int ystep
int y := y0
if y0 

**参阅**
  Patrick-Gilles Maillot's Thesis date=20090107113923  an extension of the Bresenham line drawing algorithm to perform 3D hidden lines removal; also published in MICAD '87 proceedings on CAD/CAM and Computer Graphics, page 591 - ISBN 2-86601-084-1.- 数字微分分析仪演算法，描画直线和三角形的一种简单通用方法。- 吴小林直线演算法，以同样快速的方法绘制反锯齿线。- 中点画圆演算法，以类似的方法绘画圆。

**外部连结**
  Analyze Bresenham's line algorithm in an online Javascript IDE date=20190402114026 -  The Bresenham Line-Drawing Algorithm by Colin Flanagan date=20210225022840 -  National Institute of Standards and Technology page on Bresenham's algorithm date=20081017094131 -  Calcomp 563 Incremental Plotter Information date=20210131020624 -  Bresenham's Original Paper date=20080528040104 -  An implementation in Java date=20181215173409  at the Code Codex