МІНІСТЕРСТВО ОСВІТИ І НАУКИ УКРАЇНИ
НАЦІОНАЛЬНИЙ УНІВЕРСИТЕТ «ЛЬВІВСЬКА ПОЛІТЕХНІКА»
ІКТА
Кафедра «Захист інформації»
З В І Т
про виконання лабораторної роботи №3
з курсу «Програмування комп’ютерної графіки»
на тему:
«ПОБУДОВА ПРОГРАМ ГРАФІКІВ ФУНКЦІЙ ЗА ДОПОМОГОЮ ЗАСОБІВ МОВ ПРОГРАМУВАННЯ Delphi, C++ або C#»
Мета роботи – набути практичних навиків в складанні програм для побудови графіків функцій за допомогою засобів мов програмування Delphi, С++ або С#.
.
КОРОТКІ ТЕОРЕТИЧНІ ВІДОМОСТІ
Графіки, гістограми, діаграми тощо призначені для візуалізації (полегшення сприйняття людиною) числових результатів обробки інформації. При використанні комп’ютера в інженерних та наукових дослідженнях появі зображення на екрані монітора передують складні математичні розрахунки, які виконуються, як правило, в системі координат об’єкту дослідження. Така система координат називається реальною. Зображення, яке візуалізує на екрані результати розрахунків, формується в машинних координатах, характер яких визначається режимом роботи відеоадаптера.
Тому для адекватного відображення числових результатів на екрані необхідно для кожної прикладної задачі розробити чіткий алгоритм приведення реальних координат об’єкту дослідження до машинних координат. Зокрема, визначити відображення центру реальних координат на екрані в машинних координатах та функціональні залежності для розрахунку машинних координат.
/
Рис. 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 для встановлення розміру шрифта.
ЛІСТИНГ ПРОГРАМИ
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
// для работи з бібліотекою OpenGL
using Tao.OpenGl;
// для работи з бібліотекою FreeGLUT
using Tao.FreeGlut;
// для работи з елементом управління SimpleOpenGLControl
using Tao.Platform.Windows;
namespace lab_3
{
public partial class Form1 : Form
{
// розміри вікна
double ScreenW, ScreenH;
// відношення сторін вікна візуалізації
// для коректного переводу координат миші в координати,
// що прийняті в програмі
private float devX;
private float devY;
// масив, котрий буде зберігати значення x,y точок графіка
private float[,] GrapValuesArray;
// кількість елементів в масиві
private int elements_count = 0;
// прапорець, що означає, що масив із значеннями координат графіка поки що не заповнений
private bool not_calculate = true;
// номер комірки масиву, з якого будуть узяті координати для червоної крапки
// для візуалізації поточного кадру
private int pointPosition = 0;
// допоміжні змінні для побудови ліній від курсора миші до координатних осей
float lineX, lineY;
// текучі координати курсора миші
float Mcoord_X = 0, Mcoord_Y = 0;
double MaxX = 0.0;
double kX = 0.0;
double kY = 0.0;
double MaxY = 0.0;
public Form1()
{
InitializeComponent();
OnGl.InitializeContexts();
}
private void OnGl_Load(object sender, EventArgs e)
{
}
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();
}
private void PointInGrap_Tick(object sender, EventArgs e)
{
// якщо ми дійшли до останнього елементу масиву
if (pointPosition == elements_count - 1)
pointPosition = 0; // переходимо до початкового елементу
// функція візуалізації
Draw();
// перехід до наступного елементу масиву
pointPosition++;
}
private void OnGl_MouseMove(object sender, MouseEventArgs e)
{
// зберігаємо координат миші
Mcoord_X = e.X;
Mcoord_Y = e.Y;
// обчислюємо параметри для майбутнього домальовування ліній від покажчика миші до координатних осей.
lineX = devX * e.X;
lineY = (float)(ScreenH - devY * e.Y);
}
private void PrintText2D(float x, float y, string text)
{
// устанавливаем позицию вывода растровых символов
// в переданных координатах x и y.
Gl.glRasterPos2f(x, y);
// в цикле foreach перебираем значения из массива text,
// который содержит значение строки для визуализации
foreach (char char_for_draw in text)
{
// визуализируем символ c, с помощью функции glutBitmapCharacter, используя шрифт GLUT_BITMAP_9_BY_15.
Glut.glutBitmapCharacter(Glut.GLUT_BITMAP_9_BY_15, char_for_draw);
}
}
private void functionCalculation()
{
// визначення локальних змінних X і Y
float x = 0, y = 0;
// ініціалізація масиву, який зберігатиме значення 300 точок
// з яких складатиметься графік
GrapValuesArray = new float[3800, 2];
// щотчик елементів масиву
elements_count = 0;
MaxX = 350.0;
double Y;
for (x = 5; x < 180; x += 0.5f)
{
Y = 10 * (Math.Sin(x/8)+Math.Log(3*x)*Math.Cos(x/8));
if (Math.Abs(Y) > MaxY)
MaxY = Y;
}
kX = MaxX / 13.0;
kY = MaxY / 13.0;
// обчислення всіх значень у, для x належного проміжку від 5 до 180, з кроком в //0.5f
for (x = 5; x < 180; x += 0.5f)
{
// обчислення у для поточного x
// по формулі y = (float)Math.Sin(x)*3 + 1;
// цей рядок задає формулу, що описує графік функції для нашого рівняння
//y = f(x).
y = (float)(10 * (Math.Sin(x / 8) + Math.Log(3 * x) * Math.Cos(x / 8)));
// запис координати x
GrapValuesArray[elements_count, 0] = (float)(x/kX);
GrapValuesArray[elements_count + 1900, 0] = (float)(x / kX);
// запис координати y
GrapValuesArray[elements_count, 1] = (float)(y/kY);
GrapValuesArray[elements_count + 1900, 1] = (float)(-y / kY);
// підрахунок елементів
elements_count++;
}
// змінюємо прапор, що сигналізує про те, що координати графіка не розраховані
not_calculate = false;
}
// візуалізація графіка
private void DrawDiagram()
{
// перевірка прапора, що сигналізує про те, що координати графіка вирахувані
if (not_calculate)
{
// якщо немає - то викликаємо функцію обчислення координат графіка
functionCalculation();
}
// стартуємо побудову в режимі візуалізації крапок
// об'єднуваних в лінії (GL_LINE_STRIP)
Gl.glBegin(Gl.GL_LINE_STRIP);
// малюємо початкову точку
Gl.glVertex2d(GrapValuesArray[0, 0], GrapValuesArray[0, 1]);
// проходимо по масиву з координатами обчислених точок
for (int ax = 1; ax < elements_count; ax += 2)
{
// передаємо в OPENGL інформацію про вершину, що бере участь в побудові ліній
Gl.glVertex2d(GrapValuesArray[ax, 0], GrapValuesArray[ax, 1]);
}
// завершуємо режим малювання
Gl.glEnd();
Gl.glBegin(Gl.GL_LINE_STRIP);
// малюємо початкову точку
Gl.glVertex2d(GrapValuesArray[0, 0], GrapValuesArray[0, 1]);
// проходимо по масиву з координатами обчислених точок
for (int ax = elements_count; ax < elements_count*2; 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);
}
// функція, що управляє візуалізацією сцени
private void Draw()
{
// очищення буфера кольору і буфера глибини
Gl.glClear(Gl.GL_COLOR_BUFFER_BIT | Gl.GL_DEPTH_BUFFER_BIT);
// очищення поточної матриці
Gl.glLoadIdentity();
// встановлення чорного кольору
Gl.glColor3f(0, 0, 0);
// поміщаємо стан матриці в стек матриць
Gl.glPushMatrix();
// виконуємо переміщення в просторі по осях X і Y
Gl.glTranslated(15, 15, 0);
// активуємо режим малювання (Вказані далі точки виводитимуться як точки GL_POINTS)
Gl.glBegin(Gl.GL_POINTS);
// за допомогою проходу двома циклами, створюємо сітку з крапок
for (int ax = -15; ax < 15; ax++)
{
for (int bx = -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)*kX).ToString() + " ; y: " + ((float)((ScreenH - devY * Mcoord_Y - 15)*kY)).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();
}
}
}
РЕЗУЛЬТАТИ ВИКОНАННЯ ПРОГРАМИ
/
ВИСНОВОК
На даній лабораторній роботі я набув практичних навиків в складанні програм для побудови графіків функцій за допомогою засобів мов програмування С#. Програма створює порожнє вікно для графічного виводу засобами openGL, встановлює всі необхідні параметри графічного виводу, та виводить графік.