中点算法是基于隐函数方程设计的,使用像素网格中点来判断如何选取距离理想直线最近的像素点,直线的中点算法不仅与 Bresenham 算法产生同样的像素点集,二期还可以推广到圆和椭圆。
原理
直线的隐函数表示
F
(
x
,
y
)
=
y
−
k
x
−
b
=
0
F(x, y) = y -kx -b = 0
F(x,y)=y−kx−b=0
理想直线将平面划分成三个区域
对于直线上的点, $F(x, y) = 0 $
对于直线上方的点,
F
(
x
,
y
)
>
0
F(x, y) >0
F(x,y)>0
对于直线下方的点,
F
(
x
,
y
)
<
0
F(x, y) <0
F(x,y)<0
中点误差项
d i = F ( x i + 1 , y i + 0.5 ) = y i + 0.5 − k ( x i + 1 ) − b d_i = F(x_i + 1, y_i + 0.5) = y_i + 0.5 - k(x_i + 1) -b di=F(xi+1,yi+0.5)=yi+0.5−k(xi+1)−b
y i + 1 = { y i + 1 d i < 0 y i d i ≥ 0 y_{i+1} = \begin{cases} y_i + 1 & d_i < 0 \\ y_i & d_i \geq 0 \end{cases} yi+1={yi+1yidi<0di≥0
中点误差项的递推公式
- 当 d i < 0 d_i < 0 di<0 , 下一步进行判断的中点为 M u ( x i + 2 , y i + 1.5 ) M_u(x_i +2,y_i+ 1.5) Mu(xi+2,yi+1.5) , 中点的误差项的递推公式为
d
i
+
1
=
d
i
+
1
−
k
d_{i+1} = d_{i} + 1 - k
di+1=di+1−k
上一步选择 P u P_u Pu 后,中点误差项的增量为 1 − k 1-k 1−k
- 当
d
i
≥
0
d_i \geq 0
di≥0 时,下一步进行判断的中点为
M
d
(
x
i
+
2
,
y
i
+
0.5
)
M_d(x_i + 2, y_{i} + 0.5)
Md(xi+2,yi+0.5) 中点的误差项的递推公式为
d
i
+
1
=
d
i
−
k
d_{i+1} = d_i - k
di+1=di−k
上一步选择
P
d
P_d
Pd 后,中点误差项的增量为
−
k
-k
−k
中点误差项的初始值
直线的起点坐标扫描转换后的像素为 P 0 ( x 0 , y 0 ) P_0(x_0, y_0) P0(x0,y0) .从像素 P 0 P_0 P0 出发沿着主位移 x x x 方向的递增一个单位,第一个参与判断的中点是 M ( x 0 + 1 , y 0 + 0.5 ) M(x_0+1, y_0 + 0.5) M(x0+1,y0+0.5)。 代入中点误差项计算公式, d d d 的初始值为
d 0 = 0.5 − k d_0 = 0.5 - k d0=0.5−k
算法
- 设置像素点的颜色
- 读入直线的两个端点坐标
- 计算中点误差项的初始值 d d d
- 当 d < 0 d <0 d<0 时, d d d 的增量为 1 − k 1-k 1−k, 当 d ≥ 0 d \geq 0 d≥0 时, d 的增量为 − k d 的增量为 -k d的增量为−k
- 根据每一步中点误差项的值,选择像素点并绘制出来
void MidPointLine(CDC* pDC, CPoint P0, CPoint P1) {
COLORREF crColor = RGB(0, 0, 0);
double k, d;
int dx = P1.x - P0.x;
int dy = P1.y - P1.y;
k = double (dy) / dx;
d = 0.5 -k;
double inColorUp = 1 - k;
double inColorDown = -k;
for (int x=P0.x, y= P0.y; x <P1.x; x++) {
pDC->SetPixelV(x, y, crColor)
if (d <0) {
y++;
d += inColorUp;
}
else {
d += inColorDown;
}
}
}
总结
中点算法是一种浮点数算法,现在的计算机做浮点数运算和整数运算一样快
中点算法设计巧妙,不需要取证操作
中点算法同样适用于绘制圆和椭圆
参考 《计算几何算法与实现》孔令德