Задача Для x∈[0;7] построить график функции y=sin(x).
График функции y=sin(x) симметричен относительно горизонтальной оси, поэтому должен быть построен в окне со смещением относительно левого верхнего угла окна, принятого за начало отсчета.
Координата 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 = 0;
- смещение по оси Y: OffsetY = maxY *height/MAX_Y
Значение 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).
Реализация на C++
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
132
133
134
135
136
137
138
139
140
141
#include <math.h>
const int NUM = 70; // количество точек
LONG WINAPI WndProc(HWND, UINT, WPARAM, LPARAM);
double **x; // массив данных
// Задание исходных данных для графика
// (двумерный массив, может содержать несколько рядов данных)
double ** getData(int n)
{
double **f;
f = new double*[2];
f[0] = new double[n];
f[1] = new double[n];
for (int i = 0; i<n; i++)
{
double x = (double)i * 0.1;
f[0][i] = x;
f[1][i] = sin(x);
}
return f;
}
// Функция рисования графика
void DrawGraph(HDC hdc, RECT rectClient,
double **x, // массив данных
int n, // количество точек
int numrow = 1) // количество рядов данных (по умолчанию 1)
{
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][0];
max = x[0][0];
for (int i = 0; i<n; i++)
{
if (x[0][i] < min) min = x[0][i];
if (x[0][i] > max) max = x[0][i];
}
double temp = max — min;
MAX_X = max — min;
OffsetX = min*width / MAX_X; // смещение X
ScaleX = (double)width / MAX_X; // масштабный коэффициент X
// Область допустимых значений Y
min = x[1][0];
max = x[1][0];
for (int i = 0; i<n; i++)
{
for (int j = 1; j <= numrow; j++)
{
if (x[j][i] < min) min = x[j][i];
if (x[j][i] > max) max = x[j][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; // красное перо для первого ряда данных
for (int j = 1; j <= numrow; j++)
{
hpen = CreatePen(PS_SOLID, 2, color); // формирование пера 2px
SelectObject(hdc, hpen);
X = (int)(OffsetX + x[0][0] * ScaleX); // начальная точка графика
Y = (int)(OffsetY — x[j][0] * ScaleY);
MoveToEx(hdc, X, Y, 0); // перемещение в начальную точку
for (int i = 0; i<n; i++)
{
X = OffsetX + x[0][i] * ScaleX;
Y = OffsetY — x[j][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 = 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 = "My Class";
RegisterClass(&w);
hwnd = CreateWindow("My Class", "График функции",
WS_OVERLAPPEDWINDOW,
500, 300, 500, 380, NULL, NULL,
hInstance, NULL);
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
// Оконная функция
LONG WINAPI 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, x, NUM); // построение графика
// Вывод текста y=sin(x)
SetTextColor(hdc, 0x00FF0000); // синий цвет букв
TextOut(hdc, 10, 20, "y=sin(x)", 8);
EndPaint(hwnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, Message, wparam, lparam);
}
return 0;
}
Результат выполнения
Примечание: Для корректной сборки приложения используется многобайтовая кодировка.
Назад: Задачи и их решения
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
132
133
134
135
136
137
138
139
140
141
142
#include <math.h>
#include <tchar.h>
const int NUM = 70; // количество точек
LONG WINAPI WndProc(HWND, UINT, WPARAM, LPARAM);
double** x; // массив данных
// Задание исходных данных для графика
// (двумерный массив, может содержать несколько рядов данных)
double** getData(int n)
{
double** f;
f = new double* [2];
f[0] = new double[n];
f[1] = new double[n];
for (int i = 0; i < n; i++)
{
double x = (double)i * 0.1;
f[0][i] = x;
f[1][i] = sin(x);
}
return f;
}
// Функция рисования графика
void DrawGraph(HDC hdc, RECT rectClient,
double** x, // массив данных
int n, // количество точек
int numrow = 1) // количество рядов данных (по умолчанию 1)
{
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][0];
max = x[0][0];
for (int i = 0; i < n; i++)
{
if (x[0][i] < min) min = x[0][i];
if (x[0][i] > max) max = x[0][i];
}
double temp = max - min;
MAX_X = max - min;
OffsetX = min * width / MAX_X; // смещение X
ScaleX = (double)width / MAX_X; // масштабный коэффициент X
// Область допустимых значений Y
min = x[1][0];
max = x[1][0];
for (int i = 0; i < n; i++)
{
for (int j = 1; j <= numrow; j++)
{
if (x[j][i] < min) min = x[j][i];
if (x[j][i] > max) max = x[j][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; // красное перо для первого ряда данных
for (int j = 1; j <= numrow; j++)
{
hpen = CreatePen(PS_SOLID, 2, color); // формирование пера 2px
SelectObject(hdc, hpen);
X = (int)(OffsetX + x[0][0] * ScaleX); // начальная точка графика
Y = (int)(OffsetY - x[j][0] * ScaleY);
MoveToEx(hdc, X, Y, 0); // перемещение в начальную точку
for (int i = 0; i < n; i++)
{
X = OffsetX + x[0][i] * ScaleX;
Y = OffsetY - x[j][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 = 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 = CreateWindowW(__T("My Class"), __T("График функции"),
WS_OVERLAPPEDWINDOW,
500, 300, 500, 380, NULL, NULL,
hInstance, NULL);
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
// Оконная функция
LONG WINAPI 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, x, 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;
}