Построить растровое изображение окружности. Использовать в вычислениях только целые числа Алгоритм Брезенхема построения окружности.Обратимся к тексту процедуры Pixel_circle, которая, как можно видеть, расставляет восемь точек вокруг точки (xc,yc) (центра нашей окружности). Эта процедура реализует следующее: окружность обладает центром симметрии и бесконечным количеством осей симметрии. Поэтому нет необходимости строить всю окружность, достаточно построить некоторую ее часть и последовательным применением преобразований симметрии получить из нее полную окружность. Мы станем строить 1/8 часть окружности, заключенную в ∠AOB . Каждая точка этого фрагмента должна быть еще семь раз отображена с помощью преобразований симметрии для получения полной окружности. Рис. 1 Кроме того, именно процедура Pixel_circle отвечает за расположение центра окружности. Приступим к разбору ключевой идеи алгоритма. Пусть мы находимся в некоторой промежуточной фазе построения. Мы только что поставили точку (xi, yi) и теперь должны сделать выбор между точками 1(xi+1, yi-1) и 2(xi+1, y). (Напомним, что мы строим часть окружности, заключенную в ∠AOB, следовательно, подняться выше мы не можем и спуститься вниз более чем на одну точку не можем тоже.) Рис. 2 Реальная окружность может быть расположена относительно точек 1 и 2 одним из пяти способов 1-5. Если мы выбераем точку 1, то тем самым говорим, что (xi+1)2+(yi-1)2 > R2. Если же выбераем точку 2, то допускаем, что (xi+1)2+(yi)2 > R2. Рассмотрим две погрешности Δi1 и Δi2: Δi1 = (xi+1)2+(yi-1)2-R2 Δi2 = (x1+1)2+(yi)2-R2 и контрольную величинуΔi = Δi1+Δi2. При выборе точки, следующей за (xi, yi), станем руководствоваться следующим критерием: если Δi > 0, выберем точку 1; если Δi ≤ 0, выберем точку 2. Обоснуем разумность такого выбора. Рассмотрим знаки погрешностей Δi1 и Δi2 и их влияние на знак контрольной величины Δi для всех пяти возможных положений окружности. Для положения 1. Δi1 < 0, Δi2 < 0 ⇒ Δi1+Δi2 < 0 ⇒ выбирается 2. Для положения 2. Δi1 < 0, Δi2 = 0 ⇒ Δi1+Δi2 < 0 ⇒ выбирается 2. Для положения 3 возможны варианты (учитывая, что Δi1 < 0, Δi2 > 0). Вариант 3.1. |Δi1| ⇒ |Δi2| ⇒ Δi1+Δi2 < 0 ⇒ выбирается 2. Вариант 3.2. |Δi1| < |Δi2|⇒Δi1+Δi2 > 0 ⇒ выбирается 1. Для положения 4. Δi1 = 0, Δi2 > 0 ⇒ Δi1+Δi2 > 0 ⇒ выбирается 1. Для положения 5. Δi1 > 0, Δi2 > 0 ⇒ Δi1+Δi2 > 0 ⇒ выбирается 1. Далее получим выражение для контрольной величины Δi Δi = Δi1+Δi2 = (xi+1)2+(yi-1)2-R2+(xi+1)2+(yi)2-R2 = 2xi2+2yi2+4xi-2yi+3-2R2. Выражение для Δi+1 существенным образом зависит от выбора Δi+1 [при yi+1 = yi] = 2x2i+1+2y2i+1+4xi+1-2yi+1+3-2R2 = 2(xi+1)2+2yi2+4(xi+1)-2yi+3-2R2 = Δi+4xi+6. Δi+1 [при yi+1 = yi-1] = 2x2i+1+2y2i+1+4xi+1-2yi+1+3-2R2 = 2(xi+1)2+2(yi-1)2+4(xi+1)-2(yi-1)+3-2R2 = Δi+4(xi-yi)+10. Теперь, когда получено рекуррентное выражение для Δi+1 через Δi, остается получить Δ1 (контрольную величину в начальной точке.) Она не может быть получена рекуррентно, ибо не определено предшествующее значение, зато легко может быть найдена непосредственно x1 = 0, y1 = R ⇒ Δ11 = (0+1)2+(R-1)2-R2 = 2-2R, Δ12 = (0+1)2+R2-R2 = 1 Δ1 = Δ11+Δ12 = 3-2R. Таким образом, алгоритм построения окружности, реализованный в V_BRcirc, основан на последовательном выборе точек; в зависимости от знака контрольной величины Δi выбирается следующая точка и нужным образом изменяется сама контрольная величина. Процесс начинается в точке (0, r), а первая точка, которую ставит процедура Pixel_circle, имеет координаты (xc, yc+r). При x = y процесс заканчивается. #include <conio.h> #define VGA_MODE 0x0013 #define TEXT_MODE 0x0003 typedef unsigned char byte; byte far* vga = (byte far *)0xA0000000L; void SetMode(unsigned short mode) { asm { mov ax, [mode] int 10h } } void putpixel(int x, int y, byte color) { vga[y*320+x] = color; } /*--------------------------------------------------- V_Circle * Подпрограммы для генерации окружности * Pixel_circle - занесение пикселов с учетом симметрии * V_BRcirc - генерирует окружность по алгоритму * Брезенхема. * V_MIcirc - генерирует окружность по алгоритму * Мичнера. */ /*----------------------------------------------- Pixel_circle * Заносит пикселы окружности по часовой стрелке */ static void Pixel_circle (int xc,int yc,int x,int y,int pixel) { putpixel(xc+x, yc+y, pixel); putpixel(xc+y, yc+x, pixel); putpixel(xc+y, yc-x, pixel); putpixel(xc+x, yc-y, pixel); putpixel(xc-x, yc-y, pixel); putpixel(xc-y, yc-x, pixel); putpixel(xc-y, yc+x, pixel); putpixel(xc-x, yc+y, pixel); } /* Pixel_circle */ /* Генерирует 1/8 окружности по алгоритму Брезенхема * * Процедура может строить 1/4 окружности. * Для этого надо цикл while заменить на for (;;) * и после Pixel_circle проверять достижение конца по условию * if (y <= end) break; * Где end устанавливается равным 0 * В этом случае не нужен и последний оператор * if (x == y) Pixel_circle (xc, yc, x, y, pixel); * Генерацию 1/8 можно обеспечить задав end = r / sqrt (2) */ void V_BRcirc (int xc,int yc,int r,int pixel) { int x, y, z, Dd; x= 0; y= r; Dd= 2*(1-r); while (x < y) { Pixel_circle (xc, yc, x, y, pixel); if (!Dd) goto Pd; z= 2*Dd - 1; if (Dd > 0) { if (z + 2*x <= 0) goto Pd; else goto Pv; } if (z + 2*y > 0) goto Pd; Pg: ++x; Dd= Dd + 2*x + 1; continue; /* Горизонт */ Pd: ++x; --y; Dd= Dd + 2*(x-y+1); continue; /* Диагонал */ Pv: --y; Dd= Dd - 2*y + 1; /* Вертикал */ } if (x == y) Pixel_circle (xc, yc, x, y, pixel); } /* V_BRcirc */ /*--------------------------------------------------- V_MIcirc * Генерирует 1/8 окружности по алгоритму Мичнера */ void V_MIcirc (int xc,int yc,int r,int pixel) { int x, y, d; x= 0; y= r; d= 3 - 2*r; while (x < y) { Pixel_circle (xc, yc, x, y, pixel); if (d < 0) d= d + 4*x + 6; else { d= d + 4*(x-y) + 10; --y; } ++x; } if (x == y) Pixel_circle (xc, yc, x, y, pixel); } /* V_MIcirc */ int main() { /* Устанавливаем видеорежим */ SetMode(VGA_MODE); /* * ТЕСТ ГЕНЕРАЦИИ ОКРУЖНОСТЕЙ * * Cтроит заданную окружность по алгоритму Брезенхема * и концентрично с ней с радиусом, уменьшенным на 2, и * номером цвета, уменьшенным на 1, выдает окружность по * алгоритму Мичнера. * */ int ii, Xc=150, Yc=80, R=50, Pix=14; V_BRcirc (Xc, Yc, R, Pix); V_MIcirc (Xc, Yc, R-2, Pix-1); getch(); SetMode(TEXT_MODE); return 0; }
Ключевые слова:
Алгоритм Брезенхейм Мичнер окружность
|
|||||||