Класс Polygon (Многоугольник)
Полигоном(многоугольником) называется замкнутая ломаная на плоскости. Отрезки ломаной называются ребрами или сторонами полигона, концевые точки отрезков, совпадающие для двух соседних ребер, называются вершинами. Полигон будет простым, если он не пересекает самого себя(или, что то же, в нем нет 'дыр'). Простой полигон охватывает непрерывную область плоскости, которая считается внутренней частью полигона. Неограниченная область, окружающая простой полигон, образует внешнюю часть, а набор точек, лежащих на самом полигоне, образует границу между этими двумя частями. Класс Polygon описывает простой заполненный многоугольник, т.е. объединение границы и внутренней части простого полигона. Например, если говорится, что точка находится в полигоне, то это означает принадлежность точки либо границе простого полигона, либо его внутренней части.
Класс Vertex (Вершина)
Мы будем представлять полигон в виде кольца вершин, хранящегося в кольцевом списке с двойными связями. Каждый узел соответствует вершине и связан со своими двумя соседями. Следуя связям, мы можем обойти границу полигона в любом направлении, а включая или удаляя узлы (редактируя связи соответствующим образом), мы можем создавать полигоны и динамически их модифицировать.
Эту схему обеспечивают классы Vertex и Polygon. Полигон хранится в виде циклического списка объектов класса Vertex с двойными связями. Поскольку вершины полигона существуют одновременно как точки на плоскости и узлы в связном списке, класс Vertex формируется на основе класса Point и класса Node. Класс Polygon содержит элемент данных, указывающий на некоторую вершину в связном списке, представляющем полигон. Класс Polygon служит как общедоступный (public) интерфейс для полигонов.
Класс Vertex наследует элементы данных _next и _prev из базового класса Node(узел списка) и х и у из базового класса Point. По соглашению _next указывает на последователя текущей вершины (ее соседа в направлении по часовой стрелке), a _prev - на предшественника текущей вершины (соседа в направлении против часовой стрелки).
class Node { // Узел кольцевого двойного списка protected: Node *_next; // связь к последующему узлу Node *_prev; // связь к предшествующему узлу public: Node (void); virtual ~Node (void); Node *next(void); Node *prev(void); Node *insert(Node*); // вставить узел после текущего Node *remove(void); // удалить узел из списка, возвратить его указатель void splice(Node*); // слияние/разделение кольцевых списков };
class Vertex: public Node, public Point { public: Vertex (double x, double y); Vertex (Point&); Vertex *cw(void); Vertex *ccw(void); Vertex *neighbor (int rotation); Point point (void); Vertex *insert (Vertex* ); Vertex *remove (void); void splice (Vertex*); Vertex *split (Vertex*); friend class Polygon; } };
Объект класса Vertex может быть сформирован на основе точки или по ее координатам х и у.
Vertex::Vertex (double x, double у) : Point (x, у) { }
Vertex::Vertex (Point &p) : Point (p) { }
Компонентные функции cw и ccw возвращают указатели на последователя и предшественника текущей вершины соответственно.
Vertex *Vertex::cw(void) { return (Vertex*)_next; }
Vertex *Vertex::ccw(void) { return (Vertex*)_prev; }
Компонентная функция neighbor сообщает, какой из соседей определен параметром rotation, возвращая одно из значений типа перечисления CLOCKWISE или COUNTER_CLOCKWISE
Vertex *Vertex::neighbor (int rotation) { return ((rotation == CLOCKWISE) ? cw() : ccw()); }
Компонентная функция point возвращает точку на плоскости, в которой находится текущая вершина
Point Vertex::point(void) { return *((Point*)this); }
Компонентные функции insert , remove и splice соответствуют своим аналогам, определенным в базовом классе Node.
Vertex *Vertex::insert (Vertex *v) { return (Vertex *) (Node::insert (v)); }
Vertex *Vertex::remove (void) { return (Vertex *) (Node::remove ()); } void Vertex::splice (Vertex *b) { Node::splice (b); }
Заметим, что в функциях insert и remove перед выводом производится преобразование возвращаемых значений к типу указатель_на_Vertех. Явное преобразование необходимо здесь потому, что язык C++ не может автоматически преобразовать указатель из базового класса, чтобы указать на объект производного класса. Причина заключается в том, что компилятор языка C++ не может быть уверенным в том, что имеется объект производного класса, на который нужно указать, поскольку объект базового класса не обязательно должен быть частью объекта производного класса (но, с другой стороны, компилятор языка C++ автоматически преобразует указатель на производный класс для указания на объект базового класса, поскольку каждый объект производного класса включает внутри себя объект базового класса).
Последняя компонентная функция Vertex::split будет определена несколько ниже.
1 2 3 4
8 8 8
|