Шрифт:
cpl.add(Point(250,250));
cpl.add(Point(300,200));
Как и ожидалось, результат идентичен тому, что мы получили в разделе 13.6, за исключением последнего отрезка.
Определение класса
Closed_polyline
приведено ниже.
struct Closed_polyline:Open_polyline { // замкнутый ряд линий
void draw_lines const;
};
void Closed_polyline::draw_lines const
{
Open_polyline::draw_lines; // сначала рисуем открытый ряд линий,
// затем рисуем замыкающую линию:
if (color.visibility)
fl_line(point(number_of_points–1).x,
point(number_of_points–1).y,
point(0).x,
point(0).y);
}
В классе
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));
Результат изображен ниже.
В соответствии с классическими определениями объект класса
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;