# DDA Line
DDA(Digital Differential Analyzer) 正如其名,就是最直观的直线画法,原始的算法的描述如下:
假设存在屏幕空间上的两个点 $(x1, y1)$ 和 $(x2, y2)$
- 计算 $dx=x2-x1$,$dy=y2-y1$。
- 计算斜率 $k=\frac{dy}{dx}$。
x
从x1
出发,每次向x2
移动一个单位,计算 $y=y1+k(x–x1)$。
|
|
原始算法看起来很可靠,但是仍然有一些可以优化的地方,因为直线是线性且均匀的,所以假如提前计算好了每一次循环的增量,就可以避免 y1 + k * (x - x1)
中的浮点数乘法。
优化过后的 DDA 算法如下:
|
|
# Bresenham’s Line
从上面 DDA 的优化案例可以看出,避免浮点数操作就是优化画线算法的关键。
Bresenham's Line
相比 DDA 不仅有更少的浮点数运算,而且没有浮点数和整数的类型转换。
算法的核心思想如下:
在 $(x_k, y_k)$ 的位置时候,可能走向 $(x_k+1, y_k)$ 也可能走向 $(x_k+1, y_k+1)$,显然,斜线的交点更加靠近谁,就往哪个方向走。
斜率:
$$ k = \frac{\Delta y}{\Delta x} $$
对于每一次循环,执行:
$$ x_{i+1} = x_i + 1\ e_{i+1} = e_i + k\ $$
同时,始终保证 $0 < e < 1$:
$$ e_{i+1} = e_{i+1} - 1, e_{i+1} > 1 $$
最后,得出这个点的 y
:
$$ y_{i+1} = \begin{cases} y_i+1 &\text{if } e_{i+1} \gt 0.5\cr y_i &\text{if } e_{i+1} \le 0.5\cr \end{cases} $$
上面的算法是 Bresenham's Line
的基本思想,还需要进一步优化,减少浮点数运算。
可能产生浮点数的地方是 $k = \frac{\Delta y}{\Delta x}$ 和 $e_{i+1} \gt 0.5$,所以我们最后再把上面所有的过程乘以 $2\Delta x$。
最终,我们的代码如下,其中 $\Delta x = x_2 - x_1, \Delta y = y_2 - y_1$:
|
|
最后的代码虽然看起来简洁,但是因为优化过,第一次接触容易摸不着头脑。
# 其他算法
还有一种叫 Mid-Point Line ,因为它即没有 DDA
简单直接,也没有 Bresenham
效率高,这里就不介绍了。