Литмир - Электронная Библиотека
A
A

15.1. Введение

 

Программирование. Принципы и практика использования C++ Исправленное издание - _001.png
 По сравнению с профессиональными системами программного обеспечения, которые вы будете использовать, если визуализация данных станет вашим основным занятием, описанные в этой главе средства довольно примитивны. Наша главная цель — не элегантность вывода, а понимание того, как создается графический вывод и какие приемы программирования при этом используются. Методы проектирования, способы программирования и основные математические инструменты, представленные в главе, намного важнее, чем описанные графические средства. По этой причине мы не рекомендуем вам ограничиваться беглым просмотром фрагментов кода — они содержат намного больше интересной информации, чем простое рисование.

15.2. Построение простых графиков

Начнем. Рассмотрим примеры того, что мы можем нарисовать и как это реализовать в программе. В частности, посмотрим на классы графического интерфейса: мы видим параболу, горизонтальную и наклонную линии.

Программирование. Принципы и практика использования C++ Исправленное издание - _156.png

На самом деле, поскольку эта глава посвящена графическим функциям, данная горизонтальная линия — это не просто какая-то горизонтальная линия, а график функции, представленной ниже.

double one(double) { return 1; }

Это самая простая функция, которую мы могли себе представить: она имеет один аргумент и всегда возвращает

1
. Поскольку для вычисления результата этот аргумент не нужен, называть его необязательно. Для каждого значения
x
, переданного в качестве аргумента функции
one()
, получаем значение
y
, равное
1
; иначе говоря, эта линия определяется равенством
(x,y)==(x,1)
при всех
x
.

Как любая вступительная математическая аргументация, наши рассуждения выглядят несколько тривиальными и педантичными, поэтому перейдем к более сложному примеру.

double slope(double x) { return x/2; }

Эта функция порождает наклонную линию. Для каждого аргумента

x
получаем значение
y
, равное
x/2
. Иначе говоря,
(x,y)==(x,x/2)
. Эти две линии пересекаются в точке
(2,1)
.

Теперь можем попытаться сделать кое-что интересное. Напишем квадратичную функцию, которая регулярно будет упоминаться в нашей книге.

double square(double x) { return x*x; }

Если вы помните школьную геометрию (и даже если забыли), то поймете, что эта функция определяет параболу, симметричную относительно оси y, а ее самая нижняя точка имеет координаты

(0,0)
, т.е.
(x,y)==(x,x*x)
. Итак, самая нижняя точка параболы касается наклонной линии в точке
(0,0)
.

Ниже приведен фрагмент кода, который рисует три указанные выше линии.

const int xmax = 600;      // размер окна

const int ymax = 400;

const int x_orig = xmax/2; // точка (0,0) — это центр окна

const int y_orig = ymax/2;

const Point orig(x_orig,y_orig);

const int r_min = –10;     // диапазон [–10:11)

const int r_max = 11;

const int n_points = 400;  // количество точек в диапазоне

const int x_scale = 30;    // масштабные множители

const int y_scale = 30;

Simple_window win(Point(100,100),xmax,ymax,"Function graphing");

Function s(one,r_min,r_max,orig,n_points,x_scale,y_scale);

Function s2(slope,r_min,r_max,orig,n_points,x_scale,y_scale);

Function s3(square,r_min,r_max,orig,n_points,x_scale,y_scale);

win.attach(s);

win.attach(s2);

win.attach(s3);

win.wait_for_button();

Сначала определяем несколько констант, чтобы не перегружать нашу программу “магическими константами”. Затем создаем окно, определяем функции, связываем их с окном и передаем контроль графической системе, которая выполняет реальное рисование на экране.

Все это делается по шаблону, за исключением определений трех объектов класса

Function
:
s
,
s2
и
s3
.

Function s(one,r_min,r_max,orig,n_points,x_scale,y_scale);

Function s2(slope,r_min,r_max,orig,n_points,x_scale,y_scale);

Function s3(square,r_min,r_max,orig,n_points,x_scale,y_scale);

Каждый объект класса

Function
определяет, как их первый аргумент (функция с одним аргументом типа
double
, возвращающая значение типа
double
) будет нарисован в окне. Второй и третий аргументы задают диапазон изменения переменной
x
(аргумента изображаемой функции). Четвертый аргумент (в данном случае
orig
) сообщает объекту класса
Function
, в каком месте окна расположено начало координат
(0,0)
.

 

Программирование. Принципы и практика использования C++ Исправленное издание - _003.png
 Если вы считаете, что в таком количестве аргументов легко запутаться, то мы не станем спорить. В идеале аргументов должно быть как можно меньше, поскольку большое количество аргументов сбивает с толку и открывает возможности для ошибок. Однако пока мы не можем обойтись без них. Смысл последних трех аргументов мы объясним в разделе 15.3, а пока заметим, что первый из них задает метку графика.

 

Программирование. Принципы и практика использования C++ Исправленное издание - _001.png
 Мы всегда стараемся сделать так, чтобы графики были понятны без дополнительных разъяснений. Люди не всегда читают текст, окружающий рисунок, поэтому он часто оказывается бесполезным. Все, что мы изображаем на рисунках, должно помочь читателям понять его. В данном случае мы просто ставим на каждом графике метку. Код для создания метки задается тремя объектами класса
Text
(см. раздел 13.11).

200
{"b":"847443","o":1}