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

Задачи и их решения / График функции sin(x)

 

Задача Для 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++

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
132
133
134
135
136
137
138
139
140
141
#include <windows.h>
#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;
}

 
Результат выполнения
График функции sin(x)
Примечание: Для корректной сборки приложения используется многобайтовая кодировка.


Назад: Задачи и их решения

Комментариев к записи: 13

  • 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. К сожалению, отследить за развитием компиляторов очень сложно.
          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
          132
          133
          134
          135
          136
          137
          138
          139
          140
          141
          142
          #include <windows.h>
          #include <math.h>
          #include <tchar.h>
          const int NUM = 70; // количество точек
          LONG WINAPI WndProc(HWNDUINTWPARAMLPARAM);
          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, NULLNULL,
                  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

          • Не консольное приложение случайно создаёте?

          • Неважно какое приложение, консольное или нет, ошибка выдается одна и та же! Как все-таки запустить программу?

          • Попробуйте использовать заголовок вида
            1
            LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wparam, LPARAM lparam)
            который предлагает Visual Studio по умолчанию при создании оконного приложения

          • Сделайте приведение типа w.lpfnWndProc = (WNDPROC)WndProc;

  • изобразили ее график, объяснили его построение и с его помощью перечислим основные свойства функции.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *