Лабораторная работа № 3
Вращение объекта вокруг заданного центра
 
1. Цель работы
 
1) Освоить программирование вращения двумерных объектов вокруг заданного центра с использованием методов матричного анализа.
2) Разработать программу в среде визуального проектирования C++Builder, позволяющую демонстрировать влияние параметров поворота матрицы видовых преобразований на вращение заданной фигуры вокруг начала координат или вокруг произвольной точки.
3) Освоить программирование анимации для имитации вращения графического объекта.
4) Освоить программирование закрасок (заполнений и заливок) изображения с использованием стандартных функций пакета C++Builder.
 
2. Постановка задачи и порядок выполнения работы
 
2.1. В проект, разработанный для лабораторной работы №1 добавить новый модуль с формой Form4.
2.2. В графическом окне Form4 создать систему декартовых координат.
2.3. В составе системы координат изобразить геометрическую фигуру ABCD (согласно варианту задания из табл.1) и центр вращения - произвольную точку Е, как показано на рисунке 1. Фигура должна задаваться координатами вершин: A(x1,y1), B(x2,y2), C(x3,y3), и D(x4,y4), а центр вращения – координатами E(x5,y5).
 
 
Рисунок 1 - Исходный многоугольник ABCD и центр вращения - точка Е
 
Таблица 1

Вар.
Тип фигуры
Цвет фигуры
и заливки
1
Квадрат
красный
2
Прямоугольник
синий
3
Параллелограмм
зеленый
4
Трапеция
коричневый
5
Ромб
малиновый
6
Квадрат
синий
7
Прямоугольник
зеленый
8
Параллелограмм
коричневый
9
Трапеция
малиновый
10
Ромб
красный
 
2.4. Задавая различные значения угла поворота θ (tetta), продемонстрировать следующие действия:
1). Поворот фигуры вокруг начала координат на угол θ против часовой стрелки.
2). Поворот фигуры вокруг начала координат на угол θ по часовой стрелке.
3). Поворот фигуры вокруг произвольной точки E по шагам, в соответствии с алгоритмом поворота.
4). Поворот фигуры вокруг точки E за один шаг, с помощью результирующей матрицы Трез.
Все повороты и пошаговые преобразования должны выполняться в режиме анимации. При этом необходимо принять меры к устранению эффекта «мерцания» изображения, возникающего в процессе анимационного преобразования фигуры.
2.5. Задавая различные значения переноса фигуры и точки Е, продемонстрировать свободное перемещение этих объектов.
2.6. Обеспечить возможность включения или выключения заливки (закраски) фигуры заданным цветом.
2.7. Процесс создания программного кода модуля состоит из двух этапов.
Первый этап выполняется во время лабораторного занятия, в течение которого необходимо выполнить пункты 2.1, 2.2 и 2.3.
Второй этап (пункты 2.4-2.6) выполняется самостоятельно, дома, где необходимо доработать программу. Все необходимые пояснения по порядку создания программы приведены в разделах 6 и 7.
2.8. Оформить отчет согласно правилам.
 
 
3.  Краткие теоретические сведения
 
3.1.  Вращение  объектов  вокруг  начала координат
 
Матричное уравнение поворота исходной фигуры вокруг начала координат имеет вид:
 
            Мисх× Твращ = Мрез                                                                                  (1)
 
Здесь: Мисх и  Мрез – матрицы исходных и результирующих координат фигуры.
           Твращ – матрица поворота двумерного объекта вокруг начала координат. Для поворота против часовой стрелки она записывается следующим образом:
 
где: θ (tetta) - угол поворота;
Вращение против часовой стрелки в компьютерной графике считается положительным.
Для вращения по часовой стрелке в матрице (2) необходимо поменять знаки на противоположные перед элементами, содержащими синусы угла. Тогда матрица поворота по часовой стрелке будет иметь вид:

 
Как видно из формул (2) и (3), для обеспечения вращения объекта в матрице вращения необходимо задействовать  параметры  сдвига (b = sinθ,  d = -sinθ)  и  параметры  масштабирования  по  осям  Х  и  У (a = cosθ,  е =cosθ). Совместное действие этих параметров производит реализацию процесса вращения.
Преобразование матрицы координат исходной фигуры АВСД  с помощью матрицы вращения  Твращ  в развернутой форме имеет вид:
 
Для решения (4) необходимо оцифровать обе матрицы, т.е. подставить численные значения их элементов: x1, y1, x2, y2, x3, y3, x4, y4, θ  и выполнить перемножение матриц. Полученные значения x'1, y'1, x'2, y'2, и т.д., необходимо перевести в экранные координаты и только после этого преобразованную фигуру можно прорисовывать в графическом окне проекта.
 
3.2.  Вращение  объектов  вокруг  произвольной  точки
 
Выполнить непосредственное вращение объекта вокруг произвольной точки нельзя. Это связано с тем, что базовая матрица вращения может вращать объект только вокруг центра, находящегося в начале координат. Поэтому, если центр вращения не находится в начале координат, надо сначала выполнить определенное подготовительное действие, заключающееся в переносе объекта и точки Е так, чтобы точка вращения оказалась в начале координат, после чего выполняется собственно вращение объекта вокруг этой точки, и затем объект и точку надо вернуть в исходное положение.
Всю эту последовательность преобразований можно записать в виде алгоритма:
Шаг 1: - перенос исходной фигуры  АВСД  и точки Е так, чтобы точка оказалась в начале координат.
В качестве параметров переноса  l  и  m  принимаются координаты точки E, т.е.  x5  и y5, взятые с обратными знаками;
Шаг 2: - вращение фигуры  АВСД  вокруг начала координат на заданный угол  θ;
Шаг 3: - обратный перенос фигуры  АВСД  и точки  Е  на величины  x5  и y5.
 
Тогда результирующая матрица получается как произведение матриц переноса, вращения и обратного переноса и записывается следующим образом:

 
Матричное уравнение поворота исходной фигуры вокруг произвольной точки в общем виде:

                                                      Мисх. Трез = Мрез                                                                                                         (6)
 
Или в развернутой форме:
 
В выражении (7) первая матрица – координаты вершин заданного четырехугольника ABCD и координаты произвольной точки Е – x5, y5, вокруг которой выполняется вращение, а вторая матрица - Трез.
Для решения (7) необходимо оцифровать обе матрицы, т.е. подставить численные значения их элементов: x1, y1, x2, y2, x3, y3, x4, y4, x5, y5, θ, l, m.

 
4. Интерфейс программы
 
Работа программы лабораторной работы №3 начинается с нажатия на кнопку "Lab3", расположенной на главной форме проекта Form1. После чего разворачивается дополнительная форма Form4 с установленными на ней графическим окном и панелью управления Panel1 (см. рис. 2).
На панели управления необходимо установить следующие стандартные компоненты:
- движки TrackBar1  и TrackBar2 предназначенные для перемещения ("переноса") фигуры по координатной плоскости: вправо, влево, вверх, вниз;
- окошки ввода SpinEdit1 и SpinEdit2 для управления положением точки Е по оси X и по оси Y;
- окошко ввода Edit1 для ввода угла  θ поворота фигуры;
- флажки CheckBox1 и CheckBox2, при включении которых выполняется прорисовка обозначений вершин фигуры и заливка её внутренней области;
- кнопки "Шаг 1", "Шаг 2" и "Шаг3" (Button1Button2 и Button3) - для вращения фигуры относительно произвольной точки в пошаговом режиме;
- кнопку "Поворот" (Button4) - для вращения фигуры относительно начала координат или относительно произвольной точки за один шаг;
- кнопку "Стоп" (Button5) - для остановки вращения (разрешается не устанавливать);
- кнопку "Исходное" (Button6) - для возврата фигуры в исходное положение;
- движок TrackBar3 - для изменения скорости вращения фигуры.
 
Все элементы управления, расположенные на Form4 можно условно разделить на 2 группы.
К первой группе относятся Edit1 и TrackBar3. Эти элементы являются пассивными, так как они применяются только для ввода данных, используемых затем в других функциях. Поэтому для них не потребуется создавать обработчики событий.
Ко второй группе относятся компоненты TrackBar1, TrackBar2, SpinEdit1, SpinEdit2, CheckBox1, CheckBox2, а также все кнопки Button1 - Button6. Эти компоненты, в отличие от первой группы являются активными. Для них требуется создавать обработчики событий, т.к. при осуществлении управляющих воздействий на них должно происходить изменение положения фигуры ABCD или точки Е, для чего необходимо выполнять перерисовку изображения, т.е. вызывать графический конвейер.
Работа программы должна быть организована таким образом, чтобы каждое последующее видовое преобразование изменяло положение фигуры относительно её текущего состояния (а не исходного!).
На экране фигура должна отображаться в двух состояниях - в текущем (преобразованном) и в предыдущем (до преобразования). Разное состояние фигур должно быть обозначено разным цветом.
На рисунке 2 изображено графическое окно проекта, в котором прорисованы следующие объекты:
- произвольная точка Е;
- исходная фигура ABCD, обозначенная серым цветом;
- преобразованная фигура ABCD, обозначенная красным цветом, после её поворота на 100 градусов против часовой стрелки вокруг точки Е.

 
Рисунок 2 – Окно формы Form4
 
5. Структура программы
 
5.1. Структура разрабатываемой программы
 
На рисунке 3 изображена структурная схема программы.
Так же как и в лабораторной работе №2 эта структура состоит из трех основных групп функций:
- функций инициализации исходных данных и графического окна;
- функций конвейера обработки изображения;
- функций обработки событий.
 
 Как видно из структурной схемы на рисунке 3, конвейер данной лабораторной работы незначительно отличается от конвейера предыдущей лабораторной работы. Здесь не надо прорисовывать, например, сетку и выполнять масштабирование осей (хотя и не запрещается), зато дополнительно требуется изобразить точку Е (центр вращения) и выполнить заливку фигуры ABCD заданным цветом.


 
Рисунок 3 – Структурная схема программы


6. СОЗДАНИЕ ДОПОЛНИТЕЛЬНОГО МОДУЛЯ ПРОЕКТА
 
6.1. Подключение дополнительного модуля Form4 к проекту
 
Откройте свой проект с созданными в нем модулями Form1, Form2 и Form3 и подключите дополнительный модуль с формой Form4 аналогично тому, как это было сделано в лабораторной работе №1.
 
6.2. Компоновка формы Form4
 
Порядок заполнения формы Form4 элементами управления определяется их расположением на рисунке 2 и аналогичен действиям, выполненными в лаб. раб. №2, за исключением небольших отличий в настройках:
 
1). Установите компоненты TrackBar1 и TrackBar2 с параметрами:
- Max = 20;
- Min = -20;
- Position = 0;
- TickStyle = tsManual;
 
2). Компоненты CSpinEdit1  и CSpinEdit2  находятся на вкладке Samples панели компонентов. Для них необходимо установить следующие настройки:
-.MaxValue = 10;
- MinValue = -10;
- Value = 0.
 
3).  Компонент Edit1 находятся на вкладке Standard панели компонентов. Для него необходимо установить следующие настройки:
- Text = 90.
 
4). Установите кнопки Button1Button2Button3, Button4Button5 и Button6 с соответствующими надписями;
 
5). Установите движок регулирования скорости вращения TrackBar3 с настройками:
- Max = 10;
- Min = 1;
- Position = 1;

7. РАЗРАБОТКА ФАЙЛА РЕАЛИЗАЦИИ Unit4.cpp
 
7.1. Предварительные пояснения
 
Разработку файла реализации будем вести в следующем порядке:
1) Объявим прототипы всех разрабатываемых функций и глобальные переменные, используемые в этих функциях или в обработчиках событий;
2) Выполним предварительную инициализацию переменных;
3) Разработаем функции, обеспечивающие исходную статическую прорисовку объектов, а именно:
- функцию FormPaint – являющуюся обработчиком события OnPaint для формы Form4;
- функцию графического конвейера GrafKonv(), входящую в состав FormPaint;
- функции, входящие в состав графического конвейера;
4) Разработаем функции, обеспечивающие динамические преобразования в режиме анимации:
- создадим обработчики событий для управляющих компонентов, обеспечивающих переносы фигуры и центра вращения;
- создадим обработчики событий для реализации вращения фигуры;
- создадим функцию Povorot();
5) разработаем вспомогательные функции.
 
7.2. Объявление переменных и функций
 
На рисунке 3, где изображена структурная схема программы, приведен весь перечень используемых функций. Часть этих функций стандартные, т.е. являются обработчиками инициализирующих или управляющих событий, а часть - функции собственноручной разработки, перечислим их:
 
- static void GrafKonv(void)    - функция запуска графического конвейера;
- static void Preobr(void)          - функция преобразования координат фигуры;
- static void Normir(void)         - функция нормировки;
- static void ShowAll(void)      - функция прорисовки всего изображения;
- static void ShowOsi(void)      - функция прорисовки осей координат;
- static void ShowFig(TColorcol, floatmatrT[4][3]) - функция прорисовки фигуры;
- static void Oboznath(float matrTo[4][3])                - функция прорисовки обозначений вершин фигуры;
- static void ShowToht(void)    - функция прорисовки точки Е;
- static void Povorot(void)         - функция вычисления матрицы вращения;
- static void Zalivka(void)          - функция заливки фигуры заданным цветом;
 
Каждый студент вправе выбирать свой набор функций, свои названия функций и свои списки формальных параметров функций, главное, чтобы была обеспечена корректная работа программы.
Перечислим также имена матриц координат фигуры и матриц преобразования, используемые в функциях:
- static float matrIsx[4][3]           - матрица исходных координат фигуры;
- static float matrRez[4][3]         - матрица результирующих координат фигуры;
- static float matrTek[4][3]         - матрица текущих координат фигуры;
- static float matrTekOld[4][3]   - матрица текущих координат фигуры предыдущего преобразования;
- static   int matrEkr[4][2]           - матрица экранных координат фигуры;
- static float Ted[3][3]                - единичная матрица преобразования;
- static float Tpr[3][3]                 - матрица видового преобразования;
- static float Tvr[3][3]                 - матрица вращения;
 
Все эти функции и матрицы объявите глобально. Список переменных, которые необходимо также объявить глобально составьте самостоятельно, используя данные из лабораторной работы №2.
 
7.3. Разработка функции инициализации исходных данных FormCreate()
 
Порядок создания обработчика FormCreate полностью идентичен созданию аналогичной функции в лабораторной работе №2. В составе этой функции необходимо проинициализировать графический буфер formBitmap, четыре матрицы: matrIsx[4][3], matrTek[4][3],  Ted[3][3]Tpr[3][3] и переменную nOs.
Первичную инициализацию матрицы текущих координат выполните в виде:
 
for(int i=0; i<4; i++)
    for(int j=0; j<3; j++)
        matrTek[i][j]=matrIsx[i][j];
 
Кроме этого, для обеспечения первичной прорисовки фигуры необходимо также заранее прочитать значения исходных параметров компонентов ввода и управления, установленных на форме Form4. К ним относятся следующие команды:
 
 xE = StrToFloat(Form4->CSpinEdit1->Text);         // координата x точки E
 yE = StrToFloat(Form4->CSpinEdit2->Text);        // координата y точки E
 tetta= StrToFloat(Form4->Edit1->Text);                // угол поворота фигуры
 skor=Form4->TrackBar3->Position;                       // скорость поворота фигуры
 
Объявите глобально переменные  xE, yE, tetta как float, а переменную skor как int.
 
7.4. Создание  обработчика события  FormPaint
 
Процесс создания этого обработчика полностью идентичен созданию аналогичной функции в лабораторной работе №2. Перепишите содержимое этой функции из предыдущей лабораторной работы, поменяв только номер формы.
Запустите проект на исполнение (предварительно закомментировав вызов функции GrafKonv()) и убедитесь, что в окне проекта формы Form4 в его левой части появился белый прямоугольник графического окна.
 
СТАТИЧЕСКИЙ РЕЖИМ
 
На этом этапе выполним разработку графического конвейера GrafKonv() и функций, входящих в его состав, что обеспечит исходную, статическую прорисовку всех объектов графического окна:
- осей координат;
- исходной фигуры ABCD;
- обозначений вершин фигуры;
- точки Е – произвольного центра вращения.
 
7.5. Разработка функции графического конвейера GrafKonv()
 
Содержание функции GrafKonv полностью совпадает с аналогичной функцией в лабораторной работе №2. Напомним её текст:
 
void GrafKonv(void)
{
 Preobr();         // Вызываем функцию видовых преобразований фигуры
 Normir();        // Вызываем функцию нормировки преобразованных координат
 ShowAll();      // Рисуем на битмапе всё: оси, фигуру, обозначения, точку Е
}
 
Подготовьте функцию к отладке, т.е. заглушите вызовы всех, еще не разработанных функций, входящих в состав GrafKonv() и раскомментируйте вызов GrafKonv()  в обработчике FormPaint. После этого можно запустить проект на исполнение для проверки.
 
7.6. Разработка функций Preobr() и Normir()
 
Содержание функций Preobr()  и Normir()  полностью совпадает с аналогичными функциями в лабораторной работе №2. Скопируйте эти функции из предыдущей лабораторной работы в состав данной программы. Подготовьте функции к отладке и запустите проект на исполнение для проверки.
 
7.7. Разработка функции прорисовки  изображения ShowAll()
 
В задачу функции ShowAll() данной лабораторной работы входит последовательный запуск функций, ответственных за прорисовку таких графических объектов как:
- оси координат;
- две фигуры (предыдущая и текущая (преобразованная));
- заливка текущей фигуры;
- обозначения вершин для обеих фигур и точки Е;
- точка E.
Перед вызовами функций заливки и простановки обозначений необходимо проверить состояние флажков, ответственных за их работу. С учетом этого текст функции ShowAll() будет иметь вид:
 
void ShowAll(void)
{
 ShowOsi();                                        // Прорисовка осей координат
 ShowFig(clSilver, matrTekOld);       // Прорисовка исходной фигуры серым цветом
 ShowFig(clRed, matrTek);                // Прорисовка преобразованной(текущей) фигуры
 
 if(Form4->CheckBox2->Checked)   // Если 2-ойфлажоквключен,
    Zalivka();                                       // выполняемзаливкутекущейфигуры
 
 if(Form4->CheckBox1->Checked)   // Если 1-ыйфлажоквключен,
   {Oboznath(matrTekOld);               // рисуем обозначения вершин исходной фигуры,
     Oboznath(matrTek);                     // рисуем обозначения вершин текущей фигуры.
   }
 ShowToht();                                      // Прорисовка точки E
}
Подготовьте функцию к отладке и запустите программу на исполнение для проверки.
 
7.8. Разработка функций ShowOsi() и ShowFig()
 
Тексты функций ShowOsi() и ShowFig() полностью совпадают с аналогичными функциями в лабораторной работе №2. Перепишите содержимое этих функций из предыдущей лабораторной работы.
Подготовьте эти функции к отладке и запустите программу на исполнение, чтобы убедиться в правильности прорисовки осей координат и исходной фигуры. Отладку выполняйте последовательно, сначала для одной функции, затем для второй.
 
7.9. Разработка функции заливки фигуры Zalivka()
 
Для заливки (закраски) фигуры заданным цветом применим стандартную функцию пакета C++BuilderFloodFill(). Принцип работы этой функции заключается в закраске всех пикселей, окружающих так называемый затравочный пиксель до тех пор, пока не встретится пиксель другого цвета, отличающийся от затравочного пикселя. Это, как правило, пиксели линий, ограничивающих заливаемую область.
В теле функции Zalivka() нам необходимо рассчитать координаты затравочного пикселя. Возьмем, например, для этого среднюю точку одной их диагоналей нашей фигуры и пересчитаем эти координаты в экранные. Затем, изменим цвет инструмента "Кисть" на заданный по варианту и запустим функцию закраски фигуры – FloodFill(). В заключение не забудем вернуть цвет кисти в исходное положение:
 
void Zalivka(void)
{
 float xF=(matrTek[0][0] + matrTek[2][0])/2;    // Вычисляем координаты
 float yF=(matrTek[0][1] + matrTek[2][1])/2;    // затравочного пикселя
 
 int exF=W/2+int(h*xF);                                     // Преобразуем координаты затравочного
 int eyF=H/2-int(h*yF);                                     //   пикселя в экранные
 
 FBC->Brush->Color=clRed;                                                          // Устанавливаем цвет кисти
 FBC->FloodFill(exF, eyF, FBC->Pixels[exF][eyF], fsSurface);    // Заливка
 FBC->Brush->Color=clWhite;                                                       // Возвращаем цвет кисти в исходное
}
 
Как видно из текста программного кода функции ShowAll(),  заливка фигуры осуществляется только в том случае, если включен флажок компонента CheckBox2 ("Заливка фигуры"). Поэтому, необходимо создать обработчик события CheckBox2Click, согласно пояснениям в подразделе 7.15.
Подготовьте функцию к отладке и запустите программу на исполнение. Убедитесь в том, что заливка фигуры выполняется при включении флажка компонента “Заливка”, и наоборот, исчезает при его выключении.
 
7.10. Разработка функции прорисовки обозначений  Oboznath()
 
Текст функции Oboznath() полностью совпадает с аналогичной функцией в лабораторной работе №2. Перепишите содержимое этой функции из предыдущей лабораторной работы.
Создайте обработчик события CheckBox1Click, согласно пояснениям в подразделе 7.15.
Подготовьте функцию к отладке и запустите программу на исполнение. Проверьте работу флажка CheckBox1Click (“Обозначения”) и убедитесь в правильности прорисовки обозначений вершин фигуры, а также в соответствии между координатами, выведенными возле каждой вершины и реальным местоположением фигуры в декартовой системе координат графического окна.
 
7.11. Разработка функции прорисовки точки Е
 
В задачу функции прорисовки точки ShowToht() входит выполнение следующих операций:
- пересчет координат точки Е в экранные;
- рисование точки в виде маленькой окружности;
- заливка точки черным цветом, с использованием функции FloodFill();
- простановка обозначения точки Е с её координатами (если включен флажок CheckBox1).
Значения исходных координат точки  E - xE и yE были проинициализированы в составе обработчика FormCreate(), а текущие координаты получаем при обработке событий  CSpinEdit1  и CSpinEdit2 во время внесения изменений в эти окошки. Порядок создания обработчиков CSpinEdit1  и CSpinEdit2 будет рассмотрен ниже, в динамическом режиме. Текст программного кода функции ShowToht() имеет вид:
void ShowToht(void)
{
 int exE=W/2+int(h*xE);
 int eyE=H/2-int(h*yE);
 
 FBC->Ellipse(exE-3, eyE-3, exE+3, eyE+3);
 
 FBC->Brush->Color=clBlack;
 FBC->FloodFill(exE, eyE, FPC->Pixels[exE][eyE], fsSurface);
 FBC->Brush->Color=clWhite;
 
 if(Form4->CheckBox1->Checked)
    FBC->TextOut(exE, eyE-20, "E("+FloatToStr(xE)+","+FloatToStr(yE)+")");
}
Подготовьте функцию к отладке и запустите программу на исполнение. Точка Е будет прорисована в исходном месте - в центре системы координат. При включении флажка "Обозначения" возле точки Е должны появиться её наименование и координаты.
 
На этом этапе завершается программирование статического изображения исходной фигурыABCD, точки Е и осей координат.
Далее рассмотрим программирование активных обработчиков событий, действия которых должны вызывать преобразование координат фигуры  ABCD  и точки Е, а также перерисовку всего изображения.
 
 
ДИНАМИЧЕСКИЙ РЕЖИМ
 
7.12. Предварительные замечания
 
Под динамическим режимом понимается такая работа программы, при которой можно выполнять различные преобразования фигуры ABCD и точки Е. В нашей программе к ним относятся:
- перенос фигуры ABCD вдоль осей  X и Y  с помощью движков TrackBar1 и TrackBar2;
- перенос точки Е  вдоль осей  X и Y  с использованием компонентов CSpinEdit1 и CSpinEdit2;
- вращение фигуры относительно начала координат с использованием кнопки  Button1;
- вращение фигуры относительно произвольной точки E  с использованием кнопки Button1 или трех кнопок Button3,  Button4 и Button5.
 
Все перечисленные преобразования выполним в режиме анимации.
Если в предыдущей лабораторной работе мы, при переносе фигуры, сначала вводили параметры переноса в матрицу преобразования Tpr и запускали конвейер обработки изображения с использованием цикла For, то в этой работе для реализации переноса фигуры в режиме анимации будем использовать компонент TrackBar. При перемещении движка этого компонента происходит непрерывное считывание каждой новой позиции движка на его шкале с последующей автоматической перерисовкой формы. Поэтому, для этого случая нет надобности специально формировать цикл, программа сделает это сама.
Точно так же организуем перемещение точки Е, но уже с использованием компонентов CSpinEdit.
Что касается вращения фигуры, то здесь для запуска этого процесса у нас установлена кнопка Button4. Поэтому, для реализации вращения необходимо сформировать цикл, аналогично тому, как это было сделано в предыдущей лабораторной работе. Для пересчета элементов матрицы преобразования (в данном случае это будет матрица вращения Tvr[3][3]) создадим отдельную функцию Povorot(), которую и будем вызывать в цикле, перед каждым запуском конвейера.
Далее мы рассмотрим создание всех вышеперечисленных обработчиков и функций.
 
7.13. Создание обработчиков событий для движков TrackBar1 и TrackBar2
 
Создайте обработчики событий для движков TrackBar1 и TrackBar2, аналогично тому как это делалось в лаб. раб. №2, п. 7.11. Движки предназначены для перемещения (переноса) фигуры по осям координатной плоскости: вправо, влево, вверх, вниз. Рассмотрим пример программного кода для TrackBar1:
 
void __fastcall TForm4::TrackBar1Change(TObject *Sender)
{
  for(int i=0; i<4; i++)                            // Запоминаем значения матрицы координат
    for(int j=0; j<3; j++)                          //   перед их преобразованием
       matrTekOld[i][j]=matrTek[i][j];
 
 for(int i=0; i<3; i++)                              // Очищаем матрицу видового преобразования
   for(int j=0; j<3; j++)                            //   от предыдущих изменений, т.е. приводим
       Tpr[i][j]=Ted[i][j];                           //   её к единичной матрице
 
 Tpr[2][0]=TrackBar1->Position-oldx;  // Вводим параметр переноса по Х в матрицу
                                                                //   видового преобразования
 FormPaint(0);                                        // Вызываем перерисовку изображения
}
Аналогичную функцию с необходимыми изменениями создайте для TrackBar2.
Переменные oldxoldy для обработчика TrackBar2) содержат предыдущие значения Position движков TrackBar1 и TrackBar2 . Необходимость учета этих значений связана с тем, что параметр Position движка TrackBar осуществляет полный перенос фигуры, т.е. от начала координат. Это нас не устраивает, так как нам надо переносить фигуру от её предыдущего положения на координатной плоскости на величину изменения положения движка. Поэтому параметры переноса фигуры по оси X или Y вычисляются как разница между текущим значением движков  TrackBar1 или TrackBar2  и их предыдущим положением. Необходимые предыдущие значения переменных oldx  и  oldy можно получить, если например, в функции  ShowFig, в самом её конце поместить команды:
 
 oldx=Form4->TrackBar1->Position;
 oldy=Form4->TrackBar2->Position;
 
Переменные oldx  и  oldy  объявите глобально как static int.
Запустите программу на исполнение и проверьте работу движков по перемещению фигуры.
 
7.14. Создание обработчиков событий CSpinEdit1 и CSpinEdit2
 
Создайте обработчики событий для CSpinEdit1  и CSpinEdit2.
 Компоненты CSpinEdit1  и CSpinEdit2 – представляют собой скроллинговые окошки ввода данных. В нашем конкретном случае через них мы вводим координаты точки Е – т.е. значения переменных xE для CspinEdit1 или yE для CSpinEdit2. Поэтому, содержимым обработчиков событий для этих функций будут команды чтения данных, введенных в эти окошки, и запуск команды перерисовки изображения, после которой точка Е будет прорисована в новом месте. Функция обработки события, например для CSpinEdit1, будет иметь вид:
 
void __fastcall TForm4::CSpinEdit1Change(TObject *Sender)
{
  xE = StrToFloat(Form4->CSpinEdit1->Text);
  FormPaint(0);
}
 
Функция обработки события для CSpinEdit2 создается аналогично.
Запустите программу на исполнение и проверьте работу компонентов CSpinEdit1 и CSpinEdit2 по перемещению точки Е в горизонтальном или вертикальном направлениях.
 
7.15. Создание обработчиков событий  CheckBox1 и CheckBox2
 
Флажки CheckBox1 и CheckBox2  предназначены для перезапуска графического окна с целью перерисовки изображения с новыми установками: разрешения прорисовки обозначений вершин фигуры ABCD и точки Е и для закраски фигуры заданным цветом. Порядок программирования таких обработчиков был рассмотрен в предыдущих лабораторных работах, из которых известно, что в их содержимое входят только одна команда - FormPaint(0).
 
7.16. Создание обработчика события для кнопки "Поворот"
 
Кнопка "Поворот" (Button4) предназначена для запуска видового преобразования типа "вращение" на заданный угол θ для исходной фигуры ABCD.
При нажатии на кнопку "Поворот" должны выполняться следующие действия:
- запоминание текущих координат фигуры в матрице matrTekOld[4][3] – для того, чтобы можно было обозначить предыдущее положение фигуры, т.е. её положение до поворота;
- организация цикла перерисовки фигуры со значениями углов поворота от 0 до θ, с шагом изменения параметра цикла в один градус.
Текст программного кода для этого обработчика имеет вид:
 
void __fastcall TForm4::Button4Click(TObject *Sender)
{
 for(int i=0;i<4;i++)
   for(int j=0;j<3;j++)
       matrTekOld[i][j]=matrTek[i][j];
 
 for (float i=0; i<abs(tetta); i++)
 {
   Povorot();                             // Пересчет матрицы вращения
   FormPaint(0);                       // Перерисовка графического окна
   Sleep(5*skor);                      // Задержка времени
 }
}
 
Значения угла поворота θ (tetta) и скорости вращения skor были проинициализированы в составе обработчика FormCreate(), а текущие значения угла и скорости вращения получаем при обработке событий  Edit1  и TrackBar3 во время внесения изменений в эти окошки. Порядок создания обработчиков Edit1  и TrackBar3  будет рассмотрен ниже.
Перед запуском программы для проверки, предварительно заглушите вызов функции Povorot(). Понятно, что при нажатии на кнопку "Поворот" никакого поворота фигуры мы пока не увидим.
 
7.17. Разработка функции вращения фигуры Povorot()
 
Функция  Povorot входит в состав обработчика события Button4Click (кнопка "Поворот").
При нажатии на кнопку "Поворот" запускается цикл, в котором эта функция вызывается столько раз, сколько градусов введено в окошко Edit1, с перерисовкой фигуры в каждом новом положении. Благодаря этому создается анимационный эффект вращения фигуры. Функция  Povorot  используется для реализации вращения фигуры как вокруг начала координат, так и вокруг произвольной точки.
Основное назначение функции Povorot заключается в заполнении ячеек матрицы вращения Tvr[3][3] необходимыми параметрами, для обеспечения поворота фигуры на один градус. Затем эта матрица используется в функции Preobr() в составе конвейера, для преобразования текущих координат фигуры. Последовательность команд этой функции имеет вид:
 
void Povorot(void)
{
 float te;
 
 if (tetta>=0) te= 3.14159/180;                       // Переводим один градус поворота в радианы
      else          te=-3.14159/180;
 
 float ll=xE*(1-cos(te))+yE*sin(te);              // Вычисляем заранее некоторые параметры
 float mm=yE*(1-cos(te))-xE*sin(te);           //  матрицы вращения
 
                     // Формируем матрицу вращения для поворота на один градус
 Tvr[0][0]= cos(te);   Tvr[0][1]=sin(te);   Tvr[0][2]=0;
 Tvr[1][0]=-sin(te);  Tvr[1][1]=cos(te);   Tvr[1][2]=0;
 Tvr[2][0]= ll;           Tvr[2][1]=mm;        Tvr[2][2]=1;
 
 for(int i=0; i<3; i++)                                      // Вносим изменения в текущую матрицу
   for(int j=0; j<3; j++)                                    //    преобразования
       Tpr[i][j]=Tvr[i][j];
}
 
Уберите заглушку, установленную в обработчике Button4Click  перед вызовом функции Povorot(), и запустите программу на исполнение. При нажатии на кнопку "Поворот" исходная фигура начнет вращаться с заданной скоростью до заданного значения угла поворота.
 
7.18. Создание обработчика события Edit1 для ввода угла поворота
 
Создайте обработчик события для окошка ввода Edit1 и в состав данной функции введите команду чтения значения угла поворота:
 
tetta= StrToFloat(Form4->Edit1->Text);
 
7.19. Создание обработчика TrackBar3 для регулирования скорости вращения
 
Создайте обработчик события для компонента TrackBar3 и в состав данной функции введите команду:
skor=Form4->TrackBar3->Position;
 
7.20. Создание обработчика события для кнопки "Исходное"
 
Создайте обработчик события для кнопки "Исходное" (Button6) уже известным вам способом.
Эта кнопка предназначена для выведения всех переменных, ответственных за положение фигуры ABCD и точки Е в исходное состояние. В составе этого обработчика необходимо выполнить:
- установку в исходные положения движков TrackBar1 и TrackBar2;
- обнуление окошек CSpinEdit - координат точки Е;
- присвоение исходных значений матрицам координат matrTek[4][3] и matrTekOld[4][3].
С учетом этого команды обработчика Button6Click будут иметь вид:
 
 Form4->TrackBar1->Position=0;
 Form4->TrackBar2->Position=0;
 Form4->CSpinEdit1->Text=0;
 Form4->CSpinEdit2->Text=0;
 
for(int i=0; i<4; i++)
   for(int j=0; j<3; j++)
      {matrTek[i][j]=matrIsx[i][j];
       matrTekOld[i][j]=matrIsx[i][j];
      }
 
И в заключение здесь необходимо вызвать функцию перерисовки изображения - FormPaint(0).
Запустите программу на исполнение, выполните любые изменения положения фигуры и точки Е и затем, нажав на кнопку "Исходное" убедитесь, что фигура, точка и движки элементов управления возвращаются в исходное положение.
 
7.21. Создание обработчиков событий для кнопок "Шаг 1", "Шаг 2" и "Шаг 3"
 
Создайте обработчики событий для кнопок   Button1Button2 и Button3.
При последовательном нажатии на кнопки  "Шаг 1", "Шаг 2" и "Шаг 3" должно происходить поэтапное преобразование фигуры согласно алгоритму вращения объекта вокруг произвольной точки (см. п. 3.2).
Все эти преобразования, а именно: перенос точки и фигуры таким образом, чтобы точка Е попала в центр координат (Шаг 1), вращение фигуры вокруг начала координат (Шаг 2) и обратный перенос точки и фигуры (Шаг 3) аналогичны раннее рассмотренным функциям, поэтому здесь предлагается создать эти обработчики самостоятельно.
 
На этом разработка файла реализации для данной лабораторной работы закончена.
Здесь не использована кнопка "Стоп". Надо сказать, что в рассмотренном варианте программы это сделать достаточно сложно, т. к. обычными методами прервать выполнение какой-либо функции невозможно. Но для студентов, знакомых с порядком использования системного таймера, это не составило бы особого труда.
Мы же будем использовать таймер в следующих лабораторных работах.
 
 
 
8. Контрольные  вопросы
 
1. Как выводится матрица для вращения объектов на плоскости?
2. Вокруг какой точки на плоскости вращает объекты матрица вращения?
3. Каково условие «чистого» вращения с помощью матрицы (1)?
4. Какое направление вращения в компьютерной графике принято за «положительное»?
5. У каких элементов матрицы поворота (1) необходимо поменять знак для смены направления вращения? Почему?
6. Как осуществить вращение на плоскости вокруг произвольной точки?
7. Как построить результирующую матрицу для такого преобразования?
8. За сколько шагов можно решить задачу поворота объекта вокруг произвольной точки, лежащей в плоскости координат XOY?
9. Что произойдет, если при выводе результирующей матрицы поменять порядок следования исходных матриц? Почему?
10. Как поменять направление вращения объекта?