Для того чтобы вывести график не используя маткад, как описано в предыдущей статье, была написана программа исходный код которой приведен ниже. Изменяя переменные steepVG и steepHG, в коде, можно настроить программу для показа разных графиков. steepVG - шаг по вертикали, steepHG - шаг по горизонтали. Также может понадобиться умножать загруженные значения на некоторые коэффициенты. В коде прорисовки графика значения из массива t умножаются на 10 чтобы график вытянулся по оси времени. Можно изменить надписи у горизонтальной и/или вертикальной осей,
например заменить:
glCallLists(strlen("U,B"), GL_UNSIGNED_BYTE, "U,B");
на:
glCallLists(strlen("I,A"), GL_UNSIGNED_BYTE, "I,A");
и выводить график тока.
В программе используются функции OpenGL поэтому в параметры проекта надо включить файл lopengl32.lib. Если используется Dev C++ то это можно сделать как показано на скриншоте ниже. Проект - параметры проекта - параметры - компоновщик - добавить библиотеку.
Исходный код программы:
#include < windows.h >
#include < gl/gl.h >
#include < stdio.h >
HDC hDC;
float fI;
int B;
float steepVG=1.0f;//steep vertical grid
float steepHG=0.1f;//steep horizontal grid
char buf[100];//буфер для разных случаев
float t[100],Uc[100];
FILE *t_stream;
FILE *u_stream;
LRESULT CALLBACK WndProc (HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam);
void glEnable (HWND hWnd, HGLRC *hRC);
void glDisable(HWND hWnd, HGLRC hRC);
void gPrint(float val);
int WINAPI WinMain (HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int iCmdShow)
{
WNDCLASS wc;
HWND hWnd;
HGLRC hRC;
MSG msg;
BOOL bQuit = FALSE;
wc.style = CS_OWNDC;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor (NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH) GetStockObject (BLACK_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = "gr";
RegisterClass (&wc);
hWnd = CreateWindow ("gr", "График",
WS_CAPTION | WS_POPUPWINDOW | WS_VISIBLE,
80, 50, 700, 500,
NULL, NULL, hInstance, NULL);
glEnable(hWnd, &hRC);
while (!bQuit)
{
if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
{
bQuit = TRUE;
}
else
{
TranslateMessage (&msg);
DispatchMessage (&msg);
}
}
else
{
//здесь код OpenGL
glClearColor (1.0f, 1.0f, 1.0f, 0.0f);
glClear (GL_COLOR_BUFFER_BIT);
//прорисовка сетки
glColor3f( 0.0f, 1.0f, 0.0f );
glLineWidth(1);
glBegin(GL_LINES);
for(fI=(-0.9f);fI<0.9f;fI+=0.1f)
{
glVertex2f(fI, -0.9f);glVertex2f(fI, 0.9f);//vertical grid
}
for(fI=(-0.9f);fI<0.9f;fI+=0.1f)
{
glVertex2f(-0.9f, fI);glVertex2f(0.9f, fI);//horizontal grid
}
glEnd();
//надписи у вертикальной оси
glColor3f( 0.0f, 0.0f, 0.0f );
glRasterPos2f(-0.98f, 0.9f);
glCallLists(strlen("U,B"), GL_UNSIGNED_BYTE, "U,B");
for(fI=(-0.9f);fI<0.9f;fI+=0.1f)
{
glRasterPos2f(-0.98f, fI-0.01f);
gPrint(fI*steepVG);
}
//надписи у горизонтальной оси
glRasterPos2f(0.85f, 0.05f);
glCallLists(strlen("t,c"), GL_UNSIGNED_BYTE, "t,c");
for(fI=(-1.0f);fI<0.9f;fI+=0.1f)
{
glRasterPos2f(fI+0.05f,-0.95f);
gPrint((fI+1.0f)*steepHG);
}
//прорисовка осей
glColor3f( 0.0f, 0.0f, 0.0f );
glLineWidth(1);
glBegin(GL_LINES);
glVertex2f( -0.9f, 0.0f );glVertex2f( 0.9f, 0.0f );//horizontal axis
glVertex2f( 0.9f, 0.0f );glVertex2f( 0.85f, -0.015f );
glVertex2f( 0.9f, 0.0f );glVertex2f( 0.85f, 0.015f );
glVertex2f( -0.9f, -0.9f);glVertex2f( -0.9f, 0.9f);//vertical axis
glVertex2f( -0.9f, 0.9f);glVertex2f( -0.91f, 0.85f);
glVertex2f( -0.9f, 0.9f);glVertex2f( -0.89f, 0.85f);
glEnd();
//прорисовка графика
glColor3f( 1.0f, 0.0f, 0.0f );
glBegin(GL_LINE_STRIP);
for(int i=0;i<100;i++)
{
glVertex2f( (t[i]*10.0f)-0.9f, Uc[i]);
}
glEnd();
//можно раскомментировать для показа точек
/*
glPointSize(3);
glColor3f( 0.0f, 0.0f, 1.0f );
glBegin(GL_POINTS);
for(int i=0;i<100;i++)
{
glVertex2f((t[i]*10.0f)-0.9f,Uc[i]);
}
glEnd();
*/
SwapBuffers (hDC);
}
}
glDisable(hWnd, hRC);
DestroyWindow (hWnd);
return msg.wParam;
}
LRESULT CALLBACK WndProc (HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
//загрузка значений в массивы t и Uc
if((t_stream=fopen("time.txt","r"))&&(u_stream=fopen("voltage.txt","r")))
{
for (int i=0;i<100;i++)
{
fgets(buf, 100, t_stream);
t[i]=atof(buf);
fgets(buf, 100, u_stream);
Uc[i]=atof(buf);
}
fclose(t_stream);
fclose(u_stream);
}
else MessageBox ( NULL,"Файл не найден","Error" , MB_OK);
return 0;
case WM_CLOSE:
PostQuitMessage (0);
return 0;
case WM_KEYDOWN:
switch (wParam)
{
case VK_ESCAPE:
PostQuitMessage(0);
return 0;
}
return 0;
default:
return DefWindowProc (hWnd, message, wParam, lParam);
}
}
void glEnable (HWND hWnd, HGLRC *hRC)
{
PIXELFORMATDESCRIPTOR pfd;
int iFormat;
HFONT font;
hDC = GetDC (hWnd);
ZeroMemory (&pfd, 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.cColorBits = 24;
pfd.cDepthBits = 16;
pfd.iLayerType = PFD_MAIN_PLANE;
iFormat = ChoosePixelFormat (hDC, &pfd);
SetPixelFormat (hDC, iFormat, &pfd);
*hRC = wglCreateContext(hDC);
wglMakeCurrent(hDC,*hRC);
B = glGenLists(255);
font=CreateFont(-10,0,0,0,FW_BOLD,FALSE,FALSE,FALSE,ANSI_CHARSET,OUT_TT_PRECIS,
CLIP_DEFAULT_PRECIS,ANTIALIASED_QUALITY,FF_DONTCARE|DEFAULT_PITCH,"Arial");
SelectObject(hDC, font);
wglUseFontBitmaps(hDC,1,255,B);
}
void glDisable (HWND hWnd, HGLRC hRC)
{
wglMakeCurrent (NULL, NULL);
wglDeleteContext (hRC);
ReleaseDC (hWnd, hDC);
glDeleteLists(B,255);
}
void gPrint(float val)
{
sprintf(buf,"%f",val);
glCallLists(5,GL_UNSIGNED_BYTE,buf);
}
В обработчике событий WndProc находиться код загрузки значений. Файлы из которых загружаются значения должны быть в той же папке что и программа, иметь формат txt, содержать значения расположенные по порядку в каждой строке и называться time и voltage. Для примера можно взять файлы time.txt и voltage.txt созданные программой код которой приведен в предыдущей статье. Ниже приведен график построенный по значениям из этих файлов.
Увеличив число рассчитываемых точек в программе из предыдущей статьи и изменив соответствующим образом исходный код программы приведенный здесь можно достроить график дальше до установившегося значения напряжения на конденсаторе. Если необходимо показать точки то можно раскомментировать код показа точек.
например заменить:
glCallLists(strlen("U,B"), GL_UNSIGNED_BYTE, "U,B");
на:
glCallLists(strlen("I,A"), GL_UNSIGNED_BYTE, "I,A");
и выводить график тока.
В программе используются функции OpenGL поэтому в параметры проекта надо включить файл lopengl32.lib. Если используется Dev C++ то это можно сделать как показано на скриншоте ниже. Проект - параметры проекта - параметры - компоновщик - добавить библиотеку.
Исходный код программы:
#include < windows.h >
#include < gl/gl.h >
#include < stdio.h >
HDC hDC;
float fI;
int B;
float steepVG=1.0f;//steep vertical grid
float steepHG=0.1f;//steep horizontal grid
char buf[100];//буфер для разных случаев
float t[100],Uc[100];
FILE *t_stream;
FILE *u_stream;
LRESULT CALLBACK WndProc (HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam);
void glEnable (HWND hWnd, HGLRC *hRC);
void glDisable(HWND hWnd, HGLRC hRC);
void gPrint(float val);
int WINAPI WinMain (HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int iCmdShow)
{
WNDCLASS wc;
HWND hWnd;
HGLRC hRC;
MSG msg;
BOOL bQuit = FALSE;
wc.style = CS_OWNDC;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor (NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH) GetStockObject (BLACK_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = "gr";
RegisterClass (&wc);
hWnd = CreateWindow ("gr", "График",
WS_CAPTION | WS_POPUPWINDOW | WS_VISIBLE,
80, 50, 700, 500,
NULL, NULL, hInstance, NULL);
glEnable(hWnd, &hRC);
while (!bQuit)
{
if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
{
bQuit = TRUE;
}
else
{
TranslateMessage (&msg);
DispatchMessage (&msg);
}
}
else
{
//здесь код OpenGL
glClearColor (1.0f, 1.0f, 1.0f, 0.0f);
glClear (GL_COLOR_BUFFER_BIT);
//прорисовка сетки
glColor3f( 0.0f, 1.0f, 0.0f );
glLineWidth(1);
glBegin(GL_LINES);
for(fI=(-0.9f);fI<0.9f;fI+=0.1f)
{
glVertex2f(fI, -0.9f);glVertex2f(fI, 0.9f);//vertical grid
}
for(fI=(-0.9f);fI<0.9f;fI+=0.1f)
{
glVertex2f(-0.9f, fI);glVertex2f(0.9f, fI);//horizontal grid
}
glEnd();
//надписи у вертикальной оси
glColor3f( 0.0f, 0.0f, 0.0f );
glRasterPos2f(-0.98f, 0.9f);
glCallLists(strlen("U,B"), GL_UNSIGNED_BYTE, "U,B");
for(fI=(-0.9f);fI<0.9f;fI+=0.1f)
{
glRasterPos2f(-0.98f, fI-0.01f);
gPrint(fI*steepVG);
}
//надписи у горизонтальной оси
glRasterPos2f(0.85f, 0.05f);
glCallLists(strlen("t,c"), GL_UNSIGNED_BYTE, "t,c");
for(fI=(-1.0f);fI<0.9f;fI+=0.1f)
{
glRasterPos2f(fI+0.05f,-0.95f);
gPrint((fI+1.0f)*steepHG);
}
//прорисовка осей
glColor3f( 0.0f, 0.0f, 0.0f );
glLineWidth(1);
glBegin(GL_LINES);
glVertex2f( -0.9f, 0.0f );glVertex2f( 0.9f, 0.0f );//horizontal axis
glVertex2f( 0.9f, 0.0f );glVertex2f( 0.85f, -0.015f );
glVertex2f( 0.9f, 0.0f );glVertex2f( 0.85f, 0.015f );
glVertex2f( -0.9f, -0.9f);glVertex2f( -0.9f, 0.9f);//vertical axis
glVertex2f( -0.9f, 0.9f);glVertex2f( -0.91f, 0.85f);
glVertex2f( -0.9f, 0.9f);glVertex2f( -0.89f, 0.85f);
glEnd();
//прорисовка графика
glColor3f( 1.0f, 0.0f, 0.0f );
glBegin(GL_LINE_STRIP);
for(int i=0;i<100;i++)
{
glVertex2f( (t[i]*10.0f)-0.9f, Uc[i]);
}
glEnd();
//можно раскомментировать для показа точек
/*
glPointSize(3);
glColor3f( 0.0f, 0.0f, 1.0f );
glBegin(GL_POINTS);
for(int i=0;i<100;i++)
{
glVertex2f((t[i]*10.0f)-0.9f,Uc[i]);
}
glEnd();
*/
SwapBuffers (hDC);
}
}
glDisable(hWnd, hRC);
DestroyWindow (hWnd);
return msg.wParam;
}
LRESULT CALLBACK WndProc (HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
//загрузка значений в массивы t и Uc
if((t_stream=fopen("time.txt","r"))&&(u_stream=fopen("voltage.txt","r")))
{
for (int i=0;i<100;i++)
{
fgets(buf, 100, t_stream);
t[i]=atof(buf);
fgets(buf, 100, u_stream);
Uc[i]=atof(buf);
}
fclose(t_stream);
fclose(u_stream);
}
else MessageBox ( NULL,"Файл не найден","Error" , MB_OK);
return 0;
case WM_CLOSE:
PostQuitMessage (0);
return 0;
case WM_KEYDOWN:
switch (wParam)
{
case VK_ESCAPE:
PostQuitMessage(0);
return 0;
}
return 0;
default:
return DefWindowProc (hWnd, message, wParam, lParam);
}
}
void glEnable (HWND hWnd, HGLRC *hRC)
{
PIXELFORMATDESCRIPTOR pfd;
int iFormat;
HFONT font;
hDC = GetDC (hWnd);
ZeroMemory (&pfd, 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.cColorBits = 24;
pfd.cDepthBits = 16;
pfd.iLayerType = PFD_MAIN_PLANE;
iFormat = ChoosePixelFormat (hDC, &pfd);
SetPixelFormat (hDC, iFormat, &pfd);
*hRC = wglCreateContext(hDC);
wglMakeCurrent(hDC,*hRC);
B = glGenLists(255);
font=CreateFont(-10,0,0,0,FW_BOLD,FALSE,FALSE,FALSE,ANSI_CHARSET,OUT_TT_PRECIS,
CLIP_DEFAULT_PRECIS,ANTIALIASED_QUALITY,FF_DONTCARE|DEFAULT_PITCH,"Arial");
SelectObject(hDC, font);
wglUseFontBitmaps(hDC,1,255,B);
}
void glDisable (HWND hWnd, HGLRC hRC)
{
wglMakeCurrent (NULL, NULL);
wglDeleteContext (hRC);
ReleaseDC (hWnd, hDC);
glDeleteLists(B,255);
}
void gPrint(float val)
{
sprintf(buf,"%f",val);
glCallLists(5,GL_UNSIGNED_BYTE,buf);
}
В обработчике событий WndProc находиться код загрузки значений. Файлы из которых загружаются значения должны быть в той же папке что и программа, иметь формат txt, содержать значения расположенные по порядку в каждой строке и называться time и voltage. Для примера можно взять файлы time.txt и voltage.txt созданные программой код которой приведен в предыдущей статье. Ниже приведен график построенный по значениям из этих файлов.
Комментариев нет:
Отправить комментарий