4. Разработка и тестирование программного обеспечения
Программа разрабатывалась согласно техническому заданию, приведенному в разделе 1, в среде разработки, выбранной в разделе 2, с использованием теоретических сведений, приведенных в разделе 3.
Вид экрана при работе в Microsoft Visual Studio 2008 приведен на рисунке 4.1.
Рисунок 4.1 – Вид экрана при работе в MS Visual Studio 2008
В результате получен исходный код программы, основной файл которой manipulator.cpp имеет размер 414 строк. Список основных файлов проекта приведен в таблице 4. Текст программы приведен в приложении А.
Таблица 4 – Список файлов проекта
Имя файла |
Комментарий |
manipulator.sln |
Файл сборки VS |
manipulator.vcproj |
Файл проекта VS |
manipulator.h |
Заголовочный файл |
manipulator.cpp |
Файл реализации (основной файл проекта) |
manipulator.rc |
Файл ресурсов |
Stdafx.cpp и stdafx.h |
Файлы предварительно откомпилированных заголовков |
Debug/manipulator.exe |
Исполняемый файл, полученный в результате компиляции. |
Тестирование программы производилось путем проверки соответствия поведения эмулируемого механизма командам пользователя. Также проверялась идентичность реакции механизма на команды, посылаемые путем выбора пунктов меню и нажатия дублирующих их клавиш клавиатуры.
В результате тестирования подтверждена работоспособность программы, а также ее соответствие поставленному техническому заданию.
Вид экрана при работе с программой приведен на рисунке 4.2
Рисунок 4.2 – Вид экрана при работе с программой
Заключение
В результате выполнения работы создан эмулятор руки манипулятора. В ходе выполнения работы было:
-
сформулировано техническое задание;
-
произведен анализ существующих средств разработки и выбор подходящего для решения поставленной задачи средства;
-
изучены теоретические сведения о библиотеках WinAPI и OpenGL;
-
разработана программа согласно техническому заданию и произведено ее тестирование.
Выполнение данной работы позволило получить практические навыки программирования с использованием библиотек WinAPI и OpenGL на языке C++ в среде разработки Microsoft Visual Studio 2008. Также были закреплены знания из области векторной алгебры и матричного исчисления.
Результатом выполнения работы является готовый к использованию программный продукт.
Список использованных источников
-
Win32. Основы программирования: К. Г. Финогенов — Москва, Диалог-МИФИ, 2006 г.- 416 с.
-
Программирование на C++/C# в Visual Studio .NET: Понамарев В.А, СПб.: БХВ-Петербург, 2004 г. – 544 с.
-
OpenGL. Руководство по программированию: М. Ву, Т. Девис, Дж. Нейдер, Д. Шрайнер — Москва, Питер, 2006 г.- 624 с.
Приложение а текст программы юдлолдодло
#include "stdafx.h"
#include "manipulator.h"
#define MAX_LOADSTRING 100
// Глобальные переменные:
HINSTANCE hInst; // текущий экземпляр
TCHAR szTitle[MAX_LOADSTRING]; // Текст строки заголовка
TCHAR szWindowClass[MAX_LOADSTRING]; // имя класса главного окна
HWND hWnd; // главное окно
HDC hDC; // дисплейный контекст главного окна
GLfloat trans[3];
GLfloat rot[2];
// Отправить объявления функций, включенных в этот модуль кода:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
MSG msg;
HACCEL hAccelTable;
HGLRC hRC;
// Инициализация глобальных строк
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_MANIPULATOR, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Выполнить инициализацию приложения:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_MANIPULATOR));
// инициализация OpenGL
PIXELFORMATDESCRIPTOR pfd;
int pf;
hDC = GetDC(hWnd);
memset(&pfd, 0, sizeof(pfd));
pfd.nSize = sizeof(pfd);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cDepthBits = 32;
pfd.cColorBits = 32;
pf = ChoosePixelFormat(hDC, &pfd);
if (pf == 0) {
MessageBox(NULL, "ChoosePixelFormat() failed: "
"Cannot find a suitable pixel format.", "Error", MB_OK);
return 0;
}
if (SetPixelFormat(hDC, pf, &pfd) == FALSE) {
MessageBox(NULL, "SetPixelFormat() failed: "
"Cannot set format specified.", "Error", MB_OK);
return 0;
}
DescribePixelFormat(hDC, pf, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
ReleaseDC(hWnd, hDC);
hRC = wglCreateContext(hDC);
wglMakeCurrent(hDC, hRC);
glEnable(GL_DEPTH_TEST);
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
ShowWindow(hWnd, nCmdShow);
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
wglMakeCurrent(NULL, NULL);
wglDeleteContext(hRC);
DestroyWindow(hWnd);
return (int) msg.wParam;
}
static void update(int state, int ox, int nx, int oy, int ny)
{
int dx = ox - nx;
int dy = ny - oy;
rot[0] += (dy * 180.0f) / 500.0f;
rot[1] -= (dx * 180.0f) / 500.0f;
#define clamp(x) x = x > 360.0f ? x-360.0f : x < -360.0f ? x+=360.0f : x
clamp(rot[0]);
clamp(rot[1]);
}
void reshape(int width, int height)
{
glViewport (0, 0, (GLsizei) width, (GLsizei) height);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
gluPerspective(60.0, (GLfloat) width/(GLfloat) height, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef (0, 0, -1);
}
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASS wcex;
wcex.style = CS_OWNDC;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MANIPULATOR));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = NULL;
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_MANIPULATOR);
wcex.lpszClassName = szWindowClass;
return RegisterClass(&wcex);
}
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // Сохранить дескриптор экземпляра в глобальной переменной
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
static GLboolean left = GL_FALSE;
static GLboolean right = GL_FALSE;
static GLuint state = 0;
static int omx = 0, omy = 0, mx = 0, my = 0;
static int angles[8] = {0, 0, 0, 0, 0, 0, 0, 0};
static float col1[8] = {1,1,1,1,0,0,0,1};
static float col2[8] = {1,1,0,0,1,1,0,1};
static float col3[8] = {1,0,1,0,1,0,1,1};
static char ch[8][3] = {{'q','/','a'},
{'w','/','s'},
{'e','/','d'},
{'r','/','f'},
{'t','/','g'},
{'y','/','h'},
{'u','/','j'},
{'i','/','k'}
};
GLUquadricObj* quadObj;
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Разобрать выбор в меню:
switch (wmId)
{
case IDM_S1:
angles[0] = (angles[0] + 5) % 360;
PostMessage(hWnd, WM_PAINT, 0, 0);
break;
case IDM_S1_:
angles[0] = (angles[0] - 5) % 360;
PostMessage(hWnd, WM_PAINT, 0, 0);
break;
case IDM_S2:
angles[1] = (angles[1] + 5) % 360;
PostMessage(hWnd, WM_PAINT, 0, 0);
break;
case IDM_S2_:
angles[1] = (angles[1] - 5) % 360;
PostMessage(hWnd, WM_PAINT, 0, 0);
break;
case IDM_S3:
angles[2] = (angles[2] + 5) % 360;
PostMessage(hWnd, WM_PAINT, 0, 0);
break;
case IDM_S3_:
angles[2] = (angles[2] - 5) % 360;
PostMessage(hWnd, WM_PAINT, 0, 0);
break;
case IDM_S4:
angles[3] = (angles[3] + 5) % 360;
PostMessage(hWnd, WM_PAINT, 0, 0);
break;
case IDM_S4_:
angles[3] = (angles[3] - 5) % 360;
PostMessage(hWnd, WM_PAINT, 0, 0);
break;
case IDM_S5:
angles[4] = (angles[4] + 5) % 360;
PostMessage(hWnd, WM_PAINT, 0, 0);
break;
case IDM_S5_:
angles[4] = (angles[4] - 5) % 360;
PostMessage(hWnd, WM_PAINT, 0, 0);
break;
case IDM_S6:
angles[5] = (angles[5] + 5) % 360;
PostMessage(hWnd, WM_PAINT, 0, 0);
break;
case IDM_S6_:
angles[5] = (angles[5] - 5) % 360;
PostMessage(hWnd, WM_PAINT, 0, 0);
break;
case IDM_S7:
angles[6] = (angles[6] + 5) % 360;
PostMessage(hWnd, WM_PAINT, 0, 0);
break;
case IDM_S7_:
angles[6] = (angles[6] - 5) % 360;
PostMessage(hWnd, WM_PAINT, 0, 0);
break;
case IDM_S8:
angles[7] = (angles[7] + 5) % 360;
PostMessage(hWnd, WM_PAINT, 0, 0);
break;
case IDM_S8_:
angles[7] = (angles[7] - 5) % 360;
PostMessage(hWnd, WM_PAINT, 0, 0);
break;
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_SIZE:
reshape(LOWORD(lParam), HIWORD(lParam));
PostMessage(hWnd, WM_PAINT, 0, 0);
return 0;
case WM_PAINT:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glScalef(0.7,0.7,0.7);
glTranslatef(-0.5, 0, 0);
glRotatef(rot[0], 1.0f, 0.0f, 0.0f);
glRotatef(rot[1], 0.0f, 1.0f, 0.0f);
for (int i = 0; i < 8; i++) {
glColor3f(col1[i], col2[i], col3[i]);
glPushMatrix();
glTranslatef (0.1, 0.0, 0.0);
glScalef (0.07, 0.07, 0.07);
glutSolidSphere(1, 10, 10);
glPushMatrix();
glTranslatef (0, 1.5, 0.0);
// Выбираем текущий шрифт системы
SelectObject (hDC, GetStockObject (SYSTEM_FONT));
// Форм. 255 дисплейных списков изображений символов, начиная с
// кода 1 и размещая с базового имени дисплейного списка – 1
wglUseFontBitmaps (hDC, 1, 255, 1);
glRasterPos2i(0,0); // С позиции экрана (20,10)
// Выводим 17 дисплейных списков (17 символов текста)
glCallLists (3, GL_UNSIGNED_BYTE, ch[i]);
glPopMatrix();
glPopMatrix();
glTranslatef (0.1, 0.0, 0.0);
glRotatef ((GLfloat) angles[i], 0.0, 0.0, 1.0);
glTranslatef (0.1, 0.0, 0.0);
glPushMatrix();
glScalef (0.2, 0.1, 0.1);
glutSolidCube (1);
glPopMatrix();
}
glPushMatrix();
glTranslatef (0.1, 0.0, 0.0);
glScalef(0.05,0.2,0.1);
glutSolidCube(1);
glPopMatrix();
glPushMatrix();
glTranslatef (0.15, 0.1, 0.0);
glScalef(0.15,0.05,0.1);
glutSolidCube(1);
glPopMatrix();
glPushMatrix();
glTranslatef (0.15, -0.1, 0.0);
glScalef(0.15,0.05,0.1);
glutSolidCube(1);
glPopMatrix();
glPopMatrix();
SwapBuffers(hDC);
hdc = BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
break;
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
state = 1;
SetCapture(hWnd);
mx = LOWORD(lParam);
my = HIWORD(lParam);
return 0;
case WM_LBUTTONUP:
case WM_RBUTTONUP:
ReleaseCapture();
state = 0;
return 0;
case WM_MOUSEMOVE:
if (state) {
omx = mx;
omy = my;
mx = LOWORD(lParam);
my = HIWORD(lParam);
if(mx & 1 << 15) mx -= (1 << 16);
if(my & 1 << 15) my -= (1 << 16);
update(state, omx, mx, omy, my);
PostMessage(hWnd, WM_PAINT, 0, 0);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// Обработчик сообщений для окна "О программе".
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}