Пересечение многоугольников (PSLG overlaying) — различия между версиями

Материал из Викиконспекты
Перейти к: навигация, поиск
Строка 7: Строка 7:
 
Даны два [[ППЛГ и РСДС (PSLG и DCEL): определение, построение РСДС множества прямых|ППЛГ]], требуется построить их объединение в виде [[ППЛГ и РСДС (PSLG и DCEL): определение, построение РСДС множества прямых|РСДС]]. При этом создав новые <tex>face</tex> и обновив старые.
 
Даны два [[ППЛГ и РСДС (PSLG и DCEL): определение, построение РСДС множества прямых|ППЛГ]], требуется построить их объединение в виде [[ППЛГ и РСДС (PSLG и DCEL): определение, построение РСДС множества прямых|РСДС]]. При этом создав новые <tex>face</tex> и обновив старые.
  
==Алгоритм==
+
===Формально===
'''MapOverlay (<tex>S_1</tex>, <tex>S_2</tex>)''' <tex>:</tex>
+
 
 +
Определим объединение двух pslg <tex>S1</tex> и <tex>S2</tex>, чтобы получился граф <tex>O(S1, S2)</tex>, такой, что существует <tex>face</tex> f в <tex>O(S1, S2)</tex>, тогда и только тогда есть <tex>face</tex> f1 и f2 в <tex>S1</tex> и <tex>S2</tex> соответственно, что <tex>f</tex> является максимально связанным подмножеством <tex>f1 \cap f2</tex>. Требуется чтобы каждый <tex>face</tex> в <tex>O(S1, S2)</tex> был отмечен с помощью label of the <tex>faces</tex> в <tex>S1</tex> и <tex>S2</tex>, который содержит их. Таким образом мы получаем доступ к информации хранящейся на этих <tex>faces</tex>.
 +
 
 +
===Алгоритм===
  
1. Копируем <tex>S_1</tex> и <tex>S_2</tex> в граф <tex>D</tex>.
+
====Первоначальное слияние====
  
2. Находим все пересечения ребер из <tex>S_1</tex> с ребрами из <tex>S_2</tex> с помощью заметающей прямой.
+
Для начала посмотрим, как можно больше информации от doubly connected edge lists для <tex>S1</tex> и <tex>S2</tex> мы можем повторно использовать в doubly connected edge lists для <tex>O(S1, S2)</tex>. Рассмотрим сеть ребер и вершин S1. Эта сеть разделена на кусочки краями <tex>S2</tex>. Эти кусочки в большинстве своем могут использоваться повторно, все, за исключением тех, которые отделены краями <tex>S2</tex>. Такие нужно обновлять. Если ориентация <tex>half-edge</tex> изменится, нам придется менять информацию в этих записях. Половинки ребра ориентированы таким образом, что <tex>face</tex>, которым они связаны лежит слева; форма <tex>face</tex> может изменяться в наложении, но он будет оставаться в той же стороне <tex>half-edge</tex>. Следовательно, мы можем повторно использовать <tex>half-edge</tex> records, соответствующие краям, которые не пересекаются ребра из другой карты. Иными словами, есть только <tex>half-edge</tex> records в <tex>DCEL</tex> для <tex>O(S1, S2)</tex>, которые мы не можем заимствовать из <tex>S1</tex> или <tex>S2</tex>, ими являются те, которые попадают на пересечение между краями из разных карт.
 +
Это предлагает следующие подходы. Во-первых, скопировать doubly­connected edge lists <tex>S1</tex> и <tex>S2</tex> в один новый <tex>DCEL</tex>. Новый <tex>DCEL</tex> не является допустимым <tex>DCEL</tex>, т.к. он еще не представляет собой плоский подграф.
  
2.1 Когда находим точки пересечения, то обновляем <tex>D</tex>, то есть строим из него [[ППЛГ и РСДС (PSLG и DCEL): определение, построение РСДС множества прямых|РСДС]].
+
====Объединения графов====
  
3. Теперь <tex>D</tex> это нормальный [[ППЛГ и РСДС (PSLG и DCEL): определение, построение РСДС множества прямых|РСДС]], но без информации о <tex>face</tex>'ах.
+
Это задача алгоритма заметающей прямой: он должен трансформировать <tex>DCEL</tex> в допустимый <tex>DCEL</tex> для <tex>O(S1, S2)</tex> путем вычисления пересечения между двумя сетями ребер, и связывая воедино соответствующие части из двух <tex>DCEL</tex>. Мы применяем этот алгоритм на множестве сегментов, что является объединением множеств ребер двух подграфов <tex>S1</tex> и <tex>S2</tex>. Напомним, что алгоритм поддерживается двумя структурами данных: очереди событий <tex>Q</tex>, в котором хранятся точки событий, и структура состояния <tex>T</tex>, которой является бинарное дерево храненящее сегменты, пересекающие линии развертки, расположенные слева направо. Мы теперь также должны поддерживать <tex>DCEL</tex> <tex>D</tex>. Первоначально <tex>D</tex> содержит копию <tex>DCEL</tex> для <tex>S1</tex> и <tex>DCEL</tex> для <tex>S2</tex>. В плоскости развертки преобразуем <tex>D</tex> к правильному <tex>DCEL</tex> для <tex>O(S1, S2)</tex>. Мы держим перекрестные указатели между ребер в структуре состояния <tex>T</tex> и половина текущих записей в <tex>D</tex>, которые соответствуют им. Таким образом мы можем получить доступ к части <tex>D</tex>, которая должна быть изменена, когда мы сталкиваемся с точкой пересечения.  
  
4. Находим boundary cycles в <tex>D</tex>. То есть обновляем этот граф. Пока только добавляя в него ребра (<tex>half-edge</tex>'ы соответственно).
+
В другом случае, мы поддерживаем то, что в любое время в течение развертки, часть выше линии развертки наложения будет считаться правильной. Теперь что мы должны делать, когда мы достигнем точки событий. Прежде всего, мы обновляем <tex>T</tex> и <tex>Q</tex>, как и в алгоритме заметающей прямой. Если событие включает в себя только ребра из одного из двух подграфов, это все, точка событие является вершиной, которые могут быть использованы повторно. Если событие включает края с двух подграфов, мы должны сделать локальные изменения в <tex>D</tex> -- связать doubly­ connected edge list двух оригинальных подграфов в точке пересечения.
  
5. Создаем граф <tex>G</tex> (о нем ниже), в котором узлы будут отвечать за boundary cycles и в котором ребра будут соединять только те узлы, один из которых будет являться границей дыры (<tex>hole</tex>, это внутренний цикл <tex>face</tex>'a), а другой будет находиться слева от самой левой точки первого. (В случае, если это самая внешняя граница, то для нее пусть будет мнимая гигантская граница, с которой мы ее и соединим).
+
Рассмотри один из 2 возможных случаев, а именно, когда edge <tex>е</tex> из <tex>S1</tex> проходит через вершину <tex>V</tex> <tex>S2</tex>, (см. Рисунок) edge <tex>е</tex> должно быть заменено двумя edges обозначим <tex>e'</tex> и <tex>e''</tex>. В <tex>DCEL</tex>, два <tex>half-edge</tex> для е должны превратиться в четыре. Мы создаем два новых <tex>half-edge</tex>, с <tex>V</tex> в нуле. Два существующих <tex>half-edge</tex> для е содержат конечные точки <tex>e</tex>, как их происхождения. Тогда мы объединяем попарно существующие <tex>half-edges</tex> с новыми <tex>half-edges</tex>, устанавливая их указатели twin'ов. Так <tex>e'</tex> представлен одним новым и одним существующим частично edge, и то же самое для <tex>e''</tex>. Теперь мы должны установить ряд <tex>Prev</tex> и <tex>Next</tex>. <tex>Next</tex> двух новых <tex>half-edges</tex> являются копией <tex>Next</tex> старого <tex>half-edge</tex>, не имеющего пары. В <tex>half-edges</tex>, в которые эти указатели точки должны обновлять свои <tex>Prev</tex> и установливать его на новых <tex>half-edges</tex>. Далее мы должны установить <tex>Next</tex> и <tex>Prev</tex> четырех <tex>half-edges</tex> представляющих <tex>e'</tex> и <tex>e''</tex>, и из четырех <tex>half-edges</tex> инциденого <tex>S2</tex> <tex>v</tex>. Мы размещаем эти четыре <tex>half-edges</tex> от <tex>S2</tex>, проверяя, где <tex>e'</tex> и <tex>e''</tex> должны быть в циклическом порядке вершин вокруг вершины <tex>v</tex>. Есть четыре пары <tex>half-edges</tex>, которые связанны между собой <tex>Next</tex> с одним и <tex>Prev</tex> с другим. <tex>e'</tex> должен быть привязан к первому <tex>half-edge</tex> по часовой стрелке с началом в <tex>v.</tex> <tex>half-edge</tex> для <tex>e'</tex> с началом в <tex>v</tex> должен быть связан с первым против часовой стрелки <tex>half-edge</tex> с окончанием в <tex>v</tex>. Точно также и для <tex>e''</tex>.  
  
5.1. Для каждой компоненты графа:
+
====Время работы объединения====
  
Пусть <tex>C</tex> будет уникальная наружная граница цикла в компоненте, а <tex>f</tex> будет означать face ограниченный этим циклом. Создадим face для <tex>f</tex>. Запишем <tex>outer\_component</tex> в какой-нибудь <tex>half-edge</tex> из <tex>C</tex>. И создадим список <tex>inner\_components</tex>, состоящий из указателей на какой-нибудь <tex>half-edge</tex> из каждого цикла. А так же пусть <tex>incident\_face</tex> в каждом <tex>half-edge</tex> будут обновлены на <tex>f</tex>.
+
Большинство из шагов в приведенном выше описании принимать только константное время. Есть случаи на которые потребуется дополнительное время, О(M), где M­число ребер, точки событий. Это означает, что обновление <tex>D</tex> не увеличивает время работы алгоритма заметащей прямой асимптотически. Любое пересечение, которое мы находим является вершиной наложения. Из этого следует, что вершина record и <tex>half-edge</tex> record doubly­ connected edge list для <tex>O(S1, S2)</tex> можно вычислить в <tex>O(N\ *\ log N\ +\ k\ *\ log\ n)</tex> время, где <tex>n</tex> обозначает сумму сложностей <tex>S1</tex> и <tex>S2</tex>, а k является сложностью наложения.
  
 +
====Воссоздание <tex>faces</tex>====
 +
После того, как все сделано, осталось вычислить информацию о <tex>faces</tex> в <tex>O(S1, S2)</tex>. Точнее, мы должны создать <tex>face</tex> record для каждого <tex>face</tex> е в <tex>O(S1, S2)</tex>, мы должны сделать <tex>outer\_component</tex> (<tex>e</tex>) указывают на <tex>half-edges</tex> на внешней границе <tex>F</tex>, и мы должны сделать список <tex>inner\_components</tex> (<tex>F</tex>) из указателей на <tex>half-edges</tex> на связанных областях пробелов внутри <tex>f</tex>. Кроме того, мы должны установить <tex>incident\_face</tex> () поля времени <tex>half-edges</tex> на границе <tex>F</tex> так, что они указывают на лицевые записи <tex>F</tex>. Наконец, каждый из новых <tex>faces</tex> должны быть помечены именами <tex>faces</tex> в старых подграфах, которые содержат его. Рассмотрим два <tex>half-edges</tex> цикла, свойственных <tex>v</tex>. Т.к. мы знаем, что incident <tex>face</tex> лежит слева, мы можем вычислить угол который эти два <tex>half-edges</tex> образуют внутри <tex>face</tex>. Если этот угол f меньше, чем 180◦ то циклом является внешняя граница, и в противном случае это граница дыры. Это свойство имеет место для левой вершины цикла, но не обязательно для других вершин этого цикла.
  
 +
{{Лемма
 +
|about=
 +
К предыдущему вопросу
 +
|statement=
 +
Каждая компонента графа отвечает за множество циклов инцидентных одному <tex>face</tex>.
 +
|proof= Рассмотрим цикл <tex>C</tex>, который ограничивает дыру в <tex>face</tex> <tex>f</tex>. Поскольку <tex>f</tex> локально лежит левее самой левой вершины из <tex>C</tex>, то <tex>C</tex> должен быть соединен с другим циклом, который тоже ограничивает <tex>f</tex>. отсюда следует, что циклы есть компонента связности в графе, описывающая один и тот-же <tex>face</tex>. Для того, что бы закончить доказательство, покажем, что каждый цикл ограничивающий дыру в <tex>f</tex> есть в той же компоненте связности, что и внешняя граница <tex>f</tex>. Предположим, что есть цикл, для которого это не так.  Пусть <tex>C</tex> — самый левый такой цикл, то есть тот, чья самая левая вершина самая левая (шляпа). По определению есть ребро между <tex>C</tex> и неким <tex>C'</tex>, который лежит слева от самой левой вершины <tex>C</tex>. Следовательно <tex>C</tex> в той же компоненте связности, что и <tex>C'</tex>, который не в той же компоненте, что внешняя граница <tex>f</tex>. Противоречие.
 +
}}
  
 +
Напомним, что в алгоритме развертки плоскости для отрезка пересечения мы всегда искали сегменты сразу слева от точки событий. (Они должны были быть проверены на пересечении с крайнего левого края через точку событий.) Таким образом, информация, при помощи которой мы должны построить <tex>G</tex> определяется в плоскости развертки. Таким образом, чтобы построить <tex>G</tex>, мы сначала делаем узел для каждого цикла. Чтобы найти дуги <tex>G</tex>, рассмотрим левую вершину <tex>V</tex> для каждого цикла, ограничивающую отверстие. Если <tex>half-edge</tex> сразу же выходит из <tex>V</tex>, то мы добавляем дугу между двумя узлами в <tex>G</tex>, представляющих цикл, содержащий  е и цикл у которого <tex>V</tex> является самой левой вершиной. Чтобы найти эти узлы в <tex>G</tex> мы должны указатели от каждого <tex>half-edge</tex> записать в узел <tex>G</tex>, представляющего цикл этот. Так информация o <tex>face</tex> в doubly­connected edge list может быть установлена в <tex>О(n\ +\ k)</tex> времени, после плоскости развертки. Каждая грань <tex>e</tex> в наложении должна быть помечена с именами <tex>face</tex> в старых графах, которые содержали его. Чтобы найти эти <tex>face</tex>, надо рассмотреть произвольную вершину <tex>V</tex> в <tex>F</tex>. Если <tex>v</tex> является пересечением <tex>e1</tex> от <tex>S1</tex> и <tex>е2</tex> от <tex>S2</tex>, то мы можем решить, какие <tex>face</tex> из <tex>S1</tex> и <tex>S2</tex> содержат <tex>F</tex>, глядя на <tex>incident\_face</tex> указатель соответствующих <tex>half-edges</tex> соответствующих <tex>e1</tex> и <tex>e2</tex>. Если <tex>v</tex> не пересечение, но вершина, скажем, S1, то мы знаем только <tex>face</tex> S1, содержащей <tex>f</tex>. Чтобы найти <tex>face</tex> <tex>S2</tex> , содержащий <tex>F</tex>, мы должны определить <tex>face</tex> <tex>S2</tex>, которое содержит <tex>v</tex>. Другими словами, если бы мы знали для каждой вершины <tex>S1</tex>, в котором <tex>face</tex> <tex>S2</tex> находился, и наоборот, то мы могли бы обозначить <tex>face</tex> <tex>O(S1, S2)</tex> правильно.
  
  
  
 +
==Итог==
 +
'''MapOverlay (<tex>S_1</tex>, <tex>S_2</tex>)''' <tex>:</tex>
  
==Q&A==
+
1. Копируем <tex>S_1</tex> и <tex>S_2</tex> в граф <tex>D</tex>.
*'''Копирование РСДС'''
 
Просто объединение в одну структуру. Как сделать его правильным - это уже следующие пункты.
 
  
*'''Как из пересечения ребер сделать новую компоненту РСДС'''
+
2. Находим все пересечения ребер из <tex>S_1</tex> с ребрами из <tex>S_2</tex> с помощью заметающей прямой.
См рисунок.
 
  
*'''Сколько будет faces?'''
+
2.1 Когда находим точки пересечения, то обновляем <tex>D</tex>, то есть строим из него [[ППЛГ и РСДС (PSLG и DCEL): определение, построение РСДС множества прямых|РСДС]].
Столько же, сколько <tex>outer\_boudaries</tex> + 1.
 
  
*'''Как узнать, что данный цикл это внешняя граница для face или же это дыра в нем?'''
+
3. Теперь <tex>D</tex> это нормальный [[ППЛГ и РСДС (PSLG и DCEL): определение, построение РСДС множества прямых|РСДС]], но без информации о <tex>face</tex>'ах.
Мы знаем, что face находится слева от half-edge. Поэтому возьмем самую левую точку (в случаем, если их несколько, то самую нижнюю) и возьмем входящий и выходящий из нее half-edge. В случае угла между ними менее 180 градусов, то это внешняя граница, иначе это дыра. Это действует только для самой левой точки из цикла.
 
  
*'''Что за граф и для чего он нужен? (Граф <tex>D</tex> из 5 пункта)'''
+
4. Находим boundary cycles в <tex>D</tex>. То есть обновляем этот граф. Пока только добавляя в него ребра (<tex>half-edge</tex>'ы соответственно).
См рисунок. Из него мы сможем понять, какие циклы принадлежат одному и тому же face. Например, в рисунке мы видим, что C2, C3 и C6 являются циклами одного face. Из предыдущего вопроса мы понимаем, что C2 есть внешняя граница.
 
  
Подробнее:
+
5. Создаем граф <tex>G</tex> (о нем ниже), в котором узлы будут отвечать за boundary cycles и в котором ребра будут соединять только те узлы, один из которых будет являться границей дыры (<tex>hole</tex>, это внутренний цикл <tex>face</tex>'a), а другой будет находиться слева от самой левой точки первого. (В случае, если это самая внешняя граница, то для нее пусть будет мнимая гигантская граница, с которой мы ее и соединим).
  
{{Лемма
+
5.1. Для каждой компоненты графа:
|about=
 
К предыдущему вопросу
 
|statement=
 
Каждая компонента графа отвечает за множество циклов инцидентных одному face.
 
|proof= Рассмотрим цикл <tex>C</tex>, который ограничивает дыру в face <tex>f</tex>. Поскольку <tex>f</tex> локально лежит левее самой левой вершины из <tex>C</tex>, то <tex>C</tex> должен быть соединен с другим циклом, который тоже ограничивает <tex>f</tex>. отсюда следует, что циклы есть компонента связности в графе, описывающая один и тот-же face. Для того, что бы закончить доказательство, покажем, что каждый цикл ограничивающий дыру в <tex>f</tex> есть в той же компоненте связности, что и внешняя граница <tex>f</tex>. Предположим, что есть цикл, для которого это не так.  Пусть <tex>C</tex> — самый левый такой цикл, то есть тот, чья самая левая вершина самая левая (шляпа). По определению есть ребро между <tex>C</tex> и неким <tex>C'</tex>, который лежит слева от самой левой вершины <tex>C</tex>. Следовательно <tex>C</tex> в той же компоненте связности, что и <tex>C'</tex>, который не в той же компоненте, что внешняя граница <tex>f</tex>. Противоречие.
 
}}
 
  
*'''Как построить этот граф?'''
+
Пусть <tex>C</tex> будет уникальная наружная граница цикла в компоненте, а <tex>f</tex> будет означать face ограниченный этим циклом. Создадим face для <tex>f</tex>. Запишем <tex>outer\_component</tex> в какой-нибудь <tex>half-edge</tex> из <tex>C</tex>. И создадим список <tex>inner\_components</tex>, состоящий из указателей на какой-нибудь <tex>half-edge</tex> из каждого цикла. А так же пусть <tex>incident\_face</tex> в каждом <tex>half-edge</tex> будут обновлены на <tex>f</tex>.
Вспоминаем, что во время работы алгоритма заметающей прямой, мы смотрели на отрезки левее от event point. Из этого получаем, что информацию для постройки нашего графа мы получаем из этого алгоритма. То есть для начала мы делаем узел для каждого цикла, затем для создания ребер мы смотри на самые левые вершины циклов. Если есть half-edge слева от вершины, то создаем ребро между циклами (в котором вершина и в котором half-edge).
 
  
  
 
== Литература и источники ==
 
== Литература и источники ==
 
* Вычислительная геометрия. Алгоритмы и приложения, де Берг Марк и другие. Глава 2.3
 
* Вычислительная геометрия. Алгоритмы и приложения, де Берг Марк и другие. Глава 2.3

Версия 22:16, 28 марта 2014

Input [math]\Rightarrow[/math] Output
Создание новой компоненты
Создание новой компоненты
Граф для поиска face

Постановка задачи

Даны два ППЛГ, требуется построить их объединение в виде РСДС. При этом создав новые [math]face[/math] и обновив старые.

Формально

Определим объединение двух pslg [math]S1[/math] и [math]S2[/math], чтобы получился граф [math]O(S1, S2)[/math], такой, что существует [math]face[/math] f в [math]O(S1, S2)[/math], тогда и только тогда есть [math]face[/math] f1 и f2 в [math]S1[/math] и [math]S2[/math] соответственно, что [math]f[/math] является максимально связанным подмножеством [math]f1 \cap f2[/math]. Требуется чтобы каждый [math]face[/math] в [math]O(S1, S2)[/math] был отмечен с помощью label of the [math]faces[/math] в [math]S1[/math] и [math]S2[/math], который содержит их. Таким образом мы получаем доступ к информации хранящейся на этих [math]faces[/math].

Алгоритм

Первоначальное слияние

Для начала посмотрим, как можно больше информации от doubly connected edge lists для [math]S1[/math] и [math]S2[/math] мы можем повторно использовать в doubly connected edge lists для [math]O(S1, S2)[/math]. Рассмотрим сеть ребер и вершин S1. Эта сеть разделена на кусочки краями [math]S2[/math]. Эти кусочки в большинстве своем могут использоваться повторно, все, за исключением тех, которые отделены краями [math]S2[/math]. Такие нужно обновлять. Если ориентация [math]half-edge[/math] изменится, нам придется менять информацию в этих записях. Половинки ребра ориентированы таким образом, что [math]face[/math], которым они связаны лежит слева; форма [math]face[/math] может изменяться в наложении, но он будет оставаться в той же стороне [math]half-edge[/math]. Следовательно, мы можем повторно использовать [math]half-edge[/math] records, соответствующие краям, которые не пересекаются ребра из другой карты. Иными словами, есть только [math]half-edge[/math] records в [math]DCEL[/math] для [math]O(S1, S2)[/math], которые мы не можем заимствовать из [math]S1[/math] или [math]S2[/math], ими являются те, которые попадают на пересечение между краями из разных карт. Это предлагает следующие подходы. Во-первых, скопировать doubly­connected edge lists [math]S1[/math] и [math]S2[/math] в один новый [math]DCEL[/math]. Новый [math]DCEL[/math] не является допустимым [math]DCEL[/math], т.к. он еще не представляет собой плоский подграф.

Объединения графов

Это задача алгоритма заметающей прямой: он должен трансформировать [math]DCEL[/math] в допустимый [math]DCEL[/math] для [math]O(S1, S2)[/math] путем вычисления пересечения между двумя сетями ребер, и связывая воедино соответствующие части из двух [math]DCEL[/math]. Мы применяем этот алгоритм на множестве сегментов, что является объединением множеств ребер двух подграфов [math]S1[/math] и [math]S2[/math]. Напомним, что алгоритм поддерживается двумя структурами данных: очереди событий [math]Q[/math], в котором хранятся точки событий, и структура состояния [math]T[/math], которой является бинарное дерево храненящее сегменты, пересекающие линии развертки, расположенные слева направо. Мы теперь также должны поддерживать [math]DCEL[/math] [math]D[/math]. Первоначально [math]D[/math] содержит копию [math]DCEL[/math] для [math]S1[/math] и [math]DCEL[/math] для [math]S2[/math]. В плоскости развертки преобразуем [math]D[/math] к правильному [math]DCEL[/math] для [math]O(S1, S2)[/math]. Мы держим перекрестные указатели между ребер в структуре состояния [math]T[/math] и половина текущих записей в [math]D[/math], которые соответствуют им. Таким образом мы можем получить доступ к части [math]D[/math], которая должна быть изменена, когда мы сталкиваемся с точкой пересечения.

В другом случае, мы поддерживаем то, что в любое время в течение развертки, часть выше линии развертки наложения будет считаться правильной. Теперь что мы должны делать, когда мы достигнем точки событий. Прежде всего, мы обновляем [math]T[/math] и [math]Q[/math], как и в алгоритме заметающей прямой. Если событие включает в себя только ребра из одного из двух подграфов, это все, точка событие является вершиной, которые могут быть использованы повторно. Если событие включает края с двух подграфов, мы должны сделать локальные изменения в [math]D[/math] -- связать doubly­ connected edge list двух оригинальных подграфов в точке пересечения.

Рассмотри один из 2 возможных случаев, а именно, когда edge [math]е[/math] из [math]S1[/math] проходит через вершину [math]V[/math] [math]S2[/math], (см. Рисунок) edge [math]е[/math] должно быть заменено двумя edges обозначим [math]e'[/math] и [math]e''[/math]. В [math]DCEL[/math], два [math]half-edge[/math] для е должны превратиться в четыре. Мы создаем два новых [math]half-edge[/math], с [math]V[/math] в нуле. Два существующих [math]half-edge[/math] для е содержат конечные точки [math]e[/math], как их происхождения. Тогда мы объединяем попарно существующие [math]half-edges[/math] с новыми [math]half-edges[/math], устанавливая их указатели twin'ов. Так [math]e'[/math] представлен одним новым и одним существующим частично edge, и то же самое для [math]e''[/math]. Теперь мы должны установить ряд [math]Prev[/math] и [math]Next[/math]. [math]Next[/math] двух новых [math]half-edges[/math] являются копией [math]Next[/math] старого [math]half-edge[/math], не имеющего пары. В [math]half-edges[/math], в которые эти указатели точки должны обновлять свои [math]Prev[/math] и установливать его на новых [math]half-edges[/math]. Далее мы должны установить [math]Next[/math] и [math]Prev[/math] четырех [math]half-edges[/math] представляющих [math]e'[/math] и [math]e''[/math], и из четырех [math]half-edges[/math] инциденого [math]S2[/math] [math]v[/math]. Мы размещаем эти четыре [math]half-edges[/math] от [math]S2[/math], проверяя, где [math]e'[/math] и [math]e''[/math] должны быть в циклическом порядке вершин вокруг вершины [math]v[/math]. Есть четыре пары [math]half-edges[/math], которые связанны между собой [math]Next[/math] с одним и [math]Prev[/math] с другим. [math]e'[/math] должен быть привязан к первому [math]half-edge[/math] по часовой стрелке с началом в [math]v.[/math] [math]half-edge[/math] для [math]e'[/math] с началом в [math]v[/math] должен быть связан с первым против часовой стрелки [math]half-edge[/math] с окончанием в [math]v[/math]. Точно также и для [math]e''[/math].

Время работы объединения

Большинство из шагов в приведенном выше описании принимать только константное время. Есть случаи на которые потребуется дополнительное время, О(M), где M­число ребер, точки событий. Это означает, что обновление [math]D[/math] не увеличивает время работы алгоритма заметащей прямой асимптотически. Любое пересечение, которое мы находим является вершиной наложения. Из этого следует, что вершина record и [math]half-edge[/math] record doubly­ connected edge list для [math]O(S1, S2)[/math] можно вычислить в [math]O(N\ *\ log N\ +\ k\ *\ log\ n)[/math] время, где [math]n[/math] обозначает сумму сложностей [math]S1[/math] и [math]S2[/math], а k является сложностью наложения.

Воссоздание [math]faces[/math]

После того, как все сделано, осталось вычислить информацию о [math]faces[/math] в [math]O(S1, S2)[/math]. Точнее, мы должны создать [math]face[/math] record для каждого [math]face[/math] е в [math]O(S1, S2)[/math], мы должны сделать [math]outer\_component[/math] ([math]e[/math]) указывают на [math]half-edges[/math] на внешней границе [math]F[/math], и мы должны сделать список [math]inner\_components[/math] ([math]F[/math]) из указателей на [math]half-edges[/math] на связанных областях пробелов внутри [math]f[/math]. Кроме того, мы должны установить [math]incident\_face[/math] () поля времени [math]half-edges[/math] на границе [math]F[/math] так, что они указывают на лицевые записи [math]F[/math]. Наконец, каждый из новых [math]faces[/math] должны быть помечены именами [math]faces[/math] в старых подграфах, которые содержат его. Рассмотрим два [math]half-edges[/math] цикла, свойственных [math]v[/math]. Т.к. мы знаем, что incident [math]face[/math] лежит слева, мы можем вычислить угол который эти два [math]half-edges[/math] образуют внутри [math]face[/math]. Если этот угол f меньше, чем 180◦ то циклом является внешняя граница, и в противном случае это граница дыры. Это свойство имеет место для левой вершины цикла, но не обязательно для других вершин этого цикла.

Лемма (К предыдущему вопросу):
Каждая компонента графа отвечает за множество циклов инцидентных одному [math]face[/math].
Доказательство:
[math]\triangleright[/math]
Рассмотрим цикл [math]C[/math], который ограничивает дыру в [math]face[/math] [math]f[/math]. Поскольку [math]f[/math] локально лежит левее самой левой вершины из [math]C[/math], то [math]C[/math] должен быть соединен с другим циклом, который тоже ограничивает [math]f[/math]. отсюда следует, что циклы есть компонента связности в графе, описывающая один и тот-же [math]face[/math]. Для того, что бы закончить доказательство, покажем, что каждый цикл ограничивающий дыру в [math]f[/math] есть в той же компоненте связности, что и внешняя граница [math]f[/math]. Предположим, что есть цикл, для которого это не так. Пусть [math]C[/math] — самый левый такой цикл, то есть тот, чья самая левая вершина самая левая (шляпа). По определению есть ребро между [math]C[/math] и неким [math]C'[/math], который лежит слева от самой левой вершины [math]C[/math]. Следовательно [math]C[/math] в той же компоненте связности, что и [math]C'[/math], который не в той же компоненте, что внешняя граница [math]f[/math]. Противоречие.
[math]\triangleleft[/math]

Напомним, что в алгоритме развертки плоскости для отрезка пересечения мы всегда искали сегменты сразу слева от точки событий. (Они должны были быть проверены на пересечении с крайнего левого края через точку событий.) Таким образом, информация, при помощи которой мы должны построить [math]G[/math] определяется в плоскости развертки. Таким образом, чтобы построить [math]G[/math], мы сначала делаем узел для каждого цикла. Чтобы найти дуги [math]G[/math], рассмотрим левую вершину [math]V[/math] для каждого цикла, ограничивающую отверстие. Если [math]half-edge[/math] сразу же выходит из [math]V[/math], то мы добавляем дугу между двумя узлами в [math]G[/math], представляющих цикл, содержащий е и цикл у которого [math]V[/math] является самой левой вершиной. Чтобы найти эти узлы в [math]G[/math] мы должны указатели от каждого [math]half-edge[/math] записать в узел [math]G[/math], представляющего цикл этот. Так информация o [math]face[/math] в doubly­connected edge list может быть установлена в [math]О(n\ +\ k)[/math] времени, после плоскости развертки. Каждая грань [math]e[/math] в наложении должна быть помечена с именами [math]face[/math] в старых графах, которые содержали его. Чтобы найти эти [math]face[/math], надо рассмотреть произвольную вершину [math]V[/math] в [math]F[/math]. Если [math]v[/math] является пересечением [math]e1[/math] от [math]S1[/math] и [math]е2[/math] от [math]S2[/math], то мы можем решить, какие [math]face[/math] из [math]S1[/math] и [math]S2[/math] содержат [math]F[/math], глядя на [math]incident\_face[/math] указатель соответствующих [math]half-edges[/math] соответствующих [math]e1[/math] и [math]e2[/math]. Если [math]v[/math] не пересечение, но вершина, скажем, S1, то мы знаем только [math]face[/math] S1, содержащей [math]f[/math]. Чтобы найти [math]face[/math] [math]S2[/math] , содержащий [math]F[/math], мы должны определить [math]face[/math] [math]S2[/math], которое содержит [math]v[/math]. Другими словами, если бы мы знали для каждой вершины [math]S1[/math], в котором [math]face[/math] [math]S2[/math] находился, и наоборот, то мы могли бы обозначить [math]face[/math] [math]O(S1, S2)[/math] правильно.


Итог

MapOverlay ([math]S_1[/math], [math]S_2[/math]) [math]:[/math]

1. Копируем [math]S_1[/math] и [math]S_2[/math] в граф [math]D[/math].

2. Находим все пересечения ребер из [math]S_1[/math] с ребрами из [math]S_2[/math] с помощью заметающей прямой.

2.1 Когда находим точки пересечения, то обновляем [math]D[/math], то есть строим из него РСДС.

3. Теперь [math]D[/math] это нормальный РСДС, но без информации о [math]face[/math]'ах.

4. Находим boundary cycles в [math]D[/math]. То есть обновляем этот граф. Пока только добавляя в него ребра ([math]half-edge[/math]'ы соответственно).

5. Создаем граф [math]G[/math] (о нем ниже), в котором узлы будут отвечать за boundary cycles и в котором ребра будут соединять только те узлы, один из которых будет являться границей дыры ([math]hole[/math], это внутренний цикл [math]face[/math]'a), а другой будет находиться слева от самой левой точки первого. (В случае, если это самая внешняя граница, то для нее пусть будет мнимая гигантская граница, с которой мы ее и соединим).

5.1. Для каждой компоненты графа:

Пусть [math]C[/math] будет уникальная наружная граница цикла в компоненте, а [math]f[/math] будет означать face ограниченный этим циклом. Создадим face для [math]f[/math]. Запишем [math]outer\_component[/math] в какой-нибудь [math]half-edge[/math] из [math]C[/math]. И создадим список [math]inner\_components[/math], состоящий из указателей на какой-нибудь [math]half-edge[/math] из каждого цикла. А так же пусть [math]incident\_face[/math] в каждом [math]half-edge[/math] будут обновлены на [math]f[/math].


Литература и источники

  • Вычислительная геометрия. Алгоритмы и приложения, де Берг Марк и другие. Глава 2.3