Розробка програми рисування графіка функції однієї змінної. Функція задана формулою
Наводиться приклад рисування на канві графіка функції однієї змінної
y = f(x)
Функція задається формулою.
Умова задачі
Розробити додаток, в якому будується графік функції
y = sin(x)
Графік функції повинен виводитись у окремій формі.
Математична постановка задачі
Для побудови будь-якого графіка функції y = f(x) потрібно задати прямокутну область екрану, в якій цей графік функції буде виводитись.
Прямокутна область екрану задається координатами крайніх точок (рис. 1):
– (x1; y1) – лівий верхній кут екрану;
– (x2; y2) – правий нижній кут екрану.
Рис. 1. Прямокутна область екрану
При побудові графіків функцій на екрані монітору потрібно здійснювати масштабування прямокутника з координатами (x1; y1), (x2; y2) в прямокутник з координатами екрану (xx1; yy1), (xx2; yy2) як зображено на рисунку 2.
Рис. 2. Масштабування графіків
Масштабування по осях OX та OY реалізується з допомогою лінійних залежностей:
При обчисленні вертикальних екранних координат необхідно з допомогою знаку враховувати, що нумерація рядків йде зверху вниз.
Розв’язок
1. Завантажити Borland C++ Builder.
Створити проект як “VCL Form Application”. Автоматично створюється основна форма додатку з іменем Form1.
Зберегти проект.
2. Побудова основної форми.
Розмістити на формі компоненти таких типів:
- п’ять компонент типу TLabel. Створюються об’єкти з іменами Label1, Label2, Label3, Label4, Label5;
- п’ять компонент типу TEdit. Створюються об’єкти з іменами Edit1, Edit2, Edit3, Edit4, Edit5;
- один компонент типу TButton. Створюється об’єкт з іменем Button1.
Відкорегувати позиції компонент на формі так як показано на рисунку 3.
Рис. 3. Розміщення компонент на формі Form1
3. Налаштування форми.
Щоб форма Form1 мала коректний вигляд, в Object Inspector потрібно зробити наступне:
- з вкладки Action встановити властивість Caption = “Графік функції однієї змінної” (заголовок форми);
- з вкладки Visual встановити властивість BorderStyle = “bsDialog” (рис. 4). У результаті зникнуть кнопки управління формою;
- з вкладки Miscellaneous встановити властивість Position = “poScreenCenter” (рис. 5). Ця дія відобразить форму в центрі екрану під час виконання додатку.
Рис. 4. Властивість BorderStyle форми Form1
Рис. 5. Властивість Position
4. Налаштування властивостей та розмірів компонент, розміщених на формі.
Потрібно здійснити налаштування таких властивостей компонент:
- у компоненті Label1 властивість Caption = ” К-сть точок по горизонталі, n =“;
- у компоненті Label2 властивість Caption = ” Ліва межа, x1 =“;
- у компоненті Label3 властивість Caption = “ Права межа, x2 =“;
- у компоненті Label4 властивість Caption = “ Верхня межа, y1 = “;
- у компоненті Label5 властивість Caption = ” Нижня межа, y2 =“;
- у компоненті Button1 властивість Caption = “ Вивести графік …“.
Також потрібно змінити розмір і позицію компонента Button1 на формі. Приблизний вигляд форми з розміщеними компонентами зображено на рисунку 6.
Рис. 6. Загальний вигляд форми Form1
5. Програмування події активізації форми Form1.
Під час запуску додатку на виконання необхідно запрограмувати подію OnActivate активізації основної форми додатку.
Приклад програмування події в C++ Builder описується тут.
Лістинг обробника події OnActivate має наступний вигляд:
void __fastcall TForm2::FormActivate(TObject *Sender) { Edit1->Text = "30"; Edit2->Text = "-5"; Edit3->Text = "5"; Edit4->Text = "-2"; Edit5->Text = "2"; Edit1->SetFocus(); // встановити фокус введення в Edit1 }
У обробнику події заповнюються значення полів, які є координатами прямокутної області екрану в якій виводиться графік. Прямокутна область екрану задається координатами лівого верхнього кута (x1; y1) та правого нижнього кута (x2; y2).
6. Створення нової форми виведення графіку функції.
Створити форму з іменем “Form2” за зразком, як показано на рисунку 7. Приклад створення нової форми у C++ Builder наведено тут.
Форма Form2 описується в файлах “Unit2.h” та “Unit2.cpp”.
Розмістити на формі компоненти таких типів:
– компонент типу TButton (кнопка). Автоматично створюється об’єкт з іменем Button1;
– компонент типу TImage. Створюється об’єкт з іменем Image1. У цьому компоненті буде виводитись графік функції sin(x).
Рис. 7. Форма Form2 виведення графіку функції sin(x)
З допомогою Object Inspector здійснити налаштування основних властивостей компонент:
- у компоненті Button1 властивість Caption = “OK”;
- у компоненті Button1 властивість ModalResult = “mrOk“. Це означає, що під час кліку на кнопці Button1 форма буде закриватись з кодом повернення mrOk.
З допомогою Object Inspector здійснити налаштування властивостей форми Form2:
– з вкладки Action встановити властивість Caption = “Графік функції sin(x)“;
– з вкладки Visual властивість BorderStyle = “bsDialog”. Це означає, що вікно форми прийме вигляд діалогового вікна;
– з вкладки Miscellaneous властивість Position = “poScreenCenter”. У результаті форма буде виводитись в центрі екрану.
Також потрібно відкоригувати розміри та позиції компонентів Button1 та Image1.
У результаті виконаних дій, форма Form2 буде мати вигляд, як зображено на рисунку 8
Рис. 8. Форма Form2
7. Програмування допоміжних функцій масштабування та обчислення sin(x).
7.1. Ввід внутрішніх змінних у модуль форми Form2.
Потрібно ввести наступні внутрішні змінні у текст модуля “Unit2.h” (рис. 9).
Для цього виконується така послідовність дій.
- Перейти у заголовочний файл “Unit2.h” (рис. 9).
- У розділі private класу TForm2 ввести чотири змінні:
int xx1, xx2, yy1, yy2;
Ці змінні відповідають екранним координатам (див. рис. 2 б).
- У розділі public класу TForm2 ввести п’ять змінних:
float x1, x2, y1, y2; int n;
Ці змінні відповідають фактичним координатам (рис. 2 а) прямокутної області, в якій виводиться графік. Змінна n задає кількість точок, що будуть з’єднані лініями. Чим більше значення n, тим плавніше виглядає графік на екрані.
Значення цих змінних заповнюється з основної форми Form1. Тому вони розміщуються в розділі public.
Рис. 9. Вигляд файлу модуля “Unit2.h”
Поки що лістинг файлу “Unit2.h” наступний:
//------------------------------------------------ #ifndef Unit2H #define Unit2H //------------------------------------------------ #include <Classes.hpp> #include <Controls.hpp> #include <StdCtrls.hpp> #include <Forms.hpp> #include <ExtCtrls.hpp> //------------------------------------------------ class TForm2 : public TForm { __published: // IDE-managed Components TImage *Image1; TButton *Button1; private: // User declarations int xx1, xx2, yy1, yy2; public: // User declarations __fastcall TForm2(TComponent* Owner); float x1, x2, y1, y2; // фактичні координати прямокутної області int n; // кількість точок, які з'єднуються лініями }; //-------------------------------------------------- extern PACKAGE TForm2 *Form2; //-------------------------------------------------- #endif
7.2. Додавання функцій перетворення та функції обчислення у клас TForm2.
У модулі форми Form2 потрібно створити дві функції перетворення фактичних координат в екранні координати. Функції мають імена ZoomX() та ZoomY().
Також потрібно додати функцію обчислення sin(x). Ім’я цієї функції func().
Спочатку додається опис функцій в модуль “Unit2.h”. Опис додається в розділ public.
Фрагмент лістингу файлу “Unit2.h” буде мати наступний вигляд:
... class TForm2 : public TForm { __published: // IDE-managed Components TImage *Image1; TButton *Button1; private: // User declarations int xx1, xx2, yy1, yy2; public: // User declarations __fastcall TForm2(TComponent* Owner); float x1, x2, y1, y2; int n; int ZoomX(float x); int ZoomY(float y); float func(float x); }; ...
Наступним кроком потрібно перейти в файл “Unit2.cpp” (рис. 10). У цьому файлі описується реалізація класу TForm2.
У кінець файлу додається такий програмний код:
int TForm2::ZoomX(float x) { int ret; ret = xx1 + (int)((x-x1)*(xx2-xx1)/(x2-x1)); return ret; } int TForm2::ZoomY(float y) { int ret; ret = yy2 + (int)((y-y1)*(yy1-yy2)/(y2-y1)); return ret; } float TForm2::func(float x) { float ret; ret = sin(x); // функція, для якої будується графік return ret; }
У наведеному вище лістингу функції ZoomX() та ZoomY() отримують вхідними параметрами відповідно значення x та y, які є фактичними координатами. Потім здійснюється перетворення за формулами, які наведені у математичній постановці задачі.
Функція func() отримує вхідним параметром значення у локальній змінній x. У тілі функції обчислюється значення sin(x). У це місце можна вставити будь-яку іншу власну функцію.
Рис. 10. Файл “Unit2.cpp” з введеними функціями ZoomX(), ZoomY() та func()
На даний момент лістинг файлу Unit2.cpp наступний:
//------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "Unit2.h" #include <math.h> //------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm2 *Form2; //------------------------------------------------------- __fastcall TForm2::TForm2(TComponent* Owner) : TForm(Owner) { } //------------------------------------------------------- int TForm2::ZoomX(float x) { int ret; ret = xx1 + (int)((x-x1)*(xx2-xx1)/(x2-x1)); return ret; } int TForm2::ZoomY(float y) { int ret; ret = yy2 + (int)((y-y1)*(yy1-yy2)/(y2-y1)); return ret; } float TForm2::func(float x) { float ret; ret = sin(x); return ret; }
Щоб використовувати функцію sin(x), у файлі (модулі) “Unit2.cpp” додається рядок
#include <math.h>
У цьому рядку підключається бібліотека стандартних математичних функцій. У цій бібліотеці є функція обчислення sin(x).
8. Програмування події активізації форми Form2.
Графік функції виводиться у формі Form2 одразу після кліку на кнопці “Вивести графік…” форми Form1. Тому, доцільно запрограмувати виведення графіку у події OnActivate форми Form2. Обробник події реалізований у файлі “Unit2.cpp”.
Лістинг обробника події OnActivate форми Form2 наступний:
void __fastcall TForm2::FormActivate(TObject *Sender) { TCanvas * canv; // додаткова змінна int tx, ty; int i; float x, y, h; canv = Image1->Canvas; // 1. Задавання меж екранних координат xx1 = 0; yy1 = 0; xx2 = Image1->Width; yy2 = Image1->Height; // 2. Рисування графіку canv->Pen->Color = clBlue; canv->Brush->Color = clWhite; canv->Rectangle(0, 0, Image1->Width, Image1->Height); // 2.1. Побудова осей координат canv->Pen->Color = clBlack; // 2.2. Взяти екранну точку початку координат X tx = ZoomX(0); ty = ZoomY(y1); canv->MoveTo(tx,ty); // провести лінію осі координат X tx = ZoomX(0); ty = ZoomY(y2); canv->LineTo(tx,ty); // 2.3. Точка початку координат Y canv->Pen->Color = clBlack; tx = ZoomX(x1); ty = ZoomY(0); canv->MoveTo(tx,ty); // нарисувати вісь Y tx = ZoomX(x2); ty = ZoomY(0); canv->LineTo(tx,ty); // 3. Рисування графіка функції canv->Pen->Color = clRed; // колір canv->Pen->Width = 2; // товщина лінії // координати першої точки x = x1; y = func(x); h = (x2-x1)/n; tx = ZoomX(x); ty = ZoomY(y); canv->MoveTo(tx,ty); // цикл перебору точок і рисування з'єднувальних ліній for (i = 0; i < n; i++) { x = x + h; y = func(x); tx = ZoomX(x); ty = ZoomY(y); canv->LineTo(tx,ty); } }
У скороченому вигляді файл “Unit2.cpp” має вигляд:
#include <vcl.h> #pragma hdrstop #include "Unit2.h" #include <math.h> //----------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm2 *Form2; //----------------------------------------------------------- __fastcall TForm2::TForm2(TComponent* Owner) : TForm(Owner) { } //---------------------------------------------------------- int TForm2::ZoomX(float x) { ... } int TForm2::ZoomY(float y) { ... } float TForm2::func(float x) { ... } void __fastcall TForm2::FormActivate(TObject *Sender) { ... } //--------------------------------------------------------------
9. Програмування події кліку на кнопці “Вивести графік…” форми Form1.
Останнім етапом є програмування події кліку на кнопці виведення графіку.
Для цього потрібно виконати такі дії.
9.1. Підключення форми Form2 до форми Form1.
Приклад створення нової форми та виклику її з основної форми програми детально описується тут.
Щоб підключити форму Form2 до форми Form1 потрібно у верхній частині файлу “Unit1.cpp” потрібно додати рядок:
#include "Unit2.h"
Після цього методи класу TForm2 стають доступними з форми Form1.
Поки що лістинг файлу “Unit2.cpp” наступний:
#include <vcl.h> #pragma hdrstop #include "Unit1.h" #include "Unit2.h" //--------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; //--------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------- void __fastcall TForm1::FormActivate(TObject *Sender) { Edit1->Text = "30"; Edit2->Text = "-5"; Edit3->Text = "5"; Edit4->Text = "-2"; Edit5->Text = "2"; Edit1->SetFocus(); // встановити фокус введення в Edit1 } //---------------------------------------------------------------
9.2. Програмування події кліку на кнопці “Вивести графік…“.
Обробник події Button1Click() кліку на кнопці “Вивести графік…” наступний:
void __fastcall TForm1::Button1Click(TObject *Sender) { Form2->n = StrToInt(Edit1->Text); Form2->x1 = StrToFloat(Edit2->Text); Form2->x2 = StrToFloat(Edit3->Text); Form2->y1 = StrToFloat(Edit4->Text); Form2->y2 = StrToFloat(Edit5->Text); Form2->ShowModal(); }
У обробнику формуються змінні n, x1, x2, y1, y2.
10. Запуск додатку на виконання.
Після цього можна запускати додаток на виконання (рис. 11).
Рис. 11. Результат роботи додатку