Задача: Для 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++
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, NULL, NULL,
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;
}
Результат выполнения
Примечание: Для корректной сборки приложения используется многобайтовая кодировка.
LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wparam, LPARAM lparam) — где и как использовать? Простое размещение кода программы внутри Windows- приложения, которое генерируется транслятором невозможно.
Затрудняюсь ответить — использовать там, где компилируется.
Я создала классическое приложение и посмотрела тип возвращаемого значения, который там генерирует сам Visual Studio
Компилятор MS Visual Studio 22 выдает 11 ошибок на текст данной программы. Начиная со строки height = rectClient.bottom — rectClient.top; -требуется точка с запятой..
По этой информации не смогу помочь разобраться с ошибками. К сожалению, иногда приходится немного изменять код, чтобы он компилироваться в нужном компиляторе.
Могу выслать на Ваш адрес скриншот всех ошибок.
Сообщения об ошибках:Серьезность Код Описание Проект Файл Строка Состояние подавления
Ошибка (активно) E0065 требуется точка с запятой ";" ConsoleApplication82 C:\Users\Mars\source\repos\ConsoleApplication82\ConsoleApplication82\ConsoleApplication82.cpp 40
Ошибка (активно) E0065 требуется точка с запятой ";" ConsoleApplication82 C:\Users\Mars\source\repos\ConsoleApplication82\ConsoleApplication82\ConsoleApplication82.cpp 41
Ошибка (активно) E0065 требуется точка с запятой ";" ConsoleApplication82 C:\Users\Mars\source\repos\ConsoleApplication82\ConsoleApplication82\ConsoleApplication82.cpp 50
Ошибка (активно) E0065 требуется точка с запятой ";" ConsoleApplication82 C:\Users\Mars\source\repos\ConsoleApplication82\ConsoleApplication82\ConsoleApplication82.cpp 51
Ошибка (активно) E0065 требуется точка с запятой ";" ConsoleApplication82 C:\Users\Mars\source\repos\ConsoleApplication82\ConsoleApplication82\ConsoleApplication82.cpp 65
Ошибка (активно) E0018 требуется круглая скобка ")" ConsoleApplication82 C:\Users\Mars\source\repos\ConsoleApplication82\ConsoleApplication82\ConsoleApplication82.cpp 83
Ошибка (активно) E0065 требуется точка с запятой ";" ConsoleApplication82 C:\Users\Mars\source\repos\ConsoleApplication82\ConsoleApplication82\ConsoleApplication82.cpp 88
Ошибка (активно) E0513 значение типа "LONG (__stdcall *)(HWND hwnd, UINT Message, WPARAM wparam, LPARAM lparam)" нельзя присвоить сущности типа "WNDPROC" ConsoleApplication82 C:\Users\Mars\source\repos\ConsoleApplication82\ConsoleApplication82\ConsoleApplication82.cpp 105
Ошибка (активно) E0513 значение типа "const char *" нельзя присвоить сущности типа "LPCWSTR" ConsoleApplication82 C:\Users\Mars\source\repos\ConsoleApplication82\ConsoleApplication82\ConsoleApplication82.cpp 108
Ошибка (активно) E0167 аргумент типа "const char *" несовместим с параметром типа "LPCWSTR" ConsoleApplication82 C:\Users\Mars\source\repos\ConsoleApplication82\ConsoleApplication82\ConsoleApplication82.cpp 110
Ошибка (активно) E0167 аргумент типа "const char *" несовместим с параметром типа "LPCWSTR" ConsoleApplication82 C:\Users\Mars\source\repos\ConsoleApplication82\ConsoleApplication82\ConsoleApplication82.cpp 136
Вот код, который откомпилировался в VS 2019. К сожалению, отследить за развитием компиляторов очень сложно.
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;
}
P.S. На сайте имеет место автозамена символа "минус" на "тире".
На этот текст компилятор выдал только одну ошибку:
Серьезность Код Описание Проект Файл Строка Состояние подавления
Ошибка (активно) E0513 значение типа "LONG (__stdcall *)(HWND hwnd, UINT Message, WPARAM wparam, LPARAM lparam)" нельзя присвоить сущности типа "WNDPROC" ConsoleApplication82 C:\Users\Mars\source\repos\ConsoleApplication82\ConsoleApplication82\ConsoleApplication82.cpp 101
Не консольное приложение случайно создаёте?
Неважно какое приложение, консольное или нет, ошибка выдается одна и та же! Как все-таки запустить программу?
Попробуйте использовать заголовок вида
который предлагает Visual Studio по умолчанию при создании оконного приложения
Сделайте приведение типа
w.lpfnWndProc = (WNDPROC)WndProc;
изобразили ее график, объяснили его построение и с его помощью перечислим основные свойства функции.