Программирование под Windows с использованием Win API
Пример разложения в ряд функции. Графический вывод
Проиллюстируем рассмотренный в предыдущем параграфе теоретичекий материал на примере написания Windows-приложения решения задачи о разложении в ряд некоторой функции.
Задача: Разложить в ряд Тейлора в окрестности точки 0 функции sin(x), cos(x) и вывести в окне график функции .
Напишем функции вычисления синуса и косинуса – разложения в ряд Тейлора в окрестности точки 0. Разложения в ряд имеют вид:


Радиус сходимости для этих рядов –
.
const double epsilon = 0.0000001;
const double pi = 3.14159265;
const double x_start = -2*pi;
const double x_end = 2*pi;
double sin_e(double arg, double eps)
{
double result = 0, rn = arg;
for(int i = 1; ;i++)
{
if(rn < eps && rn > -eps) return result;
result += rn;
rn = -rn*arg*arg/(i+1)/(i+2);
i++;
}
}
double cos_e(double arg, double eps)
{
double result = 0, rn = 1;
for(int i = 0; ;i++)
{
if(rn < eps && rn > -eps) return result;
result += rn;
rn = -rn*arg*arg/(i+1)/(i+2);
i++;
}
}Для дальнейшего решения задачи – вывода графика функции в клиентском окне, будем обрабатывать сообщения, которые будут посылаться окну. Когда необходима перерисовка окна (изменились размеры окна, часть окна перекрылась другим окном и т.п.), система посылает окну сообщение WM_PAINT.
Добавим функции, которые будут выводить в клиентскую часть окна график и координатные оси, а также, необходимые ветви case в операторе switch.
Для построения изображения используем API функции операционной системы: MoveToEx(...), LineTo(...), GetClientRect(...) и т.д. Информацию об этих функциях можно получить в справочной системе.
void DrawAxis(HDC hdc, RECT rectClient)
{
HPEN penGraph = CreatePen(PS_SOLID,2,RGB(0,0,255));
HGDIOBJ gdiOld = SelectObject(hdc, penGraph);
MoveToEx(hdc, 0, rectClient.bottom/2, NULL);
LineTo(hdc, rectClient.right, rectClient.bottom/2);
LineTo(hdc, rectClient.right - 5, rectClient.bottom/2 + 2);
MoveToEx(hdc, rectClient.right, rectClient.bottom/2, NULL);
LineTo(hdc, rectClient.right - 5, rectClient.bottom/2 - 2);
MoveToEx(hdc, rectClient.right/2, rectClient.bottom, NULL);
LineTo(hdc, rectClient.right/2, rectClient.top);
LineTo(hdc, rectClient.right/2 - 2, rectClient.top + 5);
MoveToEx(hdc, rectClient.right/2, rectClient.top, NULL);
LineTo(hdc, rectClient.right/2 + 2, rectClient.top + 5);
SelectObject(hdc, gdiOld);
}
void DrawGraph(HDC hdc, RECT rectClient)
{
HPEN penGraph = CreatePen(PS_SOLID,2,RGB(255,0,0));
HGDIOBJ gdiOld = SelectObject(hdc, penGraph);
double x_current = x_start;
double step = (x_end - x_start)/rectClient.right;
double y_start = cos_e(x_start, epsilon) + cos_e(x_start, epsilon);
MoveToEx(hdc, 0, int(-y_start/step) + rectClient.bottom/2, NULL);
while(x_current < x_end)
{
x_current += step;
double y_next = cos_e(x_current, epsilon) + cos_e(x_current, epsilon);
LineTo(hdc, int(x_current/step) + rectClient.right/2, int(-y_next/step) + rectClient.bottom/2);
}
SelectObject(hdc, gdiOld);
}
void OnPaint(HWND hwnd)
{
PAINTSTRUCT ps;
RECT rectClient;
HDC hdc = BeginPaint(hwnd,&ps);
GetClientRect(hwnd, &rectClient);
DrawAxis(hdc, rectClient);
DrawGraph(hdc, rectClient);
ValidateRect(hwnd,NULL);
EndPaint(hwnd,&ps);
}
LONG WINAPI WndProc(HWND hwnd, UINT Message, WPARAM wparam, LPARAM lparam)
{
switch (Message)
{
case WM_PAINT:
OnPaint(hwnd);
break;
case WM_MOUSEMOVE:
SetCapture(hwnd);
SetCursor(LoadCursor(NULL,IDC_ARROW));
ReleaseCapture();
break;
case WM_WINDOWPOSCHANGED:
UpdateWindow(hwnd);
break;
case WM_DESTROY: PostQuitMessage(0); break;
default: return DefWindowProc(hwnd, Message, wparam, lparam);
}
UpdateWindow(hwnd);
return 0;
}
Листинг
1.1.
Функция DrawGraph(...) выводит на экран график, функция DrawAxis(...) выводит координатные оси. При выводе графика функции на экран используем преобразование системы координат окна приложения в логическую систему координат и наоборот. Подробно этот вопрос рассмотрен в следующей лекции. В результате в клиентской области окна получим искомый график функции : рис. 1.1
