Построение 3D-графика функции

Запустив программу, вы видите на экране график функции z = x / y.
Вы можете изменить масштаб графика, нажимая +/-.
Вы можете изменить угол зрения. Для этого сначала нажмите <NumLock>, после чего включится дополнительная цифровая клавиатура. Нажимая стрелки, вы измените угол зрения. Нажав <5>, вы вернётесь к исходной точке и масштабу.
Сделано под Windows 98 на Visual C++ 6.0.
Скачать программу, код, инструкцию: https://yadi.sk/d/bXK0rNYX6NZ4LQ

Построение 3D-графика функции - 884681091047
Построение 3D-графика функции - 884681090791
Построение 3D-графика функции - 884681090535
// p3View.cpp : implementation of the CP3View class
//


#include "stdafx.h"
#include <math.h>
#include "p3.h"

#include "p3Doc.h"
#include "p3View.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


// Данные задачи

double xa, ya, za; // вектор ориентации в пространстве осей системы координат ("определяющий вектор") - смотрит на наблюдателя (ось Oz)
double xb, yb, zb; // ось Ox в 3D
double xc, yc, zc; // ось Oy в 3D

int scale; // масштаб графика
int flag; // флаг рисования отрезка в 3D: 0 - не рисовать; 1 - первая точка отрезка; 2 - вторая точка отрезка
int number; // номер графика
int aa;

void initialize (); // инициализация исходных данных перед построением графика
void calculate (); // расчёт векторов осей Oz, Ox, Oy
void draw (CDC *); // рисование графика
void line (double, double, double, double, double, double, CDC *); // рисование линии в 3D

double f1 (double, double); // функция z = f (x, y), график которой строится


/////////////////////////////////////////////////////////////////////////////
// CP3View

IMPLEMENT_DYNCREATE(CP3View, CView)

BEGIN_MESSAGE_MAP(CP3View, CView)
//{{AFX_MSG_MAP(CP3View)
ON_WM_CHAR()
//}}AFX_MSG_MAP
// Standard printing commands
ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CP3View construction/destruction

CP3View::CP3View()
{
number = 1; // номер графика функции
aa = 0;
initialize ();
}

CP3View::~CP3View()
{
}

BOOL CP3View::PreCreateWindow(CREATESTRUCT& cs)
{
return CView::PreCreateWindow(cs);
}

/////////////////////////////////////////////////////////////////////////////
// CP3View drawing

void CP3View::OnDraw (CDC *pDC)
{
CP3Doc *pdoc = GetDocument ();
ASSERT_VALID (pdoc);
CString a;

calculate ();
draw (pDC); // рисование 3D-графика

// рисование осей координат в 3D
line (500, 0, 0, -500, 0, 0, pDC);
line (0, 500, 0, 0, -500, 0, pDC);
line (0, 0, 0, 0, 0, 500, pDC);
a.Format ("key = %i.", aa);
pDC -> TextOut (10, 10, a);
}

/////////////////////////////////////////////////////////////////////////////
// CP3View printing

BOOL CP3View::OnPreparePrinting(CPrintInfo* pInfo)
{
// default preparation
return DoPreparePrinting(pInfo);
}

void CP3View::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
}

void CP3View::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
}

/////////////////////////////////////////////////////////////////////////////
// CP3View diagnostics

#ifdef _DEBUG
void CP3View::AssertValid() const
{
CView::AssertValid();
}

void CP3View::Dump(CDumpContext& dc) const
{
CView::Dump(dc);
}

CP3Doc* CP3View::GetDocument() // non-debug version is inline
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CP3Doc)));
return (CP3Doc*)m_pDocument;
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CP3View message handlers

void CP3View::OnChar (UINT nChar, UINT nRepCnt, UINT nFlags)
{
double a, b; // временные переменные

switch (nChar)
{
case '5': // возврат к значениям по умолчанию
initialize ();
break;

case 'a': // график первой функции
number = 1;
break;

case '4': // смещение графика влево <Left arrow>
a = xa * cos (.1) + ya * sin (.1);
b = -xa * sin (.1) + ya * cos (.1);
xa = a;
ya = b;
break;

case '6': // смещение графика вправо <Right arrow>
a = xa * cos (.1) - ya * sin (.1);
b = xa * sin (.1) + ya * cos (.1);
xa = a;
ya = b;
break;

case '8': // смещение графика вверх <Up arrow>
xa -= xb * sin (.1);
ya -= yb * sin (.1);
za -= zb * sin (.1);
break;

case '2': // смещение графика вниз <Down arrow>
xa += xb * sin (.1);
ya += yb * sin (.1);
za += zb * sin (.1);
break;

case '+': // увеличение масштаба
scale = (int) (scale * 1.3);
break;

case '-': // уменьшение масштаба
scale = (int) (scale / 1.3);
if (scale == 0) scale = 1;
}

CView::OnChar (nChar, nRepCnt, nFlags);
aa = nChar;
Invalidate ();
}


void initialize ()
{
xa = ya = za = 1; // определяющий вектор
xc = yc = zc = 0; // вектор направления оси Oy
scale = 50; // масштаб
}


void calculate ()
{
double a, b, c; // вспомогательные переменные

// 1. Нормирование определяющего вектора
a = sqrt (xa * xa + ya * ya + za * za);
xa /= a;
ya /= a;
za /= a;

// 2. Проекция вектора (0, 0, 1) на определяющий вектор
a = xa * za;
b = ya * za;
c = za * za;

xb = -a;
yb = -b;
zb = 1 - c;

// 3. Нормирование вектора оси Ox
a = sqrt (xb * xb + yb * yb + zb * zb);
if (a == 0) return;
xb /= a;
yb /= a;
zb /= a;

// 4. Вычисление вектора оси Oy; векторное произведение двух других осей.
a = ya * zb - za * yb;
b = za * xb - xa * zb;
c = xa * yb - ya * xb;

// 5. Инверсия левой тройки векторов
if (a * xc + b * yc + c * zc < 0)
{
xb = -xb; yb = -yb; zb = -zb;
xc = -a; yc = -b; zc = -c;
}
else {xc = a; yc = b; zc = c;}
}


void draw (CDC *pDC)
{
int a, b;
double d, e;

e = 0;
for (a = -500; a <= 500; a += 30) // проходим значения x
{
flag = 0;
for (b = -500; b <= 500; b++) // проходим значения y
{
switch (number) // выбираем, график какой функции строится
{
case 1:
d = f1 ((double) a / scale, (double) b / scale) * scale;
break;
default:
d = 0;
}

// Если имеются две рассчитанные точки, строим линию в 3D
if (flag == 2) line (a, b - 1, e, a, b, d, pDC);
e = d;
}
}

for (b = -500; b <= 500; b += 30) // проходим значения y
{
flag = 0;
for (a = -500; a <= 500; a++) // проходим значения x
{
switch (number) // выбираем, график какой функции строится
{
case 1:
d = f1 ((double) a / scale, (double) b / scale) * scale;
break;
default:
d = 0;
}

// Если имеются две рассчитанные точки, строим линию в 3D
if (flag == 2) line (a - 1, b, e, a, b, d, pDC);
e = d;
}
}
}


void line (double a, double b, double c, double d, double e, double f, CDC *pDC)
{
double g, h; // первая точка на плоскости
double i, j; // вторая точка на плоскости

g = a * xb + b * yb + c * zb;
h = a * xc + b * yc + c * zc; // проекция первого вектора на ось Oy
i = d * xb + e * yb + f * zb;
j = d * xc + e * yc + f * zc; // проекция второго вектора на ось Oy

if (g > 1500) g = 1500;
if (g < -1500) g = -1500;
if (i > 1500) i = 1500;
if (i < -1500) i = -1500;

pDC -> MoveTo (400 - (int) h, 400 - (int) g);
pDC -> LineTo (400 - (int) j, 400 - (int) i);
}


double f1 (double x, double y)
{
double z;

if (y == 0) {flag = 0; return 0;} // область определения функции
z = x / y; // функция, график которой надо построить

if (flag < 2) flag++;
if (z > 100) {flag = 0; return 0;}
if (z < -100) {flag = 0; return 0;}

return z;
}

Комментарии

Комментариев нет.