Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
diploma.doc
Скачиваний:
26
Добавлен:
31.08.2019
Размер:
1.03 Mб
Скачать

3.2. Кодування основної частини програми.

Спочатку потрібно підключити необхідні бібліотеки та оголосити прототипи функцій.

У файлі ATriangulation.h оголосимо прототипи функції, що буде працювати з натисканням лівої кнопки маніпулятора у вікні програми:

afx_msg void OnLButtonDown(UINT nFlags, CPoint point);

У файлі Atriangulation.cpp внесемо зміни у BEGIN_MESSAGE_MAP, а саме додамо обробник повідомлень Windows, пов'язаних з обробкою натискань кнопки миші: ON_WM_LBUTTONDOWN(). Та опишемо функцію, що буде фіксувати натискання:

void CATriangulationDlg::OnLButtonDown(UINT nFlags, CPoint point) {...}

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

Внесемо зміни у Atriangulation.cpp:

#include <atlimage.h>

#include <fstream>

#include <math.h>

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

  • double camAngle — кут огляду фотокамери;

  • double aAngle=0, bAngle=0 — кути між опорними точками;

  • double x=0, y=0 — шукані координати;

  • double sizeX, sizeY — розміри координатної системи;

  • double *X, *Y — вказівники на масиви, де містяться координати опорних точок.

  • int N – кількість опорних точок.

Змінні для роботи з зображеннями:

  • CImage image — об'єкт класу CImage;

  • CString fileName — шлях до файлу з зображенням.

Змінні для роботи інтерфейсу програми:

  • bool bClick=false — флаг, що використовується для організації порядку вимірів кутів;

  • long iPixDist=0 — відстань між опорними точками на зображенні;

  • int Index[3] — масив індексів опорних точок, що використовуються для одного вимірювання;

Налаштування програма повинна зчитувати з файлу. Зчитування конфігурації слід написати у функції програми, яка виконується відразу після її запуску, а саме в OnInitDialog():

ifstream config;

config.open("setup.cfg");

if(!config.good()) {

AfxMessageBox("Файл конфигурации не найден!",0,0);

OnCancel();

}

char ftmp[16];

config >> ftmp; camAngle = atof(ftmp);

config >> ftmp; sizeX = atof(ftmp);

config >> ftmp; sizeY = atof(ftmp);

config >> ftmp; N = atof(ftmp);

X = new double[N]; Y = new double[N];

for(int i=0; i<N ; i++) {

config >> ftmp; X[i] = atof(ftmp);

config >> ftmp; Y[i] = atof(ftmp);

}

Функція для відкриття діалогу завантаження зображення виконується при натисканні кнопки IDOK:

void CATriangulationDlg::OnBnClickedOk() {

CFileDialog File(TRUE);

INT_PTR nResult = File.DoModal();

if(nResult == IDOK) {

if(!image.Load(File.GetPathName())) {

fileName.GetBuffer(1000);

fileName = File.GetPathName();

image.AlphaBlend(this->GetDC()>m_hDC,0,0,640,480,0,0,

image.GetWidth(),image.GetHeight());

} else {

AfxMessageBox("Файл не является изображением!",0,0);

}

}

image.Destroy();

}

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

При зверненні вікна або при виході за межі екрану викликається функція OnPaint(), яка перемальовує вікно та затирає завантажене зображення. Тому необхідно модифікувати її таким чином, щоб при її виклику перемальовувалось завантажене зображення:

if(!image.Load(fileName)) {

image.AlphaBlend(this->GetDC()>m_hDC,0,0,640,480,0,0, image.GetWidth(),image.GetHeight());

image.Destroy();

}

Кут між опорними точками рахується з допомогою відстані між цими точками на зображенні у пікселях. Всі ці дії описані у функції, яка працює з повідомленням ON_WM_LBUTTONDOWN(). Функція влаштована таким чином, що працює тільки за умов, що була натиснута кнопка IDC_BUTTON1, після чого можна зробити два натискання лівої кнопки маніпулятора у межах вікна, відмітивши положення опорних точок на зображенні. Функція повертає координати натискання. Відстань між опорними точками на зображенні визначається різницею координат X двох натискань на цих точках. Також запам'ятовуються індекси опорних точок, над якими виконуються вимірювання. Індекси вводяться перед початком вимірювань у поля IDC_EDIT1 та IDC_EDIT2.

Функція, при натисканні кнопки IDC_BUTTON1:

void CATriangulationDlg::OnBnClickedButton1() {

GetDlgItem(IDC_BUTTON1)->EnableWindow(false);

}

Функція обробки натискань:

void CATriangulationDlg::OnLButtonDown(UINT nFlags, CPoint point) {...}

Дії виконуються якщо натиснута кнопка IDC_BUTTON1:

if(GetDlgItem(IDC_BUTTON1)->EnableWindow(false) != 0) {...}

Далі, якщо після натискання кнопки було зроблено два натиснення лівої кнопки миші і перший кут не був обчислений, то обчислюємо його:

GetDlgItem(IDC_BUTTON1)->EnableWindow(true);

iPixDist = abs(iPixDist-point.x);

if(aAngle==0) {

aAngle = (camAngle * (double)iPixDist) / 640;

sprintf(tmp, "%f", aAngle);

AfxMessageBox(strcat(tmp, " alpha"), 0, 0);

this->GetDlgItemText(IDC_EDIT1, buf, 4);

Index[0] = atoi(buf);

this->GetDlgItemText(IDC_EDIT2, buf, 4);

Index[1] = atoi(buf);

}

Якщо відбулося два натискання, але перший кут вже був обчислений, то обчислюємо другий кут, та викликаємо функцію CalculateCoords(), де виконуються основні математичні обчислення:

bAngle = (camAngle * (double)iPixDist) / 640;

sprintf(tmp, "%f", bAngle);

AfxMessageBox(strcat(tmp, " beta"), 0, 0);

this->GetDlgItemText(IDC_EDIT1, buf, 4);

Index[2] = atoi(buf);

if(Index[2] == Index[0] || Index[2] == Index[1]) {

this->GetDlgItemText(IDC_EDIT2, buf, 4);

Index[2] = atoi(buf);

}

CalculateCoords ( X[Index[0]], Y[Index[0]], X[Index[1]], Y[Index[1]], X[Index[2]], Y[Index[2]], aAngle, bAngle);

sprintf(tmp, "%f", x);

this->SetDlgItemText(IDC_STATIC1, tmp);

sprintf(tmp, "%f", y);

this->SetDlgItemText(IDC_STATIC2, tmp);

aAngle = 0;

bClick = false;

Якщо відбулось лише одне натискання кнопки маніпулятора, то запам'ятовуємо координати натискання:

iPixDist = point.x;

bClick = true;

Основні математичні обчислення виконуються у функції CalculateCoords(). Прототип функції описаний у самому початку тексту програми:

void CalculateCoords ( double x1, double y1, double x2, double y2, double x3, double y3, double a, double b);

Функція приймає значення координат трьох опорних точок, та двох кутів між першою та другою, і другою та третьою точками.

Опишемо дії, що виконуються в функції CalculateCoords().

Оголошення змінних, що використовуються для розрахунків:

double AB, BD, AD;

double f, f1, f2;

double R1, R2;

Обчислення сторін, координати точок яких відомі:

AB = sqrt(pow((x2-x1), 2) + pow((y2-y1), 2));

BD = sqrt(pow((x3-x2), 2) + pow((y3-y2), 2));

AD = sqrt(pow((x3-x1), 2) + pow((y3-y1), 2));

Обчислення радіусів кіл, описаних навколо першого і другого трикутників:

R1 = AB / (2*sin(a));

R2 = BD / (2*sin(b));

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

f = acos((pow(AB,2)+pow(BD,2)-pow(AD,2))/(2*AB*BD));

if((y1-y3)*x2+(x3-x1)*y2+(x1*y3-x3*y1)>0)

f = 2*M_PI - acos((pow(AB,2)+pow(BD,2)-pow(AD,2))/(2*AB*BD));

f1 = M_PI - a - atan(sin(2*M_PI-f-a-b) / (R1/R2+cos(2*M_PI-f-a-b)));

f2 = f - f1;

За допомогою обчислених радіусів розраховуються інші сторони трикутників:

double AC, DC;

AC = 2*R1*sin(f1);

DC = 2*R2*sin(f2);

Обчислення положення, якщо координати Y опорних точок збігаються:

if(y1 == y3) {

x = (pow(AC, 2) - pow(DC, 2) - pow(x1, 2) + pow(x3, 2)) / (2*(x3-x1));

y = y1 - sqrt(pow(AC,2) – pow((x-x1),2));

if(x3<x1)

y = y1 - sqrt(pow(AC,2) - pow((x-x1),2));

}

Інакше, якщо координати Х опорних точок збігаються:

else if(x1 == x3) {

y = (pow(AC, 2) - pow(DC, 2) - pow(y1, 2) + pow(y3, 2)) / (2*(y3-y1));

x = x1 + sqrt(pow(AC,2) – pow((y-y1),2));

if(y3>y1)

x = x1 - sqrt(pow(AC,2) - pow((y-y1),2));

}

Виконання обчислень у інших випадках:

else {

double dA = pow(AC,2) - pow(DC,2) - pow(x1,2) – pow(y1,2) + pow(x3,2) + pow(y3,2);

double dB = 2*(x3-x1);

double dC = 2*(y3-y1);

double dG = pow(dA,2) – 2*dA*dC*y1 + pow(dC,2)*pow(x1,2) + pow(dC,2)*pow(y1,2) - pow(dC,2)*pow(AC,2);

double dE = 2*(dB*dC*y1 - dA*dB - x1*pow(dC,2));

double dF = pow(dC,2) + pow(dB,2);

double D = sqrt(pow(dE,2) - 4*dF*dG);

x = (-dE + D) / (2*dF);

y = (dA - x*dB) / dC;

if(x3<x1 && y3>y1) {

x = (-dE - D) / (2*dF);

y = (dA - x*dB) / dC;

}

}

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

Функція OnBnClickedCancel():

void CATriangulationDlg::OnBnClickedCancel() {

fileName = "";

fileName.ReleaseBuffer();

aAngle=0;

GetDlgItem(IDC_BUTTON1)->EnableWindow(true);

this->SetDlgItemText(IDC_STATIC1, "");

this->SetDlgItemText(IDC_STATIC2, "");

Invalidate();

dlgWin2.DestroyWindow();

}

При завершені роботи програми бажано звільняти пам'ять від створених динамічних структур:

void CATriangulationDlg::OnClose() {

fileName.ReleaseBuffer();

delete[] X;

delete[] Y;

DestroyWindow();

}

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]