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); // размещает метку под линией
break;
}
case Axis::y:
{ Shape::add(xy); // ось y перемещаем вверх
Shape::add(Point(xy.x,xy.y–length));
if (0<n) { // добавляем деления
int dist = length/n;
int y = xy.y–dist;
for (int i = 0; i<n; ++i) {
notches.add(Point(xy.x,y),Point(xy.x+5,y));
y –= dist;
}
}
label.move(xy.x–10,xy.y–length–10); // размещает метку
// наверху
break;
}
case Axis::z:
error("ось z не реализована");
}
}
По сравнению с большинством реальных программ этот конструктор очень прост, но мы рекомендуем внимательно изучить его, поскольку он не настолько тривиален, как кажется, и иллюстрирует несколько полезных приемов. Обратите внимание на то, как мы храним линию в части класса
Shape
, унаследованной классом
Axis
(используя функцию
Shape::add()
), хотя деления хранятся в виде отдельного объекта (
notches
). Это позволяет нам манипулировать линией и делениями оси независимо друг от друга; например, мы можем раскрасить их в разные цвета. Аналогично метка была помещена в фиксированное положение, но, поскольку она является независимым объектом, мы всегда можем переместить ее в другое место. Для удобства используем перечисление
Orientation
.
Поскольку класс
Axis
состоит из трех частей, мы должны предусмотреть функции для манипулирования объектом класса
Axis
в целом. Рассмотрим пример.
void Axis::draw_lines() const
{
Shape::draw_lines();
notches.draw(); // цвет делений может отличаться от цвета линии
label.draw(); // цвет метки может отличаться от цвета линии
}
Для рисования объектов
notches
и
label
мы используем функцию
draw()
а не
draw_lines()
, чтобы иметь возможность использовать информацию о цвете, которая в них хранится. Объект класса
Lines
хранится в разделе
Axis::Shape
и использует информацию о цвете, хранящуюся там же.
Мы можем задать цвет линии, деления и метки по отдельности, но с точки зрения красоты стиля этого лучше не делать, а задать их все с помощью одной функции.
void Axis::set_color(Color c)
{
Shape::set_color(c);
notches.set_color(c);
label.set_color(c);
}
Аналогично, функция
Axis::move()
перемещает все три части объекта класса
Axis
одновременно.
void Axis::move(int dx, int dy)
{
Shape::move(dx,dy);
notches.move(dx,dy);
label.move(dx,dy);
}