График функции sin(x)

График функции sin(x)

Задача: Для x∈[0;7] построить график функции y=sin(x).

За начало отсчета в окне принят верхний левый угол. Именно от него задаются координаты смещения любых элементов управления, в том числе графических элементов.

График функции y=sin(x) имеет одинаковое отклонение как вверх, так и вниз относительно оси x. Поэтому за начало отсчета принимается точка со смещением 0 по горизонтали и со смещением 1/2 высоты по вертикали.

Смещение графика по горизонтали и вертикали

Координата X меняется в пределах [0;7], координата Y — в пределах [-1;1].

Величины MAX_X и MAX_Y представляют собой область допустимых значений по осям координат:

  • MAX_X = maxX — minX = 7;
  • MAX_Y = maxY — minY = 2.

Смещение графика функции представляет собой положение первой точки относительно начала отсчета левого верхнего угла:

  • смещение по оси X: OffsetX = minX * width / MAX_X;
  • смещение по оси Y: OffsetY = maxY * height / MAX_Y

В данном случае смещение по оси x OffsetX = 0, поскольку значение minX = 0 представляет собой минимальное значение координаты x из области допустимых значений.

.

Значение maxY = 1 представляет собой максимальное значение координаты y из области допустимых значений. Рассматривается именно максимальное значение, поскольку за начало отсчета принят левый верхний угол окна, и координата y увеличивается по направлению вниз.

Для того чтобы график функции разместился в окне, необходимо рассчитать масштабные коэффициенты по осям. Масштабный коэффициент представляет собой отношение размера окна к области допустимых значений функции.

  • масштабный коэффициент по оси X: ScaleX = width / MAX_X;
  • масштабный коэффициент по оси Y: ScaleY = height / MAX_Y.

Вычисление координат следующей точки (x;y) графика в окне будет осуществляться по формулам:

  • координата X = OffsetX + x * ScaleX;
  • координата Y = OffsetY + y * ScaleY,

где (x;y) — координаты точки, полученные из функции y=sin(x) для следующей координаты x.

Реализация на C++

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#include <windows.h>
#include <tchar.h>   
#include <math.h>
LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wparam, LPARAM lparam);
const int NUM = 70; // количество точек
double* x, * y; // массивы данных x и y
// Задание исходных данных для графика
// (двумерный массив, может содержать несколько рядов данных)
void getData(int n)
{
    for (int i = 0; i < n; i++)
    {
        x[i] = (double)i * 0.1;
        y[i] = sin(x[i]);
    }
    return;
}
// Функция рисования графика
void DrawGraph(HDC hdc, RECT rectClient, int n)
{
    double OffsetY, OffsetX;
    double MAX_X, MAX_Y;
    double ScaleX, ScaleY;
    double min, max;
    int height, width;
    int X, Y; // координаты в окне (в px)
    HPEN hpen;
    height = rectClient.bottom - rectClient.top;
    width = rectClient.right - rectClient.left;
    // Область допустимых значений X
    min = x[0];
    max = x[0];
    for (int i = 0; i < n; i++)
    {
        if (x[i] < min) min = x[i];
        if (x[i] > max) max = x[i];
    }
    double temp = max - min;
    MAX_X = max - min;
    OffsetX = min * width / MAX_X; // смещение X
    ScaleX = (double)width / MAX_X; // масштабный коэффициент X
    // Область допустимых значений Y
    min = y[0];
    max = y[0];
    for (int i = 0; i < n; i++)
    {
        if (y[i] < min) min = y[i];
        if (y[i] > max) max = y[i];
    }
    MAX_Y = max - min;
    OffsetY = max * height / (MAX_Y); // смещение Y
    ScaleY = (double)height / MAX_Y; // масштабный коэффициент Y
    // Отрисовка осей координат
    hpen = CreatePen(PS_SOLID, 0, 0); // черное перо 1px
    SelectObject(hdc, hpen);
    MoveToEx(hdc, 0, OffsetY, 0); // перемещение в точку (0;OffsetY)
    LineTo(hdc, width, OffsetY); // рисование горизонтальной оси
    MoveToEx(hdc, OffsetX, 0, 0); // перемещение в точку (OffsetX;0)
    LineTo(hdc, OffsetX, height); // рисование вертикальной оси (не видна)
    DeleteObject(hpen); // удаление черного пера
    // Отрисовка графика функции
    int color = 0xFF; // красное перо для ряда данных
    hpen = CreatePen(PS_SOLID, 2, color); // формирование пера 2px
    SelectObject(hdc, hpen);        // выбор пера
    X = (int)(OffsetX + x[0] * ScaleX); // начальная точка графика
    Y = (int)(OffsetY - y[0] * ScaleY);
    MoveToEx(hdc, X, Y, 0); // перемещение в начальную точку
    for (int i = 1; i < n; i++)   // точка 0 из массивов уже использована
    {
        X = OffsetX + x[i] * ScaleX;
        Y = OffsetY - y[i] * ScaleY;
        LineTo(hdc, X, Y);
    }
    color = color << 8; // изменение цвета пера для следующего ряда
    DeleteObject(hpen); // удаление текущего пера
}
// Главная функция
int WINAPI WinMain(HINSTANCE hInstance,
    HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    HWND hwnd;
    MSG msg;
    WNDCLASS w;
    x = new double[NUM];  // создаем массивы для координат x и y
    y = new double[NUM];
    getData(NUM); // задание исходны данных
    memset(&w, 0, sizeof(WNDCLASS));
    w.style = CS_HREDRAW | CS_VREDRAW;
    w.lpfnWndProc = WndProc;
    w.hInstance = hInstance;
    w.hbrBackground = CreateSolidBrush(0x00FFFFFF);
    w.lpszClassName = _T("My Class");
    RegisterClass(&w);
    hwnd = CreateWindow(_T("My Class"), _T("График функции"),
        WS_OVERLAPPEDWINDOW,
        500, 300, 500, 380, NULLNULL,
        hInstance, NULL);
    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    delete[] x;
    delete[] y;
    return msg.wParam;
}
// Оконная функция
LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wparam, LPARAM lparam)
{
    HDC hdc;
    PAINTSTRUCT ps;
    switch (Message)
    {
    case WM_PAINT:
        hdc = BeginPaint(hwnd, &ps);
        DrawGraph(hdc, ps.rcPaint, NUM); // построение графика
        // Вывод текста y=sin(x)
        SetTextColor(hdc, 0x00FF0000); // синий цвет букв
        TextOut(hdc, 10, 20, _T("y=sin(x)"), 8);
        EndPaint(hwnd, &ps);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hwnd, Message, wparam, lparam);
    }
    return 0;
}

Результат выполнения

Примечание: Для корректной сборки приложения используется многобайтовая кодировка.

Прокрутить вверх