Advertisement
CherMi

Charts

Dec 15th, 2019
227
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 12.62 KB | None | 0 0
  1. // This is a personal academic project. Dear PVS-Studio, please check it.
  2.  
  3. // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
  4. #define _CRT_SECURE_NO_WARNINGS
  5.  
  6. #include <stdio.h>
  7. #include "graphical_output.h"
  8.  
  9. int N_gl = 0;
  10. float *x_gl = NULL;
  11. float *A_gl = NULL;
  12. float *phi_gl = NULL;
  13. float *Re_gl = NULL;
  14. float *Im_gl = NULL;
  15.  
  16. void draw_and_save_chart(int N, float *x, float *A, float *phi, float *Re, float *Im)
  17. {
  18.     N_gl = N;
  19.     x_gl = x;
  20.     A_gl = A;
  21.     phi_gl = phi;
  22.     Re_gl = Re;
  23.     Im_gl = Im;
  24.  
  25.     max_x = 1250;
  26.     max_y = 700;
  27.     initWindow();
  28. }
  29.  
  30. void initWindow()
  31. {
  32.     //Получаем хендл приложения, потребуется при создании класса окна и самого окна.
  33.     HINSTANCE histance = GetModuleHandleW(NULL);
  34.  
  35.     //Создаем класс окна.
  36.     WNDCLASSEX wclass = { 0 }; //Заполнять будем не все поля, остальные будут равны 0
  37.     wclass.cbSize = sizeof(WNDCLASSEX); //По размеру структуры Windows определит, какая версия API была использована
  38.     wclass.style = CS_HREDRAW | CS_VREDRAW; //Перерисовываться при изменении размеров окна
  39.     wclass.lpfnWndProc = WndProc; //Указываем функцию обработки сообщений.
  40.     wclass.hInstance = histance; //Указываем хендл приложения.
  41.     wclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); //GetStockObject возвращает хендл на белую кисточку, для фона окна
  42.     wclass.lpszClassName = (LPCSTR)"CHARTS"; //Имя данного класса, должно быть уникальным, иначе, если класс с таким именем уже зарегестрирован, то в регистрации будет отказано.
  43.     //Регистрируем класс окна.
  44.     RegisterClassEx(&wclass);
  45.  
  46.     //Создаем окно.
  47.     HWND window = CreateWindowExW(
  48.         0,
  49.         L"CHARTS", //Имя класса.
  50.         L"Charts", //Заголовок окна.
  51.         WS_OVERLAPPEDWINDOW,  //Тип окна, влияет на отображение системного меню, кнопок в верхнем правом углу и т.п.
  52.         0, 0, //Координаты окна.
  53.         1250, 750, //Ширина окна.
  54.         0, //Ссылка на родительское окно.
  55.         0, //Хендл меню.
  56.         histance, //Хендл приложения, получаем его функцией GetModuleHandleW.
  57.         0
  58.     );
  59.  
  60.     //Показываем окно, если этого не сделать окно не будет отображено.
  61.     ShowWindow(window, SW_SHOW);
  62.     //Обновляем окно.
  63.     UpdateWindow(window);
  64.  
  65.     //Запускаем цикл обработки сообщений окна.
  66.     MSG msg = { 0 };
  67.     while (GetMessage(&msg, 0, 0, 0)) {
  68.         TranslateMessage(&msg);  //Преобразуем виртуальную клавишу в ASCII-код и посылаем сообщение WM_CHAR (тут не нужно.Необходимо, если надо работать с текстом, вводимым с клавиатуры)
  69.         DispatchMessage(&msg);  //Передаем сообщения для обработки в "главную функцию обработки сообщений"
  70.     }
  71.  
  72.     return;
  73. }
  74.  
  75. LRESULT CALLBACK WndProc(HWND hWnd, UINT messg, WPARAM wParam, LPARAM lParam)
  76. {
  77.     PAINTSTRUCT ps;
  78.     RECT Rect;
  79.     HDC hCmpDC;
  80.     HBITMAP hBmp;
  81.  
  82.     switch (messg)
  83.     {
  84.     case WM_PAINT:
  85.         GetClientRect(hWnd, &Rect);
  86.         hdc = BeginPaint(hWnd, &ps);
  87.  
  88.         // Создание теневого контекста для двойной буферизации
  89.         hCmpDC = CreateCompatibleDC(hdc);
  90.         hBmp = CreateCompatibleBitmap(hdc, Rect.right - Rect.left,
  91.             Rect.bottom - Rect.top);
  92.         SelectObject(hCmpDC, hBmp);
  93.  
  94.         // Закраска фоновым цветом
  95.         LOGBRUSH br;
  96.         br.lbStyle = BS_SOLID;
  97.         br.lbColor = 0xFFFFFF;
  98.         HBRUSH brush;
  99.         brush = CreateBrushIndirect(&br);
  100.         FillRect(hCmpDC, &Rect, brush);
  101.         DeleteObject(brush);
  102.         draw_charts(hCmpDC, 30, 30);
  103.         // Здесь рисуем на контексте hCmpDC
  104.         SaveBMPFile("C:\\test\\chart.bmp", hBmp, hCmpDC, max_x - 20, max_y);
  105.         // Копируем изображение из теневого контекста на экран
  106.         SetStretchBltMode(hdc, COLORONCOLOR);
  107.         BitBlt(hdc, 0, 0, Rect.right - Rect.left, Rect.bottom - Rect.top,
  108.             hCmpDC, 0, 0, SRCCOPY);
  109.         // Удаляем ненужные системные объекты
  110.         DeleteDC(hCmpDC);
  111.         DeleteObject(hBmp);
  112.         hCmpDC = NULL;
  113.  
  114.         EndPaint(hWnd, &ps);
  115.         break;
  116.  
  117.     case WM_DESTROY:
  118.         PostQuitMessage(0);
  119.         break;
  120.  
  121.     default:
  122.         return (DefWindowProc(hWnd, messg, wParam, lParam));
  123.     }
  124.     return (0);
  125. }
  126.  
  127. void draw_charts(HDC hdc, int offset_x, int offset_y) {
  128.     int cur_x, cur_y;
  129.     int length_x, length_y;
  130.     int i;
  131.     char str[10];
  132.  
  133.     draw_X(hdc, offset_x, offset_y);
  134.  
  135.     //Четыре графика друг под другим
  136.     length_x = max_x / 2 - 2 * offset_x;
  137.     length_y = (max_y - 8 * offset_y) / 4;
  138.     cur_x = max_x / 2 + offset_x;
  139.     cur_y = offset_y;
  140.  
  141.     draw_point_chart(hdc, offset_x, offset_y, length_x, length_y, max_x/2 + offset_x, offset_y + length_y / 2, Re_gl, "u", "Re(F(u))");
  142.     draw_point_chart(hdc, offset_x, offset_y, length_x, length_y, max_x/2 + offset_x, 3 * offset_y + length_y + length_y / 2, Im_gl, "u", "Im(F(u))");
  143.     draw_point_chart(hdc, offset_x, offset_y, length_x, length_y, max_x/2 + offset_x, 5 * offset_y + 2 * length_y + length_y / 2, A_gl, "u", "A(u)");
  144.     draw_point_chart(hdc, offset_x, offset_y, length_x, length_y, max_x/2 + offset_x, 7 * offset_y + 3 * length_y + length_y / 2, phi_gl, "u", "phi");
  145. }
  146.  
  147. void draw_X(HDC hdc, int offset_x, int offset_y)
  148. {
  149.     char str[10];
  150.     int length_x, length_y;
  151.     int cur_x, cur_y, prev_x, prev_y;
  152.     int del_x, del_y;
  153.     int i;
  154.     float y_max = 0, y;
  155.  
  156.     length_x = max_x / 2 - 2 * offset_x;
  157.     length_y = max_y - 4 * offset_y;
  158.  
  159.     MoveToEx(hdc, offset_x, 2 * offset_y, NULL); //Ось y
  160.     LineTo(hdc, offset_x, 2 * offset_y + length_y);
  161.     TextOut(hdc, offset_x - 20, 2 * offset_y - 10, L"X[k]", 1);
  162.  
  163.     MoveToEx(hdc, offset_x, length_y / 2 + 2 * offset_y, NULL); //Ось x
  164.     LineTo(hdc, offset_x + length_x, length_y / 2 + 2 * offset_y);
  165.     TextOut(hdc, offset_x + length_x, length_y / 2 + 2 * offset_y, L"k", 1);
  166.  
  167.     MoveToEx(hdc, offset_x - 3, 2 * offset_y + 5, NULL); //Стрелка на оси y
  168.     LineTo(hdc, offset_x, 2 * offset_y);
  169.     LineTo(hdc, offset_x + 3, 2 * offset_y + 5);
  170.  
  171.     MoveToEx(hdc, offset_x + length_x - 5, length_y / 2 + 2 * offset_y - 3, NULL); //Стрелка на оси x
  172.     LineTo(hdc, offset_x + length_x, length_y / 2 + 2 * offset_y);
  173.     LineTo(hdc, offset_x + length_x - 5, length_y / 2 + 2 * offset_y + 3);
  174.  
  175.     length_x -= 20;
  176.     //length_y -= 20;
  177.     cur_x = offset_x;
  178.     cur_y = length_y / 2 + 2 * offset_y;
  179.     del_x = length_x / (N_gl - 1);
  180.  
  181.     for (i = 0; i < N_gl; i++) //Подписи по оси x
  182.     {
  183.         MoveToEx(hdc, cur_x, cur_y - 3, NULL);
  184.         LineTo(hdc, cur_x, cur_y + 3);
  185.         sprintf(str, "%d", i);
  186.         TextOut(hdc, cur_x + 1, cur_y + 3, str, strlen(str));
  187.         cur_x += del_x;
  188.     }
  189.  
  190.     for (i = 0; i < N_gl; i++) //Поиск максимального значения y
  191.     {
  192.         if (fabs(*(x_gl + i)) > fabs(y_max))
  193.         {
  194.             y_max = *(x_gl + i);
  195.         }
  196.     }
  197.  
  198.     del_y = fabs((length_y/2) / y_max);
  199.  
  200.     i = 0;
  201.     y = *(x_gl + i);
  202.     prev_x = offset_x + del_x * i;
  203.     prev_y = length_y/2 + 2 * offset_y - del_y * y;
  204.     MoveToEx(hdc, offset_x - 3, prev_y, NULL);
  205.     LineTo(hdc, offset_x + 3, prev_y);
  206.     sprintf(str, "%.1f", y);
  207.     TextOut(hdc, 0, prev_y, str, strlen(str));
  208.     for (i = 1; i < N_gl; i++)
  209.     {
  210.         y = *(x_gl + i);
  211.         cur_x = offset_x + del_x * i;
  212.         cur_y = length_y / 2 + 2 * offset_y - del_y * y;
  213.         MoveToEx(hdc, prev_x, prev_y, NULL);
  214.         LineTo(hdc, cur_x, cur_y);
  215.        
  216.         MoveToEx(hdc, offset_x - 3, cur_y, NULL);
  217.         LineTo(hdc, offset_x + 3, cur_y);
  218.         sprintf(str, "%.1f", y);
  219.         TextOut(hdc, 0, cur_y, str, strlen(str));
  220.  
  221.         prev_x = cur_x;
  222.         prev_y = cur_y;
  223.     }
  224. }
  225.  
  226. void draw_point_chart(HDC hdc, int offset_x, int offset_y, int length_x, int length_y, int zero_x, int zero_y, float *arr, char *x, char *y)
  227. {
  228.     char str[10];
  229.     int cur_x, cur_y;
  230.     int del_x, del_y;
  231.     int i;
  232.     float y_max = 0, tmp;
  233.  
  234.     MoveToEx(hdc, zero_x, zero_y, NULL); //Горизонтальная ось
  235.     LineTo(hdc, zero_x + length_x, zero_y);
  236.  
  237.     MoveToEx(hdc, zero_x, zero_y + length_y / 2, NULL); //Вертикальная ось
  238.     LineTo(hdc, zero_x, zero_y - length_y / 2);
  239.  
  240.     MoveToEx(hdc, zero_x - 3, zero_y - length_y/2 + 3, NULL); //Стрелка на вертикальной оси
  241.     LineTo(hdc, zero_x, zero_y - length_y / 2);
  242.     LineTo(hdc, zero_x + 3, zero_y - length_y/2 + 3);  
  243.    
  244.     MoveToEx(hdc, zero_x + length_x - 3, zero_y - 3, NULL); //Стрелка на горизонтальной оси
  245.     LineTo(hdc, zero_x + length_x, zero_y);
  246.     LineTo(hdc, zero_x + length_x - 3, zero_y + 3);
  247.  
  248.     length_x -= 20;
  249.     for (i = 0; i < N_gl; i++) //Находим максимальное значение в массиве
  250.     {
  251.         tmp = *(arr + i);
  252.         if (fabs(tmp) > fabs(y_max))
  253.         {
  254.             y_max = tmp;
  255.         }
  256.     }
  257.  
  258.     del_x = length_x / (N_gl - 1);
  259.     del_y = fabs((length_y / 2) / y_max);
  260.  
  261.     cur_y = zero_y;
  262.     cur_x = zero_x;
  263.  
  264.     for (i = 0; i < N_gl; i++) //Разметка по оси x
  265.     {
  266.         MoveToEx(hdc, cur_x, cur_y - 3, NULL);
  267.         LineTo(hdc, cur_x, cur_y + 3);
  268.         sprintf(str, "%d", i);
  269.         TextOut(hdc, cur_x + 2, cur_y + 10, str, strlen(str));
  270.         cur_x += del_x;
  271.     }
  272.  
  273.     cur_x = zero_x;
  274.     for (i = 0; i < N_gl; i++)
  275.     {
  276.         MoveToEx(hdc, cur_x, zero_y, NULL);
  277.         cur_y = zero_y - *(arr + i) * del_y;
  278.         LineTo(hdc, cur_x, cur_y);
  279.         Ellipse(hdc, cur_x - 3, cur_y - 3, cur_x + 3, cur_y + 3);
  280.         cur_x += del_x;
  281.     }
  282.     //TextOut(hdc, cur_x + length_x, cur_y, L"x", 1); //TODO
  283.  
  284.     TextOut(hdc, zero_x + length_x + 15, zero_y + 3, x, strlen(x)); //Подпись по горизонтальной оси
  285.     TextOut(hdc, zero_x - 20, zero_y - length_y / 2 - 20, y, strlen(y)); //Подпись по вертикальной оси
  286. }
  287.  
  288. /*void save_bmp_file(char *file_name)
  289. {
  290.  
  291. }*/
  292.  
  293. int SaveBMPFile(char *filename, HBITMAP bitmap, HDC bitmapDC, int width, int height) {
  294.     HBITMAP OffscrBmp = NULL;
  295.     HDC OffscrDC = NULL;
  296.     LPBITMAPINFO lpbi = NULL;
  297.     LPVOID lpvBits = NULL;
  298.     HANDLE BmpFile = INVALID_HANDLE_VALUE;
  299.     BITMAPFILEHEADER bmfh;
  300.     if ((OffscrBmp = CreateCompatibleBitmap(bitmapDC, width, height)) == NULL)
  301.         return 0;
  302.     if ((OffscrDC = CreateCompatibleDC(bitmapDC)) == NULL)
  303.         return 0;
  304.     HBITMAP OldBmp = (HBITMAP)SelectObject(OffscrDC, OffscrBmp);
  305.     BitBlt(OffscrDC, 0, 0, width, height, bitmapDC, 0, 0, SRCCOPY);
  306.     if ((lpbi = (LPBITMAPINFO)(malloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)))) == NULL)
  307.         return 0;
  308.     ZeroMemory(&lpbi->bmiHeader, sizeof(BITMAPINFOHEADER));
  309.     lpbi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  310.     SelectObject(OffscrDC, OldBmp);
  311.     if (!GetDIBits(OffscrDC, OffscrBmp, 0, height, NULL, lpbi, DIB_RGB_COLORS))
  312.         return 0;
  313.     if ((lpvBits = malloc(lpbi->bmiHeader.biSizeImage)) == NULL)
  314.         return 0;
  315.     if (!GetDIBits(OffscrDC, OffscrBmp, 0, height, lpvBits, lpbi, DIB_RGB_COLORS))
  316.         return 0;
  317.     if ((BmpFile = CreateFile(filename,
  318.         GENERIC_WRITE,
  319.         0, NULL,
  320.         CREATE_ALWAYS,
  321.         FILE_ATTRIBUTE_NORMAL,
  322.         NULL)) == INVALID_HANDLE_VALUE)
  323.         return 0;
  324.     DWORD Written;
  325.     bmfh.bfType = 19778;
  326.     bmfh.bfReserved1 = bmfh.bfReserved2 = 0;
  327.     if (!WriteFile(BmpFile, &bmfh, sizeof(bmfh), &Written, NULL))
  328.         return 0;
  329.     if (Written < sizeof(bmfh))
  330.         return 0;
  331.     if (!WriteFile(BmpFile, &lpbi->bmiHeader, sizeof(BITMAPINFOHEADER), &Written, NULL))
  332.         return 0;
  333.     if (Written < sizeof(BITMAPINFOHEADER))
  334.         return 0;
  335.     int PalEntries;
  336.     if (lpbi->bmiHeader.biCompression == BI_BITFIELDS)
  337.         PalEntries = 3;
  338.     else PalEntries = (lpbi->bmiHeader.biBitCount <= 8) ?
  339.         (int)(1 << lpbi->bmiHeader.biBitCount) : 0;
  340.     if (lpbi->bmiHeader.biClrUsed)
  341.         PalEntries = lpbi->bmiHeader.biClrUsed;
  342.     if (PalEntries) {
  343.         if (!WriteFile(BmpFile, &lpbi->bmiColors, PalEntries * sizeof(RGBQUAD), &Written, NULL))
  344.             return 0;
  345.         if (Written < PalEntries * sizeof(RGBQUAD))
  346.             return 0;
  347.     }
  348.     bmfh.bfOffBits = SetFilePointer(BmpFile, 0, 0, FILE_CURRENT);;
  349.     if (!WriteFile(BmpFile, lpvBits, lpbi->bmiHeader.biSizeImage, &Written, NULL))
  350.         return 0;
  351.     if (Written < lpbi->bmiHeader.biSizeImage)
  352.         return 0;
  353.     bmfh.bfSize = SetFilePointer(BmpFile, 0, 0, FILE_CURRENT);
  354.     SetFilePointer(BmpFile, 0, 0, FILE_BEGIN);
  355.     if (!WriteFile(BmpFile, &bmfh, sizeof(bmfh), &Written, NULL))
  356.         return 0;
  357.     if (Written < sizeof(bmfh))
  358.         return 0;
  359.  
  360.     CloseHandle(BmpFile);
  361.     free(lpvBits);
  362.     free(lpbi);
  363.     DeleteDC(OffscrDC);
  364.     DeleteObject(OffscrBmp);
  365.  
  366.     return 1;
  367. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement