Разработка программы рисования графика функции одной переменной. Функция задана формулой
Приводится пример рисования на канве графика функции одной переменной 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
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.
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. Добавление функций преобразования и функции вычисления sin(x) в класс 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).