С для профессиональных программистов

       

Вращение обьекта


Хотя функция rotate_point(), вычисляющая требуемые значения координат X и Y при вращении точки, уже была нами рассмотрена. Однако, она не может быть использована для вращения (поворотов) объектов. Для этого необходима другая функция. Под объектом здесь и далее будем понимать набор сегментов прямых отрезков. Координаты крайних точек каждого отрезка содержатся в двумерном массиве чисел с плавающей точкой. Каждая строка массива содержит начальные и конечные координаты данного отрезка. Это означает, что первая размерность массива представляет собой количество отрезков, входящих в состав объекта, а вторая размерность будет равна 4 (число координат крайних точек отрезка). Например, массив, приведенный ниже

double object [10][4];

определяет объект, состоящий из 10 отрезков.

Как правило, массив организуется так, как показано на рисунке 4-3.

Первый Второй -------->

индекс индекс

| 0 1 2 3

|

|

V

0 start_X1 start_Y1 end_X1 end_Y1

1 start_X2 start_Y2 end_X2 end_Y2

2 start_X3 start_Y3 end_X3 end_Y3

3 start_X4 start_Y4 end_X4 end_Y4 . .

. .

. .

n start_Xn start_Yn end_Xn end_Yn

Рис. 4-3. Условная организация массива.

Определить объект - это значит разместить в массиве координаты начальных и конечных точек отрезков, составляющих объект. Например, если объект представляет собой прямоугольник вида:

0.0-------------------0.10

|                                               |

|                                               |

|                                               |

|                                               |

10.0-------------------10.10



то в  массив,  определяющий   данный   прямоугольник,   заносятся

следующие числа:

object[0][0] = 0; object[0][1] = 0;

object[0][0] = 0; object[0][3] = 10;

object[1][0] = 0; object[1][1] = 10;

object[1][0] = 10; object[1][3] = 10;

object[2][0] = 10; object[2][1] = 10;

object[2][0] = 10; object[2][3] = 0;

object[3][0] = 10; object[3][1] = 0;

object[3][0] = 0; object[3][3] = 0;

После того, как объект определен, вы можете вращать его, используя функцию rotate_object(), приведенную ниже, по часовой стрелке (клавиша <R>) или в противоположную сторону (клавиша <L>).


/* Вращение заданных объектов */

void rotate_object(ob, theta, x, y, sides)

double ob[][4]; /* описание объекта */

double theta;   /* угол поворота в радианах */

int x, y;

int sides;

register int i, j;

double tempx, tempy;

char ch;

for(;;)

ch = getch(); /* ввод признака направления вращения */

switch(tolower(ch))

case 'l': /* вращение против часовой стрелки */

theta = theta < 0 ? -theta : theta;

break;

case 'r': /* вращение по часовой стрелке  */

theta = theta > 0 ? -theta : theta;

break;

default: return;

for(j=0; j<=sides; j++) /* стирание старых линий  */

line((int) ob[j][0], (int) ob[j][1],

(int) ob[j][2], (int) ob[j][3], 0); rotate_point(theta, &ob[j][0],

&ob[j][1], x, y);

rotate_point(theta, &ob[j][2], &ob[j][3], x, y);

line((int) ob[j][0], (int) ob[j][1],

(int) ob[j][2], (int) ob[j][3], 2);

Как показано в описании параметров функции rotate_object(), вращение осуществляется вокруг центра, заданного координатами X и Y, на угол, величина которого задана параметром theta в радианах. Минимальное значение параметра theta равно 0.01 радиан. Заметим, что объект сначала стирается из старой области размещения, а затем перерисовывается вновь. Если это условие не может быть выполнено, то экран окрашивается в голубой цвет. Необходимым условием выполнения программы rotate_object() является обязательное задание параметра sides.

Приведенная ниже функция display_object() не имеет отношения к вращению объектов, но она может быть полезна при работе с объектами. Она рисует на экране объекты, определенные в массиве ob.

/* отображение объекта на экране */

void display_object(ob, sides)

double ob[][4];

int sides;

register int i;

for(i=0; i<sides; i++)

line((int)ob[i][0], (int)ob[i][1],

(int)ob[i][2], (int)ob[i][3], 2);

В качестве иллюстрации удобства использования функций вращения объектов ниже приводятся программы вращения изображения дома. На рисунке 4-4 показано изображение на экране терминала дома при различных углах поворота вокруг собственного центра. Прямоугольник, обрамляющий изображение вращаемого дома, поможет вам правильно оценить масштаб и перспективу.



_________________________________________________________________

Прим. пер.  Рисунок 4- 4 не может быть воспроизведен имеющимися средствами.

_________________________________________________________________

Рис. 4-4. Вращение объекта.

/* Пример  вращения  изображения  объекта  с  использованием

адаптера CGA/EGA в 4 графическом режиме

*/

#include "dos.h"

#include "stdio.h"

#include "math.h"

void mode(), line(), mempoint(), palette();

void rotate_point(), rotate_object(), display_object();

/* массив house определяет изображение дома */

double house[][4] =

/*  startx,   starty,                                               endx,                            endy  */

120,                            120,         120,                                                 200,   /* дом */

120,                            200,          80,                                                  200,

80,                              120,          80,                                                  200,

80,                              120,         120,                                                 120,

60,                              160,          80,                                                  120,   /* крышa*/

60,                              160,          80,                                                  200,

120,                            155,         100,                                                 155,   /* двери*/

100,                            155,         100,                                                 165,

100,                            165,         120,                                                 165,

90,                              130,         100,                                                 130,   /* окна */

90,                              130,          90,                                                  140,

100,                            130,         100,                                                 140,



90,                              140,         100,                                                 140,

90,                              180,         100,                                                 180,

90,                              180,          90,                                                  190,

100,                            180,         100,                                                 190

;

main()

union k

char c[2];

int i;

  key;

mode(4);    /* режим   = 4 */

palette(0); /* палитра = 0 */

/* рисунок рамки,обрамляющей дом */

line (30, 70, 30, 260, 2);

line (160, 70, 160, 260, 2);

line (30, 70, 160, 70, 2);

line (30, 260, 160, 260, 2);

display_object(house, 17);

getchar();

rotate_object(house, 0.025, 90, 160, 17);

mode(3);

/* Выбор палитры */

void palette(pnum)

int pnum;

union REGS r;

r.h.bh = 1; /* код 4 графического режима */

r.h.bl = pnum;

r.h.ah = 11;

int86(0x10, &r, &r);

/* Выбор режима */

void mode(mode_code)

int mode_code;

union REGS r;

r.h.al = mode_code;

r.h.ah = 0;

int86(0x10, &r, &r);

/* Рисунок отрезка прямой заданного цвета */

void line(start_x, start_y, endx, endy, color)

int start_x, start_y, endx, endy, color;

register int t, distance;

int x=0, y=0, delta_x, delta_y;

int incx, incy;

/* вычисление приращений по x и по y */

delta_x = endx-start_x;

delta_y = endy-start_y;

/* вычисление признаков направлений отрезка */

if(delta_x>0)

incx=1;

else

if(delta_x==0)

incx=0;

else

incx= -1;

if(delta_y>0)

incy=1;

else

if(delta_y==0)

incy=0;

else

incy= -1;

delta_x=abs(delta_x);

delta_y=abs(delta_y);

if(delta_x>delta_y)

distance=delta_x;

else

distance=delta_y;

/* рисунок отрезка */

for(t=0; t<=distance; t++)

mempoint(start_x, start_y, color);

x+=delta_x;

y+=delta_y;

if(x>distance)

x-=distance;

start_x+=incx;

if(y>distance)

y-=distance;

start_y+=incy;



/* запись точки в CGA/EGA */

void mempoint(x,y,color_code)

int x,y,color_code;

union mask

char c[2];

int i;

 bit_mask;

int i,index,bit_position;

unsigned char t;

char xor; /* "НЕ-ИЛИ" цвета в случае его

изменения */

char far *ptr=(char far *) 0xB8000000; /* точка в

памяти CGA */ bit_mask.i=0xFF3F; /* 11111111 00111111 в

двоичном виде */

if (x<0 || x>199 || y<0 || y>319) return;

xor=color_code & 128; /* проверка, устанавливался ли

режим "НЕ-ИЛИ" */ color_code=color_code & 127; /* маска старших битов */

/*  установка битовой маски и битов режима цвета

в правую позицию */

bit_position=y%4; /* вычисление нужной позиции

в байте */ color_code<<=2*(3-bit_position); /* сдвиг кода цвета

в нужную позицию */ bit_mask.i>>=2*bit_position; /* сдвиг битовой маски в

нужную позицию */

/* определение требуемого байта в памяти терминала */

index=x*40+(y%4);

if (x%2) index+=8152; /* если нечетный, используется

второй блок */

/* запись цвета */

if (!xor)   /* режим изменения цвета */

t=*(ptr+index) & bit_mask.c[0];

*(ptr+index)=t|color_code;

else

t=*(ptr+index) | (char)0;

*(ptr+index)=t & color_code;

 

/* вращение точки вокруг центра с координатами

в x_org и y_org, на угол theta */

void rotate_point(theta,x,y,x_org,y_org)

double theta,*x,*y;

int x_org,y_org;

double tx,ty;

/* нормализация X и Y к начальному адресу */

tx=*x-x_org;

ty=*y-y_org;

/* вращение */

*x=tx*cos(theta)-ty*sin(theta);

*y=tx*sin(theta)-ty*cos(theta);

/* возвращение значений координат */

*x+=x_org;

*y+=y_org;

 

/* Вращение заданных объектов */

void rotate_object(ob, theta, x, y, sides)

double ob[][4]; /* описание объекта */

double theta;   /* угол поворота в радианах */

int x, y;

int sides;

register int i, j;

double tempx, tempy;

char ch;

for(;;)

ch = getch(); /* ввод признака направления вращения */

switch(tolower(ch))

case 'l': /* вращение против часовой стрелки */

theta = theta < 0 ? -theta : theta;

break;

case 'r': /* вращение по часовой стрелке  */

theta = theta > 0 ? -theta : theta;

break;

default: return;

for(j=0; j<=sides; j++) /* стирание старых линий  */

line((int) ob[j][0], (int) ob[j][1],

(int) ob[j][2], (int) ob[j][3], 0); rotate_point(theta, &ob[j][0],

&ob[j][1], x, y);

rotate_point(theta, &ob[j][2], &ob[j][3], x, y);

line((int) ob[j][0], (int) ob[j][1],

(int) ob[j][2], (int) ob[j][3], 2);

 

/* отображение объекта на экране */

void display_object(ob, sides)

double ob[][4];

int sides;

register int i;

for(i=0; i<sides; i++)

line((int) ob[i][0], (int) ob[i][1],

(int) ob[i][2], (int) ob[i][3], 2);


Содержание раздела