Читаем Программирование полностью

Для представления данных мы используем класс 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

        int dist = length/n;

        int x = xy.x+dist;

        for (int i = 0; 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

      int dist = length/n;

      int y = xy.y–dist;

      for (int i = 0; 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);

} 

15.5. Аппроксимация

Перейти на страницу:
Нет соединения с сервером, попробуйте зайти чуть позже