Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Алгоритм Форчуна.docx
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
81.75 Кб
Скачать

Алгоритм Форчуна

В этой статье мы рассмотрим построение диаграммы Вороного с помощью алгоритма Форчуна. Что такое диаграммы Вороного?

Это разбиение метрического пространства на области, в которых находятся объекты, таким образом, что каждому объекту соответствует область пространства, образованная точками, которые находятся ближе к этому объекту, чем к любому другому. Иначе говоря, пространство разделяется на области, содержащие точки или объекты, такого вида, что каждая точка принадлежит области, образованной всем, что ближе к этой точке, чем к какой-либо другой точке[1].

Области применения диаграммы Вороного довольно обширны, ознакомиться со списком можно на википедии[2]. О диаграммах Вороного я узнал благодаря этой статье, после чего решил написать свою реализацию на C++.

Стоит уточнить, что для реализации алгоритма были использованы C++11 и glm. Из glm были использованы вектора и несколько функций для работы с ними. Если необходимости в glm нет, можно определить свой формат векторов. Для визуализации использовались библиотеки lodepng и gif-h.

Исходники компилировались в Qt под Ubuntu и в MS2010 под Windows 7.

Основными требованиями к реализации были:

  • Высокая скорость

  • Низкое потребление памяти

  • Удобный интерфейс

На википедии предложено три алгоритма для построения диаграммы Вороного:

  1. Простой алгоритм

  2. Алгоритм Форчуна

  3. Рекурсивный алгоритм

После не долгих раздумий я выбрал алгоритм Форчуна, он быстрый O(n*log(n)) и имеет не высокое потребление памяти O(n)[3], так же по данному алгоритму есть несколько содержательных англоязычных статей и статья на хабре. Простой алгоритм довольно медленный O(n^2 * log(n)), рекурсивный алгоритм я не рассматривал.

Алгоритм Форчуна основан на применении заметающей прямой. Заметающая прямая — это вспомогательный объект, представляющий собой вертикальную прямую линию. На каждом шаге алгоритма диаграмма Вороного построена для множества, состоящего из заметающей прямой и точек слева от неё. При этом граница между областью Вороного, прямой и областями точек состоит из отрезков парабол (так как геометрическое место точек, равноудалённых от заданной точки и прямой — это парабола). Прямая движется слева направо. Каждый раз, когда она проходит через очередную точку, эта точка добавляется к уже построенному участку диаграммы[4].

Описание алгоритма Форчуна.

Мы будем строить диаграмму Вороного для 2d случая. Заметающая прямая расположена горизонтально и будет опускаться сверху вниз. Начало координат находится в левом нижнем углу. Диаграмма строится в области [O; S], где точка O(0, 0) – начало координат, а точка S – правая верхняя точка, задающая область, с которой мы работаем. По сути значения точки S являются размером рабочей области.

Определимся с несколькими понятиями. Точку из набора входных точек будем называть «точкой» (site). Отрезок, расположенный между двумя точками будем называть «грань» (edge). Точку на конце грани (точка соединения граней) будем называть «вершиной» (vertex).

При пересечении заметающей прямой очередной точки, добавляется новая парабола. Парабола строится по каноническому уравнению параболы. Фокусом параболы являются координаты точки, директрисой параболы является заметающая прямая. В этот момент парабола имеет вид двух совпадающих лучей, т.к. высота заметающей прямой соответствует высоте точки. Если взять огибающую снизу всех парабол, у нас получится «береговая линия». В данном алгоритме мы работаем именно с береговой линией. Береговая линия состоит из «арок». Арка – часть параболы. В береговую линию может входить несколько арок одной и той же параболы. Точку пересечения арок будем называть «брекпоинт» (BreakPoint). Через точку пересечения арок проходит грань, т.е. грань содержит брекпоинт.

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

При скольжении заметающей прямой вниз, можно заметить, что некоторые арки начинают сжиматься, остальные растягиваться. Настанет такой момент, когда одна из арок полностью исчезнет. В этом месте появится точка пересечения граней – «ендпоинт» (EndPoint).

Таким образом мы имеем две основных операции:

  1. Добавление новой параболы в береговую линию.

    • Ищем арку в которую нужно вставить параболу.

    • Разбиваем арку на две, вставляем между ними новую арку. Справа и слева от новой арки, в точках пересечения арок создаем брекпоинты и проходящие через них грани.

  2. Удаление арки

    • Удаляем арку, соединяем арки справа и слева от удаленной.

    • Создаем новый брекпоинт между соединенными арками и грань проходящую через него.

    • Создаем ендпоинт между тремя гранями. Две грани лежали по сторонам удаленной арки, третья грань – новая.

    • Заменяем соответствующие брекпоинты в этих гранях на ендпоинты.