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

Министерство образования Республики Беларусь

Учреждение образования «Институт информационных технологий


Белорусского государственного университета информатики и
радиоэлектроники»

Факультет компьютерных технологий

Кафедра информационных систем и технологий

Дисциплина: Алгоритмы компьютерной графики

ОТЧЁТ
по лабораторной работе

на тему:
«Отсечение многоугольников (двухмерное отсекающее окно). Отсечение
одной фигурой другой фигуры»

Вариант № 7

Выполнил: студент гр. ХХХ


ХХХХХХ.

Приняла: Коренская И.Н.

Минск 2022
Цель: изучить и реализовать алгоритмы Коэна-Сазерленда и Кируса-
Бэка.

Задание: необходимо реализовать двухмерное отсекающее окно,


размеры которого должны задаваться пользователем. В данном окне,
согласно варианту задания, вывести пересекающиеся примитивы с
отсечением невидимых линий: видимые линии — сплошные, невидимые
пунктирные. Реализовать анимацию сближения и пересечения двухмерных
примитивов с учетом вращения последних вокруг собственного центра.
Обеспечить возможность управления местоположением любого из
примитивов манипулятором типа «мышь».
Индивидуальное задание представлено на рисунке 1.

Рисунок 1 – Индивидуальное задание

Теоретическая часть
Отсечение - это процесс выделения некоторой части базы данных,
описывающей изображение. Основное применение алгоритмов отсечения -
это отбор той информации, которая необходима для визуализации
конкретной сцены или вида, как части более обширной обстановки. Но кроме
этого отсечение применяется в алгоритмах удаления невидимых линий и
поверхностей, при построении теней, а также при формировании фактуры.
Двухмерное отсечение
Целью алгоритма отсечения является определение тех точек, отрезков
или их частей, которые лежат внутри отсекающего окна. Эти точки, отрезки
или их части остаются для визуализации, а все остальное отбрасывается.
Алгоритм двухмерного отсекающего окна
1) Переопределение координат отрезков в параметрах IX, IY.
2) Определение видимости отрезков по отношению к отсекающему окну
(определение координат отсечки):
а) если IX1— ІX2 ≠ 0 или IY1 — IҮ2 ≠ 0, то отрезок не принадлежит
отсекающему окну (невидим);
б) если IХ1— ІX2 - IҮ1 — IҮ2 — 0, то отрезок целиком лежит внутри
отсекающего окна (полностью видим);
в) если IX1 ≠ 0 и/или IҮ1 ≠ 0, то конец отрезка (х, у) лежит за пределами
отсекающего окна и должна быть определена точка отсечки, т. е. точка ( x '1, у '1
), пересечения отрезка со стороной отсекающего окна (отрезок частично
видим); аналогично вычисляется точка отсечки ( x '2, у '2), если IX2 ≠ 0 и/или
IҮ2 ≠ 0 (отрезок частично видим);
г) если точка ( x '1, у '1) или ( x '2, у '2) есть пересечение отрезка с одним из
продолжений сторон отсекающего окна, т. е. отрезок проходит вне отсекаю-
щего окна, то он игнорируется и не вычерчивается (отрезок невидим).
3) Конец алгоритма.

Код программы

float rotate2 = 0;
float posX1 = 100;
float posX2 = 500;
float posX3 = 30;
float posY1 = -550;
float posY2 = -550;
float posY3 = -630;
float moveSide1 = 1;
float moveSide2 = 1;
float width = 600;
float height = 250;
float speedMove = 0.1;
private: System::Void pictureBox1_Paint(System::Object^ sender,
System::Windows::Forms::PaintEventArgs^ e) {

int pictureBox_width = pictureBox1->Width;


int pictureBox_height = pictureBox1->Height;
Bitmap^ img = gcnew Bitmap(pictureBox_width, pictureBox_height);

Graphics^ g1 = Graphics::FromImage(img);
Graphics^ g2 = Graphics::FromImage(img);
Graphics^ g3 = Graphics::FromImage(img);

g1->ScaleTransform(1, -1);
g1->TranslateTransform(posX1, posY1);
g2->ScaleTransform(1, -1);
g2->TranslateTransform(posX2, posY2);
g3->ScaleTransform(1, -1);
g3->TranslateTransform(posX3, posY3);

Generic::List<PointF>^ points = gcnew Generic::List<PointF>();


points->Add(PointF(-60, 65));
points->Add(PointF(50, 80));
points->Add(PointF(50, -30));

/*points->Add(PointF(-100, 20));
points->Add(PointF(100, 20));
points->Add(PointF(100, -20));
points->Add(PointF(-100, -20));*/

System::Drawing::Drawing2D::GraphicsPath^ polygonInvisible = gcnew


System::Drawing::Drawing2D::GraphicsPath();
polygonInvisible->AddPolygon(points->ToArray());

System::Drawing::Drawing2D::Matrix^ translatePolyInvisible = gcnew


System::Drawing::Drawing2D::Matrix();

translatePolyInvisible->Translate(posX2 - posX1, posY2 - posY1);


translatePolyInvisible->Rotate(rotate2);
polygonInvisible->Transform(translatePolyInvisible);

System::Drawing::Region^ regionPolygon = gcnew


System::Drawing::Region(polygonInvisible);
System::Drawing::Drawing2D::GraphicsPath^ rectInvisible = gcnew
System::Drawing::Drawing2D::GraphicsPath();

rectInvisible->AddRectangle(Rectangle(0.0, 0.0, width, height));


System::Drawing::Drawing2D::Matrix^ translateRectInv = gcnew
System::Drawing::Drawing2D::Matrix();

translateRectInv->Translate(posX3 - posX2, posY3 - posY2);


rectInvisible->Transform(translateRectInv);

System::Drawing::Region^ regionRect = gcnew


System::Drawing::Region(rectInvisible);
System::Drawing::Drawing2D::GraphicsPath^ rectInvisible2 = gcnew
System::Drawing::Drawing2D::GraphicsPath();

rectInvisible2->AddRectangle(Rectangle(0.0, 0.0, width, height));


System::Drawing::Drawing2D::Matrix^ translateRectInv2 = gcnew
System::Drawing::Drawing2D::Matrix();
translateRectInv2->Translate(posX3 - posX1, posY3 - posY1);
rectInvisible2->Transform(translateRectInv2);

System::Drawing::Region^ regionRect2 = gcnew


System::Drawing::Region(rectInvisible2);

System::Drawing::Drawing2D::GraphicsPath^ polygon = gcnew


System::Drawing::Drawing2D::GraphicsPath();
polygon->AddPolygon(points->ToArray());
System::Drawing::Drawing2D::Matrix^ translatePolygon = gcnew
System::Drawing::Drawing2D::Matrix();
translatePolygon->Rotate(rotate2);
polygon->Transform(translatePolygon);

g3->DrawRectangle(Pens::Black, 0.0, 0.0, width, height);


g2->ExcludeClip(regionRect);

//При пересечении - пунктир


Pen^ pen = gcnew Pen(Color::Red, 1.0f);
array<float>^ pattern = { 5.0f, 3.0f };
pen->DashPattern = pattern;
g2->DrawPath(pen, polygon);
g2->SetClip(regionRect, System::Drawing::Drawing2D::CombineMode::Complement);
//Синий - прямоугольник
g2->DrawPath(Pens::Blue, polygon);
g1->ExcludeClip(regionRect2);

/*Generic::List<PointF>^ pointss = gcnew Generic::List<PointF>();


pointss->Add(PointF(-100, 20));
pointss->Add(PointF(100, 20));
pointss->Add(PointF(100, -20));

g3->DrawPolygon(Pens::Black, pointss->ToArray());*/

g1->DrawEllipse(pen, -50, -50, 100, 100);


g1->SetClip(regionRect2, System::Drawing::Drawing2D::CombineMode::Complement);
g1->DrawEllipse(pen, -50, -50, 100, 100);
g1->ExcludeClip(regionPolygon);

g1->DrawEllipse(Pens::Green, -50, -50, 100, 100);


g1->SetClip(regionPolygon, System::Drawing::Drawing2D::CombineMode::Complement);
g1->DrawEllipse(pen, -50, -50, 100, 100);

delete g1;
delete g2;
delete g3;
this->pictureBox1->Image = img;
rotate2 = rotate2 + 0.5;
if (moveSide1 == 1) {
posX1 = posX1 + speedMove;
if (posX1 >= 300) {
moveSide1 = 0;
}
}
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {
float num;
bool isnumX = float::TryParse(textBox1->Text, num);
bool isnumY = float::TryParse(textBox2->Text, num);
if (isnumX) {
width = float::Parse(textBox1->Text);
}
if (isnumY) {
height = float::Parse(textBox2->Text);
}
}
bool moveFirst = false;
bool moveSecond = false;
private: System::Void pictureBox1_MouseDown(System::Object^ sender,
System::Windows::Forms::MouseEventArgs^ e) {
if ((e->X <= posX1 + 50) && (e->X >= posX1 - 50) && (-e->Y <= posY1 + 50) && (-e-
>Y >= posY1 - 50)) {
moveFirst = true;
}
else
if ((e->X <= posX2 + 50) && (e->X >= posX2 - 50) && (-e->Y <= posY2 + 50)
&& (-e->Y >= posY2 - 50)) {
moveSecond = true;
}
}
private: System::Void pictureBox1_MouseMove(System::Object^ sender,
System::Windows::Forms::MouseEventArgs^ e) {
if (moveFirst) {
posX1 = e->X;
posY1 = -e->Y;
}
else
if (moveSecond) {
posX2 = e->X;
posY2 = -e->Y;
}
}
private: System::Void pictureBox1_MouseUp(System::Object^ sender,
System::Windows::Forms::MouseEventArgs^ e) {
moveFirst = false;
moveSecond = false;
}
int mode = 1;
private: System::Void button2_Click(System::Object^ sender, System::EventArgs^ e) {
if (mode == 1) {
mode = 0;
button2->Text = "Старт";
speedMove = 0;
}
else if (mode == 0) {
mode = 1;
button2->Text = "Стоп";
speedMove = 0.2;
}
}
};
}

Результаты работы программы

Результат работы программы представлен на рисунке 2.

Рисунок 2 – Результат работы программы

Вывод: в ходе выполнения лабораторной работы мы изучили алгоритмы


двумерного отсечения, а именно алгоритм Кируса-Бека и Сазерленда-Коэна,
после чего применили знания на практике разработав программу на языке C+
+, демонстрирующую на экране контуры пересекающихся примитивов,
находящихся в движении.
Алгоритм Сазерленда-Коэна был применен для проверки концов
концевых точек отрезков, получающихся в результате деления исходного
отрезка пополам. Алгоритм Кируса-Бека, особенностью которого является
корректная работа для любого выпуклого многоугольника, мы использовали
для отсечения невидимых линий при пересечении фигур.
Также в данной лабораторной работе были задействованы аффинные
преобразования для реализации движения и поворота фигур вокруг своей
оси.
Подводя итог данной лабораторной работы можно сказать, что при
сравнении алгоритмов мы можем сказать, что алгоритм Сазерленда-Коэна
уступает алгоритму Кируса-Бека по эффективности, однако для меня он
оказался проще для восприятия. Алгоритм Сазерленда-Коэна эффективнее
применять в случае, когда большинство примитивов содержится целиком в
большом окне либо же большинство примитивов лежит целиком вне
относительно маленького окна. А вот алгоритму Кируса-Бека является
качественной заменой Коэна-Сазерленда, который выполняет отсечение за
несколько итераций.
Цель лабораторной работы была достигнута в полом объёме.

Вам также может понравиться