有两点
P0(x0, y0), P1(x1, y1)确定一条线段
L(P0, P1),设线段所在直线方程为
y=kx+b其中斜率
k=(y1−y0)/(x1−x0),截距
b=y0−kx0。
注:以下算法中
∣k∣≤1,对于
∣k∣>1的情况可同理推导得出。
1 直线方程法
1.1 基本思想:
根据直线的表达式确定线段路径上点的像素位置。
1.2 算法描述
- 取
x坐标:将区间
[x0, x1]均分,每段长
d,假设端点为
ti=x0+i∗d,
t0=x0,tn=x1.(注:
ti要为整数)
- 计算
y坐标:
yi=kti+b
- 取整:因为像素坐标都是整数,所以取整:
yi′=(int)(yi+0.5)
1.3 算法评价
- 主要运算:乘法+加法+浮点数运算(取整)
- 计算量大,这种方法一般不使用。
2 数值微分法(DDA算法)
2.1 基本思想
从
x的左端点
x0开始,向x右端点步进,步长为1(像素),按
y=kx+b计算相应的
y坐标,并取像素点
(x, round(y))作为当前点的坐标。
2.2 算法描述
设
x步长为
Δx,则
xi+1=xi+Δx,于是:
yi+1=kxi+1+b =kxi+kΔx+b =yi+kΔx
Δx=1时,
yi+1=yi+k.
- 起始点
(x0, y0);
- 计算下一个点
(xi+1, yi+1)=(xi+1, round(yi+k))
- 循环执行步骤2,直至
xi=x1,结束。
其中,
round(yi+k)=(int)(yi+k+0.5).
2.3 算法评价
-
如博文开篇所述,上述算法仅仅适用于
∣k∣≤1的情况,在这种情况下,
x每增加1,
y最多增加1。对于
∣k∣>1的情况,必须把
x和
y的地位互换,
x随着
y的变化而变化,
y每增加1,
x相应增加
1/k。
-
主要运算:加法+浮点数运算(取整),仍有浮点数运算,不利于硬件实现。
3 中点画线法
依旧分析
∣k∣≤1的情况。
3.1 基本思想
根据上文,我们可以知道,当
xi+1=xi+1,
yi+1经过四舍五入之后只有两种情况:
-
yp+1=round(yi+1)<yp+0.5 ⇒ yp+1=yp
-
yp+1=round(yi+1)≥yp+0.5 ⇒ yp+1=yp+1
(假设第
i个像素点为
(xp, yp),则它的下一个像素点为
(xp+1, yp+1),注意区分
yi和
yp)
可以发现,下一个像素点
yp+1的取值,与
yp和
yp+1的中点(
yp+0.5)有很大的关系,所以我们可以直接用这个中点去判断
yp+1的取值。
如图所示,假设
A点为当前像素点,而且已确定,接下来的像素点确定如下:
- 下一个像素点
B,在
B1和
B2之间选择,由于
B中在直线下方,所以直线更靠近
B2点,则下一个像素点
(xp+1, yp+1)选择
B2。
- 下一个像素点
C,在
C1和
C2之间选择,由于
C中在直线上方,所以直线更靠近
C1点,则下一个像素点
(xp+2, yp+2)选择
C1。
- 下一个像素点
D,在
D1和
D2之间选择,由于
D中刚好在直线上,所以直线距离
D1和
D2同样远,则下一个像素点
(xp+3, yp+3)可以选择任一点。(一般提前统一好,选择任一点都可以)
3.2 算法描述
设函数
F(x,y)=y−kx−b,则:
d=F(xM,yM)=F(xp+1,yp+0.5)=yp+0.5−k(xp+1)−b
根据下述方法更新下一个像素点的相关值:
-
dp<0⇒中点在直线下方⇒xp+1=xp+1, yp+1=yp+1,知道下一个像素点之后,可求
dp+1=F(xp+2,yp+1.5) =yp+1.5−k(xp+2)−b =[yp+0.5−k(xp+1)−b]+1−k=dp+1−k
-
d>0⇒中点在直线上方⇒xp+1=xp+1, yp+1=yp,同理可推:
dp+1=dp−k
-
d=0同
d>0
- 初始点
P0(x0,y0),计算
d0=F(x0+1,y0+0.5)=y0+0.5−k(x0+1)−b=0.5−k
- 根据
{dp<0⇒xp+1=xp+1, yp+1=yp+1,dp+1=d+1−kdi≥0⇒xp+1=xp+1, yp+1=yp, dp+1=d−k
更新。
- 循环步骤2,直至
xp=x1,结束。
3.3 算法评价
- 该算法只涉及加法。但在计算
d0时,涉及到(
0.5)浮点数计算,可以将
2d代替
d以消除浮点数计算。
3.4 算法实现
C++实现代码(任意k值)
4 Bresenham算法
4.1 基本思想
如上图所示,
xi+1=xi+1,
yi+1=yi+k,现在设一个误差项
d:
-
d0=0
- 如果只在
x方向上走一步:
di+1=di+k
- 一旦
y方向上走了一步,
di+1=di+k−1
那么我们就可以比较
d和
0.5,来确定下一个像素点的坐标。
-
dp<0.5:直线更接近下面的点,所以下一个像素点:
xp+1=xp+1, yp+1=yp。同时更新
dp+1=dp+k。
-
dp≥0.5:直线更接近上面的点,所以更新
xp+1=xp+1, yp+1=yp+1。同时更新
dp+1=dp+k−1。
4.2 算法描述
-
d0=0
-
dp+1=dp+k,判断
di:
- 若
dp<0.5,
xp+1=xp+1, yp+1=yp;
- 若
dp≥0.5,
xp+1=xp+1, yp+1=yp+1,
dp=dp−1;
- 重复步骤2,直到画到
P1,结束。
4.3 算法评价
- 改进一:用
e=d−0.5代替
d,
e0=−0.5,这样可以减少一点运算量。
- 改进二:同中点画线算法,用
2eΔx代替
e。
- 该算法与中点画线法差不多,个人认为只是计算
d的顺序不同:中点画线法是确定像素点之后更新
d,而Bresenham算法是先计算
d,再去确定像素点。两者大同小异。