Алгоритм Брезенхема растрового построения линии

Алгоритм Брезенхема (англ. Bresenham's line algorithm) — это алгоритм, определяющий, какие точки двумерного растра нужно закрасить, чтобы получить близкое приближение прямой линии между двумя заданными точками. Это один из старейших алгоритмов в машинной графике — он был разработан Джеком Е. Брезенхемом (Jack E. Bresenham) в компании IBM в 1962 году. Алгоритм широко используется, в частности, для рисования линий на экране компьютера.

В алгоритме используется управляющая переменная $d_i$, которая на каждом шаге пропорциональна разности между $s$ и $t$ (см. рис.1). На рисунке 1 приведен i-ый шаг, когда пиксель $P_{i-1}$ уже найден как ближайший к реальному изображаемому отрезку, и теперь требуется определить, какой из пикселей должен быть установлен следующим: $T_i$ или $S_i$.

Рис.1

Если $s < t$, то $S_i$ ближе к отрезку и необходимо выбрать его; в противном случае ближе находится $T_i$. Другими словами, если $s - t < 0$, то выбирается $S_i$; иначе выбирается $T_i$.

Отрезок в примере (на рис.1) проводится из точки $(x_1, y_1)$ в точку $(x_2, y_2)$. Пусть первая точка находится ближе к началу координат, тогда вычтем из соответствующих координат $x_1$ и $y_1$ тем самым перенеся первую точку в начало координат, тогда конечная окажется в $(Δx, Δy)$, где $Δx = x_2 - x_1$, $Δy = y_2 - y_1$. Уравнение прямой теперь имеет вид $y = x\frac{Δy}{Δx}$. В рассматриваемом примере предполагается, что $Δx >= Δy$ и $Δy >= 0$.

Из рисунка 1 следует, что

$$s = \frac{Δy}{Δx}(x + 1) - y, \\
t = y + 1 - \frac{Δy}{Δx}(x + 1)$$

поэтому

$$s - t = 2 \frac{Δy}{Δx}(x + 1) - 2y - 1$$

Домножим обе части равенства на Δx:

$$Δx(s - t) = 2(Δy\cdot x - y\cdot Δx) + 2Δy - Δx$$

Так как $Δx > 0$, то величину $Δx(s-t)$ можно использовать в качестве критерия для выбора пикселя. Обозначим эту величину $d_i$:

$$d_i = 2(Δy\cdot x_{i-1} - y_{i-1}\cdot Δx) + 2Δy - Δx$$

Так как $d_i$ надо считать на каждом шаге, рассчитаем величину $Δ_i$ — приращения $d_i$:

$$Δ_i = d_i - d_{i-1} = 2Δy(x_i - x_{i-1}) - 2Δx(y_i - y_{i-1})$$

Известно, что $x_i – x_{i-1} = 1$.

Если $d_i >= 0$, то выбираем $T_i$, т.е. $y_i — y_{i-1} = 1$ (перемещаем точку по y), а $Δ_i$ тогда равно

$$Δ_i = 2(Δy - Δx)$$

Если $d_i < 0$, то выбираем $S_i$, т.е. $y_i — y_{i-1} = 0$ (у не меняется), тогда $Δ_i = 2Δy$.

Таким образом, мы получили итеративную формулу для вычисления критерия di.

Начальное значение $d_1 = 2Δy - Δx$.

Важно учитывать, что такой алгоритм требует определения ещё одного параметра — значения, определяющего изменение yi. В примере мы предполагали $Δy >= 0$, а потому при перемещении точки изменяли значение на +1. Если значение $Δy < 0$, то изменение происходит на -1.

Аналогично рассматривается случай, когда $Δx < Δy$. Алгоритм Брезенхэма в своей реализации требует учёт всех возможных ситуаций взаимного расположения точек.

Код алгоритма Брезенхемма построения линии на JavaScript:

function drawLine(x1, y1, x2, y2) {
    var deltaX = Math.abs(x2 - x1);
    var deltaY = Math.abs(y2 - y1);
    var signX = x1 < x2 ? 1 : -1;
    var signY = y1 < y2 ? 1 : -1;
    var d = deltaX - deltaY;
    plot(x2, y2); // Ставим точку собственной функцией, т.к. JS не имеет оператора точки
    while(x1 != x2 || y1 != y2) 
    {
        plot(x1, y1);
        var d2 = d * 2;
        if(d2 > -deltaY) 
        {
            d -= deltaY;
            x1 += signX;
        }
        if(d2 < deltaX) 
        {
            d += deltaX;
            y1 += signY;
        }
    }
}