C++. Разработка программы рисования графика функции одной переменной. Функция задана формулой.




Разработка программы рисования графика функции одной переменной. Функция задана формулой

Приводится пример рисования на канве графика функции одной переменной y = f(x).

Функция задается формулой

 

Условие задачи

Разработать приложение, в котором строится график функции

y = sin (x)

График функции должен выводиться в отдельной форме.

 

Математическая постановка задачи

Для построения любого графика функции y = f(x) нужно задать прямоугольную область экрана, в которой этот график функции будет выводиться.

Прямоугольная область экрана задается координатами крайних точек (рис. 1):

– (x1; y1) – левый верхний угол экрана;

– (x2; y2) – правый нижний угол экрана.

05_01_00_012_01_Рис. 1. Прямоугольная область экрана

При построении графиков функций на экране монитора нужно реализовать масштабирование прямоугольника с координатами (x1; y1), (x2; y2) в прямоугольник с координатами экрана (xx1; yy1), (xx2; yy2) как изображено на рисунке 2.

05_01_00_012_02rРис. 2. Масштабирование координат

Масштабирование по осям OX и OY реализуется с помощью линейных зависимостей:

05_01_00_012_formula_01 При вычислении вертикальных экранных координат необходимо с помощью знака учесть, что нумерация строк идет сверху вниз.

 

Решение

1. Загрузить Borland C++ Builder.

 

Создать проект как «VCL Form Application». Автоматически создается основная форма приложения с именем Form1.

Сохранить проект.

 

2. Создание основной формы.

Разместить на форме компоненты таких типов:

  • пять компонент типа TLabel. Создаются объекты с именами Label1, Label2, Label3, Label4, Label5;
  • пять компонент типа TEdit. Создаются объекты с именами Edit1, Edit2, Edit3, Edit4, Edit5;
  • один компонент типа TButton. Создается объект с именем Button1.

Откорректировать позиции компонент на форме как показано на рисунке 3.

05_01_00_012_03_Рис. 3. Размещение компонент на форме Form1

 

3. Настройка формы.

Чтобы форма Form1 имела корректный вид, в Object Inspector нужно сделать следующее:

  • из вкладки Action установить свойство Caption = «График функции одной переменной» (заголовок формы);
  • из вкладки Visual установить свойство BorderStyle = «bsDialog» (рис. 4). В результате исчезнут кнопки управления формой;
  • из вкладки Miscellaneous установить свойство Position = «poScreenCenter» (рис. 5). Это действие отобразит форму в центре экрана во время выполнения приложения.

05_01_00_012_04_ Рис. 4. Свойство BorderStyle формы Form1

05_01_00_012_05_Рис. 5. Свойство Position

 

4. Настройка свойств и размеров компонент, размещенных на форме.

Нужно настроить следующие свойства компонентов:

  • в компоненте Label1 свойство Caption = » К-во точек по горизонтали, n =«;
  • в компоненте Label2 свойство Caption = « Левая граница, x1 =«;
  • в компоненте Label3 свойство Caption = » Правая граница, x2 =«;
  • в компоненте Label4 свойство Caption = « Верхняя граница, y1 = «;
  • в компоненте Label5 свойство Caption = « Нижняя граница, y2 =«;
  • в компоненте Button1 свойство Caption = » Вывести график …«.

Также нужно изменить размер и позицию компонента Button1 на форме. Приблизительный вид формы с размещенными компонентами изображен на рисунке 6.

05_01_00_012_06r

Рис. 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).

05_01_00_012_07_

Рис. 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.

05_01_00_012_08rРис. 8. Форма Form2

 

7. Программирование дополнительных функций масштабирования и вычисления sin(x).
7.1. Ввод внутренних переменных в модуль формы Form2.

Нужно ввести следующие внутренние переменные в текст файла «Unit2.h» (рис. 9).

Для этого выполняется следующая последовательность действий.

  1. Перейти в заголовочный файл «Unit2.h» (рис. 9).
  1. В разделе private класса TForm2 ввести четыре переменные:
int xx1, xx2, yy1, yy2;

Эти переменные соответствуют экранным координатам (см. рис. 2 б).

  1. В разделе public класса TForm2 ввести пять переменных:
float x1, x2, y1, y2;
int n;

Эти переменные отвечают фактическим координатам (рис. 2 а) прямоугольной области, в которой выводится график. Переменная n задает количество точек, которые будут соединены линиями. Чем больше значение n, тем более плавно выглядит график на экране.

Значение этих переменных заполняется из основной формы Form1. Поэтому они размещаются в разделе public.

05_01_00_012_09_Рис. 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). В это место можно вставить любую другую собственную функцию.

05_01_00_012_10_Рис. 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).

05_01_00_012_11rРис. 11. Выполнение приложения, окно вывода графика функции