Visibility graph и motion planning — различия между версиями

Материал из Викиконспекты
Перейти к: навигация, поиск
м
м
Строка 28: Строка 28:
 
==== Наивный алгоритм. <tex> O(n ^ 3) </tex> ====
 
==== Наивный алгоритм. <tex> O(n ^ 3) </tex> ====
 
Если делать наивно, т. е. для каждой пары вершин проверять можно ли добавить ли такое ребро(нет ли пересечений с полигонами), будет <tex> O(n^3) </tex>.
 
Если делать наивно, т. е. для каждой пары вершин проверять можно ли добавить ли такое ребро(нет ли пересечений с полигонами), будет <tex> O(n^3) </tex>.
[[Файл:search.png|400px|thumb|right|Дерево поиска пересекаемых ребер]]
 
  
 
==== Lee’s Algorithm. <tex> O(n ^ 2 \log n) </tex> ====
 
==== Lee’s Algorithm. <tex> O(n ^ 2 \log n) </tex> ====
[[Файл:zam.png|400px|thumb|left|Заметание плоскости вращающимся лучом]]
+
[[Файл:zam.png|300px|thumb|left|Заметание плоскости вращающимся лучом]]
[[Файл:zamrefr1.png|400px|thumb|right|Обновление статуса заметающей прямой]]
+
[[Файл:zamrefr1.png|300px|thumb|right|Обновление статуса заметающей прямой]]
[[Файл:zamrefr2.png|400px|thumb|right|Обновление статуса заметающей прямой]]
+
[[Файл:zamrefr2.png|300px|thumb|right|Обновление статуса заметающей прямой]]
[[Файл:zamrefr3.png|400px|thumb|right|Обновление статуса заметающей прямой]]
+
[[Файл:zamrefr3.png|300px|thumb|right|Обновление статуса заметающей прямой]]
 
Однако можно это сделать за <tex> O(n ^ 2 \log  n) </tex>. Для каждой вершины найдём все видимые из неё вершины при помощи метода плоского заметания. Нам нужно решить следующую задачу: на плоскости дано множество отрезков (рёбер препятствий) и точка <tex> p </tex>. Найти все концы отрезков, видимые из точки <tex> p </tex>. Будем заметать плоскость вращающимся лучом с началом в точке <tex> p </tex>. Статусом заметающей прямой будет отрезки, которые её пересекают, упорядоченные по возрастанию расстояния от точки <tex> p </tex> до точки пересечения. Точками событий будут концы отрезков. Итак, первым делом вершины <tex> w \in W </tex> сортируются по углу между лучом <tex> vw </tex> и вертикальной полуосью, проходящей через <tex> v </tex>. Затем происходит инициализация множества видимых вершин (по умолчанию, такое множество пустое). Далее начинается заметание плоскости. В порядке сортировки вершин для каждой из них выполняется проверка: видна ли вершина <tex> w </tex> из вершины <tex> v </tex>. Поскольку такая проверка означает наличие пересечений, которые хранятся в сбалансированном дереве, она может быть выполнена за <tex> O(\log n) </tex>. Если вершина видима, необходимо добавить её в список видимых вершин. И, наконец, вне зависимости от видимости вершины, необходимо изменить статус заметающей прямой. Для этого, для текущей вершины <tex> w </tex> необходимо удалить из списка текущих пересечений все рёбра (отрезки), которые заканчиваются в этой вершине (лежат слева от прямой <tex> vw </tex>) и добавить все рёбра (отрезки), которые в ней начинаются (лежат справа от прямой <tex> vw </tex>).
 
Однако можно это сделать за <tex> O(n ^ 2 \log  n) </tex>. Для каждой вершины найдём все видимые из неё вершины при помощи метода плоского заметания. Нам нужно решить следующую задачу: на плоскости дано множество отрезков (рёбер препятствий) и точка <tex> p </tex>. Найти все концы отрезков, видимые из точки <tex> p </tex>. Будем заметать плоскость вращающимся лучом с началом в точке <tex> p </tex>. Статусом заметающей прямой будет отрезки, которые её пересекают, упорядоченные по возрастанию расстояния от точки <tex> p </tex> до точки пересечения. Точками событий будут концы отрезков. Итак, первым делом вершины <tex> w \in W </tex> сортируются по углу между лучом <tex> vw </tex> и вертикальной полуосью, проходящей через <tex> v </tex>. Затем происходит инициализация множества видимых вершин (по умолчанию, такое множество пустое). Далее начинается заметание плоскости. В порядке сортировки вершин для каждой из них выполняется проверка: видна ли вершина <tex> w </tex> из вершины <tex> v </tex>. Поскольку такая проверка означает наличие пересечений, которые хранятся в сбалансированном дереве, она может быть выполнена за <tex> O(\log n) </tex>. Если вершина видима, необходимо добавить её в список видимых вершин. И, наконец, вне зависимости от видимости вершины, необходимо изменить статус заметающей прямой. Для этого, для текущей вершины <tex> w </tex> необходимо удалить из списка текущих пересечений все рёбра (отрезки), которые заканчиваются в этой вершине (лежат слева от прямой <tex> vw </tex>) и добавить все рёбра (отрезки), которые в ней начинаются (лежат справа от прямой <tex> vw </tex>).
  
Строка 42: Строка 41:
 
[http://igitur-archive.library.uu.nl/math/2006-1214-201604/overmars_88_new_methods.pdf visibility graph при помощи rotation tree]
 
[http://igitur-archive.library.uu.nl/math/2006-1214-201604/overmars_88_new_methods.pdf visibility graph при помощи rotation tree]
  
Ковалев сказал что это можно рассказывать по желанию.
+
C помощью [http://bit.ly/1eEqTzk rotation tree] можно достичь асимптотики <tex> O(n^2) </tex>.
  
Каким-то магическим образом, можно избавиться и от логарифма в асимптотике. Это делается с помощью [http://bit.ly/1eEqTzk rotation tree]. Про него рассказывал Антон Ков., но как-то мутно и не очень понятно. Суть такова, что мы обходим вершины в таком хитром порядке, что почти не просматриваем лишнее и получаем асимптотику {{---}} квадрат.
+
Идея такова, что для каждой вершины заметающий луч пробегается от <tex> -\pi / 2 </tex> до <tex> \pi / 2 </tex>. В основном цикле получается, что мы вращаем все лучи одновременно. По определенным правилам определяем следующую вершину, таким образом некоторые вершины могут закончить свою "жизнь" раньше других. Чтобы понять эти правила, нужно разобраться в rotation tree, что можно сделать по желанию.
 
 
Короче тут мы делаем то же самое, что и н2логн, только сортим не для каждой вершины отдельно, а рассматриваем все одновременно.
 
 
 
"The idea is simple: for each vertex, a scanline is kept which runs from <tex> -\pi / 2 </tex> to <tex> \pi / 2 </tex> hopping from vertex to vertex in its path. During the main loop, it appears that all of the scanlines are proceeding simultaneously. In fact, there are exact rules about determining the next vertex to process, and some vertices may finish their scan before others. To understand the rules about finding the next vertex, the rotation tree must be understood. A rotation tree is a rooted planar tree where each vertex is a node and points to its parent. There are two special nodes: <tex> +\infty </tex> and <tex> -\infty </tex>. Initially, all vertices point to <tex> -\infty </tex> as their parent and <tex> -\infty </tex> points to <tex> +\infty </tex>. Also stored is the rightmost child (if a node is a parent), and its right and left siblings (if they exist). The ordering of children is by slope: the one with the smallest slope is the leftmost. The loop that examines all pairs simply takes the rightmost leftmost leaf as the next segment to process and then reattaches it to the tree (while maintaining the property of being a rotation tree). It can reattach to the left of its parent or to the tangent of the chain above it. When a vertex attaches to <tex> +\infty </tex>, it is finished. The loop continues when all points have attached to <tex> +\infty </tex>".
 
 
 
/*мне лень это переводить, и так понятно/непонятно*/
 
  
 
== Motion planning ==
 
== Motion planning ==
 
[[Файл:mink.png|200px|thumb|left|Раздуваем препятствия]]
 
[[Файл:mink.png|200px|thumb|left|Раздуваем препятствия]]
 
[[Файл:mink2.png|400px|thumb|right|Логично же]]
 
[[Файл:mink2.png|400px|thumb|right|Логично же]]
В общем тут все очевидно. Тут мы просто двигаем не точку, а произвольный выпуклый полигон. Если мы его не можем вращать, просто "обводим" препятствия нашим полигоном (запиливаем [[Сумма Минковского (определение, вычисление)|сумму Минковского]] препятствий и полигона, сдвинутого в начало координат какой-нибудь точкой) и получаем другие препятствия, но зато теперь мы двигаем точку. А это мы уже научились делать выше.
+
Тут мы двигаем не точку, а произвольный выпуклый полигон. Если мы его не можем вращать, просто "обводим" препятствия нашим полигоном (делаем [[Сумма Минковского (определение, вычисление)|сумму Минковского]] препятствий и полигона, сдвинутого в начало координат какой-нибудь точкой) и получаем другие препятствия, но зато теперь мы двигаем точку. А это мы уже научились делать выше.
 
 
Если же этот полигон можно вращать, то делаем примерно то же самое, только как-то по-хитрому. Нам про это, кажется, не рассказывали(или рассказывали так же:))
 
  
 
== Источники ==
 
== Источники ==

Версия 00:35, 22 февраля 2014

Visibility graph

Путь с препятствиями через трапецоидную карту
Такой путь не самый короткий

Пусть мы ищем какой-то путь от точки [math] S [/math] до [math] T [/math] с препятствиями (сначала будем двигать точку, а не полигон). Для нахождения можно построить трапецоидную карту, соединить ребрами середины вертикальных сторон с центрами трапецоидов и в этом графе Дейкстрой найти путь от [math] S [/math] до [math] T [/math]. Но этот путь, очевидно, не будет кратчайшим.

Лемма:
Любой кратчайший путь от [math] S [/math] до [math] T [/math] с полигональными препятствиями представляет собой ломаную, вершины которой — вершины полигонов.
Доказательство:
[math]\triangleright[/math]
Short cut
Пусть путь проходит(в смысле вершины) через какую-то другую точку. Рассмотрим окрестность этой точки. По неравенству треугольника мы сможем немножко срезать. Значит этот путь не кратчайший. Противоречие, значит лемма доказана.
[math]\triangleleft[/math]

По этому создадим visibility graph. Его вершины — вершины полигонов. Между вершинами [math] u [/math] и [math] v [/math] существует ребро, если из [math] u [/math] видна (mutually visible) [math] v [/math] (ребра полигонов тоже входят в этот граф). Теперь, если мы добавим к множеству вершин [math] S [/math] и [math] T [/math] (и ребра в видимые вершины), у нас получится граф, в котором опять же Дейкстрой находим кратчайший путь. По лемме любое ребро кратчайшего пути — ребро visibility графа, так что мы нашли то, что нужно.

Чтобы уменьшить объем графа, следует удалить из него ребра, по которым точно не пройдет путь.

Лемма:
Если у ребра на предыдущю точку от данной левый поворот, а на следующую, от данной, правый - то ребро, идущее к текущей точке может быть удалено.
Доказательство:
[math]\triangleright[/math]
Удаляем [math] BD [/math]
Очевидно, что путь проходящий через ребро [math] BD [/math] будет длинее, чем через соседей точки [math] B [/math]. Так как по неравенству треугольника [math] AB + BD \lt AD [/math]
[math]\triangleleft[/math]

Построение visibility графа

Наивный алгоритм. [math] O(n ^ 3) [/math]

Если делать наивно, т. е. для каждой пары вершин проверять можно ли добавить ли такое ребро(нет ли пересечений с полигонами), будет [math] O(n^3) [/math].

Lee’s Algorithm. [math] O(n ^ 2 \log n) [/math]

Заметание плоскости вращающимся лучом
Обновление статуса заметающей прямой
Обновление статуса заметающей прямой
Обновление статуса заметающей прямой

Однако можно это сделать за [math] O(n ^ 2 \log n) [/math]. Для каждой вершины найдём все видимые из неё вершины при помощи метода плоского заметания. Нам нужно решить следующую задачу: на плоскости дано множество отрезков (рёбер препятствий) и точка [math] p [/math]. Найти все концы отрезков, видимые из точки [math] p [/math]. Будем заметать плоскость вращающимся лучом с началом в точке [math] p [/math]. Статусом заметающей прямой будет отрезки, которые её пересекают, упорядоченные по возрастанию расстояния от точки [math] p [/math] до точки пересечения. Точками событий будут концы отрезков. Итак, первым делом вершины [math] w \in W [/math] сортируются по углу между лучом [math] vw [/math] и вертикальной полуосью, проходящей через [math] v [/math]. Затем происходит инициализация множества видимых вершин (по умолчанию, такое множество пустое). Далее начинается заметание плоскости. В порядке сортировки вершин для каждой из них выполняется проверка: видна ли вершина [math] w [/math] из вершины [math] v [/math]. Поскольку такая проверка означает наличие пересечений, которые хранятся в сбалансированном дереве, она может быть выполнена за [math] O(\log n) [/math]. Если вершина видима, необходимо добавить её в список видимых вершин. И, наконец, вне зависимости от видимости вершины, необходимо изменить статус заметающей прямой. Для этого, для текущей вершины [math] w [/math] необходимо удалить из списка текущих пересечений все рёбра (отрезки), которые заканчиваются в этой вершине (лежат слева от прямой [math] vw [/math]) и добавить все рёбра (отрезки), которые в ней начинаются (лежат справа от прямой [math] vw [/math]).

Вершин у нас [math] O(n) [/math], сортим за [math] O(n \log n) [/math] плюс запросы в дереве за [math] O(n) * O(\log n) [/math]. Итого что хотели.

Overmars and Welzl’s Algorithm [math] O(n ^ 2) [/math]

visibility graph при помощи rotation tree

C помощью rotation tree можно достичь асимптотики [math] O(n^2) [/math].

Идея такова, что для каждой вершины заметающий луч пробегается от [math] -\pi / 2 [/math] до [math] \pi / 2 [/math]. В основном цикле получается, что мы вращаем все лучи одновременно. По определенным правилам определяем следующую вершину, таким образом некоторые вершины могут закончить свою "жизнь" раньше других. Чтобы понять эти правила, нужно разобраться в rotation tree, что можно сделать по желанию.

Motion planning

Раздуваем препятствия
Логично же

Тут мы двигаем не точку, а произвольный выпуклый полигон. Если мы его не можем вращать, просто "обводим" препятствия нашим полигоном (делаем сумму Минковского препятствий и полигона, сдвинутого в начало координат какой-нибудь точкой) и получаем другие препятствия, но зато теперь мы двигаем точку. А это мы уже научились делать выше.

Источники

  • Mark de Berg, Otfried Cheong, Marc van Kreveld, Mark Overmars (2008), Computational Geometry: Algorithms and Applications (3rd edition), Springer-Verlag, ISBN 978-3-540-77973-5 Chapter 15 page 324-331
  • статья про visibility graphs
  • Хабр