1. Булеви функции. Теорема на Пост-Яблонски за пълнота. Нека J2 = { 0, 1}. Всяка функция f : J2n  J



страница12/29
Дата11.01.2018
Размер5.91 Mb.
#44141
1   ...   8   9   10   11   12   13   14   15   ...   29

Компютърната графика е наука за методите за съхранение, създаване и обработване на модели и техните визуални образи с помощта на компютър. Интерактивността в компютърната графика изисква визуализацията да става чрез устройства, които много бързо могат да променят образа. Най-широко използвани са графичните дисплеи с електронно-лъчева тръба. От тесния край на тръбата се излъчва сноп от електрони и той се насочва чрез специални магнитни системи. В другия на тръбата е екрана, който се състои от точки, които са достатъчно гъсто разположени, че за човешкото око да се създаде илюзия за непрекъснат образ. Тези точки се наричат пиксели. Един пиксел се формира от три зърна специално вещество, наречено луминофор, което има свойството да свети, когато снопът от електрони се удари в него. Трите зърна светят в червено (R), зелено (G) и синьо (B). Останалите цветове се получават чрез подходяща комбинация на тези три основни цвята.

Тъй като светлинният импулс на луминофора намалява много бързо с времето, образът се нуждае от непрекъснато прерисуване, дори когато е статичен. За да се постигне илюзията на постоянен образ, честотата на опресняване трябва да е най-малко 60 Hz.

В зависимост от начина на регенерация на образа дисплеите се делят на два вида – векторни и растерни. Ние ще разглеждаме цветни растерни дисплеи. При тях във всеки един момент изображението представлява една правоъгълна матрица от пиксели. С всеки пиксел се свързват (обикновено) 24 бита – по

3 бита за всяка от основните цветови компоненти на пиксела.

По този начин се осигуряват над 16000000 цветове. Основни характеристики на тези дисплеи са броят на пикселите (размерите на матрицата, например 800/600, 1024/768) и гъстотата на пикселите (броят на пикселите, които се събират в един инч, варира от 72 до 130).

Така при растерните дисплеи възниква необходимостта от създаването на ефективни алгоритми за растеризация на отсечки и криви линии, т.е. за преобразуване на криви и отсечки в растерен формат. Когато е дадена една отсечка (например, чрез двата си края) или крива (например, чрез уравнението си), за да се изчертае тя, трябва да се определи кои пиксели на дисплея да се оцветят, така че да се да се получи достатъчно близка апроксимация на отсечката или кривата.

Обикновено на всеки пиксел се съпоставя двойка координати – номера на стълба x и номера на реда y на пиксела. За начало на координатната система се счита горният ляв ъгъл, така че като се придвижваме надясно x нараства, а като се придвижваме надолу y нараства.
При всички алгоритми за растеризиране на отсечка, считаме, че отсечката е зададена с двата си края (X1, Y1) и (X2, Y2), където координатите са с цели числа. Целта на тези алгоритми е да се оцветят подходящи пиксели, така че да се създаде илюзията, че на екрана е начертана отсечката с начало в пиксела с координати X1 и Y1 и край в пиксела с координати X2 и Y2.
Първо разглеждаме алгоритъма на Брезенхем за растеризиране на отсечка. Първо изчисляваме наклонът на отсечката.
Той е m = dY/dX, където dY = Y2 – Y1, dX = X2 – X1 и уравнението на правата, определена от отсечката е y = m.x + b, където

b = Y2 – m.X2. Ще считаме, че за наклона m е изпълнено -1  m  1. Ако това не е така, извършваме симетрия относно правата y = x и след това при изчертаване просто променяме ролите на двете координати.

Също така, ще считаме, че dX > 0. Ако това не е така, просто разменяме краищата на отсечката (при тази размяна наклонът m не се променя). Ще отбележим, че dX  0 – това е осигурено от първото съображение.

Така след тези две предварителни съображения, (X1, Y1) е левият край и (X2, Y2) е десният край на отсечката. Също, тъй като

|m|  1, във всеки стълб между X1 и X2 (за всяка фиксирана първа координата между X1 и X2) трябва да се оцвети точно един пиксел. Първият оцветен пиксел е (x0, y0) = (X1, Y1).

Нека (xi, yi) е i-тият оцветен пиксел. Отсечката пресича стълба

xi + 1 при y = m.(xi + 1) + b. При това, i-тият оцветен пиксел ще е така избран, че yi  m.(xi + 1) + b  yi + 1, ако dY е неотрицателно и

yi – 1  m.(xi + 1) + b  yi, ако dY е отрицателно. Сега трябва да изберем (i+1)-ият пиксел за оцветяване. Ако dY е неотрицателно, той ще е един от двата пиксела (xi + 1, yi) и (x1 + 1, yi + 1). Ако dY е отрицателно, той ще е един от двата пиксела (xi + 1, yi) и

(xi + 1, yi – 1). И в двата случая, кой точно пиксел да се избере се определя от това кой е по-близо до пресечната точка на отсечката със стълба xi + 1.

При dY  0, разстоянието от (xi + 1, yi) до (xi + 1, m.(xi + 1) + b) е

t = m.(xi + 1) + b – yi, а разстоянието от (xi + 1, yi +1) до

(xi + 1, m.(xi + 1) + b) е s = 1 – t = yi + 1 – m.(xi + 1) – b.

Така t – s = m.(xi + 1) + b – yi – (yi + 1 – m.(xi + 1) – b) =

= 2.m.(xi + 1) + 2.b – 2.yi – 1. Умножаваме полученото равенство

с dX и получаваме dX.(t – s) = 2.dY.(xi + 1) + 2.dX.b – 2.dX.yi – dX.

Така знакът на t – s съвпада със знака на числото

di = 2.dY.(xi + 1) + 2.dX.b – 2.dX.yi – dX.

Ако di > 0, тогава избираме (xi+1, yi+1) = (xi + 1, yi + 1).

Ако di  0, тогава избираме (xi+1, yi+1) = (xi + 1, yi).

При dY < 0, разсъжденията са аналогични: тогава

di = - 2.dY.(xi + 1) – 2.dX.b + 2.dX.yi – dX и

ако di > 0, избираме (xi+1, yi+1) = (xi+1, yi+1) = (xi + 1, yi – 1),

ако di  0, тогава избираме (xi+1, yi+1) = (xi + 1, yi).

За по-лесно изчисляване да съобразим следното:

d0 = 2.dY.(X1 + 1) + 2.dX.b – 2.dX.Y1 – dX = 2.dY – dX, ако dY  0,

d0 = - 2.dY – dX, ако dY < 0. Двата случая можем да обединим така:

d0 = 2.abs (dY) – dX.

След това, при dY  0, di+1 = 2.dY.(xi+1 + 1) + 2.dX.b – 2.dX.yi+1 – dX 

 di+1 – di = 2.dY.(xi+1 – xi) – 2.dX.(yi+1 – yi).

При dY < 0, di+1 = - 2.dY.(xi+1 + 1) – 2.dX.b + 2.dX.yi+1 – dX 

 di+1 – di = - 2.dY.(xi+1 – xi) + 2.dX.(yi+1 – yi).

Двата случая можем да обединим така:

ако di > 0, di+1 = di + 2.abs (dY) – 2.dX,

ако di  0, di+1 = di + 2.abs (dY).


Така достигаме до следния алгоритъм:

Вход: (X1, Y1), (X2, Y2).

1. Ако abs (X2 – X1) < abs (Y2 – Y1), тогава

разменяме X1, Y1 и X2, Y2 и rev = 1, иначе rev = 0; към 2.

2. Ако X2 < X1, тогава разменяме X1, X2 и Y1, Y2; към 3.

3. dY = Y2 – Y1, dX = X2 – X1; към 4.

4. d0 = 2.abs (dY) – dX, x0 = X1, y0 = Y1, i = 0; към 5.

5. Ако dY  0, incY = 1, иначе incY = -1; към 6.

6. Ако rev = 0, чертаем (xi, yi), иначе чертаем (yi, xi); към 7.

7. Ако xi < X2, към 8., иначе към 10.

8. Ако di > 0, тогава di+1 = di + 2.abs (dY) – 2.dX, xi+1 = xi + 1,

yi+1 = yi + incY, иначе di+1 = di + 2.abs (dY), xi+1 = xi +1, yi+1 = yi; към 9.

9. i = i+1; към 6.

10. Край.


Сега ще разгледаме алгоритъма на средната точка за растеризиране на отсечка. Отново трябва да се направят двете съображения, както при алгоритъма на Брезенхем.

Така можем да считаме, че за наклона m имаме – 1  m  1 и освен това, че dX > 0. Правата, която е определена от точките (X1, Y1) и (X2, Y2) има уравнение F (x, y) = dY.x – dX.y + C = 0, където

C = dX.Y1 – dY.X1. Тази права определя две полуравнини: за всички точки (x, y) над правата е изпълнено F (x, y) < 0 и за всички точки (x, y) под правата е изпълнено F (x, y) > 0.
Първият оцветен пиксел е (x0, y0) = (X1, Y1).

Нека (xi, yi) е i-тият оцветен пиксел. Трябва да изберем (i+1)-ият пиксел за оцветяване. Както при Брезенхем, ако dY е неотрицателно, той ще е един от двата пиксела (xi + 1, yi) и

(x1 + 1, yi + 1). Ако dY е отрицателно, той ще е един от двата пиксела (xi + 1, yi) и (xi + 1, yi – 1). Тук обаче, изборът кой точно пиксел да се избере се определя по друг начин.

Ако dY  0, нека Mi е средата на отсечката (xi + 1, yi) (xi + 1, yi + 1),

ако dY < 0, нека Mi е средата на отсечката (xi + 1, yi) (xi + 1, yi – 1).

Изчисляваме di = F (Mi) и определяме в коя полуравнина се намира точката Mi относно правата и по този начин определяме кой от двата пиксела да изберем (естествено, този който лежи в противоположната полуравнина).

При dY  0, di = F (Mi) = dY.(xi + 1) – dX.(yi + ) + C. Ако di > 0, избираме (xi+1, yi+1) = (xi + 1, yi + 1), ако di  0 избираме

(xi+1, yi+1) = (xi + 1, yi).

При dY < 0, di = F (Mi) = dY.(xi + 1) – dX.(yi - ) + C. Ако di  0, избираме (xi+1, yi+1) = (xi + 1, yi), ако di < 0 избираме

(xi+1, yi+1) = (xi + 1, yi – 1).

Отново можем да съобразим някои неща за да изчисляваме

по-лесно.

Ако dY  0, d0 = F (M0) = dY.(X1 + 1) – dX.(Y1 + ) + C = dY - ,

di+1 = F (Mi+1) = dY.(xi+1 + 1) – dX.(yi+1 + ) + C =

= di + dY.(xi+1 – xi) – dX.(yi+1 – yi)  при di > 0, di+1 = di + dY – dX,

при di  0, di+1 = di + dY.

Ако dY < 0, d0 = F (M0) = dY.(X1 + 1) – dX.(Y1 - ) + C = dY + ,

di+1 = F (Mi+1) = dY.(xi+1 + 1) – dX.(yi+1 - ) + C =

= di + dY.(xi+1 – xi) – dX.(yi+1 – yi)  при di  0, di+1 = di + dY,

при di < 0, di+1 = di + dY + dX.

Тук привидно имаме недостатък – резултатът от делението на 2 може да не е целочислено, но ние лесно можем да го поправим като разглеждаме уравнението 2.F (x, y) = 2.dY.x – 2.dX.y + 2.C = 0 за правата.

Така достигаме до следния алгоритъм:

Вход: (X1, Y1), (X2, Y2).

1. Ако abs (X2 – X1) < abs (Y2 – Y1), тогава

разменяме X1, Y1 и X2, Y2 и rev = 1, иначе rev = 0; към 2.

2. Ако X2 < X1, тогава разменяме X1, X2 и Y1, Y2; към 3.

3. dY = 2.(Y2 – Y1), dX = 2.(X2 – X1); към 4.

4. Ако dY  0, d0 = dY – dX/2, иначе d0 = dY + dX/2; към 5.

5. x0 = X1, y0 = Y1, i = 0; към 6.

6. Ако rev = 0, чертаем (xi, yi), иначе чертаем (yi, xi); към 7.

7. Ако xi < X2, към 8., иначе към 12.

8. Ако dY  0, към 9., иначе към 10.

9. Ако di > 0, тогава di+1 = di + dY – dX, xi+1 = xi + 1,

yi+1 = yi + 1, иначе di+1 = di + dY, xi+1 = xi + 1, yi+1 = yi; към 11.

10. Ако di  0, тогава di+1 = di + dY, xi+1 = xi + 1, yi+1 = yi, иначе

di+1 = di + dY + dX, xi+1 = xi + 1, yi+1 = yi – 1; към 11.

11. i = i+1; към 6.

12. Край.


Третият метод, който ще разгледаме е алгоритъмът на порциите за растеризиране на отсечка. Отново искаме да са в сила предположенията, че – 1  m  1 и dX > 0. Тук, обаче, добавяме и допълнително предположение (X1, Y1) = (0, 0). Това не е никакво ограничение, тъй като просто можем при изчертаването да правим подходяща транслация. Полагаме H = X2, H > 0,

V = Y2. Тогава m = . Във всеки фиксиран ред (при фиксирана втора координата) при растеризиране на отсечката трябва да се изчертава известна порция последователни пиксели. При направените предположения, първата порция трябва да е в


реда 0 и започва от стълба 0, втората порция в реда 1

(-1, при V < 0) започва точно с един стълб по надясно от последния стълб в първата порция и т.н. Порциите се определят по следния начин: в реда y порцията е от всички x, такива че

y - .x  y + . Оттук нататък предполагаме, че V > 0 – случаят V = 0 ще се разглежда отделно в алгоритъма, а случаят

V < 0 лесно може да се сведе към V > 0, тъй като порциите и в двата случая са едни и същи.

Умножаваме последното неравенство с и получаваме:

.y -  x  .y + .

Сега нека = c0 + , където c0, r0   и 0  r0 < 2.V и



= c1 + , където c1, r1   и 0  r1 < 2.V.

Тогава, (c1 + ).y – c0 -  x  (c1 + ).y + c0 +

c1.y – c0 +  x  c1.y + c0 + .y + . Така първата порция при y = 0 е 0, 1, …, c0, тъй като < 1. Да положим mod0 = r0.

Очевидно е, че 0 = - . Втората порция при y = 1 започва точно с един стълб по-надясно от края на първата порция, т.е. в c0 + 1 и продължава до c0 + c1 + . При това,



= 0 или 1, тъй като 0  r0 + r1 < 4.V. Полагаме

mod1 = mod0 + r1, ако mod0 + r1 < 2.V (т.е. = 0) или

mod1 = mod0 + r1 – 2.V, ако mod0 + r1  2.V (т.е. = 1).

Тогава е ясно, че = = - .

По-общо, нека порцията в реда y завършва в c. Имаме

c = c1.y + c0 + = c1.y + c0 + - .

Тогава порцията в реда y+1 започва в c+1 и завършва в = =

.

Първото събираемо е равно или на 0 или на 1, тъй като

mody + r1 < 4.V. Ако mody + r1 < 2.V, тогава порцията в реда y + 1 завършва в c + c1 и тогава полагаме mody+1 = mody + r1.

Ако mody + r1  2.V, тогава порцията в реда y+1 завършва в

1 + c + c1 и тогава полагаме mody+1 = mody + r1 – 2.V.

Естествено, полагането е такова, че



= - =

= + -



= - .

Този процес продължава естествено до момента, в който края на някоя от порциите достигне (или надмине) H.

Така достигаме до следния алгоритъм:

Вход: (X1, Y1), (X2, Y2).

1. Ако abs (X2 – X1) < abs (Y2 – Y1), тогава

разменяме X1, Y1 и X2, Y2 и rev = 1, иначе rev = 0; към 2.

2. Ако X2 < X1, тогава разменяме X1, X2 и Y1, Y2; към 3.

3. H = X2 – X1, V = abs (Y2 – Y1); към 4.

4. Ако Y2 > Y1, incY = 1, иначе incY = -1; към 5.

5. y = 0, x = 0, ако V = 0 към 6., иначе към 7.

6. c = H; към 8.

7. r1 = (H + H) % (V + V), c1 = (H + H) / (V + V), mod0 = H % (V + V),

c = H / (V + V); към 8.

8. Ако c < H, към 9., иначе към 10.

9. Ако rev = 1 изчертаване на пикселите (Y1 + y, X1 + x),

(Y1 + y, X1 + x +1), …, (Y1 + y, X1 + c), иначе изчертаване на пикселите (X1 + x, Y1 + y), (X1 + x + 1, Y1 + y), …, (X1 + c, Y1 + y); към 11.

10. Ако rev = 1 изчертаване на пикселите (Y1 + y, X1 + x),

(Y1 + y, X1 + x +1), …, (Y1 + y, X1 + H), иначе изчертаване на пикселите (X1 + x, Y1 + y), (X1 + x + 1, Y1 + y), …, (X1 + H, Y1 + y); към 14.

11. x = c + 1; към 12.

12. Ако mody + r1  V + V, mody+1 = (mody + r1) – (V + V), c = c + c1 + 1,

иначе mody+1 = mody + r1, c = c + c1; към 13.

13. y = y + incY; към 8.

14. Край.
По-нататък ще разгледаме алгоритми за растеризиране на окръжност. Навсякъде ще предполагаме, че окръжността има център (0, 0) и радиус цяло неотрицателно число R. Естествено, чрез подходяща транслация могат да се растеризират окръжности с произволен център. Целта на алгоритмите е да се оцветят по такъв начин пикселите, че да се създаде илюзията, че на екрана окръжността с център в пиксела (0, 0) и радиус R.

Естествено, при тези предположения, окръжността има уравнение F (x, y) = x2 + y2 – R2 = 0. Тя разделя равнината на три части – вътрешността на кръга (тези с F (x, y) < 0), самата окръжност (контура на кръга, тези с F (x, y) = 0) и точките, извън кръга

(тези с F (x, y) > 0).
Първо разглеждаме алгоритъмът на Брезенхем за растеризиране на окръжност. При алгоритъма се растеризира само дъгата от окръжността, която се намира в първи квадрант и се използва, че окръжността е симетрична спрямо координатните оси и спрямо центъра. Първият пиксел, който оцветяваме е (x0, y0) = (0, R).

Нека е изчертан i-тият пиксел (xi, yi).

Да означим Hi = (xi + 1, yi), Di = (xi + 1, yi – 1), Vi = (xi, yi – 1).

Следващият пиксел за чертане ще е един от Hi, Di, Vi. За да определим точно кой изчисляваме

di = F (Di) = F (xi + 1, yi – 1) = (xi + 1)2 + (yi – 1)2 – R2.

Ако di  0 окръжността минава под Di, но не и под Vi и затова ще избираме един от двата пиксела Di и Vi. За целта изчисляваме

i = F (Di) + F (Vi). Тъй като F (Di)  0, то F (Di) е най-близкото разстояние от Di до окръжността. Тъй като F (Vi)  0, то F (Vi) е

най-близкото разстояние от Vi до окръжността, но взето с обратен знак. Така, ако i  0, трябва да изберем Vi, а когато i < 0 трябва да изберем Di. Имаме i = F (Di) + F (Vi) = di + xi2 + (yi – 1)2 – R2 =

= 2.di + xi2 – (xi + 1)2 = 2.di – 2.xi – 1. Така i  0  2.di – 2.xi – 1  0  di  xi +  di > xi, тъй като xi и di са цели числа. Също,

i < 0  di < xi +  di  xi, тъй като xi и di са цели числа.

Така в случая 0  di  xi избираме Di, а в случая di > xi избираме Vi.

Вторият случай е di < 0 и тогава окръжността минава над Di, но не и над Hi и затова ще избираме един от двата пиксела Di и Hi. За целта изчисляваме i = F (Di) + F (Hi). Тъй като F (Di) < 0, то F (Di) е най-близкото разстояние от Di до окръжността, взето с обратен знак. Тъй като F (Hi)  0, то F (Hi) е най-близкото разстояние от Hi до окръжността. Така, ако i  0, трябва да изберем Di, а когато

i < 0 трябва да изберем Hi. Имаме i = F (Di) + F (Hi) =

= di + (xi + 1)2 + yi2 – R2 = 2.di + yi2 – (yi – 1)2 = 2.di + 2.yi – 1.

Така i  0  2.di + 2.yi – 1  0  di  - yi +  di > - yi, тъй като

yi и di са цели числа. Също, i < 0  di < - yi +  di  - yi, тъй като yi и di са цели числа. Така в случая - yi < di < 0 избираме Di, а в случая di  - yi избираме Hi.

Като комбинираме двата случая получаваме:

ако di  - yi избираме (xi+1, yi+1) = Hi, ако – yi < di  xi избираме

(xi+1, yi+1) = Di, ако xi < di избираме (xi+1, yi+1) = Vi.
За по-ефективно изчисление да съобразим, че

d0 = F (d0) = F (x0 + 1, y0 – 1) = F (1, R – 1) = 12 + (R – 1)2 – R2 =

= 2 – 2.R.

Освен това, di+1 = F (Di+1) = F (xi+1 + 1, yi+1 – 1) =

= (xi+1 + 1)2 + (yi+1 – 1)2 – R2 = di – (xi + 1)2 – (yi – 1)2 + (xi+1 + 1)2 +

+ (yi+1 – 1)2 = di + (xi+1 – xi).(xi+1 + xi + 2) + (yi+1 – yi).(yi+1 + yi – 2).

Така, при (xi+1, yi+1) = Hi = (xi + 1, yi) имаме

di+1 = di + 2.xi + 3, при (xi+1, yi+1) = Di = (xi + 1, yi – 1) имаме

di+1 = di + 2.xi + 3 – (yi – 1 + yi – 2) = di + 2.xi – 2.yi + 6,

при (xi+1, yi+1) = Vi = (xi, yi – 1) имаме

di+1 = di – (yi – 1 + yi – 2) = di – 2.yi + 3.
Така достигаме до следния алгоритъм:

Вход: R.


1. x0 = 0, y0 = R, d0 = 2 – 2.R, i = 0; към 2.

2. Изчертаване на пиксела (xi, yi) и трите му симетрични точки относно координатните оси и относно центъра; към 3.

3. Ако yi = 0 към 7., иначе към 4.

4. Ако di > - yi, di+1 = di - 2.yi + 3, yi+1 = yi – 1, иначе yi+1 = yi, di+1 = di; към 5.

5. Ако di  xi, di+1 = di+1 + 2.xi + 3, xi+1 = xi + 1, иначе xi+1 = xi; към 6.

6. i = i + 1, към 2.

7. Край.
Сега ще разгледаме алгоритъма на Михенер за растеризиране на окръжност. При този алгоритъм се растеризира само горния октант в първи квадрант и се използва, че окръжността е симетрична относно координатните оси, центъра и ъглополовящите на квадрантите.

Първият пиксел, който оцветяваме е (x0, y0) = (0, R).

Нека сме оцветили i-тият пиксел (xi, yi).

Отново да означим Hi = (xi + 1, yi), Di = (xi + 1, yi – 1).

Тогава (i+1)-ият пиксел ще е един от Hi, Di. С други думи, в означенията от алгоритъма на Брезенхем, при изчертаване на въпросния октант никога няма да се прави избор на Vi.

За да определим кой от двата пиксела да оцветим, изчисляваме

di = F (Hi) + F (Di). Тъй като се намираме във въпросния октант,

винаги имаме F (Hi)  0 и F (Di)  0. Така F (Hi) е най-близкото разстояние от Hi до окръжността и F (Di) е най-близкото разстояние от Di до окръжността, но взето с обратен знак.

И следователно при di  0 трябва да вземем (xi+1, yi+1) = Di, а при

di < 0 трябва да вземем (xi+1, yi+1) = Hi.

За по-ефективно изчисление да съобразим, че

d0 = F (H0) + F (D0) = F (1, R) + F (1, R – 1) = 12 + R2 – R2 + 12 +

+ (R – 1)2 – R2 = 3 – 2.R.

Освен това, di+1 = F (Hi+1) + F (Di+1) = (xi+1 + 1)2 + yi+12 – R2 +

+ (xi+1 + 1)2 + (yi+1 – 1)2 – R2 = di + (xi+1 + 1)2 + yi+12 – (xi + 1)2 – yi2 +

+ (xi+1 + 1)2 + (yi+1 – 1)2 – (xi + 1)2 – (yi – 1)2 = di +

+ 2.(xi+1 – xi).(xi+1 + xi + 2) + (yi+1 – yi).(yi+1 + yi) + (yi+1 – yi).(yi+1 + yi – 2) =

= di + 2.(xi+1 – xi).(xi+1 + xi + 2) + 2.(yi+1 – yi).(yi+1 + yi – 1).

Така, при (xi+1, yi+1) = Hi = (xi + 1, yi), di+1 = di + 4.xi + 6, а

при (xi+1, yi+1) = Di = (xi + 1, yi – 1), di+1 = di + 4.xi + 6 – 2.(2.yi – 2) =

= di + 4.xi – 4.yi + 10.
Така достигаме следния алгоритъм:

Вход: R.


1. x0 = 0, y0 = R, d0 = 3 – 2.R, i = 0; към 2.

2. Изчертаване на пикселите (xi, yi) и (yi, xi) и шестте им симетрични точки относно двете координатни оси и центъра на координатната система; към 3.

3. Ако xi  yi към 6., иначе към 4.

4. Ако di  0, di+1 = di + 4.xi – 4.yi + 10, yi+1 = yi – 1, иначе

di+1 = di + 4.xi + 6, yi+1 = yi; към 5.

5. xi+1 = xi + 1, i = i + 1, към 2.

6. Край.
Следващият алгоритъм за растеризиране на окръжност е алгоритъма на средната точка. При този алгоритъм също се растеризира само горния октант в първи квадрант.

Първият пиксел, който оцветяваме е (x0, y0) = (0, R).

Нека сме оцветили i-тият пиксел (xi, yi).

Отново да означим Hi = (xi + 1, yi), Di = (xi + 1, yi – 1).

Както при алгоритъма на Михенер, тъй като изчертаваме въпросният октант, (i+1)-ият пиксел ще е един от Hi, Di (няма да се прави избор на Vi). За да определим кой от двата пиксела ще се оцвети, въвеждаме Mi = (xi + 1, yi - ) – средата на HiDi и изчисляваме di = F (Mi) = F (xi + 1, yi - ) = (xi + 1)2 – (yi - )2 – R2.

Ако di  0, т.е. окръжността минава под Mi, тогава е ясно, че трябва да изберем Di, ако di < 0, т.е. окръжността минава над Mi, то е ясно, че трябва да изберем Hi.


За да улесним изчисленията забелязваме следното:

di+1 = F (Mi+1) = (xi+1 + 1)2 + (yi+1 - )2 – R2 = di + (xi+1 + 1)2 – (xi + 1)2 +

+ (yi+1 - )2 – (yi - )2 = di + (xi+1 – xi).(xi+1 + xi + 2) +

+ (yi+1 – yi).(yi+1 + yi – 1). Така, ако (xi+1, yi+1) = Di = (xi + 1, yi – 1),

di+1 = di + 2.xi + 3 – (2.yi – 2) = di + 2.xi – 2.yi + 5, а ако

(xi+1, yi+1) = Hi = (xi + 1, yi), di+1 = di + 2.xi + 3. Освен това,

d0 = F (M0) = F (1, R - ) = 12 + (R - )2 – R2 = - R.

Тук достигаме до недостатък, тъй като не е цяло число.

Това, обаче, лесно може да се преодолее по следния начин:

полагаме ei = di - за всяко i. Естествено, горните зависимости между di+1 и di автоматично се пренасят и за ei+1 и ei, също

e0 = 1 – R. Оттук се вижда, че за всяко i, ei е цяло число 

ei  0  di  0, ei < 0  di < 0. Така при определянето на това кой пиксел да се избере можем да използваме знака на ei вместо знака на di.


Така достигаме до следния алгоритъм:

Вход : R.

1. x0 = 0, y0 = R, e0 = 1 – R, i = 0; към 2.

2. Изчертаване на пикселите (xi, yi) и (yi, xi) и симетрични им точки относно двете координатни оси и центъра на координатната система; към 3.

3. Ако xi  yi към 6., иначе към 4.

4. Ако ei  0, ei+1 = ei + 2.xi – 2.yi + 5, yi+1 = yi – 1, иначе

ei+1 = ei + 2.xi + 3, yi+1 = yi; към 5.

5. xi+1 = xi + 1, i = i + 1, към 2.

6. Край.
Последният алгоритъм за растеризиране на окръжност, който ще разгледаме е алгоритъма на вторите крайни разлики. Отново окръжността растеризираме само в горния октант на първи квадрант и използваме нейната богата симетрия.

Първият оцветен пиксел е (x0, y0) = (0, R). Нека сме оцветили i-тият пиксел (xi, yi). Тогава, както в алгоритъма на средната точка, за (i+1)-ви пиксел избираме Di или Hi, в зависимост от знака на

di = F (Mi) = (xi + 1)2 + (yi - )2 – R2. Хитрото тук е начинът на изчисляване на di. Дефинираме diH като изменението на di, ако на i-тата стъпка е избран пиксела Hi, т.е. diH = di+1 – di, ако

(xi+1, yi+1) = Hi. Дефинираме diD като изменението на di, ако на i-тата стъпка е избран пиксела Di, т.е. diD = di+1 – di, ако (xi+1, yi+1) = Di.

Ако на i-тата стъпка сме избрали Hi, то от по-горе

di+1 = di + 2.xi + 3  diH = 2.xi + 3. Ако на i-тата стъпка сме избрали Di, то от по-горе di+1 = di + 2.xi – 2.yi + 5  diD = 2.xi – 2.yi + 5.

Нека на i-тата стъпка е избрана Hi, т.е. (xi+1, yi+1) = Hi.

Тогава di+1H = di+2 – di+1, ако на (i+1)-та стъпка е избрана Hi+1.

Така di+1H = F (Mi+2) – F (Mi+1) = (xi + 3)2 + (yi - )2 – R2 – (xi + 2)2

(yi - )2 + R2 = 2.xi + 5 = diH + 2.

Също, di+1D = di+2 – di+1, ако на (i+1)-та стъпка е избрана Di+1.

Така di+1D = F (Mi+2) – F (Mi+1) = (xi + 3)2 + (yi - )2 – R2 – (xi + 2)2

(yi - )2 + R2 = 2.xi + 5 – (2.yi – 2) = 2.xi – 2.yi + 7 = diD + 2.

Нека на i-тата стъпка е избрана Di, т.е. (xi+1, y+1) = Di.

Тогава di+1H = di+2 – di+1, ако на (i+1)-та стъпка е избрана Hi+1.

Така di+1H = F (Mi+2) – F (Mi+1) = (xi + 3)2 + (yi - )2 – R2 – (xi + 2)2

(yi - )2 + R2 = 2.xi + 5 = diH + 2.

Също, di+1D = di+2 – di+1, ако на (i+1)-та стъпка е избрана Di+1.

Така di+1D = F (Mi+2) – F (Mi+1) = (xi + 3)2 + (yi - )2 – R2 – (xi + 2)2

(yi - )2 + R2 = 2.xi + 5 – (2.yi – 4) = 2.xi – 2.yi + 9 = diD + 4.

Освен това, d0H = d1 – d0, ако на 0-та стъпка е избранo Hi, т.е.

d0H = F (M1) – F (M0) = 22 + (R – )2 – R2 – 12 – (R – )2 + R2 = 3.

Също, d0D = d1 – d0, ако на 0-та стъпка е избрано Di, т.е.

d0D = F (M1) – F (M0) = 22 + (R – )2 – R2 – 12 – (R – )2 + R2 =

= 3 – (2.R – 2) = 5 – 2.R.

Имаме d0 = - R и затова отново въвеждаме ei = di - за всяко i.

Тогава e0 = 1 – R и освен това в процеса на изчисление ei се изменят по същия начин, както di – ако заменим навсякъде

по-горе di с ei ще получим коректни резултати. Но ei са цели 

ei  0  di  0, ei < 0  di < 0 и следователно можем да използваме знакът на ei за да определяме кой пиксел да изберем на i-тата стъпка. Сега е ясно следното: ако на i-тата стъпка сме избрали

Hi, т.е. (xi+1, yi+1) = Hi  ei+1 = ei + diH, а ако на i-тата стъпка сме избрали Di, т.е. (xi+1, yi+1) = Di  ei+1 = ei + diD. Така като знаем e0 и

diH, diD за всяко i ние можем да изчисляваме ei за всяко i.
Така стигаме до следния алгоритъм:

Вход: R.


1. e0 = 1 – R, d0H = 3, d0D = 5 – 2.R, x0 = 0, y0 = R, i = 0; към 2.

2. Изчертаване на пикселите (xi, yi) и (yi, xi) и шестте им симетрични точки относно двете координатни оси и центъра на координатната система; към 3.

3. Ако xi  yi към 6., иначе към 4.

4. Ако ei  0, ei+1 = ei + diD, di+1H = diH + 2, di+1D = diD + 4, yi+1 = yi – 1, иначе ei+1 = ei + diH, di+1H = diH + 2, di+1D = diD + 2, yi+1 = yi; към 5.

5. xi+1 = xi + 1, i = i + 1, към 2.

6. Край.
Всички разгледани алгоритми могат да се използват за растеризиране на дъга от окръжност по следната схема:

да предположим, че трябва да се изчертае дъгата на окръжността

F (x, y) = x2 + y2 – R2 = 0, от ъгъл  до ъгъл  (спрямо абсцисата).

Тогава трябва да действаме по следната схема: първо изчисляваме

StartX = R.cos, StartY = R.sin, EndX = R.cos , EndY = R.sin

и след това чертаем цялата окръжност по някой от алгоритмите, като оцветяваме само тези пиксели, чийто номер на стълб е между StartX и EndX и чийто номер на ред е между StartY и EndY.

Естествено, тук прибягваме до изчисляване на тригонометричните функции, но няма как.


Накрая ще разгледаме едно обобщение на алгоритъма на средната точка, което ни позволява да разстеризираме елипса. Предполагаме, че елипсата има главни направления, успоредни на координатните оси и, че нейният център е в началото. Това не е голямо ограничение, тъй като с подходяща ротация и транслация всяка елипса може да се изобрази в този вид. Така елипсата има уравнение F (x, y) = = 0, a > 0, b > 0. Еквивалентен запис е F (x, y) = b2.x2 + a2.y2 – a2.b2 = 0. Елипсата ще растеризираме в първи квадрант и ще използваме, че тя е симетрична относно координатните оси. Първият оцветен пиксел е (x0, y0) = (0, b).

Нека сме оцветили i-тият пиксел (xi, yi). Тогава (i+1)-ят пиксел се избира между пикселите Hi = (xi + 1, yi), Di = (xi + 1, yi – 1) и

Vi = (xi, yi – 1). При това растеризацията се разделя на два етапа:

през първия етап градиента на елипсата в изчертаваната точка сключва ъгъл по-голям от 45 градуса с абсцисната ос, а през втория етап градиента на елипсата в изчертаваната точка сключва ъгъл по-малък от 45 градуса с абсцисната ос. Ясно е, че през първия етап няма да има избор на Vi, а през втория етап няма да има избор на Hi. Границата между двата етапа е първият момента, в който ъгълът между градиента на елипсата в изчертаваната точка и абсцисната ос стане по-малък или равен на 45 градуса (в началото, естествено, този ъгъл е 90 градуса).

За градиента имаме grad F (xi, yi) = () =

= (2.b2.xi, 2.a2.yi). Тогава първият етап се определя от неравенството b2.xi < a2.yi. В първия момент, в който b2.xi  a2.yi трябва да започне вторият етап.

Нека сме в първия етап. За да определим кой пиксел ще се оцветява – Hi или Di, полагаме Mi = (xi + 1, yi - ) и изчисляваме

di = F (Mi) = b2.(xi + 1)2 + a2.(yi - )2 – a2.b2. Ако di  0, т.е. Mi не попада във вътрешността на елипсата, то естествено трябва да изберем (xi+1, yi+1) = Di, ако di < 0, т.е. Mi е във вътрешността на елипсата, трябва да изберем Hi. Ако сме избрали Di, тогава

di+1 = F (Mi+1) = b2.(xi + 2)2 + a2.(yi) – a2.b2 = di + b2.(xi + 2)2 +

+ a2.(yi) – b2.(xi + 1)2 – a2.(yi) = di + b2.(2.xi + 3) – a2.(2.yi – 2) =

= di + 2.b2.xi – 2.a2.yi + 3.b2 + 2.a2. Ако сме избрали Hi, тогава

di+1 = F (Mi+1) = b2.(xi + 2)2 + a2.(yi) – a2.b2 = di + b2.(xi + 2)2 +

+ a2.(yi) – b2.(xi + 1)2 – a2.(yi) = di + b2.(2.xi + 3) =

= di + 2.b2.xi + 3.b2.

Нека сме във втория етап. За да определим кой пиксел ще се оцветява – Vi или Di, полагаме Mi = (xi + , yi - 1) и изчисляваме

di = F (Mi) = b2.(xi + )2 + a2.(yi - 1)2 – a2.b2. Ако di  0, т.е. Mi не попада във вътрешността на елипсата, то естествено трябва да изберем (xi+1, yi+1) = Vi, ако di < 0, т.е. Mi е във вътрешността на елипсата, трябва да изберем Di. Ако сме избрали Vi, тогава

di+1 = F (Mi+1) = b2.(xi + )2 + a2.(yi – 2) – a2.b2 = di + b2.(xi + )2 +

+ a2.(yi – 2) – b2.(xi + )2 – a2.(yi – 1) = di – a2.(2.yi – 3) =

= di – 2.a2.yi + 3.a2. Ако сме избрали Di, тогава

di+1 = F (Mi+1) = b2.(xi + )2 + a2.(yi – 2) – a2.b2 = di + b2.(xi + )2 +

+ a2.(yi – 2) – b2.(xi + )2 – a2.(yi – 1) = di + b2.(2.xi + 2) – a2.(2.yi – 3) =

= di + 2.b2.xi – 2.a2.yi + 2.b2 + 3.a2.

Освен това, d0 = F (M0) = b2.12 + a2.(b - )2 – a2.b2 = b2 + a2.b2 – b.a2 + .a2 – a2.b2 = b2 – b.a2 + .a2. Също, при прехода между етапите, естествено, трябва в началото да изчислим di директно.

Тук привидно има недостатък, тъй като не е цяло число. Това лесно може да се избегне, ако вместо уравнението F (x, y) = 0 за елипсата използваме еквивалентното уравнение 4.F (x, y) = 0.


Така достигаме до следния алгоритъм:

Вход: a, b.

1. x0 = 0, y0 = b, d0 = 4.b2 – 4.b.a2 + a2, i = 0; към 2.

2. Изчертваваме пикселът (xi, yi) и трите му симетрични относно координатните оси и центъра на координатната система; към 3.

3. Ако a2.yi  b2.xi към 6., иначе към 4.

4. Ако di  0, di+1 = di + 8.b2.xi – 8.a2.yi + 12.b2 + 8.a2, yi+1 = yi – 1, иначе di+1 = di + 8.b2.xi + 12.b2, yi+1 = yi; към 5.

5. xi+1 = xi + 1, i = i + 1; към 2.

6. di = b2.(2.xi + 1)2 + a2.(2.yi - 2)2 – 4.a2.b2; към 7.

7. Ако di  0, di+1 = di – 8.a2.yi + 12.a2, xi+1 = xi, иначе

di+1 = di + 8.b2.xi – 8.a2.yi + 8.b2 + 12.a2, xi+1 = xi + 1; към 8.

8. yi+1 = yi – 1, i = i + 1; към 9.

9. Изчертваваме пикселът (xi, yi) и трите му симетрични относно координатните оси и центъра на координатната система; към 10.

10. Ако y > 0 към 7., иначе към 11.

11. Край.


10. Процедурно програмиране – основни информационни и алгоритмични структури (C++).
Основните принципи на структурното програмиране са принципа за модулност и принципа за абстракция на данните.

Съгласно принципа за модулност, програмата се разделя на подходящи взаимосвързани части, всяка от които се реализира чрез определени средства. Целта е промените в представянето на данните да не променят голям брой от модулите на програмата.





Сподели с приятели:
1   ...   8   9   10   11   12   13   14   15   ...   29




©obuch.info 2024
отнасят до администрацията

    Начална страница