Вы находитесь на странице: 1из 13

МІНІСТЕРСТВО ОСВІТИ І НАУКИ УКРАЇНИ

Національний аерокосмічний університет ім. М.Є. Жуковського


“Харківський авіаційний інститут”

Факультет програмної інженерії та бізнесу

Кафедра інженерії програмного забезпечення

ЛАБОРАТОРНА РОБОТА 4
з курсу «Компьютерная графика с OpenGL»

на тему: «КРИВЫЕ ВТОРОГО ПОРЯДКА»

Виконав: студент 3 курсу групи № 632п


напряму підготовки (спеціальності)
121 «Інженерія програмного забезпечення»
(шифр і назва напряму підготовки (спеціальності))
Тука Я.Л.
(прізвище й ініціали студента)
Прийняв: доц. Лучшев П.О.
(посада, науковий ступінь, прізвище й ініціали)
Національна шкала:
Кількість балів:
Оцінка ECTS:
2

Харків – 2019
10 вариант
ЦЕЛЬ РАБОТЫ: изучить математические методы и средства для реализации
графических примитивов.
ЗАДАНИЕ
Используя инструментальные средства, указанные преподавателем,
разработать программу для вывода кривых второго порядка на экран (в окно
Windows) с помощью отрезков. Для кривых, которые в варианте отмечены «++»,
найти и вывести на экран точки пересечения, если такие есть, с произвольным
отрезком, координаты которого задает пользователь.
ТЕОРЕТИЧЕСКИЕ СВЕДЕНИЯ

Перепишем уравнение гиперболы:

в виде 

Отсюда видно, что 

Положим 

тогда  и 

следовательно,  (1)

Две гиперболы, заданные уравнениями

 и 

в одной и той же декартовой прямоугольной системе координат с


одними и теми же значениями полуосей а и b, называются
сопряженными

Выше доказано, что всякая гипербола


3

может быть выражена параметрическими уравнениями  ;

параметрические уравнения гиперболы, сопряженной с данной, будут

Достаточно хорошее представление окружности получается, если


соединить отрезками некоторое количество равномерно
распределенных на ней точек. Однако, если рассчитывать точки эллипса
через равные приращения угла, изображение будет неверным, как
показано штриховой линией на рис. 4.6. Особенно сильно неточности
проявляются на концах, где кривизна слишком велика и требуется
большее количество точек.
Другой метод основан на равных приращениях по периметру и дает хороший
результат для достаточно большого количества точек. Недостатки его в том, что
указывается слишком много точек на сторонах с малой кривизной, и
вычисление равных частей периметра требует  сложного расчета
эллиптического интеграла. Что нам необходимо, это малые приращения
параметра у концов, где кривизна велика, и большие приращения параметра
вдоль сторон с малой кривизной.
Такое распределение точек получается из параметрического представления
эллипса с центром в начале координат, большой полуосью   и малой
полуосью  :

,                 (4-6)

где   - параметр.

Рис. 4-6 Равноугольное представление сильно вытянутого эллипса.

Диапазон от 0 до   задает полный эллипс. Требуемое распределение точек


порождается равномерными приращениями параметра  .
4

Рассматривая производные   и  :

,                       (4-7)

получаем, что при  , близком к 0 или  , т.е. у концов,   и  . Если   


близко к   или  , т.е. вдоль сторон, то   и  . Таким образом,
около концов, где кривизна более высокая, точки располагаются чаще, а вдоль
сторон, где кривизна меньше, - реже. Отношение приращений периметра
концов к приращениям вдоль сторон приблизительно равно  . Отметим, что
для окружности   достигается оптимальное представление - равные
приращения параметра или угла.

Если задано фиксированное количество точек на эллипсе, можно, пользуясь


формулами суммы углов, получить эффективный алгоритм [4-2]. Координаты
любой точки на эллипсе:

где   - фиксированное приращение  ,   - количество точек на


периметре,   - значение параметра для точки  ,  .

По формуле суммы углов

Применяя уравнение (4-4) с  , перепишем эти уравнения:

,
5

.        (4-8)

Так как  ,   и   - константы, полученный алгоритм содержит во внутреннем


цикле только четыре умножения, одно сложение и вычитание и достаточно
эффективен. В работе [4-2] показано, что алгоритм
дает многоугольник максимальной площади, вписанный в эллипс. Результат
представлен на рис. 4-7.
Чтобы получить эллипс с центром не в начале координат и с главной осью,
расположенной под углом к горизонтали, его поворачивают вокруг начала
координат, а затем переносят.
Пример 4-4 Параметрическое построение эллипса

Построить эллипс с большой полуосью   и малой полуосью  , под углом   к


горизонтали, с центром в точке  .

Сначала построим эллипс с центром в начале координат с помощью 32 точек ( , так


как первая и последняя точки совпадают). Мы рассмотрим только точки первого
квадранта, т.е. диапазон параметра от 0 до  .

Рис. 4-7 Параметрическое представление эллипса.

Приращение параметра

Пользуясь уравнением (4-6) с начальным значением  , найдем   и  :


6

Вычислим величины  ,   и

Теперь по формуле (4-8) найдем вторую точку

РЕШЕНИЕ ПОСТАВЛЕННОЙ ЗАДАЧИ

МАШИННЫЙ ЛИСТИНГ
using System;
using System.ComponentModel;
using System.Data.Metadata.Edm;
using System.Drawing;

namespace glWinForm6
{
[ToolboxItem(true), ToolboxBitmap(typeof(RenderControl),
"RenderControl.bmp")]
public partial class RenderControl : OpenGL
{
private float WinWid = 60.0F;
private float WinHei = 60.0F;
private double x1 = 2, x2 = 1, y1 = 1, y2 = 3;
private double a = -30, b = 15;
private double n = 30, Omin, Omax, xmin = 0, xmax = 4;
public double A
{
get
{
7

return this.a;
}
set
{
this.a = value;
this.Invalidate();
}
}
public double B
{
get
{
return this.b;
}
set
{
this.b = value;
this.Invalidate();
}
}

public double X1
{
get
{
return this.x1;
}
set
{
this.x1 = value;
this.Invalidate();
}
}
public double X2
{
get
{
return this.x2;
}
set
{
this.x2 = value;
this.Invalidate();
}
}
public double Y1
{
get
{
return this.y1;
}
set
{
this.y1 = value;
this.Invalidate();
}
}
public double Y2
{
8

get
{
return this.y2;
}
set
{
this.y2 = value;
this.Invalidate();
}
}
public RenderControl() : base(false)
{
InitializeComponent();
}

public override void OnStartingOpenGL()


{
glClearColor(BackColor);
}

public override void OnFinishingOpenGL()


{
}

public override void OnRender()


{
screen();
grid();
coordPlane();
StrokeEllipse(0, 0, 2, 3, 360);
hyperandper();
}

private void screen()


{
double size = 15;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |
GL_STENCIL_BUFFER_BIT);
glLoadIdentity();
glClearColor(Color.White);
glClear(GL_COLOR_BUFFER_BIT);

glViewport(0, 0, Width, Height);


if (Width > Height)
glViewport((Width - Height) / 2, 0, Height, Height);
else
glViewport(0, (Height - Width) / 2, Width, Width);

gluOrtho2D(-size, +size, -size, +size);


}

private void hyperandper()


{
Omin = 0;
Omax = (1 / Math.Cosh(xmax / a));
double bO = (Omax - Omin) / (n - 1);

double ch = Math.Cosh(bO);
double sh = Math.Sinh(bO);
9

double x11 = a * Math.Cosh(Omin);


double y11 = b * Math.Sinh(Omin);
double x22;
double y22;

glColor(Color.DarkBlue);
glLineWidth(2);

glBegin(GL_LINE_STRIP);

glVertex2d(x11, y11);

for (double i = 0; i < n; i++)


{

x22 = x11 * ch + (a / b) * y11 * sh;


y22 = (b / a) * x11 * sh + y11 * ch;

glVertex2d(x22, y22);
x11 = x22; y11 = y22;
}
glEnd();

x11 = -(a * Math.Cosh(Omin));


y11 = 0;
glBegin(GL_LINE_STRIP);
glVertex2d(x11, -y11);

for (double i = 0; i < n; i++)


{

x22 = x11 * ch + (a / b) * (-y11) * sh;


y22 = (b / a) * x11 * sh + (-y11) * ch;

glVertex2d(x22, -y22);
x11 = x22; y11 = -y22;
}
glEnd();

x11 = a * Math.Cosh(Omin);
y11 = 0;
glBegin(GL_LINE_STRIP);
glVertex2d(x11, -y11);

for (double i = 0; i < n; i++)


{

x22 = x11 * ch + (a / b) * (-y11) * sh;


y22 = (b / a) * x11 * sh + (-y11) * ch;

glVertex2d(x22, -y22);
x11 = x22; y11 = -y22;
}
glEnd();

x11 = -(a * Math.Cosh(Omin));


y11 = 0;
glBegin(GL_LINE_STRIP);
glVertex2d(x11, -y11);
10

for (double i = 0; i < n; i++)


{

x22 = (-x11) * ch + (a / b) * (-y11) * sh;


y22 = (b / a) * (-x11) * sh + (-y11) * ch;

glVertex2d(-x22, -y22);
x11 = -x22; y11 = -y22;
}
glEnd();

line();

x11 = -(a * Math.Cosh(Omin));


y11 = b * Math.Sinh(Omin);

for (double i = 0; i < n; i++)


{
x22 = x11 * ch + (a / b) * y11 * sh;
y22 = (b / a) * x11 * sh + y11 * ch;
double a11 = x22 - x11;
double a12 = x1 - x2;
double a21 = y22 - y11;
double a22 = y1 - y2;
double b1 = x1 - x11, b2 = y1 - y11;
double det, det1, det2, t1, t2, xx, yy;

det = a11 * a22 - a12 * a21;


det1 = b1 * a22 - a12 * b2;
det2 = a11 * b2 - b1 * a21;
t1 = det1 / det;
t2 = det2 / det;
xx = (x22 - x11) * t1 + x11;
yy = (y22 - y11) * t1 + y11;

glPointSize(3);
glBegin(GL_POINTS);
if (((0 <= t1) && (t1 <= 1)) && ((0 <= t2) && (t2 <= 1)))
{
glColor(Color.Yellow);
glVertex2d(xx, yy);
}
glEnd();
x11 = -x22; y11 = -y22;
}

private void coordPlane()


{
glColor(Color.Black);
glLineWidth(1.5F);
glBegin(GL_LINES);
glVertex2d(0, -15);
11

glVertex2d(0, 15);
glVertex2d(-15, 0);
glVertex2d(15, 0);
glVertex2d(0, 15);
glVertex2d(0.1, 14.5);
glVertex2d(0, 15);
glVertex2d(-0.1, 14.5);
glVertex2d(15, 0);
glVertex2d(14.5, 0.1);
glVertex2d(15, 0);
glVertex2d(14.5, -0.1);
glEnd();
}

private void grid()


{
glColor(Color.Gray);
glLineWidth(0.1F);

glBegin(GL_LINES);

for (double ax = -15; ax < 15; ax += 1.0)


{
for (double bx = -15; bx < 15; bx += 1.0)
{
glVertex2d(ax + 1.0, WinHei);
glVertex2d(ax + 1.0, -WinHei);
glVertex2d(WinWid, -bx + 1.0);
glVertex2d(-WinWid, -bx + 1.0);
}
}
glEnd();
}

//контур эллипса
private void StrokeEllipse(double xCenter, double yCenter, double rx,
double ry, int pointCount)
{
double step = 2 * Math.PI / pointCount;
// pointCount точек на его границе с шагом 2*PI/pointCount
glColor(Color.Red);
glBegin(GL_LINE_STRIP);
for (double angle = 0; angle < 2 * Math.PI; angle += step)
{
double dx = rx * Math.Cos(angle);
double dy = ry * Math.Sin(angle);
glVertex2d(dx + xCenter, dy + yCenter);
}
glEnd();
}
private void line()
{
glColor(Color.DarkGreen);
glBegin(GL_LINE_STRIP);
glVertex2d(x1, y1);
glVertex2d(x2, y2);
glEnd();
}
}
12

using System.Windows.Forms;

namespace glWinForm6
{
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
this.renderControl1.X1 = (double)this.numericUpDown1.Value;
this.renderControl1.Y1 = (double)this.numericUpDown2.Value;
this.renderControl1.X2 = (double)this.numericUpDown3.Value;
this.renderControl1.Y2 = (double)this.numericUpDown4.Value;
this.renderControl1.A = (double)this.numericUpDown5.Value;
this.renderControl1.B = (double)this.numericUpDown6.Value;
}

private void NumericUpDown1_ValueChanged(object sender, System.EventArgs


e)
{
this.renderControl1.X1 = (double)this.numericUpDown1.Value;
}

private void NumericUpDown2_ValueChanged(object sender, System.EventArgs


e)
{
this.renderControl1.Y1 = (double)this.numericUpDown2.Value;
}

private void NumericUpDown3_ValueChanged(object sender, System.EventArgs


e)
{
this.renderControl1.X2 = (double)this.numericUpDown3.Value;
}

private void NumericUpDown4_ValueChanged(object sender, System.EventArgs


e)
{
this.renderControl1.Y2 = (double)this.numericUpDown4.Value;
}

private void NumericUpDown5_ValueChanged(object sender, System.EventArgs


e)
{
this.renderControl1.A = (double)this.numericUpDown5.Value;
}

private void NumericUpDown6_ValueChanged(object sender, System.EventArgs


e)
{
this.renderControl1.B = (double)this.numericUpDown6.Value;
}
}
}
13

ЭКРАННАЯ ФОРМА

ТРЕБОВАНИЯ
№ Сложность Требования Баллы
1 Базовый уровень Установка изотропной системы 1
координат для
окна с изменяемыми размерами
2 Вывод кривых второго порядка в 2
соответствии с вариантом задания
3 Вывод отрезка и расчет его точек 2
пересечения с кривой второго порядка в
соответствии с вариантом

Вывод: в данной лабораторной работе изучил математические методы и


средства для реализации графических примитивов.