- •Московский институт электронной техники
- •Аффинные преобразования на плоскости.
- •Два взгляда на аффинные преобразования.
- •Элементарные аффинные преобразования.
- •Однородные координаты.
- •Композиция элементарных аффинных преобразований.
- •Класс Matrix2d для реализации аффинных преобразований в 2d графике.
- •Пример использования аффинных преобразований для моделирования движения в 2d-графике.
- •Пример программы моделирования движения в Windows.
- •Уничтожение следа за движущимся объектом повторным рисованием объекта в Windows программах.
- •Использование режима xor для моделирования движения в Windows программах.
- •Использование видеостраниц для моделирования движения в однопользовательских операционных системах, например в dos.
- •Использование оперативной памяти для моделирования движения в Windows программах.
- •Примеры анимации в Windows программах.
- •Задание к выполнению лабораторной работы.
- •Задание к выполнению второго пункта работы.
Пример использования аффинных преобразований для моделирования движения в 2d-графике.
Рассмотрим программу mov01.cpp, которая моделирует движение стрелки. Пусть центр стрелки движется по заданной траектории. Стрелка вращается относительно центра, и размеры стрелки уменьшаются по мере движения по траектории.
Для описания точек траектории введем функцию TrajA(). Пусть траекторией является парабола.
(31)
Уравнение траектории (31) удобно представить в параметрическом виде.
(32)
В этом случае параметр tможно считать временем. Ниже приведено описание функцииTrajA().
//структура для описания точек фигуры
struct Point
{
double x;
double y;
};
//траектория стрелки
Point TrajA(double t)
{
Point P;
P.x = t - 8;
P.y = 4 - (t - 8)*(t - 8)/10;
return P;
}
Теперь нужно описать стрелку. Пусть стрелка определяется 7-ю вершинами.
//координаты вершин стрелки текущие и начальные
Point PtA[7], PtA0[7];
//начальные координаты вершин стрелки
PtA0[0].x = 1.0; PtA0[0].y = 0.0;
PtA0[1].x = 2.0; PtA0[1].y = 0.0;
PtA0[2].x = 0.0; PtA0[2].y = 2.0;
PtA0[3].x = -2.0; PtA0[3].y = 0.0;
PtA0[4].x = -1.0; PtA0[4].y = 0.0;
PtA0[5].x = -1.0; PtA0[5].y = -2.0;
PtA0[6].x = 1.0; PtA0[6].y = -2.0;
Рис. 13.
Начальное положение стрелки.
В процессе движения стрелки координаты вершин Pбудут менять по законам аффинного преобразования.
(33)
Здесь A– матрица соответствующего аффинного преобразования. Приведем описание функцииaffine, которая выполняет аффинные преобразования над вершинами стрелки.
//аффинное преобразование координат точки P с помощью
//матрицы A
Point affine( Matrix2D A, Point P)
{
Point Pp;
Pp.x = A.x[0][0]*P.x + A.x[0][1]*P.y + A.x[0][2]*1;
Pp.y = A.x[1][0]*P.x + A.x[1][1]*P.y + A.x[1][2]*1;
return Pp;
}
Пусть цент стрелки находится в точки C(x1,y1). Нужно совершить поворот стрелки на уголвокруг этого центра. Изменить размеры стрелки относительно этого центра с коэффициентамиkx,ky. Перенести центр стрелки в точкуC*(x2,y2),как показано на Рис.14 .
Рис. 14.
Перенос цента стрелки на вектор трансляции (x2-x1,y2-y1).
Последовательность элементарных аффинных преобразований в этом примере будет следующей.
Переносим стрелку в центр системы координат на вектор (-x1,-y1), с помощью матрицыT1.
Поворачиваем стрелку относительно начала координат на угол с помощью матрицыR.
Сжимаем стрелку относительно начала координат вдоль координатных осей, с коэффициентами kx,ky, с помощью матрицыD.
Совершаем перенос стрелки на вектор трансляции (x2-x1,y2-y1) с помощью матицыT.
Переносим стрелку на вектор (x1,y1), с помощью матрицыT2 в конечное положение.
В результате матрица аффинного преобразования будет найдена путем перемножения указанных матриц.
(34)
Ниже приводится фрагмент кода программы реализующий это аффинное преобразование.
//создаем 6 матриц аффинных преобразований
Matrix2D R, T, D, A, T1, T2;
//создаем матрицы аффинного преобразования
T1.transl(-x1,-y1);
R.rotate(fi);
D.displa(kx, ky);
T.transl(x2-x1,y2-y1);
T2.transl(x1,y1);
A = T2*T*D*R*T1;
//совершаем аффинное преобразование точек фигуры
for(int n=0; n<7; n++)
Pt[n] = affine(A,Pt[n]);
После определения нового положения стрелки, стрелка выводится на экран. Рассмотренное аффинное преобразование и вывод стрелки на экран осуществляется в функции Arrow(). Ниже приведено определение этой функции.
//рисует стрелку по координатам вершин Pt в точке x2, y2
void Arrow(HDC hdc, Point *Pt, int N, double x1,double y1,
double x2,double y2,double fi,double kx,double ky)
{
//создаем матрицы аффинного преобразования
T1.transl(-x1,-y1);
R.rotate(fi);
D.displa(kx, ky);
T.transl(x2-x1,y2-y1);
T2.transl(x1,y1);
A = T2*T*D*R*T1;
//совершаем аффинное преобразование точек фигуры
for(int n=0; n<7; n++)
Pt[n] = affine(A,Pt[n]);
HPEN hpen, hpenOld;
hpen = CreatePen(PS_SOLID,1,RGB(255,255,0));
hpenOld = (HPEN)SelectObject(hdc,hpen);
MoveToEx(hdc, xn(Pt[0].x),ym(Pt[0].y), 0);
for(int i = 0; i < N; i++)
{
int j = (i + 1)%N;
LineTo(hdc,xn(Pt[j].x),ym(Pt[j].y));
}
SelectObject(hdc,hpenOld);
DeleteObject(hpen);
}
В задачах анимации встречаются два типа графических объектов, динамические объекты и статические объекты. К динамическим объектам применяются аффинные преобразования, и затем эти объекты в измененном виде рисуются на экране. Статические объекты не подвергаются преобразованием. В нашем примере динамическим объектом является стрелка. В качестве статического объекта введем закрашенный эллипс с осями координат.
Статический объект рисуется с помощью функции Land(). Ниже приведено определение этой функции.
//рисует статический объект
void Land(HDC hdc)
{
HBRUSH hbrush, hbrushOld;
HPEN hpen1, hpen2, hpenOld;
hbrush = CreateSolidBrush(RGB(0,200,0));
hbrushOld = (HBRUSH)SelectObject(hdc,hbrush);
hpen1 = CreatePen(PS_SOLID,3,RGB(255,255,255));
hpenOld = (HPEN)SelectObject(hdc,hpen1);
Ellipse(hdc,nLeft+160,mTop+20,nRight-160,mBottom-20);
//рисуем координатные оси
hpen2 = CreatePen(PS_SOLID,1,RGB(0,255,255));
SelectObject(hdc,hpen2);
int nb, ne, mb, me;
nb = xn(xLeft); mb = ym(0);
MoveToEx(hdc, nb, mb, 0);
ne = xn(xRight); me = ym(0);
LineTo(hdc,ne,me);
nb = xn(0); mb = ym(yBottom);
MoveToEx(hdc, nb, mb, 0);
ne = xn(0); me = ym(yTop);
LineTo(hdc,ne,me);
SelectObject(hdc,hpenOld);
DeleteObject(hpen1);
DeleteObject(hpen2);
SelectObject(hdc,hbrushOld);
DeleteObject(hbrush);
}