Это не официальный сайт wikipedia.org 01.01.2023

Алгоритм Брезенхэма — Википедия

Алгоритм Брезенхэма

(перенаправлено с «Алгоритм Брезенхема»)

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

Демонстрация работы алгоритма

АлгоритмПравить

Отрезок проводится между двумя точками — ( x 0 , y 0 )   и ( x 1 , y 1 )  , где в этих парах указаны столбец и строка соответственно, номера которых растут вправо и вниз. Сначала мы будем предполагать, что наша линия идёт вправо и вниз, причём горизонтальное расстояние x 1 x 0   превосходит вертикальное y 1 y 0  , то есть наклон линии от горизонтали — менее 45°. Наша цель состоит в том, чтобы для каждого столбца x между x 0   и x 1   определить, какая строка y ближе всего к линии, и нарисовать точку ( x , y )  .

Общая формула линии между двумя точками:

y y 0 = y 1 y 0 x 1 x 0 ( x x 0 ) .  

Поскольку мы знаем колонку x  , то строка y   получается округлением к целому следующего значения:

y = y 1 y 0 x 1 x 0 ( x x 0 ) + y 0 .  

Однако, вычислять точное значение этого выражения нет необходимости. Достаточно заметить, что y   уменьшается от y 0   и за каждый шаг мы добавляем к x   единицу и добавляем к y   значение наклона (в нашем случае значение наклона будет отрицательным числом):

s = y 1 y 0 x 1 x 0 ,  

которое можно вычислить заранее. Более того, на каждом шаге мы делаем одно из двух: либо сохраняем тот же y, либо уменьшаем его на 1.

Что из этих двух выбрать, можно решить, отслеживая значение ошибки, которое означает вертикальное расстояние между текущим значением y и точным значением y для текущего x. Всякий раз, когда мы увеличиваем x, мы увеличиваем значение ошибки на величину наклона s, приведённую выше. Если ошибка превысила 1.0, линия стала ближе к следующему y, поэтому мы увеличиваем y на 1.0, одновременно уменьшая значение ошибки на 1.0. В реализации алгоритма, приведённой ниже, plot(x,y) рисует точку, а abs возвращает абсолютную величину числа:

 function line(int x0, int x1, int y0, int y1)
     int deltax := abs(x1 - x0)
     int deltay := abs(y1 - y0)
     real error := 0
     real deltaerr := (deltay + 1) / (deltax + 1)
     int y := y0
     int diry := y1 - y0
     if diry > 0 
         diry := 1
     if diry < 0 
         diry := -1
     for x from x0 to x1
         plot(x,y)
         error := error + deltaerr
         if error >= 1.0
             y := y + diry
             error := error - 1.0

Проблема такого подхода в том, что с вещественными величинами, такими как error и deltaerr, компьютеры работают относительно медленно. Кроме того, при вычислениях с плавающей точкой из-за ограничений, связанных с представлением вещественных чисел, невозможно получить точные значения при делении. Это приводит к тому, что в процессе вычислений происходит накопление ошибки и может привести к нежелательным результатам. По этим причинам лучше работать только с целыми числами. Это можно сделать, если умножить все используемые вещественные величины на (deltax + 1). Получаем следующий код:

 function line(int x0, int x1, int y0, int y1)
     int deltax := abs(x1 - x0)
     int deltay := abs(y1 - y0)
     int error := 0
     int deltaerr := (deltay + 1)
     int y := y0
     int diry := y1 - y0
     if diry > 0 
         diry := 1
     if diry < 0 
         diry := -1
     for x from x0 to x1
         plot(x,y)
         error := error + deltaerr
         if error >= (deltax + 1)
             y := y + diry
             error := error - (deltax + 1)

Необходимость прибавлять единицу к deltax и deltay вызвана тем, что функция должна строить линию от точки (x0, y0) до точки (x1, y1) включительно! Теперь мы можем быстро рисовать линии, направленные вправо-вниз с величиной наклона меньше 1. Осталось распространить алгоритм на рисование во всех направлениях. Это достигается за счёт зеркальных отражений, то есть заменой знака (шаг в 1 заменяется на −1), обменом переменных x и y, обменом координат начала отрезка с координатами конца.

Рисование окружностейПравить

Также существует алгоритм Брезенхема для рисования окружностей. По методу построения он похож на рисование линии. В этом алгоритме строится дуга окружности для первого квадранта, а координаты точек окружности для остальных квадрантов получаются симметрично. На каждом шаге алгоритма рассматриваются три пикселя, и из них выбирается наиболее подходящий путём сравнения расстояний от центра до выбранного пикселя с радиусом окружности.

 
Разложение окружности в растр
   // этот алгоритм рисует смежные пиксели,
   // R - радиус, X1, Y1 - координаты центра
   int x := 0
   int y := R
   int delta := 1 - 2 * R
   int error := 0
   while (y >= x)
       drawpixel(X1 + x, Y1 + y)
       drawpixel(X1 + x, Y1 - y)
       drawpixel(X1 - x, Y1 + y)
       drawpixel(X1 - x, Y1 - y)
       drawpixel(X1 + y, Y1 + x)
       drawpixel(X1 + y, Y1 - x)
       drawpixel(X1 - y, Y1 + x)
       drawpixel(X1 - y, Y1 - x)
       error := 2 * (delta + y) - 1
       if ((delta < 0) && (error <= 0))
           delta += 2 * ++x + 1
           continue
       if ((delta > 0) && (error > 0))
           delta -= 2 * --y + 1
           continue
       delta += 2 * (++x - --y)
   // этот алгоритм не рисует смежные пиксели
   var x = 0;
   var y = R;
   var delta = 3 - 2 * y;
   while (x <= y) {
       drawpixel(X1 + x, Y1 + y);
       drawpixel(X1 + x, Y1 - y);
       drawpixel(X1 - x, Y1 + y);
       drawpixel(X1 - x, Y1 - y);
       drawpixel(X1 + y, Y1 + x);
       drawpixel(X1 + y, Y1 - x);
       drawpixel(X1 - y, Y1 + x);
       drawpixel(X1 - y, Y1 - x);
       delta += delta < 0 ? 4 * x + 6 : 4 * (x - y--) + 10;
       ++x;
   }

ЛитератураПравить

См. такжеПравить