Алгоритм брезенхема на c для построения прямой. Алгоритм брезенхема для рисования наклонных отрезков

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

Алгоритм брезенхема на c для построения прямой. Алгоритм брезенхема для рисования наклонных отрезков

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

Алгоритм Брезенхэма -это алгоритм, определяющий, какие точки двумерного растра нужно закрасить, чтобы получить близкое приближение прямой линии между двумя заданными точками.

Это один из старейших алгоритмов в машинной графике — он был разработан Джеком Е. Брезенхэм компании IBM в 1962 году. Алгоритм широко используется, в частности, для рисования линий на экране компьютера.

Существует обобщение алгоритма Брезенхэма для построения кривых 2-го порядка.

Более подробно про растровые алгоритмы, к которым относится данный алгоритм смотри в вопросе №13.

Алгоритм:

Отрезок проводится между двумя точками — (x0,y0) и (x1,y1), где в этих парах указаны колонка и строка, соответственно, номера которых растут вправо и вниз.

Сначала мы будем предполагать, что наша линия идёт вниз и вправо, причём горизонтальное расстояние x1 − x0 превосходит вертикальное y1 − y0, т.е. наклон линии от горизонтали — менее 45°.

Наша цель состоит в том, чтобы для каждой колонки x между x0 и x1, определить, какая строка y ближе всего к линии, и нарисовать точку (x,y).

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

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

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

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

Что из этих двух выбрать — можно решить, отслеживая значение ошибки, которое означает — вертикальное расстояние между текущим значением y и точным значением y для текущего x.

Всякий раз, когда мы увеличиваем x, мы увеличиваем значение ошибки на величину наклона s, приведённую выше. Если ошибка превысила 0.5, линия стала ближе к следующему y, поэтому мы увеличиваем y на единицу, одновременно уменьшая значение ошибки на 1.

В реализации алгоритма, приведённой ниже, plot(x,y)рисует точку, а abs возвращает абсолютную величину числа:

function line(x0, x1, y0, y1)

     int deltax := abs(x1 – x0)

     int deltay := abs(y1 – y0)

     real error := 0

     real deltaerr := deltay / deltax

     int y := y0

     for x from x0 to x1

         plot(x,y)

         error := error + deltaerr

         if error >= 0.5

             y := y + 1

             error := error – 1.0

Проблема такого подхода — в том, что с вещественными величинами, такими как error и deltaerr, компьютеры работают относительно медленно. Кроме того, при вычислениях с плавающей точкой может накапливаться ошибка.

По этим причинам, лучше работать только с целыми числами. Это можно сделать, если умножить все используемые вещественные величины на deltax. Единственная проблема — с константой 0.

5 — но в данном случае достаточно умножить обе части неравенства на 2. Получаем следующий код:

function line(x0, x1, y0, y1)

     int deltax := abs(x1 – x0)

     int deltay := abs(y1 – y0)

     int error := 0

     int deltaerr := deltay

     int y := y0

     for x from x0 to x1

         plot(x,y)

         error := error + deltaerr

         if 2 * error >= deltax

             y := y + 1

             error := error – deltax

Умножение на 2 для целых чисел реализуется битовым сдвигом влево.

Теперь мы можем быстро рисовать линии, направленные вправо-вниз с величиной наклона меньше 1. Осталось распространить алгоритм на рисование во всех направлениях. Это достигается за счёт зеркальных отражений, т.е. заменой знака (шаг в 1 заменяется на -1), обменом переменных x и y, обменом координат начала отрезка с координатами конца.

Из презентации:

Отрезок от A(xa, ya) до B(xb, yb)

0 £ yb- ya £ xb- xa, k=(yb- ya) / (xb- xa) y = ya+ k (x – xa)

procedure line(xa,ya,xb,yb:integer);

var k,y : double;

begin

                k:=(yb-ya)/(xb-xa);

                y:=ya;

                for i:=xa to xb do begin

                               put(x,round(y)); y:=y+k

                end;

end;

Источник: https://ek-ek.jimdofree.com/%D0%BF%D0%B5%D1%82%D1%83%D1%85%D0%B8%D0%BD/%D0%BA%D0%BE%D0%BC%D0%BF-%D0%B3%D1%80%D0%B0%D1%84%D0%B8%D0%BA%D0%B0/%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC-%D0%B1%D1%80%D0%B5%D0%B7%D0%B5%D0%BD%D1%85%D0%B5%D0%BC%D0%B0-%D1%80%D0%B8%D1%81%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F-%D0%BE%D1%82%D1%80%D0%B5%D0%B7%D0%BA%D0%B0/

Брезенхем и У на страже диагоналей

Алгоритм брезенхема на c для построения прямой. Алгоритм брезенхема для рисования наклонных отрезков

На что вы сейчас смотрите? Если вы не из параллельной вселенной, где все сидят за векторными мониторами, то перед вами растровое изображение. Поглядите на эту полоску: /. Если придвинуться поближе к монитору, то можно увидеть пиксельные ступеньки, которые пытаются притвориться векторной линией.

Для этой цели существует целая куча всевозможных алгоритмов растеризации, но я бы хотел рассказать об алгоритме Брезенхема и алгоритме У, которые находят приближение векторного отрезка в растровых координатах. С проблемой растеризации мне довелось столкнуться во время работы над процедурным генератором планов зданий.

Мне нужно было представить стены помещения в виде ячеек двумерного массива. Похожие задачи могут встретиться в физических расчётах, алгоритмах поиска пути или расчёте освещения, если используется разбиение пространства. Кто бы мог подумать, что знакомство с алгоритмами растеризации однажды может пригодиться?
Принцип работы алгоритма Брезенхема очень простой.

Берётся отрезок и его начальная координата x. К иксу в цикле прибавляем по единичке в сторону конца отрезка. На каждом шаге вычисляется ошибка — расстояние между реальной координатой y в этом месте и ближайшей ячейкой сетки. Если ошибка не превышает половину высоты ячейки, то она заполняется. Вот и весь алгоритм.

Это была суть алгоритма, на деле всё выглядит следующим образом. Сначала вычисляется угловой коэффициент (y1 — у0)/(x1 — x0). Значение ошибки в начальной точке отрезка (0,0) принимается равным нулю и первая ячейка заполняется. На следующем шаге к ошибке прибавляется угловой коэффициент и анализируется её значение, если ошибка меньше 0.

5, то заполняется ячейка (x0+1, у0), если больше, то заполняется ячейка (x0+1, у0+1) и из значения ошибки вычитается единица. На картинке ниже жёлтым цветом показана линия до растеризации, зелёным и красным — расстояние до ближайших ячеек.

Угловой коэффициент равняется одной шестой, на первом шаге ошибка становится равной угловому коэффициенту, что меньше 0.5, а значит ордината остаётся прежней. К середине линии ошибка пересекает рубеж, из неё вычитается единица, а новый пиксель поднимается выше. И так до конца отрезка.

Ещё один нюанс. Если проекция отрезка на ось x меньше проекции на ось y или начало и конец отрезка переставлены местами, то алгоритм не будет работать.

Чтобы этого не случилось, нужно проверять направление вектора и его наклон, а потом по необходимости менять местами координаты отрезка, поворачивать оси, и, в конечном итоге, сводить всё к какому-то одному или хотя бы двум случаям.

Главное не забывать во время рисования возвращать оси на место.

Для оптимизации расчётов, применяют трюк с умножением всех дробных переменных на dx = (x1 — x0). Тогда на каждом шаге ошибка будет изменяться на dy = (y1 — y0) вместо углового коэффициента и на dx вместо единицы. Также можно немного поменять логику, «передвинуть» ошибку так, чтобы граница была в нуле, и можно было проверять знак ошибки, это может быть быстрее.

Примерно так может выглядеть код для рисования растровой линии по алгоритму Брезенхема. Псевдокод из Википедии переделанный под C#.void BresenhamLine(int x0, int y0, int x1, int y1){ var steep = Math.Abs(y1 – y0) > Math.Abs(x1 – x0); // Проверяем рост отрезка по оси икс и по оси игрек // Отражаем линию по диагонали, если угол наклона слишком большой if (steep) { Swap(ref x0, ref y0); // Перетасовка координат вынесена в отдельную функцию для красоты Swap(ref x1, ref y1); } // Если линия растёт не слева направо, то меняем начало и конец отрезка местами if (x0 > x1) { Swap(ref x0, ref x1); Swap(ref y0, ref y1); } int dx = x1 – x0; int dy = Math.Abs(y1 – y0); int error = dx / 2; // Здесь используется оптимизация с умножением на dx, чтобы избавиться от лишних дробей int ystep = (y0 < y1) ? 1 : -1; // Выбираем направление роста координаты y int y = y0; for (int x = x0; x = y) { DrawPoint(x + x0, y + y0); DrawPoint(y + x0, x + y0); DrawPoint(-x + x0, y + y0); DrawPoint(-y + x0, x + y0); DrawPoint(-x + x0, -y + y0); DrawPoint(-y + x0, -x + y0); DrawPoint(x + x0, -y + y0); DrawPoint(y + x0, -x + y0); y++; if (radiusError < 0) { radiusError += 2 * y + 1; } else { x--; radiusError += 2 * (y - x + 1); } }} Теперь про алгоритм У Сяолиня для рисования сглаженных линий. Он отличается тем, что на каждом шаге ведётся расчёт для двух ближайших к прямой пикселей, и они закрашиваются с разной интенсивностью, в зависимости от удаленности. Точное пересечение середины пикселя даёт 100% интенсивности, если пиксель находится на расстоянии в 0.9 пикселя, то интенсивность будет 10%. Иными словами, сто процентов интенсивности делится между пикселями, которые ограничивают векторную линию с двух сторон. На картинке выше красным и зелёным цветом показаны расстояния до двух соседних пикселей. Для расчёта ошибки можно использовать переменную с плавающей запятой и брать значение ошибки из дробной части. Примерный код сглаженной линии У Сяолиня на C#.private void WuLine(int x0, int y0, int x1, int y1){ var steep = Math.Abs(y1 – y0) > Math.Abs(x1 – x0); if (steep) { Swap(ref x0, ref y0); Swap(ref x1, ref y1); } if (x0 > x1) { Swap(ref x0, ref x1); Swap(ref y0, ref y1); } DrawPoint(steep, x0, y0, 1); // Эта функция автоматом меняет координаты местами в зависимости от переменной steep DrawPoint(steep, x1, y1, 1); // Последний аргумент — интенсивность в долях единицы float dx = x1 – x0; float dy = y1 – y0; float gradient = dy / dx; float y = y0 + gradient; for (var x = x0 + 1; x

Источник: https://habr.com/post/185086/

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

Алгоритм брезенхема на c для построения прямой. Алгоритм брезенхема для рисования наклонных отрезков

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

Хотя алгоритм Брезенхема был первоначально разработан для цифровых графопостроителей, однако он в равной степени подходит для использования растровыми устройствами с ЭЛТ. Алгоритм выбирает оптимальные растровые координаты для представления отрезка.

В процессе работы одна из координат – либо x, либо y (в зависиимости от углового коэффициента) – изменяется на единицу. Изменение другой координаты (на 0 или 1) зависит от расстояния между действительным положением отрезка и ближайшими координатами сетки.

Такое расстояние мы назовем ошибкой.

Алгоритм построен так, что требуется проверить лишь знак этой ошибки. На рис.3.1 это иллюстрируется для отрезка в первом октанте, т.е. для отрезка с угловым коэффициентом, лежащим в диапазоне от 0 до 1.

Из рисунка можно заметить, что если угловой коэффициент отрезка из точки (0,0) больше, чем 1/2, то пересечение с прямой x = 1 будет расположено ближе к прямой y = 1, чем к прямой y = 0. Следовательно, точка растра (1,1) лучше аппроксимирует ход отрезка, чем точка (1,0). Если угловой коэффициент меньше 1/2, то верно обратное.

для углового кэффициента, равного 1/2, нет какого либо предпочтительного выбора. В данном случае алгоритм выбирает точку (1,1).

Рис. 3.1. Основная идея алгоритма Брезенхема.

Не все отрезки проходят через точки растра. Подобная ситуация иллюстрируется рис.3.2, где отрезок с тангенсом угла наклона 3/8 сначала походит через точку растра (0,0) и последовательно пересекает три пиксела. Также иллюстрируется вычисление ошибки при представлении отрезка дискретными пикселами.

Рис.3.2. График ошибки в алгоритме Брезенхема.

Так как желательно проверять только знак ошибки, то она первоначально устанавливается равной -1/2. Таким образом, если угловой коэффициент отрезка больше или равен 1/2, то величина ошибки в следующей точке растра с координатами (1,0) может быть вычислена как

e = e + m

где m – угловой коэффициент. В нашем случае при начальном значении ошибки -1/2

e = 1/2 + 3/8 = -1/8

Так как е отрицательно, отрезок пройдет ниже середины пиксела. Следовательно, пиксел на том же самом горизонтальном уровне лучше аппроксимирует положение отрезка, поэтому у не увеличивается. Аналогично вычисляем ошибку

e = -1/8 + 3/8 = 1/4

в следующей точке растра (2,0). Теперь е положительно, значит отрезок пройдет выше средней точки. Растровый элемент (2,1) со следующей по величине координатой у лучше аппроксимирует положение отрезка. Следовательно у увеличивается на 1. Прежде чем рассматривать следующий пиксел, необходимо откорректировать ошибку вычитанием из нее 1. Имеем

e = 1/4 – 1 = -3/4

Заметим, что пересечение вертикальной прямой x = 2 с заданным отрезком лежит на 1/4 ниже прямой у = 1. Еслиже перенести отрезок 1/2 вниз, мы получим как раз величину -3/4. Продолжение вычислений для следующего пиксела дает

e = -3/4 + 3/8 = -3/8

Так как е отрицательно, то у не увеличивается. Из всего сказанного следует, что ошибка – это интервал, отсекаемый по оси у рассматриваемым отрезком в каждом растровом элементе (относительно -1/2).

Приведем алгоритм Брезенхема для первого октанта, т.е. для случая 0 =< Dy =< Dx.

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

предполагается, что концы отрезка (x1,y1) и (x2,y2) не совпадают

Integer – функция преобразования в целое

x, y, Dx, Dy – целые

е – вещественное

инициализация переменных

x = x1

y = y1

Dx = x2 – x1

Dy = y2 – y1

Инициализация с поправкой на половину пиксела

е = Dy/Dx – 1/2

начало основного цикла

for i = 1 to Dx

plot (x,y)

while ( e => 0 )

y = y + 1

e = e – 1

end while

x = x + 1

e = e + Dy/Dx

next i

finish

Блок-схема алгоритма приводится на рис.3.3. Пример приведен ниже.

Рис. 3.3. Блок-схема алгоритма Брезенхема.

Пример 3.1. Алгоритм Брезенхема.

Рассмотрим отрезок проведенный из точки (0,0) в точку (5,5). Разложение отрезка в растр по алгоритму Брезенхема приводит к такому результату:

начальные установки

x = 0

y = 0

Dx = 5

Dy = 5

е = 1 – 1/2 = 1/2

результаты работы пошагового цикла

iPlotexy
1/200
1(0,0)
-1/201
1/211
2(1,1)
-1/212
1/222
3(2,2)
-1/223
1/233
4(3,3)
-1/234
1/244
5(4,4)
-1/255
1/255

Результат показан на рис.3.4 и совпадает с ожидаемым. Заметим, что точка растра с координатами (5,5) не активирована. Эту точку можно активировать путем изменения цикла for-next на 0 to Dx. Активацию точки (0,0) можно устранить, если поставить оператор Plot непосредственно перед строкой next i.

Рис. 3.4. Результат работы алгоритма Брезенхема в первом октанте.

В следующем разделе описан общий алгоритм Брезенхема.

Источник: http://www.mari-el.ru/mmlab/home/kg/Lection5/3.html

Алгоритм Брезенхема растровой дискретизации отрезка

Алгоритм брезенхема на c для построения прямой. Алгоритм брезенхема для рисования наклонных отрезков

Лекция: Растровое преобразование графических примитивов

  • Алгоритм Брезенхема растровой дискретизации отрезка
  • Алгоритмы Брезенхема растровой дискретизации окружности и эллипса
  • Алгоритмы заполнения областей
  • Вопросы и упражнения

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

При построении растрового образа отрезка необходимо, прежде всего, установить критерии “хорошей” аппроксимации.

Первое требование состоит в том, что отрезок должен начинаться и кончаться в заданных точках и при этом выглядеть сплошным и прямым (при достаточно высоком разрешении дисплея этого можно добиться).

Кроме того, яркость вдоль отрезка должна быть одинаковой и не зависеть от наклона отрезка и его длины.

Это требование выполнить сложнее, поскольку горизонтальные и вертикальные отрезки всегда будут ярче наклонных, а постоянная яркость вдоль отрезка опять же достигается на вертикальных, горизонтальных и наклоненных под углом в 45° линиях. И, наконец, алгоритм должен работать быстро. Для этого необходимо по возможности исключить операции с вещественными числами. С целью ускорения работы алгоритма можно также реализовать его на аппаратном уровне.

Рис. 8.1. Растровый образ отрезка

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

Задача состоит в построении отрезка, соединяющего на экране точки с координатами (будем считать, что ). Для построения отрезка прямой на плоскости с вещественными координатами можно воспользоваться уравнением прямой, проходящей через две заданные точки, которое имеет вид

Теперь, считая, что – координаты текущей точки растрового образа, а – точное значение координаты точки отрезка, можно построить следующую точку:

Следует заметить, что целочисленная координата изменится только в том случае, если y превысит величину ( есть ближайшее к целое число, полученное в результате операции округления).

Приведенный пример включает операции с вещественными числами, которые выполняются существенно медленнее, чем соответствующие целочисленные операции, а при построении растрового образа отрезка желателен алгоритм, по возможности обращающийся только к целочисленной арифметике. Кроме того, алгоритм должен работать при любом взаимном расположении концов отрезка.

Алгоритм Брезенхема построения растрового образа отрезка был изначально разработан для графопостроителей, но он полностью подходит и для растровых дисплеев.

В процессе работы в зависимости от углового коэффициента отрезка наращивается на единицу либо , либо , а изменение другой координаты зависит от расстояния между действительным положением точки и ближайшей точкой растра (смещения).

Алгоритм построен так, что анализируется лишь знак этого смещения.

Рис. 8.2. Связь углового коэффициента с выбором пикселя

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

На рис. 8.3 показано, каким образом строятся точки растра для отрезка с тангенсом угла наклона , а на рис. 8.4 – график смещения. В начале построения смещение полагается равным , а затем на каждом шаге оно наращивается на величину , и если при этом вертикальная координата точки растра увеличивается на единицу, то смещение в свою очередь уменьшается на единицу.

На рис. 8.5 приведена блок-схема алгоритма для случая . Нетрудно понять, как от этого алгоритма перейти к целочисленному: достаточно вместо величины смещения перейти к величине .

Рис. 8.3. Пиксели, принадлежащие развертке отрезка

Рис. 8.4. График изменения отклонения

Приведем общий алгоритм Брезенхема, который учитывает все возможные случаи направления отрезка, рассматриваемого как вектор на координатной плоскости (на рис. 8.6 выделены четыре области и указаны особенности алгоритма в каждой из них).

В описании алгоритма используются следующие функции:

swap (a, b): обмен значений переменных a, b;abs (a): абсолютное значение a;sign (a): 0, если a= 0, 1, если a>0, –1, если adi) { swap(di,dj); c=1;} else c=0;e=2*dj-di; // Инициализация смещения// Основной циклfor (l=0; l=0) { if (c==1) i=i+s1; else j=j+s2; e=e-2*di; } if (c==1) j=j+s2; else i=i+s1; e=e+2*dj; }

Рис. 8.6. Четыре возможных направления отрезка

——————————————————————————————————————————————————————————————————————————пояснение из другого источника——————————

Не нашли то, что искали? Воспользуйтесь поиском:

Источник: https://studopedia.ru/3_67082_algoritm-brezenhema-rastrovoy-diskretizatsii-otrezka.html

Мед-Центр Здоровье
Добавить комментарий