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

Text ts(Point(100,y_orig–40),"one");

Text ts2(Point(100,y_orig+y_orig/2–20),"x/2");

Text ts3(Point(x_orig–100,20),"x*x");

win.set_label("Function graphing: label functions");

win.wait_for_button();

С этого момента на протяжении всей главы мы будем пропускать повторяющийся код, связывающий фигуру с окном, присваивающий ей метку и ожидающий щелчка на кнопке Next.

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

 

Программирование. Принципы и практика использования C++ Исправленное издание - _001.png
 Тем не менее этот рисунок еще нельзя считать законченным. Мы уже отметили, что наклонная линия
x/2
касается параболы
x*x
в точке
(0,0)
, а график функции one пересекает линию
x/2
в точке
(2,1)
, но это известно лишь нам; для того чтобы это стало очевидно читателям, на рисунке следует нанести оси координат.

Код для построения осей состоит из объявлений двух объектов класса

Axis
(раздел 15.4).

const int xlength = xmax–40; // оси должны быть чуть меньше окна

const int ylength = ymax–40;

Axis x(Axis::x,Point(20,y_orig), xlength,

     xlength/x_scale, "one notch == 1");

Axis y(Axis::y,Point(x_orig, ylength+20),

     ylength, ylength/y_scale, " one notch == 1");

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

Использование значения

xlength/x_scale
в качестве параметра, задающего количество делений, позволяет использовать целочисленные отметки 1, 2, 3 и т.д. Выбор точки
(0,0)
в качестве начала координат является общепринятым. Если хотите, чтобы начало координат было не в центре, а, как обычно, в левом нижнем углу окна (раздел 15.6), вы легко сможете сделать это. Кроме того, для того чтобы различать оси, можно использовать цвет.

x.set_color(Color::red);

y.set_color(Color::red);

Итак, получаем результат, показанный ниже.

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

 

Программирование. Принципы и практика использования C++ Исправленное издание - _001.png
 Такой рисунок вполне приемлем, но по эстетическим причинам стоило бы сдвинуть линии немного вниз. Кроме того, было бы неплохо отодвинуть метки оси x немного влево. Однако мы не будем этого делать, поскольку эстетический вид графика можно обсуждать до бесконечности. Одно из профессиональных качеств программиста заключается в том, чтобы знать, когда остановиться и потратить сэкономленное время на что-нибудь более полезное (например, на изучение новых методов или на сон). Помните: “лучшее — враг хорошего”.

15.3. Класс Function

Определение класса графического интерфейса

Function
приведено ниже.

struct Function:Shape {

  // параметры функции не хранятся

 Function(Fct f,double r1,double r2,Point orig,

          int count = 100,double xscale = 25,double yscale = 25);

};

Класс

Function
является производным от класса
Shape
. Конструктор класса
Function
генерирует множество отрезков линий и хранит их в членах класса
Shape
. Эти отрезки линий аппроксимируют значения функции
f
. Значения функции
f
вычисляются count раз в точках, равномерно распределенных по интервалу
[r1:r2]
.

Function::Function(Fct f,double r1,double r2,Point xy,

                   int count,double xscale,double yscale)

  // строит график функции f(x) для x из диапазона [r1:r2),

  // используя count отрезков линий;

  // начало координат (0,0) располагается в точке xy

  // координаты x масштабируются множителем xscale

  // координаты y масштабируются множителем yscale

{

  if (r2–r1<=0) error("Неправильный диапазон");

  if (count <=0) error("Отрицательное значение count");

  double dist = (r2–r1)/count;

  double r = r1;

  for (int i = 0; i<count; ++i) {

    add(Point(xy.x+int(r*xscale),xy.y–int(f(r)*yscale)));

    r += dist;

  }

}

Параметры

xscale
и
yscale
используются для масштабирования координат x и y соответственно. Обычно масштабирование необходимо для того, чтобы правильно расположить рисунок в окне.

Обратите внимание на то, что объект класса

Function
не хранит значения, передаваемые его конструктору, поэтому мы не можем впоследствии запросить у функции информацию о том, где находится начало координат, или перерисовать график с другими масштабирующими множителями. Этот объект просто хранит точки (в классе
Shape
) и выводит график на экран. Если бы мы хотели повысить гибкость объекта класса Function после его создания, то должны были бы хранить в нем требуемые значения (см. упр. 2). 

15.3.1. Аргументы по умолчанию

Обратите внимание на способ инициализации аргументов

xscale
и
yscale
конструктора класса Function. Такой способ инициализации называют заданием аргументов по умолчанию (default arguments). Их значения используются тогда, когда при вызове значения аргументов вообще не указываются.