среда, 10 августа 2011 г.

Программа для вывода графика на языке C++.

Для того чтобы вывести график не используя маткад, как описано в предыдущей статье, была написана программа исходный код которой приведен ниже. Изменяя переменные 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 созданные программой код которой приведен в предыдущей статье. Ниже приведен график построенный по значениям из этих файлов.
график напряжения на конденсаторе емкостного фильтра
Увеличив число рассчитываемых точек в программе из предыдущей статьи и изменив соответствующим образом исходный код программы приведенный здесь можно достроить график дальше до установившегося значения напряжения на конденсаторе. Если необходимо показать точки то можно раскомментировать код показа точек.

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

Отправить комментарий