Выпуклая оболочка на плоскости

Иногда приходится решать следующую задачу: дано n неупорядочных точек на плоскости, необходимо найти их выпуклую оболочку. Представленный ниже метод решения этой задачи является вариантом алгоритма "заворачивания подарка". Время работы этого метода пропорционально m * n, где m - количество точек выпуклой оболочки. Существуют более быстрые методы, но этот алгоритм более прост для понимания и реализации, кроме того он эффективен в случае, когда m мало по сравнению с n.

SuiteRef<Vector2d> & convexMN ( SuiteRef<Vector2d> & vert );
Входной параметр - это ссылка на набор точек. Туда же будут записаны точки найденной выпуклой оболочки и их количество.

Существует множество методов построения выпуклой оболочки за время O ( n log n ) в худшем случае. Вот один из них. Идея заключается в следующем. Вначале исходные точки упорядочиваются по возрастанию координаты X, а в случае равенства по Y. Для этой цели используется сортировка слияниями, которая сделает это за время O ( n log n ) в худшем случае:

void mergeSort123 ( nat n, const Vector2d ** a, const Vector2d ** b );

После этого проводится прямая линия проходящая через первую и последнюю точки, и строятся выпуклые оболочки отдельно для точек лежащих ниже линии и выше. Это займёт время O ( n ).

SuiteRef<Vector2d> & convexNlogN ( CArrRef<Vector2d> vert, SuiteRef<Vector2d> & res );
SuiteRef<  nat   > & convexNlogN ( CArrRef<Vector2d> vert, SuiteRef<  nat   > & res );

Алгоритм реализован в виде двух функций. В первой функции res - это ссылка на набор точек, а во второй - ссылка на набор индексов точек. Ссылки vert и res должны указывать на разные наборы. Этот алгоритм в моих экспериментах работал на случайных точках в 10 и более раз быстрее, чем предыдущий.

Если исходные точки являются вершинами простого многоугольника, то в этом случае выпуклую оболочку можно построить за время O ( n ). Следующий алгоритм был взят с небольшими изменениями из книги "Вычислительная геометрия" (Препарата, Шеймос) пункт 4.1.4:

SuiteRef<nat> & convexPolygon ( CArrRef<Vector2d> vert, SuiteRef<nat> & index );

DynArrRef<Vector2d> & convexPolygon ( CArrRef<Vector2d> vert, DynArrRef<Vector2d> & res );

DynArrRef<Vector2d> & convexPolygon ( DynArrRef<Vector2d> & vert );

Как обычно обход вершин полагается против часовой стрелки. Во втором варианте алгоритма указатели vert и res могут указывать на один массив.

Описание шаблонов классов CArrRef, DynArrRef и SuiteRef находится здесь.
Описание класса Vector2d находится здесь.

Исходники алгоритмов находятся в файле func2d.cpp.

Наверх

Hosted by uCoz