Алгоритм Брезенхема для генерации окружности.

В растр нужно разлагать не только линейные, но и другие, более сложные функции. Разложению конических сечений, т. е. окружностей, эллипсов, парабол, гипербол, было посвящено значительное число работ . Наибольшее внимание, разумеется, уделено окружности. Один из наиболее эффективных и простых для понимания алгоритмов генерации окружности принадлежит Брезенхему . Для начала заметим, что необходимо сгенерировать только одну восьмую часть окружности. Остальные ее части могут быть получены последовательными отражениями, как это показано на рис. 5.1. Если сгенерирован первый октант (от 0 до 45° против часовой стрелки), то второй октант можно получить зеркальным отражением относительно прямой у = х, что дает в совокупности первый квадрант. Первый квадрант отражается относительно прямой х = 0 для получения соответствующей части окружности во втором квадранте. Верхняя полуокружность отражается относительно прямой у = 0 для завершения построения. На рис. 5.1 приведены двумерные матрицы соответствующих преобразований.

Рис. 5.1. Генерация полной окружности из дуги в первом октанте.

Для вывода алгоритма рассмотрим первую четверть окружности с центром в начале координат. Заметим, что если работа алгоритма начинается в точке х = 0, у = R, то при генерации окружности по часовой стрелке в первом квадранте у является монотонно убывающей функцией аргументам (рис. 5.2). Аналогично, если исходной точкой является у = 0, х == R, то при генерации окружности против часовой стрелки х будет монотонно убывающей функцией аргумента у. В нашем случае выбирается генерация по часовой стрелке с началом в точке х = 0, у = R. Предполагается, что центр окружности и начальная точка находятся точно в точках растра.

Для любой заданной точки на окружности при генерации по часовой стрелке существует только три возможности выбрать следующий пиксел, наилучшим образом приближающий окружность: горизонтально вправо, по диагонали вниз и вправо, вертикально вниз. На рис. 5.3 эти направления обозначены соответственно mH, mD, mV. Алгоритм выбирает пиксел, для которого минимален квадрат расстояния между одним из этих пикселов и окружностью, т. е. минимум из

mH = |(xi + 1)2 + (yi)2 -R2|

mD = |(xi + 1)2 + (yi -1)2 -R2|

mV = |(xi )2 + (yi -1)2 -R2|

Рис. 5.2. Окружность в первом квадранте.   Рис.5.3. Выбор пикселов в первом квадранте.

Вычисления можно упростить, если заметить, что в окрестности точки (xi,yi,) возможны только пять типов пересечений окружности и сетки растра, приведенных на рис. 5.4.

Рис. 5.4. Пересечение окружности и сетки растра.

Разность между квадратами расстояний от центра окружности до диагонального пиксела (xi, + 1, уi - 1) и от центра до точки на окружности R2 равна

i = (xi + 1)2 + (yi -1)2 -R2

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

При i < 0 диагональная точка (xi, + 1, уi - 1) находится внутри реальной окружности, т. е. это случаи 1 или 2 на рис. 5.4. Ясно, что в этой ситуации следует выбрать либо пиксел (xi, + 1, уi), т. е. mH, либо пиксел (xi, + 1, уi - 1), т. е. mD. Для этого сначала рассмотрим случай 1 и проверим разность квадратов расстояний от окружности до пикселов в горизонтальном и диагональном направлениях:

 = |(xi + 1)2 + (yi )2 -R2| - |(xi + 1)2 + (yi -1)2 -R2|

При  < 0 расстояние от окружности до диагонального пиксела больше, чем до горизонтального. Напротив, если  > 0, расстояние до горизонтального пиксела больше. Таким образом,

при  <= 0 выбираем mH в (xi, + 1, уi - 1)

при  > 0 выбираем mD в (xi, + 1, уi - 1)

При  = 0, когда расстояние от окружности до обоих пикселов одинаковы, выбираем горизонтальный шаг.

Количество вычислений, необходимых для оценки величины , можно сократить, если заметить, что в случае 1

(xi + 1)2 + (yi )2 -R2 >= 0

(xi + 1)2 + (yi -1)2 -R2 < 0

так как диагональный пиксел (xi, + 1, уi - 1) всегда лежит внутри окружности, а горизонтальный (xi, + 1, уi) - вне ее. Таким образом,  можно вычислить по формуле

= (xi + 1)2 + (yi )2 -R2 + (xi + 1)2 + (yi -1)2 -R2

Дополнение до полного квадрата члена (yi )2 с помощью добавления и вычитания - 2yi + 1 дает

= 2[(xi + 1)2 + (yi -1)2 -R2] + 2yi - 1

В квадратных скобках стоит по определению i и его подстановка

= 2( i + yi) - 1

существенно упрощает выражение.

Рассмотрим случай 2 на рис. 5.4 и заметим, что здесь должен быть выбран горизонтальный пиксел (xi, + 1, уi), так как .у является монотонно убывающей функцией. Проверка компонент  показывает, что

(xi + 1)2 + (yi )2 -R2 < 0

(xi + 1)2 + (yi -1)2 -R2 < 0

поскольку в случае 2 горизонтальный (xi, + 1, уi) и диагональный (xi, + 1, уi -1) пикселы лежат внутри окружности. Следовательно,  < 0, и при использовании того же самого критерия, что и в случае 1, выбирается пиксел (xi, + 1, уi).

Если i > 0, то диагональная точка (xi, + 1, уi -1) находится вне окружности, т. е. это случаи 3 и 4 на рис. 5.4. В данной ситуации ясно, что должен быть выбран либо пиксел (xi, + 1, уi -1), либо (xi, , уi -1). Аналогично разбору предыдущего случая критерий выбора можно получить, рассматривая сначала случай 3 и проверяя разность между квадратами расстояний от окружности до диагонального mD и вертикального mV пикселов,

т. е. ' = |(xi + 1)2 + (yi -1)2 -R2| - |(xi)2 + (yi -1)2 -R2 |

При'< 0 расстояние от окружности до вертикального пиксела (xi, , уi -1) больше и следует выбрать диагональный шаг к пикселу (xi, + 1, уi -1). Напротив, в случае'> 0 расстояние от окружности до диагонального пиксела больше и следует выбрать вертикальное движение к пикселу (xi, , уi -1). Таким образом,

при '<= 0 выбираем mD в (xi +1, , уi -1)

при '> 0 выбираем mV в (xi, , уi -1)

Здесь в случае ' = 0, т. е. когда расстояния равны, выбран диагональный шаг.

Проверка компонент ' показывает, что

(xi )2 + (yi -1)2 -R2 >= 0

(xi + 1)2 + (yi -1)2 -R2 < 0

поскольку для случая 3 диагональный пиксел (xi +1, уi -1) находится вне окружности, тогда как вертикальный пиксел (xi, , уi -1) лежит внутри ее. Это позволяет записать ' в виде

' = (xi +1)2 + (yi -1)2 -R2 + (xi )2 + (yi -1)2 -R2

Дополнение до полного квадрата члена (xi)2 с помощью добавления и вычитания 2xi + 1 дает

' = 2[(xi +1)2 + (yi -1)2 -R2] - 2xi - 1

Использование определения i приводит выражение к виду

' = 2( i - xi )- 1

Теперь, рассматривая случай 4, снова заметим, что следует выбрать вертикальный пиксел (xi, уi -1), так как у является монотонно убывающей функцией при возрастании х.

Проверка компонент ' для случая 4 показывает, что

(xi +1)2 + (yi -1)2 -R2 > 0

(xi )2 + (yi -1)2 -R2 > 0

поскольку оба пиксела находятся вне окружности. Следовательно, ' > 0 и при использовании критерия, разработанного для случая 3, происходит верный выбор mV.

Осталось проверить только случай 5 на рис. 5.4, который встречается, когда диагональный пиксел (xi, , уi -1) лежит на окружности, т. е. i = 0. Проверка компонент  показывает, что

(xi +1)2 + (yi)2 -R2 > 0

(xi +1)2 + (yi -1)2 -R2 = 0

Следовательно, > 0 и выбирается диагональный пиксел (xi +1 , уi -1) . Аналогичным образом оцениваем компоненты ' :

(xi +1)2 + (yi -1)2 -R2 = 0

(xi +1)2 + (yi -1)2 -R2 < 0

и ' < 0, что является условием выбора правильного диагонального шага к (xi +1 , уi -1) . Таким образом, случай i = 0 подчиняется тому же критерию, что и случай i < 0 или i > 0. Подведем итог полученных результатов:

i < 0

<= 0выбираем пиксел (xi +1 , уi ) - mH

> 0 выбираем пиксел (xi +1 , уi -1)-mD

i > 0

' <= 0 выбираем пиксел (xi +1 , уi -1) - mD

' > 0 выбираем пиксел (xi , уi -1)- mV

i = 0 выбираем пиксел (xi +1 , уi -1) - mD

Легко разработать простые рекуррентные соотношения для реализации пошагового алгоритма. Сначала рассмотрим горизонтальный шаг mH к пикселу (xi + 1, уi). Обозначим это новое положение пиксела как (i + 1). Тогда координаты нового пиксела и значение i равны

xi+1 = xi +1

yi+1 = yi

i+1 = (xi+1 +1)2 + (yi+1 -1)2 -R2 i + 2xi+1+ 1

Аналогично координаты нового пиксела и значение i для шага mD к пикселу (xi + 1, уi -1) таковы:

xi+1 = xi +1

yi+1 = yi -1

i+1 = i + 2xi+1 - 2yi+1 +2

То же самое для шага mVк (xi, уi -1)

xi+1 = xi

yi+1 = yi -1

i+1 = i - 2yi+1 +1

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

Пошаговый алгоритм Брезенхема для генерации окружности в первом квадранте

все переменные - целые

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

xi = 0

yi = R

i =2(1 - R)

Предел = 0

1 Plot (xi, yi

if yi <= Пределthen 4

Выделениеслучая 1 или 2, 4 или 5, или 3

if i < 0then 2

ifi> 0then 3

if i= 0then 20

определение случая 1 или 2

2  = 2i+ 2уi - 1

if  <= 0then 10

if  > 0then 20

определение случая 4 или 5

3 = 2i+ 2хi- 1

if <= 0then20

if > 0 then30

выполнение шагов

шаг к mH

10 хi = хi + 1

i = i+ 2хi + 1