Плоская машинная графика, страница 2

2) Простой ЦДА. В простом ЦДА e = 1/max{|x1-x0|, |y1-y0|}. В этом случае либо e×(x1-x0), либо e×(y1-y0) по модулю равно 1, поэтому для хранения дробной части можно обойтись одним аккумулятором. Положим l = max{|x1-x0|, |y1-y0|}. Приращения по x и y будут равны dx = (x1-x0)/l и dy = (y1-y0)/l. Координаты точек, генерируемых простым ЦДА, будут принимать значения

 


X = (int)(0.5 + x0 + i×dx ),

Y = (int)(0.5 + y0 + i×dy ),

где i = 0,1,...,l.

Программа

//Метод простого ЦДА

#include<conio.h>

#include<graphics.h>

#include<math.h>

int x0, y0; //Координаты центра системы координат относит. лев. верх. угла

int hx=3, hy=3; //1/2 ширины и длины пиксела

//Функция определения знака целого числа

sign(int r)

{

if(r>0) return 1;

else if(r<0) return -1;

else return 0;

}

//Вывод "крупного" пиксела на экран

void point(int ix, int iy)

{bar(x0+hx*2*ix-hx+1, y0-hy*2*iy-hy+1,x0+hx*2*ix+hx-1, y0-hy*2*iy+hy-1);}

//Генерация и вывод точек отрезка

void line_cda(int x0,int y0,int x1,int y1)

{

int i,l,x,y;

if(abs(x1-x0)>abs(y1-y0)) l=abs(x1-x0);

else l=abs(y1-y0);

if(l==0) {point(x0,y0); return;}

float hhx=1, hhy=1;

float dx=(float)((x1-x0)/float(l));

float dy=(float)((y1-y0)/float(l));

int ex=sign(x1-x0), ey=sign(y1-y0);

float rez=0.5;          //аккумулятор

x=x0; y=y0;

int flagx=0, flagy=0;   //флаги для проверки на конечную точку

do

{

if(abs(dx)<abs(dy))

{

//приращение всегда по у, а по х при условии rez<=0 rez>=1

point(x,y);

rez+=dx;

if(rez>=1||rez<=0)

{

x+=ex*hhx;

rez-=ex;

}

if(!flagx) flagx=x==x1?1:0;

y+=ey*hhy;

if(!flagy) flagy=y==y1?1:0;

}

else

{

//всегда по х, а по у при условии rez<=0 rez>=1

point(x,y);

x+=ex*hhx;

if(!flagx)flagx=x==x1?1:0;

rez+=dy;

if(rez>=1||rez<=0) {y+=ey*hhy; rez-=ey;}

if(!flagy)flagy=y==y1?1:0;

}

}

while(!(flagx==1 && flagy==1));

point(x1,y1);     //последняя точка

}

void main()

{

int gdriver=DETECT, gmode;

initgraph (&gdriver, &gmode, "");

x0=getmaxx()/2; y0=getmaxy()/2;

moveto(0,y0); linerel(getmaxx(),0);

moveto(x0,0); linerel(0, getmaxy());

line_cda(0,0,5,3);      //Вывод отрезка

getch();                //Ожидание нажатия клавиши

closegraph();           //Выключение графического режима

}

Результаты работы программы приведены на рис. 2.

Алгоритм Брезенхема. Положим Dx = x1-x0, Dy = y1-y0 . Пусть £D£Dx. При изменении координаты x на 1 координата y увеличивается на величину Dy/Dx. Пусть (x, y) - точка пересечения идеальной прямой, проходящей через точки (x0,y0) и (x1,y1), с прямой x=X, где  (X,Y)  - координаты текущей выведенной точки. Положим d = y-Y. Будем в цикле производить следующие действия: ставим точку и увеличиваем X на 1. При этом величине d придадим приращение Dy/Dx. Если число d вышло из диапазона

-1/2 £ d < 1/2 , то надо координату Y увеличить на 1, а число d уменьшить на 1. Затем переходим к началу цикла. Цикл повторяется Dx + 1 раз. Например, при Dx=4, Dy=1 величина d будет принимать значения 0, 1/4, -1/2, -1/4, 0, в этом случае при x0 = y0 = 0 будет сгенерирована последовательность точек – (0,0), (1,0), (2,1), (3,1), (4,1).

Пусть point(x,y) - функция изображения точки. Вводя переменную

e = d-1/2, -1 £ e < 0, приходим к такому алгоритму

X, Y, Dx, Dy - целые

e - вещественное

X = x0, Y = y0

Dx = x1-x0, Dy = y1 -y0(0£Dy£Dx)

e = -1/2

for i = 0 to Dx

point(X,Y)

X = X + 1

e = e + Dy/Dx

while (³ 0)

Y = Y + 1

e = e - 1

end while

next i

finish

В отличие от стандартных вариантов, данная версия генерирует и последнюю точку (x,y1). Полагая E = 2×Dx×e, приходим к целочисленному алгоритму Брезенхема генерации точек отрезка (при условии £D£Dx):

X, Y, Dx, Dy, E - целые