Программирование под 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