直线的扫描转换
直接计算法
假定直线的起点、终点分别为:(x1,y1), (x2,y2),且都为整数。
计算出斜率k=(y2-y1)/(x2-x1) ,
在Y轴的截距b=y1-k*x1
这样一来,只要给定 x的值,根据解析式立即可以计算出对应的y值,然后输出(x,round(y))。这种方法直观,但效率太低,因为每一步需要一次浮点乘法、一次浮点加法和一次舍入运算。
数值微分法(DDA)
假定直线的起点、终点分别为:(x1,y1), (x2,y2),且都为整数。
已知过端点P0 (x1, y1), P1(x2, y2)的直线段L:y=kx+b
直线斜率为:k=(y2-y1)/(x2-x1)
考虑当x从xi
→
→
xi+1时y的变化规律:
设:
Δx=xi+1−xi
Δ
x
=
x
i
+
1
−
x
i
xi+1=xi+Δx
x
i
+
1
=
x
i
+
Δ
x
计算:
yi+1=kxi+1+b=k(xi+Δx)+b=kxi+b+kΔx=yi+kΔx
y
i
+
1
=
k
x
i
+
1
+
b
=
k
(
x
i
+
Δ
x
)
+
b
=
k
x
i
+
b
+
k
Δ
x
=
y
i
+
k
Δ
x
当
Δx=1;yi+1=yi+k
Δ
x
=
1
;
y
i
+
1
=
y
i
+
k
即:当x每递增1,y递增k(即直线斜率);
注意上述分析的算法仅适用于|k|≤1的情形。在这种情况下,x每增加1,y最多增加1。
当 |k|>1时,必须把x,y地位互换。
DDA算法就是一个增量算法。
void DDALine(int x0,int y0,int x1,int y1,int color) {
int x;
float dx, dy, y, k;
dx= x1-x0, dy=y1-y0;
k=dy/dx, y=y0;
for (x=x0; x<=x1; x++){
drawpixel (x, int(y+0.5), color);
y=y+k;
}
}
中点Bresenham算法
原理:每次在主位移方向上走一步,另一个方向上走不走步取决于中点误差项的值。给定理想直线的起点坐标为P0(x0,y0),终点坐标为P1(x1,y1),则直线的隐函数方程为:
F(x,y)=y−kx−b=0
F
(
x
,
y
)
=
y
−
k
x
−
b
=
0
其中,直线的斜率:
k=ΔyΔx=y1−y0x1−x0
k
=
Δ
y
Δ
x
=
y
1
−
y
0
x
1
−
x
0
直线水平方向位移:
Δx=x1−x0
Δ
x
=
x
1
−
x
0
直线垂直方向位移:
Δy=y1−y0
Δ
y
=
y
1
−
y
0
理想直线将平面划分成三个区域:对于直线上的点,F(x,y)=0;对于直线上方的点,F(x,y)>0;对于直线下方的点,F(x,y)<0。
假设直线的斜率为0≤k≤1,则Δx≥Δy,所以确定x方向为主位移方向。按照Bresenham原理,x方向上每次加1,y方向上加不加1取决于中点误差项的值。
假定直线的当前点是P,沿主位移x方向走一步,下一点只能在Pu和Pd两点中选取,Pu和Pd的中点为M。显然,若中点M在理想直线的下方,则Pu点距离直线近,否则选取Pd。(u代表up,上面的像素;d代表down,下面的像素)
构造中点误差项:
从Pi(xi,yi)点出发选取下一像素时,需将Pu和Pd的中点M(xi+1,yi+0.5)代入隐函数方程,构造中点误差项di。
从
P
i
(
x
i
,
y
i
)
点
出
发
选
取
下
一
像
素
时
,
需
将
P
u
和
P
d
的
中
点
M
(
x
i
+
1
,
y
i
+
0.5
)
代
入
隐
函
数
方
程
,
构
造
中
点
误
差
项
d
i
。
di=F(xi+1,yi+0.5)=yi+0.5−k(xi+1)−b
d
i
=
F
(
x
i
+
1
,
y
i
+
0.5
)
=
y
i
+
0.5
−
k
(
x
i
+
1
)
−
b
中点误差项的递推公式
-
当di<0时,下一步的中点坐标为M(xi+2,yi+1.5),下一步中点误差项为
当
d
i
<
0
时
,
下
一
步
的
中
点
坐
标
为
M
(
x
i
+
2
,
y
i
+
1.5
)
,
下
一
步
中
点
误
差
项
为
di+1=F(xi+2,yi+1.5)=yi+1.5−k(xi+2)−b d i + 1 = F ( x i + 2 , y i + 1.5 ) = y i + 1.5 − k ( x i + 2 ) − b
=yi+0.5−k(xi+1)−b+1−k = y i + 0.5 − k ( x i + 1 ) − b + 1 − k
=di+1−k = d i + 1 − k -
当di≥0,时下一步的中点坐标为M(xi+2,yi+0.5),下一步中点误差项为
当
d
i
≥
0
,
时
下
一
步
的
中
点
坐
标
为
M
(
x
i
+
2
,
y
i
+
0.5
)
,
下
一
步
中
点
误
差
项
为
di+1=F(xi+2,yi+0.5)=yi+0.5−k(xi+2)−b d i + 1 = F ( x i + 2 , y i + 0.5 ) = y i + 0.5 − k ( x i + 2 ) − b
=yi+0.5−k(xi+1)−b−k = y i + 0.5 − k ( x i + 1 ) − b − k
=di−k = d i − k
中点误差项的初始值
直线的起点坐标为P0(x0,y0),x为主位移方向。因此,第一个中点是M(x0+1,y0+0.5),相应的di的初始值为:
直
线
的
起
点
坐
标
为
P
0
(
x
0
,
y
0
)
,
x
为
主
位
移
方
向
。
因
此
,
第
一
个
中
点
是
M
(
x
0
+
1
,
y
0
+
0.5
)
,
相
应
的
d
i
的
初
始
值
为
:
d0=F(x0+1,y0+0.5)=y0+0.5−k(x0+1)−b
d
0
=
F
(
x
0
+
1
,
y
0
+
0.5
)
=
y
0
+
0.5
−
k
(
x
0
+
1
)
−
b
=y0−kx0−b−k+0.5
=
y
0
−
k
x
0
−
b
−
k
+
0.5
其中,因为(x0,y0)在直线上,所以y0−kx0−b=0
其
中
,
因
为
(
x
0
,
y
0
)
在
直
线
上
,
所
以
y
0
−
k
x
0
−
b
=
0
所以d0=0.5−k
所
以
d
0
=
0.5
−
k
由于使用的是di的符号,可以用 2diΔx 2 d i Δ x 代替 di d i 来摆脱小数,使得算法只涉及整数运算。现有的研究已经证明:端点采用整数坐标没有什么益处,因为现在的CPU可以按照与处理整数同样的速度处理浮点数。

浙公网安备 33010602011771号