Програма пошуку перетину відрізків та побудови чотирикутників

Узнать стоимость написания работы

Національний університет «Львівська політехніка»

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

КУРСОВА РОБОТА

з дисципліни «Об’єктно-орієнтоване програмування»

на тему:

«Програма пошуку перетину відрізків та побудови чотирикутників»

Виконав: студент

напряму 6.050103«Програмна інженерія»

групи ПІ-21

Хижняк Д. Е.

Керівник:

асистент кафедри програмного забезпечення,

Цимбалюк Т.М.

Оцінка:

Національна шкала___________________

Кількість балів_______Оцінка ECTS____

Члени комісії ____________ Коротєєва Т.О.

(підпис)

____________ Цимбалюк Т.М.

(підпис)

Львів – 2016 рік

ЗМІСТ

1. ЗАВДАННЯ.. 3

2. АЛГОРИТМ РОЗВ’ЯЗКУ ЗАВДАННЯ.. 4

3. UML ДІАГРАМИ.. 7

4. ВИХІДНИЙ КОД ПРОГРАМИ.. 11

4.1. Клас головної форми. 11

4.2. Клас відрізка. 21

4.3. Клас чотирикутника. 25

4.4. Клас обробника відрізків. 27

4.5. Класи винятків. 28

5. ПРОТОКОЛ РОБОТИ ПРОГРАМИ.. 30

6. ІНСТРУКЦІЯ КОРИСТУВАЧА.. 39

6.1. Призначення програми. 39

6.2. Правила використання. 39

6.2.1. Навігація. 39

6.2.2. Вхідні та вихідні дані 42

6.2.3. Додаткове ПЗ. 43

6.2.4. Системні вимоги. 44

7. ВИСНОВОК.. 45


1. ЗАВДАННЯ

Написати програму засобами ООП визначення координат точок перетину відрізків в площині або в просторі. Знайти периметр та площу чотирикутника, утвореного з’єднанням чотирьох точок відрізків. Відрізки задаються координатами крайніх точок з клавіатури або з файлу. Зобразити поточну задачу на екрані (для просторового випадку – проекцію на площину). Інтерфейс програми повинен бути написаний українською мовою. Передбачити виняткові ситуації.


2. АЛГОРИТМ РОЗВ’ЯЗКУ ЗАВДАННЯ

Для розв’язку поставленого завдання було необхідно реалізувати такі алгоритми: алгоритм пошуку перетину відрізків на площині та у просторі, обчислення периметра та площі утвореного чотирикутника.

Суть алгоритму пошуку перетину відрізків на площині (Рис. 2.1.) полягає у створенні матриці площини, основаної на чотирьох точках кінців відрізків. Обчисливши значення визначника матриці, можна робити висновок про положення відрізка відносно площини.

Рис. 2.1. Блок-схема алгоритму пошуку перетину відрізків на площині

Для знаходження перетину відрізків у просторі використовується алгоритм зображений на Рис. 2.2. Для знаходження перетину відрізки проектуються на площини XOY, XOZ та YOZ. Після цього, аналізуючи результати перетину на проекціях, отримуємо результат перетину у просторі.

Рис. 2.2. Блок-схема пошуку перетину відрізків у просторі

Отримання периметра чотирикутника є досить тривіальною задачею. Необхідно просто додати довжини відрізків, що задають його сторони. Алгоритм обрахунку зображений на Рис. 2.3.

Рис. 2.3. Блок-схема обчислення периметра прямокутника

Знайти площу чотирикутника дещо складніше, адже чотирикутник може бути самоперетинаючимось (протилежні сторони мають точку перетину). Тому необхідно перевірити такий випадок, а також, випадок, коли сторони накладаються одна на одну.

Рис. 2.4. Блок-схема обчислення площі чотирикутника


3. UML ДІАГРАМИ

Для розробки програми були побудовані UML діаграми класів, прецедентів та послідовності (Рис. 3.1.). На діаграмі класів зображена взаємодія головних класів застосунку. Клас відрізка “GLSegment”, який зберігає інформацію про відрізок, дозволяє його опрацьовувати та виконувати пошук перетину між двома відрізками, що є одним з головних завдань. Аналогічний клас створений для представлення чотирикутника “GLRectangle”. Використовуючи об’єкти класу точки “GLPoint”, інші фігури позиціонуються у просторі. Інтерфейс “IDrawable” надає базові функції та поля, які використовуються геометричними фігурами. Клас “SegmentProcessor” виступає класом – контейнером для відрізків та надає функції для обробки колекцій відрізків.

Рис. 3.1. Діаграма класів

На діаграмі прецедентів (Рис. 3.2.) зображено загальну логіку роботи програми та основні дії, які може виконати користувач, при роботі з нею.

Рис. 3.2. Діаграма прецедентів

На діаграмі послідовності можна побачити один з варіантів ходу виконання програми, дії, які може виконати користувач та функції, які будуть виконані програмою при певному ході роботи.

Рис. 3.3. Діаграма послідовності


4. ВИХІДНИЙ КОД ПРОГРАМИ

4.1. Клас головної форми

Тут описана більшість візуальних ефектів, структура програми, та її взаємодія з користувачем.


#pragma once

#include "OpenGLView.h"

#include "GLPoint.h"

#include "GLSegment.h"

#include "GLRectangle.h"

#include "FancyButton.h"

#include "TextBoxValidator.h"

#include "FileReader.h"

namespace SegmentsIntersection {

using namespace System;

using namespace System::ComponentModel;

using namespace System::Collections;

using namespace System::Windows::Forms;

using namespace System::Data;

using namespace System::Drawing;

public ref class MainForm : public System::Windows::Forms::Form

{

public:

MainForm(void)

{

InitializeComponent();

PostInit();

}

protected:

~MainForm()

{

if (components)

{

delete components;

}

}

private: bool Dragging = false;

private: Point MouseDragStart;

private: System::Drawing::Image^ ImgCloseNormal;

private: System::Drawing::Image^ ImgCloseDark;

private: System::Drawing::Image^ ImgHomeNormal;

private: System::Drawing::Image^ ImgHomeDark;

private: System::Drawing::Image^ ImgBackNormal;

private: System::Drawing::Image^ ImgBackDark;

private: System::Drawing::Image^ ImgChecked;

private: System::Drawing::Image^ ImgUnchecked;

private: Constants::FormState formState;

private: Constants::FormState prevFormState;

private: FancyButton^ ButtonInputState;

private: FancyButton^ ButtonLoadState;

private: FancyButton^ ButtonManualState;

private: FancyButton^ ButtonCheckSegments;

private: DataGridViewSelectedRowCollection^ PointsTableSelection;

private: DataGridViewSelectedRowCollection^ SegmentsTableSelection;

private: bool NeedReselectionPoints;

private: bool NeedReselectionSegments;

private: System::Collections::Generic::List<GLPoint^>^ rectanglePoints;

private: bool *IsValidInput;

private: cli::array<TextBoxValidator^>^ TextBoxArray;

private: SegmentProcessor^ sProc;

private: GLPoint^ answPoint;

private: GLRectangle^ answRect;

private: String^ CrossAnswer;

private: OpenGLView^ OpenGL;

private: FileReader^ SegmentReader;

private: System::Windows::Forms::PictureBox^ ButtonClose;

private: System::Windows::Forms::Panel^ TopPanel;

private: System::Windows::Forms::Label^ Title;

private: System::Windows::Forms::PictureBox^ ButtonHome;

private: System::Windows::Forms::Panel^ PanelHome;

private: System::Windows::Forms::Panel^ PanelInput;

private: System::Windows::Forms::ImageList^ imageList;

private: System::Windows::Forms::Label^ lblSegment1;

private: System::Windows::Forms::Label^ lblCheckBox;

private: System::Windows::Forms::PictureBox^ cbIsFlat;

private: System::Windows::Forms::Label^ lblSegment2Z;

private: System::Windows::Forms::Label^ lblSegment2Y;

private: System::Windows::Forms::Label^ lblSegment2X;

private: System::Windows::Forms::Label^ lblSegment1Z;

private: System::Windows::Forms::Label^ lblSegment1Y;

private: System::Windows::Forms::Label^ lblSegment1X;

private: System::Windows::Forms::Label^ lblPoint2;

private: System::Windows::Forms::Panel^ tbX1Border;

private: System::Windows::Forms::Panel^ tbX1BorderBot;

private: System::Windows::Forms::TextBox^ tbX1;

private: System::Windows::Forms::Panel^ tbY1Border;

private: System::Windows::Forms::Panel^ tbY1BorderBot;

private: System::Windows::Forms::TextBox^ tbY1;

private: System::Windows::Forms::Panel^ tbZ1Border;

private: System::Windows::Forms::Panel^ tbZ1BorderBot;

private: System::Windows::Forms::TextBox^ tbZ1;

private: System::Windows::Forms::Panel^ tbX2Border;

private: System::Windows::Forms::Panel^ tbX2BorderBot;

private: System::Windows::Forms::TextBox^ tbX2;

private: System::Windows::Forms::Panel^ tbY2Border;

private: System::Windows::Forms::Panel^ tbY2BorderBot;

private: System::Windows::Forms::TextBox^ tbY2;

private: System::Windows::Forms::Panel^ tbZ2Border;

private: System::Windows::Forms::Panel^ tbZ2BorderBot;

private: System::Windows::Forms::TextBox^ tbZ2;

private: System::Windows::Forms::Panel^ PanelResult;

private: System::Windows::Forms::Panel^ DebugOpenGL;

private: System::Windows::Forms::Label^ lblResult;

private: System::Windows::Forms::Label^ lblAnswer;

private: System::Windows::Forms::PictureBox^ ButtonResultBack;

private: System::Windows::Forms::Label^ lblResultBack;

private: System::Windows::Forms::Panel^ DebugButonCheckSegments;

private: System::Windows::Forms::Label^ lblInputError;

private: System::Windows::Forms::WebBrowser^ wbManual;

private: System::Windows::Forms::DataGridView^ ResultPointsTable;

private: System::Windows::Forms::DataGridViewTextBoxColumn^ colPoint;

private: System::Windows::Forms::DataGridView^ SegmentInputTable;

private: System::Windows::Forms::DataGridViewTextBoxColumn^ dataGridViewTextBoxColumn1;

private: System::Windows::Forms::Button^ btnClearSegment;

private: System::Windows::Forms::Button^ btnDeleteSegment;

private: System::Windows::Forms::Button^ btnAddSegment;

private: System::Windows::Forms::Label^ lblSegmentTable;

private: System::Windows::Forms::Button^ btnCreateRectangle;

private: System::Windows::Forms::Label^ lblErrorRectangle;

private: System::ComponentModel::IContainer^ components;

private:

//оголошення функцій, реалізація яких винесена поза класс

private: void PostInit();

private: void HomePageInit();

private: void InputPageInit();

private: void ResultPageInit();

private: void ManualPageInit();

private: void InitializeOpenGL();

private: void HomePageVisibility(bool visible);

private: void InputPageVisibility(bool visible);

private: void ResultPageVisibility(bool visible);

private: void ManualPageVisibility(bool visible);

private: void LoadPageVisibility(bool visible);

private: System::Void btnAddSegment_Click(System::Object^ sender, System::EventArgs^ e);

private: System::Void btnDeleteSegment_Click(System::Object^ sender, System::EventArgs^ e);

private: System::Void btnClearSegment_Click(System::Object^ sender, System::EventArgs^ e);

private: System::Void btnCreateRectangle_Click(System::Object^ sender, System::EventArgs^ e);

private: System::Void ButtonCheckSegments_Click(System::Object^ sender, System::EventArgs^ e);

private: System::Void rbIsFlat_Click(System::Object^ sender, System::EventArgs^ e);

private: System::Void lblCheckBox_Click(System::Object^ sender, System::EventArgs^ e) {

rbIsFlat_Click(sender, e);

}

//-----------------------------------

//ОБРОБКА СТАНУ ФОРМИ

//-----------------------------------

private: property Constants::FormState MainForm::FormState

{

void set(Constants::FormState value)

{

if (this->formState == value)

return;

switch (this->formState)

{

case Constants::FormState::EMPTY:

break;

case Constants::FormState::HOME:

HomePageVisibility(false);

break;

case Constants::FormState::INPUT:

InputPageVisibility(false);

break;

case Constants::FormState::LOAD:

LoadPageVisibility(false);

break;

case Constants::FormState::RESULT:

ResultPageVisibility(false);

break;

case Constants::FormState::MANUAL:

ManualPageVisibility(false);

break;

}

switch (value)

{

case Constants::FormState::EMPTY:

break;

case Constants::FormState::HOME:

HomePageVisibility(true);

break;

case Constants::FormState::INPUT:

InputPageVisibility(true);

break;

case Constants::FormState::LOAD:

LoadPageVisibility(true);

break;

case Constants::FormState::RESULT:

this->OpenGL->UpdateOrthoSystem();

ResultPageVisibility(true);

break;

case Constants::FormState::MANUAL:

ManualPageVisibility(true);

break;

}

this->prevFormState = this->formState;

this->formState = value;

}

Constants::FormState get()

{

return formState;

}

}

private: System::Void ButtonInputState_Click(System::Object^ sender, System::EventArgs^ e) {

//якщо вхід відбувається з головної панелі, очищаємо поля вводу

if (this->formState == Constants::FormState::HOME)

for each(auto tb in TextBoxArray)

tb->ClearText();

if (this->OpenGL->FlatView)

rbIsFlat_Click(sender, e);

this->lblInputError->Visible = false;

this->FormState = Constants::FormState::INPUT;

}

private: System::Void ButtonLoadState_Click(System::Object^ sender, System::EventArgs^ e) {

this->LoadPageVisibility(true);

}

private: System::Void ButtonManualState_Click(System::Object^ sender, System::EventArgs^ e) {

this->FormState = Constants::FormState::MANUAL;

}

//Повертаємось до страртового виду

private: System::Void ButtonHome_Click(System::Object^ sender, System::EventArgs^ e) {

this->FormState = Constants::FormState::HOME;

}

private: System::Void ButtonClose_Click(System::Object^ sender, System::EventArgs^ e) {

Application::Exit();

}

//повертаємось назад

private: System::Void ButtonResultBack_Click(System::Object^ sender, System::EventArgs^ e) {

this->FormState = this->prevFormState;

}

private: System::Void lblResultBack_Click(System::Object^ sender, System::EventArgs^ e) {

this->ButtonResultBack_Click(sender, e);

}

//при натисканні кнопки Enter при активній компоненті вводу відбувається натиск кнопки обробки результату

void InputDone(System::Object^ sender, System::Windows::Forms::PreviewKeyDownEventArgs^ e)

{

if (e->KeyCode != System::Windows::Forms::Keys::Enter)

return;

this->ButtonCheckSegments_Click(this, gcnew System::EventArgs());

}

//-----------------------------------

//ОБРОБКА ПЕРЕМІЩЕННЯ ФОРМИ

//-----------------------------------

private: System::Void TopPanel_MouseDown(System::Object^ sender, System::Windows::Forms::MouseEventArgs^ e) {

if (e->Button != System::Windows::Forms::MouseButtons::Left)

return;

Dragging = true;

MouseDragStart = e->Location;

}

private: System::Void TopPanel_MouseUp(System::Object^ sender, System::Windows::Forms::MouseEventArgs^ e) {

if (Dragging)

Dragging = false;

}

private: System::Void TopPanel_MouseMove(System::Object^ sender, System::Windows::Forms::MouseEventArgs^ e) {

if (Dragging)

this->Location = Point(this->Location.X + e->Location.X - MouseDragStart.X, this->Location.Y + e->Location.Y - MouseDragStart.Y);

}

private: System::Void Title_MouseDown(System::Object^ sender, System::Windows::Forms::MouseEventArgs^ e) {

if (e->Button != System::Windows::Forms::MouseButtons::Left)

return;

Dragging = true;

MouseDragStart = e->Location;

}

private: System::Void Title_MouseUp(System::Object^ sender, System::Windows::Forms::MouseEventArgs^ e) {

if (Dragging)

Dragging = false;

}

private: System::Void Title_MouseMove(System::Object^ sender, System::Windows::Forms::MouseEventArgs^ e) {

if (Dragging)

this->Location = Point(this->Location.X + e->Location.X - MouseDragStart.X, this->Location.Y + e->Location.Y - MouseDragStart.Y);

}

//-----------------------------------

//ПІДСВІТКА КНОПОК ПРИ НАВЕДЕННІ

//-----------------------------------

private: System::Void ButtonHome_MouseEnter(System::Object^ sender, System::EventArgs^ e) {

this->ButtonHome->BackgroundImage = ImgHomeDark;

}

private: System::Void ButtonHome_MouseLeave(System::Object^ sender, System::EventArgs^ e) {

this->ButtonHome->BackgroundImage = ImgHomeNormal;

}

private: System::Void ButtonClose_MouseEnter(System::Object^ sender, System::EventArgs^ e) {

this->ButtonClose->BackgroundImage = ImgCloseDark;

}

private: System::Void ButtonClose_MouseLeave(System::Object^ sender, System::EventArgs^ e) {

this->ButtonClose->BackgroundImage = ImgCloseNormal;

}

private: System::Void ButtonResultBack_MouseEnter(System::Object^ sender, System::EventArgs^ e) {

this->ButtonResultBack->BackgroundImage = ImgBackDark;

}

private: System::Void ButtonResultBack_MouseLeave(System::Object^ sender, System::EventArgs^ e) {

this->ButtonResultBack->BackgroundImage = ImgBackNormal;

}

private: System::Void SegmentInputTable_PreviewKeyDown(System::Object^ sender, System::Windows::Forms::PreviewKeyDownEventArgs^ e) {

if (e->KeyCode == System::Windows::Forms::Keys::Delete)

{

btnDeleteSegment_Click(sender, e);

}

}

//-----------------------------------

//ВИДІЛЕННЯ РЯДКІВ ТАБЛИЦІ

//-----------------------------------

//запам'ятовування виділених комірок

private: System::Void ResultPointsTable_CellMouseClick(System::Object^ sender, System::Windows::Forms::DataGridViewCellMouseEventArgs^ e) {

if (e->Button != System::Windows::Forms::MouseButtons::Left)

return;

if (ResultPointsTable->SelectedRows->Count <= 1 && ResultPointsTable[e->ColumnIndex, e->RowIndex]->OwningRow->Selected)

ResultPointsTable[e->ColumnIndex, e->RowIndex]->OwningRow->Selected = false;

ResultPointsTable[e->ColumnIndex, e->RowIndex]->OwningRow->Selected =

!ResultPointsTable[e->ColumnIndex, e->RowIndex]->OwningRow->Selected;

PointsTableSelection = ResultPointsTable->SelectedRows;

//якщо рядок вибрали, занести до списку, інакше видалити

GLPoint^ selectedPoint = GLPoint::FromString(ResultPointsTable[0, e->RowIndex]->Value->ToString());

for each(GLPoint^ pt in rectanglePoints)

if (selectedPoint->Equal(pt))

selectedPoint = pt;

if (ResultPointsTable[e->ColumnIndex, e->RowIndex]->OwningRow->Selected)

rectanglePoints->Add(selectedPoint);

else

rectanglePoints->Remove(selectedPoint);

NeedReselectionPoints = true;

}

//оновлення виділених комірок

private: System::Void ResultPointsTable_SelectionChanged(System::Object^ sender, System::EventArgs^ e) {

if (!NeedReselectionPoints)

return;

NeedReselectionPoints = false;

ResultPointsTable->ClearSelection();

for each(DataGridViewRow^ row in PointsTableSelection)

row->Selected = true;

}

//запам'ятовування виділених комірок

private: System::Void SegmentInputTable_CellMouseClick(System::Object^ sender, System::Windows::Forms::DataGridViewCellMouseEventArgs^ e) {

if (e->Button != System::Windows::Forms::MouseButtons::Left)

return;

if (SegmentInputTable->SelectedRows->Count <= 1 && SegmentInputTable[e->ColumnIndex, e->RowIndex]->OwningRow->Selected)

SegmentInputTable[e->ColumnIndex, e->RowIndex]->OwningRow->Selected = false;

SegmentInputTable[e->ColumnIndex, e->RowIndex]->OwningRow->Selected =

!SegmentInputTable[e->ColumnIndex, e->RowIndex]->OwningRow->Selected;

SegmentsTableSelection = SegmentInputTable->SelectedRows;

NeedReselectionSegments = true;

}

//оновлення виділених комірок

private: System::Void SegmentInputTable_SelectionChanged(System::Object^ sender, System::EventArgs^ e) {

if (!NeedReselectionSegments)

return;

NeedReselectionSegments = false;

SegmentInputTable->ClearSelection();

for each(DataGridViewRow^ row in SegmentsTableSelection)

if(row->Index >= 0)

row->Selected = true;

}

};

}

using namespace SegmentsIntersection;

//-------------------------------------------// ІНІЦІАЛІЗАЦІЯ ФОРМИ

//-------------------------------------------

void MainForm::PostInit()

{

this->sProc = gcnew SegmentProcessor();

this->SegmentReader = gcnew FileReader();

this->rectanglePoints = gcnew System::Collections::Generic::List<GLPoint^>();

this->answRect = gcnew GLRectangle();

this->answRect->Color = Constants::Colors::AccentYellow;

this->IsValidInput = new bool[Constants::INPUT_COUNT];

for (int i = 0; i < Constants::INPUT_COUNT; i++)

this->IsValidInput[i] = false;

this->TopPanel->BackColor = Constants::Colors::HighlightingBrown;

this->Title->ForeColor = Constants::Colors::DarkBlue;

this->BackColor = Constants::Colors::BackgroundWhite;

this->ImgCloseNormal = this->ButtonClose->BackgroundImage;

this->ImgCloseDark = this->ButtonClose->InitialImage;

this->ImgHomeNormal = this->ButtonHome->BackgroundImage;

this->ImgHomeDark = this->ButtonHome->InitialImage;

this->ImgBackNormal = this->ButtonResultBack->BackgroundImage;

this->ImgBackDark = this->ButtonResultBack->InitialImage;

this->ImgUnchecked = this->cbIsFlat->BackgroundImage;

this->ImgChecked = this->cbIsFlat->InitialImage;

this->ButtonHome->Visible = false;

this->formState = Constants::FormState::HOME;

this->prevFormState = Constants::FormState::HOME;

HomePageInit();

InputPageInit();

ResultPageInit();

ManualPageInit();

InitializeOpenGL();

HomePageVisibility(true);

}

void MainForm::HomePageInit()

{

this->PanelHome->Visible = false;

this->PanelHome->Location = System::Drawing::Point(0, 40);

//button1

this->ButtonInputState = gcnew FancyButton(this->PanelHome);

this->ButtonInputState->Title = L"Нові дані";

this->ButtonInputState->Image = this->imageList->Images[(int)Constants::ImageIndex::INPUT];

this->ButtonInputState->Location = System::Drawing::Point(50, 50);

this->ButtonInputState->Size = System::Drawing::Size(200, 300);

this->ButtonInputState->IdleColor = Constants::Colors::MainBrown;

this->ButtonInputState->ActiveColor = Constants::Colors::HighlightingBrown;

this->ButtonInputState->IdleTextColor = Constants::Colors::DarkBlue;

this->ButtonInputState->ActiveTextColor = Constants::Colors::AccentRed;

this->ButtonInputState->ClickEvent(gcnew System::EventHandler(this, &MainForm::ButtonInputState_Click));

//button2

this->ButtonLoadState = gcnew FancyButton(this->PanelHome);

this->ButtonLoadState->Title = L"Зчитати з файлу";

this->ButtonLoadState->Image = this->imageList->Images[(int)Constants::ImageIndex::OPEN];

this->ButtonLoadState->Location = System::Drawing::Point(300, 50);

this->ButtonLoadState->Size = System::Drawing::Size(200, 300);

this->ButtonLoadState->IdleColor = Constants::Colors::MainBrown;

this->ButtonLoadState->ActiveColor = Constants::Colors::HighlightingBrown;

this->ButtonLoadState->IdleTextColor = Constants::Colors::DarkBlue;

this->ButtonLoadState->ActiveTextColor = Constants::Colors::AccentRed;

this->ButtonLoadState->ClickEvent(gcnew System::EventHandler(this, &MainForm::ButtonLoadState_Click));

//button3

this->ButtonManualState = gcnew FancyButton(this->PanelHome);

this->ButtonManualState->Title = L"Довідка";

this->ButtonManualState->Image = this->imageList->Images[(int)Constants::ImageIndex::MANUAL];

this->ButtonManualState->Location = System::Drawing::Point(550, 50);

this->ButtonManualState->Size = System::Drawing::Size(200, 300);

this->ButtonManualState->IdleColor = Constants::Colors::MainBrown;

this->ButtonManualState->ActiveColor = Constants::Colors::HighlightingBrown;

this->ButtonManualState->IdleTextColor = Constants::Colors::DarkBlue;

this->ButtonManualState->ActiveTextColor = Constants::Colors::AccentRed;

this->ButtonManualState->ClickEvent(gcnew System::EventHandler(this, &MainForm::ButtonManualState_Click));

}

void MainForm::InputPageInit()

{

this->PanelInput->Location = System::Drawing::Point(0, 40);

this->PanelInput->Visible = false;

this->ButtonCheckSegments = gcnew FancyButton(this->PanelInput);

this->ButtonCheckSegments->Title = L"Перевірити";

this->ButtonCheckSegments->Location = System::Drawing::Point(475, 300);

this->ButtonCheckSegments->Size = System::Drawing::Size(250, 75);

this->ButtonCheckSegments->IdleColor = Constants::Colors::MainBrown;

this->ButtonCheckSegments->ActiveColor = Constants::Colors::HighlightingBrown;

this->ButtonCheckSegments->IdleTextColor = Constants::Colors::DarkBlue;

this->ButtonCheckSegments->ActiveTextColor = Constants::Colors::AccentRed;

this->ButtonCheckSegments->ClickEvent(gcnew System::EventHandler(this, &MainForm::ButtonCheckSegments_Click));

this->lblInputError->Visible = false;

this->lblInputError->ForeColor = Constants::Colors::ErrorRed;

this->lblCheckBox->ForeColor = Constants::Colors::DarkBlue;

this->lblSegment1->ForeColor = Constants::Colors::DarkBlue;

this->lblPoint1->ForeColor = Constants::Colors::DarkBlue;

this->lblPoint2->ForeColor = Constants::Colors::DarkBlue;

this->lblSegment1X->ForeColor = Constants::Colors::DarkBlue;

this->lblSegment1Y->ForeColor = Constants::Colors::DarkBlue;

this->lblSegment1Z->ForeColor = Constants::Colors::DarkBlue;

this->lblSegment2X->ForeColor = Constants::Colors::DarkBlue;

this->lblSegment2Y->ForeColor = Constants::Colors::DarkBlue;

this->lblSegment2Z->ForeColor = Constants::Colors::DarkBlue;

this->TextBoxArray = gcnew cli::array<TextBoxValidator^>(Constants::INPUT_COUNT);

this->TextBoxArray[0] = gcnew TextBoxValidator(this->tbX1Border, this->tbX1BorderBot, this->tbX1);

this->TextBoxArray[1] = gcnew TextBoxValidator(this->tbY1Border, this->tbY1BorderBot, this->tbY1);

this->TextBoxArray[2] = gcnew TextBoxValidator(this->tbZ1Border, this->tbZ1BorderBot, this->tbZ1);

this->TextBoxArray[3] = gcnew TextBoxValidator(this->tbX2Border, this->tbX2BorderBot, this->tbX2);

this->TextBoxArray[4] = gcnew TextBoxValidator(this->tbY2Border, this->tbY2BorderBot, this->tbY2);

this->TextBoxArray[5] = gcnew TextBoxValidator(this->tbZ2Border, this->tbZ2BorderBot, this->tbZ2);

this->btnAddSegment->BackColor = Constants::Colors::HighlightingBrown;

this->btnAddSegment->ForeColor = Constants::Colors::DarkBlue;

this->btnDeleteSegment->BackColor = Constants::Colors::HighlightingBrown;

this->btnDeleteSegment->ForeColor = Constants::Colors::DarkBlue;

this->btnClearSegment->BackColor = Constants::Colors::HighlightingBrown;

this->btnClearSegment->ForeColor = Constants::Colors::DarkBlue;

this->SegmentInputTable->BackgroundColor = Constants::Colors::HighlightingBrown;

this->SegmentInputTable->GridColor = Constants::Colors::DarkBlue;

System::Windows::Forms::DataGridViewCellStyle^ style = this->SegmentInputTable->DefaultCellStyle;

style->BackColor = Constants::Colors::HighlightingBrown;

style->ForeColor = Constants::Colors::DarkBlue;

style->SelectionBackColor = Constants::Colors::AccentBlue;

style->SelectionForeColor = Constants::Colors::HighlightingBrown;

this->SegmentInputTable->DefaultCellStyle = style;

}

void MainForm::ResultPageInit()

{

this->PanelResult->Location = System::Drawing::Point(0, 40);

this->PanelResult->Visible = false;

this->lblResult->ForeColor = Constants::Colors::DarkBlue;

this->lblAnswer->ForeColor = Constants::Colors::DarkBlue;

this->lblAnswer->BackColor = Constants::Colors::HighlightingBrown;

this->lblResultBack->ForeColor = Constants::Colors::DarkBlue;

this->ResultPointsTable->BackgroundColor = Constants::Colors::HighlightingBrown;

this->ResultPointsTable->GridColor = Constants::Colors::DarkBlue;

System::Windows::Forms::DataGridViewCellStyle^ style = this->ResultPointsTable->DefaultCellStyle;

style->BackColor = Constants::Colors::HighlightingBrown;

style->ForeColor = Constants::Colors::DarkBlue;

style->SelectionBackColor = Constants::Colors::AccentBlue;

style->SelectionForeColor = Constants::Colors::HighlightingBrown;

this->ResultPointsTable->DefaultCellStyle = style;

this->btnCreateRectangle->BackColor = Constants::Colors::HighlightingBrown;

this->btnCreateRectangle->ForeColor = Constants::Colors::DarkBlue;

this->lblErrorRectangle->Visible = false;

this->lblErrorRectangle->ForeColor = Constants::Colors::ErrorRed;

}

void MainForm::ManualPageInit()

{

this->wbManual->Visible = false;

this->wbManual->Location = System::Drawing::Point(0, 40);

this->wbManual->Url = gcnew System::Uri(System::String::Format("file:///{0}/Manual.html", System::IO::Directory::GetCurrentDirectory()));

}

void MainForm::InitializeOpenGL()

{

//створюємо компонент

try

{

this->OpenGL = gcnew OpenGLView(this->PanelResult);

}

catch (MyException::GLInitException^)

{

MessageBox::Show("Не вдалося створити компонент OpenGL. Виконання програми буде зупинено.", "Помилка ініціалізації",

System::Windows::Forms::MessageBoxButtons::OK, System::Windows::Forms::MessageBoxIcon::Error);

Application::Exit();

}

this->OpenGL->Location = System::Drawing::Point(410, 10);

this->OpenGL->SetSize(System::Drawing::Size(380, 380));

this->OpenGL->FlatView = false;

this->answPoint = gcnew GLPoint();

this->answPoint->Color = Constants::Colors::ErrorRed;

}

//зміна панелі вводу для випадків на площині та у просторі

System::Void MainForm::rbIsFlat_Click(System::Object^ sender, System::EventArgs^ e) {

this->OpenGL->FlatView = !this->OpenGL->FlatView;

this->lblSegment1Z->Visible = !this->OpenGL->FlatView;

this->TextBoxArray[2]->Visible = !this->OpenGL->FlatView;

this->lblSegment2Z->Visible = !this->OpenGL->FlatView;

this->TextBoxArray[5]->Visible = !this->OpenGL->FlatView;

if (this->OpenGL->FlatView)

this->cbIsFlat->Image = this->ImgChecked;

else

this->cbIsFlat->Image = this->ImgUnchecked;

sProc->PrintSegments(SegmentInputTable);

}

//-------------------------------------------

//ФУНКЦІЇ ОБРОБКИ ПЕРЕХОДІВ

//-------------------------------------------

void MainForm::HomePageVisibility(bool visible)

{

this->PanelHome->Visible = visible;

this->ButtonHome->Visible = !visible;

//зтираємо всі значення при поверненні на головну сторінку

if (visible)

{

this->sProc->Clear();

this->OpenGL->ClearScene();

this->SegmentInputTable->RowCount = 0;

}

}

void MainForm::InputPageVisibility(bool visible)

{

this->PanelHome->Visible = false;

this->PanelInput->Visible = visible;

this->ButtonHome->Visible = visible;

}

void MainForm::ResultPageVisibility(bool visible)

{

this->PanelHome->Visible = false;

this->PanelResult->Visible = visible;

this->ButtonHome->Visible = visible;

if (visible)

{

//виводимо точки на екран

sProc->PrintPoints(ResultPointsTable);

if (OpenGL->Contains(answRect))

OpenGL->RemoveFromScene(answRect);

this->lblErrorRectangle->Text = "Виберіть чотири точки для побудови читирикутника";

this->lblErrorRectangle->Visible = true;

}

else

{

this->lblErrorRectangle->Visible = false;

rectanglePoints->Clear();

}

if (ResultPointsTable->RowCount)

ResultPointsTable->ClearSelection();

}

void MainForm::ManualPageVisibility(bool visible)

{

this->PanelHome->Visible = false;

this->wbManual->Visible = visible;

this->ButtonHome->Visible = visible;

}

//-------------------------------------------

//ФУНКЦІЇ ОБРАХУВАННЯ РЕЗУЛЬТАТІВ

//-------------------------------------------

void MainForm::LoadPageVisibility(bool visible)

{

if (!visible)

return;

HomePageVisibility(false);

InputPageVisibility(false);

ResultPageVisibility(false);

ManualPageVisibility(false);

sProc->Clear();

OpenGL->ClearScene();

this->SegmentInputTable->RowCount = 0;

System::String^ errorLines = gcnew System::String("");

int i = 0;

try

{

if (!this->SegmentReader->ShowDialog())

{

HomePageVisibility(true);

this->prevFormState = Constants::FormState::HOME;

this->formState = Constants::FormState::HOME;

return;

}

//перевірка розмірності файлу

if (this->SegmentReader->Lines() > Constants::MAX_FILE_LINES)

{

auto dResult = MessageBox::Show("У файлі забагато записів. Обробка потребуватиме багато часу. Продовжити", "Помилка зчитування",

System::Windows::Forms::MessageBoxButtons::YesNoCancel, System::Windows::Forms::MessageBoxIcon::Warning);

switch (dResult)

{

case System::Windows::Forms::DialogResult::Yes:

break;

default:

HomePageVisibility(true);

this->prevFormState = Constants::FormState::HOME;

this->formState = Constants::FormState::HOME;

return;

}

}

//виконуємо цикл, поки не закінчиться потік даних

while(true)

{

GLSegment^ segment = gcnew GLSegment(gcnew GLPoint(), gcnew GLPoint());

try

{

i++;

this->SegmentReader->ReadSegment(segment);

}

catch (MyException::CoruptedLineException^) //пропускаємо пошкоджені рядки

{

errorLines += i + " ";

continue;

}

catch (MyException::ValueOverflowException^ e)

{

errorLines += i + " ";

continue;

}

//перевіряємо, чи не є введений відрізок точкою

if (segment->Point[0]->X != segment->Point[1]->X ||

segment->Point[0]->Y != segment->Point[1]->Y ||

segment->Point[0]->Z != segment->Point[1]->Z)

{

sProc->AddSegment(segment);

OpenGL->AddToScene(segment);

OpenGL->AddToScene(segment->Point[0]);

OpenGL->AddToScene(segment->Point[1]);

}

else

{

errorLines += i + " ";

continue;

}

}

}

catch (System::IO::EndOfStreamException^)

{

//вихід з циклу відбувається при обробці винятку

}

finally

{

this->SegmentReader->CloseFile();

}

GLSegment::CrossAnswer ^answer;

try

{

//після зчитування відразу переходимо до результатів

this->OpenGL->FlatView = this->SegmentReader->IsFlat();

answer = sProc->CrossAll();

}

catch (MyException::NotEnoughObjectsException^)

{

MessageBox::Show("Не достатня кількість записів. Або частина записів не коректна.", "Помилка зчитування",

System::Windows::Forms::MessageBoxButtons::OK, System::Windows::Forms::MessageBoxIcon::Warning);

HomePageVisibility(true);

OpenGL->ClearScene();

this->prevFormState = Constants::FormState::HOME;

this->formState = Constants::FormState::HOME;

return;

}

//якщо з'являється додаткова дочка відображуємо її на сцені

if (OpenGL->Contains(answPoint))

OpenGL->RemoveFromScene(answPoint);

if (answer->Type == GLSegment::CrossAnswer::CrossType::POINT)

{

answPoint = answer->Point1;

answPoint->Color = Constants::Colors::AccentRed;

OpenGL->AddToScene(answPoint);

}

this->CrossAnswer = answer->Answer;

this->lblAnswer->Text = CrossAnswer;

this->OpenGL->UpdateOrthoSystem();

this->formState = Constants::FormState::LOAD;

this->FormState = Constants::FormState::RESULT;

if(errorLines != "")

MessageBox::Show("Знайдено пошкоджені рядки: " + errorLines + ". Їх зчитування не відбулося.", "Помилка зчитування",

System::Windows::Forms::MessageBoxButtons::OK, System::Windows::Forms::MessageBoxIcon::Warning);

}

//додаємо відрізок до списку

System::Void MainForm::btnAddSegment_Click(System::Object^ sender, System::EventArgs^ e) {

//перевыряємо корекність даних

for (int i = 0; i < Constants::INPUT_COUNT; i++)

if (!TextBoxArray[i]->IsValid())

{

//якщо вибраний вид на площині, не враховувати координату Z

if (OpenGL->FlatView && i % 3 == 2)

continue;

this->lblInputError->Text = "Не всі поля заповнені, або містять не коректні дані!";

this->lblInputError->Visible = true;

return;

}

GLSegment^ segment = gcnew GLSegment(gcnew GLPoint(), gcnew GLPoint());

segment->Point[0]->X = TextBoxArray[0]->Value();

segment->Point[0]->Y = TextBoxArray[1]->Value();

segment->Point[0]->Z = TextBoxArray[2]->Value();

segment->Point[1]->X = TextBoxArray[3]->Value();

segment->Point[1]->Y = TextBoxArray[4]->Value();

segment->Point[1]->Z = TextBoxArray[5]->Value();

//якщо відрізок є однією точкою

if (segment->Point[0]->X == segment->Point[1]->X &&

segment->Point[0]->Y == segment->Point[1]->Y &&

(OpenGL->FlatView || segment->Point[0]->Z == segment->Point[1]->Z))

{

this->lblInputError->Text = "Tочки початку та кінця відрізку не можуть збігатися!";

this->lblInputError->Visible = true;

return;

}

this->lblInputError->Visible = false;

for (int i = 0; i < Constants::INPUT_COUNT; i++)

TextBoxArray[i]->ClearText();

segment->Color = Constants::Colors::AccentBlue;

segment->Point[0]->Color = Constants::Colors::MainBrown;

segment->Point[1]->Color = Constants::Colors::MainBrown;

//додаємо запис до всіх необхідних контейнерів

OpenGL->AddToScene(segment);

OpenGL->AddToScene(segment->Point[0]);

OpenGL->AddToScene(segment->Point[1]);

sProc->AddSegment(segment);

cli::array<System::String^>^ row = gcnew cli::array<System::String^>(1); row[0] = segment->ToString();

SegmentInputTable->Rows->Add(row);

SegmentInputTable->ClearSelection();

}

System::Void MainForm::btnDeleteSegment_Click(System::Object^ sender, System::EventArgs^ e) {

for each (System::Windows::Forms::DataGridViewRow^ row in SegmentInputTable->SelectedRows)

{

int idx = SegmentInputTable->Rows->IndexOf(row);

GLSegment^ segment = sProc->GetSegment(idx);

OpenGL->RemoveFromScene(segment->Point[0]);

OpenGL->RemoveFromScene(segment->Point[1]);

OpenGL->RemoveFromScene(segment);

sProc->RemoveSegmentAt(idx);

SegmentInputTable->Rows->RemoveAt(idx);

}

SegmentInputTable->ClearSelection();

}

System::Void MainForm::btnClearSegment_Click(System::Object^ sender, System::EventArgs^ e) {

this->sProc->Clear();

this->OpenGL->ClearScene();

this->SegmentInputTable->RowCount = 0;

}

//кнопка обробки результату

System::Void MainForm::ButtonCheckSegments_Click(System::Object^ sender, System::EventArgs^ e) {

if (Constants::SEGMENT_COUNT < 2)

{

this->lblInputError->Text = "Для подальшої роботи необхідно додати не менше двох відрізків!";

this->lblInputError->Visible = true;

return;

}

//отримуємо відповідь

GLSegment::CrossAnswer ^answer = sProc->CrossAll();

//якщо з'являється додаткова точка відображуємо її на сцені

if (OpenGL->Contains(answPoint))

OpenGL->RemoveFromScene(answPoint);

if (answer->Type == GLSegment::CrossAnswer::CrossType::POINT)

{

answPoint = answer->Point1;

answPoint->Color = Constants::Colors::ErrorRed;

OpenGL->AddToScene(answPoint);

}

this->CrossAnswer = answer->Answer;

this->lblAnswer->Text = CrossAnswer;

OpenGL->UpdateOrthoSystem();

this->FormState = Constants::FormState::RESULT;

this->lblInputError->Visible = false;

}

//створюємо чотирикутник з вибраних точок

System::Void MainForm::btnCreateRectangle_Click(System::Object^ sender, System::EventArgs^ e) {

if (rectanglePoints->Count != 4)

{

//додаткова перевірка таблиці

if (ResultPointsTable->SelectedRows->Count == 4)

{

rectanglePoints->Clear();

for each(DataGridViewRow^ row in ResultPointsTable->SelectedRows)

{

GLPoint^ selectedPoint = GLPoint::FromString(ResultPointsTable[0, row->Index]->Value->ToString());

rectanglePoints->Add(selectedPoint);

}

}

else

{

lblErrorRectangle->Text = "Для побудови необхідно вибрати 4 точки.";

lblErrorRectangle->Visible = true;

return;

}

}

try {

answRect->Set(rectanglePoints->ToArray());

}

catch (MyException::InvalidRectangleException^)

{

lblErrorRectangle->Text = "Вибрані точки не можуть збігатися.";

lblErrorRectangle->Visible = true;

return;

}

lblErrorRectangle->Visible = false;

if (answRect->IsOnPlane() && !Double::IsNaN(answRect->Square()) && answRect->Square() > 0)

{

if (Constants::ENABLE_ANSWER_ROUNDING)

lblAnswer->Text = CrossAnswer +

String::Format("\nПериметр: {0} см\nПлоща: {1} см^2", Math::Round(answRect->Perimeter(), Constants::ANSWER_PRESITION), Math::Round(answRect->Square(), Constants::ANSWER_PRESITION));

else

lblAnswer->Text = CrossAnswer +

String::Format("\nПериметр: {0} см\nПлоща: {1} см^2", answRect->Perimeter(), answRect->Square());

if (!OpenGL->Contains(answRect))

OpenGL->AddToScene(answRect);

}

else if(Double::IsNaN(answRect->Square()) || answRect->Square() <= 0)

{

lblAnswer->Text = CrossAnswer + "\nВибрані точки лежать на одній прямій. Не можна побудувати чотирикутник";

if (OpenGL->Contains(answRect))

OpenGL->RemoveFromScene(answRect);

}

else

{

lblAnswer->Text = CrossAnswer + "\nВибрані точки не лежать у одній площині. Не можна побудувати чотирикутник";

if (OpenGL->Contains(answRect))

OpenGL->RemoveFromScene(answRect);

}

}


4.2. Клас відрізка

Клас відрізка зберігає інформацію про відрізок, дозволяє його опрацьовувати та виконувати пошук перетину між двома відрізками.


#pragma once

#include <GL\glut.h>

#include "IDrawable.h"

#include "GLPoint.h"

#include "Constants.h"

using namespace System;

ref class GLSegment : IDrawable

{

//структура, що повертає інформацію про перетин відрізків

public: ref struct CrossAnswer {

CrossAnswer(bool isFlat)

{

Type = CrossType::NONE;

Point1 = gcnew GLPoint();

Point2 = gcnew GLPoint();

Point1->IsInAnswer = true;

Point2->IsInAnswer = true;

Point1->Flat = isFlat;

Point2->Flat = isFlat;

}

enum class CrossType { NONE, POINT, SEGMENT } Type;

GLPoint^ Point1;

GLPoint^ Point2;

property System::String^ Answer

{

System::String^ get()

{

System::String^ answer = gcnew System::String("");

switch (Type)

{

case CrossType::NONE:

answer = "Відрізки не перетинаються.";

break;

case CrossType::POINT:

answer = "Відрізки перетинаються у точці " + Constants::AnswerPoint + ".";

break;

case CrossType::SEGMENT:

answer = "Відрізки перетинаються на проміжку [" + Point1->ToString() + ", " + Point2->ToString() + "].";

break;

}

return answer;

}

}

};

public:

GLSegment(GLPoint^ point1, GLPoint^ point2);

~GLSegment() {}

//функція малювання відрізка

virtual void Draw() override;

//чи перетинаються відрізки

CrossAnswer^ Cross(GLSegment^ segment2);

//довжина відрізка

double Magnitude();

//відстань між двома точками

static double Magnitude(GLPoint^ p1, GLPoint^ p2);

//створює проекцію відрізка на вісь координат

GLSegment^ ProjectionTo(Constants::Projection proj);

//перевіряє, чи містить відрізок точку

bool Contains(GLPoint^ point);

property cli::array<GLPoint^>^ Point

{

void set(cli::array<GLPoint^>^ value)

{

this->_point1 = value[0];

this->_point2 = value[1];

}

cli::array<GLPoint^>^ get()

{

cli::array<GLPoint^>^ tmp = gcnew cli::array<GLPoint^>(2);

tmp[0] = this->_point1;

tmp[1] = this->_point2;

return tmp;

}

}

System::String^ ToString() override;

private:

GLPoint^ _point1;

GLPoint^ _point2;

//перевіряє чи перетинаються проекції відрізків

CrossAnswer^ cross2d(GLSegment^ s2, Constants::Projection proj);

//перевіряє чи перетинаються відрізки у просторі

CrossAnswer^ cross3d(GLSegment^ segment2);

};

#include "GLSegment.h"

GLSegment::GLSegment(GLPoint^ point1, GLPoint^ point2)

{

_point1 = point1;

_point2 = point2;

}

void GLSegment::Draw()

{

glBegin(GL_LINES);

glColor3f(_r, _g, _b);

if (Flat)

{

glVertex2f(_point1->X, _point1->Y);

glVertex2f(_point2->X, _point2->Y);

}

else

{

glVertex3f(_point1->X, _point1->Y, _point1->Z);

glVertex3f(_point2->X, _point2->Y, _point2->Z);

}

glEnd();

}

GLSegment::CrossAnswer^ GLSegment::Cross(GLSegment^ segment2)

{

if (Flat)

return cross2d(segment2, Constants::Projection::XY);

else

return cross3d(segment2);

}

double GLSegment::Magnitude()

{

return Magnitude(this->_point1, this->_point2);

}

double GLSegment::Magnitude(GLPoint^ p1, GLPoint^ p2)

{

return Math::Sqrt(

(double)System::Decimal::Add(

System::Decimal::Add(

System::Decimal::Multiply(

System::Decimal::Subtract(

(System::Decimal)p2->X,

(System::Decimal)p1->X

),

System::Decimal::Subtract(

(System::Decimal)p2->X,

(System::Decimal)p1->X

)

),

System::Decimal::Multiply(

System::Decimal::Subtract(

(System::Decimal)p2->Y,

(System::Decimal)p1->Y

),

System::Decimal::Subtract(

(System::Decimal)p2->Y,

(System::Decimal)p1->Y

)

)

),

System::Decimal::Multiply(

System::Decimal::Subtract(

(System::Decimal)p2->Z,

(System::Decimal)p1->Z

),

System::Decimal::Subtract(

(System::Decimal)p2->Z,

(System::Decimal)p1->Z

)

)

)

);

}

GLSegment^ GLSegment::ProjectionTo(Constants::Projection proj)

{

GLSegment^ val = gcnew GLSegment(gcnew GLPoint(this->_point1->X, this->_point1->Y, this->_point1->Z), gcnew GLPoint(this->_point2->X, this->_point2->Y, this->_point2->Z));

switch (proj)

{

case Constants::Projection::XY:

val->_point1->Z = 0;

val->_point2->Z = 0;

break;

case Constants::Projection::XZ:

val->_point1->Y = 0;

val->_point2->Y = 0;

break;

case Constants::Projection::YZ:

val->_point1->X = 0;

val->_point2->X = 0;

break;

}

return val;

}

bool GLSegment::Contains(GLPoint^ point)

{

if (Math::Abs(Magnitude(_point1, point) + Magnitude(point, _point2) - Magnitude()) < Constants::DELTA)

return true;

else

return false;

}

System::String^ GLSegment::ToString()

{

return System::String::Format("[{0}, {1}]", this->_point1->ToString(), this->_point2->ToString());

}

GLSegment::CrossAnswer^ GLSegment::cross2d(GLSegment^ s2, Constants::Projection proj)

{

//перехід до координат проекції

double U1, U2, V1, V2;//перший відрізок

double U3, U4, V3, V4;//другий відрізок

double UN1, VN1, UN2, VN2;//точки перетину

switch (proj)

{

case Constants::Projection::XY:

U1 = this->_point1->X;

U2 = this->_point2->X;

V1 = this->_point1->Y;

V2 = this->_point2->Y;

U3 = s2->_point1->X;

U4 = s2->_point2->X;

V3 = s2->_point1->Y;

V4 = s2->_point2->Y;

break;

case Constants::Projection::XZ:

U1 = this->_point1->X;

U2 = this->_point2->X;

V1 = this->_point1->Z;

V2 = this->_point2->Z;

U3 = s2->_point1->X;

U4 = s2->_point2->X;

V3 = s2->_point1->Z;

V4 = s2->_point2->Z;

break;

case Constants::Projection::YZ:

U1 = this->_point1->Y;

U2 = this->_point2->Y;

V1 = this->_point1->Z;

V2 = this->_point2->Z;

U3 = s2->_point1->Y;

U4 = s2->_point2->Y;

V3 = s2->_point1->Z;

V4 = s2->_point2->Z;

break;

}

CrossAnswer^ value = gcnew CrossAnswer(this->Flat);

//матриці рівняння прямих

double A[2][2], B[2];

A[0][0] = V2 - V1; A[0][1] = U1 - U2;

A[1][0] = V4 - V3; A[1][1] = U3 - U4;

B[1] = U3 * V4 - V3 * U4;

B[0] = U1 * V2 - V1 * U2;

//визначники матриць

double d = A[0][0] * A[1][1] - A[1][0] * A[0][1];

double d1 = B[0] * A[1][1] - B[1] * A[0][1];

double d2 = A[0][0] * B[1] - A[1][0] * B[0];

//чи паралельні прямі

if (Math::Abs(d) < Constants::DELTA)

{

//чи співпадають прямі

if (Math::Abs(d1) < Constants::DELTA && Math::Abs(d2) < Constants::DELTA)

{

value->Type = CrossAnswer::CrossType::SEGMENT;

//визначаємо відносні позиції кінців відрізків

double s1MaxX = Math::Max(U1, U2);

double s1MinX = Math::Min(U1, U2);

double s1MaxY = Math::Max(V1, V2);

double s1MinY = Math::Min(V1, V2);

double s2MaxX = Math::Max(U3, U4);

double s2MinX = Math::Min(U3, U4);

double s2MaxY = Math::Max(V3, V4);

double s2MinY = Math::Min(V3, V4);

if ((s1MinX > s2MaxX || s2MinX > s1MaxX) && (s1MinY > s2MaxY || s2MinY > s1MaxY))

{

//відрізки не перетинаються

value->Type = CrossAnswer::CrossType::NONE;

return value;

}

else

{

//проміжок перетину відрізків

UN1 = Math::Max(s1MinX, s2MinX);

VN1 = Math::Max(s1MinY, s2MinY);

UN2 = Math::Min(s1MaxX, s2MaxX);

VN2 = Math::Min(s1MaxY, s2MaxY);

if (Math::Abs(UN1 - UN2) < Constants::DELTA && Math::Abs(VN1 - VN2) < Constants::DELTA)

value->Type = CrossAnswer::CrossType::POINT;

}

}

else

value->Type = CrossAnswer::CrossType::NONE;

}

else

{

//точка перетину

value->Type = CrossAnswer::CrossType::POINT;

UN1 = d1 / d;

VN1 = d2 / d;

}

//переходимо від проекції назад до реальних координат

switch (proj)

{

case Constants::Projection::XY:

value->Point1->X = UN1;

value->Point1->Y = VN1;

value->Point2->X = UN2;

value->Point2->Y = VN2;

break;

case Constants::Projection::XZ:

value->Point1->X = UN1;

value->Point1->Z = VN1;

value->Point2->X = UN2;

value->Point2->Z = VN2;

break;

case Constants::Projection::YZ:

value->Point1->Y = UN1;

value->Point1->Z = VN1;

value->Point2->Y = UN2;

value->Point2->Z = VN2;

break;

default:

break;

}

if (value->Type == CrossAnswer::CrossType::POINT)

//чи знаходиться точка на відрізках

if (!this->ProjectionTo(proj)->Contains(value->Point1->ProjectionTo(proj)) ||

!s2->ProjectionTo(proj)->Contains(value->Point1->ProjectionTo(proj)))

value->Type = CrossAnswer::CrossType::NONE;

return value;

}

GLSegment::CrossAnswer^ GLSegment::cross3d(GLSegment^ segment2)

{

CrossAnswer^ value = gcnew CrossAnswer(this->Flat);

//Аналізуємо 3 проекції

array<CrossAnswer^>^ crossProj = gcnew array<CrossAnswer^>(3);

crossProj[0] = cross2d(segment2, Constants::Projection::XY);

crossProj[1] = cross2d(segment2, Constants::Projection::XZ);

crossProj[2] = cross2d(segment2, Constants::Projection::YZ);

//чи накладаються відрізки один на одного

if (crossProj[0]->Type == CrossAnswer::CrossType::SEGMENT &&

crossProj[1]->Type == CrossAnswer::CrossType::SEGMENT &&

crossProj[2]->Type == CrossAnswer::CrossType::SEGMENT)

{

value->Type = CrossAnswer::CrossType::SEGMENT;

value->Point1 = crossProj[0]->Point1;

value->Point2 = crossProj[0]->Point2;

value->Point1->Z = crossProj[1]->Point1->Z;

value->Point2->Z = crossProj[1]->Point2->Z;

}

//чи перетинаються відрізки у точці

else if ((crossProj[0]->Type == CrossAnswer::CrossType::SEGMENT || crossProj[0]->Type == CrossAnswer::CrossType::POINT) &&

(crossProj[1]->Type == CrossAnswer::CrossType::SEGMENT || crossProj[1]->Type == CrossAnswer::CrossType::POINT) &&

(crossProj[2]->Type == CrossAnswer::CrossType::SEGMENT || crossProj[2]->Type == CrossAnswer::CrossType::POINT))

{

//шукаємо, які з проекцій є точками

bool isPoint[3];

int pointCount = 0;

for (int i = 0; i < 3; i++)

if (crossProj[i]->Type == CrossAnswer::CrossType::POINT)

{

isPoint[i] = true;

pointCount++;

}

else

isPoint[i] = false;

value->Type = CrossAnswer::CrossType::POINT;

if (pointCount == 1)

{

//якщо точка одна, третю координату вибираємо з іншої відповіді

if (isPoint[0])

{

value->Point1 = crossProj[0]->Point1;

value->Point2 = crossProj[0]->Point2;

value->Point1->Z = crossProj[1]->Point1->Z;

value->Point2->Z = crossProj[1]->Point2->Z;

}

else if (isPoint[1])

{

value->Point1 = crossProj[1]->Point1;

value->Point2 = crossProj[1]->Point2;

value->Point1->Y = crossProj[0]->Point1->Y;

value->Point2->Y = crossProj[0]->Point2->Y;

}

else if (isPoint[2])

{

value->Point1 = crossProj[2]->Point1;

value->Point2 = crossProj[2]->Point2;

value->Point1->X = crossProj[0]->Point1->X;

value->Point2->X = crossProj[0]->Point2->X;

}

}

else

{

//шукаємо 2 проекції, на яких видно точку перетину

//якщо на першій проекції видно точку, шкуаємо наступну

if (isPoint[0])

{

value->Point1 = crossProj[0]->Point1;

value->Point2 = crossProj[0]->Point2;

for (int i = 1; i <= 2; i++)

if (isPoint[i])

{

value->Point1->Z = crossProj[i]->Point1->Z;

value->Point2->Z = crossProj[i]->Point2->Z;

}


4.3. Клас чотирикутника

Цей клас зберігає та обробляє дані чотирикутника.


#pragma once

#include "IDrawable.h"

#include "GLPoint.h"

#include "GLSegment.h"

#include "Exceptions.h"

ref class GLRectangle : IDrawable

{

public:

GLRectangle();

~GLRectangle() {};

//створення нового чотирикутника

void Set(GLPoint^ pt1, GLPoint^ pt2, GLPoint^ pt3, GLPoint^ pt4);

void Set(array<GLPoint^>^ pts);

//функція малювання

virtual void Draw() override;

double Square();

double Perimeter();

bool IsOnPlane();

private:

//чи розташовані всі вершини у одній площині

bool _isOnPlane;

double _square;

double _perimeter;

void countIsONPlane();

void countSquare();

void countPerimeter();

static double countPolygonSquare(GLPoint^ p1, GLPoint^p2, GLPoint^ p3);

array<GLPoint^>^ _points;

array<GLSegment^>^ _sides;

};

#include "GLRectangle.h"

GLRectangle::GLRectangle() {}

void GLRectangle::Set(GLPoint^ pt1, GLPoint^ pt2, GLPoint^ pt3, GLPoint^ pt4)

{

array<GLPoint^>^ points = gcnew array<GLPoint^>(4);

points[0] = pt1;

points[1] = pt2;

points[2] = pt3;

points[3] = pt4;

this->Set(points);

}

void GLRectangle::Set(array<GLPoint^>^ pts)

{

if (pts->Length != 4)

return;

this->_square = 0;

this->_points = pts;

for (int i = 3; i > 0; i--)

for (int j = 0; j < i; j++)

if (_points[i]->Equal(_points[j]))

throw gcnew MyException::InvalidRectangleException(this);

this->Flat = _points[0]->Flat;

this->_sides = gcnew array<GLSegment^>(4);

for (int i = 0; i < 4; i++)

{

_sides[i] = gcnew GLSegment(_points[i % 4], _points[(i + 1) % 4]);

_sides[i]->Flat = _points[0]->Flat;

//перевіряємо, що фігура має 4 кути

GLSegment^ checkerNear = gcnew GLSegment(_points[i % 4], _points[(i + 1) % 4]);

GLSegment^ checkerFar = gcnew GLSegment(_points[i % 4], _points[(i + 2) % 4]);

if (checkerFar->Contains(_points[(i + 1) % 4]) || checkerNear->Contains(_points[(i + 2) % 4]) || checkerNear->Contains(_points[(i + 3) % 4]))

{

this->_isOnPlane = true;

this->_square = -1;

}

}

countPerimeter();

if (_square == 0)

{

countIsONPlane();

if (this->_isOnPlane)

countSquare();

else

this->_square = -1;

}

}

void GLRectangle::Draw()

{

glBegin(GL_LINE_LOOP);

glColor3f(_r, _g, _b);

if (Flat)

{

for(int i = 0; i < 4; i++)

glVertex2f(_points[i]->X, _points[i]->Y);

}

else

{

for (int i = 0; i < 4; i++)

glVertex3f(_points[i]->X, _points[i]->Y, _points[i]->Z);

}

glEnd();

}

double GLRectangle::Square()

{

return this->_square;

}

double GLRectangle::Perimeter()

{

return this->_perimeter;

}

bool GLRectangle::IsOnPlane()

{

return this->_isOnPlane;

}

void GLRectangle::countIsONPlane()

{

//визначник матриці площини чотирикутника

double surfaceDet =

_points[0]->X * (_points[3]->Z * (_points[1]->Y - _points[2]->Y)

- _points[1]->Y * _points[2]->Z + _points[1]->Z * (_points[2]->Y - _points[3]->Y)

+ _points[3]->Y * _points[2]->Z) +

_points[1]->X * (_points[3]->Z * (_points[2]->Y - _points[0]->Y)

+ _points[0]->Y * _points[2]->Z - _points[2]->Y * _points[0]->Z + _points[3]->Y

* (_points[0]->Z - _points[2]->Z)) +

_points[2]->X * (_points[3]->Z * (_points[0]->Y - _points[1]->Y) - _points[0]->Y

* _points[1]->Z + _points[1]->Y * _points[0]->Z - _points[3]->Y * _points[0]->Z

+ _points[3]->Y * _points[1]->Z) +

_points[3]->X * _points[0]->Y * (_points[1]->Z - _points[2]->Z) + _points[3]->X

* (_points[1]->Y * (_points[2]->Z - _points[0]->Z) + _points[2]->Y * _points[0]->Z

- _points[2]->Y * _points[1]->Z);

//якщо визначник нуль, то всі чотири точки у одній площині

if (Math::Abs(surfaceDet) < Constants::DELTA)

this->_isOnPlane = true;

else

this->_isOnPlane = false;

}

void GLRectangle::countSquare()

{

//якщо чотирикутник самоперетинаючий

GLSegment::CrossAnswer^ cross1 = _sides[0]->Cross(_sides[2]);

GLSegment::CrossAnswer^ cross2 = _sides[1]->Cross(_sides[3]);

if (cross1->Type == GLSegment::CrossAnswer::CrossType::POINT)

{

double p1 = countPolygonSquare(_points[0], cross1->Point1, _points[3]);

double p2 = countPolygonSquare(_points[1], cross1->Point1, _points[2]);

if (Math::Abs(p1) < Constants::DELTA || Math::Abs(p2) < Constants::DELTA)

{

this->_square = 0.;

return;

}

this->_square = p1 + p2;

return;

}

else if (cross2->Type == GLSegment::CrossAnswer::CrossType::POINT)

{

double p1 = countPolygonSquare(_points[0], cross2->Point1, _points[1]);

double p2 = countPolygonSquare(_points[2], cross2->Point1, _points[3]);

if (Math::Abs(p1) < Constants::DELTA || Math::Abs(p2) < Constants::DELTA)

{

this->_square = 0.;

return;

}

this->_square = p1 + p2;

return;

}

else

{

this->_square =

countPolygonSquare(_points[0], _points[1], _points[2]) +

countPolygonSquare(_points[0], _points[3], _points[2]);

return;

}

}

void GLRectangle::countPerimeter()

{

double perim = 0;

for (int i = 0; i < 4; i++)

perim += _sides[i]->Magnitude();

this->_perimeter = perim;

}

double GLRectangle::countPolygonSquare(GLPoint^ p1, GLPoint^p2, GLPoint^ p3)

{

//сторони

double a = GLSegment::Magnitude(p1, p2);

double b = GLSegment::Magnitude(p2, p3);

double c = GLSegment::Magnitude(p3, p1);

//півпериметр

double p = (a + b + c) / 2;

return Math::Sqrt(p * (p - a) * (p - b) * (p - c));

}


4.4. Клас обробника відрізків

Клас надає засоби інкапсуляції відрізків та високорівневої роботи з ними.


#pragma once

#include "GLSegment.h"

#include "Exceptions.h"

ref class SegmentProcessor

{

public:

SegmentProcessor();

~SegmentProcessor() {};

//робота зі списком відрізків

void AddSegment(GLSegment^ obj);

void RemoveSegment(GLSegment^ obj);

void RemoveSegmentAt(int idx);

//затирає всі дані, не знищуючи об'єкт

void Clear();

//знайти точку перетину між усіма відрізками

GLSegment::CrossAnswer^ CrossAll();

GLSegment^ GetSegment(int idx);

//друкує список відрізків у таблицю

void PrintSegments(System::Windows::Forms::DataGridView^ table);

//друкує список точок у таблицю

void PrintPoints(System::Windows::Forms::DataGridView^ table);

private:

System::Collections::Generic::List<GLSegment^>^ _segment;

};

SegmentProcessor::SegmentProcessor()

{

_segment = gcnew System::Collections::Generic::List<GLSegment^>();

}

void SegmentProcessor::AddSegment(GLSegment^ obj)

{

_segment->Add(obj);

Constants::SEGMENT_COUNT++;

}

void SegmentProcessor::RemoveSegment(GLSegment^ obj)

{

if (_segment->Remove(obj))

Constants::SEGMENT_COUNT--;

}

void SegmentProcessor::RemoveSegmentAt(int idx)

{

if (idx < 0 || idx >= _segment->Count)

return;

_segment->RemoveAt(idx);

Constants::SEGMENT_COUNT--;

}

void SegmentProcessor::Clear()

{

_segment->Clear();

Constants::SEGMENT_COUNT = 0;

}

GLSegment::CrossAnswer^ SegmentProcessor::CrossAll()

{

if (_segment->Count < 2)

throw gcnew MyException::NotEnoughObjectsException(this);

//послідовно шукаємо перетин між кожним відрізком та результатом попереднього перетину

GLSegment::CrossAnswer^ answer = _segment[0]->Cross(_segment[1]);

for(int i = 1; i < _segment->Count; i++)

{

if (answer->Type == GLSegment::CrossAnswer::CrossType::NONE)

return answer;

else if (answer->Type == GLSegment::CrossAnswer::CrossType::POINT)

{

if (!_segment[i]->Contains(answer->Point1))

{

answer->Type = GLSegment::CrossAnswer::CrossType::NONE;

return answer;

}

}

else if (answer->Type == GLSegment::CrossAnswer::CrossType::SEGMENT)

answer = _segment[i]->Cross(gcnew GLSegment(answer->Point1, answer->Point2));

}

return answer;

}

GLSegment^ SegmentProcessor::GetSegment(int idx)

{

if (idx < 0 || idx >= _segment->Count)

throw gcnew System::IndexOutOfRangeException();

return _segment[idx];

}

void SegmentProcessor::PrintSegments(System::Windows::Forms::DataGridView^ table)

{

table->RowCount = _segment->Count;

if (_segment->Count == 0)

return;

for (int i = 0; i < _segment->Count; i++)

table->Rows[i]->Cells[0]->Value = _segment[i]->ToString();

}

void SegmentProcessor::PrintPoints(System::Windows::Forms::DataGridView^ table)

{

table->RowCount = 0;

if (_segment->Count == 0)

return;

bool stopAdding;

for (int i = 0, idx = 0; i < _segment->Count * 2; i++)

{

stopAdding = false;

GLPoint^ pt = _segment[i/2]->Point[i % 2];

for (int j = 0; j < i; j++)

if (pt->Equal(_segment[j / 2]->Point[j % 2]))

{

stopAdding = true;

break;

}

if (stopAdding)

continue;

table->Rows->Add();

table->Rows[table->RowCount - 1]->Cells[0]->Value = Constants::GetLetterIdx(idx++) + pt->ToString();

}

}


4.5. Класи винятків

Забезпечують виявлення не стандартних виняткових ситуацій.


#pragma once

namespace MyException

{

ref class BaseException abstract

{

public:

BaseException(Object^ sender)

{

this->Sender = sender;

}

property System::String^ Message

{

virtual System::String^ get() = 0;

}

Object^ Sender;

};

ref class GLInitException : public BaseException

{

public:

GLInitException(Object^ sender) : BaseException(sender) {};

property System::String^ Message

{

virtual System::String^ get() override

{

return gcnew System::String("Не вдалося отримати обробник компонента!");

}

}

};

ref class BusyObjectException : public BaseException

{

public:

BusyObjectException(Object^ sender) : BaseException(sender){};

property System::String^ Message

{

virtual System::String^ get() override

{

return gcnew System::String("Об'єкт не може виконати цю операцію зараз!");

}

}

};

ref class EmptyStreamException : public BaseException

{

public:

EmptyStreamException(Object^ sender) : BaseException(sender) {};

property System::String^ Message

{

virtual System::String^ get() override

{

return gcnew System::String("Потік досяг кінця файла!");

}

}

};

ref class CoruptedLineException : public BaseException

{

public:

CoruptedLineException(Object^ sender) : BaseException(sender) {};

property System::String^ Message

{

virtual System::String^ get() override

{

return gcnew System::String("Рядок пошкоджено!");

}

}

};

ref class ValueOverflowException : public BaseException

{

public:

ValueOverflowException(Object^ sender) : BaseException(sender) { Value = 0; };

ValueOverflowException(Object^ sender, double value) : BaseException(sender) { Value = value; };

property System::String^ Message

{

virtual System::String^ get() override

{

return gcnew System::String("Значення виходить за межі типу!");

}

}

double Value;

};

ref class NotEnoughObjectsException : public BaseException

{

public:

NotEnoughObjectsException(Object^ sender) : BaseException(sender) {};

property System::String^ Message

{

virtual System::String^ get() override

{

return gcnew System::String("У контейнері недостаньо змінних для проведення операції!");

}

}

};

ref class InvalidRectangleException : public BaseException

{

public:

InvalidRectangleException(Object^ sender) : BaseException(sender) {};

property System::String^ Message

{

virtual System::String^ get() override

{

return gcnew System::String("Точки чотирикутника знаходяться на одній прямій!");

}

}

};



5. ПРОТОКОЛ РОБОТИ ПРОГРАМИ

Для початку роботи з програмою запустіть застосунок “SegmentsIntersection.exe” у робочому каталозі програми. Після запуку відкриється домашня сторінка програми (Рис. 5.1.). На поточному кроці можна виконати 3 дії.

Рис. 5.1. Домашня сторінка

Відкрити довідку (Рис. 5.2.). У довідці можна знайти детальну інформацію про будь-який аспект роботи програми під час виконання.

Рис. 5.2. Довідка

При зчитуванні даних з файлу віддкривається діалогове вікно (Рис. 5.3.).

Рис. 5.3. Вибір файлу

Вибравши потрібний файл користувач натискає кнопку “Відкрити” та бачить резутьтат (Рис. 5.4.).

Рис. 5.4. Результат

На формі результату у лівому нижньому куті є список доступних точок для побудови чотирикутника (Рис. 5.5.). Потрібно послідовно натиснути мишкою та 4 точки, на яких ви бажаєте побудувати чотирикутник і після цього натиснути кнопку “Створити чотирикутник”.

Рис. 5.5. Список точок для побудови чотирикутника

Чотирикутник буде відображений графічно та буде отримана текстова інформація про площу та периметр (Рис. 5.6.).

Рис. 5.6. Результат побудови чотирикутника

Якщо обрати на домашній сторінці кнопку “Нові дані”, відбудеться перехід до форми вводу ( Рис. 5.7.).

Рис. 5.7. Форма вводу

Введіть дані про відрізок у текстові поля (1) і натисність кнопку “Додати”. Під списком (2). Записаний відрізок буде додано до списку. Якщо ж потрібно перевірити перетин відрізків на площині, поставте прапорець “На площині”(4). Форма вводу модифікується для вводу даних на площині (Рис.5.8.). Додавши декілька відрізків натисніть кнопку “Перевірити” (3). Відбудеться перехід до форми результату, подальші кроки роботи описані вище.

Рис. 5.8. Форма вводу на площині

У ході виконання програми користувач можете отримати попередження, або повідомлення про помилки. Далі можна дізнатися причини їх появи, та шляхи їх усунення.

Рис. 5.8. Не коректні дані

Таке повідомлення виникає, якщо ви натиснули кнопку «Додати» на формі введення попередньо не заповнивши всі поля для введення координат, або заповнивши їх не правильно. Не вірно заповнені поля підсвічуються червоним кольором, що полегшує виявлення та виправлення помилок. Про формат вводу можна дізнатися з розділу 6.2.2. Вхідні та вихідні дані.

Рис. 5.9. Не достатньо даних

Для перевірки результату необхідно додати до списку щонайменше два відрізки. Перевірте таблицю та додайте необхідні елементи.

Рис. 5.10. Помилка зчитування

Помилка зазвичай виникає, якщо зчитування відбувається з порожнього файлу, або якщо у файлі немає хоча б двох коректних записів. Введіть дані у файл, або виберіть інший та повторіть спробу.

Рис. 5.11. Пошкоджені рядки

Таке попередження повідомляє, що у файл занесені не коректні рядки, але він був прочитаний. 4, або по 6 чисел розділених символами пробілу та вони не перевищують допустимі межі. Про формат вводу можна дізнатися розділі 6.2.2. Вхідні та вихідні дані.

Рис. 5.12. Однакові точки

Координати двох точок, що задають відрізок збігаються, а відрізок не може бути заданий однією точкою. Змініть дані і повторіть спробу.

Рис. 5.13. Помилка ініціалізації OpenGL

Критична помилка,що виникає, при несумісності програми з операційною системою, або апаратним забезпеченням. Перевірте розділ 6.2.3. Додаткове ПЗ. та 6.2.4. Системні вимоги.

Рис. 5.14. Не знайдена бібліотека glut32.dll

Помилка виникає, якщо у каталозі з програмою немає файлу glut32.dll. Перемістіть даний файл у робочу директорію, перевірте наявність необхідних компонентів з розділу 3. Компоненти та перезапустіть програму.

Рис. 5.15. Помилка відображення сторінки

Помилка виникає, якщо у каталозі з програмою не знайдено файлу Manual.html. Перемістіть даний файл у робочу директорію, перевірте наявність необхідних компонентів з розділу 3. Компоненти та перезапустіть програму.


6. ІНСТРУКЦІЯ КОРИСТУВАЧА

6.1. Призначення програми

Цей програмний продукт використовується для вирішення вузького кола геометричних задач, а саме, пошук точок перетину декількох відрізків та побудова чотирикутників, з отриманням інформації про їх периметр і площу. При виконанні програми можна отримати інформацію про те, чи є перетином відрізків точка, чи відрізок та чи перетинаються відрізки взагалі. З точок, якими були задані відрізки можна будувати чотирикутники. Пошук рішень можливий як на площині, так і у просторі.

6.2. Правила використання

6.2.1. Навігація

Запустивши програму ви побачите її домашню сторінку (Рис. 6.1.).Звідси можливо виконати 3 дії: перейти до сторінки введення даних, перейти до діалогового вікна вибору файлу та відкрити інструкцію користування. Для виконання будь-якої дії достатньо натиснути відповідну кнопку.

Рис. 6.1. Домашня сторінка

При натисканні на довідку відкриється інструкція (Рис. 6.2.). Тут можна дізнатися про особливості роботи програми, причини виникнення помилок та інше.

Рис. 6.2. Довідка

При переході до форми введення даних (Рис. 6.3.) ви бачите поля для задання нових відрізків (1). За замовчуванням увімкнений ввід для просторового варіанту задачі. Для переходу до задачі на площині, або назад необхідно натиснути check-box (2) у лівій нижній частині форми. Після переходу до задачі на площині, зникають поля для введення координати Z для кожної з точок. Після введення координат відрізку потрібно додати його до списку, натиснувши кнопку (3) під таблицею. також з таблиці можна видаляти окремі елементи, виділивши їх і натиснувши кнопку (4), або очистити її повістю, кнопка (5). Задавши декілька відрізків, можна перевірити чи перетинаються вони, натиснувши кнопку (6) у правій нижній частині форми.

Рис. 6.3. Сторінка вводу

При переході до зчитування з файлу буде відкрито діалог (Рис. 6.4.), де необхідно вибрати файл, з якого буде отримано вхідні значення. Якщо файл коректний, відразу буде відображено результат.

Рис. 6.4. Вибір файлу

На сторінці результату (Рис 6.5.) ви побачите його текстове та візуальне представлення. Звідси можливе швидке повернення до вводу кнопкою (якщо дані були введені вручну, то на форму вводу, якщо завантажені з файлу, до вікна вибору файлу). Щоб повернутися потрібно натиснути кнопку (1) у лівій верхній частині сторінки. Також можливо повернутися на домашню сторінку, натиснувши на піктограму будинку (2), яка знаходиться зліва від заголовку вікна. Перехід до домашньої сторінки також можливий з форм введення та вибору файлу.

Список (3) у лівому нижньому куті форми показує точки, якими були задані відрізки, доступні для побудови чотирикутників. Для виділення точок послідовно натисніть на їх представлення у таблиці. Для зняття виділення повторно натисніть на виділену раніше кнопку. Порядок виділення важливий, чотирикутник буде побудований на точках у тому порядку, у якому вони були виділені. Щоб побудувати чотирикутник на виділених точках, натисніть кнопку "Створити Чотирикутник".

Рис. 6.5. Сторінка результату

6.2.2. Вхідні та вихідні дані

Програма приймає на вхід координати відрізків, кожен з яких заданий двома точками. Кожна точка задається координатами (X, Y), або (X, Y, Z), залежно від простору, у контексті якого вона буде обраховуватись. Дві точки. що задають відрізок не можуть мати однакові координати. Координати мають бути задані цілими числами, або числами з плаваючою крапкою, що представляють дані у сантиметрах. Максимальне допустиме вхідне значення 1010, мінімальне відповідно -1010. Якщо ви бажаєте зчитати дані з файлу, рядок має бути записаний наступним чином.

Для випадку на площині:

X1 Y1 X2 Y2

Для випадку у просторі:

X1 Y1 Z1 X2 Y2 Z2

Де індекс після імені координати (1, або 2) відповідає точці, координата якої буде зчитана. Відрізки будуть утворені з’єднанням точок. Не бажано опрацьовувати більше 20 відрізків одночасно, інакше їх відображення займатиме тривалий час.

Зчитування даних відбувається лише з фалів розширенням .dat. На виході ви отримаєте одне з трьох повідомлень:

· "Відрізки не перетинаються"

· "Відрізки перетинаються у точці"

· "Відрізки перетинаються на проміжку"

А також координати точки перетину, або пару координат, що задають проміжок, при відповідних повідомленнях. Окрім текстового представлення результату, він буде зображений графічно. При побудові чотирикутника він буде відображений на сцені разом з відрізками. Якщо всі вершини чотирикутника знаходяться у одній площині, буде обрахована його площа та периметр, у іншому випадку буде показне відповідне повідомлення.

6.2.3. Додаткове ПЗ

Для коректної роботи програми необхідно:

· Visual C++ 2015 Redistributable Package;

· Microsoft .NET Framework 4.5.2;

· OpenGL 4.3.0, або вище;

6.2.4. Системні вимоги

· 50 Мб ОЗУ;

· Windows 7, або вище;

· Відеокарта з підтримкою OpenGL 4.3.0, або вище;

· Пристрій вводу – клавіатура, миша;

· Пристрій виводу – екран;

7. ВИСНОВОК

Завдання курсової роботи було виконано завдяки використанню Об’єктно орієнтованого підходу. Було створено користувацькі класи, які зберігали дані та надавали неохідний функціонал використовуючи принцип інкапсуляції. Був створений клас інтерфейсу, який надавав функціонал похідним класам та зумовлював використання поліморфізму.

Програма була написана мовою с++ з розширенням cli. та використанням технології .NET. Використання даної технології збільшує потужність та можливості використання ООП завдяки великим бібліотекам стандартних класів. Також було використано додадкову бібліотеку OpenGL, для роботи з коп'ютерною графікою. Використання бібліотеки дозволило ввевсти додадкову можливісь для перегляду результату у трьохвимірному просторі, а не як проекція на площину. Додатково був розроблений приємний графічний дизайн, що забечує почуття естетичної насолоди під час роботи з програмою.

За час написання даної роботи були успішно виконані всі поставлені завдання. Отримані нові навички у проектуванні та та організації життєвого циклу програмного забезпечення. На практиці були застосовані шаблони проектування та стандарти кодування. Покращені навички написання об'єктно орієнтованого коду.

Щоб покращити роботу програми можна створити користувацький клас списку з вибором, та замінити ним стандартні таблиці, які використовуюються у проекті. Така модифікація значно покращить швидкодію та зменшить витрати ресурсів, адже вбудовані таблиці Windows forms є дуже повільними та не оптимізованими.

Источник: портал www.KazEdu.kz

Другие материалы

  • Особливості вивчення математики в профільних класах у сучасних умовах
  • ... ільно орієнтуватись на використання підручників [53; 54; 5; 1].   РОЗДІЛ 2 ОСОБЛИВОСТІ ВИВЧЕННЯ МАТЕМАТИКИ У ПРОФІЛЬНИХ КЛАСАХ В СУЧАСНИХ УМОВАХ 2.1. ОСНОВНІ ПОЛОЖЕННЯ ПРОФІЛЬНОЇ ДИФЕРЕНЦІАЦІЇ НАВЧАННЯ МАТЕМАТИКИ Математика є універсальною мовою, яка широко застосовується в ...

  • Вміння порівнювати в процесі навчання математики
  • ... ів розумової діяльності вимагає врахування індивідуально-вікових особливостей учнів.   1.2 Формування уміння порівнювати в процесі навчання математики   Порівняння в навчанні – це розумова операція, за допомогою якої встановлюються риси подібності і відмінності між визначеними ...

  • Вивчення елементів стереометрії у курсі геометрії 9 класу
  • ... повну відсутність серед добірок завдань контролюючого характеру.   2.2 Загальні методичні рекомендації вивчення елементів стереометрії у курсі геометрії 9 класу   2.2.1 Формування уявлень і понять про стереометричні фігури та деякі їх властивості Формування понять – складний психолог ...

  • Особливості формування навичок кольоротворення на уроках образотворчого мистецтва в початкових класах
  • ... відтінків, які залежать від кольору предмета. На підтвердження наведених теоретичних положень ми проводили дослідження особливостей формування відчуття кольору на уроках образотворчого мистецтва у початкових класах. Це дослідження мало практичний характер. Навчальна робота, яка проводилася нами в ...

  • Вивчення математики в початковій школі
  • ... ім учнів ознайомлюють з вимірюванням ламаних ліній таким способом: виміряти ланки ламаної і додати знайдені числа. 1.2 Вивчення многокутників у початковій школі Поняття про многокутники формуються у дітей поступово, протягом усього початкового навчання і в наступних класах. Спочатку під час ...

  • Декоративно-прикладне мистецтво
  • ... комбінуючи метал і каміння. ХУДОЖНЯ ОБРОБКА КІСТКИ ТА РОГУ Художня обробка кістки та рогу — один із найдавніших видів декоративно-прикладного мистецтва. Протягом тисячоліть художні вироби з цих матеріалів були незамінимі у різноманітних галузях людської діяльності. У середині XX ст. пластмасов ...

  • Держава і ринок: філософія взаємодії
  • ... побудови; на визначенні пріоритетних цінностей та економічного порядку, який повинен забезпечувати реалізацію цієї моделі. Тому розроблення філософії взаємодії держави і ринку передбачає дослідження багатогранності цього процесу, урахування впливу інституційного середовища на конкретну модель економ ...

  • Методика формування відчуття кольору у процесі малювання натюрморту у початковій школі
  • ... теоретичних положень ми проводили перевірку ефективності удосконаленої методики формування відчуття кольору у процесі виконання натюрморту на уроках образотворчого мистецтва у початкових класах. Сам процес експериментального навчання за пропонованими нами методичними положеннями відбувався на ...

  • Використання комп'ютера на уроках математики
  • ... вчителя чи прослухати (переглянути) вже наявні файли (на диску чи на комп'ютері). Розділ 2. Конспекти уроків з математики із використанням дидактичних посібників, зроблених за допомогою комп'ютера   Урок 1. Доповнення до 10. Узагальнена таблиця додавання і віднімання в межах 10 (1 клас) ...

Каталог учебных материалов

Свежие работы в разделе

Наша кнопка

Разместить ссылку на наш сайт можно воспользовавшись следующим кодом:

Контакты

Если у вас возникли какие либо вопросы, обращайтесь на email администратора: admin@kazreferat.info