Мета роботи - набути практичних навиків в складанні програм для побудови графіків функцій за допомогою засобів мов програмування Delphi, С++ або С#.
1. КОРОТКІ ТЕОРЕТИЧНІ ДАНІ
Графіки, гістограми, діаграми тощо призначені для візуалізації (полегшення сприйняття людиною) числових результатів обробки інформації. При використанні комп’ютера в інженерних та наукових дослідженнях появі зображення на екрані монітора передують складні математичні розрахунки, які виконуються, як правило, в системі координат об’єкту дослідження. Така система координат називається реальною. Зображення, яке візуалізує на екрані результати розрахунків, формується в машинних координатах, характер яких визначається режимом роботи відеоадаптера.
Тому для адекватного відображення числових результатів на екрані необхідно для кожної прикладної задачі розробити чіткий алгоритм приведення реальних координат об’єкту дослідження до машинних координат. Зокрема, визначити відображення центру реальних координат на екрані в машинних координатах та функціональні залежності для розрахунку машинних координат.
/
Рис. 1. Побудова графіка на екрані монітора
При побудові графіків для приведення реальних координат до машинних в загальному випадку (рис. 1) використовують наступні вирази:
; (1)
, (2)
де Xмаш , Yмаш - поточні машинні координати точки в пікселях ;
, - відображення центру реальних координат на екрані в машинних координатах ;
Xреальн ,Yреальн - поточні реальні координати точки ;
kX, kY- коефіцієнти перетворення .
Коефіцієнти перетворення в загальному випадку розраховують за наступними співвідношеннями :
; (3)
. (4)
Отже, для побудови графікадовільної функції можна скористатися наступним алгоритмом:
Протабулювати задану функцію на проміжку зміни аргументу з метою визначення максимального та мінімального значень функції.
Визначити значення коефіцієнтів перетворення для стискання (у випадку, якщо максимальні значення функції або аргументу перевищують допустиму роздільну здатність монітора) або розширення діапазонів значень функції і аргументу для нормального візуального сприйняття заданої функції на екрані монітора. Наприклад, діапазон зміни значень функції синус від -1до 1. Якщо не ввести коефіцієнт розтягу то на екрані монітора при побудові графіка функції одержимо пряму лінію. Домноживши значення Y на ky = 100, одержимо функцію синуса в звичному для нас вигляді.
Побудувати графік функції, з’єднуючи за допомогою ліній (процедури LINE() або LINETO()) попередньо обраховані значення координат точки функції з наступними.
Здійснити розмітку осей через певні проміжки табулювання для Xта Y.
Для розмітки осей користуються процедурами LINE() і LINETO() для зображення відміток на осях, а для підписування числових значень поблизу відміток - процедурами OUTTEXT() і OUTTEXTXY().
Процедура OUTTEXT()виводить текст за поточним положенням вказівника. Звертання
OUTTEXT(<текст>),
де <текст> - вираз типу string,що вказує на текст, який виводиться на екран монітора.
Процедура OUTTEXTXY()виводить текст за заданими координатами. Формат звертання
OUTTEXTXY(X,Y, <текст>),
де X,Y - змінні типу integer- координати точки, в яку виводитиметься текст, <текст> - вираз типу string,що вказує на текст, який виводитиметься на екран монітора.
Процедура SETTEXTSTYLE() встановлює тип шрифта, орієнтацію та розмір тексту, що виводиться на екран монітора. Синтаксис:
SETTEXTSTYLE(Font, Direction, SizeChar),
де Font - змінна типу word, що вказує на тип шрифта, Direction - змінна типу word, що визначає напрям виведення тексту (0 - горизонтально, 1 - вертикально), SizeChar - змінна типу word для встановлення розміру шрифта.
2. ЗАВДАННЯ
2.1. Домашня пiдготовка до роботи
Ознайомлення з методами візуалізації графіків функцій на екрані монітора комп’ютера з використанням бібліотеки OPENGL (C#).
Розглянемо процес створення програми, завданням якої буде візуалізація графіка заданої функції в середовищі VisualC# (www.esate.ru). Особливістю програми буде те, що в ній буде анімована демонстрація того, як міняється значення функції на графіку.
Це буде реалізовано таким чином: по графіку рухається червона крапка, що приймає значення у для заданого x.Крім цього, біля курсорабудутьвиводитись його координати.
Створіть або використайте основу додатку, як це було зроблено в попередніх лабораторних роботах. Тільки не додавайте кнопки «Візуалізувати» і «Закрити», обмежтеся елементом Simpleopenglcontrol.
Додайте в проект 1 таймер - назвіть його (параметр nameу властивостях таймера) Pointingrap, і встановіть в його властивостях інтервал 30 мілісекунд. Посля цього клацніть по ньому двічі, щоб створилася функція Pointingrap_tick, яка відповідає за обробку події ontimer.
Тепер, коли основа додатку створена, ми перейдемо до початкового коду. Він буде базуватись на 7 функціях, які ми зараз розглянемо, але спочатку, перед кодом функції-конструктора класу додайте ініціалізацію наступних змінних:
// разміривікна doubleScreenW, ScreenH; // відношення сторін вікна візуалізації// для коректного переводу координат миші в координати, // що прийняті в програмі privatefloatdevX; privatefloatdevY; // масив, котрий буде зберігати значенняx,y точок графіка privatefloat[,] GrapValuesArray; // кількістьелементів в масивіprivateintelements_count = 0; // прапорець, що означає, що масив із значеннями координат графіка поки що не заповнений
privateboolnot_calculate = true; // номер комірки масиву, з якого будуть узяті координати для червоної крапки // для візуалізації текучого кадраprivateintpointPosition = 0; // допоміжні змінні для побудови ліній від курсора миші до координатних осейfloatlineX, lineY; // текучі координатикурсора мишіfloatMcoord_X = 0, Mcoord_Y = 0;
Тепер розглянемо нашступні 7 функцій.
Перша функція - це обробник події завантаження форми - Form1_load. Тут, при завантаженні додатку буде проведена ініціалізація OPENGLдля подальшої візуалізації. Ініціалізацію OPENGLз двомірною проекцією було розглянуто в попередній лабораторній роботі. Єдиною відмінністю є те, що код став трохи більш докладним. Код цієї функції:
private void Form1_Load(object sender, EventArgs e) {
// ініціалізаціябібліотеки glut Glut.glutInit(); // ініціалізація режиму екрануGlut.glutInitDisplayMode(Glut.GLUT_RGB | Glut.GLUT_DOUBLE); // установка кольору очищення екрану (RGBA) Gl.glClearColor(255, 255, 255, 1); // установкапортавиводуGl.glViewport(0, 0, OnGl.Width, OnGl.Height); // активація проекційної матриціGl.glMatrixMode(Gl.GL_PROJECTION); // очисткаматриціGl.glLoadIdentity(); // визначення параметрів настройки проекції, залежно від розмірів сторінелементаOnGl. if ((float)OnGl.Width<= (float)OnGl.Height) {
ScreenW = 30.0; ScreenH = 30.0 * (float)OnGl.Height / (float)OnGl.Width; Glu.gluOrtho2D(0.0, ScreenW, 0.0, ScreenH);
} else {
ScreenW = 30.0 * (float)OnGl.Width / (float)OnGl.Height; ScreenH = 30.0; Glu.gluOrtho2D(0.0, 30.0 * (float)OnGl.Width / (float)OnGl.Height, 0.0, 30.0);
} // збереження коефіцентов, які нам необхідні для перекладу координат покажчика у віконній системі, в координати// прийнятівнашій OpenGL сценіdevX = (float)ScreenW / (float)OnGl.Width; devY = (float)ScreenH / (float)OnGl.Height; // установка об'єктно-видової матриціGl.glMatrixMode(Gl.GL_MODELVIEW); // старт лічильника, що відповідає за старт функції візуалізації сцениPointInGrap.Start();
}
Тепер звернемося до функції Pointingrap_tick. Ця функція викликається із затримкою в 30 мілісекунд. У ній ми ведемо відлік того, з якого елементу масиву з координатами графіка, ми зараз возмем координати, які використовуємо для малювання червоної крапки. Звідси так само викликається функція Draw, що відповідає за візуалізацію. Код цієї функції:
// функція обробник події таймераprivate void PointInGrap_Tick(object sender, EventArgs e) {
// якщо ми дійшли до останнього елементу масивуif (pointPosition == elements_count-1) pointPosition = 0; // переходимо до початкового елементу // функція візуалізаціїDraw(); // перехід до наступного елементу масивуpointPosition++;
}
Тепер, перш ніж перейти до функцій, що відповідають за візуалізацію, ми розглянемо несолько невеликих допоміжних функий. Начитаємо з функції OnGl_mousemove. Эта функція додається створенням події Mousemoveдля елементу Simpleopnglcontrol (OnGl). Подія створюється аналогічно тому, як ми його створювали в розділі 2.2. Тільки в даному випадку ми переходимо до властивостей елементу OnGl, і вже в них перезходім у вкладку Event і додаємо подію Mousemove. У даній функції, ми проводимо збереження поточних координат миші, щоб в будующем використовувати їх при візуалізації графіка, а так само проводимо обчислення розмірів ліній, які по нормалях сполучатимуть координати покажчика миші з координатними осями. Код цієї функції виглядає наступним чином
// обробка руху миші над елементомOnGlprivatevoidOnGl_MouseMove(objectsender, MouseEventArgse) {
// зберігаємо координат миші Mcoord_X = e.X; Mcoord_Y = e.Y; // обчислюємо параметри для майбутнього домальовування ліній від покажчика миші до координатних осей. lineX = devX * e.X;lineY = (float)(ScreenH - devY * e.Y);
}
Тепер розглянемо функцію, яка здійснюватиме візуалізацію текстових рядків. Дана функція встановлює координати виведення растрових символів, відповідно до координат, переданих в параметрах x і у, а потім в циклі перебирає всі символи з вказаного в параметрі рядка тексту. Кожен з символів відображається за допомогою функції . У цій функції указується шрифт для виводу і змінна типу char для відображення. Код функції виглядає таким чином
// функція відображення текстуprivatevoidPrintText2D(floatx, floaty, stringtext) {
// встановлюємо позицію виведення растрових символів// у переданих координатах x і у. Gl.glRasterPos2f(x, y); // // у циклі foreach перебираємо значення з масиву text, // який містить значення рядка для візуалізації
foreach (char char_for_draw in text) {
// візуалізуємо символ з, за допомогою функції glutbitmapcharacter, використовуючи //шрифт
GLUT_BITMAP_9_BY_15. Glut.glutBitmapCharacter(Glut.GLUT_BITMAP_9_BY_15, char_for_draw);
}
}
Наступна функція, якої ми торкнемося, - це функція, що обчислює координати для побудови графіка. У ній ініціалізується масив координат і проводиться обчислення всіх координат графіка, залежно від вказаного діапазону значень x і кроку приросту цих значень. Звернете увагу на те, що при ініціалізації масиву для зберігання координат, повинно бути вказаний така кількість елементів масиву, щоб надалі їх вистачило для розміщення всіх координат, інакше відбудеться виключення, оскільки програма в процесі роботи спробує звернутися до області пам'яті, яка їй не належить. Код цієї функції з докладними коментарями
// функція, що проводить обчислення координат графіка // і що заносить їх в масив Grapvaluesarray
privatevoidfunctionCalculation() {
// визначення локальних змінних X і Yfloatx = 0, y = 0; // ініціалізація масиву, який зберігатиме значення 300 точок// з яких складатиметься графік GrapValuesArray = newfloat[300, 2]; // щетчик елементів масивуelements_count = 0; // обчислення всіх значень у, для x пренадлежащего проміжку від -15 до 15, з кроком в //0.01ffor (x = -15; x< 15; x += 0.1f) {
// обчислення у для поточного x// по формулі y = (float)Math.Sin(x)*3 + 1; // цей рядок задає формулу, що описує графік функції для нашого рівняння y = f(x). y = (float)Math.Sin(x)*3 + 1; // запис координати xGrapValuesArray[elements_count, 0] = x; // запис координати y GrapValuesArray[elements_count, 1] = y; // підрахунок елементівelements_count++;
} // змінюємо прапор, що сигналізує про те, що координати графіка не розрахованіnot_calculate = false;
}
Функція, що виконує візуалізацію графіка. Оскільки візуалізацію графіка можна віднести до конкретної підзадачі функції візуалізації сцени (і щоб не захаращувати функцію візуалізації сцени), ми винесемо візуалізацію графіка в окрему функцію.
У цій функції спочатку буде перевірений прапор, що сигналізує про те, що координати графіка обчислені і занесені в масив (змінна not_calculate). В тому випадку, якщо прапор указує, що прорахунку значень ще не було - викликається функція, яка порахує значення координат точок графіка і заповнить ними масив.
Далі реалізується прохід циклом for по масиву значень координат точок графіка і їх візуалізація, причому ми візуалізуємо не крапки, а об'єднуємо ці крапки в лінію, грунтуючись на значенні координат крапок, як на вершинах.
По завершенню отрісовки графіка, проводитися малювання червоної крапки, в тих координатах, до яких ми дійшли, послідовно перебираючи значення елементів в масиві координат.
Вихідний код даної функції
// візуалізація графікаprivatevoidDrawDiagram() {
// перевірка прапора, що сигналізує про те, що координати графіка вичеслениif (not_calculate) {
// якщо немає - те викликаємо функцію обчислення координат графікаfunctionCalculation();
} // стартуємо побудову в режимі візуалізації крапок// об'єднуваних в лінії (GL_LINE_STRIP) Gl.glBegin(Gl.GL_LINE_STRIP); // малюємо початкову точкуGl.glVertex2d(GrapValuesArray[0, 0], GrapValuesArray[0, 1]); // проходимо по масиву з координатами обчислених точокfor (intax = 1; ax<elements_count; ax+=2){
// передаємо в OPENGL інформацію про вершину, що бере участь в побудові лінійGl.glVertex2d(GrapValuesArray[ax, 0], GrapValuesArray[ax, 1]);
} // завершуємо режим малюванняGl.glEnd(); // встановлюємо розмір крапок, рівний 5 пікселямGl.glPointSize(5);// встановлюємо поточним кольором - червоний колірGl.glColor3f(255, 0, 0);// активуємо режим виведення точок (GL_POINTS) Gl.glBegin(Gl.GL_POINTS);// виводимо червону крапку, використовуючи ту ячеку масиву, до якої ми дійшли
// (обчислюється у функиі обробнику подій таймера)Gl.glVertex2d(GrapValuesArray[pointPosition, 0], GrapValuesArray[pointPosition, 1]);// завершуємо режим малюванняGl.glEnd();// встановлюємо розмір крапок рівний одиниціGl.glPointSize(1);
}
І тепер нам залишилося проглянути лише останню функцію - функцію Draw. У нім візуалізується координатна сітка під графіком, координатні осі і букви для їх позначень, а так само викликаємося функція малювання графіка, і виводяться координати миші з лініями, що сполучають покажчик миші і осі координат. Код цієї функції виглядає таким чином
// функція, що управляє візуалізацією сцениprivatevoidDraw(){
// очищення буфера кольору і буфера глибиниGl.glClear(Gl.GL_COLOR_BUFFER_BIT | Gl.GL_DEPTH_BUFFER_BIT); // очищення поточної матриціGl.glLoadIdentity(); // утснаовка чорного кольоруGl.glColor3f(0, 0, 0); // поміщаємо стан матриці в стек матрицьGl.glPushMatrix(); // виконуємо переміщення в прострастве по осях X і YGl.glTranslated(15, 15, 0); // активуємо режим малювання (Вказані далі точки виводитимуться як точки GL_POINTS) Gl.glBegin(Gl.GL_POINTS); // за допомогою проходу вдумя циклами, створюємо сітку з крапокfor (intax = -15; ax< 15; ax++) {
for (intbx = -15; bx< 15; bx++) {
// вивідточкиGl.glVertex2d(ax, bx);
}
} // завершення режиму малювання примітивівGl.glEnd(); // активуємо режим малювання, кожні 2 послідовно викликані коммандиglVertex// об'єднуються в лініїGl.glBegin(Gl.GL_LINES); // далі ми малюємо координатні осі і стреклі на їх кінцяхGl.glVertex2d(0, -15);Gl.glVertex2d(0, 15); Gl.glVertex2d(-15, 0);Gl.glVertex2d(15, 0); // вертикальна стрілкаGl.glVertex2d(0, 15);Gl.glVertex2d(0.1, 14.5);Gl.glVertex2d(0, 15);Gl.glVertex2d(-0.1, 14.5); // горизонтальна стрілкаGl.glVertex2d(15, 0);Gl.glVertex2d(14.5, 0.1);Gl.glVertex2d(15, 0);Gl.glVertex2d(14.5, -0.1); // завершуємо режим малюванняGl.glEnd(); // виводимо підписи осей "x" і "y"PrintText2D(15.5f, 0, "x"); PrintText2D(0.5f, 14.5f, "y"); // викликаємо функцію малювання графікаDrawDiagram(); // повертаємо матрицю із стекаGl.glPopMatrix(); // виводимо текст із значенням координат біля курсораPrintText2D(devX * Mcoord_X + 0.2f, (float)ScreenH - devY * Mcoord_Y + 0.4f, "[ x: " + (devX * Mcoord_X - 15).ToString() + " ; y: " + ((float)ScreenH - devY * Mcoord_Y - 15).ToString() + "]"); // встановлюємо червоний колірGl.glColor3f(255, 0, 0); // вмикаємо режим малювання ліній, для того, щоб намалювати// лінії від курсора миші до координатних осейGl.glBegin(Gl.GL_LINES); Gl.glVertex2d(lineX, 15);Gl.glVertex2d(lineX, lineY);Gl.glVertex2d(15, lineY);Gl.glVertex2d(lineX, lineY); Gl.glEnd(); // чекаємо завершення візуалізації кадруGl.glFlush(); // сигнал для оновлення елементу того, що реалізовує візуалізацію.OnGl.Invalidate();
}
2. Написати програму, яка будує в середині екрану систему координат XY і на ній графік функції Y=F(X), використовуючи графічні бібліотеку OpenGl, якщо аргумент або параметр змінюється на проміжку [a;b] з кроком h. Крім C# можна використовувати С+ або Delphi. Варіанти завдань беруть з таблиці 1 за вказівкою викладача.
Таблиця 1.
N%п/п
Функція
Інтервал
Крок

1

r=[1;50]
k=[0;2*pi]
h=5
h=pi/(4*r)

2

x=[0;16]
h=0.1

3

x=[0;180]
h=0.15

4

x=[1;]
h=0.5

5

t=[1;200]
h=0.5

6

t=[1;2]
h=0.01

7

t=[-100;100]
h=0.5

8

t=[1;20]
h=0.1


Продовження таблиці 2.
N%п/п
Функція
Інтервал
Крок

9

t=[1;18]
h=0.1

10

t=[-100;100]
h=0.5

11

t=[1;500]
h=0.5

12

t=[1;3]
h=0.005

13

t=[-100;100]
h=0.5

14

t=[0;20]
h=0.01

15

t=[-100;100]
h=0.5

16

t=[1;20]
h=0.01

17

x=[1;20]
h=0.01

18

t=[-1;200]
h=0.5

19

t=[1;200]
h=0.5

20

x=[0;180]
h=0.5

21

x=[0;180]
h=0.5

22

x=[5;180]
h=0.5

23

x=[0;180]
h=0.5

24

t=[1;17]
h=0.01

25

x=[5;150]
h=0.1


2.2. Робота в лабораторiї
1. Ввести в комп'ютер програму, написану на одній з мов програмування (Delphi, С++, С#) згідно з отриманим завданням.
2. Здійснити налагодження введеної програми, виправивши виявлені компілятором помилки.
3. Виконати програму. Текст налагодженої програми та отримані результати оформити в звіт з лабораторної роботи.
3. ЗМIСТ ЗВIТУ
1. Повний текст завдання.
2. Блок-схема алгоритму програми.
3. Список ідентифікаторів констант, змінних, процедур і функцій, використаних в програмі, та їх пояснення.
4. Остаточно відлагоджений текст програми згідно з отриманим завданням.
5. Результати виконання програми.
4. КОНТРОЛЬНI ПИТАННЯ
Як здійснюється масштабування при побудові графіків на екрані монітора комп’ютера.
Які процедури та функції мовпрограмування для управління текстом в графічному режимі вам відомі?
Як встановити поточний стиль тексту?
СПИСОК ЛIТЕРАТУРИ
Петров М. Компьютернаяграфика. Підручник|посібник| для вузів. - Спб.: Пітер, 2002.
Рейбоу В. Компьютернаяграфика. Енциклопедія. - Спб.: Пітер, 2002.
Роджерс Д. Алгоритмическиеосновымашиннойграфики. - М.: Мир|світ|, 1989..
Сніжко Е. Компьютернаягеометрия и графика: Конспект лекций. – Спб.: Видавництво БГТУ, 2005.
Блинова Т.А., Порев В.Н. Компьютернаяграфика. Учебноепособие. К. Юниор., 2006.
www.esate.ru