Литмир - Электронная Библиотека
A
A

  if (color().visibility())

    fl_line(point(number_of_points()–1).x,

            point(number_of_points()–1).y,

            point(0).x,

            point(0).y);

}

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

В классе

Closed_polyline
нужна отдельная функция
draw_lines()
, рисующая замыкающую линию, которая соединяет последнюю точку с первой. К счастью, для этого достаточно реализовать небольшую деталь, которая отличает класс
Closed_polyline
от класса
Shape
. Этот важный прием иногда называют “программированием различий“ (“programming by difference”). Нам нужно запрограммировать лишь то, что отличает наш производный класс (
Closed_polyline
) от базового (
Open_polyline
).

Итак, как же нарисовать замыкающую линию? Воспользуемся функцией

fl_line()
из библиотеки FLTK. Она получает четыре аргументы типа
int
, задающих четыре точки. И здесь нам снова понадобится графическая библиотека. Однако обратите внимание на то, что, как и во многих других ситуациях, упоминание библиотеки FLTK скрыто от пользователей. В программе пользователя нет никаких ссылок на функцию
fl_line()
, и ей неизвестно ничего о неявном представлении точек в виде пар целых чисел. При необходимости мы могли бы заменить библиотеку FLTK другой библиотекой графического пользовательского интерфейса, а пользователи этого почти не заметили бы.

13.8. Класс Polygon

Класс Polygon очень похож на класс

Closed_polyline
. Единственная разница состоит в том, что в классе
Polygon
линии не могут пересекаться. Например, объект класса
Closed_polyline
, изображенный выше, был многоугольником, но если к нему добавить еще одну точку, то ситуация изменится.

cpl.add(Point(100,250));

Результат изображен ниже.

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

В соответствии с классическими определениями объект класса

Closed_polyline
многоугольником не является. Как определить класс
Polygon
так, чтобы он правильно отображал связь с классом
Closed_polyline
, не нарушая правил геометрии? Подсказка содержится в предыдущем описании. Класс
Polygon
— это класс
Closed_polyline
, в котором линии не пересекаются. Иначе говоря, мы могли бы подчеркнуть способ образования фигуры из точек и сказать, что класс
Polygon
— это класс
Closed_polyline
, в который невозможно добавить объект класса
Point
, определяющий отрезок линии, пересекающийся с одной из существующих линий в объекте класса
Polygon
.

Эта идея позволяет описать класс

Polygon
следующим образом:

struct Polygon:Closed_polyline { // замкнутая последовательность

                                 // непересекающихся линий

  void add(Point p);

  void draw_lines() const;

};

void Polygon::add(Point p)

{

  // проверка того, что новая линия не пересекает существующие

  // (код скрыт)

  Closed_polyline::add(p);

}

Здесь мы унаследовали определение функции

draw_lines()
из класса
Closed_polyline
, сэкономив усилия и избежав дублирования кода. К сожалению, мы должны проверить каждый вызов функции
add()
. Это приводит нас к неэффективному алгоритму, сложность которого оценивается как N в квадрате, — определение объекта класса
Polygon
, состоящего из N точек, требует N*(N–1)/2 вызовов функции
intersect()
. По существу, мы сделали предположение, что класс
Polygon
будет использоваться для создания многоугольников с меньшим количеством точек.

 Например, для того чтобы создать объект класса

Polygon
, состоящего из 24 точек, потребуется 24*(24–1)/2 == 276 вызовов функции
intersect()
. Вероятно, это допустимо, но если бы мы захотели создать многоугольник, состоящий из 2000 точек, то вынуждены были бы сделать около 2 000 000 вызовов. Мы должны поискать более эффективный алгоритм, который может вынудить нас модифицировать интерфейс.

В любом случае можем создать следующий многоугольник:

Polygon poly;

poly.add(Point(100,100));

poly.add(Point(150,200));

poly.add(Point(250,250));

poly.add(Point(300,200));

Очевидно, что этот фрагмент создает объект класса

Polygon
, идентичный (вплоть до последнего пикселя) исходному объекту класса
Closed_polyline
.

Проверка того, что объект класса

Polygon
действительно представляет собой многоугольник, оказывается на удивление запутанной. Проверка пересечений, которая реализована в функции
Polygon::add()
, является наиболее сложной во всей графической библиотеке. Если вас интересуют кропотливые геометрические манипуляции с координатами, взгляните на код. И это еще не все. Посмотрим, что произойдет, когда мы попытаемся создать объект класса
Polygon
лишь из двух точек. Лучше предусмотреть защиту от таких попыток.

void Polygon::draw_lines() const

{

  if (number_of_points() < 3)

    error("Меньше трех точек вводить нельзя.");

  Closed_polyline::draw_lines();
}

179
{"b":"847443","o":1}