Растровая развёртка эллипса Выполнил студент третьего курса отделения прикладной математики Данный алгоритм является модификацией алгоритма генерации
окружности, предложенного Джеком Брезенхемом Уравнение эллипса имеет вид . Перепишем его следующим образом: b2x2+a2y2=a2b2 Рассмотрим точку с абсциссой xm=. Касательная к эллипсу в этой точке будет составлять угол
45º. Тогда эллипс в первой четверти можно построить в два этапа: сперва
при изменении абсциссы от 0 до xm, затем от a до xm. Алгоритм Брезенхема
пошагово генерирует очередные точки эллипса, выбирая на каждом шаге для
занесения пикселя точку растра Pi(xi, yi),
ближайшую к истинному эллипсу, так чтобы ошибка ε(Pi) = b2xi2+a2yi2 - a2b2 была минимальной. Рассмотрим генерацию части эллипса, лежащей в первой четверти, по
часовой стрелке при изменении абсциссы от 0 до xm. Проанализируем
возможные варианты занесения i-й точки, после занесения i–1 -й. При генерации эллипса
в рассматриваемой области после занесения точки P(xi-1,
yi-1)
следующая точка может быть (см. рис) либо S (xi-1+1,
yi-1)
- перемещение по горизонтали, либо T (xi-1
+ 1, yi-1 - 1) - перемещение по диагонали. Для этих
возможных точек вычислим и сравним абсолютные значения разностей квадратов
расстояний от центра эллипса до точки и эллипса: |Si| = |(xi-1+1)2 b2
+ yi-12a2 – a2b2| |Ti| = |(xi-1+1)2 b2
+ (yi-1 - 1)2a2 – a2b2| Выбирается и
заноситься та точка, для которой это значение минимально. Для определения того,
какой пиксель выбрать, составим разность di = |Si| - |Ti|= |(xi-1+1)2
b2 + yi-12a2 – a2b2|
- |(xi-1+1)2 b2 + (yi-1 - 1)2a2
– a2b2| И будем выбирать Ti
если di
> 0 и Si если di ≤ 0.
Попробуем избавиться
от модулей. Возможны 3 случая: 1. Si > 0,
а Ti
< 0. Тогда di = Si + Ti. 2. Si > 0,
а Ti
> 0. Тогда надо будет выбрать точку Ti. Если рассмотрим di
= Si
+ Ti, то
оно, очевидно, будет положительным, что соответствует точке Ti 3. Si < 0,
а Ti
< 0. Тогда надо будет выбрать точку Si. Если рассмотрим di
= Si
+ Ti, то
оно, очевидно, будет отрицательным, что соответствует точке Si Одним словом, знак
выражения di
= Si
+ Ti
определяет следующую точку однозначно. Преобразуем его
следующим образом: di
= Si + Ti = 2(xi-1+1)2 b2 + 2yi-12a2
+ a2 - 2yi-1 a2
- 2a2b2
= = 2xi-12b2 + 4xi-1b2
+ 2b2 + 2yi-12a2 + a2
- 2yi-1 a2 - 2a2b2 (*) Выведем рекуррентную
формулу для di. Для этого
рассмотрим разность di+1 - di. di+1
- di = 2xi2b2 + 4xib2
+ 2b2 + 2yi2a2 + a2
- 2yi a2 - 2a2b2 – (2xi-12b2 + 4xi-1b2
+ 2b2 + 2yi-12a2
+ a2 - 2yi-1 a2 - 2a2b2) Так как xi = xi-1 +
1, то di+1 - di = 4b2xi-1 + 6b2 + 2a2(yi
- yi-1) (yi
+ yi-1+1) Если на i-ом шаге выбрана точка S, то yi
= yi-1
и di+1= di + 4b2xi-1 + 6b2; а если точка P, то yi
= yi-1
– 1 и di+1= di + 4b2xi-1 + 6b2 - 4 a2
yi-1 Подставляя в формулу
(*) начальные значения x
= 0 и у = b, получаем, что d1 = 2b2 + a2 - 2b a2 Таким образом, дуга эллипса при изменении абсциссы от 0 до xm построена. Построение оставшейся части
эллипса в первой четверти ведётся аналогично, только меняется направление
просмотра и все х заменяются на у. Эллипс целиком можно получить отображением части, лежащей в первой
четверти, относительно осей координат и начала координат. Это делает процедура Pixel4. procedure Pixel4(xc, yc, x, y : integer); begin PutPixel(xc + x, yc + y, cc); PutPixel(xc + x, yc - y, cc); PutPixel(xc - x, yc + y, cc); PutPixel(xc - x, yc - y, cc) end; procedure Ellipse(xc, yc : integer; XRadius,
YRadius : Word); var x, y : integer; xr2, yr2, d :
longint; xm : double; begin xr2 :=
sqr(XRadius) shl 1; yr2 := sqr(YRadius) shl 1; x := 0; y :=
YRadius; d := (yr2 - xr2 * y) + xr2 shr 1 ; xm := xr2 /
sqrt((xr2 + yr2) shl 1) - 1; Pixel4(xc, yc,
x, y); while x
< xm do begin if d
> 0 then begin dec(y); d := d +
yr2 * (x shl 1 + 3) - xr2 * y shl 1 end else d := d +
yr2 * (x shl 1 + 3); inc(x); Pixel4(xc,
yc, x, y) end; d := (xr2 - yr2
* XRadius) + yr2 shr 1; x :=
XRadius; y := 0; Pixel4(xc, yc,
x, y); xm := xm + 2; while x
> xm do begin if d
> 0 then begin dec(x); d := d +
xr2 * (y shl 1 + 3) - yr2 * x shl 1 end else d := d +
xr2 * (y shl 1 + 3); inc(y); Pixel4(xc,
yc, x, y) end end; Проведённые исследования показывают, что приведённая выше процедура в 2.3 раза быстрее аналогичной из модуля Graph.
|