Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лабораторная работа 3 по КГ.docx
Скачиваний:
1
Добавлен:
20.08.2019
Размер:
579.93 Кб
Скачать

Федеральное агентство по образованию РФ

Государственное образовательное учреждение высшего профессионального образования

Волгоградский государственный технический университет

(ВолгГТУ)

Кафедра "ЭВМ и сети"

Лабораторная работа №3

по дисциплине:

"Компьютерная графика"

Выполнил: студент группы ВМ-09.2

Тимофеев Е.К.

Проверил: Земцов А.Н.

Оценка работы __________ баллов

Волгоград 2010

1 Задание

Написать программу, выполняющую вращение перспективного изображения куба (или более сложной фигуры, например, икосаэдра или додекаэдра) вокруг произвольного вектора или вращение со случайными параметрами.

2 Листинг программы

Для решения поставленной задачи был создан стандартный проект MFC Dialog на С++ в Microsoft Visial Studio 2008.

В проекте для реализации управлением геометрическими преобразованиями были использованы кнопки блока стрелок клавиатуры. Для чего была перегружена стандартная функция обработки сообщений в проекте. Описание добавлено в Lab3_PatrakeevDS_EVM-09.2Dlg.h:

public:

afx_msg void OnRButtonDown(UINT nFlags, CPoint point);

BOOL PreTranslateMessage(MSG* pMsg); //Перегрузка функции

Реализация перегруженной функции связано с тем, что кнопки стрелок вправо и влево вращают октаэдр вокруг случайного вектора, задаваемой левой клавишей мыши. В свою очередь кнопки вверх и вниз вращают мировые координаты по часовой и против часовой стрелки. Щелчок правой клавишей сбрасывает значения всех параметров к нулевым. Реализация функции находится в Lab3_PatrakeevDS_EVM-09.2Dlg.cpp:

BOOL CLab3_PatrakeevDS_EVM092Dlg::PreTranslateMessage(MSG* pMsg)

{

if(pMsg->message == WM_KEYDOWN)

{

if(pMsg->wParam == VK_LEFT)//поворачиваем октаэдр

{

alfa+=0.0157;//поворачиваем октаэдр вокруг вектора

this->Invalidate();//очищаем клиентскую область

OnPaint();//перерисовываем клиентскую область

}

if(pMsg->wParam == VK_RIGHT)//поворачиваем октаэдр

{

alfa-=0.0157;//поворачиваем октаэдр вокруг вектора

this->Invalidate();//очищаем клиентскую область

OnPaint();//перерисовываем клиентскую область

}

if(pMsg->wParam == VK_UP)//поворачиваем мировые координаты

{

nu+=0.0157;

this->Invalidate();//очищаем клиентскую область

OnPaint();//перерисовываем клиентскую область

}

if(pMsg->wParam == VK_DOWN)//поворачиваем мировые координаты

{

nu-=0.0157;

this->Invalidate();//очищаем клиентскую область

OnPaint();//перерисовываем клиентскую область

}

}

return CDialog::PreTranslateMessage(pMsg);

}

К основной форме проекта было добавлено следующее событие, возникающее при клике левой кнопкой мыши, создающее вектор со случайными параметрами, относительно которого будет происходить вращение октаэдра:

void CLab3_PatrakeevDS_EVM092Dlg::OnLButtonDown(UINT nFlags, CPoint point)

{

// TODO: Add your message handler code here and/or call default

this->Invalidate();//очищаем клиентскую область

//зададим случайным образом параметры вектора вращения

srand((unsigned)time(NULL));

xyzvv.x = rand()%30-30;

xyzvv.y = rand()%30-30;

xyzvv.z = rand()%30-30;

nuv = (rand()%314-314)/100.0;

fiv = (rand()%314-314)/100.0;

OnPaint();

CDialog::OnLButtonDown(nFlags, point);

}

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

void CLab3_PatrakeevDS_EVM092Dlg::OnRButtonDown(UINT nFlags, CPoint point)

{

// TODO: Add your message handler code here and/or call default

this->Invalidate();//очищаем клиентскую область

//обнуляем параметры вектора вращения

xyzvv.x = 0;

xyzvv.y = 0;

xyzvv.z = 0;

nuv = 0;

fiv = 0;

alfa = 0;

nu = 0.314;

//обнуляем массив точек октаэдра в мировом пространстве с длиной ребра 20 ед.

octm.t1.x = 0;

octm.t1.y = 0;

octm.t1.z = 14;

octm.t2.x = -10;

octm.t2.y = 10;

octm.t2.z = 0;

octm.t3.x = 10;

octm.t3.y = 10;

octm.t3.z = 0;

octm.t4.x = 10;

octm.t4.y = -10;

octm.t4.z = 0;

octm.t5.x = -10;

octm.t5.y = -10;

octm.t5.z = 0;

octm.t6.x = 0;

octm.t6.y = 0;

octm.t6.z = -14;

OnPaint();

CDialog::OnRButtonDown(nFlags, point);

}

Предварительно были объявлены нужные для работы библиотеки и глобальные переменные:

#include "func.h"

#include "math.h"

#include "time.h"

OctaedrXYZ octm = //задаём массив точек октаэдра в мировом пространстве с длиной ребра 20 ед.

{

{0,0,14},

{-10,10,0},

{10,10,0},

{10,-10,0},

{-10,-10,0},

{0,0,-14}

};

int p = 750;//расстояние от глаза до объекта

float nu = 0.314, fi = 0.785;//углы определяющие наклон вектора до глаза в мировых координатах

int d = 600;//расстояние до экрана

double nuv = 0, fiv = 0, alfa = 0;//характеристики вектора вращения и угла поворота

XYZ xyzvv = {0,0,0};//начальная точка вектора вращения определяемого в сферических координатах

Рисование на форме осуществляется модифицированной функцией OnPaint():

void CLab3_PatrakeevDS_EVM092Dlg::OnPaint()

{

if (IsIconic())

{

CPaintDC dc(this); // device context for painting

SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

// Center icon in client rectangle

int cxIcon = GetSystemMetrics(SM_CXICON);

int cyIcon = GetSystemMetrics(SM_CYICON);

CRect rect;

GetClientRect(&rect);

int x = (rect.Width() - cxIcon + 1) / 2;

int y = (rect.Height() - cyIcon + 1) / 2;

// Draw the icon

dc.DrawIcon(x, y, m_hIcon);

}

else

{

CDialog::OnPaint();

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

//листинг лабораторной работы

CDC* pDC = this->GetDC();//получение контекста устройства

CRect rect;

this->GetClientRect(&rect); //получаем размеры области вывода

//устанавливаем систему координат

pDC->SetMapMode(MM_ISOTROPIC);

pDC->SetWindowExt(100,100);

pDC->SetViewportExt(rect.Width(),-rect.Height());

pDC->SetViewportOrg(rect.Width()/2,rect.Height()/2);

//устанавливаем инструменты рисования

CBrush brush(RGB(255,0,0));

CPen pen(PS_SOLID,1,RGB(0,0,0));

CBrush* old_brush = pDC->SelectObject(&brush);

CPen* old_pen = pDC->SelectObject(&pen);

//рисуем оси

Osi(p,nu,fi,d,pDC);

//рисуем вектор вращения

Vector(xyzvv,p,nuv,fiv,d,pDC);

//рисуем октаэдр

OctaedrXYZ octv;

PreobIsMirVVid(octm.t1,&octv.t1,p,nu,fi);

PreobIsMirVVid(octm.t2,&octv.t2,p,nu,fi);

PreobIsMirVVid(octm.t3,&octv.t3,p,nu,fi);

PreobIsMirVVid(octm.t4,&octv.t4,p,nu,fi);

PreobIsMirVVid(octm.t5,&octv.t5,p,nu,fi);

PreobIsMirVVid(octm.t6,&octv.t6,p,nu,fi);

OctaedrXY octe;

Perspect(octv.t1,d,&octe.t1);

Perspect(octv.t2,d,&octe.t2);

Perspect(octv.t3,d,&octe.t3);

Perspect(octv.t4,d,&octe.t4);

Perspect(octv.t5,d,&octe.t5);

Perspect(octv.t6,d,&octe.t6);

Transform(&octm.t1,nuv,fiv,xyzvv,alfa);

Transform(&octm.t2,nuv,fiv,xyzvv,alfa);

Transform(&octm.t3,nuv,fiv,xyzvv,alfa);

Transform(&octm.t4,nuv,fiv,xyzvv,alfa);

Transform(&octm.t5,nuv,fiv,xyzvv,alfa);

Transform(&octm.t6,nuv,fiv,xyzvv,alfa);

Octaedr(octe,pDC);

}

}

Реализация пользовательских функций осуществлено в func.h:

#include "stdafx.h"

#include "math.h"

struct XYZ//объявляем структуру типа координат точки

{

int x;

int y;

int z;

};

struct XY//координаты точки в плоскости экрана

{

int x;

int y;

};

struct OctaedrXYZ//структура хранит координаты вершин октаэдра в мировом пространстве

{

XYZ t1;

XYZ t2;

XYZ t3;

XYZ t4;

XYZ t5;

XYZ t6;

};

struct OctaedrXY//структура хранит координаты вершин октаэдра в плоскости экрана

{

XY t1;

XY t2;

XY t3;

XY t4;

XY t5;

XY t6;

};

void Osi(int p, float nu, float fi, int d, CDC* pole)//рисование осей мировых координат

{

CBrush brush(RGB(255,0,0));

CPen pen(PS_SOLID,1,RGB(255,0,0));

CBrush* old_brush = pole->SelectObject(&brush);

CPen* old_pen = pole->SelectObject(&pen);

XYZ OXYZm[4] = //задаём точки для построения осей

{

{0,0,0},

{50,0,0},

{0,50,0},

{0,0,50}

};

XYZ OXYZv[4];

for (int i=0;i<=3;i++)//преобразуем координаты из мировых координат в видовые

{

int mir[4] = {OXYZm[i].x,OXYZm[i].y,OXYZm[i].z,1};

float V[4][4] =

{

{-sin(nu),-cos(fi)*cos(nu),-sin(fi)*cos(nu),0},

{cos(nu),-cos(fi)*sin(nu),-sin(fi)*sin(nu),0},

{0,sin(fi),-cos(fi),0},

{0,0,p,1}

};

float vidV [4] =

{

mir[0]*V[0][0]+mir[1]*V[1][0]+mir[2]*V[2][0]+mir[3]*V[3][0],

mir[0]*V[0][1]+mir[1]*V[1][1]+mir[2]*V[2][1]+mir[3]*V[3][1],

mir[0]*V[0][2]+mir[1]*V[1][2]+mir[2]*V[2][2]+mir[3]*V[3][2],

mir[0]*V[0][3]+mir[1]*V[1][3]+mir[2]*V[2][3]+mir[3]*V[3][3]

};

OXYZv[i].x = vidV[0];

OXYZv[i].y = vidV[1];

OXYZv[i].z = vidV[2];

}

XY OXYZ[4];

for (int j=0;j<=3;j++)//производим перспективные преобразования

{

//Perspect(OXYZv[j],d,&OXYZ[j]);

OXYZ[j].x = d*OXYZv[j].x/OXYZv[j].z;

OXYZ[j].y = d*OXYZv[j].y/OXYZv[j].z;

}

for (int k=1;k<=3;k++)

{

pole->MoveTo(OXYZ[0].x,OXYZ[0].y);

pole->LineTo(OXYZ[k].x,OXYZ[k].y);

}

pole->SelectObject(&old_brush);

pole->SelectObject(&old_pen);

}

void Vector(XYZ xyzvn,int p, float nuv, float fiv, int d, CDC* pole)//рисование вектора вращения

{

CBrush brush(RGB(255,0,0));

CPen pen(PS_SOLID,1,RGB(255,0,0));

CBrush* old_brush = pole->SelectObject(&brush);

CPen* old_pen = pole->SelectObject(&pen);

XYZ xyzvk;

xyzvk.x = 50*sin(fiv)*cos(nuv);

xyzvk.y = 50*sin(fiv)*sin(nuv);

xyzvk.z = 50*cos(fiv);

XYZ OXYZm[2] = //задаём точки для построения вектора

{

xyzvn,

xyzvk

};

XYZ OXYZv[2];

for (int i=0;i<=1;i++)//преобразуем координаты из мировых координат в видовые

{

int mir[4] = {OXYZm[i].x,OXYZm[i].y,OXYZm[i].z,1};

float V[4][4] =

{

{-sin(nuv),-cos(fiv)*cos(nuv),-sin(fiv)*cos(nuv),0},

{cos(nuv),-cos(fiv)*sin(nuv),-sin(fiv)*sin(nuv),0},

{0,sin(fiv),-cos(fiv),0},

{0,0,p,1}

};

float vidV [4] =

{

mir[0]*V[0][0]+mir[1]*V[1][0]+mir[2]*V[2][0]+mir[3]*V[3][0],

mir[0]*V[0][1]+mir[1]*V[1][1]+mir[2]*V[2][1]+mir[3]*V[3][1],

mir[0]*V[0][2]+mir[1]*V[1][2]+mir[2]*V[2][2]+mir[3]*V[3][2],

mir[0]*V[0][3]+mir[1]*V[1][3]+mir[2]*V[2][3]+mir[3]*V[3][3]

};

OXYZv[i].x = vidV[0];

OXYZv[i].y = vidV[1];

OXYZv[i].z = vidV[2];

}

XY OXYZ[2];

for (int j=0;j<=1;j++)//производим перспективные преобразования

{

OXYZ[j].x = d*OXYZv[j].x/OXYZv[j].z;

OXYZ[j].y = d*OXYZv[j].y/OXYZv[j].z;

}

pole->MoveTo(OXYZ[0].x,OXYZ[0].y);

pole->LineTo(OXYZ[1].x,OXYZ[1].y);

pole->SelectObject(&old_brush);

pole->SelectObject(&old_pen);

}

void Octaedr(OctaedrXY octe, CDC* pole)//рисование октаэдра

{

CBrush brush(RGB(255,255,255));

CPen pen(PS_SOLID,1,RGB(0,255,0));

CBrush* old_brush = pole->SelectObject(&brush);

CPen* old_pen = pole->SelectObject(&pen);

POINT mass[6];

mass[0].x=octe.t1.x;

mass[0].y=octe.t1.y;

mass[1].x=octe.t2.x;

mass[1].y=octe.t2.y;

mass[2].x=octe.t3.x;

mass[2].y=octe.t3.y;

mass[3].x=octe.t4.x;

mass[3].y=octe.t4.y;

mass[4].x=octe.t5.x;

mass[4].y=octe.t5.y;

mass[5].x=octe.t6.x;

mass[5].y=octe.t6.y;

POINT m1[3] = {mass[0],mass[1],mass[2]};

POINT m2[3] = {mass[5],mass[1],mass[2]};

POINT m3[3] = {mass[0],mass[2],mass[3]};

POINT m4[3] = {mass[5],mass[2],mass[3]};

POINT m5[3] = {mass[0],mass[3],mass[4]};

POINT m6[3] = {mass[5],mass[3],mass[4]};

POINT m7[3] = {mass[0],mass[4],mass[1]};

POINT m8[3] = {mass[5],mass[4],mass[1]};

pole->Polygon(m1,3);

pole->Polygon(m2,3);

pole->Polygon(m3,3);

pole->Polygon(m4,3);

pole->Polygon(m5,3);

pole->Polygon(m6,3);

pole->Polygon(m7,3);

pole->Polygon(m8,3);

pole->Polyline(m1,3);

pole->Polyline(m2,3);

pole->Polyline(m3,3);

pole->Polyline(m4,3);

pole->Polyline(m5,3);

pole->Polyline(m6,3);

pole->Polyline(m7,3);

pole->Polyline(m8,3);

pole->SelectObject(&old_brush);

pole->SelectObject(&old_pen);

}

void Transform(XYZ* xyz, double nu, double fi, XYZ xyzvn, double alfa)//вращение точки вокруг вектора с входными параметрами

{

double r11 = cos(nu)*(cos(nu)*pow(sin(fi),2)+cos(fi)*(sin(nu)*sin(alfa)+cos(alfa)*cos(nu)*cos(fi)))+

sin(nu)*(cos(alfa)*sin(nu)-cos(nu)*cos(fi)*sin(alfa));//

double r12 = sin(nu)*(cos(nu)*pow(sin(fi),2)+cos(fi)*(sin(alfa)*sin(nu)+cos(alfa)*cos(nu)*cos(fi)))-

cos(nu)*(cos(alfa)*sin(nu)-cos(nu)*cos(fi)*sin(alfa));//

double r13 = cos(nu)*cos(fi)*sin(fi)-sin(fi)*(sin(alfa)*sin(nu)+cos(alfa)*cos(nu)*cos(fi));//

double r21 = cos(nu)*(sin(nu)*pow(sin(fi),2)-cos(fi)*(cos(nu)*sin(alfa)-cos(alfa)*sin(nu)*cos(fi)))-

sin(nu)*(cos(alfa)*cos(nu)+sin(nu)*cos(fi)*sin(alfa));//

double r22 = sin(nu)*(sin(nu)*pow(sin(fi),2)-cos(fi)*(sin(alfa)*cos(nu)-cos(alfa)*sin(nu)*cos(fi)))+

cos(nu)*(cos(alfa)*cos(nu)+sin(nu)*cos(fi)*sin(alfa));//

double r23 = cos(fi)*sin(nu)*sin(fi)+sin(fi)*(sin(alfa)*cos(nu)-cos(alfa)*sin(nu)*cos(fi));//

double r31 = cos(nu)*(cos(fi)*sin(fi)-sin(fi)*cos(alfa)*cos(fi))+sin(fi)*sin(alfa)*sin(nu);//

double r32 = sin(nu)*(cos(fi)*sin(fi)-cos(alfa)*cos(fi)*sin(fi))-cos(nu)*sin(alfa)*sin(fi);//

double r33 = pow(sin(fi),2)*cos(alfa)+pow(cos(fi),2);//

xyz->x = r11*xyz->x+r21*xyz->y+r31*xyz->z-r11*xyzvn.x-r21*xyzvn.y-r31*xyzvn.z+xyzvn.x;

xyz->y = r12*xyz->x+r22*xyz->y+r32*xyz->z-r12*xyzvn.x-r22*xyzvn.y-r32*xyzvn.z+xyzvn.y;

xyz->z = r13*xyz->x+r23*xyz->y+r33*xyz->z-r13*xyzvn.x-r23*xyzvn.y-r33*xyzvn.z+xyzvn.z;

}

void PreobIsMirVVid(XYZ Mir, XYZ* Vid, int p, float nu, float fi)

{

int mir[4] = {Mir.x,Mir.y,Mir.z,1};

float V[4][4] =

{

{-sin(nu),-cos(fi)*cos(nu),-sin(fi)*cos(nu),0},

{cos(nu),-cos(fi)*sin(nu),-sin(fi)*sin(nu),0},

{0,sin(fi),-cos(fi),0},

{0,0,p,1}

};

float vidV [4] =

{

mir[0]*V[0][0]+mir[1]*V[1][0]+mir[2]*V[2][0]+mir[3]*V[3][0],

mir[0]*V[0][1]+mir[1]*V[1][1]+mir[2]*V[2][1]+mir[3]*V[3][1],

mir[0]*V[0][2]+mir[1]*V[1][2]+mir[2]*V[2][2]+mir[3]*V[3][2],

mir[0]*V[0][3]+mir[1]*V[1][3]+mir[2]*V[2][3]+mir[3]*V[3][3]

};

Vid->x = vidV[0];

Vid->y = vidV[1];

Vid->z = vidV[2];

}

void Perspect(XYZ Vid, int d ,XY* xy)

{

xy->x = d*Vid.x/Vid.z;

xy->y = d*Vid.y/Vid.z;

}