Function s5(sloping_cos, r_min,r_max,orig,400,20,20);
x.label.move(–160,0);
x.notches.set_color(Color::dark_red);
Кроме
сложения этих двух функций, мы сместили метку оси x и (просто для иллюстрации) немного изменили цвет шкалы деления.
В заключение построим графики логарифма, экспоненты, синуса и косинуса.
Function f1(log,0.000001,r_max,orig,200,30,30); // ln
Function f2(sin,r_min,r_max,orig,200,30,30); // sin
f2.set_color(Color::blue);
Function f3(cos,r_min,r_max,orig,200,30,30); // cos
Function f4(exp,r_min,r_max,orig,200,30,30); // exp
Поскольку значение
log(0)
не определено (с математической точки зрения оно равно бесконечности), мы начали диапазон изменения функции
log
с небольшого положительного числа. Результат приведен ниже.
Вместо приписывания меток этим графикам мы изменили их цвет.
Стандартные математические функции, такие как
cos
,
sin
и
sqrt
, объявлены в стандартном библиотечном заголовке
<cmath>
. Список стандартных математических функций приведен в разделах 24.8 и B.9.2.
15.4. Оси
Для представления данных мы используем класс
Axis
(например, как в разделе 15.6.4), поскольку график без информации о его масштабе выглядит подозрительно. Класс
Axis
состоит из линии, определенного количества делений оси и текстовой метки. Конструктор класса
Axis
вычисляет координаты линии оси и (при необходимости) линий, используемых как деления оси.
struct Axis:Shape {
enum Orientation { x, y, z };
Axis(Orientation d, Point xy, int length,
int number_of_notches=0, string label = "");
void draw_lines const;
void move(int dx, int dy);
void set_color(Color c);
Text label;
Lines notches;
};
Объекты
label
и
notches
остаются открытыми, поэтому пользователи могут ими манипулировать, например приписывать делениям цвет, отличающийся от цвета линии, или перемещать объект
label
с помощью функции
move
в более удобное место. Объект класса
Axis
— это пример объекта, состоящего из нескольких полунезависимых
объектов.
Конструктор класса
Axis
размещает линии и добавляет на них деления, если значение
number_ of_notches
больше нуля.
Axis::Axis(Orientation d, Point xy, int length, int n, string lab)
:label(Point(0,0),lab)
{
if (length<0) error("bad axis length");
switch (d){
case Axis::x:
{
Shape::add(xy); // линия оси
Shape::add(Point(xy.x+length,xy.y));
if (0<n) { // добавляет деления
int dist = length/n;
int x = xy.x+dist;
for (int i = 0; i<n; ++i) {
notches.add(Point(x,xy.y),Point(x,xy.y–5));
x += dist;
}
}
label.move(length/3,xy.y+20); // размещает метку под линией
По сравнению с большинством реальных программ этот конструктор очень прост, но мы рекомендуем внимательно изучить его, поскольку он не настолько тривиален, как кажется, и иллюстрирует несколько полезных приемов. Обратите внимание на то, как мы храним линию в части класса
Shape
, унаследованной классом
Axis
(используя функцию
Shape::add
), хотя деления хранятся в виде отдельного объекта (
notches
). Это позволяет нам манипулировать линией и делениями оси независимо друг от друга; например, мы можем раскрасить их в разные цвета. Аналогично метка была помещена в фиксированное положение, но, поскольку она является независимым объектом, мы всегда можем переместить ее в другое место. Для удобства используем перечисление
Orientation
.
Поскольку класс
Axis
состоит из трех частей, мы должны предусмотреть функции для манипулирования объектом класса
Axis
в целом. Рассмотрим пример.
void Axis::draw_lines const
{
Shape::draw_lines;
notches.draw; // цвет делений может отличаться от цвета линии
label.draw; // цвет метки может отличаться от цвета линии