在看 这篇文章时,上面的公式没明白,这里做笔记记录一下。

这里表达的是:用一个“判别变量 d”来画直线,每次不用重新代入直线方程算,而是用增量更新。
它本质上是在讲 Bresenham / 中点画线算法。
1. 这条直线先被写成隐式方程
图里给了:
这其实就是过两点:
的直线方程。
它的作用不是直接求 (y=kx+b),而是判断一个点 ((x,y)) 在直线的哪一侧。
对于这条直线:
表示点正好在直线上。
如果:
说明点在直线一侧。
如果:
说明点在直线另一侧。
在常见的数学坐标系下,假设 (0<k<1),也就是直线从左下往右上走,那么:
通常表示点在直线上方;
表示点在直线下方。
2. 画线时,每次 x 增加 1
假设我们从左往右画线,并且斜率满足:
也就是说,直线比较平缓。
那么每走一步,(x) 必然加 1。
但是 (y) 有两个选择:
选择 1:往右走
这个像素可以叫做 E,East。
选择 2:往右上走
这个像素可以叫做 NE,North-East。
所以问题变成:
下一步到底选 ((x+1,y)),还是选 ((x+1,y+1))?
3. 用中点判断选下面还是上面
这两个候选像素中间有一个点:
它就是下面像素和上面像素之间的中点。
也就是:
(x+1, y+1) 上面的候选像素(x+1, y+0.5) 中点(x+1, y) 下面的候选像素
于是算法的判断逻辑是:
如果真实直线在这个中点上方,那么上面的像素更接近直线,选:
如果真实直线在这个中点下方,那么下面的像素更接近直线,选:
所以我们只需要判断:
的符号。
图里写:
这个 (d) 就是第一次的中点判别值。
4. 为什么 d < 0 时 y = y + 1?
图里的伪代码是:
if d < 0 theny = y + 1d = d + (x1 - x0) + (y0 - y1)
elsed = d + (y0 - y1)
这里的含义是:
当前中点是:
计算:
如果:
说明这个中点在直线下方。
也就是说,真实直线比中点更高。
因此上面的像素 ((x+1,y+1)) 更接近直线,所以:
如果:
说明中点在直线上方或正好在线上,那么下面的像素 ((x+1,y)) 更合适,所以 (y) 不变。
5. 重点:为什么后面不用重新算 f?
如果每一步都重新算:
那就要做乘法、加法,比较麻烦。
但是观察这个函数:
它是一个一次函数。
所以当 (x) 增加 1 时,(f) 的变化量是固定的。
情况一:下一步只向右走
也就是从:
变成:
那么:
这就是图里第一条:
意思是:
横坐标加 1,纵坐标不变时,f 的值只需要加上 ((y_0-y_1))。
情况二:下一步向右上走
也就是从:
变成:
那么:
这就是图里第二条:
意思是:
横坐标加 1,纵坐标也加 1 时,f 的值只需要加上两个增量。
6. 把整个过程用人话说一遍
假设当前已经画到了:
下一列一定是:
但是有两个候选像素:
和:
于是看它们中间的点:
如果真实直线在这个中点上方,就选上面的像素。
如果真实直线在这个中点下方,就选下面的像素。
判断中点在直线哪边,用:
如果:
说明中点在直线下方,选上面的像素,所以:
如果:
说明中点在直线上方,选下面的像素,所以 (y) 不变。
然后更新 (d)。
关键是,更新 (d) 不用重新算 (f),只需要加固定增量。
7. 图里的伪代码整体含义
y = y0
d = f(x0 + 1, y0 + 0.5)for x = x0 to x1 dodraw(x, y)if d < 0 theny = y + 1d = d + (x1 - x0) + (y0 - y1)elsed = d + (y0 - y1)
对应的中文解释是:
- 从起点 ((x_0,y_0)) 开始。
- 初始 (y=y_0)。
- 先计算第一个中点的判别值:
- 每次画当前像素 ((x,y))。
- 然后判断下一步应该走右边还是右上。
- 如果 (d<0),说明真实直线在中点上方,所以 (y) 加 1。
- 如果 (d> 0),说明真实直线在中点下方或附近,所以 (y) 不变。
- 每次根据走法更新 (d),避免重新计算直线方程。
8. 核心一句话
这段想表达的是:
画一条斜率在 (0) 到 (1) 之间的直线时,每次 (x) 加 1,(y) 只可能不变或者加 1。为了决定选哪个像素,用中点 ((x+1,y+0.5)) 判断真实直线在上方还是下方。判别值 (d=f(x+1,y+0.5)) 第一次直接算,之后用固定增量更新,所以整个算法不需要反复做浮点乘除运算。
这就是中点画线算法的核心。
