概述
中点画线法(Midpoint Line Algorithm)是一种画线(Line Drawing)算法,用来在计算机屏幕上绘制线条。
它的基本思想是从线段的起点和终点出发,按照一定的规则向终点逐步逼近,并在途中以控制变量的方式得出每个像素点的坐标,从而绘制出所需的线条。
具体实现中,中点画线法通过计算线段斜率的变化情况,来分为斜率小于1和大于等于1两种情况,并采用Bresenham的对称性原理,以中点的颜色来控制每个像素点的生长方向,从而获得较高的绘制效率和图像质量表现。
总的来说,中点画线法是一种高效且易于实现的线段绘制算法,也是计算机图形学领域最基本的算法之一。
一、基本思想
当前像素点为
(
x
p
,
y
p
)
(x_p,y_p)
(xp,yp),下一个像素点为
P
1
P1
P1或
P
2
P2
P2。
设
M
=
(
x
p
+
1
,
y
p
+
0.5
)
M=(x_p+1,y_p+0.5)
M=(xp+1,yp+0.5)为
P
1
P1
P1与
P
2
P2
P2之中点,
Q
Q
Q为理想直线与
x
=
x
p
+
1
x=x_p+1
x=xp+1垂线的交点。将
Q
Q
Q与
M
M
M的
y
y
y坐标进行比较。
当
M
M
M在
Q
Q
Q的下方,则
P
2
P2
P2应为下一个像素点;当
M
M
M在
Q
Q
Q的上方,则
P
1
P1
P1应为下一个像素点。
二、构造判别式:
d
=
F
(
M
)
=
F
(
x
p
+
1
,
y
p
+
0.5
)
=
a
(
x
p
+
1
)
+
b
(
y
p
+
0.5
)
+
c
d=F(M)=F(x_p+1,y_p+0.5)=a(x_p+1)+b(y_p+0.5)+c
d=F(M)=F(xp+1,yp+0.5)=a(xp+1)+b(yp+0.5)+c
其中,
a
=
y
0
−
y
1
,
b
=
x
1
−
x
0
,
c
=
x
0
y
1
−
x
1
y
0
a=y_0-y_1, b=x_1-x_0, c=x_0y_1-x_1y_0
a=y0−y1,b=x1−x0,c=x0y1−x1y0.
- 当 d < 0 d<0 d<0时, M M M在 L ( Q L(Q L(Q点 ) ) )下方,取右上方 P 2 ( x p + 1 , y p + 1 ) P2(x_p+1,y_p+1) P2(xp+1,yp+1)为下一个像素;
- 当 d > 0 d>0 d>0时, M M M在 L ( Q L(Q L(Q点 ) ) )上方,取右方 P 1 ( x p + 1 , y p ) P1(x_p+1,y_p) P1(xp+1,yp)为下一个像素;
- 当 d = 0 d=0 d=0时,选 P 1 P1 P1或 P 2 P2 P2均可,约定取 P 1 ( x p + 1 , y p ) P1(x_p+1,y_p) P1(xp+1,yp)为下一个像素;
三、递推出增量
若当前像素处于:
d
≥
0
d\geq 0
d≥0情况,则取正右方像素
P
1
(
x
p
+
1
,
y
p
)
P1(x_p+1, y_p)
P1(xp+1,yp),要判下一个像素位置,应计算
d
1
=
F
(
x
p
+
2
,
y
p
+
0.5
)
=
a
(
x
p
+
2
)
+
b
(
y
p
+
0.5
)
=
d
+
a
d1=F(x_p+2, y_p+0.5)=a(x_p+2)+b(y_p+0.5)=d+a
d1=F(xp+2,yp+0.5)=a(xp+2)+b(yp+0.5)=d+a
增量为
a
a
a。
d
<
0
d<0
d<0时,则取右上方像素
P
2
(
x
p
+
1
,
y
p
+
1
)
P2(x_p+1, y_p+1)
P2(xp+1,yp+1)。要判断再下一像素,则要计算
d
2
=
F
(
x
p
+
2
,
y
p
+
1.5
)
=
a
(
x
p
+
2
)
+
b
(
y
p
+
1.5
)
+
c
=
d
+
a
+
b
d2= F(x_p+2, y_p+1.5)=a(x_p+2)+b(y_p+1.5)+c=d+a+b
d2=F(xp+2,yp+1.5)=a(xp+2)+b(yp+1.5)+c=d+a+b
增量为
a
+
b
a+b
a+b。
优化:
由于画线从
(
x
0
,
y
0
(x_0, y_0
(x0,y0)开始,
d
d
d的初值为:
d
0
=
F
(
x
0
+
1
,
y
0
+
0.5
)
=
F
(
x
0
,
y
0
)
+
a
+
0.5
b
=
a
+
0.5
b
d_0=F(x_0+1, y_0+0.5)=F(x_0, y_0)+a+0.5b=a+0.5b
d0=F(x0+1,y0+0.5)=F(x0,y0)+a+0.5b=a+0.5b
可以用
2
d
2d
2d代替
d
d
d来避免小数,提高效率。令
d
0
=
2
a
+
b
,
d
1
=
2
a
,
d
2
=
2
a
+
2
b
d_0=2a+b, d_1=2a, d_2=2a+2b
d0=2a+b,d1=2a,d2=2a+2b。
总结:
如果 d > 0 d > 0 d>0,则中点 ( x , y m ) (x_, y_m) (x,ym)在 L ( Q ) L(Q) L(Q)的上方,此时应该取右边的像素点 P 1 ( x p + 1 , y p ) P1(x_p+1,y_p) P1(xp+1,yp),即 x x x加1、 y y y不变。此时, d d d的值增加 d 1 d1 d1,即 d = d + d 1 d=d+d1 d=d+d1。
如果 d < 0 d<0 d<0,则中点 ( x m , y m ) (x_m, y_m) (xm,ym)在 L ( Q ) L(Q) L(Q)的下方,应该取右上方的像素点 P 2 ( x p + 1 , y p + 1 ) P2(x_p+1,y_p+1) P2(xp+1,yp+1),即 x x x和 y y y均加1。此时, d d d的值增加 d 2 d2 d2,即 d = d + d 2 d=d+d2 d=d+d2。
四、例题分析
以P0(0,0)到P1(5,2)为例,使用中点画线法,计算 d 0 d_0 d0, d 1 d_1 d1和 d 2 d_2 d2,并画出对应表格。
首先,根据两点坐标求出
a
a
a、
b
b
b、
c
c
c的值,有:
a
=
y
0
−
y
1
=
−
2
a=y_0-y_1=-2
a=y0−y1=−2
b
=
x
1
−
x
0
=
5
b=x_1-x_0=5
b=x1−x0=5
c
=
x
0
y
1
−
x
1
y
0
=
−
10
c=x_0y_1-x_1y_0=-10
c=x0y1−x1y0=−10
接着,根据公式得到
d
0
d_0
d0,
d
1
d_1
d1和
d
2
d_2
d2的初值,有:
d
0
=
2
a
+
b
=
1
d_0 = 2a+b = 1
d0=2a+b=1
d
1
=
2
a
=
−
4
d_1 = 2a = -4
d1=2a=−4
d
2
=
2
a
+
2
b
=
6
d_2 = 2a+2b = 6
d2=2a+2b=6
然后,根据中点画线法的算法流程结合总结,可以按照如下表格计算每个像素点的坐标 ( x i , y i ) (x_i,y_i) (xi,yi)以及 d i d_i di的变化:
count | x | y | d | P |
---|---|---|---|---|
0 | 0 | 0 | 1 | P0 |
1 | 1 | 0 | -3 | |
2 | 2 | 1 | 3 | |
3 | 3 | 1 | -1 | |
4 | 4 | 2 | 5 | |
5 | 5 | 2 | 1 | P1 |
其中, P P P表示像素点位置, c o u n t count count表示计数, d d d表示中点到直线距离的判别式值(经过放大2倍),根据 d > 0 d>0 d>0还是 d < 0 d < 0 d<0判断所选的下一个像素点。对于 d = 0 d=0 d=0,约定选择右下方的像素点。
最终,依照算法,连线的轨迹如下:
P0 (0, 0) -> (1, 1) -> (2, 1) -> (3, 2) -> (4, 2) -> P1 (5, 2)
如下图:
五、伪代码
/* mid PointLine */
void Midpoint Line (int x0,int y0,int x1, int y1,int color)
{ int a, b, d1, d2, d, x, y;
a=y0-y1, b=x1-x0, d=2*a+b;
d1=2*a, d2=2* (a+b);
x=x0, y=y0;
drawpixel(x, y, color);
while (x<x1)
{ if (d<0) {x++, y++, d+=d2; }
else {x++, d+=d1;}
drawpixel (x, y, color);
} /* while */
}