Что мы хотим увидеть на экране? Этот ответ можно найти в начале раздела 15.6. На первый взгляд, для изображения данных нужны три объекта класса Open_polyline
clearer
, — поместить метку где-то на самой линии. Кроме того, для того чтобы отличать графики друг от друга, мы используем разные цвета и связываем их с метками.Мы хотим пометить ось
В качестве названия изображения мы решили просто использовать метку окна.
const int xmax = 600; // размер окна
const int ymax = 400;
const int xoffset = 100;// расстояние от левого края окна до оси y
const int yoffset = 60; // расстояние от нижнего края окна до оси х
const int xspace = 40; // пространство между осями
const int yspace = 40;
const int xlength = xmax–xoffset–xspace; // длина осей
const int ylength = ymax–yoffset–yspace;
В принципе эти инструкции определяют прямоугольную область (окно) и вложенный в него прямоугольник (определенный осями).
Без такого схематического представления о размещении элементов экрана в нашем окне с помощью символических констант код был бы безнадежно запутанным.
15.6.3. Масштабирование данных
Теперь мы должны определить, как изобразить данные в описанной области. Для этого масштабируем данные так, чтобы они помещались в прямоугольнике, определенном осями координат. Масштабирование осуществляется с помощью масштабных множителей, представляющих собой отношение диапазона изменения данных и меток на осях.
const int base_year = 1960;
const int end_year = 2040;
const double xscale = double(xlength)/(end_year–base_year);
const double yscale = double(ylength)/100;
Мы объявили наши масштабирующие множители (xscale
yscale
) как числа с плавающей точкой — иначе в наших вычислениях возникли бы серьезные ошибки, связанные с округлением. Для того чтобы избежать целочисленного деления, перед делением преобразовываем наши длины в тип double
(см. раздел 4.3.3).Теперь можно поместить точки на ось
1960
), масштабируя с помощью множителя xscale
и добавляя смещение xoffset
. Значение y обрабатывается аналогично. Эти операции тривиальны, но кропотливы и скучны. Для того чтобы упростить код и минимизировать вероятность ошибок (а также, чтобы не приходить в отчаяние), мы определили небольшой класс, в который включили эти вычисления.class Scale { // класс для преобразования координат
int cbase; // координатная база
int vbase; // база значений
double scale;
public:
Scale(int b,int vb,double s):cbase(b),vbase(vb),scale(s)
{ }
int operator()(int v) const
{ return cbase + (v–vbase)*scale; } // см. раздел 21.4
};
Мы хотим создать класс, поскольку вычисление зависит от трех констант, которые не обязательно повторяются. В этих условиях можно определить следующие функции:
Scale xs(xoffset,base_year,xscale);
Scale ys(ymax–yoffset,0,–yscale);
Обратите внимание на то, что мы сделали масштабирующий множитель ys
xs
для преобразования лет в координату x
. Аналогично можно использовать функцию ys
для преобразования процентов в координату y
. 15.6.4. Построение графика
Итак, у нас есть все предпосылки для создания элегантной программы. Начнем с создания окна и размещения осей.
Window win(Point(100,100),xmax,ymax,"Aging Japan");