Python matplotlib 实现DDA算法
DDA算法全称数值微分法(Digital Differential Analyzer),是用数值方法解微分方程,即通过对x和y各增加一个小量,计算下一步的x、y值。实际上,应该令一个值增加1个单位,同时保证另一个值的增加量小于1个单位,这样才能绘制出更多的像素点,从而得到更准确的直线。因此,选择x增1还是y增1要看直线的斜率,
不妨令直线的表达式为:
y
=
k
x
+
b
y = kx + b
y=kx+b
对于第i和第i+1个像素点,令x值分别为xi,xi+1,有
y
i
=
k
x
i
+
b
y_i = kx_i + b
yi=kxi+b
y
i
+
1
=
k
x
i
+
1
+
b
y_{i+1} = kx_{i+1} + b
yi+1=kxi+1+b
以上两式作差,可以得到:
Δ
y
=
y
i
+
1
−
y
i
=
k
(
x
x
+
1
−
x
i
)
=
k
Δ
x
\Delta y = y_{i+1}-y_i=k(x_{x+1}-x_i)=k\Delta x
Δy=yi+1−yi=k(xx+1−xi)=kΔx
由此可知,当x增加1个单位时,y增加k个单位;当y增加1个单位时,x增加 1/k 个单位。
因为要保证令一个值增加1个单位的同时,另一个值的增加量小于1个单位,所以当直线斜率k<1时,令x增1,y增k;当k>1时,令y增1,x增加 1/k;(k = 1时,两种情况都可以,默认x增1)
以下只考虑k<=1的情况。
直线的起点坐标为(x0,y0),下一个像素点的坐标(x1,y1),因为k<=1,所以
x
1
=
x
0
+
1
,
y
1
=
y
0
+
k
x_1 = x_0 + 1,y_1=y_0+k
x1=x0+1,y1=y0+k
因为像素点的坐标必须为整数,所以要对y1进行四舍五入处理,即Round(y1),Round()函数为自定义的四舍五入函数,这样做的含义是选择最接近(x1,y1)的像素点。
然后计算x2,y2,绘制(x2,Round(y2)),其中
x
2
=
x
1
+
1
,
y
2
=
y
1
+
k
x_2=x1+1,y_2=y_1+k
x2=x1+1,y2=y1+k
依次计算x3,y3,x4,y4…直到终点xn,yn。像素点集合(xi,Round(yi))即为组成直线的像素点,其中0<=i<=n。
代码部分:
函数介绍:
def Round(x):
if x >= 0:
return int(x+0.5)
else:
return int(x-0.5)
四舍五入取整函数,注意与python自带的取整函数round()不同。
def ShowPoint(x,y):
plt.plot(x,y,'*')
plt.text(x,y,'(' + str(x) + ',' + str(y) + ')',fontsize = 14)
return
显示函数,作用是显示像素点,并在对应位置标注(x,y)。
以下为主体代码:
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
plt.grid(True)
x=[]
y=[]
Input()
if x[0]==x[1]:
#斜率不存在时
yi = min(y)
for i in range(max(y) - min(y) + 1):
ShowPoint(x[0],yi)
yi = yi + 1
else:
k = (y[1]-y[0])/(x[1]-x[0])
if abs(k)<=1:
#k的正负无所谓
xi = min(x)
yi = min(y) if k>=0 else max(y)
#k>=0时,直线递增,当x最小时,y最小
#k<0时,直线递减,当x最小时, y最大
for i in range(max(x)-min(x) + 1):
ShowPoint(xi, Round(yi))
xi = xi + 1#x增1
yi = yi + k#y增k
else:
#abs(k)大于1的情况
t = 1 / k
yi = min(y)
xi = min(x) if k>0 else max(x)
for i in range(max(y) - min(y) + 1):
ShowPoint(Round(xi),yi)
xi = xi + t
yi = yi + 1
plt.show()
缺点:
在DDA算法中,x(或y)和k必须用浮点数表示,这不便于用硬件实现。