Міністерство освіти і науки України
Національний університет «Львівська Політехніка»
Інститут комп’ютерних технологій автоматики та метрології
Кафедра БІТ
Звіт
до лабораторної роботи № 3
з дисципліни :
“Програмування комп’ютерної графіки ”
Львів 2012
Мета: Набути практичних навиків в складанні програм для побудови графіків функцій за допомогою засобів мов програмування 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 для встановлення розміру шрифта.
Хід роботи:
1. Ввести в комп'ютер програму, написану на одній з мов програмування (Delphi, С++, С#) згідно з отриманим завданням.
2. Здійснити налагодження введеної програми, виправивши виявлені компілятором помилки.
3. Виконати програму. Текст налагодженої програми та отримані результати оформити в звіт з лабораторної роботи.
Текст програми:
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 test
{
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;
public Form1()
{
InitializeComponent();
AnT.InitializeContexts();
}
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, AnT.Width, AnT.Height);
// активация проекционной матрицы
Gl.glMatrixMode(Gl.GL_PROJECTION);
// очистка матрицы
Gl.glLoadIdentity();
// определение параметров настройки проекции, в зависимости от размеров сторон элемента AnT.
if ((float)AnT.Width <= (float)AnT.Height)
{
ScreenW = 30.0;
ScreenH = 30.0 * (float)AnT.Height / (float)AnT.Width;
Glu.gluOrtho2D(0.0, ScreenW, 0.0, ScreenH);
}
else
{
ScreenW = 30.0 * (float)AnT.Width / (float)AnT.Height;
ScreenH = 30.0;
Glu.gluOrtho2D(0.0, 30.0 * (float)AnT.Width / (float)AnT.Height, 0.0, 30.0);
}
// сохранение коэфицентов, которые нам необходимы для перевода координат указателя в оконной системе, в координаты
// принятые в нашей OpenGL сцене
devX = (float)ScreenW / (float)AnT.Width;
devY = (float)ScreenH / (float)AnT.Height;
// установка объектно-видовой матрицы
Gl.glMatrixMode(Gl.GL_MODELVIEW);
// старт щетчика, отвечающего за выхов функции визуализации сцены
PointInGrap.Start();
}
private void AnT_Load(object sender, EventArgs e)
{
}
private void PointInGrap_Tick(object sender, EventArgs e)
{
// если мы дошли до последнего элемента массива
if (pointPosition == elements_count - 1)
pointPosition = 0; // переходим к начальному элементу
// функция визуализации
Draw();
// переход к следующему элементу массива
pointPosition++;
}
private void AnT_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);
}
}
// функция, производящая вычисления координат графика
// и заносящая их в массив GrapValuesArray
private void functionCalculation()
{
// определение локальных переменных X и Y
float x = 0, y = 0;
// инициализация массива, который будет хранить значение 300 точек
// из которых будет состоять график
GrapValuesArray = new float[300, 2];
// щетчик элементов массива
elements_count = 0;
// вычисления всех значений y, для x пренадлежащего промежутку от -15 до 15, с шагом в 0.01f
for (x = -15; x < 15; x += 0.1f)
{
// вычисление y для текущего x
// по формуле y = (float)Math.Sin(x)*3 + 1;
// эта строка задает формулу, описывающую график функции для нашего уравнения y = f(x).
y = (float)Math.Sin(x) * 3 + 1;
// запись координаты x
GrapValuesArray[elements_count, 0] = x;
// запись координаты y
GrapValuesArray[elements_count, 1] = y;
// подсчет элементов
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();
// устанавливаем размер точек, равный 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).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();
// сигнал для обновление элемента реализующего визуализацию.
AnT.Invalidate();
}
}
}
Виконання програми:
Висновок: На даній лабораторній роботі я набув практичних навиків в складанні програм для побудови графіків функцій за допомогою засобів мов програмування С#. Програма створює порожнє вікно для графічного виводу засобами openGL, встановлює всі необхідні параметри графічного виводу, та виводить графік.