<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
		<id>http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Igorjan94</id>
		<title>Викиконспекты - Вклад участника [ru]</title>
		<link rel="self" type="application/atom+xml" href="http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Igorjan94"/>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%B1%D0%BD%D0%B0%D1%8F:%D0%92%D0%BA%D0%BB%D0%B0%D0%B4/Igorjan94"/>
		<updated>2026-06-11T14:08:02Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.30.0</generator>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D0%B8%D1%80%D0%BA%D0%BF%D0%B0%D1%82%D1%80%D0%B8%D0%BA%D0%B0_%D0%B4%D0%B5%D1%82%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%82%D1%80%D0%B8%D0%B0%D0%BD%D0%B3%D1%83%D0%BB%D1%8F%D1%86%D0%B8%D0%B8&amp;diff=44897</id>
		<title>Алгоритм Киркпатрика детализации триангуляции</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D0%B8%D1%80%D0%BA%D0%BF%D0%B0%D1%82%D1%80%D0%B8%D0%BA%D0%B0_%D0%B4%D0%B5%D1%82%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D1%82%D1%80%D0%B8%D0%B0%D0%BD%D0%B3%D1%83%D0%BB%D1%8F%D1%86%D0%B8%D0%B8&amp;diff=44897"/>
				<updated>2015-02-19T12:23:35Z</updated>
		
		<summary type="html">&lt;p&gt;Igorjan94: /* Выбор множества удаляемых вершин */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Мотивация==&lt;br /&gt;
Существует ли метод локализации со временем поиска за &amp;lt;tex&amp;gt;O(\log n)&amp;lt;/tex&amp;gt;, использующий менее чем квадратичную память? Эта задача оставалась не решенной довольно долго. Но все же была решена Липтоном и Тарьяном в 1977-1980 гг. Но их метод оказался на столько громоздким, а оценки времени его эффективности содержат слишком большую константу, что сами авторы не считали этот метод практичным, но его существование заставляет думать, что может найтись практичный алгоритм с временной оценкой &amp;lt;tex&amp;gt;O(\log n)&amp;lt;/tex&amp;gt; и линейной памятью.&lt;br /&gt;
&lt;br /&gt;
Недавно Киркпатриком был предложен оптимальный метод, дающий ответ на ожидания Липтона и Тарьяна, {{---}} детализация триангуляции.&lt;br /&gt;
&lt;br /&gt;
==Описание алгоритма==&lt;br /&gt;
===Предобработка===&lt;br /&gt;
&amp;lt;wikitex&amp;gt;[[Файл:кирк1.png|right|420px|thumb|Триангуляция в охватывающем треугольнике.]]Пусть планарный N-вершинный граф задает триангуляцию нашего многоугольника (если это не так, то воспользуемся методом триангуляции многоугольника за время $O (n \log n)$. Напомним, что триангуляция на множестве вершин $V$ есть планарный граф с не более чем $3 |V| - 6$ ребрами ([[Формула_Эйлера |формула Эйлера]]). Для удобства описания алгоритма поместим нашу триангуляцию в охватывающий треугольник и построим триангуляцию области между нашими объектами. После этого преобразования все триангуляции будут обладать тремя границами и ровно $3 |V| - 6$ ребрами.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/wikitex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Структура данных===&lt;br /&gt;
&amp;lt;wikitex&amp;gt;[[Файл:кирк2.png|right|420px|thumb|Последовательность триангуляций.]]&lt;br /&gt;
[[Файл:кирк3.png|right|420px|thumb|Структура триангуляций.]]&lt;br /&gt;
Итак, имеется N-вершинная триангуляция $G$, и пусть строится последовательность триангуляций $S_1, S_2, \dots, S_{h(N)}$, где $S_1 = G$, а $S_i$ получается из $S_{i - 1}$ по следующим правилам:&lt;br /&gt;
* Шаг 1. Удалим некоторое количество неграничных и независимых (попарно несмежных друг с другом) вершин и инцидентные им ребра (от выбора этого множества напрямую зависит оптимальность алгоритма).&lt;br /&gt;
* Шаг 2. Построить триангуляцию получившихся в результате шага 1 многоугольников.&lt;br /&gt;
Таким образом $S_{h(N)}$ состоит из одного треугольника. Заметим, что все триангуляции имеют одну общую границу, так как удаляются только внутренние узлы. Далее, будем обозначать все треугольники как $R$, а также будем говорить, что треугольник $R_ij$ принадлежит триангуляции $S_i$, если &lt;br /&gt;
он был создан на шаге (2) при построении этой триангуляции.&lt;br /&gt;
&lt;br /&gt;
Теперь построим структуру данных $T$ для поиска. Эта структура представляет собой направленный ацикличный граф, вершинами которого будут наши треугольники. Определим эту структуру следующим образом: из треугольника $R_k$ будет вести ребро в треугольник $R_j$, если при построении $S_i$ из $S_{i-1}$ мы имеем&lt;br /&gt;
* $R_j$ удалятся из $S_{i - 1}$ на шаге (1)&lt;br /&gt;
* $R_k$ создается в $S_{i}$ на шаге (2)&lt;br /&gt;
* $R_j \cap R_k \ne  \varnothing $&lt;br /&gt;
&lt;br /&gt;
Очевидно, что треугольники из $S_1$ (и только они) не имеют исходящих ребер.&lt;br /&gt;
&lt;br /&gt;
Для ясности удобно изобразить $T$ в рассмотренном виде, то есть помещая его узлы в горизонтальные строки, каждая из &lt;br /&gt;
которых соответствует какой-нибудь триангуляции. Последовательность триангуляций и соответствующая ей структура $T$ показаны на рисунке. Треугольники пронумерованы в порядке их появления. Кружком обведены вершины, которые удалены на данном шаге. &amp;lt;/wikitex&amp;gt;&lt;br /&gt;
====Выбор множества удаляемых вершин====&lt;br /&gt;
&amp;lt;wikitex&amp;gt;Как уже упоминалось, от выбора множества вершин триангуляции, которые будут удалены при построении $S_i$ по $S_{i-1}$ существенно зависит эффективность метода. Предположим, что можно выбрать это множество так, чтобы выполнялись следующие ''свойства'' ($N_i$ обозначает число вершин в $S_i$):&lt;br /&gt;
&lt;br /&gt;
'''Свойство 1'''. $N_i = a_i N_{i-1}$, где $a_i \le a &amp;lt; 1$ для $i = 2,\dots , h(N)$.&lt;br /&gt;
&lt;br /&gt;
'''Свойство 2'''. Каждый треугольник $R_i \in S_i$ пересекается не более чем с $H$ треугольниками из $S_{i-1}$ и наоборот.&lt;br /&gt;
Первое свойство немедленно влечет за собой следствие, что $h(N) \le \left \lceil \log_{1/a}N \right \rceil = O(log N)$, поскольку при переходе от $S_{i-1}$ к $S_i$ удаляется по меньшей мере фиксированная доля вершин.&lt;br /&gt;
&lt;br /&gt;
Также из этих свойств следует, что память для $T$ равна $O(N)$. Действительно, заметим, что эта память используется для хранения узлов и указателей на их потомков. Из [[Формула_Эйлера|теоремы Эйлера]] о плоских графах следует, что $S_i$ содержит $F_i &amp;lt; 2N_i$ треугольников. Число узлов в $T$, представляющих треугольники из $S_i$, не превосходит $F_i$ (только те треугольники, которые действительно принадлежат $S_i$, появляются на соответствующем «ярусе» $T$). Отсюда следует, что общее число узлов в $T$ меньше, чем&lt;br /&gt;
$2(N_1 + N_2 + \dots + N_{h(N)}) \le 2N_1(1 + a + a^2 + \dots + a^{h(N) - 1}) &amp;lt; \frac{2N}{1 - a}$.&lt;br /&gt;
Что касается памяти, используемой под указатели, то по свойству 2 каждый узел имеет не более $H$ указателей, поэтому не более $\frac{2NH}{1-a}$ указателей появится в $T$. Это доказывает последнее утверждение.&lt;br /&gt;
&lt;br /&gt;
Покажем теперь, что критерий выбора множества удаляемых вершин, удовлетворяющий вышеописанным свойствам, существует.&lt;br /&gt;
{{Теорема&lt;br /&gt;
|about=&lt;br /&gt;
критерий выбора множества удаляемых вершин&lt;br /&gt;
|statement=&lt;br /&gt;
Если на шаге (1) построения последовательности триангуляции удалять несмежные вершины со степенью меньше некоторого целого (будет указано позже) числа $K$, то свойства, описанные выше, будут выполнены.&lt;br /&gt;
|proof=&lt;br /&gt;
'''1. ''' Для проверки первого свойства воспользуемся некоторыми особенностями плоских графов. Из [[Формула_Эйлера | формулы Эйлера]] для плоских графов, в частном случае триангуляции, ограниченной тремя ребрами, следует, что число вершин $N$ и число ребер $e$ связаны соотношением &lt;br /&gt;
$e = 3N - 6$.&lt;br /&gt;
Пока в триангнуляции есть внутренние вершины (в противном случае задача тривиальна), степень каждой из трех граничных вершин не меньше трех. Поскольку существует $3N - 6$ ребер, а каждое ребро инцидентно двум вершинам, то сумма степеней всех вершин меньше $6N$. Отсюда сразу следует, что не менее $ \frac{N}{2}$ вершин имеет степень меньше 12. Следовательно, пусть $K = 12$. Пусть также $v$ {{---}} число выбранных вершин. Поскольку каждой из них инцидентно не более $K-1 = 11$ ребер, а три граничные вершины не выбираются, то мы имеем &lt;br /&gt;
$v \ge \left \lfloor \frac{1}{12}(\frac{N}{2} - 3) \right \rfloor $.&lt;br /&gt;
Следовательно, $a \cong 1 - \frac{1}{24} &amp;lt; 0,959 &amp;lt; 1$, что доказывает справедливость свойства 1.&lt;br /&gt;
'''2. ''' Выполнение второго свойства обеспечивается тривиально. Поскольку удаление вершины со степенью меньше $K$ приводит к образованию многоугольника с числом ребер менее $K$, то каждый из удаленных треугольников пересекает не более $K - 2 = H$ новых треугольников.&lt;br /&gt;
}}&amp;lt;/wikitex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Поиск===&lt;br /&gt;
&amp;lt;wikitex&amp;gt;После построения структуры легко понять, как в ней происходит поиск. Элементарной операцией здесь является определение принадлежности треугольнику. Очевидно, что она выполняется константное время. Сначала мы локализуемся в треугольнике $S_1$. После этого мы строим путь от корневой вершины до листа следующим образом: находясь в какой-либо вершине $z$, просмотрим всех ее  детей на принадлежность точки соответствующему треугольнику и, так как точка может находиться лишь в одном треугольнике конкретной триангуляции, перейдем в эту вершину, и продолжим поиск.&lt;br /&gt;
Этот поиск также можно рассматривать как последовательную локализацию в триангуляциях $S_1, \dots, S_{h(N)}$, откуда и происходит название самого метода.&lt;br /&gt;
&amp;lt;/wikitex&amp;gt;&lt;br /&gt;
====Псевдокод====&lt;br /&gt;
&amp;lt;wikitex&amp;gt;Пусть все потомки узла $u$ из $T$ собраны в список successors(u), а triangle(u) обозначает треугольник, соответствующий узлу $u$. Тогда алгоритм поиска может выглядеть следующим образом: &amp;lt;/wikitex&amp;gt;&lt;br /&gt;
 procedure localization(z)&lt;br /&gt;
   if (z not in triangle(root))&lt;br /&gt;
     z in infinite region&lt;br /&gt;
   else&lt;br /&gt;
     u = root&lt;br /&gt;
     while (successors(u) != null)&lt;br /&gt;
       for (v in successors(u))&lt;br /&gt;
         if (z in triangle(v))&lt;br /&gt;
           u = v&lt;br /&gt;
     return u&lt;br /&gt;
==Источники==&lt;br /&gt;
* Препарата Ф., Шеймос М. Вычислительная геометрия: Введение: Пер. с англ. {{---}} М.: Мир, 1989. {{---}} 478 с. {{---}} ISBN 5-03-001041-6&lt;br /&gt;
&lt;br /&gt;
[[Категория: Вычислительная геометрия]]&lt;/div&gt;</summary>
		<author><name>Igorjan94</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44875</id>
		<title>Visibility graph и motion planning</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44875"/>
				<updated>2015-02-15T14:40:40Z</updated>
		
		<summary type="html">&lt;p&gt;Igorjan94: /* Псевдокод */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Нахождение любого пути между точками с препятствиями ==&lt;br /&gt;
{|align=&amp;quot;right&amp;quot;&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
|[[Файл:trap.png|200px|thumb|right|Путь с препятствиями через трапецоидную карту]]&lt;br /&gt;
|[[Файл:notShort.png|300px|thumb|right|Такой путь не самый короткий]]&lt;br /&gt;
|}&lt;br /&gt;
Для начала рассмотрим движение материальной точки. Случай, когда размером и формой движимого объекта пренебречь нельзя, будет рассмотрен [[Visibility graph и motion planning#Motion planning|позднее]]. &lt;br /&gt;
&lt;br /&gt;
Эту задачу можно решить с помощью [[Трапецоидная карта | трапецоидной карты]]. По ней строится граф, ребра которого соединяют центры трапедоидов, а также начальную и конечную вершины с серединами вертикальных сторон трапецоидов. В таком графе ищется путь между начальной и конечной вершинами.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм работает за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; и за линейное количество памяти и хорошо подходит для нахождения какого-нибудь пути между парой данных вершин. Но если нужно найти кратчайший путь, этот алгоритм не подходит, хоть и работает быстро. Однако, решения нахождения кратчайшего пути в лучшем случае работают за &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; времени и памяти (здесь и далее &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество всех вершин).&lt;br /&gt;
&lt;br /&gt;
== Нахождение кратчайшего пути между точками с препятствиями ==&lt;br /&gt;
=== Visibility graph ===&lt;br /&gt;
Рассмотрим точное решение нахождения кратчайшего пути на плоскости между двумя точками с полигональными препятствиями с помощью построения графа видимости. После его построения, как и в случае с трапецоидной картой, кратчайший путь ищется любым стандартным алгоритмом поиска (например, алгоритмом [[Алгоритм Дейкстры|Дейкстры]] или [[Алгоритм A*|A*]]).&lt;br /&gt;
&lt;br /&gt;
Для простоты рассуждений начальную и конечную вершины будем считать вершинами полигонов.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|about=О кратчайшем пути&lt;br /&gt;
|statement=&lt;br /&gt;
Любой кратчайший путь между двумя вершинами с полигональными препятствиями представляет собой ломаную, вершины которой {{---}} вершины полигонов.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:short.png|150px|thumb|right|Short cut]]&lt;br /&gt;
Пусть кратчайший путь {{---}} не ломаная. В таком случае, на пути существует такая точка &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, которая не принадлежит ни одному прямому отрезку. Это означает, что существует &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестность точки &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, в которую не попадает ни одно препятствие (случай, когда точка попала на ребро рассматривается аналогично). В таком случае, подпуть, который находится внутри &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности, по неравенству треугольника может быть сокращён по хорде, соединяющий точки пересечения границы &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности с путем. Раз часть пути может быть уменьшена, значит и весь путь может быть уменьшен, а значит исходное предположение некорректно.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
Говорят, что вершина &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; ''видна'' (англ. mutually visible) из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;, если отрезок &amp;lt;tex&amp;gt; uv &amp;lt;/tex&amp;gt; не пересекает ни одного препятствия.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
''Граф видимости'' (англ. visibility graph) {{---}} граф, вершины которого {{---}} вершины полигонов. Между вершинами &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; существует ребро, если из &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; видна &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
В худшем случае в таком графе может быть &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; ребер. Однако по некоторым ребрам кратчайший путь точно не пройдет, и такие ребра из графа можно удалить.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
[[Файл:edgeToDelete.png|150px|thumb|right|Удаляем &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Если существуют вершины &amp;lt;tex&amp;gt; A, B, C &amp;lt;/tex&amp;gt; одного препятствия и вершина &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; такая, что поворот &amp;lt;tex&amp;gt; DBA &amp;lt;/tex&amp;gt; не совпадает с поворотом &amp;lt;tex&amp;gt; DBC &amp;lt;/tex&amp;gt;, то ребро &amp;lt;tex&amp;gt; DB &amp;lt;/tex&amp;gt; не принадлежит кратчайшему пути и его можно удалить из графа. (См. поясняющую картинку справа)&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:edgeNotToDelete.png|200px|thumb|right|Не удаляем &amp;lt;tex&amp;gt; BS &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Путь проходящий через ребро &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt; будет длиннее, чем через соседей точки &amp;lt;tex&amp;gt; B &amp;lt;/tex&amp;gt;, так как по неравенству треугольника &amp;lt;tex&amp;gt; AB + BD &amp;gt; AD &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
По доказанным леммам любое ребро кратчайшего пути содержится в графе. Таким образом, для нахождения кратчайшего пути осталось найти кратчайший путь в этом графе от начальной до конечной вершины.&lt;br /&gt;
&lt;br /&gt;
=== Построение visibility графа ===&lt;br /&gt;
==== Наивный алгоритм. &amp;lt;tex&amp;gt; O(n ^ 3) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
Для каждой пары вершин проверяем, можно ли добавить ребро между ними, то есть нет ли пересечений с полигонами. &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; пар вершин и &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; ребер, то есть &amp;lt;tex&amp;gt; O(n^3) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Lee’s Algorithm. &amp;lt;tex&amp;gt; O(n ^ 2 \log n) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
{|&lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zam.png|300px|thumb|left|Заметание плоскости вращающимся лучом]]&lt;br /&gt;
Однако можно это сделать за &amp;lt;tex&amp;gt; O(n ^ 2 \log  n) &amp;lt;/tex&amp;gt;. Идея алгоритма проста: для каждой вершины найдем видимые из нее вершины. Если научиться делать это за &amp;lt;tex&amp;gt; O(n \log  n) &amp;lt;/tex&amp;gt;, задача решена, так как всего точек &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для каждой вершины будем рассматривать только правую половину плоскости, так как ребра, которые должны идти в левую половину, будут исходить из вершин, для которых текущая вершина будет справа.&lt;br /&gt;
&lt;br /&gt;
Переформулируем задачу. Дано: точка &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и множество отрезков {{---}} ребер препятствий. &lt;br /&gt;
Найти: множество концов отрезков, видимых из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для решения этой задачи будем использовать заметающий луч с началом в точке &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Его статусом будут отрезки, которые его пересекают, упорядоченные по возрастанию расстояния от точки &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; до точки пересечения. Точками событий будут концы отрезков. &lt;br /&gt;
&lt;br /&gt;
Пустим луч из рассматриваемой вершины &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вертикально вверх и добавим в статус все отрезки, которые он пересекает, по увеличению расстояния до них. Теперь будем рассматривать точки &amp;lt;tex&amp;gt; w \in V &amp;lt;/tex&amp;gt; в порядке сортировки по углу между &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и вертикальной полуосью &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt;. При таком обходе для проверки видимости вершины достаточно проверить пересечение с ближайшим к &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; отрезком, то есть первым в статусе(так как отрезки отсортированы по расстоянию до них). Действительно, если вершина &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; не видна, то отрезок &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; пересекает несколько отрезков, лежащих перед &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt;, а значит и ближайший. В противном случае все пересекаемые лучом отрезки лежат за вершиной &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; и пересечения отрезка &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; с ближайшим отрезком не будет. Вне зависимости от видимости вершины, необходимо изменить статус заметающего луча. Для этого необходимо удалить из статуса все отрезки, которые заканчиваются вершине &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; (лежат слева от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;) и добавить все отрезки, которые в ней начинаются (лежат справа от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Псевдокод =====&lt;br /&gt;
 graph buildVisibilityGraph(Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
    vertices = getVertices(segments) &amp;lt;tex&amp;gt; \cup\ \{s,\ t\} &amp;lt;/tex&amp;gt;&lt;br /&gt;
    graph = visibilityGraph(vertices)                  &lt;br /&gt;
    '''for''' Vertex &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; '''in''' vertices&lt;br /&gt;
       '''for''' Vertex &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt; '''in''' getVisibleVertices(&amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, segments)&lt;br /&gt;
          visibilityGraph.addEdge(&amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;)&lt;br /&gt;
    '''return''' visibilityGraph&lt;br /&gt;
Здесь функция getVisibleVertices(&amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;) возвращает все видимые из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вершины и выглядит так:&lt;br /&gt;
 Set&amp;lt;Vertex&amp;gt; getVisibleVertices(Vertex &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
    Set&amp;lt;Vertex&amp;gt; answer&lt;br /&gt;
    '''for''' Segment &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; '''in''' segments&lt;br /&gt;
       '''if''' intersect(&amp;lt;tex&amp;gt; s &amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt;)&lt;br /&gt;
          status.add(&amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;)&lt;br /&gt;
    '''for''' Point &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt; '''in''' segments&lt;br /&gt;
       '''if''' &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;.x &amp;lt;tex&amp;gt;\le&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;.x&lt;br /&gt;
          currentVertices.add(&amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;)&lt;br /&gt;
    sort(currentVertices) by angle&lt;br /&gt;
    '''for''' Point &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt; '''in''' currentVertices&lt;br /&gt;
       '''if''' '''not''' intersect(&amp;lt;tex&amp;gt;vw&amp;lt;/tex&amp;gt;, status.closest)&lt;br /&gt;
          answer.add(&amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;)&lt;br /&gt;
       '''for''' Segment &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; ending in &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;&lt;br /&gt;
          status.delete(&amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;)&lt;br /&gt;
       '''for''' Segment &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; beginning in &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;&lt;br /&gt;
          status.add(&amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;)&lt;br /&gt;
    '''return''' answer&lt;br /&gt;
В качестве статуса нужно использовать структуру данных, позволяющую добавлять и удалять из нее отрезки за &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; и извлекать минимум за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt;. В этом случае достигается асимптотика &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;, так как для каждой из &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; точек выполняется сортировка за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, обновление статуса (суммарно &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, так как каждый отрезок добавляется и удаляется из статуса не более одного раза) и запросы ближайшего отрезка (&amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; на точку, то есть &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;). &lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zamrefr1.png|250px|thumb|right|Обновление статуса заметающего луча: добавляем ребра &amp;lt;tex&amp;gt; w_1 w_5 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; w_1 w_2 &amp;lt;/tex&amp;gt; в статус]]&lt;br /&gt;
[[Файл:Zamrefr2.png|250px|thumb|right|Добавляем ребра &amp;lt;tex&amp;gt; w_3 w_2 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; w_3 w_4 &amp;lt;/tex&amp;gt; в статус]]&lt;br /&gt;
[[Файл:Zamrefr3.png|250px|thumb|right|Удаляем ребра &amp;lt;tex&amp;gt; w_3 w_2 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; w_1 w_2 &amp;lt;/tex&amp;gt; из статуса]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Overmars and Welzl’s Algorithm &amp;lt;tex&amp;gt; O(n ^ 2) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
[http://igitur-archive.library.uu.nl/math/2006-1214-201604/overmars_88_new_methods.pdf visibility graph при помощи rotation tree]&lt;br /&gt;
&lt;br /&gt;
C помощью [http://bit.ly/1eEqTzk rotation tree] можно достичь асимптотики &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Motion planning ==&lt;br /&gt;
[[Файл:mink.png|200px|thumb|left|Изменяем препятствия]]&lt;br /&gt;
[[Файл:mink2.png|400px|thumb|right|Ищем путь для точки]]&lt;br /&gt;
Рассмотрим задачу нахождения кратчайшего пути, когда движимый объект {{---}} это выпуклый полигон. Например, робот, которого надо доставить из начальной в конечную точку.&lt;br /&gt;
&lt;br /&gt;
Если полигон вращать нельзя, задачу сводится к движению точки так: выбирается точка на полигоне, которая принимается за начало координат. В такой системе координат для каждого препятствия считается [[Сумма Минковского (определение, вычисление)|сумма Минковского]] с полигоном. Получаются бОльшие препятствия, но теперь достаточно двигать выбранную точку, что было описано выше.&lt;br /&gt;
&lt;br /&gt;
Если полигон можно вращать, задача нахождения ''кратчайшего'' пути становится достаточно ресурсоёмка, поэтому обычно рассматривают задачу нахождения какого-нибудь пути между конечными точками.&lt;br /&gt;
&lt;br /&gt;
Первый шаг решения этой задачи совпадает с предыдущим случаем: выберем точку и построим [[Сумма Минковского (определение, вычисление)|сумму Минковского]] препятствий с полигоном. Рассмотрим малый угол &amp;lt;tex&amp;gt; \epsilon &amp;lt;/tex&amp;gt;. Представим, что поворот полигона на этот угол {{---}} это движение вверх-вниз между слоями, на каждом из которых посчитана сумма Минковского с полигоном, повернутым на этот угол.&lt;br /&gt;
&lt;br /&gt;
На каждом слое построим трапецоидную карту и граф, как описано в [[Visibility graph и motion planning#Нахождение пути между точками с препятствиями|начале]]. Если [[Пересечение многоугольников (PSLG overlaying)|пересечь]] соседние слои и добавить между их графами ребра, получится один большой граф, в котором ищется кратчайший путь.&lt;br /&gt;
&lt;br /&gt;
При таком подходе может возникнуть ошибка при пересечении слоев: на каждом слое состояния будут допустимые, а осуществить поворот физически будет невозможно. Обычно, эту проблему решают двумя способами: измельчением угла поворота и изначальным сглаживанием углов полигона. Первый способ повышает не только точность решения, но и вычислительную сложность задачи. Второй подход практически исключает возможность нахождения пути, когда его нет, но повышает вероятность &amp;quot;ненахождения&amp;quot; пути, когда он есть.&lt;br /&gt;
&lt;br /&gt;
== Источники ==&lt;br /&gt;
* 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&lt;br /&gt;
* [http://www.academia.edu/2845047/3D_Visibility_Graph статья] про visibility graphs на academia.edu&lt;br /&gt;
* [http://habrahabr.ru/post/199256/ Хабр]&lt;br /&gt;
[[Категория: Вычислительная геометрия]]&lt;br /&gt;
&lt;br /&gt;
== Ссылки ==&lt;br /&gt;
* Моя [https://github.com/Igorjan94/cg/blob/master/include/cg/algorithms/visibilityGraph.h реализация] алгоритма за &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;. Далеко от идеального, но работает&lt;/div&gt;</summary>
		<author><name>Igorjan94</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44874</id>
		<title>Visibility graph и motion planning</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44874"/>
				<updated>2015-02-15T13:54:15Z</updated>
		
		<summary type="html">&lt;p&gt;Igorjan94: /* Псевдокод */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Нахождение любого пути между точками с препятствиями ==&lt;br /&gt;
{|align=&amp;quot;right&amp;quot;&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
|[[Файл:trap.png|200px|thumb|right|Путь с препятствиями через трапецоидную карту]]&lt;br /&gt;
|[[Файл:notShort.png|300px|thumb|right|Такой путь не самый короткий]]&lt;br /&gt;
|}&lt;br /&gt;
Для начала рассмотрим движение материальной точки. Случай, когда размером и формой движимого объекта пренебречь нельзя, будет рассмотрен [[Visibility graph и motion planning#Motion planning|позднее]]. &lt;br /&gt;
&lt;br /&gt;
Эту задачу можно решить с помощью [[Трапецоидная карта | трапецоидной карты]]. По ней строится граф, ребра которого соединяют центры трапедоидов, а также начальную и конечную вершины с серединами вертикальных сторон трапецоидов. В таком графе ищется путь между начальной и конечной вершинами.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм работает за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; и за линейное количество памяти и хорошо подходит для нахождения какого-нибудь пути между парой данных вершин. Но если нужно найти кратчайший путь, этот алгоритм не подходит, хоть и работает быстро. Однако, решения нахождения кратчайшего пути в лучшем случае работают за &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; времени и памяти (здесь и далее &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество всех вершин).&lt;br /&gt;
&lt;br /&gt;
== Нахождение кратчайшего пути между точками с препятствиями ==&lt;br /&gt;
=== Visibility graph ===&lt;br /&gt;
Рассмотрим точное решение нахождения кратчайшего пути на плоскости между двумя точками с полигональными препятствиями с помощью построения графа видимости. После его построения, как и в случае с трапецоидной картой, кратчайший путь ищется любым стандартным алгоритмом поиска (например, алгоритмом [[Алгоритм Дейкстры|Дейкстры]] или [[Алгоритм A*|A*]]).&lt;br /&gt;
&lt;br /&gt;
Для простоты рассуждений начальную и конечную вершины будем считать вершинами полигонов.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|about=О кратчайшем пути&lt;br /&gt;
|statement=&lt;br /&gt;
Любой кратчайший путь между двумя вершинами с полигональными препятствиями представляет собой ломаную, вершины которой {{---}} вершины полигонов.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:short.png|150px|thumb|right|Short cut]]&lt;br /&gt;
Пусть кратчайший путь {{---}} не ломаная. В таком случае, на пути существует такая точка &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, которая не принадлежит ни одному прямому отрезку. Это означает, что существует &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестность точки &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, в которую не попадает ни одно препятствие (случай, когда точка попала на ребро рассматривается аналогично). В таком случае, подпуть, который находится внутри &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности, по неравенству треугольника может быть сокращён по хорде, соединяющий точки пересечения границы &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности с путем. Раз часть пути может быть уменьшена, значит и весь путь может быть уменьшен, а значит исходное предположение некорректно.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
Говорят, что вершина &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; ''видна'' (англ. mutually visible) из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;, если отрезок &amp;lt;tex&amp;gt; uv &amp;lt;/tex&amp;gt; не пересекает ни одного препятствия.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
''Граф видимости'' (англ. visibility graph) {{---}} граф, вершины которого {{---}} вершины полигонов. Между вершинами &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; существует ребро, если из &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; видна &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
В худшем случае в таком графе может быть &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; ребер. Однако по некоторым ребрам кратчайший путь точно не пройдет, и такие ребра из графа можно удалить.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
[[Файл:edgeToDelete.png|150px|thumb|right|Удаляем &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Если существуют вершины &amp;lt;tex&amp;gt; A, B, C &amp;lt;/tex&amp;gt; одного препятствия и вершина &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; такая, что поворот &amp;lt;tex&amp;gt; DBA &amp;lt;/tex&amp;gt; не совпадает с поворотом &amp;lt;tex&amp;gt; DBC &amp;lt;/tex&amp;gt;, то ребро &amp;lt;tex&amp;gt; DB &amp;lt;/tex&amp;gt; не принадлежит кратчайшему пути и его можно удалить из графа. (См. поясняющую картинку справа)&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:edgeNotToDelete.png|200px|thumb|right|Не удаляем &amp;lt;tex&amp;gt; BS &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Путь проходящий через ребро &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt; будет длиннее, чем через соседей точки &amp;lt;tex&amp;gt; B &amp;lt;/tex&amp;gt;, так как по неравенству треугольника &amp;lt;tex&amp;gt; AB + BD &amp;gt; AD &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
По доказанным леммам любое ребро кратчайшего пути содержится в графе. Таким образом, для нахождения кратчайшего пути осталось найти кратчайший путь в этом графе от начальной до конечной вершины.&lt;br /&gt;
&lt;br /&gt;
=== Построение visibility графа ===&lt;br /&gt;
==== Наивный алгоритм. &amp;lt;tex&amp;gt; O(n ^ 3) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
Для каждой пары вершин проверяем, можно ли добавить ребро между ними, то есть нет ли пересечений с полигонами. &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; пар вершин и &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; ребер, то есть &amp;lt;tex&amp;gt; O(n^3) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Lee’s Algorithm. &amp;lt;tex&amp;gt; O(n ^ 2 \log n) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
{|&lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zam.png|300px|thumb|left|Заметание плоскости вращающимся лучом]]&lt;br /&gt;
Однако можно это сделать за &amp;lt;tex&amp;gt; O(n ^ 2 \log  n) &amp;lt;/tex&amp;gt;. Идея алгоритма проста: для каждой вершины найдем видимые из нее вершины. Если научиться делать это за &amp;lt;tex&amp;gt; O(n \log  n) &amp;lt;/tex&amp;gt;, задача решена, так как всего точек &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для каждой вершины будем рассматривать только правую половину плоскости, так как ребра, которые должны идти в левую половину, будут исходить из вершин, для которых текущая вершина будет справа.&lt;br /&gt;
&lt;br /&gt;
Переформулируем задачу. Дано: точка &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и множество отрезков {{---}} ребер препятствий. &lt;br /&gt;
Найти: множество концов отрезков, видимых из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для решения этой задачи будем использовать заметающий луч с началом в точке &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Его статусом будут отрезки, которые его пересекают, упорядоченные по возрастанию расстояния от точки &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; до точки пересечения. Точками событий будут концы отрезков. &lt;br /&gt;
&lt;br /&gt;
Пустим луч из рассматриваемой вершины &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вертикально вверх и добавим в статус все отрезки, которые он пересекает, по увеличению расстояния до них. Теперь будем рассматривать точки &amp;lt;tex&amp;gt; w \in V &amp;lt;/tex&amp;gt; в порядке сортировки по углу между &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и вертикальной полуосью &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt;. При таком обходе для проверки видимости вершины достаточно проверить пересечение с ближайшим к &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; отрезком, то есть первым в статусе(так как отрезки отсортированы по расстоянию до них). Действительно, если вершина &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; не видна, то отрезок &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; пересекает несколько отрезков, лежащих перед &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt;, а значит и ближайший. В противном случае все пересекаемые лучом отрезки лежат за вершиной &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; и пересечения отрезка &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; с ближайшим отрезком не будет. Вне зависимости от видимости вершины, необходимо изменить статус заметающего луча. Для этого необходимо удалить из статуса все отрезки, которые заканчиваются вершине &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; (лежат слева от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;) и добавить все отрезки, которые в ней начинаются (лежат справа от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Псевдокод =====&lt;br /&gt;
 graph buildVisibilityGraph(Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
    //все вершины препятствий, а также начальная и конечная вершины&lt;br /&gt;
    vertices = getVertices(segments) &amp;lt;tex&amp;gt; \cup\ \{S, T\} &amp;lt;/tex&amp;gt;     &lt;br /&gt;
    //изначально в графе только вершины&lt;br /&gt;
    graph = visibilityGraph(vertices)                  &lt;br /&gt;
    '''for''' Vertex &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; '''in''' vertices&lt;br /&gt;
       //добавляем в граф все видимые из нее вершины&lt;br /&gt;
       '''for''' Vertex &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt; '''in''' getVisibleVertices(&amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, segments)&lt;br /&gt;
          visibilityGraph.addEdge(&amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;)&lt;br /&gt;
    '''return''' visibilityGraph&lt;br /&gt;
Здесь функция getVisibleVertices(&amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;) возвращает все видимые из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вершины и выглядит так:&lt;br /&gt;
 Set&amp;lt;Vertex&amp;gt; getVisibleVertices(Vertex &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
    Set&amp;lt;Vertex&amp;gt; answer&lt;br /&gt;
 // Инициализируем статус&lt;br /&gt;
    '''for''' Segment &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; '''in''' segments&lt;br /&gt;
       '''if''' intersection &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; and ray from &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; to up exists&lt;br /&gt;
          status.add(&amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;)&lt;br /&gt;
 // Инициализируем множество вершин, которые нужно рассматривать&lt;br /&gt;
    '''for''' Point &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt; '''in''' segments&lt;br /&gt;
       '''if''' &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;.x &amp;lt;tex&amp;gt;\le&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;.x&lt;br /&gt;
          currentVertices.add(&amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;)&lt;br /&gt;
    sort(currentVertices) by angle&lt;br /&gt;
 // Для каждой вершины проверяем, видима ли она и обновляем статус&lt;br /&gt;
    '''for''' Point &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt; '''in''' currentVertices&lt;br /&gt;
       '''if''' intersection &amp;lt;tex&amp;gt;vw&amp;lt;/tex&amp;gt; and status.closest not exists&lt;br /&gt;
          answer.add(&amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;)&lt;br /&gt;
       '''for''' Segment &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; ending in &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;&lt;br /&gt;
          status.delete(&amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;)&lt;br /&gt;
       '''for''' Segment &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; beginning in &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;&lt;br /&gt;
          status.add(&amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;)&lt;br /&gt;
    '''return''' answer&lt;br /&gt;
В качестве статуса нужно использовать структуру данных, позволяющую добавлять и удалять из нее отрезки за &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; и извлекать минимум за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt;. В этом случае достигается асимптотика &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;, так как для каждой из &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; точек выполняется сортировка за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, обновление статуса (суммарно &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, так как каждый отрезок добавляется и удаляется из статуса не более одного раза) и запросы ближайшего отрезка (&amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; на точку, то есть &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;). &lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zamrefr1.png|250px|thumb|right|Обновление статуса заметающего луча: добавляем ребра &amp;lt;tex&amp;gt; w_1 w_5 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; w_1 w_2 &amp;lt;/tex&amp;gt; в статус]]&lt;br /&gt;
[[Файл:Zamrefr2.png|250px|thumb|right|Добавляем ребра &amp;lt;tex&amp;gt; w_3 w_2 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; w_3 w_4 &amp;lt;/tex&amp;gt; в статус]]&lt;br /&gt;
[[Файл:Zamrefr3.png|250px|thumb|right|Удаляем ребра &amp;lt;tex&amp;gt; w_3 w_2 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; w_1 w_2 &amp;lt;/tex&amp;gt; из статуса]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Overmars and Welzl’s Algorithm &amp;lt;tex&amp;gt; O(n ^ 2) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
[http://igitur-archive.library.uu.nl/math/2006-1214-201604/overmars_88_new_methods.pdf visibility graph при помощи rotation tree]&lt;br /&gt;
&lt;br /&gt;
C помощью [http://bit.ly/1eEqTzk rotation tree] можно достичь асимптотики &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Motion planning ==&lt;br /&gt;
[[Файл:mink.png|200px|thumb|left|Изменяем препятствия]]&lt;br /&gt;
[[Файл:mink2.png|400px|thumb|right|Ищем путь для точки]]&lt;br /&gt;
Рассмотрим задачу нахождения кратчайшего пути, когда движимый объект {{---}} это выпуклый полигон. Например, робот, которого надо доставить из начальной в конечную точку.&lt;br /&gt;
&lt;br /&gt;
Если полигон вращать нельзя, задачу сводится к движению точки так: выбирается точка на полигоне, которая принимается за начало координат. В такой системе координат для каждого препятствия считается [[Сумма Минковского (определение, вычисление)|сумма Минковского]] с полигоном. Получаются бОльшие препятствия, но теперь достаточно двигать выбранную точку, что было описано выше.&lt;br /&gt;
&lt;br /&gt;
Если полигон можно вращать, задача нахождения ''кратчайшего'' пути становится достаточно ресурсоёмка, поэтому обычно рассматривают задачу нахождения какого-нибудь пути между конечными точками.&lt;br /&gt;
&lt;br /&gt;
Первый шаг решения этой задачи совпадает с предыдущим случаем: выберем точку и построим [[Сумма Минковского (определение, вычисление)|сумму Минковского]] препятствий с полигоном. Рассмотрим малый угол &amp;lt;tex&amp;gt; \epsilon &amp;lt;/tex&amp;gt;. Представим, что поворот полигона на этот угол {{---}} это движение вверх-вниз между слоями, на каждом из которых посчитана сумма Минковского с полигоном, повернутым на этот угол.&lt;br /&gt;
&lt;br /&gt;
На каждом слое построим трапецоидную карту и граф, как описано в [[Visibility graph и motion planning#Нахождение пути между точками с препятствиями|начале]]. Если [[Пересечение многоугольников (PSLG overlaying)|пересечь]] соседние слои и добавить между их графами ребра, получится один большой граф, в котором ищется кратчайший путь.&lt;br /&gt;
&lt;br /&gt;
При таком подходе может возникнуть ошибка при пересечении слоев: на каждом слое состояния будут допустимые, а осуществить поворот физически будет невозможно. Обычно, эту проблему решают двумя способами: измельчением угла поворота и изначальным сглаживанием углов полигона. Первый способ повышает не только точность решения, но и вычислительную сложность задачи. Второй подход практически исключает возможность нахождения пути, когда его нет, но повышает вероятность &amp;quot;ненахождения&amp;quot; пути, когда он есть.&lt;br /&gt;
&lt;br /&gt;
== Источники ==&lt;br /&gt;
* 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&lt;br /&gt;
* [http://www.academia.edu/2845047/3D_Visibility_Graph статья] про visibility graphs на academia.edu&lt;br /&gt;
* [http://habrahabr.ru/post/199256/ Хабр]&lt;br /&gt;
[[Категория: Вычислительная геометрия]]&lt;br /&gt;
&lt;br /&gt;
== Ссылки ==&lt;br /&gt;
* Моя [https://github.com/Igorjan94/cg/blob/master/include/cg/algorithms/visibilityGraph.h реализация] алгоритма за &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;. Далеко от идеального, но работает&lt;/div&gt;</summary>
		<author><name>Igorjan94</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44873</id>
		<title>Visibility graph и motion planning</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44873"/>
				<updated>2015-02-15T13:53:56Z</updated>
		
		<summary type="html">&lt;p&gt;Igorjan94: /* Псевдокод */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Нахождение любого пути между точками с препятствиями ==&lt;br /&gt;
{|align=&amp;quot;right&amp;quot;&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
|[[Файл:trap.png|200px|thumb|right|Путь с препятствиями через трапецоидную карту]]&lt;br /&gt;
|[[Файл:notShort.png|300px|thumb|right|Такой путь не самый короткий]]&lt;br /&gt;
|}&lt;br /&gt;
Для начала рассмотрим движение материальной точки. Случай, когда размером и формой движимого объекта пренебречь нельзя, будет рассмотрен [[Visibility graph и motion planning#Motion planning|позднее]]. &lt;br /&gt;
&lt;br /&gt;
Эту задачу можно решить с помощью [[Трапецоидная карта | трапецоидной карты]]. По ней строится граф, ребра которого соединяют центры трапедоидов, а также начальную и конечную вершины с серединами вертикальных сторон трапецоидов. В таком графе ищется путь между начальной и конечной вершинами.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм работает за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; и за линейное количество памяти и хорошо подходит для нахождения какого-нибудь пути между парой данных вершин. Но если нужно найти кратчайший путь, этот алгоритм не подходит, хоть и работает быстро. Однако, решения нахождения кратчайшего пути в лучшем случае работают за &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; времени и памяти (здесь и далее &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество всех вершин).&lt;br /&gt;
&lt;br /&gt;
== Нахождение кратчайшего пути между точками с препятствиями ==&lt;br /&gt;
=== Visibility graph ===&lt;br /&gt;
Рассмотрим точное решение нахождения кратчайшего пути на плоскости между двумя точками с полигональными препятствиями с помощью построения графа видимости. После его построения, как и в случае с трапецоидной картой, кратчайший путь ищется любым стандартным алгоритмом поиска (например, алгоритмом [[Алгоритм Дейкстры|Дейкстры]] или [[Алгоритм A*|A*]]).&lt;br /&gt;
&lt;br /&gt;
Для простоты рассуждений начальную и конечную вершины будем считать вершинами полигонов.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|about=О кратчайшем пути&lt;br /&gt;
|statement=&lt;br /&gt;
Любой кратчайший путь между двумя вершинами с полигональными препятствиями представляет собой ломаную, вершины которой {{---}} вершины полигонов.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:short.png|150px|thumb|right|Short cut]]&lt;br /&gt;
Пусть кратчайший путь {{---}} не ломаная. В таком случае, на пути существует такая точка &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, которая не принадлежит ни одному прямому отрезку. Это означает, что существует &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестность точки &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, в которую не попадает ни одно препятствие (случай, когда точка попала на ребро рассматривается аналогично). В таком случае, подпуть, который находится внутри &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности, по неравенству треугольника может быть сокращён по хорде, соединяющий точки пересечения границы &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности с путем. Раз часть пути может быть уменьшена, значит и весь путь может быть уменьшен, а значит исходное предположение некорректно.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
Говорят, что вершина &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; ''видна'' (англ. mutually visible) из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;, если отрезок &amp;lt;tex&amp;gt; uv &amp;lt;/tex&amp;gt; не пересекает ни одного препятствия.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
''Граф видимости'' (англ. visibility graph) {{---}} граф, вершины которого {{---}} вершины полигонов. Между вершинами &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; существует ребро, если из &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; видна &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
В худшем случае в таком графе может быть &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; ребер. Однако по некоторым ребрам кратчайший путь точно не пройдет, и такие ребра из графа можно удалить.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
[[Файл:edgeToDelete.png|150px|thumb|right|Удаляем &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Если существуют вершины &amp;lt;tex&amp;gt; A, B, C &amp;lt;/tex&amp;gt; одного препятствия и вершина &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; такая, что поворот &amp;lt;tex&amp;gt; DBA &amp;lt;/tex&amp;gt; не совпадает с поворотом &amp;lt;tex&amp;gt; DBC &amp;lt;/tex&amp;gt;, то ребро &amp;lt;tex&amp;gt; DB &amp;lt;/tex&amp;gt; не принадлежит кратчайшему пути и его можно удалить из графа. (См. поясняющую картинку справа)&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:edgeNotToDelete.png|200px|thumb|right|Не удаляем &amp;lt;tex&amp;gt; BS &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Путь проходящий через ребро &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt; будет длиннее, чем через соседей точки &amp;lt;tex&amp;gt; B &amp;lt;/tex&amp;gt;, так как по неравенству треугольника &amp;lt;tex&amp;gt; AB + BD &amp;gt; AD &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
По доказанным леммам любое ребро кратчайшего пути содержится в графе. Таким образом, для нахождения кратчайшего пути осталось найти кратчайший путь в этом графе от начальной до конечной вершины.&lt;br /&gt;
&lt;br /&gt;
=== Построение visibility графа ===&lt;br /&gt;
==== Наивный алгоритм. &amp;lt;tex&amp;gt; O(n ^ 3) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
Для каждой пары вершин проверяем, можно ли добавить ребро между ними, то есть нет ли пересечений с полигонами. &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; пар вершин и &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; ребер, то есть &amp;lt;tex&amp;gt; O(n^3) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Lee’s Algorithm. &amp;lt;tex&amp;gt; O(n ^ 2 \log n) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
{|&lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zam.png|300px|thumb|left|Заметание плоскости вращающимся лучом]]&lt;br /&gt;
Однако можно это сделать за &amp;lt;tex&amp;gt; O(n ^ 2 \log  n) &amp;lt;/tex&amp;gt;. Идея алгоритма проста: для каждой вершины найдем видимые из нее вершины. Если научиться делать это за &amp;lt;tex&amp;gt; O(n \log  n) &amp;lt;/tex&amp;gt;, задача решена, так как всего точек &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для каждой вершины будем рассматривать только правую половину плоскости, так как ребра, которые должны идти в левую половину, будут исходить из вершин, для которых текущая вершина будет справа.&lt;br /&gt;
&lt;br /&gt;
Переформулируем задачу. Дано: точка &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и множество отрезков {{---}} ребер препятствий. &lt;br /&gt;
Найти: множество концов отрезков, видимых из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для решения этой задачи будем использовать заметающий луч с началом в точке &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Его статусом будут отрезки, которые его пересекают, упорядоченные по возрастанию расстояния от точки &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; до точки пересечения. Точками событий будут концы отрезков. &lt;br /&gt;
&lt;br /&gt;
Пустим луч из рассматриваемой вершины &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вертикально вверх и добавим в статус все отрезки, которые он пересекает, по увеличению расстояния до них. Теперь будем рассматривать точки &amp;lt;tex&amp;gt; w \in V &amp;lt;/tex&amp;gt; в порядке сортировки по углу между &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и вертикальной полуосью &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt;. При таком обходе для проверки видимости вершины достаточно проверить пересечение с ближайшим к &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; отрезком, то есть первым в статусе(так как отрезки отсортированы по расстоянию до них). Действительно, если вершина &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; не видна, то отрезок &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; пересекает несколько отрезков, лежащих перед &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt;, а значит и ближайший. В противном случае все пересекаемые лучом отрезки лежат за вершиной &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; и пересечения отрезка &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; с ближайшим отрезком не будет. Вне зависимости от видимости вершины, необходимо изменить статус заметающего луча. Для этого необходимо удалить из статуса все отрезки, которые заканчиваются вершине &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; (лежат слева от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;) и добавить все отрезки, которые в ней начинаются (лежат справа от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Псевдокод =====&lt;br /&gt;
 graph buildVisibilityGraph(Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
    //все вершины препятствий, а также начальная и конечная вершины&lt;br /&gt;
    vertices = getVertices(segments) &amp;lt;tex&amp;gt; \cup\ \{S, T\} &amp;lt;/tex&amp;gt;     &lt;br /&gt;
    //изначально в графе только вершины&lt;br /&gt;
    graph = visibilityGraph(vertices)                  &lt;br /&gt;
    '''for''' Vertex &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; '''in''' vertices&lt;br /&gt;
       //добавляем в граф все видимые из нее вершины&lt;br /&gt;
       '''for''' Vertex &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt; '''in''' getVisibleVertices(&amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, segments)&lt;br /&gt;
          visibilityGraph.addEdge(&amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;)&lt;br /&gt;
    '''return''' visibilityGraph&lt;br /&gt;
Здесь функция getVisibleVertices(&amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;) возвращает все видимые из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вершины и выглядит так:&lt;br /&gt;
 Set&amp;lt;Vertex&amp;gt; getVisibleVertices(Vertex &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
    Set&amp;lt;Vertex&amp;gt; answer&lt;br /&gt;
 // Инициализируем статус&lt;br /&gt;
    '''for''' Segment &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; '''in''' segments&lt;br /&gt;
       '''if''' intersection &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; and ray from &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; to up exists&lt;br /&gt;
          status.add(&amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;)&lt;br /&gt;
 // Инициализируем множество вершин, которые нужно рассматривать&lt;br /&gt;
    '''for''' Point &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt; '''in''' segments&lt;br /&gt;
       '''if''' &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;.x &amp;lt;tex&amp;gt;\le&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;.x&lt;br /&gt;
          currentVertices.add(&amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;)&lt;br /&gt;
    sort(currentVertices) by angle&lt;br /&gt;
 // Для каждой вершины проверяем, видима ли она и обновляем статус&lt;br /&gt;
    '''for''' Point &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt; '''in''' currentVertices&lt;br /&gt;
       '''if''' intersection &amp;lt;tex&amp;gt;vw&amp;lt;/tex&amp;gt; and status.closest not exists&lt;br /&gt;
          answer.add(&amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;)&lt;br /&gt;
       '''for''' Segment &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; ending in &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;&lt;br /&gt;
          status.delete(s)&lt;br /&gt;
       '''for''' Segment &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; beginning in &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;&lt;br /&gt;
          status.add(s)&lt;br /&gt;
    '''return''' answer&lt;br /&gt;
В качестве статуса нужно использовать структуру данных, позволяющую добавлять и удалять из нее отрезки за &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; и извлекать минимум за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt;. В этом случае достигается асимптотика &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;, так как для каждой из &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; точек выполняется сортировка за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, обновление статуса (суммарно &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, так как каждый отрезок добавляется и удаляется из статуса не более одного раза) и запросы ближайшего отрезка (&amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; на точку, то есть &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;). &lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zamrefr1.png|250px|thumb|right|Обновление статуса заметающего луча: добавляем ребра &amp;lt;tex&amp;gt; w_1 w_5 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; w_1 w_2 &amp;lt;/tex&amp;gt; в статус]]&lt;br /&gt;
[[Файл:Zamrefr2.png|250px|thumb|right|Добавляем ребра &amp;lt;tex&amp;gt; w_3 w_2 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; w_3 w_4 &amp;lt;/tex&amp;gt; в статус]]&lt;br /&gt;
[[Файл:Zamrefr3.png|250px|thumb|right|Удаляем ребра &amp;lt;tex&amp;gt; w_3 w_2 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; w_1 w_2 &amp;lt;/tex&amp;gt; из статуса]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Overmars and Welzl’s Algorithm &amp;lt;tex&amp;gt; O(n ^ 2) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
[http://igitur-archive.library.uu.nl/math/2006-1214-201604/overmars_88_new_methods.pdf visibility graph при помощи rotation tree]&lt;br /&gt;
&lt;br /&gt;
C помощью [http://bit.ly/1eEqTzk rotation tree] можно достичь асимптотики &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Motion planning ==&lt;br /&gt;
[[Файл:mink.png|200px|thumb|left|Изменяем препятствия]]&lt;br /&gt;
[[Файл:mink2.png|400px|thumb|right|Ищем путь для точки]]&lt;br /&gt;
Рассмотрим задачу нахождения кратчайшего пути, когда движимый объект {{---}} это выпуклый полигон. Например, робот, которого надо доставить из начальной в конечную точку.&lt;br /&gt;
&lt;br /&gt;
Если полигон вращать нельзя, задачу сводится к движению точки так: выбирается точка на полигоне, которая принимается за начало координат. В такой системе координат для каждого препятствия считается [[Сумма Минковского (определение, вычисление)|сумма Минковского]] с полигоном. Получаются бОльшие препятствия, но теперь достаточно двигать выбранную точку, что было описано выше.&lt;br /&gt;
&lt;br /&gt;
Если полигон можно вращать, задача нахождения ''кратчайшего'' пути становится достаточно ресурсоёмка, поэтому обычно рассматривают задачу нахождения какого-нибудь пути между конечными точками.&lt;br /&gt;
&lt;br /&gt;
Первый шаг решения этой задачи совпадает с предыдущим случаем: выберем точку и построим [[Сумма Минковского (определение, вычисление)|сумму Минковского]] препятствий с полигоном. Рассмотрим малый угол &amp;lt;tex&amp;gt; \epsilon &amp;lt;/tex&amp;gt;. Представим, что поворот полигона на этот угол {{---}} это движение вверх-вниз между слоями, на каждом из которых посчитана сумма Минковского с полигоном, повернутым на этот угол.&lt;br /&gt;
&lt;br /&gt;
На каждом слое построим трапецоидную карту и граф, как описано в [[Visibility graph и motion planning#Нахождение пути между точками с препятствиями|начале]]. Если [[Пересечение многоугольников (PSLG overlaying)|пересечь]] соседние слои и добавить между их графами ребра, получится один большой граф, в котором ищется кратчайший путь.&lt;br /&gt;
&lt;br /&gt;
При таком подходе может возникнуть ошибка при пересечении слоев: на каждом слое состояния будут допустимые, а осуществить поворот физически будет невозможно. Обычно, эту проблему решают двумя способами: измельчением угла поворота и изначальным сглаживанием углов полигона. Первый способ повышает не только точность решения, но и вычислительную сложность задачи. Второй подход практически исключает возможность нахождения пути, когда его нет, но повышает вероятность &amp;quot;ненахождения&amp;quot; пути, когда он есть.&lt;br /&gt;
&lt;br /&gt;
== Источники ==&lt;br /&gt;
* 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&lt;br /&gt;
* [http://www.academia.edu/2845047/3D_Visibility_Graph статья] про visibility graphs на academia.edu&lt;br /&gt;
* [http://habrahabr.ru/post/199256/ Хабр]&lt;br /&gt;
[[Категория: Вычислительная геометрия]]&lt;br /&gt;
&lt;br /&gt;
== Ссылки ==&lt;br /&gt;
* Моя [https://github.com/Igorjan94/cg/blob/master/include/cg/algorithms/visibilityGraph.h реализация] алгоритма за &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;. Далеко от идеального, но работает&lt;/div&gt;</summary>
		<author><name>Igorjan94</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44872</id>
		<title>Visibility graph и motion planning</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44872"/>
				<updated>2015-02-15T13:53:20Z</updated>
		
		<summary type="html">&lt;p&gt;Igorjan94: /* Псевдокод */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Нахождение любого пути между точками с препятствиями ==&lt;br /&gt;
{|align=&amp;quot;right&amp;quot;&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
|[[Файл:trap.png|200px|thumb|right|Путь с препятствиями через трапецоидную карту]]&lt;br /&gt;
|[[Файл:notShort.png|300px|thumb|right|Такой путь не самый короткий]]&lt;br /&gt;
|}&lt;br /&gt;
Для начала рассмотрим движение материальной точки. Случай, когда размером и формой движимого объекта пренебречь нельзя, будет рассмотрен [[Visibility graph и motion planning#Motion planning|позднее]]. &lt;br /&gt;
&lt;br /&gt;
Эту задачу можно решить с помощью [[Трапецоидная карта | трапецоидной карты]]. По ней строится граф, ребра которого соединяют центры трапедоидов, а также начальную и конечную вершины с серединами вертикальных сторон трапецоидов. В таком графе ищется путь между начальной и конечной вершинами.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм работает за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; и за линейное количество памяти и хорошо подходит для нахождения какого-нибудь пути между парой данных вершин. Но если нужно найти кратчайший путь, этот алгоритм не подходит, хоть и работает быстро. Однако, решения нахождения кратчайшего пути в лучшем случае работают за &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; времени и памяти (здесь и далее &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество всех вершин).&lt;br /&gt;
&lt;br /&gt;
== Нахождение кратчайшего пути между точками с препятствиями ==&lt;br /&gt;
=== Visibility graph ===&lt;br /&gt;
Рассмотрим точное решение нахождения кратчайшего пути на плоскости между двумя точками с полигональными препятствиями с помощью построения графа видимости. После его построения, как и в случае с трапецоидной картой, кратчайший путь ищется любым стандартным алгоритмом поиска (например, алгоритмом [[Алгоритм Дейкстры|Дейкстры]] или [[Алгоритм A*|A*]]).&lt;br /&gt;
&lt;br /&gt;
Для простоты рассуждений начальную и конечную вершины будем считать вершинами полигонов.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|about=О кратчайшем пути&lt;br /&gt;
|statement=&lt;br /&gt;
Любой кратчайший путь между двумя вершинами с полигональными препятствиями представляет собой ломаную, вершины которой {{---}} вершины полигонов.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:short.png|150px|thumb|right|Short cut]]&lt;br /&gt;
Пусть кратчайший путь {{---}} не ломаная. В таком случае, на пути существует такая точка &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, которая не принадлежит ни одному прямому отрезку. Это означает, что существует &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестность точки &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, в которую не попадает ни одно препятствие (случай, когда точка попала на ребро рассматривается аналогично). В таком случае, подпуть, который находится внутри &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности, по неравенству треугольника может быть сокращён по хорде, соединяющий точки пересечения границы &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности с путем. Раз часть пути может быть уменьшена, значит и весь путь может быть уменьшен, а значит исходное предположение некорректно.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
Говорят, что вершина &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; ''видна'' (англ. mutually visible) из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;, если отрезок &amp;lt;tex&amp;gt; uv &amp;lt;/tex&amp;gt; не пересекает ни одного препятствия.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
''Граф видимости'' (англ. visibility graph) {{---}} граф, вершины которого {{---}} вершины полигонов. Между вершинами &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; существует ребро, если из &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; видна &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
В худшем случае в таком графе может быть &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; ребер. Однако по некоторым ребрам кратчайший путь точно не пройдет, и такие ребра из графа можно удалить.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
[[Файл:edgeToDelete.png|150px|thumb|right|Удаляем &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Если существуют вершины &amp;lt;tex&amp;gt; A, B, C &amp;lt;/tex&amp;gt; одного препятствия и вершина &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; такая, что поворот &amp;lt;tex&amp;gt; DBA &amp;lt;/tex&amp;gt; не совпадает с поворотом &amp;lt;tex&amp;gt; DBC &amp;lt;/tex&amp;gt;, то ребро &amp;lt;tex&amp;gt; DB &amp;lt;/tex&amp;gt; не принадлежит кратчайшему пути и его можно удалить из графа. (См. поясняющую картинку справа)&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:edgeNotToDelete.png|200px|thumb|right|Не удаляем &amp;lt;tex&amp;gt; BS &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Путь проходящий через ребро &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt; будет длиннее, чем через соседей точки &amp;lt;tex&amp;gt; B &amp;lt;/tex&amp;gt;, так как по неравенству треугольника &amp;lt;tex&amp;gt; AB + BD &amp;gt; AD &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
По доказанным леммам любое ребро кратчайшего пути содержится в графе. Таким образом, для нахождения кратчайшего пути осталось найти кратчайший путь в этом графе от начальной до конечной вершины.&lt;br /&gt;
&lt;br /&gt;
=== Построение visibility графа ===&lt;br /&gt;
==== Наивный алгоритм. &amp;lt;tex&amp;gt; O(n ^ 3) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
Для каждой пары вершин проверяем, можно ли добавить ребро между ними, то есть нет ли пересечений с полигонами. &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; пар вершин и &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; ребер, то есть &amp;lt;tex&amp;gt; O(n^3) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Lee’s Algorithm. &amp;lt;tex&amp;gt; O(n ^ 2 \log n) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
{|&lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zam.png|300px|thumb|left|Заметание плоскости вращающимся лучом]]&lt;br /&gt;
Однако можно это сделать за &amp;lt;tex&amp;gt; O(n ^ 2 \log  n) &amp;lt;/tex&amp;gt;. Идея алгоритма проста: для каждой вершины найдем видимые из нее вершины. Если научиться делать это за &amp;lt;tex&amp;gt; O(n \log  n) &amp;lt;/tex&amp;gt;, задача решена, так как всего точек &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для каждой вершины будем рассматривать только правую половину плоскости, так как ребра, которые должны идти в левую половину, будут исходить из вершин, для которых текущая вершина будет справа.&lt;br /&gt;
&lt;br /&gt;
Переформулируем задачу. Дано: точка &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и множество отрезков {{---}} ребер препятствий. &lt;br /&gt;
Найти: множество концов отрезков, видимых из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для решения этой задачи будем использовать заметающий луч с началом в точке &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Его статусом будут отрезки, которые его пересекают, упорядоченные по возрастанию расстояния от точки &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; до точки пересечения. Точками событий будут концы отрезков. &lt;br /&gt;
&lt;br /&gt;
Пустим луч из рассматриваемой вершины &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вертикально вверх и добавим в статус все отрезки, которые он пересекает, по увеличению расстояния до них. Теперь будем рассматривать точки &amp;lt;tex&amp;gt; w \in V &amp;lt;/tex&amp;gt; в порядке сортировки по углу между &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и вертикальной полуосью &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt;. При таком обходе для проверки видимости вершины достаточно проверить пересечение с ближайшим к &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; отрезком, то есть первым в статусе(так как отрезки отсортированы по расстоянию до них). Действительно, если вершина &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; не видна, то отрезок &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; пересекает несколько отрезков, лежащих перед &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt;, а значит и ближайший. В противном случае все пересекаемые лучом отрезки лежат за вершиной &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; и пересечения отрезка &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; с ближайшим отрезком не будет. Вне зависимости от видимости вершины, необходимо изменить статус заметающего луча. Для этого необходимо удалить из статуса все отрезки, которые заканчиваются вершине &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; (лежат слева от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;) и добавить все отрезки, которые в ней начинаются (лежат справа от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Псевдокод =====&lt;br /&gt;
 graph buildVisibilityGraph(Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
    //все вершины препятствий, а также начальная и конечная вершины&lt;br /&gt;
    vertices = getVertices(segments) &amp;lt;tex&amp;gt; \cup\ \{S, T\} &amp;lt;/tex&amp;gt;     &lt;br /&gt;
    //изначально в графе только вершины&lt;br /&gt;
    graph = visibilityGraph(vertices)                  &lt;br /&gt;
    '''for''' Vertex &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; '''in''' vertices&lt;br /&gt;
       //добавляем в граф все видимые из нее вершины&lt;br /&gt;
       '''for''' Vertex &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt; '''in''' getVisibleVertices(&amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, segments)&lt;br /&gt;
          visibilityGraph.addEdge(&amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;)&lt;br /&gt;
    '''return''' visibilityGraph&lt;br /&gt;
Здесь функция getVisibleVertices(&amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;) возвращает все видимые из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вершины и выглядит так:&lt;br /&gt;
 Set&amp;lt;Vertex&amp;gt; getVisibleVertices(Vertex &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
    Set&amp;lt;Vertex&amp;gt; answer&lt;br /&gt;
 // Инициализируем статус&lt;br /&gt;
    '''for''' Segment &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; '''in''' segments&lt;br /&gt;
       '''if''' intersection &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; and ray from &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; to up exists&lt;br /&gt;
          status.add(&amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;)&lt;br /&gt;
 // Инициализируем множество вершин, которые нужно рассматривать&lt;br /&gt;
    '''for''' Point &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt; '''in''' segments&lt;br /&gt;
       '''if''' &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;.x &amp;lt;tex&amp;gt;\le&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;.x&lt;br /&gt;
          currentVertices.add(&amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;)&lt;br /&gt;
    sort(currentVertices) by angle&lt;br /&gt;
 // Для каждой вершины проверяем, видима ли она и обновляем статус&lt;br /&gt;
    '''for''' Point &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt; '''in''' currentVertices&lt;br /&gt;
       '''if''' intersection &amp;lt;tex&amp;gt;vw&amp;lt;/tex&amp;gt; and status.closest not exists&lt;br /&gt;
          answer.add(&amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;)&lt;br /&gt;
       '''for''' Segment s ending in &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;&lt;br /&gt;
          status.delete(s)&lt;br /&gt;
       '''for''' Segment s beginning in &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;&lt;br /&gt;
          status.add(s)&lt;br /&gt;
    '''return''' answer&lt;br /&gt;
В качестве статуса нужно использовать структуру данных, позволяющую добавлять и удалять из нее отрезки за &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; и извлекать минимум за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt;. В этом случае достигается асимптотика &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;, так как для каждой из &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; точек выполняется сортировка за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, обновление статуса (суммарно &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, так как каждый отрезок добавляется и удаляется из статуса не более одного раза) и запросы ближайшего отрезка (&amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; на точку, то есть &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;). &lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zamrefr1.png|250px|thumb|right|Обновление статуса заметающего луча: добавляем ребра &amp;lt;tex&amp;gt; w_1 w_5 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; w_1 w_2 &amp;lt;/tex&amp;gt; в статус]]&lt;br /&gt;
[[Файл:Zamrefr2.png|250px|thumb|right|Добавляем ребра &amp;lt;tex&amp;gt; w_3 w_2 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; w_3 w_4 &amp;lt;/tex&amp;gt; в статус]]&lt;br /&gt;
[[Файл:Zamrefr3.png|250px|thumb|right|Удаляем ребра &amp;lt;tex&amp;gt; w_3 w_2 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; w_1 w_2 &amp;lt;/tex&amp;gt; из статуса]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Overmars and Welzl’s Algorithm &amp;lt;tex&amp;gt; O(n ^ 2) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
[http://igitur-archive.library.uu.nl/math/2006-1214-201604/overmars_88_new_methods.pdf visibility graph при помощи rotation tree]&lt;br /&gt;
&lt;br /&gt;
C помощью [http://bit.ly/1eEqTzk rotation tree] можно достичь асимптотики &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Motion planning ==&lt;br /&gt;
[[Файл:mink.png|200px|thumb|left|Изменяем препятствия]]&lt;br /&gt;
[[Файл:mink2.png|400px|thumb|right|Ищем путь для точки]]&lt;br /&gt;
Рассмотрим задачу нахождения кратчайшего пути, когда движимый объект {{---}} это выпуклый полигон. Например, робот, которого надо доставить из начальной в конечную точку.&lt;br /&gt;
&lt;br /&gt;
Если полигон вращать нельзя, задачу сводится к движению точки так: выбирается точка на полигоне, которая принимается за начало координат. В такой системе координат для каждого препятствия считается [[Сумма Минковского (определение, вычисление)|сумма Минковского]] с полигоном. Получаются бОльшие препятствия, но теперь достаточно двигать выбранную точку, что было описано выше.&lt;br /&gt;
&lt;br /&gt;
Если полигон можно вращать, задача нахождения ''кратчайшего'' пути становится достаточно ресурсоёмка, поэтому обычно рассматривают задачу нахождения какого-нибудь пути между конечными точками.&lt;br /&gt;
&lt;br /&gt;
Первый шаг решения этой задачи совпадает с предыдущим случаем: выберем точку и построим [[Сумма Минковского (определение, вычисление)|сумму Минковского]] препятствий с полигоном. Рассмотрим малый угол &amp;lt;tex&amp;gt; \epsilon &amp;lt;/tex&amp;gt;. Представим, что поворот полигона на этот угол {{---}} это движение вверх-вниз между слоями, на каждом из которых посчитана сумма Минковского с полигоном, повернутым на этот угол.&lt;br /&gt;
&lt;br /&gt;
На каждом слое построим трапецоидную карту и граф, как описано в [[Visibility graph и motion planning#Нахождение пути между точками с препятствиями|начале]]. Если [[Пересечение многоугольников (PSLG overlaying)|пересечь]] соседние слои и добавить между их графами ребра, получится один большой граф, в котором ищется кратчайший путь.&lt;br /&gt;
&lt;br /&gt;
При таком подходе может возникнуть ошибка при пересечении слоев: на каждом слое состояния будут допустимые, а осуществить поворот физически будет невозможно. Обычно, эту проблему решают двумя способами: измельчением угла поворота и изначальным сглаживанием углов полигона. Первый способ повышает не только точность решения, но и вычислительную сложность задачи. Второй подход практически исключает возможность нахождения пути, когда его нет, но повышает вероятность &amp;quot;ненахождения&amp;quot; пути, когда он есть.&lt;br /&gt;
&lt;br /&gt;
== Источники ==&lt;br /&gt;
* 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&lt;br /&gt;
* [http://www.academia.edu/2845047/3D_Visibility_Graph статья] про visibility graphs на academia.edu&lt;br /&gt;
* [http://habrahabr.ru/post/199256/ Хабр]&lt;br /&gt;
[[Категория: Вычислительная геометрия]]&lt;br /&gt;
&lt;br /&gt;
== Ссылки ==&lt;br /&gt;
* Моя [https://github.com/Igorjan94/cg/blob/master/include/cg/algorithms/visibilityGraph.h реализация] алгоритма за &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;. Далеко от идеального, но работает&lt;/div&gt;</summary>
		<author><name>Igorjan94</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44871</id>
		<title>Visibility graph и motion planning</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44871"/>
				<updated>2015-02-15T13:46:06Z</updated>
		
		<summary type="html">&lt;p&gt;Igorjan94: /* Псевдокод */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Нахождение любого пути между точками с препятствиями ==&lt;br /&gt;
{|align=&amp;quot;right&amp;quot;&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
|[[Файл:trap.png|200px|thumb|right|Путь с препятствиями через трапецоидную карту]]&lt;br /&gt;
|[[Файл:notShort.png|300px|thumb|right|Такой путь не самый короткий]]&lt;br /&gt;
|}&lt;br /&gt;
Для начала рассмотрим движение материальной точки. Случай, когда размером и формой движимого объекта пренебречь нельзя, будет рассмотрен [[Visibility graph и motion planning#Motion planning|позднее]]. &lt;br /&gt;
&lt;br /&gt;
Эту задачу можно решить с помощью [[Трапецоидная карта | трапецоидной карты]]. По ней строится граф, ребра которого соединяют центры трапедоидов, а также начальную и конечную вершины с серединами вертикальных сторон трапецоидов. В таком графе ищется путь между начальной и конечной вершинами.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм работает за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; и за линейное количество памяти и хорошо подходит для нахождения какого-нибудь пути между парой данных вершин. Но если нужно найти кратчайший путь, этот алгоритм не подходит, хоть и работает быстро. Однако, решения нахождения кратчайшего пути в лучшем случае работают за &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; времени и памяти (здесь и далее &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество всех вершин).&lt;br /&gt;
&lt;br /&gt;
== Нахождение кратчайшего пути между точками с препятствиями ==&lt;br /&gt;
=== Visibility graph ===&lt;br /&gt;
Рассмотрим точное решение нахождения кратчайшего пути на плоскости между двумя точками с полигональными препятствиями с помощью построения графа видимости. После его построения, как и в случае с трапецоидной картой, кратчайший путь ищется любым стандартным алгоритмом поиска (например, алгоритмом [[Алгоритм Дейкстры|Дейкстры]] или [[Алгоритм A*|A*]]).&lt;br /&gt;
&lt;br /&gt;
Для простоты рассуждений начальную и конечную вершины будем считать вершинами полигонов.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|about=О кратчайшем пути&lt;br /&gt;
|statement=&lt;br /&gt;
Любой кратчайший путь между двумя вершинами с полигональными препятствиями представляет собой ломаную, вершины которой {{---}} вершины полигонов.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:short.png|150px|thumb|right|Short cut]]&lt;br /&gt;
Пусть кратчайший путь {{---}} не ломаная. В таком случае, на пути существует такая точка &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, которая не принадлежит ни одному прямому отрезку. Это означает, что существует &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестность точки &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, в которую не попадает ни одно препятствие (случай, когда точка попала на ребро рассматривается аналогично). В таком случае, подпуть, который находится внутри &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности, по неравенству треугольника может быть сокращён по хорде, соединяющий точки пересечения границы &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности с путем. Раз часть пути может быть уменьшена, значит и весь путь может быть уменьшен, а значит исходное предположение некорректно.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
Говорят, что вершина &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; ''видна'' (англ. mutually visible) из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;, если отрезок &amp;lt;tex&amp;gt; uv &amp;lt;/tex&amp;gt; не пересекает ни одного препятствия.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
''Граф видимости'' (англ. visibility graph) {{---}} граф, вершины которого {{---}} вершины полигонов. Между вершинами &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; существует ребро, если из &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; видна &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
В худшем случае в таком графе может быть &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; ребер. Однако по некоторым ребрам кратчайший путь точно не пройдет, и такие ребра из графа можно удалить.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
[[Файл:edgeToDelete.png|150px|thumb|right|Удаляем &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Если существуют вершины &amp;lt;tex&amp;gt; A, B, C &amp;lt;/tex&amp;gt; одного препятствия и вершина &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; такая, что поворот &amp;lt;tex&amp;gt; DBA &amp;lt;/tex&amp;gt; не совпадает с поворотом &amp;lt;tex&amp;gt; DBC &amp;lt;/tex&amp;gt;, то ребро &amp;lt;tex&amp;gt; DB &amp;lt;/tex&amp;gt; не принадлежит кратчайшему пути и его можно удалить из графа. (См. поясняющую картинку справа)&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:edgeNotToDelete.png|200px|thumb|right|Не удаляем &amp;lt;tex&amp;gt; BS &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Путь проходящий через ребро &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt; будет длиннее, чем через соседей точки &amp;lt;tex&amp;gt; B &amp;lt;/tex&amp;gt;, так как по неравенству треугольника &amp;lt;tex&amp;gt; AB + BD &amp;gt; AD &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
По доказанным леммам любое ребро кратчайшего пути содержится в графе. Таким образом, для нахождения кратчайшего пути осталось найти кратчайший путь в этом графе от начальной до конечной вершины.&lt;br /&gt;
&lt;br /&gt;
=== Построение visibility графа ===&lt;br /&gt;
==== Наивный алгоритм. &amp;lt;tex&amp;gt; O(n ^ 3) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
Для каждой пары вершин проверяем, можно ли добавить ребро между ними, то есть нет ли пересечений с полигонами. &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; пар вершин и &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; ребер, то есть &amp;lt;tex&amp;gt; O(n^3) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Lee’s Algorithm. &amp;lt;tex&amp;gt; O(n ^ 2 \log n) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
{|&lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zam.png|300px|thumb|left|Заметание плоскости вращающимся лучом]]&lt;br /&gt;
Однако можно это сделать за &amp;lt;tex&amp;gt; O(n ^ 2 \log  n) &amp;lt;/tex&amp;gt;. Идея алгоритма проста: для каждой вершины найдем видимые из нее вершины. Если научиться делать это за &amp;lt;tex&amp;gt; O(n \log  n) &amp;lt;/tex&amp;gt;, задача решена, так как всего точек &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для каждой вершины будем рассматривать только правую половину плоскости, так как ребра, которые должны идти в левую половину, будут исходить из вершин, для которых текущая вершина будет справа.&lt;br /&gt;
&lt;br /&gt;
Переформулируем задачу. Дано: точка &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и множество отрезков {{---}} ребер препятствий. &lt;br /&gt;
Найти: множество концов отрезков, видимых из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для решения этой задачи будем использовать заметающий луч с началом в точке &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Его статусом будут отрезки, которые его пересекают, упорядоченные по возрастанию расстояния от точки &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; до точки пересечения. Точками событий будут концы отрезков. &lt;br /&gt;
&lt;br /&gt;
Пустим луч из рассматриваемой вершины &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вертикально вверх и добавим в статус все отрезки, которые он пересекает, по увеличению расстояния до них. Теперь будем рассматривать точки &amp;lt;tex&amp;gt; w \in V &amp;lt;/tex&amp;gt; в порядке сортировки по углу между &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и вертикальной полуосью &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt;. При таком обходе для проверки видимости вершины достаточно проверить пересечение с ближайшим к &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; отрезком, то есть первым в статусе(так как отрезки отсортированы по расстоянию до них). Действительно, если вершина &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; не видна, то отрезок &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; пересекает несколько отрезков, лежащих перед &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt;, а значит и ближайший. В противном случае все пересекаемые лучом отрезки лежат за вершиной &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; и пересечения отрезка &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; с ближайшим отрезком не будет. Вне зависимости от видимости вершины, необходимо изменить статус заметающего луча. Для этого необходимо удалить из статуса все отрезки, которые заканчиваются вершине &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; (лежат слева от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;) и добавить все отрезки, которые в ней начинаются (лежат справа от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Псевдокод =====&lt;br /&gt;
 graph buildVisibilityGraph(Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
    //все вершины препятствий, а также начальная и конечная вершины&lt;br /&gt;
    vertices = getVertices(segments) &amp;lt;tex&amp;gt; \cup\ \{S, T\} &amp;lt;/tex&amp;gt;     &lt;br /&gt;
    //изначально в графе только вершины&lt;br /&gt;
    graph = visibilityGraph(vertices)                  &lt;br /&gt;
    '''for''' Vertex &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; '''in''' vertices&lt;br /&gt;
       //добавляем в граф все видимые из нее вершины&lt;br /&gt;
       '''for''' Vertex &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt; '''in''' getVisibleVertices(&amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, segments)&lt;br /&gt;
          visibilityGraph.addEdge(&amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;)&lt;br /&gt;
    '''return''' visibilityGraph&lt;br /&gt;
Здесь функция getVisibleVertices(&amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;) возвращает все видимые из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вершины и выглядит так:&lt;br /&gt;
 Set&amp;lt;Vertex&amp;gt; getVisibleVertices(Vertex &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
    Set&amp;lt;Vertex&amp;gt; answer&lt;br /&gt;
 // Инициализируем статус&lt;br /&gt;
    '''for''' Segment &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; '''in''' segments&lt;br /&gt;
       '''if''' intersection &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; and ray from &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; to up exists&lt;br /&gt;
          status.add(&amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;)&lt;br /&gt;
 // Инициализируем множество вершин, которые нужно рассматривать&lt;br /&gt;
    '''for''' Point &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt; '''in''' segments&lt;br /&gt;
       '''if''' &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;.x &amp;lt;tex&amp;gt;\le&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;.x&lt;br /&gt;
          currentVertices.add(&amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;)&lt;br /&gt;
    sort(currentVertices) by angle&lt;br /&gt;
 // Для каждой вершины проверяем, видима ли она и обновляем статус&lt;br /&gt;
    '''for''' Point &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt; '''in''' currentVertices&lt;br /&gt;
       '''if''' intersection &amp;lt;tex&amp;gt;vw&amp;lt;/tex&amp;gt; and status.closest not exists&lt;br /&gt;
          answer.add(&amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;)&lt;br /&gt;
       delete from status all segments ending in &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;&lt;br /&gt;
          add in status all segments beginning in &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;&lt;br /&gt;
    '''return''' answer&lt;br /&gt;
В качестве статуса нужно использовать структуру данных, позволяющую добавлять и удалять из нее отрезки за &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; и извлекать минимум за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt;. В этом случае достигается асимптотика &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;, так как для каждой из &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; точек выполняется сортировка за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, обновление статуса (суммарно &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, так как каждый отрезок добавляется и удаляется из статуса не более одного раза) и запросы ближайшего отрезка (&amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; на точку, то есть &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;). &lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zamrefr1.png|250px|thumb|right|Обновление статуса заметающего луча: добавляем ребра &amp;lt;tex&amp;gt; w_1 w_5 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; w_1 w_2 &amp;lt;/tex&amp;gt; в статус]]&lt;br /&gt;
[[Файл:Zamrefr2.png|250px|thumb|right|Добавляем ребра &amp;lt;tex&amp;gt; w_3 w_2 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; w_3 w_4 &amp;lt;/tex&amp;gt; в статус]]&lt;br /&gt;
[[Файл:Zamrefr3.png|250px|thumb|right|Удаляем ребра &amp;lt;tex&amp;gt; w_3 w_2 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; w_1 w_2 &amp;lt;/tex&amp;gt; из статуса]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Overmars and Welzl’s Algorithm &amp;lt;tex&amp;gt; O(n ^ 2) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
[http://igitur-archive.library.uu.nl/math/2006-1214-201604/overmars_88_new_methods.pdf visibility graph при помощи rotation tree]&lt;br /&gt;
&lt;br /&gt;
C помощью [http://bit.ly/1eEqTzk rotation tree] можно достичь асимптотики &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Motion planning ==&lt;br /&gt;
[[Файл:mink.png|200px|thumb|left|Изменяем препятствия]]&lt;br /&gt;
[[Файл:mink2.png|400px|thumb|right|Ищем путь для точки]]&lt;br /&gt;
Рассмотрим задачу нахождения кратчайшего пути, когда движимый объект {{---}} это выпуклый полигон. Например, робот, которого надо доставить из начальной в конечную точку.&lt;br /&gt;
&lt;br /&gt;
Если полигон вращать нельзя, задачу сводится к движению точки так: выбирается точка на полигоне, которая принимается за начало координат. В такой системе координат для каждого препятствия считается [[Сумма Минковского (определение, вычисление)|сумма Минковского]] с полигоном. Получаются бОльшие препятствия, но теперь достаточно двигать выбранную точку, что было описано выше.&lt;br /&gt;
&lt;br /&gt;
Если полигон можно вращать, задача нахождения ''кратчайшего'' пути становится достаточно ресурсоёмка, поэтому обычно рассматривают задачу нахождения какого-нибудь пути между конечными точками.&lt;br /&gt;
&lt;br /&gt;
Первый шаг решения этой задачи совпадает с предыдущим случаем: выберем точку и построим [[Сумма Минковского (определение, вычисление)|сумму Минковского]] препятствий с полигоном. Рассмотрим малый угол &amp;lt;tex&amp;gt; \epsilon &amp;lt;/tex&amp;gt;. Представим, что поворот полигона на этот угол {{---}} это движение вверх-вниз между слоями, на каждом из которых посчитана сумма Минковского с полигоном, повернутым на этот угол.&lt;br /&gt;
&lt;br /&gt;
На каждом слое построим трапецоидную карту и граф, как описано в [[Visibility graph и motion planning#Нахождение пути между точками с препятствиями|начале]]. Если [[Пересечение многоугольников (PSLG overlaying)|пересечь]] соседние слои и добавить между их графами ребра, получится один большой граф, в котором ищется кратчайший путь.&lt;br /&gt;
&lt;br /&gt;
При таком подходе может возникнуть ошибка при пересечении слоев: на каждом слое состояния будут допустимые, а осуществить поворот физически будет невозможно. Обычно, эту проблему решают двумя способами: измельчением угла поворота и изначальным сглаживанием углов полигона. Первый способ повышает не только точность решения, но и вычислительную сложность задачи. Второй подход практически исключает возможность нахождения пути, когда его нет, но повышает вероятность &amp;quot;ненахождения&amp;quot; пути, когда он есть.&lt;br /&gt;
&lt;br /&gt;
== Источники ==&lt;br /&gt;
* 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&lt;br /&gt;
* [http://www.academia.edu/2845047/3D_Visibility_Graph статья] про visibility graphs на academia.edu&lt;br /&gt;
* [http://habrahabr.ru/post/199256/ Хабр]&lt;br /&gt;
[[Категория: Вычислительная геометрия]]&lt;br /&gt;
&lt;br /&gt;
== Ссылки ==&lt;br /&gt;
* Моя [https://github.com/Igorjan94/cg/blob/master/include/cg/algorithms/visibilityGraph.h реализация] алгоритма за &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;. Далеко от идеального, но работает&lt;/div&gt;</summary>
		<author><name>Igorjan94</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44843</id>
		<title>Visibility graph и motion planning</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44843"/>
				<updated>2015-02-10T21:47:29Z</updated>
		
		<summary type="html">&lt;p&gt;Igorjan94: /* Псевдокод */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Нахождение любого пути между точками с препятствиями ==&lt;br /&gt;
{|align=&amp;quot;right&amp;quot;&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
|[[Файл:trap.png|200px|thumb|right|Путь с препятствиями через трапецоидную карту]]&lt;br /&gt;
|[[Файл:notShort.png|300px|thumb|right|Такой путь не самый короткий]]&lt;br /&gt;
|}&lt;br /&gt;
Для начала рассмотрим движение материальной точки. Случай, когда размером и формой движимого объекта пренебречь нельзя, будет рассмотрен [[Visibility graph и motion planning#Motion planning|позднее]]. &lt;br /&gt;
&lt;br /&gt;
Эту задачу можно решить с помощью [[Трапецоидная карта | трапецоидной карты]]. По ней строится граф, ребра которого соединяют центры трапедоидов, а также начальную и конечную вершины с серединами вертикальных сторон трапецоидов. В таком графе ищется путь между начальной и конечной вершинами.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм работает за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; и за линейное количество памяти и хорошо подходит для нахождения какого-нибудь пути между парой данных вершин. Но если нужно найти кратчайший путь, этот алгоритм не подходит, хоть и работает быстро. Однако, решения нахождения кратчайшего пути в лучшем случае работают за &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; времени и памяти (здесь и далее &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество всех вершин).&lt;br /&gt;
&lt;br /&gt;
== Нахождение кратчайшего пути между точками с препятствиями ==&lt;br /&gt;
=== Visibility graph ===&lt;br /&gt;
Рассмотрим точное решение нахождения кратчайшего пути на плоскости между двумя точками с полигональными препятствиями с помощью построения графа видимости. После его построения, как и в случае с трапецоидной картой, кратчайший путь ищется любым стандартным алгоритмом поиска (например, алгоритмом [[Алгоритм Дейкстры|Дейкстры]] или [[Алгоритм A*|A*]]).&lt;br /&gt;
&lt;br /&gt;
Для простоты рассуждений начальную и конечную вершины будем считать вершинами полигонов.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|about=О кратчайшем пути&lt;br /&gt;
|statement=&lt;br /&gt;
Любой кратчайший путь между двумя вершинами с полигональными препятствиями представляет собой ломаную, вершины которой {{---}} вершины полигонов.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:short.png|150px|thumb|right|Short cut]]&lt;br /&gt;
Пусть кратчайший путь {{---}} не ломаная. В таком случае, на пути существует такая точка &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, которая не принадлежит ни одному прямому отрезку. Это означает, что существует &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестность точки &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, в которую не попадает ни одно препятствие (случай, когда точка попала на ребро рассматривается аналогично). В таком случае, подпуть, который находится внутри &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности, по неравенству треугольника может быть сокращён по хорде, соединяющий точки пересечения границы &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности с путем. Раз часть пути может быть уменьшена, значит и весь путь может быть уменьшен, а значит исходное предположение некорректно.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
Говорят, что вершина &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; ''видна'' (англ. mutually visible) из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;, если отрезок &amp;lt;tex&amp;gt; uv &amp;lt;/tex&amp;gt; не пересекает ни одного препятствия.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
''Граф видимости'' (англ. visibility graph) {{---}} граф, вершины которого {{---}} вершины полигонов. Между вершинами &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; существует ребро, если из &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; видна &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
В худшем случае в таком графе может быть &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; ребер. Однако по некоторым ребрам кратчайший путь точно не пройдет, и такие ребра из графа можно удалить.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
[[Файл:edgeToDelete.png|150px|thumb|right|Удаляем &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Если существуют вершины &amp;lt;tex&amp;gt; A, B, C &amp;lt;/tex&amp;gt; одного препятствия и вершина &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; такая, что поворот &amp;lt;tex&amp;gt; DBA &amp;lt;/tex&amp;gt; не совпадает с поворотом &amp;lt;tex&amp;gt; DBC &amp;lt;/tex&amp;gt;, то ребро &amp;lt;tex&amp;gt; DB &amp;lt;/tex&amp;gt; не принадлежит кратчайшему пути и его можно удалить из графа. (См. поясняющую картинку справа)&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:edgeNotToDelete.png|200px|thumb|right|Не удаляем &amp;lt;tex&amp;gt; BS &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Путь проходящий через ребро &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt; будет длиннее, чем через соседей точки &amp;lt;tex&amp;gt; B &amp;lt;/tex&amp;gt;, так как по неравенству треугольника &amp;lt;tex&amp;gt; AB + BD &amp;gt; AD &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
По доказанным леммам любое ребро кратчайшего пути содержится в графе. Таким образом, для нахождения кратчайшего пути осталось найти кратчайший путь в этом графе от начальной до конечной вершины.&lt;br /&gt;
&lt;br /&gt;
=== Построение visibility графа ===&lt;br /&gt;
==== Наивный алгоритм. &amp;lt;tex&amp;gt; O(n ^ 3) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
Для каждой пары вершин проверяем, можно ли добавить ребро между ними, то есть нет ли пересечений с полигонами. &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; пар вершин и &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; ребер, то есть &amp;lt;tex&amp;gt; O(n^3) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Lee’s Algorithm. &amp;lt;tex&amp;gt; O(n ^ 2 \log n) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
{|&lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zam.png|300px|thumb|left|Заметание плоскости вращающимся лучом]]&lt;br /&gt;
Однако можно это сделать за &amp;lt;tex&amp;gt; O(n ^ 2 \log  n) &amp;lt;/tex&amp;gt;. Идея алгоритма проста: для каждой вершины найдем видимые из нее вершины. Если научиться делать это за &amp;lt;tex&amp;gt; O(n \log  n) &amp;lt;/tex&amp;gt;, задача решена, так как всего точек &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для каждой вершины будем рассматривать только правую половину плоскости, так как ребра, которые должны идти в левую половину, будут исходить из вершин, для которых текущая вершина будет справа.&lt;br /&gt;
&lt;br /&gt;
Переформулируем задачу. Дано: точка &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и множество отрезков {{---}} ребер препятствий. &lt;br /&gt;
Найти: множество концов отрезков, видимых из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для решения этой задачи будем использовать заметающий луч с началом в точке &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Его статусом будут отрезки, которые его пересекают, упорядоченные по возрастанию расстояния от точки &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; до точки пересечения. Точками событий будут концы отрезков. &lt;br /&gt;
&lt;br /&gt;
Пустим луч из рассматриваемой вершины &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вертикально вверх и добавим в статус все отрезки, которые он пересекает, по увеличению расстояния до них. Теперь будем рассматривать точки &amp;lt;tex&amp;gt; w \in V &amp;lt;/tex&amp;gt; в порядке сортировки по углу между &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и вертикальной полуосью &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt;. При таком обходе для проверки видимости вершины достаточно проверить пересечение с ближайшим к &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; отрезком, то есть первым в статусе(так как отрезки отсортированы по расстоянию до них). Действительно, если вершина &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; не видна, то отрезок &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; пересекает несколько отрезков, лежащих перед &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt;, а значит и ближайший. В противном случае все пересекаемые лучом отрезки лежат за вершиной &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; и пересечения отрезка &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; с ближайшим отрезком не будет. Вне зависимости от видимости вершины, необходимо изменить статус заметающего луча. Для этого необходимо удалить из статуса все отрезки, которые заканчиваются вершине &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; (лежат слева от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;) и добавить все отрезки, которые в ней начинаются (лежат справа от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Псевдокод =====&lt;br /&gt;
 graph buildVisibilityGraph(Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
    //все вершины препятствий, а также начальная и конечная вершины&lt;br /&gt;
    vertices = getVertices(segments) &amp;lt;tex&amp;gt; \cup\ \{S, T\} &amp;lt;/tex&amp;gt;     &lt;br /&gt;
    //изначально в графе только вершины&lt;br /&gt;
    graph = visibilityGraph(vertices)                  &lt;br /&gt;
    '''for''' Vertex &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; '''in''' vertices&lt;br /&gt;
       //добавляем в граф все видимые из нее вершины&lt;br /&gt;
       '''for''' Vertex &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt; '''in''' getVisibleVertices(&amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, segments)&lt;br /&gt;
          visibilityGraph.addEdge(&amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;)&lt;br /&gt;
    '''return''' visibilityGraph&lt;br /&gt;
Здесь функция getVisibleVertices(&amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;) возвращает все видимые из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вершины и выглядит так:&lt;br /&gt;
 Set&amp;lt;Vertex&amp;gt; getVisibleVertices(Vertex &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
    Set&amp;lt;Vertex&amp;gt; answer&lt;br /&gt;
 // Инициализируем статус&lt;br /&gt;
    '''for''' Segment &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; '''in''' segments&lt;br /&gt;
       '''if''' intersection &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; and ray from &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; to up exists&lt;br /&gt;
          status.add(&amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;)&lt;br /&gt;
 // Инициализируем множество вершин, которые нужно рассматривать&lt;br /&gt;
    '''for''' Point &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt; '''in''' segments&lt;br /&gt;
       '''if''' &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;.x &amp;gt;= &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;.x&lt;br /&gt;
          currentVertices.add(&amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;)&lt;br /&gt;
    sort(currentVertices) by angle&lt;br /&gt;
 // Для каждой вершины проверяем, видима ли она и обновляем статус&lt;br /&gt;
    '''for''' Point &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt; '''in''' currentVertices&lt;br /&gt;
       '''if''' intersection &amp;lt;tex&amp;gt;vw&amp;lt;/tex&amp;gt; and status.closest not exists&lt;br /&gt;
          answer.add(&amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;)&lt;br /&gt;
       delete from status all segments ending in &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;&lt;br /&gt;
          add in status all segments beginning in &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;&lt;br /&gt;
       '''return''' answer&lt;br /&gt;
В качестве статуса нужно использовать структуру данных, позволяющую добавлять и удалять из нее отрезки за &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; и извлекать минимум за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt;. В этом случае достигается асимптотика &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;, так как для каждой из &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; точек выполняется сортировка за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, обновление статуса (суммарно &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, так как каждый отрезок добавляется и удаляется из статуса не более одного раза) и запросы ближайшего отрезка (&amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; на точку, то есть &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;). &lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zamrefr1.png|250px|thumb|right|Обновление статуса заметающего луча: добавляем ребра &amp;lt;tex&amp;gt; w_1 w_5 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; w_1 w_2 &amp;lt;/tex&amp;gt; в статус]]&lt;br /&gt;
[[Файл:Zamrefr2.png|250px|thumb|right|Добавляем ребра &amp;lt;tex&amp;gt; w_3 w_2 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; w_3 w_4 &amp;lt;/tex&amp;gt; в статус]]&lt;br /&gt;
[[Файл:Zamrefr3.png|250px|thumb|right|Удаляем ребра &amp;lt;tex&amp;gt; w_3 w_2 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; w_1 w_2 &amp;lt;/tex&amp;gt; из статуса]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Overmars and Welzl’s Algorithm &amp;lt;tex&amp;gt; O(n ^ 2) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
[http://igitur-archive.library.uu.nl/math/2006-1214-201604/overmars_88_new_methods.pdf visibility graph при помощи rotation tree]&lt;br /&gt;
&lt;br /&gt;
C помощью [http://bit.ly/1eEqTzk rotation tree] можно достичь асимптотики &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Motion planning ==&lt;br /&gt;
[[Файл:mink.png|200px|thumb|left|Изменяем препятствия]]&lt;br /&gt;
[[Файл:mink2.png|400px|thumb|right|Ищем путь для точки]]&lt;br /&gt;
Рассмотрим задачу нахождения кратчайшего пути, когда движимый объект {{---}} это выпуклый полигон. Например, робот, которого надо доставить из начальной в конечную точку.&lt;br /&gt;
&lt;br /&gt;
Если полигон вращать нельзя, задачу сводится к движению точки так: выбирается точка на полигоне, которая принимается за начало координат. В такой системе координат для каждого препятствия считается [[Сумма Минковского (определение, вычисление)|сумма Минковского]] с полигоном. Получаются бОльшие препятствия, но теперь достаточно двигать выбранную точку, что было описано выше.&lt;br /&gt;
&lt;br /&gt;
Если полигон можно вращать, задача нахождения ''кратчайшего'' пути становится достаточно ресурсоёмка, поэтому обычно рассматривают задачу нахождения какого-нибудь пути между конечными точками.&lt;br /&gt;
&lt;br /&gt;
Первый шаг решения этой задачи совпадает с предыдущим случаем: выберем точку и построим [[Сумма Минковского (определение, вычисление)|сумму Минковского]] препятствий с полигоном. Рассмотрим малый угол &amp;lt;tex&amp;gt; \epsilon &amp;lt;/tex&amp;gt;. Представим, что поворот полигона на этот угол {{---}} это движение вверх-вниз между слоями, на каждом из которых посчитана сумма Минковского с полигоном, повернутым на этот угол.&lt;br /&gt;
&lt;br /&gt;
На каждом слое построим трапецоидную карту и граф, как описано в [[Visibility graph и motion planning#Нахождение пути между точками с препятствиями|начале]]. Если [[Пересечение многоугольников (PSLG overlaying)|пересечь]] соседние слои и добавить между их графами ребра, получится один большой граф, в котором ищется кратчайший путь.&lt;br /&gt;
&lt;br /&gt;
При таком подходе может возникнуть ошибка при пересечении слоев: на каждом слое состояния будут допустимые, а осуществить поворот физически будет невозможно. Обычно, эту проблему решают двумя способами: измельчением угла поворота и изначальным сглаживанием углов полигона. Первый способ повышает не только точность решения, но и вычислительную сложность задачи. Второй подход практически исключает возможность нахождения пути, когда его нет, но повышает вероятность &amp;quot;ненахождения&amp;quot; пути, когда он есть.&lt;br /&gt;
&lt;br /&gt;
== Источники ==&lt;br /&gt;
* 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&lt;br /&gt;
* [http://www.academia.edu/2845047/3D_Visibility_Graph статья] про visibility graphs на academia.edu&lt;br /&gt;
* [http://habrahabr.ru/post/199256/ Хабр]&lt;br /&gt;
[[Категория: Вычислительная геометрия]]&lt;br /&gt;
&lt;br /&gt;
== Ссылки ==&lt;br /&gt;
* Моя [https://github.com/Igorjan94/cg/blob/master/include/cg/algorithms/visibilityGraph.h реализация] алгоритма за &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;. Далеко от идеального, но работает&lt;/div&gt;</summary>
		<author><name>Igorjan94</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44842</id>
		<title>Visibility graph и motion planning</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44842"/>
				<updated>2015-02-10T20:55:37Z</updated>
		
		<summary type="html">&lt;p&gt;Igorjan94: картинки, на место!&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Нахождение любого пути между точками с препятствиями ==&lt;br /&gt;
{|align=&amp;quot;right&amp;quot;&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
|[[Файл:trap.png|200px|thumb|right|Путь с препятствиями через трапецоидную карту]]&lt;br /&gt;
|[[Файл:notShort.png|300px|thumb|right|Такой путь не самый короткий]]&lt;br /&gt;
|}&lt;br /&gt;
Для начала рассмотрим движение материальной точки. Случай, когда размером и формой движимого объекта пренебречь нельзя, будет рассмотрен [[Visibility graph и motion planning#Motion planning|позднее]]. &lt;br /&gt;
&lt;br /&gt;
Эту задачу можно решить с помощью [[Трапецоидная карта | трапецоидной карты]]. По ней строится граф, ребра которого соединяют центры трапедоидов, а также начальную и конечную вершины с серединами вертикальных сторон трапецоидов. В таком графе ищется путь между начальной и конечной вершинами.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм работает за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; и за линейное количество памяти и хорошо подходит для нахождения какого-нибудь пути между парой данных вершин. Но если нужно найти кратчайший путь, этот алгоритм не подходит, хоть и работает быстро. Однако, решения нахождения кратчайшего пути в лучшем случае работают за &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; времени и памяти (здесь и далее &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество всех вершин).&lt;br /&gt;
&lt;br /&gt;
== Нахождение кратчайшего пути между точками с препятствиями ==&lt;br /&gt;
=== Visibility graph ===&lt;br /&gt;
Рассмотрим точное решение нахождения кратчайшего пути на плоскости между двумя точками с полигональными препятствиями с помощью построения графа видимости. После его построения, как и в случае с трапецоидной картой, кратчайший путь ищется любым стандартным алгоритмом поиска (например, алгоритмом [[Алгоритм Дейкстры|Дейкстры]] или [[Алгоритм A*|A*]]).&lt;br /&gt;
&lt;br /&gt;
Для простоты рассуждений начальную и конечную вершины будем считать вершинами полигонов.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|about=О кратчайшем пути&lt;br /&gt;
|statement=&lt;br /&gt;
Любой кратчайший путь между двумя вершинами с полигональными препятствиями представляет собой ломаную, вершины которой {{---}} вершины полигонов.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:short.png|150px|thumb|right|Short cut]]&lt;br /&gt;
Пусть кратчайший путь {{---}} не ломаная. В таком случае, на пути существует такая точка &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, которая не принадлежит ни одному прямому отрезку. Это означает, что существует &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестность точки &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, в которую не попадает ни одно препятствие (случай, когда точка попала на ребро рассматривается аналогично). В таком случае, подпуть, который находится внутри &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности, по неравенству треугольника может быть сокращён по хорде, соединяющий точки пересечения границы &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности с путем. Раз часть пути может быть уменьшена, значит и весь путь может быть уменьшен, а значит исходное предположение некорректно.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
Говорят, что вершина &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; ''видна'' (англ. mutually visible) из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;, если отрезок &amp;lt;tex&amp;gt; uv &amp;lt;/tex&amp;gt; не пересекает ни одного препятствия.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
''Граф видимости'' (англ. visibility graph) {{---}} граф, вершины которого {{---}} вершины полигонов. Между вершинами &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; существует ребро, если из &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; видна &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
В худшем случае в таком графе может быть &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; ребер. Однако по некоторым ребрам кратчайший путь точно не пройдет, и такие ребра из графа можно удалить.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
[[Файл:edgeToDelete.png|150px|thumb|right|Удаляем &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Если существуют вершины &amp;lt;tex&amp;gt; A, B, C &amp;lt;/tex&amp;gt; одного препятствия и вершина &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; такая, что поворот &amp;lt;tex&amp;gt; DBA &amp;lt;/tex&amp;gt; не совпадает с поворотом &amp;lt;tex&amp;gt; DBC &amp;lt;/tex&amp;gt;, то ребро &amp;lt;tex&amp;gt; DB &amp;lt;/tex&amp;gt; не принадлежит кратчайшему пути и его можно удалить из графа. (См. поясняющую картинку справа)&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:edgeNotToDelete.png|200px|thumb|right|Не удаляем &amp;lt;tex&amp;gt; BS &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Путь проходящий через ребро &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt; будет длиннее, чем через соседей точки &amp;lt;tex&amp;gt; B &amp;lt;/tex&amp;gt;, так как по неравенству треугольника &amp;lt;tex&amp;gt; AB + BD &amp;gt; AD &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
По доказанным леммам любое ребро кратчайшего пути содержится в графе. Таким образом, для нахождения кратчайшего пути осталось найти кратчайший путь в этом графе от начальной до конечной вершины.&lt;br /&gt;
&lt;br /&gt;
=== Построение visibility графа ===&lt;br /&gt;
==== Наивный алгоритм. &amp;lt;tex&amp;gt; O(n ^ 3) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
Для каждой пары вершин проверяем, можно ли добавить ребро между ними, то есть нет ли пересечений с полигонами. &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; пар вершин и &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; ребер, то есть &amp;lt;tex&amp;gt; O(n^3) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Lee’s Algorithm. &amp;lt;tex&amp;gt; O(n ^ 2 \log n) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
{|&lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zam.png|300px|thumb|left|Заметание плоскости вращающимся лучом]]&lt;br /&gt;
Однако можно это сделать за &amp;lt;tex&amp;gt; O(n ^ 2 \log  n) &amp;lt;/tex&amp;gt;. Идея алгоритма проста: для каждой вершины найдем видимые из нее вершины. Если научиться делать это за &amp;lt;tex&amp;gt; O(n \log  n) &amp;lt;/tex&amp;gt;, задача решена, так как всего точек &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для каждой вершины будем рассматривать только правую половину плоскости, так как ребра, которые должны идти в левую половину, будут исходить из вершин, для которых текущая вершина будет справа.&lt;br /&gt;
&lt;br /&gt;
Переформулируем задачу. Дано: точка &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и множество отрезков {{---}} ребер препятствий. &lt;br /&gt;
Найти: множество концов отрезков, видимых из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для решения этой задачи будем использовать заметающий луч с началом в точке &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Его статусом будут отрезки, которые его пересекают, упорядоченные по возрастанию расстояния от точки &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; до точки пересечения. Точками событий будут концы отрезков. &lt;br /&gt;
&lt;br /&gt;
Пустим луч из рассматриваемой вершины &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вертикально вверх и добавим в статус все отрезки, которые он пересекает, по увеличению расстояния до них. Теперь будем рассматривать точки &amp;lt;tex&amp;gt; w \in V &amp;lt;/tex&amp;gt; в порядке сортировки по углу между &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и вертикальной полуосью &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt;. При таком обходе для проверки видимости вершины достаточно проверить пересечение с ближайшим к &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; отрезком, то есть первым в статусе(так как отрезки отсортированы по расстоянию до них). Действительно, если вершина &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; не видна, то отрезок &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; пересекает несколько отрезков, лежащих перед &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt;, а значит и ближайший. В противном случае все пересекаемые лучом отрезки лежат за вершиной &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; и пересечения отрезка &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; с ближайшим отрезком не будет. Вне зависимости от видимости вершины, необходимо изменить статус заметающего луча. Для этого необходимо удалить из статуса все отрезки, которые заканчиваются вершине &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; (лежат слева от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;) и добавить все отрезки, которые в ней начинаются (лежат справа от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Псевдокод =====&lt;br /&gt;
 graph buildVisibilityGraph(Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
    vertices = getVertices(segments) &amp;lt;tex&amp;gt; \cup\ \{S, T\} &amp;lt;/tex&amp;gt;     //вершины препятствий, а также начальная и конечная вершины&lt;br /&gt;
    graph = visibilityGraph(vertices)                  //изначально в графе только вершины&lt;br /&gt;
    '''for''' Vertex &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; '''in''' vertices                           //для каждой вершины&lt;br /&gt;
       '''for''' Vertex &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt; '''in''' getVisibleVertices(&amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, segments) //добавляем в граф все видимые из нее вершины&lt;br /&gt;
          visibilityGraph.addEdge(&amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;)&lt;br /&gt;
    '''return''' visibilityGraph&lt;br /&gt;
Здесь функция getVisibleVertices(&amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;) возвращает все видимые из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вершины и выглядит так:&lt;br /&gt;
 Set&amp;lt;Vertex&amp;gt; getVisibleVertices(Vertex &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
    Set&amp;lt;Vertex&amp;gt; answer&lt;br /&gt;
 // Инициализируем статус&lt;br /&gt;
    '''for''' Segment &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; '''in''' segments&lt;br /&gt;
       '''if''' intersection &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; and ray from &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; to up exists&lt;br /&gt;
          status.add(&amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;)&lt;br /&gt;
 // Инициализируем множество вершин, которые нужно рассматривать&lt;br /&gt;
    '''for''' Point &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt; '''in''' segments&lt;br /&gt;
       '''if''' &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;.x &amp;gt;= &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;.x&lt;br /&gt;
          currentVertices.add(&amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;)&lt;br /&gt;
    sort(currentVertices) by angle&lt;br /&gt;
 // Для каждой вершины проверяем, видима ли она и обновляем статус&lt;br /&gt;
    '''for''' Point &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt; '''in''' currentVertices&lt;br /&gt;
       '''if''' intersection &amp;lt;tex&amp;gt;vw&amp;lt;/tex&amp;gt; and status.closest not exists&lt;br /&gt;
          answer.add(&amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;)&lt;br /&gt;
       delete from status all segments ending in &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;&lt;br /&gt;
          add in status all segments beginning in &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;&lt;br /&gt;
       '''return''' answer&lt;br /&gt;
В качестве статуса нужно использовать структуру данных, позволяющую добавлять и удалять из нее отрезки за &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; и извлекать минимум за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt;. В этом случае достигается асимптотика &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;, так как для каждой из &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; точек выполняется сортировка за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, обновление статуса (суммарно &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, так как каждый отрезок добавляется и удаляется из статуса не более одного раза) и запросы ближайшего отрезка (&amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; на точку, то есть &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;). &lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zamrefr1.png|250px|thumb|right|Обновление статуса заметающего луча: добавляем ребра &amp;lt;tex&amp;gt; w_1 w_5 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; w_1 w_2 &amp;lt;/tex&amp;gt; в статус]]&lt;br /&gt;
[[Файл:Zamrefr2.png|250px|thumb|right|Добавляем ребра &amp;lt;tex&amp;gt; w_3 w_2 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; w_3 w_4 &amp;lt;/tex&amp;gt; в статус]]&lt;br /&gt;
[[Файл:Zamrefr3.png|250px|thumb|right|Удаляем ребра &amp;lt;tex&amp;gt; w_3 w_2 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; w_1 w_2 &amp;lt;/tex&amp;gt; из статуса]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Overmars and Welzl’s Algorithm &amp;lt;tex&amp;gt; O(n ^ 2) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
[http://igitur-archive.library.uu.nl/math/2006-1214-201604/overmars_88_new_methods.pdf visibility graph при помощи rotation tree]&lt;br /&gt;
&lt;br /&gt;
C помощью [http://bit.ly/1eEqTzk rotation tree] можно достичь асимптотики &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Motion planning ==&lt;br /&gt;
[[Файл:mink.png|200px|thumb|left|Изменяем препятствия]]&lt;br /&gt;
[[Файл:mink2.png|400px|thumb|right|Ищем путь для точки]]&lt;br /&gt;
Рассмотрим задачу нахождения кратчайшего пути, когда движимый объект {{---}} это выпуклый полигон. Например, робот, которого надо доставить из начальной в конечную точку.&lt;br /&gt;
&lt;br /&gt;
Если полигон вращать нельзя, задачу сводится к движению точки так: выбирается точка на полигоне, которая принимается за начало координат. В такой системе координат для каждого препятствия считается [[Сумма Минковского (определение, вычисление)|сумма Минковского]] с полигоном. Получаются бОльшие препятствия, но теперь достаточно двигать выбранную точку, что было описано выше.&lt;br /&gt;
&lt;br /&gt;
Если полигон можно вращать, задача нахождения ''кратчайшего'' пути становится достаточно ресурсоёмка, поэтому обычно рассматривают задачу нахождения какого-нибудь пути между конечными точками.&lt;br /&gt;
&lt;br /&gt;
Первый шаг решения этой задачи совпадает с предыдущим случаем: выберем точку и построим [[Сумма Минковского (определение, вычисление)|сумму Минковского]] препятствий с полигоном. Рассмотрим малый угол &amp;lt;tex&amp;gt; \epsilon &amp;lt;/tex&amp;gt;. Представим, что поворот полигона на этот угол {{---}} это движение вверх-вниз между слоями, на каждом из которых посчитана сумма Минковского с полигоном, повернутым на этот угол.&lt;br /&gt;
&lt;br /&gt;
На каждом слое построим трапецоидную карту и граф, как описано в [[Visibility graph и motion planning#Нахождение пути между точками с препятствиями|начале]]. Если [[Пересечение многоугольников (PSLG overlaying)|пересечь]] соседние слои и добавить между их графами ребра, получится один большой граф, в котором ищется кратчайший путь.&lt;br /&gt;
&lt;br /&gt;
При таком подходе может возникнуть ошибка при пересечении слоев: на каждом слое состояния будут допустимые, а осуществить поворот физически будет невозможно. Обычно, эту проблему решают двумя способами: измельчением угла поворота и изначальным сглаживанием углов полигона. Первый способ повышает не только точность решения, но и вычислительную сложность задачи. Второй подход практически исключает возможность нахождения пути, когда его нет, но повышает вероятность &amp;quot;ненахождения&amp;quot; пути, когда он есть.&lt;br /&gt;
&lt;br /&gt;
== Источники ==&lt;br /&gt;
* 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&lt;br /&gt;
* [http://www.academia.edu/2845047/3D_Visibility_Graph статья] про visibility graphs на academia.edu&lt;br /&gt;
* [http://habrahabr.ru/post/199256/ Хабр]&lt;br /&gt;
[[Категория: Вычислительная геометрия]]&lt;br /&gt;
&lt;br /&gt;
== Ссылки ==&lt;br /&gt;
* Моя [https://github.com/Igorjan94/cg/blob/master/include/cg/algorithms/visibilityGraph.h реализация] алгоритма за &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;. Далеко от идеального, но работает&lt;/div&gt;</summary>
		<author><name>Igorjan94</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44841</id>
		<title>Visibility graph и motion planning</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44841"/>
				<updated>2015-02-10T20:53:58Z</updated>
		
		<summary type="html">&lt;p&gt;Igorjan94: /* tex */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Нахождение любого пути между точками с препятствиями ==&lt;br /&gt;
{|align=&amp;quot;right&amp;quot;&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
|[[Файл:trap.png|200px|thumb|right|Путь с препятствиями через трапецоидную карту]]&lt;br /&gt;
|[[Файл:notShort.png|300px|thumb|right|Такой путь не самый короткий]]&lt;br /&gt;
|}&lt;br /&gt;
Для начала рассмотрим движение материальной точки. Случай, когда размером и формой движимого объекта пренебречь нельзя, будет рассмотрен [[Visibility graph и motion planning#Motion planning|позднее]]. &lt;br /&gt;
&lt;br /&gt;
Эту задачу можно решить с помощью [[Трапецоидная карта | трапецоидной карты]]. По ней строится граф, ребра которого соединяют центры трапедоидов, а также начальную и конечную вершины с серединами вертикальных сторон трапецоидов. В таком графе ищется путь между начальной и конечной вершинами.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм работает за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; и за линейное количество памяти и хорошо подходит для нахождения какого-нибудь пути между парой данных вершин. Но если нужно найти кратчайший путь, этот алгоритм не подходит, хоть и работает быстро. Однако, решения нахождения кратчайшего пути в лучшем случае работают за &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; времени и памяти (здесь и далее &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество всех вершин).&lt;br /&gt;
&lt;br /&gt;
== Нахождение кратчайшего пути между точками с препятствиями ==&lt;br /&gt;
=== Visibility graph ===&lt;br /&gt;
Рассмотрим точное решение нахождения кратчайшего пути на плоскости между двумя точками с полигональными препятствиями с помощью построения графа видимости. После его построения, как и в случае с трапецоидной картой, кратчайший путь ищется любым стандартным алгоритмом поиска (например, алгоритмом [[Алгоритм Дейкстры|Дейкстры]] или [[Алгоритм A*|A*]]).&lt;br /&gt;
&lt;br /&gt;
Для простоты рассуждений начальную и конечную вершины будем считать вершинами полигонов.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|about=О кратчайшем пути&lt;br /&gt;
|statement=&lt;br /&gt;
Любой кратчайший путь между двумя вершинами с полигональными препятствиями представляет собой ломаную, вершины которой {{---}} вершины полигонов.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:short.png|150px|thumb|right|Short cut]]&lt;br /&gt;
Пусть кратчайший путь {{---}} не ломаная. В таком случае, на пути существует такая точка &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, которая не принадлежит ни одному прямому отрезку. Это означает, что существует &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестность точки &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, в которую не попадает ни одно препятствие (случай, когда точка попала на ребро рассматривается аналогично). В таком случае, подпуть, который находится внутри &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности, по неравенству треугольника может быть сокращён по хорде, соединяющий точки пересечения границы &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности с путем. Раз часть пути может быть уменьшена, значит и весь путь может быть уменьшен, а значит исходное предположение некорректно.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
Говорят, что вершина &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; ''видна'' (англ. mutually visible) из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;, если отрезок &amp;lt;tex&amp;gt; uv &amp;lt;/tex&amp;gt; не пересекает ни одного препятствия.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
''Граф видимости'' (англ. visibility graph) {{---}} граф, вершины которого {{---}} вершины полигонов. Между вершинами &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; существует ребро, если из &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; видна &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
В худшем случае в таком графе может быть &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; ребер. Однако по некоторым ребрам кратчайший путь точно не пройдет, и такие ребра из графа можно удалить.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
[[Файл:edgeToDelete.png|150px|thumb|right|Удаляем &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Если существуют вершины &amp;lt;tex&amp;gt; A, B, C &amp;lt;/tex&amp;gt; одного препятствия и вершина &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; такая, что поворот &amp;lt;tex&amp;gt; DBA &amp;lt;/tex&amp;gt; не совпадает с поворотом &amp;lt;tex&amp;gt; DBC &amp;lt;/tex&amp;gt;, то ребро &amp;lt;tex&amp;gt; DB &amp;lt;/tex&amp;gt; не принадлежит кратчайшему пути и его можно удалить из графа. (См. поясняющую картинку справа)&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:edgeNotToDelete.png|200px|thumb|right|Не удаляем &amp;lt;tex&amp;gt; BS &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Путь проходящий через ребро &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt; будет длиннее, чем через соседей точки &amp;lt;tex&amp;gt; B &amp;lt;/tex&amp;gt;, так как по неравенству треугольника &amp;lt;tex&amp;gt; AB + BD &amp;gt; AD &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
По доказанным леммам любое ребро кратчайшего пути содержится в графе. Таким образом, для нахождения кратчайшего пути осталось найти кратчайший путь в этом графе от начальной до конечной вершины.&lt;br /&gt;
&lt;br /&gt;
=== Построение visibility графа ===&lt;br /&gt;
==== Наивный алгоритм. &amp;lt;tex&amp;gt; O(n ^ 3) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
Для каждой пары вершин проверяем, можно ли добавить ребро между ними, то есть нет ли пересечений с полигонами. &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; пар вершин и &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; ребер, то есть &amp;lt;tex&amp;gt; O(n^3) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Lee’s Algorithm. &amp;lt;tex&amp;gt; O(n ^ 2 \log n) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
{|&lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zam.png|300px|thumb|left|Заметание плоскости вращающимся лучом]]&lt;br /&gt;
Однако можно это сделать за &amp;lt;tex&amp;gt; O(n ^ 2 \log  n) &amp;lt;/tex&amp;gt;. Идея алгоритма проста: для каждой вершины найдем видимые из нее вершины. Если научиться делать это за &amp;lt;tex&amp;gt; O(n \log  n) &amp;lt;/tex&amp;gt;, задача решена, так как всего точек &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для каждой вершины будем рассматривать только правую половину плоскости, так как ребра, которые должны идти в левую половину, будут исходить из вершин, для которых текущая вершина будет справа.&lt;br /&gt;
&lt;br /&gt;
Переформулируем задачу. Дано: точка &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и множество отрезков {{---}} ребер препятствий. &lt;br /&gt;
Найти: множество концов отрезков, видимых из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для решения этой задачи будем использовать заметающий луч с началом в точке &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Его статусом будут отрезки, которые его пересекают, упорядоченные по возрастанию расстояния от точки &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; до точки пересечения. Точками событий будут концы отрезков. &lt;br /&gt;
&lt;br /&gt;
Пустим луч из рассматриваемой вершины &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вертикально вверх и добавим в статус все отрезки, которые он пересекает, по увеличению расстояния до них. Теперь будем рассматривать точки &amp;lt;tex&amp;gt; w \in V &amp;lt;/tex&amp;gt; в порядке сортировки по углу между &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и вертикальной полуосью &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt;. При таком обходе для проверки видимости вершины достаточно проверить пересечение с ближайшим к &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; отрезком, то есть первым в статусе(так как отрезки отсортированы по расстоянию до них). Действительно, если вершина &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; не видна, то отрезок &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; пересекает несколько отрезков, лежащих перед &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt;, а значит и ближайший. В противном случае все пересекаемые лучом отрезки лежат за вершиной &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; и пересечения отрезка &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; с ближайшим отрезком не будет. Вне зависимости от видимости вершины, необходимо изменить статус заметающего луча. Для этого необходимо удалить из статуса все отрезки, которые заканчиваются вершине &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; (лежат слева от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;) и добавить все отрезки, которые в ней начинаются (лежат справа от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Псевдокод =====&lt;br /&gt;
 graph buildVisibilityGraph(Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
    vertices = getVertices(segments) &amp;lt;tex&amp;gt; \cup\ \{S, T\} &amp;lt;/tex&amp;gt;           //все вершины препятствий, а также начальная и конечная вершины&lt;br /&gt;
    graph = visibilityGraph(vertices)                  //изначально в графе только вершины&lt;br /&gt;
    '''for''' Vertex &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; '''in''' vertices                           //для каждой вершины&lt;br /&gt;
       '''for''' Vertex &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt; '''in''' getVisibleVertices(&amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, segments) //добавляем в граф все видимые из нее вершины&lt;br /&gt;
          visibilityGraph.addEdge(&amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;)&lt;br /&gt;
    '''return''' visibilityGraph&lt;br /&gt;
Здесь функция getVisibleVertices(&amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;) возвращает все видимые из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вершины и выглядит так:&lt;br /&gt;
 Set&amp;lt;Vertex&amp;gt; getVisibleVertices(Vertex &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
    Set&amp;lt;Vertex&amp;gt; answer&lt;br /&gt;
 // Инициализируем статус&lt;br /&gt;
    '''for''' Segment &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; '''in''' segments&lt;br /&gt;
       '''if''' intersection &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; and ray from &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; to up exists&lt;br /&gt;
          status.add(&amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;)&lt;br /&gt;
 // Инициализируем множество вершин, которые нужно рассматривать&lt;br /&gt;
    '''for''' Point &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt; '''in''' segments&lt;br /&gt;
       '''if''' &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;.x &amp;gt;= &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;.x&lt;br /&gt;
          currentVertices.add(&amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;)&lt;br /&gt;
    sort(currentVertices) by angle&lt;br /&gt;
 // Для каждой вершины проверяем, видима ли она и обновляем статус&lt;br /&gt;
    '''for''' Point &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt; '''in''' currentVertices&lt;br /&gt;
       '''if''' intersection &amp;lt;tex&amp;gt;vw&amp;lt;/tex&amp;gt; and status.closest not exists&lt;br /&gt;
          answer.add(&amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;)&lt;br /&gt;
       delete from status all segments ending in &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;&lt;br /&gt;
          add in status all segments beginning in &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;&lt;br /&gt;
       '''return''' answer&lt;br /&gt;
В качестве статуса нужно использовать структуру данных, позволяющую добавлять и удалять из нее отрезки за &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; и извлекать минимум за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt;. В этом случае достигается асимптотика &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;, так как для каждой из &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; точек выполняется сортировка за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, обновление статуса (суммарно &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, так как каждый отрезок добавляется и удаляется из статуса не более одного раза) и запросы ближайшего отрезка (&amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; на точку, то есть &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;). &lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zamrefr1.png|250px|thumb|right|Обновление статуса заметающего луча: добавляем ребра &amp;lt;tex&amp;gt; w_1 w_5 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; w_1 w_2 &amp;lt;/tex&amp;gt; в статус]]&lt;br /&gt;
[[Файл:Zamrefr2.png|250px|thumb|right|Добавляем ребра &amp;lt;tex&amp;gt; w_3 w_2 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; w_3 w_4 &amp;lt;/tex&amp;gt; в статус]]&lt;br /&gt;
[[Файл:Zamrefr3.png|250px|thumb|right|Удаляем ребра &amp;lt;tex&amp;gt; w_3 w_2 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; w_1 w_2 &amp;lt;/tex&amp;gt; из статуса]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Overmars and Welzl’s Algorithm &amp;lt;tex&amp;gt; O(n ^ 2) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
[http://igitur-archive.library.uu.nl/math/2006-1214-201604/overmars_88_new_methods.pdf visibility graph при помощи rotation tree]&lt;br /&gt;
&lt;br /&gt;
C помощью [http://bit.ly/1eEqTzk rotation tree] можно достичь асимптотики &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Motion planning ==&lt;br /&gt;
[[Файл:mink.png|200px|thumb|left|Изменяем препятствия]]&lt;br /&gt;
[[Файл:mink2.png|400px|thumb|right|Ищем путь для точки]]&lt;br /&gt;
Рассмотрим задачу нахождения кратчайшего пути, когда движимый объект {{---}} это выпуклый полигон. Например, робот, которого надо доставить из начальной в конечную точку.&lt;br /&gt;
&lt;br /&gt;
Если полигон вращать нельзя, задачу сводится к движению точки так: выбирается точка на полигоне, которая принимается за начало координат. В такой системе координат для каждого препятствия считается [[Сумма Минковского (определение, вычисление)|сумма Минковского]] с полигоном. Получаются бОльшие препятствия, но теперь достаточно двигать выбранную точку, что было описано выше.&lt;br /&gt;
&lt;br /&gt;
Если полигон можно вращать, задача нахождения ''кратчайшего'' пути становится достаточно ресурсоёмка, поэтому обычно рассматривают задачу нахождения какого-нибудь пути между конечными точками.&lt;br /&gt;
&lt;br /&gt;
Первый шаг решения этой задачи совпадает с предыдущим случаем: выберем точку и построим [[Сумма Минковского (определение, вычисление)|сумму Минковского]] препятствий с полигоном. Рассмотрим малый угол &amp;lt;tex&amp;gt; \epsilon &amp;lt;/tex&amp;gt;. Представим, что поворот полигона на этот угол {{---}} это движение вверх-вниз между слоями, на каждом из которых посчитана сумма Минковского с полигоном, повернутым на этот угол.&lt;br /&gt;
&lt;br /&gt;
На каждом слое построим трапецоидную карту и граф, как описано в [[Visibility graph и motion planning#Нахождение пути между точками с препятствиями|начале]]. Если [[Пересечение многоугольников (PSLG overlaying)|пересечь]] соседние слои и добавить между их графами ребра, получится один большой граф, в котором ищется кратчайший путь.&lt;br /&gt;
&lt;br /&gt;
При таком подходе может возникнуть ошибка при пересечении слоев: на каждом слое состояния будут допустимые, а осуществить поворот физически будет невозможно. Обычно, эту проблему решают двумя способами: измельчением угла поворота и изначальным сглаживанием углов полигона. Первый способ повышает не только точность решения, но и вычислительную сложность задачи. Второй подход практически исключает возможность нахождения пути, когда его нет, но повышает вероятность &amp;quot;ненахождения&amp;quot; пути, когда он есть.&lt;br /&gt;
&lt;br /&gt;
== Источники ==&lt;br /&gt;
* 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&lt;br /&gt;
* [http://www.academia.edu/2845047/3D_Visibility_Graph статья] про visibility graphs на academia.edu&lt;br /&gt;
* [http://habrahabr.ru/post/199256/ Хабр]&lt;br /&gt;
[[Категория: Вычислительная геометрия]]&lt;br /&gt;
&lt;br /&gt;
== Ссылки ==&lt;br /&gt;
* Моя [https://github.com/Igorjan94/cg/blob/master/include/cg/algorithms/visibilityGraph.h реализация] алгоритма за &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;. Далеко от идеального, но работает&lt;/div&gt;</summary>
		<author><name>Igorjan94</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44840</id>
		<title>Visibility graph и motion planning</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44840"/>
				<updated>2015-02-10T20:48:45Z</updated>
		
		<summary type="html">&lt;p&gt;Igorjan94: /* Псевдокод */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Нахождение любого пути между точками с препятствиями ==&lt;br /&gt;
{|align=&amp;quot;right&amp;quot;&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
|[[Файл:trap.png|200px|thumb|right|Путь с препятствиями через трапецоидную карту]]&lt;br /&gt;
|[[Файл:notShort.png|300px|thumb|right|Такой путь не самый короткий]]&lt;br /&gt;
|}&lt;br /&gt;
Для начала рассмотрим движение материальной точки. Случай, когда размером и формой движимого объекта пренебречь нельзя, будет рассмотрен [[Visibility graph и motion planning#Motion planning|позднее]]. &lt;br /&gt;
&lt;br /&gt;
Эту задачу можно решить с помощью [[Трапецоидная карта | трапецоидной карты]]. По ней строится граф, ребра которого соединяют центры трапедоидов, а также начальную и конечную вершины с серединами вертикальных сторон трапецоидов. В таком графе ищется путь между начальной и конечной вершинами.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм работает за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; и за линейное количество памяти и хорошо подходит для нахождения какого-нибудь пути между парой данных вершин. Но если нужно найти кратчайший путь, этот алгоритм не подходит, хоть и работает быстро. Однако, решения нахождения кратчайшего пути в лучшем случае работают за &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; времени и памяти (здесь и далее &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество всех вершин).&lt;br /&gt;
&lt;br /&gt;
== Нахождение кратчайшего пути между точками с препятствиями ==&lt;br /&gt;
=== Visibility graph ===&lt;br /&gt;
Рассмотрим точное решение нахождения кратчайшего пути на плоскости между двумя точками с полигональными препятствиями с помощью построения графа видимости. После его построения, как и в случае с трапецоидной картой, кратчайший путь ищется любым стандартным алгоритмом поиска (например, алгоритмом [[Алгоритм Дейкстры|Дейкстры]] или [[Алгоритм A*|A*]]).&lt;br /&gt;
&lt;br /&gt;
Для простоты рассуждений начальную и конечную вершины будем считать вершинами полигонов.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|about=О кратчайшем пути&lt;br /&gt;
|statement=&lt;br /&gt;
Любой кратчайший путь между двумя вершинами с полигональными препятствиями представляет собой ломаную, вершины которой {{---}} вершины полигонов.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:short.png|150px|thumb|right|Short cut]]&lt;br /&gt;
Пусть кратчайший путь {{---}} не ломаная. В таком случае, на пути существует такая точка &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, которая не принадлежит ни одному прямому отрезку. Это означает, что существует &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестность точки &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, в которую не попадает ни одно препятствие (случай, когда точка попала на ребро рассматривается аналогично). В таком случае, подпуть, который находится внутри &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности, по неравенству треугольника может быть сокращён по хорде, соединяющий точки пересечения границы &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности с путем. Раз часть пути может быть уменьшена, значит и весь путь может быть уменьшен, а значит исходное предположение некорректно.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
Говорят, что вершина &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; ''видна'' (англ. mutually visible) из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;, если отрезок &amp;lt;tex&amp;gt; uv &amp;lt;/tex&amp;gt; не пересекает ни одного препятствия.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
''Граф видимости'' (англ. visibility graph) {{---}} граф, вершины которого {{---}} вершины полигонов. Между вершинами &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; существует ребро, если из &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; видна &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
В худшем случае в таком графе может быть &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; ребер. Однако по некоторым ребрам кратчайший путь точно не пройдет, и такие ребра из графа можно удалить.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
[[Файл:edgeToDelete.png|150px|thumb|right|Удаляем &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Если существуют вершины &amp;lt;tex&amp;gt; A, B, C &amp;lt;/tex&amp;gt; одного препятствия и вершина &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; такая, что поворот &amp;lt;tex&amp;gt; DBA &amp;lt;/tex&amp;gt; не совпадает с поворотом &amp;lt;tex&amp;gt; DBC &amp;lt;/tex&amp;gt;, то ребро &amp;lt;tex&amp;gt; DB &amp;lt;/tex&amp;gt; не принадлежит кратчайшему пути и его можно удалить из графа. (См. поясняющую картинку справа)&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:edgeNotToDelete.png|200px|thumb|right|Не удаляем &amp;lt;tex&amp;gt; BS &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Путь проходящий через ребро &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt; будет длиннее, чем через соседей точки &amp;lt;tex&amp;gt; B &amp;lt;/tex&amp;gt;, так как по неравенству треугольника &amp;lt;tex&amp;gt; AB + BD &amp;gt; AD &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
По доказанным леммам любое ребро кратчайшего пути содержится в графе. Таким образом, для нахождения кратчайшего пути осталось найти кратчайший путь в этом графе от начальной до конечной вершины.&lt;br /&gt;
&lt;br /&gt;
=== Построение visibility графа ===&lt;br /&gt;
==== Наивный алгоритм. &amp;lt;tex&amp;gt; O(n ^ 3) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
Для каждой пары вершин проверяем, можно ли добавить ребро между ними, то есть нет ли пересечений с полигонами. &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; пар вершин и &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; ребер, то есть &amp;lt;tex&amp;gt; O(n^3) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Lee’s Algorithm. &amp;lt;tex&amp;gt; O(n ^ 2 \log n) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
{|&lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zam.png|300px|thumb|left|Заметание плоскости вращающимся лучом]]&lt;br /&gt;
Однако можно это сделать за &amp;lt;tex&amp;gt; O(n ^ 2 \log  n) &amp;lt;/tex&amp;gt;. Идея алгоритма проста: для каждой вершины найдем видимые из нее вершины. Если научиться делать это за &amp;lt;tex&amp;gt; O(n \log  n) &amp;lt;/tex&amp;gt;, задача решена, так как всего точек &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для каждой вершины будем рассматривать только правую половину плоскости, так как ребра, которые должны идти в левую половину, будут исходить из вершин, для которых текущая вершина будет справа.&lt;br /&gt;
&lt;br /&gt;
Переформулируем задачу. Дано: точка &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и множество отрезков {{---}} ребер препятствий. &lt;br /&gt;
Найти: множество концов отрезков, видимых из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для решения этой задачи будем использовать заметающий луч с началом в точке &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Его статусом будут отрезки, которые его пересекают, упорядоченные по возрастанию расстояния от точки &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; до точки пересечения. Точками событий будут концы отрезков. &lt;br /&gt;
&lt;br /&gt;
Пустим луч из рассматриваемой вершины &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вертикально вверх и добавим в статус все отрезки, которые он пересекает, по увеличению расстояния до них. Теперь будем рассматривать точки &amp;lt;tex&amp;gt; w \in V &amp;lt;/tex&amp;gt; в порядке сортировки по углу между &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и вертикальной полуосью &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt;. При таком обходе для проверки видимости вершины достаточно проверить пересечение с ближайшим к &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; отрезком, то есть первым в статусе(так как отрезки отсортированы по расстоянию до них). Действительно, если вершина &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; не видна, то отрезок &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; пересекает несколько отрезков, лежащих перед &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt;, а значит и ближайший. В противном случае все пересекаемые лучом отрезки лежат за вершиной &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; и пересечения отрезка &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; с ближайшим отрезком не будет. Вне зависимости от видимости вершины, необходимо изменить статус заметающего луча. Для этого необходимо удалить из статуса все отрезки, которые заканчиваются вершине &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; (лежат слева от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;) и добавить все отрезки, которые в ней начинаются (лежат справа от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Псевдокод =====&lt;br /&gt;
 graph buildVisibilityGraph(Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
    vertices = getVertices(segments) &amp;lt;tex&amp;gt; \cup\ \{S, T\} &amp;lt;/tex&amp;gt;           //все вершины препятствий, а также начальная и конечная вершины&lt;br /&gt;
    graph = visibilityGraph(vertices)                  //изначально в графе только вершины&lt;br /&gt;
    '''for''' Vertex v '''in''' vertices                           //для каждой вершины&lt;br /&gt;
       '''for''' Vertex w '''in''' getVisibleVertices(v, segments) //добавляем в граф все видимые из нее вершины&lt;br /&gt;
          visibilityGraph.addEdge(v, w)&lt;br /&gt;
    '''return''' visibilityGraph&lt;br /&gt;
Здесь функция getVisibleVertices(&amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;) возвращает все видимые из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вершины и выглядит так:&lt;br /&gt;
 Set&amp;lt;Vertex&amp;gt; getVisibleVertices(Vertex v, Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
    Set&amp;lt;Vertex&amp;gt; answer&lt;br /&gt;
 // Инициализируем статус&lt;br /&gt;
    '''for''' Segment s '''in''' segments&lt;br /&gt;
       '''if''' intersection s and ray from v to up exists&lt;br /&gt;
          status.add(s)&lt;br /&gt;
 // Инициализируем множество вершин, которые нужно рассматривать&lt;br /&gt;
    '''for''' Point w '''in''' segments&lt;br /&gt;
       '''if''' w.x &amp;gt;= v.x&lt;br /&gt;
          currentVertices.add(w)&lt;br /&gt;
    sort(currentVertices) by angle&lt;br /&gt;
 // Для каждой вершины проверяем, видима ли она и обновляем статус&lt;br /&gt;
    '''for''' Point w '''in''' currentVertices&lt;br /&gt;
       '''if''' intersection vw and status.closest not exists&lt;br /&gt;
          answer.add(w)&lt;br /&gt;
       delete from status all segments ending in w&lt;br /&gt;
          add in status all segments beginning in w&lt;br /&gt;
       '''return''' answer&lt;br /&gt;
В качестве статуса нужно использовать структуру данных, позволяющую добавлять и удалять из нее отрезки за &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; и извлекать минимум за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt;. В этом случае достигается асимптотика &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;, так как для каждой из &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; точек выполняется сортировка за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, обновление статуса (суммарно &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, так как каждый отрезок добавляется и удаляется из статуса не более одного раза) и запросы ближайшего отрезка (&amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; на точку, то есть &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;). &lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zamrefr1.png|250px|thumb|right|Обновление статуса заметающего луча: добавляем ребра &amp;lt;tex&amp;gt; w_1 w_5 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; w_1 w_2 &amp;lt;/tex&amp;gt; в статус]]&lt;br /&gt;
[[Файл:Zamrefr2.png|250px|thumb|right|Добавляем ребра &amp;lt;tex&amp;gt; w_3 w_2 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; w_3 w_4 &amp;lt;/tex&amp;gt; в статус]]&lt;br /&gt;
[[Файл:Zamrefr3.png|250px|thumb|right|Удаляем ребра &amp;lt;tex&amp;gt; w_3 w_2 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; w_1 w_2 &amp;lt;/tex&amp;gt; из статуса]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Overmars and Welzl’s Algorithm &amp;lt;tex&amp;gt; O(n ^ 2) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
[http://igitur-archive.library.uu.nl/math/2006-1214-201604/overmars_88_new_methods.pdf visibility graph при помощи rotation tree]&lt;br /&gt;
&lt;br /&gt;
C помощью [http://bit.ly/1eEqTzk rotation tree] можно достичь асимптотики &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Motion planning ==&lt;br /&gt;
[[Файл:mink.png|200px|thumb|left|Изменяем препятствия]]&lt;br /&gt;
[[Файл:mink2.png|400px|thumb|right|Ищем путь для точки]]&lt;br /&gt;
Рассмотрим задачу нахождения кратчайшего пути, когда движимый объект {{---}} это выпуклый полигон. Например, робот, которого надо доставить из начальной в конечную точку.&lt;br /&gt;
&lt;br /&gt;
Если полигон вращать нельзя, задачу сводится к движению точки так: выбирается точка на полигоне, которая принимается за начало координат. В такой системе координат для каждого препятствия считается [[Сумма Минковского (определение, вычисление)|сумма Минковского]] с полигоном. Получаются бОльшие препятствия, но теперь достаточно двигать выбранную точку, что было описано выше.&lt;br /&gt;
&lt;br /&gt;
Если полигон можно вращать, задача нахождения ''кратчайшего'' пути становится достаточно ресурсоёмка, поэтому обычно рассматривают задачу нахождения какого-нибудь пути между конечными точками.&lt;br /&gt;
&lt;br /&gt;
Первый шаг решения этой задачи совпадает с предыдущим случаем: выберем точку и построим [[Сумма Минковского (определение, вычисление)|сумму Минковского]] препятствий с полигоном. Рассмотрим малый угол &amp;lt;tex&amp;gt; \epsilon &amp;lt;/tex&amp;gt;. Представим, что поворот полигона на этот угол {{---}} это движение вверх-вниз между слоями, на каждом из которых посчитана сумма Минковского с полигоном, повернутым на этот угол.&lt;br /&gt;
&lt;br /&gt;
На каждом слое построим трапецоидную карту и граф, как описано в [[Visibility graph и motion planning#Нахождение пути между точками с препятствиями|начале]]. Если [[Пересечение многоугольников (PSLG overlaying)|пересечь]] соседние слои и добавить между их графами ребра, получится один большой граф, в котором ищется кратчайший путь.&lt;br /&gt;
&lt;br /&gt;
При таком подходе может возникнуть ошибка при пересечении слоев: на каждом слое состояния будут допустимые, а осуществить поворот физически будет невозможно. Обычно, эту проблему решают двумя способами: измельчением угла поворота и изначальным сглаживанием углов полигона. Первый способ повышает не только точность решения, но и вычислительную сложность задачи. Второй подход практически исключает возможность нахождения пути, когда его нет, но повышает вероятность &amp;quot;ненахождения&amp;quot; пути, когда он есть.&lt;br /&gt;
&lt;br /&gt;
== Источники ==&lt;br /&gt;
* 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&lt;br /&gt;
* [http://www.academia.edu/2845047/3D_Visibility_Graph статья] про visibility graphs на academia.edu&lt;br /&gt;
* [http://habrahabr.ru/post/199256/ Хабр]&lt;br /&gt;
[[Категория: Вычислительная геометрия]]&lt;br /&gt;
&lt;br /&gt;
== Ссылки ==&lt;br /&gt;
* Моя [https://github.com/Igorjan94/cg/blob/master/include/cg/algorithms/visibilityGraph.h реализация] алгоритма за &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;. Далеко от идеального, но работает&lt;/div&gt;</summary>
		<author><name>Igorjan94</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44839</id>
		<title>Visibility graph и motion planning</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44839"/>
				<updated>2015-02-10T20:43:13Z</updated>
		
		<summary type="html">&lt;p&gt;Igorjan94: /* Псевдокод */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Нахождение любого пути между точками с препятствиями ==&lt;br /&gt;
{|align=&amp;quot;right&amp;quot;&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
|[[Файл:trap.png|200px|thumb|right|Путь с препятствиями через трапецоидную карту]]&lt;br /&gt;
|[[Файл:notShort.png|300px|thumb|right|Такой путь не самый короткий]]&lt;br /&gt;
|}&lt;br /&gt;
Для начала рассмотрим движение материальной точки. Случай, когда размером и формой движимого объекта пренебречь нельзя, будет рассмотрен [[Visibility graph и motion planning#Motion planning|позднее]]. &lt;br /&gt;
&lt;br /&gt;
Эту задачу можно решить с помощью [[Трапецоидная карта | трапецоидной карты]]. По ней строится граф, ребра которого соединяют центры трапедоидов, а также начальную и конечную вершины с серединами вертикальных сторон трапецоидов. В таком графе ищется путь между начальной и конечной вершинами.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм работает за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; и за линейное количество памяти и хорошо подходит для нахождения какого-нибудь пути между парой данных вершин. Но если нужно найти кратчайший путь, этот алгоритм не подходит, хоть и работает быстро. Однако, решения нахождения кратчайшего пути в лучшем случае работают за &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; времени и памяти (здесь и далее &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество всех вершин).&lt;br /&gt;
&lt;br /&gt;
== Нахождение кратчайшего пути между точками с препятствиями ==&lt;br /&gt;
=== Visibility graph ===&lt;br /&gt;
Рассмотрим точное решение нахождения кратчайшего пути на плоскости между двумя точками с полигональными препятствиями с помощью построения графа видимости. После его построения, как и в случае с трапецоидной картой, кратчайший путь ищется любым стандартным алгоритмом поиска (например, алгоритмом [[Алгоритм Дейкстры|Дейкстры]] или [[Алгоритм A*|A*]]).&lt;br /&gt;
&lt;br /&gt;
Для простоты рассуждений начальную и конечную вершины будем считать вершинами полигонов.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|about=О кратчайшем пути&lt;br /&gt;
|statement=&lt;br /&gt;
Любой кратчайший путь между двумя вершинами с полигональными препятствиями представляет собой ломаную, вершины которой {{---}} вершины полигонов.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:short.png|150px|thumb|right|Short cut]]&lt;br /&gt;
Пусть кратчайший путь {{---}} не ломаная. В таком случае, на пути существует такая точка &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, которая не принадлежит ни одному прямому отрезку. Это означает, что существует &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестность точки &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, в которую не попадает ни одно препятствие (случай, когда точка попала на ребро рассматривается аналогично). В таком случае, подпуть, который находится внутри &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности, по неравенству треугольника может быть сокращён по хорде, соединяющий точки пересечения границы &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности с путем. Раз часть пути может быть уменьшена, значит и весь путь может быть уменьшен, а значит исходное предположение некорректно.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
Говорят, что вершина &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; ''видна'' (англ. mutually visible) из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;, если отрезок &amp;lt;tex&amp;gt; uv &amp;lt;/tex&amp;gt; не пересекает ни одного препятствия.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
''Граф видимости'' (англ. visibility graph) {{---}} граф, вершины которого {{---}} вершины полигонов. Между вершинами &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; существует ребро, если из &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; видна &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
В худшем случае в таком графе может быть &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; ребер. Однако по некоторым ребрам кратчайший путь точно не пройдет, и такие ребра из графа можно удалить.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
[[Файл:edgeToDelete.png|150px|thumb|right|Удаляем &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Если существуют вершины &amp;lt;tex&amp;gt; A, B, C &amp;lt;/tex&amp;gt; одного препятствия и вершина &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; такая, что поворот &amp;lt;tex&amp;gt; DBA &amp;lt;/tex&amp;gt; не совпадает с поворотом &amp;lt;tex&amp;gt; DBC &amp;lt;/tex&amp;gt;, то ребро &amp;lt;tex&amp;gt; DB &amp;lt;/tex&amp;gt; не принадлежит кратчайшему пути и его можно удалить из графа. (См. поясняющую картинку справа)&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:edgeNotToDelete.png|200px|thumb|right|Не удаляем &amp;lt;tex&amp;gt; BS &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Путь проходящий через ребро &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt; будет длиннее, чем через соседей точки &amp;lt;tex&amp;gt; B &amp;lt;/tex&amp;gt;, так как по неравенству треугольника &amp;lt;tex&amp;gt; AB + BD &amp;gt; AD &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
По доказанным леммам любое ребро кратчайшего пути содержится в графе. Таким образом, для нахождения кратчайшего пути осталось найти кратчайший путь в этом графе от начальной до конечной вершины.&lt;br /&gt;
&lt;br /&gt;
=== Построение visibility графа ===&lt;br /&gt;
==== Наивный алгоритм. &amp;lt;tex&amp;gt; O(n ^ 3) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
Для каждой пары вершин проверяем, можно ли добавить ребро между ними, то есть нет ли пересечений с полигонами. &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; пар вершин и &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; ребер, то есть &amp;lt;tex&amp;gt; O(n^3) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Lee’s Algorithm. &amp;lt;tex&amp;gt; O(n ^ 2 \log n) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
{|&lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zam.png|300px|thumb|left|Заметание плоскости вращающимся лучом]]&lt;br /&gt;
Однако можно это сделать за &amp;lt;tex&amp;gt; O(n ^ 2 \log  n) &amp;lt;/tex&amp;gt;. Идея алгоритма проста: для каждой вершины найдем видимые из нее вершины. Если научиться делать это за &amp;lt;tex&amp;gt; O(n \log  n) &amp;lt;/tex&amp;gt;, задача решена, так как всего точек &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для каждой вершины будем рассматривать только правую половину плоскости, так как ребра, которые должны идти в левую половину, будут исходить из вершин, для которых текущая вершина будет справа.&lt;br /&gt;
&lt;br /&gt;
Переформулируем задачу. Дано: точка &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и множество отрезков {{---}} ребер препятствий. &lt;br /&gt;
Найти: множество концов отрезков, видимых из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для решения этой задачи будем использовать заметающий луч с началом в точке &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Его статусом будут отрезки, которые его пересекают, упорядоченные по возрастанию расстояния от точки &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; до точки пересечения. Точками событий будут концы отрезков. &lt;br /&gt;
&lt;br /&gt;
Пустим луч из рассматриваемой вершины &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вертикально вверх и добавим в статус все отрезки, которые он пересекает, по увеличению расстояния до них. Теперь будем рассматривать точки &amp;lt;tex&amp;gt; w \in V &amp;lt;/tex&amp;gt; в порядке сортировки по углу между &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и вертикальной полуосью &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt;. При таком обходе для проверки видимости вершины достаточно проверить пересечение с ближайшим к &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; отрезком, то есть первым в статусе(так как отрезки отсортированы по расстоянию до них). Действительно, если вершина &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; не видна, то отрезок &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; пересекает несколько отрезков, лежащих перед &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt;, а значит и ближайший. В противном случае все пересекаемые лучом отрезки лежат за вершиной &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; и пересечения отрезка &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; с ближайшим отрезком не будет. Вне зависимости от видимости вершины, необходимо изменить статус заметающего луча. Для этого необходимо удалить из статуса все отрезки, которые заканчиваются вершине &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; (лежат слева от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;) и добавить все отрезки, которые в ней начинаются (лежат справа от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Псевдокод =====&lt;br /&gt;
    graph buildVisibilityGraph(Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
       vertices = getVertices(segments) &amp;lt;tex&amp;gt; \cup\ \{S, T\} &amp;lt;/tex&amp;gt;           //все вершины препятствий, а также начальная и конечная вершины&lt;br /&gt;
       graph = visibilityGraph(vertices)                  //изначально в графе только вершины&lt;br /&gt;
       '''for''' Vertex v '''in''' vertices                           //для каждой вершины&lt;br /&gt;
          '''for''' Vertex w '''in''' getVisibleVertices(v, segments) //добавляем в граф все видимые из нее вершины&lt;br /&gt;
             visibilityGraph.addEdge(v, w)&lt;br /&gt;
       '''return''' visibilityGraph&lt;br /&gt;
Здесь функция getVisibleVertices(&amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;) возвращает все видимые из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вершины и выглядит так:&lt;br /&gt;
    Set&amp;lt;Vertex&amp;gt; getVisibleVertices(Vertex v, Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
       Set&amp;lt;Vertex&amp;gt; answer&lt;br /&gt;
    // Инициализируем статус&lt;br /&gt;
       '''for''' Segment s '''in''' segments&lt;br /&gt;
          '''if''' intersection s and ray from v to up exists&lt;br /&gt;
             status.add(s)&lt;br /&gt;
    // Инициализируем множество вершин, которые нужно рассматривать&lt;br /&gt;
       '''for''' Point w '''in''' segments&lt;br /&gt;
          '''if''' w.x &amp;gt;= v.x&lt;br /&gt;
             currentVertices.add(w)&lt;br /&gt;
       sort(currentVertices) by angle&lt;br /&gt;
    // Для каждой вершины проверяем, видима ли она и обновляем статус&lt;br /&gt;
       '''for''' Point w '''in''' currentVertices&lt;br /&gt;
          '''if''' intersection vw and status.closest not exists&lt;br /&gt;
             answer.add(w)&lt;br /&gt;
          delete from status all segments ending in w&lt;br /&gt;
          add in status all segments beginning in w&lt;br /&gt;
       '''return''' answer&lt;br /&gt;
В качестве статуса нужно использовать структуру данных, позволяющую добавлять и удалять из нее отрезки за &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; и извлекать минимум за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt;. В этом случае достигается асимптотика &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;, так как для каждой из &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; точек выполняется сортировка за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, обновление статуса (суммарно &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, так как каждый отрезок добавляется и удаляется из статуса не более одного раза) и запросы ближайшего отрезка (&amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; на точку, то есть &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;). &lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zamrefr1.png|250px|thumb|right|Обновление статуса заметающего луча: добавляем ребра &amp;lt;tex&amp;gt; w_1 w_5 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; w_1 w_2 &amp;lt;/tex&amp;gt; в статус]]&lt;br /&gt;
[[Файл:Zamrefr2.png|250px|thumb|right|Добавляем ребра &amp;lt;tex&amp;gt; w_3 w_2 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; w_3 w_4 &amp;lt;/tex&amp;gt; в статус]]&lt;br /&gt;
[[Файл:Zamrefr3.png|250px|thumb|right|Удаляем ребра &amp;lt;tex&amp;gt; w_3 w_2 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; w_1 w_2 &amp;lt;/tex&amp;gt; из статуса]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Overmars and Welzl’s Algorithm &amp;lt;tex&amp;gt; O(n ^ 2) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
[http://igitur-archive.library.uu.nl/math/2006-1214-201604/overmars_88_new_methods.pdf visibility graph при помощи rotation tree]&lt;br /&gt;
&lt;br /&gt;
C помощью [http://bit.ly/1eEqTzk rotation tree] можно достичь асимптотики &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Motion planning ==&lt;br /&gt;
[[Файл:mink.png|200px|thumb|left|Изменяем препятствия]]&lt;br /&gt;
[[Файл:mink2.png|400px|thumb|right|Ищем путь для точки]]&lt;br /&gt;
Рассмотрим задачу нахождения кратчайшего пути, когда движимый объект {{---}} это выпуклый полигон. Например, робот, которого надо доставить из начальной в конечную точку.&lt;br /&gt;
&lt;br /&gt;
Если полигон вращать нельзя, задачу сводится к движению точки так: выбирается точка на полигоне, которая принимается за начало координат. В такой системе координат для каждого препятствия считается [[Сумма Минковского (определение, вычисление)|сумма Минковского]] с полигоном. Получаются бОльшие препятствия, но теперь достаточно двигать выбранную точку, что было описано выше.&lt;br /&gt;
&lt;br /&gt;
Если полигон можно вращать, задача нахождения ''кратчайшего'' пути становится достаточно ресурсоёмка, поэтому обычно рассматривают задачу нахождения какого-нибудь пути между конечными точками.&lt;br /&gt;
&lt;br /&gt;
Первый шаг решения этой задачи совпадает с предыдущим случаем: выберем точку и построим [[Сумма Минковского (определение, вычисление)|сумму Минковского]] препятствий с полигоном. Рассмотрим малый угол &amp;lt;tex&amp;gt; \epsilon &amp;lt;/tex&amp;gt;. Представим, что поворот полигона на этот угол {{---}} это движение вверх-вниз между слоями, на каждом из которых посчитана сумма Минковского с полигоном, повернутым на этот угол.&lt;br /&gt;
&lt;br /&gt;
На каждом слое построим трапецоидную карту и граф, как описано в [[Visibility graph и motion planning#Нахождение пути между точками с препятствиями|начале]]. Если [[Пересечение многоугольников (PSLG overlaying)|пересечь]] соседние слои и добавить между их графами ребра, получится один большой граф, в котором ищется кратчайший путь.&lt;br /&gt;
&lt;br /&gt;
При таком подходе может возникнуть ошибка при пересечении слоев: на каждом слое состояния будут допустимые, а осуществить поворот физически будет невозможно. Обычно, эту проблему решают двумя способами: измельчением угла поворота и изначальным сглаживанием углов полигона. Первый способ повышает не только точность решения, но и вычислительную сложность задачи. Второй подход практически исключает возможность нахождения пути, когда его нет, но повышает вероятность &amp;quot;ненахождения&amp;quot; пути, когда он есть.&lt;br /&gt;
&lt;br /&gt;
== Источники ==&lt;br /&gt;
* 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&lt;br /&gt;
* [http://www.academia.edu/2845047/3D_Visibility_Graph статья] про visibility graphs на academia.edu&lt;br /&gt;
* [http://habrahabr.ru/post/199256/ Хабр]&lt;br /&gt;
[[Категория: Вычислительная геометрия]]&lt;br /&gt;
&lt;br /&gt;
== Ссылки ==&lt;br /&gt;
* Моя [https://github.com/Igorjan94/cg/blob/master/include/cg/algorithms/visibilityGraph.h реализация] алгоритма за &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;. Далеко от идеального, но работает&lt;/div&gt;</summary>
		<author><name>Igorjan94</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44838</id>
		<title>Visibility graph и motion planning</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44838"/>
				<updated>2015-02-10T20:33:04Z</updated>
		
		<summary type="html">&lt;p&gt;Igorjan94: /* Псевдокод */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Нахождение любого пути между точками с препятствиями ==&lt;br /&gt;
{|align=&amp;quot;right&amp;quot;&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
|[[Файл:trap.png|200px|thumb|right|Путь с препятствиями через трапецоидную карту]]&lt;br /&gt;
|[[Файл:notShort.png|300px|thumb|right|Такой путь не самый короткий]]&lt;br /&gt;
|}&lt;br /&gt;
Для начала рассмотрим движение материальной точки. Случай, когда размером и формой движимого объекта пренебречь нельзя, будет рассмотрен [[Visibility graph и motion planning#Motion planning|позднее]]. &lt;br /&gt;
&lt;br /&gt;
Эту задачу можно решить с помощью [[Трапецоидная карта | трапецоидной карты]]. По ней строится граф, ребра которого соединяют центры трапедоидов, а также начальную и конечную вершины с серединами вертикальных сторон трапецоидов. В таком графе ищется путь между начальной и конечной вершинами.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм работает за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; и за линейное количество памяти и хорошо подходит для нахождения какого-нибудь пути между парой данных вершин. Но если нужно найти кратчайший путь, этот алгоритм не подходит, хоть и работает быстро. Однако, решения нахождения кратчайшего пути в лучшем случае работают за &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; времени и памяти (здесь и далее &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество всех вершин).&lt;br /&gt;
&lt;br /&gt;
== Нахождение кратчайшего пути между точками с препятствиями ==&lt;br /&gt;
=== Visibility graph ===&lt;br /&gt;
Рассмотрим точное решение нахождения кратчайшего пути на плоскости между двумя точками с полигональными препятствиями с помощью построения графа видимости. После его построения, как и в случае с трапецоидной картой, кратчайший путь ищется любым стандартным алгоритмом поиска (например, алгоритмом [[Алгоритм Дейкстры|Дейкстры]] или [[Алгоритм A*|A*]]).&lt;br /&gt;
&lt;br /&gt;
Для простоты рассуждений начальную и конечную вершины будем считать вершинами полигонов.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|about=О кратчайшем пути&lt;br /&gt;
|statement=&lt;br /&gt;
Любой кратчайший путь между двумя вершинами с полигональными препятствиями представляет собой ломаную, вершины которой {{---}} вершины полигонов.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:short.png|150px|thumb|right|Short cut]]&lt;br /&gt;
Пусть кратчайший путь {{---}} не ломаная. В таком случае, на пути существует такая точка &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, которая не принадлежит ни одному прямому отрезку. Это означает, что существует &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестность точки &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, в которую не попадает ни одно препятствие (случай, когда точка попала на ребро рассматривается аналогично). В таком случае, подпуть, который находится внутри &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности, по неравенству треугольника может быть сокращён по хорде, соединяющий точки пересечения границы &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности с путем. Раз часть пути может быть уменьшена, значит и весь путь может быть уменьшен, а значит исходное предположение некорректно.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
Говорят, что вершина &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; ''видна'' (англ. mutually visible) из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;, если отрезок &amp;lt;tex&amp;gt; uv &amp;lt;/tex&amp;gt; не пересекает ни одного препятствия.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
''Граф видимости'' (англ. visibility graph) {{---}} граф, вершины которого {{---}} вершины полигонов. Между вершинами &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; существует ребро, если из &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; видна &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
В худшем случае в таком графе может быть &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; ребер. Однако по некоторым ребрам кратчайший путь точно не пройдет, и такие ребра из графа можно удалить.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
[[Файл:edgeToDelete.png|150px|thumb|right|Удаляем &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Если существуют вершины &amp;lt;tex&amp;gt; A, B, C &amp;lt;/tex&amp;gt; одного препятствия и вершина &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; такая, что поворот &amp;lt;tex&amp;gt; DBA &amp;lt;/tex&amp;gt; не совпадает с поворотом &amp;lt;tex&amp;gt; DBC &amp;lt;/tex&amp;gt;, то ребро &amp;lt;tex&amp;gt; DB &amp;lt;/tex&amp;gt; не принадлежит кратчайшему пути и его можно удалить из графа. (См. поясняющую картинку справа)&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:edgeNotToDelete.png|200px|thumb|right|Не удаляем &amp;lt;tex&amp;gt; BS &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Путь проходящий через ребро &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt; будет длиннее, чем через соседей точки &amp;lt;tex&amp;gt; B &amp;lt;/tex&amp;gt;, так как по неравенству треугольника &amp;lt;tex&amp;gt; AB + BD &amp;gt; AD &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
По доказанным леммам любое ребро кратчайшего пути содержится в графе. Таким образом, для нахождения кратчайшего пути осталось найти кратчайший путь в этом графе от начальной до конечной вершины.&lt;br /&gt;
&lt;br /&gt;
=== Построение visibility графа ===&lt;br /&gt;
==== Наивный алгоритм. &amp;lt;tex&amp;gt; O(n ^ 3) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
Для каждой пары вершин проверяем, можно ли добавить ребро между ними, то есть нет ли пересечений с полигонами. &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; пар вершин и &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; ребер, то есть &amp;lt;tex&amp;gt; O(n^3) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Lee’s Algorithm. &amp;lt;tex&amp;gt; O(n ^ 2 \log n) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
{|&lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zam.png|300px|thumb|left|Заметание плоскости вращающимся лучом]]&lt;br /&gt;
Однако можно это сделать за &amp;lt;tex&amp;gt; O(n ^ 2 \log  n) &amp;lt;/tex&amp;gt;. Идея алгоритма проста: для каждой вершины найдем видимые из нее вершины. Если научиться делать это за &amp;lt;tex&amp;gt; O(n \log  n) &amp;lt;/tex&amp;gt;, задача решена, так как всего точек &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для каждой вершины будем рассматривать только правую половину плоскости, так как ребра, которые должны идти в левую половину, будут исходить из вершин, для которых текущая вершина будет справа.&lt;br /&gt;
&lt;br /&gt;
Переформулируем задачу. Дано: точка &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и множество отрезков {{---}} ребер препятствий. &lt;br /&gt;
Найти: множество концов отрезков, видимых из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для решения этой задачи будем использовать заметающий луч с началом в точке &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Его статусом будут отрезки, которые его пересекают, упорядоченные по возрастанию расстояния от точки &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; до точки пересечения. Точками событий будут концы отрезков. &lt;br /&gt;
&lt;br /&gt;
Пустим луч из рассматриваемой вершины &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вертикально вверх и добавим в статус все отрезки, которые он пересекает, по увеличению расстояния до них. Теперь будем рассматривать точки &amp;lt;tex&amp;gt; w \in V &amp;lt;/tex&amp;gt; в порядке сортировки по углу между &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и вертикальной полуосью &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt;. При таком обходе для проверки видимости вершины достаточно проверить пересечение с ближайшим к &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; отрезком, то есть первым в статусе(так как отрезки отсортированы по расстоянию до них). Действительно, если вершина &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; не видна, то отрезок &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; пересекает несколько отрезков, лежащих перед &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt;, а значит и ближайший. В противном случае все пересекаемые лучом отрезки лежат за вершиной &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; и пересечения отрезка &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; с ближайшим отрезком не будет. Вне зависимости от видимости вершины, необходимо изменить статус заметающего луча. Для этого необходимо удалить из статуса все отрезки, которые заканчиваются вершине &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; (лежат слева от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;) и добавить все отрезки, которые в ней начинаются (лежат справа от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Псевдокод =====&lt;br /&gt;
    graph buildVisibilityGraph(Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
       Set&amp;lt;Vertex&amp;gt; vertices = getVertices(segments)       //получаем все вершины препятствий&lt;br /&gt;
       graph visibilityGraph(vertices)                    //изначально в графе только вершины&lt;br /&gt;
       '''for''' Vertex v '''in''' vertices                           //для каждой вершины&lt;br /&gt;
          '''for''' Vertex w '''in''' getVisibleVertices(v, segments) //добавляем в граф все видимые из нее вершины&lt;br /&gt;
             visibilityGraph.addEdge(v, w)&lt;br /&gt;
       '''return''' visibilityGraph&lt;br /&gt;
Здесь функция getVisibleVertices(&amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;) возвращает все видимые из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вершины и выглядит так:&lt;br /&gt;
    Set&amp;lt;Vertex&amp;gt; getVisibleVertices(Vertex v, Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
       Set&amp;lt;Vertex&amp;gt; answer&lt;br /&gt;
    // Инициализируем статус&lt;br /&gt;
       '''for''' Segment s '''in''' segments&lt;br /&gt;
          '''if''' intersection s and ray from v to up exists&lt;br /&gt;
             status.add(s)&lt;br /&gt;
    // Инициализируем множество вершин, которые нужно рассматривать&lt;br /&gt;
       '''for''' Point w '''in''' segments&lt;br /&gt;
          '''if''' w.x &amp;gt;= v.x&lt;br /&gt;
             currentVertices.add(w)&lt;br /&gt;
       sort(currentVertices) by angle&lt;br /&gt;
    // Для каждой вершины проверяем, видима ли она и обновляем статус&lt;br /&gt;
       '''for''' Point w '''in''' currentVertices&lt;br /&gt;
          '''if''' intersection vw and status.closest not exists&lt;br /&gt;
             answer.add(w)&lt;br /&gt;
          delete from status all segments ending in w&lt;br /&gt;
          add in status all segments beginning in w&lt;br /&gt;
       '''return''' answer&lt;br /&gt;
В качестве статуса нужно использовать структуру данных, позволяющую добавлять и удалять из нее отрезки за &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; и извлекать минимум за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt;. В этом случае достигается асимптотика &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;, так как для каждой из &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; точек выполняется сортировка за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, обновление статуса (суммарно &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, так как каждый отрезок добавляется и удаляется из статуса не более одного раза) и запросы ближайшего отрезка (&amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; на точку, то есть &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;). &lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zamrefr1.png|250px|thumb|right|Обновление статуса заметающего луча: добавляем ребра &amp;lt;tex&amp;gt; w_1 w_5 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; w_1 w_2 &amp;lt;/tex&amp;gt; в статус]]&lt;br /&gt;
[[Файл:Zamrefr2.png|250px|thumb|right|Добавляем ребра &amp;lt;tex&amp;gt; w_3 w_2 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; w_3 w_4 &amp;lt;/tex&amp;gt; в статус]]&lt;br /&gt;
[[Файл:Zamrefr3.png|250px|thumb|right|Удаляем ребра &amp;lt;tex&amp;gt; w_3 w_2 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; w_1 w_2 &amp;lt;/tex&amp;gt; из статуса]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Overmars and Welzl’s Algorithm &amp;lt;tex&amp;gt; O(n ^ 2) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
[http://igitur-archive.library.uu.nl/math/2006-1214-201604/overmars_88_new_methods.pdf visibility graph при помощи rotation tree]&lt;br /&gt;
&lt;br /&gt;
C помощью [http://bit.ly/1eEqTzk rotation tree] можно достичь асимптотики &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Motion planning ==&lt;br /&gt;
[[Файл:mink.png|200px|thumb|left|Изменяем препятствия]]&lt;br /&gt;
[[Файл:mink2.png|400px|thumb|right|Ищем путь для точки]]&lt;br /&gt;
Рассмотрим задачу нахождения кратчайшего пути, когда движимый объект {{---}} это выпуклый полигон. Например, робот, которого надо доставить из начальной в конечную точку.&lt;br /&gt;
&lt;br /&gt;
Если полигон вращать нельзя, задачу сводится к движению точки так: выбирается точка на полигоне, которая принимается за начало координат. В такой системе координат для каждого препятствия считается [[Сумма Минковского (определение, вычисление)|сумма Минковского]] с полигоном. Получаются бОльшие препятствия, но теперь достаточно двигать выбранную точку, что было описано выше.&lt;br /&gt;
&lt;br /&gt;
Если полигон можно вращать, задача нахождения ''кратчайшего'' пути становится достаточно ресурсоёмка, поэтому обычно рассматривают задачу нахождения какого-нибудь пути между конечными точками.&lt;br /&gt;
&lt;br /&gt;
Первый шаг решения этой задачи совпадает с предыдущим случаем: выберем точку и построим [[Сумма Минковского (определение, вычисление)|сумму Минковского]] препятствий с полигоном. Рассмотрим малый угол &amp;lt;tex&amp;gt; \epsilon &amp;lt;/tex&amp;gt;. Представим, что поворот полигона на этот угол {{---}} это движение вверх-вниз между слоями, на каждом из которых посчитана сумма Минковского с полигоном, повернутым на этот угол.&lt;br /&gt;
&lt;br /&gt;
На каждом слое построим трапецоидную карту и граф, как описано в [[Visibility graph и motion planning#Нахождение пути между точками с препятствиями|начале]]. Если [[Пересечение многоугольников (PSLG overlaying)|пересечь]] соседние слои и добавить между их графами ребра, получится один большой граф, в котором ищется кратчайший путь.&lt;br /&gt;
&lt;br /&gt;
При таком подходе может возникнуть ошибка при пересечении слоев: на каждом слое состояния будут допустимые, а осуществить поворот физически будет невозможно. Обычно, эту проблему решают двумя способами: измельчением угла поворота и изначальным сглаживанием углов полигона. Первый способ повышает не только точность решения, но и вычислительную сложность задачи. Второй подход практически исключает возможность нахождения пути, когда его нет, но повышает вероятность &amp;quot;ненахождения&amp;quot; пути, когда он есть.&lt;br /&gt;
&lt;br /&gt;
== Источники ==&lt;br /&gt;
* 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&lt;br /&gt;
* [http://www.academia.edu/2845047/3D_Visibility_Graph статья] про visibility graphs на academia.edu&lt;br /&gt;
* [http://habrahabr.ru/post/199256/ Хабр]&lt;br /&gt;
[[Категория: Вычислительная геометрия]]&lt;br /&gt;
&lt;br /&gt;
== Ссылки ==&lt;br /&gt;
* Моя [https://github.com/Igorjan94/cg/blob/master/include/cg/algorithms/visibilityGraph.h реализация] алгоритма за &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;. Далеко от идеального, но работает&lt;/div&gt;</summary>
		<author><name>Igorjan94</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44837</id>
		<title>Visibility graph и motion planning</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44837"/>
				<updated>2015-02-10T20:26:04Z</updated>
		
		<summary type="html">&lt;p&gt;Igorjan94: /* Lee’s Algorithm.  O(n ^ 2 \log n)  */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Нахождение любого пути между точками с препятствиями ==&lt;br /&gt;
{|align=&amp;quot;right&amp;quot;&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
|[[Файл:trap.png|200px|thumb|right|Путь с препятствиями через трапецоидную карту]]&lt;br /&gt;
|[[Файл:notShort.png|300px|thumb|right|Такой путь не самый короткий]]&lt;br /&gt;
|}&lt;br /&gt;
Для начала рассмотрим движение материальной точки. Случай, когда размером и формой движимого объекта пренебречь нельзя, будет рассмотрен [[Visibility graph и motion planning#Motion planning|позднее]]. &lt;br /&gt;
&lt;br /&gt;
Эту задачу можно решить с помощью [[Трапецоидная карта | трапецоидной карты]]. По ней строится граф, ребра которого соединяют центры трапедоидов, а также начальную и конечную вершины с серединами вертикальных сторон трапецоидов. В таком графе ищется путь между начальной и конечной вершинами.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм работает за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; и за линейное количество памяти и хорошо подходит для нахождения какого-нибудь пути между парой данных вершин. Но если нужно найти кратчайший путь, этот алгоритм не подходит, хоть и работает быстро. Однако, решения нахождения кратчайшего пути в лучшем случае работают за &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; времени и памяти (здесь и далее &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество всех вершин).&lt;br /&gt;
&lt;br /&gt;
== Нахождение кратчайшего пути между точками с препятствиями ==&lt;br /&gt;
=== Visibility graph ===&lt;br /&gt;
Рассмотрим точное решение нахождения кратчайшего пути на плоскости между двумя точками с полигональными препятствиями с помощью построения графа видимости. После его построения, как и в случае с трапецоидной картой, кратчайший путь ищется любым стандартным алгоритмом поиска (например, алгоритмом [[Алгоритм Дейкстры|Дейкстры]] или [[Алгоритм A*|A*]]).&lt;br /&gt;
&lt;br /&gt;
Для простоты рассуждений начальную и конечную вершины будем считать вершинами полигонов.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|about=О кратчайшем пути&lt;br /&gt;
|statement=&lt;br /&gt;
Любой кратчайший путь между двумя вершинами с полигональными препятствиями представляет собой ломаную, вершины которой {{---}} вершины полигонов.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:short.png|150px|thumb|right|Short cut]]&lt;br /&gt;
Пусть кратчайший путь {{---}} не ломаная. В таком случае, на пути существует такая точка &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, которая не принадлежит ни одному прямому отрезку. Это означает, что существует &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестность точки &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, в которую не попадает ни одно препятствие (случай, когда точка попала на ребро рассматривается аналогично). В таком случае, подпуть, который находится внутри &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности, по неравенству треугольника может быть сокращён по хорде, соединяющий точки пересечения границы &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности с путем. Раз часть пути может быть уменьшена, значит и весь путь может быть уменьшен, а значит исходное предположение некорректно.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
Говорят, что вершина &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; ''видна'' (англ. mutually visible) из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;, если отрезок &amp;lt;tex&amp;gt; uv &amp;lt;/tex&amp;gt; не пересекает ни одного препятствия.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
''Граф видимости'' (англ. visibility graph) {{---}} граф, вершины которого {{---}} вершины полигонов. Между вершинами &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; существует ребро, если из &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; видна &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
В худшем случае в таком графе может быть &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; ребер. Однако по некоторым ребрам кратчайший путь точно не пройдет, и такие ребра из графа можно удалить.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
[[Файл:edgeToDelete.png|150px|thumb|right|Удаляем &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Если существуют вершины &amp;lt;tex&amp;gt; A, B, C &amp;lt;/tex&amp;gt; одного препятствия и вершина &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; такая, что поворот &amp;lt;tex&amp;gt; DBA &amp;lt;/tex&amp;gt; не совпадает с поворотом &amp;lt;tex&amp;gt; DBC &amp;lt;/tex&amp;gt;, то ребро &amp;lt;tex&amp;gt; DB &amp;lt;/tex&amp;gt; не принадлежит кратчайшему пути и его можно удалить из графа. (См. поясняющую картинку справа)&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:edgeNotToDelete.png|200px|thumb|right|Не удаляем &amp;lt;tex&amp;gt; BS &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Путь проходящий через ребро &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt; будет длиннее, чем через соседей точки &amp;lt;tex&amp;gt; B &amp;lt;/tex&amp;gt;, так как по неравенству треугольника &amp;lt;tex&amp;gt; AB + BD &amp;gt; AD &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
По доказанным леммам любое ребро кратчайшего пути содержится в графе. Таким образом, для нахождения кратчайшего пути осталось найти кратчайший путь в этом графе от начальной до конечной вершины.&lt;br /&gt;
&lt;br /&gt;
=== Построение visibility графа ===&lt;br /&gt;
==== Наивный алгоритм. &amp;lt;tex&amp;gt; O(n ^ 3) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
Для каждой пары вершин проверяем, можно ли добавить ребро между ними, то есть нет ли пересечений с полигонами. &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; пар вершин и &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; ребер, то есть &amp;lt;tex&amp;gt; O(n^3) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Lee’s Algorithm. &amp;lt;tex&amp;gt; O(n ^ 2 \log n) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
{|&lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zam.png|300px|thumb|left|Заметание плоскости вращающимся лучом]]&lt;br /&gt;
Однако можно это сделать за &amp;lt;tex&amp;gt; O(n ^ 2 \log  n) &amp;lt;/tex&amp;gt;. Идея алгоритма проста: для каждой вершины найдем видимые из нее вершины. Если научиться делать это за &amp;lt;tex&amp;gt; O(n \log  n) &amp;lt;/tex&amp;gt;, задача решена, так как всего точек &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для каждой вершины будем рассматривать только правую половину плоскости, так как ребра, которые должны идти в левую половину, будут исходить из вершин, для которых текущая вершина будет справа.&lt;br /&gt;
&lt;br /&gt;
Переформулируем задачу. Дано: точка &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и множество отрезков {{---}} ребер препятствий. &lt;br /&gt;
Найти: множество концов отрезков, видимых из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для решения этой задачи будем использовать заметающий луч с началом в точке &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Его статусом будут отрезки, которые его пересекают, упорядоченные по возрастанию расстояния от точки &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; до точки пересечения. Точками событий будут концы отрезков. &lt;br /&gt;
&lt;br /&gt;
Пустим луч из рассматриваемой вершины &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вертикально вверх и добавим в статус все отрезки, которые он пересекает, по увеличению расстояния до них. Теперь будем рассматривать точки &amp;lt;tex&amp;gt; w \in V &amp;lt;/tex&amp;gt; в порядке сортировки по углу между &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и вертикальной полуосью &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt;. При таком обходе для проверки видимости вершины достаточно проверить пересечение с ближайшим к &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; отрезком, то есть первым в статусе(так как отрезки отсортированы по расстоянию до них). Действительно, если вершина &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; не видна, то отрезок &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; пересекает несколько отрезков, лежащих перед &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt;, а значит и ближайший. В противном случае все пересекаемые лучом отрезки лежат за вершиной &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; и пересечения отрезка &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; с ближайшим отрезком не будет. Вне зависимости от видимости вершины, необходимо изменить статус заметающего луча. Для этого необходимо удалить из статуса все отрезки, которые заканчиваются вершине &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; (лежат слева от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;) и добавить все отрезки, которые в ней начинаются (лежат справа от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Псевдокод =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
graph buildVisibilityGraph(Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
   Set&amp;lt;Vertex&amp;gt; vertices = getVertices(segments)       //получаем все вершины препятствий&lt;br /&gt;
   graph visibilityGraph(vertices)                    //изначально в графе только вершины&lt;br /&gt;
   for Vertex v in vertices                           //для каждой вершины&lt;br /&gt;
      for Vertex w in getVisibleVertices(v, segments) //добавляем в граф все видимые из нее вершины&lt;br /&gt;
         visibilityGraph.addEdge(v, w)&lt;br /&gt;
   return visibilityGraph&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Здесь функция getVisibleVertices(&amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;) возвращает все видимые из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вершины и выглядит так:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Set&amp;lt;Vertex&amp;gt; getVisibleVertices(Vertex v, Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
   Set&amp;lt;Vertex&amp;gt; answer&lt;br /&gt;
// Инициализируем статус&lt;br /&gt;
   for Segment s in segments&lt;br /&gt;
      if intersection s and ray from v to up exists&lt;br /&gt;
         status.add(s)&lt;br /&gt;
// Инициализируем множество вершин, которые нужно рассматривать&lt;br /&gt;
   for Point w in segments&lt;br /&gt;
      if w.x &amp;gt;= v.x&lt;br /&gt;
         currentVertices.add(w)&lt;br /&gt;
   sort(currentVertices) by angle&lt;br /&gt;
// Для каждой вершины проверяем, видима ли она и обновляем статус&lt;br /&gt;
   for Point w in currentVertices&lt;br /&gt;
      if intersection vw and status.closest not exists&lt;br /&gt;
         answer.add(w)&lt;br /&gt;
      delete from status all segments ending in w&lt;br /&gt;
      add in status all segments beginning in w&lt;br /&gt;
   return answer&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
В качестве статуса нужно использовать структуру данных, позволяющую добавлять и удалять из нее отрезки за &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; и извлекать минимум за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt;. В этом случае достигается асимптотика &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;, так как для каждой из &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; точек выполняется сортировка за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, обновление статуса (суммарно &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, так как каждый отрезок добавляется и удаляется из статуса не более одного раза) и запросы ближайшего отрезка (&amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; на точку, то есть &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;). &lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zamrefr1.png|250px|thumb|right|Обновление статуса заметающего луча: добавляем ребра &amp;lt;tex&amp;gt; w_1 w_5 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; w_1 w_2 &amp;lt;/tex&amp;gt; в статус]]&lt;br /&gt;
[[Файл:Zamrefr2.png|250px|thumb|right|Добавляем ребра &amp;lt;tex&amp;gt; w_3 w_2 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; w_3 w_4 &amp;lt;/tex&amp;gt; в статус]]&lt;br /&gt;
[[Файл:Zamrefr3.png|250px|thumb|right|Удаляем ребра &amp;lt;tex&amp;gt; w_3 w_2 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; w_1 w_2 &amp;lt;/tex&amp;gt; из статуса]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Overmars and Welzl’s Algorithm &amp;lt;tex&amp;gt; O(n ^ 2) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
[http://igitur-archive.library.uu.nl/math/2006-1214-201604/overmars_88_new_methods.pdf visibility graph при помощи rotation tree]&lt;br /&gt;
&lt;br /&gt;
C помощью [http://bit.ly/1eEqTzk rotation tree] можно достичь асимптотики &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Motion planning ==&lt;br /&gt;
[[Файл:mink.png|200px|thumb|left|Изменяем препятствия]]&lt;br /&gt;
[[Файл:mink2.png|400px|thumb|right|Ищем путь для точки]]&lt;br /&gt;
Рассмотрим задачу нахождения кратчайшего пути, когда движимый объект {{---}} это выпуклый полигон. Например, робот, которого надо доставить из начальной в конечную точку.&lt;br /&gt;
&lt;br /&gt;
Если полигон вращать нельзя, задачу сводится к движению точки так: выбирается точка на полигоне, которая принимается за начало координат. В такой системе координат для каждого препятствия считается [[Сумма Минковского (определение, вычисление)|сумма Минковского]] с полигоном. Получаются бОльшие препятствия, но теперь достаточно двигать выбранную точку, что было описано выше.&lt;br /&gt;
&lt;br /&gt;
Если полигон можно вращать, задача нахождения ''кратчайшего'' пути становится достаточно ресурсоёмка, поэтому обычно рассматривают задачу нахождения какого-нибудь пути между конечными точками.&lt;br /&gt;
&lt;br /&gt;
Первый шаг решения этой задачи совпадает с предыдущим случаем: выберем точку и построим [[Сумма Минковского (определение, вычисление)|сумму Минковского]] препятствий с полигоном. Рассмотрим малый угол &amp;lt;tex&amp;gt; \epsilon &amp;lt;/tex&amp;gt;. Представим, что поворот полигона на этот угол {{---}} это движение вверх-вниз между слоями, на каждом из которых посчитана сумма Минковского с полигоном, повернутым на этот угол.&lt;br /&gt;
&lt;br /&gt;
На каждом слое построим трапецоидную карту и граф, как описано в [[Visibility graph и motion planning#Нахождение пути между точками с препятствиями|начале]]. Если [[Пересечение многоугольников (PSLG overlaying)|пересечь]] соседние слои и добавить между их графами ребра, получится один большой граф, в котором ищется кратчайший путь.&lt;br /&gt;
&lt;br /&gt;
При таком подходе может возникнуть ошибка при пересечении слоев: на каждом слое состояния будут допустимые, а осуществить поворот физически будет невозможно. Обычно, эту проблему решают двумя способами: измельчением угла поворота и изначальным сглаживанием углов полигона. Первый способ повышает не только точность решения, но и вычислительную сложность задачи. Второй подход практически исключает возможность нахождения пути, когда его нет, но повышает вероятность &amp;quot;ненахождения&amp;quot; пути, когда он есть.&lt;br /&gt;
&lt;br /&gt;
== Источники ==&lt;br /&gt;
* 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&lt;br /&gt;
* [http://www.academia.edu/2845047/3D_Visibility_Graph статья] про visibility graphs на academia.edu&lt;br /&gt;
* [http://habrahabr.ru/post/199256/ Хабр]&lt;br /&gt;
[[Категория: Вычислительная геометрия]]&lt;br /&gt;
&lt;br /&gt;
== Ссылки ==&lt;br /&gt;
* Моя [https://github.com/Igorjan94/cg/blob/master/include/cg/algorithms/visibilityGraph.h реализация] алгоритма за &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;. Далеко от идеального, но работает&lt;/div&gt;</summary>
		<author><name>Igorjan94</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44836</id>
		<title>Visibility graph и motion planning</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44836"/>
				<updated>2015-02-10T20:23:59Z</updated>
		
		<summary type="html">&lt;p&gt;Igorjan94: /* Lee’s Algorithm.  O(n ^ 2 \log n)  */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Нахождение любого пути между точками с препятствиями ==&lt;br /&gt;
{|align=&amp;quot;right&amp;quot;&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
|[[Файл:trap.png|200px|thumb|right|Путь с препятствиями через трапецоидную карту]]&lt;br /&gt;
|[[Файл:notShort.png|300px|thumb|right|Такой путь не самый короткий]]&lt;br /&gt;
|}&lt;br /&gt;
Для начала рассмотрим движение материальной точки. Случай, когда размером и формой движимого объекта пренебречь нельзя, будет рассмотрен [[Visibility graph и motion planning#Motion planning|позднее]]. &lt;br /&gt;
&lt;br /&gt;
Эту задачу можно решить с помощью [[Трапецоидная карта | трапецоидной карты]]. По ней строится граф, ребра которого соединяют центры трапедоидов, а также начальную и конечную вершины с серединами вертикальных сторон трапецоидов. В таком графе ищется путь между начальной и конечной вершинами.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм работает за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; и за линейное количество памяти и хорошо подходит для нахождения какого-нибудь пути между парой данных вершин. Но если нужно найти кратчайший путь, этот алгоритм не подходит, хоть и работает быстро. Однако, решения нахождения кратчайшего пути в лучшем случае работают за &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; времени и памяти (здесь и далее &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество всех вершин).&lt;br /&gt;
&lt;br /&gt;
== Нахождение кратчайшего пути между точками с препятствиями ==&lt;br /&gt;
=== Visibility graph ===&lt;br /&gt;
Рассмотрим точное решение нахождения кратчайшего пути на плоскости между двумя точками с полигональными препятствиями с помощью построения графа видимости. После его построения, как и в случае с трапецоидной картой, кратчайший путь ищется любым стандартным алгоритмом поиска (например, алгоритмом [[Алгоритм Дейкстры|Дейкстры]] или [[Алгоритм A*|A*]]).&lt;br /&gt;
&lt;br /&gt;
Для простоты рассуждений начальную и конечную вершины будем считать вершинами полигонов.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|about=О кратчайшем пути&lt;br /&gt;
|statement=&lt;br /&gt;
Любой кратчайший путь между двумя вершинами с полигональными препятствиями представляет собой ломаную, вершины которой {{---}} вершины полигонов.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:short.png|150px|thumb|right|Short cut]]&lt;br /&gt;
Пусть кратчайший путь {{---}} не ломаная. В таком случае, на пути существует такая точка &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, которая не принадлежит ни одному прямому отрезку. Это означает, что существует &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестность точки &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, в которую не попадает ни одно препятствие (случай, когда точка попала на ребро рассматривается аналогично). В таком случае, подпуть, который находится внутри &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности, по неравенству треугольника может быть сокращён по хорде, соединяющий точки пересечения границы &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности с путем. Раз часть пути может быть уменьшена, значит и весь путь может быть уменьшен, а значит исходное предположение некорректно.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
Говорят, что вершина &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; ''видна'' (англ. mutually visible) из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;, если отрезок &amp;lt;tex&amp;gt; uv &amp;lt;/tex&amp;gt; не пересекает ни одного препятствия.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
''Граф видимости'' (англ. visibility graph) {{---}} граф, вершины которого {{---}} вершины полигонов. Между вершинами &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; существует ребро, если из &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; видна &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
В худшем случае в таком графе может быть &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; ребер. Однако по некоторым ребрам кратчайший путь точно не пройдет, и такие ребра из графа можно удалить.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
[[Файл:edgeToDelete.png|150px|thumb|right|Удаляем &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Если существуют вершины &amp;lt;tex&amp;gt; A, B, C &amp;lt;/tex&amp;gt; одного препятствия и вершина &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; такая, что поворот &amp;lt;tex&amp;gt; DBA &amp;lt;/tex&amp;gt; не совпадает с поворотом &amp;lt;tex&amp;gt; DBC &amp;lt;/tex&amp;gt;, то ребро &amp;lt;tex&amp;gt; DB &amp;lt;/tex&amp;gt; не принадлежит кратчайшему пути и его можно удалить из графа. (См. поясняющую картинку справа)&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:edgeNotToDelete.png|200px|thumb|right|Не удаляем &amp;lt;tex&amp;gt; BS &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Путь проходящий через ребро &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt; будет длиннее, чем через соседей точки &amp;lt;tex&amp;gt; B &amp;lt;/tex&amp;gt;, так как по неравенству треугольника &amp;lt;tex&amp;gt; AB + BD &amp;gt; AD &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
По доказанным леммам любое ребро кратчайшего пути содержится в графе. Таким образом, для нахождения кратчайшего пути осталось найти кратчайший путь в этом графе от начальной до конечной вершины.&lt;br /&gt;
&lt;br /&gt;
=== Построение visibility графа ===&lt;br /&gt;
==== Наивный алгоритм. &amp;lt;tex&amp;gt; O(n ^ 3) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
Для каждой пары вершин проверяем, можно ли добавить ребро между ними, то есть нет ли пересечений с полигонами. &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; пар вершин и &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; ребер, то есть &amp;lt;tex&amp;gt; O(n^3) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Lee’s Algorithm. &amp;lt;tex&amp;gt; O(n ^ 2 \log n) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
{|&lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zam.png|300px|thumb|left|Заметание плоскости вращающимся лучом]]&lt;br /&gt;
Однако можно это сделать за &amp;lt;tex&amp;gt; O(n ^ 2 \log  n) &amp;lt;/tex&amp;gt;. Идея алгоритма проста: для каждой вершины найдем видимые из нее вершины. Если научиться делать это за &amp;lt;tex&amp;gt; O(n \log  n) &amp;lt;/tex&amp;gt;, задача решена, так как всего точек &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для каждой вершины будем рассматривать только правую половину плоскости, так как ребра, которые должны идти в левую половину, будут исходить из вершин, для которых текущая вершина будет справа.&lt;br /&gt;
&lt;br /&gt;
Переформулируем задачу. Дано: точка &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и множество отрезков {{---}} ребер препятствий. &lt;br /&gt;
Найти: множество концов отрезков, видимых из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для решения этой задачи будем использовать заметающий луч с началом в точке &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Его статусом будут отрезки, которые его пересекают, упорядоченные по возрастанию расстояния от точки &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; до точки пересечения. Точками событий будут концы отрезков. &lt;br /&gt;
&lt;br /&gt;
Пустим луч из рассматриваемой вершины &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вертикально вверх и добавим в статус все отрезки, которые он пересекает, по увеличению расстояния до них. Теперь будем рассматривать точки &amp;lt;tex&amp;gt; w \in V &amp;lt;/tex&amp;gt; в порядке сортировки по углу между &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и вертикальной полуосью &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt;. При таком обходе для проверки видимости вершины достаточно проверить пересечение с ближайшим к &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; отрезком, то есть первым в статусе(так как отрезки отсортированы по расстоянию до них). Действительно, если вершина &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; не видна, то отрезок &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; пересекает несколько отрезков, лежащих перед &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt;, а значит и ближайший. В противном случае все пересекаемые лучом отрезки лежат за вершиной &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; и пересечения отрезка &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; с ближайшим отрезком не будет. Вне зависимости от видимости вершины, необходимо изменить статус заметающего луча. Для этого необходимо удалить из статуса все отрезки, которые заканчиваются вершине &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; (лежат слева от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;) и добавить все отрезки, которые в ней начинаются (лежат справа от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Псевдокод =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
graph buildVisibilityGraph(Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
   Set&amp;lt;Vertex&amp;gt; vertices = getVertices(segments)       //получаем все вершины препятствий&lt;br /&gt;
   graph visibilityGraph(vertices)                    //изначально в графе только вершины&lt;br /&gt;
   for Vertex v in vertices                           //для каждой вершины&lt;br /&gt;
      for Vertex w in getVisibleVertices(v, segments) //добавляем в граф все видимые из нее вершины&lt;br /&gt;
         visibilityGraph.addEdge(v, w)&lt;br /&gt;
   return visibilityGraph&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Здесь функция getVisibleVertices(&amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;) возвращает все видимые из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вершины и выглядит так:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Set&amp;lt;Vertex&amp;gt; getVisibleVertices(Vertex v, Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
   Set&amp;lt;Vertex&amp;gt; answer&lt;br /&gt;
// Инициализируем статус&lt;br /&gt;
   for Segment s in segments&lt;br /&gt;
      if intersection s and ray from v to up exists&lt;br /&gt;
         status.add(s)&lt;br /&gt;
// Инициализируем множество вершин, которые нужно рассматривать&lt;br /&gt;
   for Point w in segments&lt;br /&gt;
      if w.x &amp;gt;= v.x&lt;br /&gt;
         currentVertices.add(w)&lt;br /&gt;
   sort(currentVertices) by angle&lt;br /&gt;
// Для каждой вершины проверяем, видима ли она и обновляем статус&lt;br /&gt;
   for Point w in currentVertices&lt;br /&gt;
      if intersection vw and status.closest not exists&lt;br /&gt;
         answer.add(w)&lt;br /&gt;
      delete from status all segments ending in w&lt;br /&gt;
      add in status all segments beginning in w&lt;br /&gt;
   return answer&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
В качестве статуса нужно использовать структуру данных, позволяющую добавлять и удалять из нее отрезки за &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; и извлекать минимум за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt;. В этом случае достигается асимптотика &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;, так как для каждой из &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; точек выполняется сортировка(&amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;), обновление статуса (суммарно &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, так как каждый отрезок добавляется и удаляется из статуса только один раз) и запросы ближайшего отрезка (&amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; на точку, то есть &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;). &lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zamrefr1.png|250px|thumb|right|Обновление статуса заметающего луча: добавляем ребра &amp;lt;tex&amp;gt; w_1 w_5 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; w_1 w_2 &amp;lt;/tex&amp;gt; в статус]]&lt;br /&gt;
[[Файл:Zamrefr2.png|250px|thumb|right|Добавляем ребра &amp;lt;tex&amp;gt; w_3 w_2 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; w_3 w_4 &amp;lt;/tex&amp;gt; в статус]]&lt;br /&gt;
[[Файл:Zamrefr3.png|250px|thumb|right|Удаляем ребра &amp;lt;tex&amp;gt; w_3 w_2 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; w_1 w_2 &amp;lt;/tex&amp;gt; из статуса]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Overmars and Welzl’s Algorithm &amp;lt;tex&amp;gt; O(n ^ 2) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
[http://igitur-archive.library.uu.nl/math/2006-1214-201604/overmars_88_new_methods.pdf visibility graph при помощи rotation tree]&lt;br /&gt;
&lt;br /&gt;
C помощью [http://bit.ly/1eEqTzk rotation tree] можно достичь асимптотики &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Motion planning ==&lt;br /&gt;
[[Файл:mink.png|200px|thumb|left|Изменяем препятствия]]&lt;br /&gt;
[[Файл:mink2.png|400px|thumb|right|Ищем путь для точки]]&lt;br /&gt;
Рассмотрим задачу нахождения кратчайшего пути, когда движимый объект {{---}} это выпуклый полигон. Например, робот, которого надо доставить из начальной в конечную точку.&lt;br /&gt;
&lt;br /&gt;
Если полигон вращать нельзя, задачу сводится к движению точки так: выбирается точка на полигоне, которая принимается за начало координат. В такой системе координат для каждого препятствия считается [[Сумма Минковского (определение, вычисление)|сумма Минковского]] с полигоном. Получаются бОльшие препятствия, но теперь достаточно двигать выбранную точку, что было описано выше.&lt;br /&gt;
&lt;br /&gt;
Если полигон можно вращать, задача нахождения ''кратчайшего'' пути становится достаточно ресурсоёмка, поэтому обычно рассматривают задачу нахождения какого-нибудь пути между конечными точками.&lt;br /&gt;
&lt;br /&gt;
Первый шаг решения этой задачи совпадает с предыдущим случаем: выберем точку и построим [[Сумма Минковского (определение, вычисление)|сумму Минковского]] препятствий с полигоном. Рассмотрим малый угол &amp;lt;tex&amp;gt; \epsilon &amp;lt;/tex&amp;gt;. Представим, что поворот полигона на этот угол {{---}} это движение вверх-вниз между слоями, на каждом из которых посчитана сумма Минковского с полигоном, повернутым на этот угол.&lt;br /&gt;
&lt;br /&gt;
На каждом слое построим трапецоидную карту и граф, как описано в [[Visibility graph и motion planning#Нахождение пути между точками с препятствиями|начале]]. Если [[Пересечение многоугольников (PSLG overlaying)|пересечь]] соседние слои и добавить между их графами ребра, получится один большой граф, в котором ищется кратчайший путь.&lt;br /&gt;
&lt;br /&gt;
При таком подходе может возникнуть ошибка при пересечении слоев: на каждом слое состояния будут допустимые, а осуществить поворот физически будет невозможно. Обычно, эту проблему решают двумя способами: измельчением угла поворота и изначальным сглаживанием углов полигона. Первый способ повышает не только точность решения, но и вычислительную сложность задачи. Второй подход практически исключает возможность нахождения пути, когда его нет, но повышает вероятность &amp;quot;ненахождения&amp;quot; пути, когда он есть.&lt;br /&gt;
&lt;br /&gt;
== Источники ==&lt;br /&gt;
* 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&lt;br /&gt;
* [http://www.academia.edu/2845047/3D_Visibility_Graph статья] про visibility graphs на academia.edu&lt;br /&gt;
* [http://habrahabr.ru/post/199256/ Хабр]&lt;br /&gt;
[[Категория: Вычислительная геометрия]]&lt;br /&gt;
&lt;br /&gt;
== Ссылки ==&lt;br /&gt;
* Моя [https://github.com/Igorjan94/cg/blob/master/include/cg/algorithms/visibilityGraph.h реализация] алгоритма за &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;. Далеко от идеального, но работает&lt;/div&gt;</summary>
		<author><name>Igorjan94</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44835</id>
		<title>Visibility graph и motion planning</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44835"/>
				<updated>2015-02-10T20:10:51Z</updated>
		
		<summary type="html">&lt;p&gt;Igorjan94: подписи к картинкам&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Нахождение любого пути между точками с препятствиями ==&lt;br /&gt;
{|align=&amp;quot;right&amp;quot;&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
|[[Файл:trap.png|200px|thumb|right|Путь с препятствиями через трапецоидную карту]]&lt;br /&gt;
|[[Файл:notShort.png|300px|thumb|right|Такой путь не самый короткий]]&lt;br /&gt;
|}&lt;br /&gt;
Для начала рассмотрим движение материальной точки. Случай, когда размером и формой движимого объекта пренебречь нельзя, будет рассмотрен [[Visibility graph и motion planning#Motion planning|позднее]]. &lt;br /&gt;
&lt;br /&gt;
Эту задачу можно решить с помощью [[Трапецоидная карта | трапецоидной карты]]. По ней строится граф, ребра которого соединяют центры трапедоидов, а также начальную и конечную вершины с серединами вертикальных сторон трапецоидов. В таком графе ищется путь между начальной и конечной вершинами.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм работает за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; и за линейное количество памяти и хорошо подходит для нахождения какого-нибудь пути между парой данных вершин. Но если нужно найти кратчайший путь, этот алгоритм не подходит, хоть и работает быстро. Однако, решения нахождения кратчайшего пути в лучшем случае работают за &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; времени и памяти (здесь и далее &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество всех вершин).&lt;br /&gt;
&lt;br /&gt;
== Нахождение кратчайшего пути между точками с препятствиями ==&lt;br /&gt;
=== Visibility graph ===&lt;br /&gt;
Рассмотрим точное решение нахождения кратчайшего пути на плоскости между двумя точками с полигональными препятствиями с помощью построения графа видимости. После его построения, как и в случае с трапецоидной картой, кратчайший путь ищется любым стандартным алгоритмом поиска (например, алгоритмом [[Алгоритм Дейкстры|Дейкстры]] или [[Алгоритм A*|A*]]).&lt;br /&gt;
&lt;br /&gt;
Для простоты рассуждений начальную и конечную вершины будем считать вершинами полигонов.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|about=О кратчайшем пути&lt;br /&gt;
|statement=&lt;br /&gt;
Любой кратчайший путь между двумя вершинами с полигональными препятствиями представляет собой ломаную, вершины которой {{---}} вершины полигонов.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:short.png|150px|thumb|right|Short cut]]&lt;br /&gt;
Пусть кратчайший путь {{---}} не ломаная. В таком случае, на пути существует такая точка &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, которая не принадлежит ни одному прямому отрезку. Это означает, что существует &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестность точки &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, в которую не попадает ни одно препятствие (случай, когда точка попала на ребро рассматривается аналогично). В таком случае, подпуть, который находится внутри &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности, по неравенству треугольника может быть сокращён по хорде, соединяющий точки пересечения границы &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности с путем. Раз часть пути может быть уменьшена, значит и весь путь может быть уменьшен, а значит исходное предположение некорректно.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
Говорят, что вершина &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; ''видна'' (англ. mutually visible) из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;, если отрезок &amp;lt;tex&amp;gt; uv &amp;lt;/tex&amp;gt; не пересекает ни одного препятствия.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
''Граф видимости'' (англ. visibility graph) {{---}} граф, вершины которого {{---}} вершины полигонов. Между вершинами &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; существует ребро, если из &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; видна &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
В худшем случае в таком графе может быть &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; ребер. Однако по некоторым ребрам кратчайший путь точно не пройдет, и такие ребра из графа можно удалить.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
[[Файл:edgeToDelete.png|150px|thumb|right|Удаляем &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Если существуют вершины &amp;lt;tex&amp;gt; A, B, C &amp;lt;/tex&amp;gt; одного препятствия и вершина &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; такая, что поворот &amp;lt;tex&amp;gt; DBA &amp;lt;/tex&amp;gt; не совпадает с поворотом &amp;lt;tex&amp;gt; DBC &amp;lt;/tex&amp;gt;, то ребро &amp;lt;tex&amp;gt; DB &amp;lt;/tex&amp;gt; не принадлежит кратчайшему пути и его можно удалить из графа. (См. поясняющую картинку справа)&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:edgeNotToDelete.png|200px|thumb|right|Не удаляем &amp;lt;tex&amp;gt; BS &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Путь проходящий через ребро &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt; будет длиннее, чем через соседей точки &amp;lt;tex&amp;gt; B &amp;lt;/tex&amp;gt;, так как по неравенству треугольника &amp;lt;tex&amp;gt; AB + BD &amp;gt; AD &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
По доказанным леммам любое ребро кратчайшего пути содержится в графе. Таким образом, для нахождения кратчайшего пути осталось найти кратчайший путь в этом графе от начальной до конечной вершины.&lt;br /&gt;
&lt;br /&gt;
=== Построение visibility графа ===&lt;br /&gt;
==== Наивный алгоритм. &amp;lt;tex&amp;gt; O(n ^ 3) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
Для каждой пары вершин проверяем, можно ли добавить ребро между ними, то есть нет ли пересечений с полигонами. &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; пар вершин и &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; ребер, то есть &amp;lt;tex&amp;gt; O(n^3) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Lee’s Algorithm. &amp;lt;tex&amp;gt; O(n ^ 2 \log n) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
{|&lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zam.png|300px|thumb|left|Заметание плоскости вращающимся лучом]]&lt;br /&gt;
Однако можно это сделать за &amp;lt;tex&amp;gt; O(n ^ 2 \log  n) &amp;lt;/tex&amp;gt;. Идея алгоритма проста: для каждой вершины найдем видимые из нее вершины. Если научиться делать это за &amp;lt;tex&amp;gt; O(n \log  n) &amp;lt;/tex&amp;gt;, задача решена, так как всего точек &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для каждой вершины будем рассматривать только правую половину плоскости, так как ребра, которые должны идти в левую половину, будут исходить из вершин, для которых текущая вершина будет справа.&lt;br /&gt;
&lt;br /&gt;
Переформулируем задачу. Дано: точка &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и множество отрезков {{---}} ребер препятствий. &lt;br /&gt;
Найти: множество концов отрезков, видимых из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для решения этой задачи будем использовать заметающий луч с началом в точке &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Его статусом будут отрезки, которые его пересекают, упорядоченные по возрастанию расстояния от точки &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; до точки пересечения. Точками событий будут концы отрезков. &lt;br /&gt;
&lt;br /&gt;
Пустим луч из рассматриваемой вершины &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вертикально вверх и добавим в статус все отрезки, которые он пересекает, по увеличению расстояния до них. Теперь будем рассматривать точки &amp;lt;tex&amp;gt; w \in V &amp;lt;/tex&amp;gt; в порядке сортировки по углу между &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и вертикальной полуосью &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt;. При таком обходе проверка видимости вершины будет выполняться за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;, так как достаточно проверить пересечение с отрезком, первым в статусе. Действительно, если вершина не видна, то отрезок &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; пересекает несколько отрезков, лежащих перед &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt;, а значит и ближайший, то есть первый в статусе. В противном случае все пересекаемые лучом отрезки лежат за вершиной &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; и пересечения отрезка &amp;lt;tex&amp;gt; uw &amp;lt;/tex&amp;gt; с ближайшим отрезком в статусе не будет. Вне зависимости от видимости вершины, необходимо изменить статус заметающего луча. Для этого необходимо удалить из статуса все отрезки, которые заканчиваются вершине &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; (лежат слева от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;) и добавить все отрезки, которые в ней начинаются (лежат справа от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Псевдокод =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
graph buildVisibilityGraph(Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
   Set&amp;lt;Vertex&amp;gt; vertices = getVertices(segments)       //получаем все вершины препятствий&lt;br /&gt;
   graph visibilityGraph(vertices)                    //изначально в графе только вершины&lt;br /&gt;
   for Vertex v in vertices                           //для каждой вершины&lt;br /&gt;
      for Vertex w in getVisibleVertices(v, segments) //добавляем в граф все видимые из нее вершины&lt;br /&gt;
         visibilityGraph.addEdge(v, w)&lt;br /&gt;
   return visibilityGraph&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Здесь функция getVisibleVertices(&amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;) возвращает все видимые из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вершины и выглядит так:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Set&amp;lt;Vertex&amp;gt; getVisibleVertices(vertex v, set&amp;lt;segment&amp;gt; segments)&lt;br /&gt;
   Set&amp;lt;Vertex&amp;gt; answer&lt;br /&gt;
// Инициализируем статус&lt;br /&gt;
   for segment s in segments&lt;br /&gt;
      if intersection s and ray from v to up exists&lt;br /&gt;
         status.add(s)&lt;br /&gt;
// Инициализируем множество вершин, которые нужно рассматривать&lt;br /&gt;
   for point w in segments&lt;br /&gt;
      if w.x &amp;gt;= v.x&lt;br /&gt;
         currentVertices.add(w)&lt;br /&gt;
   sort(currentVertices) by angle&lt;br /&gt;
// Для каждой вершины проверяем, видима ли она и обновляем статус&lt;br /&gt;
   for w in currentVertices&lt;br /&gt;
      if intersection vw and status.first not exists&lt;br /&gt;
         answer.add(w)&lt;br /&gt;
      delete from status all edges ending in w&lt;br /&gt;
      add in status all edges beginning in w&lt;br /&gt;
   return answer&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
В качестве статуса нужно использовать структуру данных, позволяющую добавлять и удалять из нее отрезки за &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; и извлекать минимум за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt;. В этом случае достигается асимптотика &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;, так как для каждой из &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; точек выполняется сортировка(&amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;), обновление статуса (суммарно &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, так как каждый отрезок добавляется и удаляется из статуса только один раз) и запросы ближайшего отрезка (&amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; на точку, то есть &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;). &lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zamrefr1.png|250px|thumb|right|Обновление статуса заметающего луча: добавляем ребра &amp;lt;tex&amp;gt; w_1 w_5 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; w_1 w_2 &amp;lt;/tex&amp;gt; в статус]]&lt;br /&gt;
[[Файл:Zamrefr2.png|250px|thumb|right|Добавляем ребра &amp;lt;tex&amp;gt; w_3 w_2 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; w_3 w_4 &amp;lt;/tex&amp;gt; в статус]]&lt;br /&gt;
[[Файл:Zamrefr3.png|250px|thumb|right|Удаляем ребра &amp;lt;tex&amp;gt; w_3 w_2 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; w_1 w_2 &amp;lt;/tex&amp;gt; из статуса]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Overmars and Welzl’s Algorithm &amp;lt;tex&amp;gt; O(n ^ 2) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
[http://igitur-archive.library.uu.nl/math/2006-1214-201604/overmars_88_new_methods.pdf visibility graph при помощи rotation tree]&lt;br /&gt;
&lt;br /&gt;
C помощью [http://bit.ly/1eEqTzk rotation tree] можно достичь асимптотики &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Motion planning ==&lt;br /&gt;
[[Файл:mink.png|200px|thumb|left|Изменяем препятствия]]&lt;br /&gt;
[[Файл:mink2.png|400px|thumb|right|Ищем путь для точки]]&lt;br /&gt;
Рассмотрим задачу нахождения кратчайшего пути, когда движимый объект {{---}} это выпуклый полигон. Например, робот, которого надо доставить из начальной в конечную точку.&lt;br /&gt;
&lt;br /&gt;
Если полигон вращать нельзя, задачу сводится к движению точки так: выбирается точка на полигоне, которая принимается за начало координат. В такой системе координат для каждого препятствия считается [[Сумма Минковского (определение, вычисление)|сумма Минковского]] с полигоном. Получаются бОльшие препятствия, но теперь достаточно двигать выбранную точку, что было описано выше.&lt;br /&gt;
&lt;br /&gt;
Если полигон можно вращать, задача нахождения ''кратчайшего'' пути становится достаточно ресурсоёмка, поэтому обычно рассматривают задачу нахождения какого-нибудь пути между конечными точками.&lt;br /&gt;
&lt;br /&gt;
Первый шаг решения этой задачи совпадает с предыдущим случаем: выберем точку и построим [[Сумма Минковского (определение, вычисление)|сумму Минковского]] препятствий с полигоном. Рассмотрим малый угол &amp;lt;tex&amp;gt; \epsilon &amp;lt;/tex&amp;gt;. Представим, что поворот полигона на этот угол {{---}} это движение вверх-вниз между слоями, на каждом из которых посчитана сумма Минковского с полигоном, повернутым на этот угол.&lt;br /&gt;
&lt;br /&gt;
На каждом слое построим трапецоидную карту и граф, как описано в [[Visibility graph и motion planning#Нахождение пути между точками с препятствиями|начале]]. Если [[Пересечение многоугольников (PSLG overlaying)|пересечь]] соседние слои и добавить между их графами ребра, получится один большой граф, в котором ищется кратчайший путь.&lt;br /&gt;
&lt;br /&gt;
При таком подходе может возникнуть ошибка при пересечении слоев: на каждом слое состояния будут допустимые, а осуществить поворот физически будет невозможно. Обычно, эту проблему решают двумя способами: измельчением угла поворота и изначальным сглаживанием углов полигона. Первый способ повышает не только точность решения, но и вычислительную сложность задачи. Второй подход практически исключает возможность нахождения пути, когда его нет, но повышает вероятность &amp;quot;ненахождения&amp;quot; пути, когда он есть.&lt;br /&gt;
&lt;br /&gt;
== Источники ==&lt;br /&gt;
* 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&lt;br /&gt;
* [http://www.academia.edu/2845047/3D_Visibility_Graph статья] про visibility graphs на academia.edu&lt;br /&gt;
* [http://habrahabr.ru/post/199256/ Хабр]&lt;br /&gt;
[[Категория: Вычислительная геометрия]]&lt;br /&gt;
&lt;br /&gt;
== Ссылки ==&lt;br /&gt;
* Моя [https://github.com/Igorjan94/cg/blob/master/include/cg/algorithms/visibilityGraph.h реализация] алгоритма за &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;. Далеко от идеального, но работает&lt;/div&gt;</summary>
		<author><name>Igorjan94</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44834</id>
		<title>Visibility graph и motion planning</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44834"/>
				<updated>2015-02-10T19:58:23Z</updated>
		
		<summary type="html">&lt;p&gt;Igorjan94: Отмена правки 44832 участника Igorjan94 (обсуждение)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Нахождение любого пути между точками с препятствиями ==&lt;br /&gt;
{|align=&amp;quot;right&amp;quot;&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
|[[Файл:trap.png|200px|thumb|right|Путь с препятствиями через трапецоидную карту]]&lt;br /&gt;
|[[Файл:notShort.png|300px|thumb|right|Такой путь не самый короткий]]&lt;br /&gt;
|}&lt;br /&gt;
Для начала рассмотрим движение материальной точки. Случай, когда размером и формой движимого объекта пренебречь нельзя, будет рассмотрен [[Visibility graph и motion planning#Motion planning|позднее]]. &lt;br /&gt;
&lt;br /&gt;
Эту задачу можно решить с помощью [[Трапецоидная карта | трапецоидной карты]]. По ней строится граф, ребра которого соединяют центры трапедоидов, а также начальную и конечную вершины с серединами вертикальных сторон трапецоидов. В таком графе ищется путь между начальной и конечной вершинами.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм работает за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; и за линейное количество памяти и хорошо подходит для нахождения какого-нибудь пути между парой данных вершин. Но если нужно найти кратчайший путь, этот алгоритм не подходит, хоть и работает быстро. Однако, решения нахождения кратчайшего пути в лучшем случае работают за &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; времени и памяти (здесь и далее &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество всех вершин).&lt;br /&gt;
&lt;br /&gt;
== Нахождение кратчайшего пути между точками с препятствиями ==&lt;br /&gt;
=== Visibility graph ===&lt;br /&gt;
Рассмотрим точное решение нахождения кратчайшего пути на плоскости между двумя точками с полигональными препятствиями с помощью построения графа видимости. После его построения, как и в случае с трапецоидной картой, кратчайший путь ищется любым стандартным алгоритмом поиска (например, алгоритмом [[Алгоритм Дейкстры|Дейкстры]] или [[Алгоритм A*|A*]]).&lt;br /&gt;
&lt;br /&gt;
Для простоты рассуждений начальную и конечную вершины будем считать вершинами полигонов.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|about=О кратчайшем пути&lt;br /&gt;
|statement=&lt;br /&gt;
Любой кратчайший путь между двумя вершинами с полигональными препятствиями представляет собой ломаную, вершины которой {{---}} вершины полигонов.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:short.png|150px|thumb|right|Short cut]]&lt;br /&gt;
Пусть кратчайший путь {{---}} не ломаная. В таком случае, на пути существует такая точка &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, которая не принадлежит ни одному прямому отрезку. Это означает, что существует &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестность точки &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, в которую не попадает ни одно препятствие (случай, когда точка попала на ребро рассматривается аналогично). В таком случае, подпуть, который находится внутри &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности, по неравенству треугольника может быть сокращён по хорде, соединяющий точки пересечения границы &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности с путем. Раз часть пути может быть уменьшена, значит и весь путь может быть уменьшен, а значит исходное предположение некорректно.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
Говорят, что вершина &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; ''видна'' (англ. mutually visible) из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;, если отрезок &amp;lt;tex&amp;gt; uv &amp;lt;/tex&amp;gt; не пересекает ни одного препятствия.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
''Граф видимости'' (англ. visibility graph) {{---}} граф, вершины которого {{---}} вершины полигонов. Между вершинами &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; существует ребро, если из &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; видна &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
В худшем случае в таком графе может быть &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; ребер. Однако по некоторым ребрам кратчайший путь точно не пройдет, и такие ребра из графа можно удалить.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
[[Файл:edgeToDelete.png|150px|thumb|right|Удаляем &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Если существуют вершины &amp;lt;tex&amp;gt; A, B, C &amp;lt;/tex&amp;gt; одного препятствия и вершина &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; такая, что поворот &amp;lt;tex&amp;gt; DBA &amp;lt;/tex&amp;gt; не совпадает с поворотом &amp;lt;tex&amp;gt; DBC &amp;lt;/tex&amp;gt;, то ребро &amp;lt;tex&amp;gt; DB &amp;lt;/tex&amp;gt; не принадлежит кратчайшему пути и его можно удалить из графа. (См. поясняющую картинку справа)&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:edgeNotToDelete.png|200px|thumb|right|Не удаляем &amp;lt;tex&amp;gt; BS &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Путь проходящий через ребро &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt; будет длиннее, чем через соседей точки &amp;lt;tex&amp;gt; B &amp;lt;/tex&amp;gt;, так как по неравенству треугольника &amp;lt;tex&amp;gt; AB + BD &amp;gt; AD &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
По доказанным леммам любое ребро кратчайшего пути содержится в графе. Таким образом, для нахождения кратчайшего пути осталось найти кратчайший путь в этом графе от начальной до конечной вершины.&lt;br /&gt;
&lt;br /&gt;
=== Построение visibility графа ===&lt;br /&gt;
==== Наивный алгоритм. &amp;lt;tex&amp;gt; O(n ^ 3) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
Для каждой пары вершин проверяем, можно ли добавить ребро между ними, то есть нет ли пересечений с полигонами. &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; пар вершин и &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; ребер, то есть &amp;lt;tex&amp;gt; O(n^3) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Lee’s Algorithm. &amp;lt;tex&amp;gt; O(n ^ 2 \log n) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
{|&lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zam.png|300px|thumb|left|Заметание плоскости вращающимся лучом]]&lt;br /&gt;
Однако можно это сделать за &amp;lt;tex&amp;gt; O(n ^ 2 \log  n) &amp;lt;/tex&amp;gt;. Идея алгоритма проста: для каждой вершины найдем видимые из нее вершины. Если научиться делать это за &amp;lt;tex&amp;gt; O(n \log  n) &amp;lt;/tex&amp;gt;, задача решена, так как всего точек &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для каждой вершины будем рассматривать только правую половину плоскости, так как ребра, которые должны идти в левую половину, будут исходить из вершин, для которых текущая вершина будет справа.&lt;br /&gt;
&lt;br /&gt;
Переформулируем задачу. Дано: точка &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и множество отрезков {{---}} ребер препятствий. &lt;br /&gt;
Найти: множество концов отрезков, видимых из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для решения этой задачи будем использовать заметающий луч с началом в точке &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Его статусом будут отрезки, которые его пересекают, упорядоченные по возрастанию расстояния от точки &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; до точки пересечения. Точками событий будут концы отрезков. &lt;br /&gt;
&lt;br /&gt;
Пустим луч из рассматриваемой вершины &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вертикально вверх и добавим в статус все отрезки, которые он пересекает, по увеличению расстояния до них. Теперь будем рассматривать точки &amp;lt;tex&amp;gt; w \in V &amp;lt;/tex&amp;gt; в порядке сортировки по углу между &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и вертикальной полуосью &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt;. При таком обходе проверка видимости вершины будет выполняться за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;, так как достаточно проверить пересечение с отрезком, первым в статусе. Действительно, если вершина не видна, то отрезок &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; пересекает несколько отрезков, лежащих перед &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt;, а значит и ближайший, то есть первый в статусе. В противном случае все пересекаемые лучом отрезки лежат за вершиной &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; и пересечения отрезка &amp;lt;tex&amp;gt; uw &amp;lt;/tex&amp;gt; с ближайшим отрезком в статусе не будет. Вне зависимости от видимости вершины, необходимо изменить статус заметающего луча. Для этого необходимо удалить из статуса все отрезки, которые заканчиваются вершине &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; (лежат слева от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;) и добавить все отрезки, которые в ней начинаются (лежат справа от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Псевдокод =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
graph buildVisibilityGraph(Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
   Set&amp;lt;Vertex&amp;gt; vertices = getVertices(segments)       //получаем все вершины препятствий&lt;br /&gt;
   graph visibilityGraph(vertices)                    //изначально в графе только вершины&lt;br /&gt;
   for Vertex v in vertices                           //для каждой вершины&lt;br /&gt;
      for Vertex w in getVisibleVertices(v, segments) //добавляем в граф все видимые из нее вершины&lt;br /&gt;
         visibilityGraph.addEdge(v, w)&lt;br /&gt;
   return visibilityGraph&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Здесь функция getVisibleVertices(&amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;) возвращает все видимые из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вершины и выглядит так:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Set&amp;lt;Vertex&amp;gt; getVisibleVertices(vertex v, set&amp;lt;segment&amp;gt; segments)&lt;br /&gt;
   Set&amp;lt;Vertex&amp;gt; answer&lt;br /&gt;
// Инициализируем статус&lt;br /&gt;
   for segment s in segments&lt;br /&gt;
      if intersection s and ray from v to up exists&lt;br /&gt;
         status.add(s)&lt;br /&gt;
// Инициализируем множество вершин, которые нужно рассматривать&lt;br /&gt;
   for point w in segments&lt;br /&gt;
      if w.x &amp;gt;= v.x&lt;br /&gt;
         currentVertices.add(w)&lt;br /&gt;
   sort(currentVertices) by angle&lt;br /&gt;
// Для каждой вершины проверяем, видима ли она и обновляем статус&lt;br /&gt;
   for w in currentVertices&lt;br /&gt;
      if intersection vw and status.first not exists&lt;br /&gt;
         answer.add(w)&lt;br /&gt;
      delete from status all edges ending in w&lt;br /&gt;
      add in status all edges beginning in w&lt;br /&gt;
   return answer&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
В качестве статуса нужно использовать структуру данных, позволяющую добавлять и удалять из нее отрезки за &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; и извлекать минимум за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt;. В этом случае достигается асимптотика &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;, так как для каждой из &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; точек выполняется сортировка(&amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;), обновление статуса (суммарно &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, так как каждый отрезок добавляется и удаляется из статуса только один раз) и запросы ближайшего отрезка (&amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; на точку, то есть &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;). &lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zamrefr1.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr2.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr3.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Overmars and Welzl’s Algorithm &amp;lt;tex&amp;gt; O(n ^ 2) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
[http://igitur-archive.library.uu.nl/math/2006-1214-201604/overmars_88_new_methods.pdf visibility graph при помощи rotation tree]&lt;br /&gt;
&lt;br /&gt;
C помощью [http://bit.ly/1eEqTzk rotation tree] можно достичь асимптотики &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Motion planning ==&lt;br /&gt;
[[Файл:mink.png|200px|thumb|left|Изменяем препятствия]]&lt;br /&gt;
[[Файл:mink2.png|400px|thumb|right|Ищем путь для точки]]&lt;br /&gt;
Рассмотрим задачу нахождения кратчайшего пути, когда движимый объект {{---}} это выпуклый полигон. Например, робот, которого надо доставить из начальной в конечную точку.&lt;br /&gt;
&lt;br /&gt;
Если полигон вращать нельзя, задачу сводится к движению точки так: выбирается точка на полигоне, которая принимается за начало координат. В такой системе координат для каждого препятствия считается [[Сумма Минковского (определение, вычисление)|сумма Минковского]] с полигоном. Получаются бОльшие препятствия, но теперь достаточно двигать выбранную точку, что было описано выше.&lt;br /&gt;
&lt;br /&gt;
Если полигон можно вращать, задача нахождения ''кратчайшего'' пути становится достаточно ресурсоёмка, поэтому обычно рассматривают задачу нахождения какого-нибудь пути между конечными точками.&lt;br /&gt;
&lt;br /&gt;
Первый шаг решения этой задачи совпадает с предыдущим случаем: выберем точку и построим [[Сумма Минковского (определение, вычисление)|сумму Минковского]] препятствий с полигоном. Рассмотрим малый угол &amp;lt;tex&amp;gt; \epsilon &amp;lt;/tex&amp;gt;. Представим, что поворот полигона на этот угол {{---}} это движение вверх-вниз между слоями, на каждом из которых посчитана сумма Минковского с полигоном, повернутым на этот угол.&lt;br /&gt;
&lt;br /&gt;
На каждом слое построим трапецоидную карту и граф, как описано в [[Visibility graph и motion planning#Нахождение пути между точками с препятствиями|начале]]. Если [[Пересечение многоугольников (PSLG overlaying)|пересечь]] соседние слои и добавить между их графами ребра, получится один большой граф, в котором ищется кратчайший путь.&lt;br /&gt;
&lt;br /&gt;
При таком подходе может возникнуть ошибка при пересечении слоев: на каждом слое состояния будут допустимые, а осуществить поворот физически будет невозможно. Обычно, эту проблему решают двумя способами: измельчением угла поворота и изначальным сглаживанием углов полигона. Первый способ повышает не только точность решения, но и вычислительную сложность задачи. Второй подход практически исключает возможность нахождения пути, когда его нет, но повышает вероятность &amp;quot;ненахождения&amp;quot; пути, когда он есть.&lt;br /&gt;
&lt;br /&gt;
== Источники ==&lt;br /&gt;
* 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&lt;br /&gt;
* [http://www.academia.edu/2845047/3D_Visibility_Graph статья] про visibility graphs на academia.edu&lt;br /&gt;
* [http://habrahabr.ru/post/199256/ Хабр]&lt;br /&gt;
[[Категория: Вычислительная геометрия]]&lt;br /&gt;
&lt;br /&gt;
== Ссылки ==&lt;br /&gt;
* Моя [https://github.com/Igorjan94/cg/blob/master/include/cg/algorithms/visibilityGraph.h реализация] алгоритма за &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;. Далеко от идеального, но работает&lt;/div&gt;</summary>
		<author><name>Igorjan94</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44832</id>
		<title>Visibility graph и motion planning</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44832"/>
				<updated>2015-02-10T19:56:55Z</updated>
		
		<summary type="html">&lt;p&gt;Igorjan94: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Нахождение любого пути между точками с препятствиями ==&lt;br /&gt;
{|align=&amp;quot;right&amp;quot;&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
|[[Файл:trap.png|200px|thumb|right|Путь с препятствиями через трапецоидную карту]]&lt;br /&gt;
|[[Файл:notShort.png|300px|thumb|right|Такой путь не самый короткий]]&lt;br /&gt;
|}&lt;br /&gt;
Для начала рассмотрим движение материальной точки. Случай, когда размером и формой движимого объекта пренебречь нельзя, будет рассмотрен [[Visibility graph и motion planning#Motion planning|позднее]]. &lt;br /&gt;
&lt;br /&gt;
Эту задачу можно решить с помощью [[Трапецоидная карта | трапецоидной карты]]. По ней строится граф, ребра которого соединяют центры трапедоидов, а также начальную и конечную вершины с серединами вертикальных сторон трапецоидов. В таком графе ищется путь между начальной и конечной вершинами.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм работает за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; и за линейное количество памяти и хорошо подходит для нахождения какого-нибудь пути между парой данных вершин. Но если нужно найти кратчайший путь, этот алгоритм не подходит, хоть и работает быстро. Однако, решения нахождения кратчайшего пути в лучшем случае работают за &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; времени и памяти (здесь и далее &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество всех вершин).&lt;br /&gt;
&lt;br /&gt;
== Нахождение кратчайшего пути между точками с препятствиями ==&lt;br /&gt;
=== Visibility graph ===&lt;br /&gt;
Рассмотрим точное решение нахождения кратчайшего пути на плоскости между двумя точками с полигональными препятствиями с помощью построения графа видимости. После его построения, как и в случае с трапецоидной картой, кратчайший путь ищется любым стандартным алгоритмом поиска (например, алгоритмом [[Алгоритм Дейкстры|Дейкстры]] или [[Алгоритм A*|A*]]).&lt;br /&gt;
&lt;br /&gt;
Для простоты рассуждений начальную и конечную вершины будем считать вершинами полигонов.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|about=О кратчайшем пути&lt;br /&gt;
|statement=&lt;br /&gt;
Любой кратчайший путь между двумя вершинами с полигональными препятствиями представляет собой ломаную, вершины которой {{---}} вершины полигонов.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:short.png|150px|thumb|right|Short cut]]&lt;br /&gt;
Пусть кратчайший путь {{---}} не ломаная. В таком случае, на пути существует такая точка &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, которая не принадлежит ни одному прямому отрезку. Это означает, что существует &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестность точки &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, в которую не попадает ни одно препятствие (случай, когда точка попала на ребро рассматривается аналогично). В таком случае, подпуть, который находится внутри &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности, по неравенству треугольника может быть сокращён по хорде, соединяющий точки пересечения границы &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности с путем. Раз часть пути может быть уменьшена, значит и весь путь может быть уменьшен, а значит исходное предположение некорректно.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
Говорят, что вершина &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; ''видна'' (англ. mutually visible) из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;, если отрезок &amp;lt;tex&amp;gt; uv &amp;lt;/tex&amp;gt; не пересекает ни одного препятствия.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
''Граф видимости'' (англ. visibility graph) {{---}} граф, вершины которого {{---}} вершины полигонов. Между вершинами &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; существует ребро, если из &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; видна &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
В худшем случае в таком графе может быть &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; ребер. Однако по некоторым ребрам кратчайший путь точно не пройдет, и такие ребра из графа можно удалить.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
[[Файл:edgeToDelete.png|150px|thumb|right|Удаляем &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Если существуют вершины &amp;lt;tex&amp;gt; A, B, C &amp;lt;/tex&amp;gt; одного препятствия и вершина &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; такая, что поворот &amp;lt;tex&amp;gt; DBA &amp;lt;/tex&amp;gt; не совпадает с поворотом &amp;lt;tex&amp;gt; DBC &amp;lt;/tex&amp;gt;, то ребро &amp;lt;tex&amp;gt; DB &amp;lt;/tex&amp;gt; не принадлежит кратчайшему пути и его можно удалить из графа. (См. поясняющую картинку справа)&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:edgeNotToDelete.png|200px|thumb|right|Не удаляем &amp;lt;tex&amp;gt; BS &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Путь проходящий через ребро &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt; будет длиннее, чем через соседей точки &amp;lt;tex&amp;gt; B &amp;lt;/tex&amp;gt;, так как по неравенству треугольника &amp;lt;tex&amp;gt; AB + BD &amp;gt; AD &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
По доказанным леммам любое ребро кратчайшего пути содержится в графе. Таким образом, для нахождения кратчайшего пути осталось найти кратчайший путь в этом графе от начальной до конечной вершины.&lt;br /&gt;
&lt;br /&gt;
=== Построение visibility графа ===&lt;br /&gt;
==== Наивный алгоритм. &amp;lt;tex&amp;gt; O(n ^ 3) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
Для каждой пары вершин проверяем, можно ли добавить ребро между ними, то есть нет ли пересечений с полигонами. &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; пар вершин и &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; ребер, то есть &amp;lt;tex&amp;gt; O(n^3) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Lee’s Algorithm. &amp;lt;tex&amp;gt; O(n ^ 2 \log n) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
{|&lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zam.png|300px|thumb|left|Заметание плоскости вращающимся лучом]]&lt;br /&gt;
Однако можно это сделать за &amp;lt;tex&amp;gt; O(n ^ 2 \log  n) &amp;lt;/tex&amp;gt;. Идея алгоритма проста: для каждой вершины найдем видимые из нее вершины. Если научиться делать это за &amp;lt;tex&amp;gt; O(n \log  n) &amp;lt;/tex&amp;gt;, задача решена, так как всего точек &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для каждой вершины будем рассматривать только правую половину плоскости, так как ребра, которые должны идти в левую половину, будут исходить из вершин, для которых текущая вершина будет справа.&lt;br /&gt;
&lt;br /&gt;
Переформулируем задачу. Дано: точка &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и множество отрезков {{---}} ребер препятствий. &lt;br /&gt;
Найти: множество концов отрезков, видимых из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для решения этой задачи будем использовать заметающий луч с началом в точке &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Его статусом будут отрезки, которые его пересекают, упорядоченные по возрастанию расстояния от точки &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; до точки пересечения. Точками событий будут концы отрезков. &lt;br /&gt;
&lt;br /&gt;
Пустим луч &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; из рассматриваемой вершины &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вертикально вверх и добавим в статус все отрезки, которые он пересекает, по увеличению расстояния до них. Теперь будем рассматривать точки &amp;lt;tex&amp;gt; w \in V &amp;lt;/tex&amp;gt; в порядке сортировки по углу между &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и вертикальной полуосью &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt;. При таком обходе проверка видимости вершины будет выполняться за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;, так как достаточно проверить пересечение с отрезком, первым в статусе. Действительно, если вершина не видна, то отрезок &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; пересекает несколько отрезков, лежащих перед &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt;, а значит и ближайший, то есть первый в статусе. В противном случае все пересекаемые лучом отрезки лежат за вершиной &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; и пересечения отрезка &amp;lt;tex&amp;gt; uw &amp;lt;/tex&amp;gt; с ближайшим отрезком в статусе не будет. Вне зависимости от видимости вершины, необходимо изменить статус заметающего луча. Для этого необходимо удалить из статуса все отрезки, которые заканчиваются вершине &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; (лежат слева от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;) и добавить все отрезки, которые в ней начинаются (лежат справа от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Псевдокод =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
graph buildVisibilityGraph(Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
   Set&amp;lt;Vertex&amp;gt; vertices = getVertices(segments)       //получаем все вершины препятствий&lt;br /&gt;
   graph visibilityGraph(vertices)                    //изначально в графе только вершины&lt;br /&gt;
   for Vertex v in vertices                           //для каждой вершины&lt;br /&gt;
      for Vertex w in getVisibleVertices(v, segments) //добавляем в граф все видимые из нее вершины&lt;br /&gt;
         visibilityGraph.addEdge(v, w)&lt;br /&gt;
   return visibilityGraph&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Здесь функция getVisibleVertices(&amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;) возвращает все видимые из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вершины и выглядит так:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Set&amp;lt;Vertex&amp;gt; getVisibleVertices(vertex v, set&amp;lt;segment&amp;gt; segments)&lt;br /&gt;
   Set&amp;lt;Vertex&amp;gt; answer&lt;br /&gt;
// Инициализируем статус&lt;br /&gt;
   for segment s in segments&lt;br /&gt;
      if intersection s and ray from v to up exists&lt;br /&gt;
         status.add(s)&lt;br /&gt;
// Инициализируем множество вершин, которые нужно рассматривать&lt;br /&gt;
   for point w in segments&lt;br /&gt;
      if w.x &amp;gt;= v.x&lt;br /&gt;
         currentVertices.add(w)&lt;br /&gt;
   sort(currentVertices) by angle&lt;br /&gt;
// Для каждой вершины проверяем, видима ли она и обновляем статус&lt;br /&gt;
   for w in currentVertices&lt;br /&gt;
      if intersection vw and status.first not exists&lt;br /&gt;
         answer.add(w)&lt;br /&gt;
      delete from status all edges ending in w&lt;br /&gt;
      add in status all edges beginning in w&lt;br /&gt;
   return answer&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
В качестве статуса нужно использовать структуру данных, позволяющую добавлять и удалять из нее отрезки за &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; и извлекать минимум за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt;. В этом случае достигается асимптотика &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;, так как для каждой из &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; точек выполняется сортировка(&amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;), обновление статуса (суммарно &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, так как каждый отрезок добавляется и удаляется из статуса только один раз) и запросы ближайшего отрезка (&amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; на точку, то есть &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;). &lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zamrefr1.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr2.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr3.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Overmars and Welzl’s Algorithm &amp;lt;tex&amp;gt; O(n ^ 2) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
[http://igitur-archive.library.uu.nl/math/2006-1214-201604/overmars_88_new_methods.pdf visibility graph при помощи rotation tree]&lt;br /&gt;
&lt;br /&gt;
C помощью [http://bit.ly/1eEqTzk rotation tree] можно достичь асимптотики &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Motion planning ==&lt;br /&gt;
[[Файл:mink.png|200px|thumb|left|Изменяем препятствия]]&lt;br /&gt;
[[Файл:mink2.png|400px|thumb|right|Ищем путь для точки]]&lt;br /&gt;
Рассмотрим задачу нахождения кратчайшего пути, когда движимый объект {{---}} это выпуклый полигон. Например, робот, которого надо доставить из начальной в конечную точку.&lt;br /&gt;
&lt;br /&gt;
Если полигон вращать нельзя, задачу сводится к движению точки так: выбирается точка на полигоне, которая принимается за начало координат. В такой системе координат для каждого препятствия считается [[Сумма Минковского (определение, вычисление)|сумма Минковского]] с полигоном. Получаются бОльшие препятствия, но теперь достаточно двигать выбранную точку, что было описано выше.&lt;br /&gt;
&lt;br /&gt;
Если полигон можно вращать, задача нахождения ''кратчайшего'' пути становится достаточно ресурсоёмка, поэтому обычно рассматривают задачу нахождения какого-нибудь пути между конечными точками.&lt;br /&gt;
&lt;br /&gt;
Первый шаг решения этой задачи совпадает с предыдущим случаем: выберем точку и построим [[Сумма Минковского (определение, вычисление)|сумму Минковского]] препятствий с полигоном. Рассмотрим малый угол &amp;lt;tex&amp;gt; \epsilon &amp;lt;/tex&amp;gt;. Представим, что поворот полигона на этот угол {{---}} это движение вверх-вниз между слоями, на каждом из которых посчитана сумма Минковского с полигоном, повернутым на этот угол.&lt;br /&gt;
&lt;br /&gt;
На каждом слое построим трапецоидную карту и граф, как описано в [[Visibility graph и motion planning#Нахождение пути между точками с препятствиями|начале]]. Если [[Пересечение многоугольников (PSLG overlaying)|пересечь]] соседние слои и добавить между их графами ребра, получится один большой граф, в котором ищется кратчайший путь.&lt;br /&gt;
&lt;br /&gt;
При таком подходе может возникнуть ошибка при пересечении слоев: на каждом слое состояния будут допустимые, а осуществить поворот физически будет невозможно. Обычно, эту проблему решают двумя способами: измельчением угла поворота и изначальным сглаживанием углов полигона. Первый способ повышает не только точность решения, но и вычислительную сложность задачи. Второй подход практически исключает возможность нахождения пути, когда его нет, но повышает вероятность &amp;quot;ненахождения&amp;quot; пути, когда он есть.&lt;br /&gt;
&lt;br /&gt;
== Источники ==&lt;br /&gt;
* 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&lt;br /&gt;
* [http://www.academia.edu/2845047/3D_Visibility_Graph статья] про visibility graphs на academia.edu&lt;br /&gt;
* [http://habrahabr.ru/post/199256/ Хабр]&lt;br /&gt;
[[Категория: Вычислительная геометрия]]&lt;br /&gt;
&lt;br /&gt;
== Ссылки ==&lt;br /&gt;
* Моя [https://github.com/Igorjan94/cg/blob/master/include/cg/algorithms/visibilityGraph.h реализация] алгоритма за &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;. Далеко от идеального, но работает&lt;/div&gt;</summary>
		<author><name>Igorjan94</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44831</id>
		<title>Visibility graph и motion planning</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44831"/>
				<updated>2015-02-10T19:50:56Z</updated>
		
		<summary type="html">&lt;p&gt;Igorjan94: ' : ' -&amp;gt; ': '&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Нахождение любого пути между точками с препятствиями ==&lt;br /&gt;
{|align=&amp;quot;right&amp;quot;&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
|[[Файл:trap.png|200px|thumb|right|Путь с препятствиями через трапецоидную карту]]&lt;br /&gt;
|[[Файл:notShort.png|300px|thumb|right|Такой путь не самый короткий]]&lt;br /&gt;
|}&lt;br /&gt;
Для начала рассмотрим движение материальной точки. Случай, когда размером и формой движимого объекта пренебречь нельзя, будет рассмотрен [[Visibility graph и motion planning#Motion planning|позднее]]. &lt;br /&gt;
&lt;br /&gt;
Эту задачу можно решить с помощью [[Трапецоидная карта | трапецоидной карты]]. По ней строится граф, ребра которого соединяют центры трапедоидов, а также начальную и конечную вершины с серединами вертикальных сторон трапецоидов. В таком графе ищется путь между начальной и конечной вершинами.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм работает за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; и за линейное количество памяти и хорошо подходит для нахождения какого-нибудь пути между парой данных вершин. Но если нужно найти кратчайший путь, этот алгоритм не подходит, хоть и работает быстро. Однако, решения нахождения кратчайшего пути в лучшем случае работают за &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; времени и памяти (здесь и далее &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество всех вершин).&lt;br /&gt;
&lt;br /&gt;
== Нахождение кратчайшего пути между точками с препятствиями ==&lt;br /&gt;
=== Visibility graph ===&lt;br /&gt;
Рассмотрим точное решение нахождения кратчайшего пути на плоскости между двумя точками с полигональными препятствиями с помощью построения графа видимости. После его построения, как и в случае с трапецоидной картой, кратчайший путь ищется любым стандартным алгоритмом поиска (например, алгоритмом [[Алгоритм Дейкстры|Дейкстры]] или [[Алгоритм A*|A*]]).&lt;br /&gt;
&lt;br /&gt;
Для простоты рассуждений начальную и конечную вершины будем считать вершинами полигонов.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|about=О кратчайшем пути&lt;br /&gt;
|statement=&lt;br /&gt;
Любой кратчайший путь между двумя вершинами с полигональными препятствиями представляет собой ломаную, вершины которой {{---}} вершины полигонов.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:short.png|150px|thumb|right|Short cut]]&lt;br /&gt;
Пусть кратчайший путь {{---}} не ломаная. В таком случае, на пути существует такая точка &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, которая не принадлежит ни одному прямому отрезку. Это означает, что существует &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестность точки &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, в которую не попадает ни одно препятствие (случай, когда точка попала на ребро рассматривается аналогично). В таком случае, подпуть, который находится внутри &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности, по неравенству треугольника может быть сокращён по хорде, соединяющий точки пересечения границы &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности с путем. Раз часть пути может быть уменьшена, значит и весь путь может быть уменьшен, а значит исходное предположение некорректно.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
Говорят, что вершина &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; ''видна'' (англ. mutually visible) из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;, если отрезок &amp;lt;tex&amp;gt; uv &amp;lt;/tex&amp;gt; не пересекает ни одного препятствия.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
''Граф видимости'' (англ. visibility graph) {{---}} граф, вершины которого {{---}} вершины полигонов. Между вершинами &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; существует ребро, если из &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; видна &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
В худшем случае в таком графе может быть &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; ребер. Однако по некоторым ребрам кратчайший путь точно не пройдет, и такие ребра из графа можно удалить.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
[[Файл:edgeToDelete.png|150px|thumb|right|Удаляем &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Если существуют вершины &amp;lt;tex&amp;gt; A, B, C &amp;lt;/tex&amp;gt; одного препятствия и вершина &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; такая, что поворот &amp;lt;tex&amp;gt; DBA &amp;lt;/tex&amp;gt; не совпадает с поворотом &amp;lt;tex&amp;gt; DBC &amp;lt;/tex&amp;gt;, то ребро &amp;lt;tex&amp;gt; DB &amp;lt;/tex&amp;gt; не принадлежит кратчайшему пути и его можно удалить из графа. (См. поясняющую картинку справа)&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:edgeNotToDelete.png|200px|thumb|right|Не удаляем &amp;lt;tex&amp;gt; BS &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Путь проходящий через ребро &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt; будет длиннее, чем через соседей точки &amp;lt;tex&amp;gt; B &amp;lt;/tex&amp;gt;, так как по неравенству треугольника &amp;lt;tex&amp;gt; AB + BD &amp;gt; AD &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
По доказанным леммам любое ребро кратчайшего пути содержится в графе. Таким образом, для нахождения кратчайшего пути осталось найти кратчайший путь в этом графе от начальной до конечной вершины.&lt;br /&gt;
&lt;br /&gt;
=== Построение visibility графа ===&lt;br /&gt;
==== Наивный алгоритм. &amp;lt;tex&amp;gt; O(n ^ 3) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
Для каждой пары вершин проверяем, можно ли добавить ребро между ними, то есть нет ли пересечений с полигонами. &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; пар вершин и &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; ребер, то есть &amp;lt;tex&amp;gt; O(n^3) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Lee’s Algorithm. &amp;lt;tex&amp;gt; O(n ^ 2 \log n) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
{|&lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zam.png|300px|thumb|left|Заметание плоскости вращающимся лучом]]&lt;br /&gt;
Однако можно это сделать за &amp;lt;tex&amp;gt; O(n ^ 2 \log  n) &amp;lt;/tex&amp;gt;. Идея алгоритма проста: для каждой вершины найдем видимые из нее вершины. Если научиться делать это за &amp;lt;tex&amp;gt; O(n \log  n) &amp;lt;/tex&amp;gt;, задача решена, так как всего точек &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для каждой вершины будем рассматривать только правую половину плоскости, так как ребра, которые должны идти в левую половину, будут исходить из вершин, для которых текущая вершина будет справа.&lt;br /&gt;
&lt;br /&gt;
Переформулируем задачу. Дано: точка &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и множество отрезков {{---}} ребер препятствий. &lt;br /&gt;
Найти: множество концов отрезков, видимых из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для решения этой задачи будем использовать заметающий луч с началом в точке &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Его статусом будут отрезки, которые его пересекают, упорядоченные по возрастанию расстояния от точки &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; до точки пересечения. Точками событий будут концы отрезков. &lt;br /&gt;
&lt;br /&gt;
Пустим луч из рассматриваемой вершины &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вертикально вверх и добавим в статус все отрезки, которые он пересекает, по увеличению расстояния до них. Теперь будем рассматривать точки &amp;lt;tex&amp;gt; w \in V &amp;lt;/tex&amp;gt; в порядке сортировки по углу между &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и вертикальной полуосью &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt;. При таком обходе проверка видимости вершины будет выполняться за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;, так как достаточно проверить пересечение с отрезком, первым в статусе. Действительно, если вершина не видна, то отрезок &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; пересекает несколько отрезков, лежащих перед &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt;, а значит и ближайший, то есть первый в статусе. В противном случае все пересекаемые лучом отрезки лежат за вершиной &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; и пересечения отрезка &amp;lt;tex&amp;gt; uw &amp;lt;/tex&amp;gt; с ближайшим отрезком в статусе не будет. Вне зависимости от видимости вершины, необходимо изменить статус заметающего луча. Для этого необходимо удалить из статуса все отрезки, которые заканчиваются вершине &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; (лежат слева от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;) и добавить все отрезки, которые в ней начинаются (лежат справа от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Псевдокод =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
graph buildVisibilityGraph(Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
   Set&amp;lt;Vertex&amp;gt; vertices = getVertices(segments)       //получаем все вершины препятствий&lt;br /&gt;
   graph visibilityGraph(vertices)                    //изначально в графе только вершины&lt;br /&gt;
   for Vertex v in vertices                           //для каждой вершины&lt;br /&gt;
      for Vertex w in getVisibleVertices(v, segments) //добавляем в граф все видимые из нее вершины&lt;br /&gt;
         visibilityGraph.addEdge(v, w)&lt;br /&gt;
   return visibilityGraph&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Здесь функция getVisibleVertices(&amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;) возвращает все видимые из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вершины и выглядит так:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Set&amp;lt;Vertex&amp;gt; getVisibleVertices(vertex v, set&amp;lt;segment&amp;gt; segments)&lt;br /&gt;
   Set&amp;lt;Vertex&amp;gt; answer&lt;br /&gt;
// Инициализируем статус&lt;br /&gt;
   for segment s in segments&lt;br /&gt;
      if intersection s and ray from v to up exists&lt;br /&gt;
         status.add(s)&lt;br /&gt;
// Инициализируем множество вершин, которые нужно рассматривать&lt;br /&gt;
   for point w in segments&lt;br /&gt;
      if w.x &amp;gt;= v.x&lt;br /&gt;
         currentVertices.add(w)&lt;br /&gt;
   sort(currentVertices) by angle&lt;br /&gt;
// Для каждой вершины проверяем, видима ли она и обновляем статус&lt;br /&gt;
   for w in currentVertices&lt;br /&gt;
      if intersection vw and status.first not exists&lt;br /&gt;
         answer.add(w)&lt;br /&gt;
      delete from status all edges ending in w&lt;br /&gt;
      add in status all edges beginning in w&lt;br /&gt;
   return answer&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
В качестве статуса нужно использовать структуру данных, позволяющую добавлять и удалять из нее отрезки за &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; и извлекать минимум за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt;. В этом случае достигается асимптотика &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;, так как для каждой из &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; точек выполняется сортировка(&amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;), обновление статуса (суммарно &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, так как каждый отрезок добавляется и удаляется из статуса только один раз) и запросы ближайшего отрезка (&amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; на точку, то есть &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;). &lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zamrefr1.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr2.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr3.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Overmars and Welzl’s Algorithm &amp;lt;tex&amp;gt; O(n ^ 2) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
[http://igitur-archive.library.uu.nl/math/2006-1214-201604/overmars_88_new_methods.pdf visibility graph при помощи rotation tree]&lt;br /&gt;
&lt;br /&gt;
C помощью [http://bit.ly/1eEqTzk rotation tree] можно достичь асимптотики &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Motion planning ==&lt;br /&gt;
[[Файл:mink.png|200px|thumb|left|Изменяем препятствия]]&lt;br /&gt;
[[Файл:mink2.png|400px|thumb|right|Ищем путь для точки]]&lt;br /&gt;
Рассмотрим задачу нахождения кратчайшего пути, когда движимый объект {{---}} это выпуклый полигон. Например, робот, которого надо доставить из начальной в конечную точку.&lt;br /&gt;
&lt;br /&gt;
Если полигон вращать нельзя, задачу сводится к движению точки так: выбирается точка на полигоне, которая принимается за начало координат. В такой системе координат для каждого препятствия считается [[Сумма Минковского (определение, вычисление)|сумма Минковского]] с полигоном. Получаются бОльшие препятствия, но теперь достаточно двигать выбранную точку, что было описано выше.&lt;br /&gt;
&lt;br /&gt;
Если полигон можно вращать, задача нахождения ''кратчайшего'' пути становится достаточно ресурсоёмка, поэтому обычно рассматривают задачу нахождения какого-нибудь пути между конечными точками.&lt;br /&gt;
&lt;br /&gt;
Первый шаг решения этой задачи совпадает с предыдущим случаем: выберем точку и построим [[Сумма Минковского (определение, вычисление)|сумму Минковского]] препятствий с полигоном. Рассмотрим малый угол &amp;lt;tex&amp;gt; \epsilon &amp;lt;/tex&amp;gt;. Представим, что поворот полигона на этот угол {{---}} это движение вверх-вниз между слоями, на каждом из которых посчитана сумма Минковского с полигоном, повернутым на этот угол.&lt;br /&gt;
&lt;br /&gt;
На каждом слое построим трапецоидную карту и граф, как описано в [[Visibility graph и motion planning#Нахождение пути между точками с препятствиями|начале]]. Если [[Пересечение многоугольников (PSLG overlaying)|пересечь]] соседние слои и добавить между их графами ребра, получится один большой граф, в котором ищется кратчайший путь.&lt;br /&gt;
&lt;br /&gt;
При таком подходе может возникнуть ошибка при пересечении слоев: на каждом слое состояния будут допустимые, а осуществить поворот физически будет невозможно. Обычно, эту проблему решают двумя способами: измельчением угла поворота и изначальным сглаживанием углов полигона. Первый способ повышает не только точность решения, но и вычислительную сложность задачи. Второй подход практически исключает возможность нахождения пути, когда его нет, но повышает вероятность &amp;quot;ненахождения&amp;quot; пути, когда он есть.&lt;br /&gt;
&lt;br /&gt;
== Источники ==&lt;br /&gt;
* 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&lt;br /&gt;
* [http://www.academia.edu/2845047/3D_Visibility_Graph статья] про visibility graphs на academia.edu&lt;br /&gt;
* [http://habrahabr.ru/post/199256/ Хабр]&lt;br /&gt;
[[Категория: Вычислительная геометрия]]&lt;br /&gt;
&lt;br /&gt;
== Ссылки ==&lt;br /&gt;
* Моя [https://github.com/Igorjan94/cg/blob/master/include/cg/algorithms/visibilityGraph.h реализация] алгоритма за &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;. Далеко от идеального, но работает&lt;/div&gt;</summary>
		<author><name>Igorjan94</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44830</id>
		<title>Visibility graph и motion planning</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44830"/>
				<updated>2015-02-10T19:38:37Z</updated>
		
		<summary type="html">&lt;p&gt;Igorjan94: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Нахождение любого пути между точками с препятствиями ==&lt;br /&gt;
{|align=&amp;quot;right&amp;quot;&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
|[[Файл:trap.png|200px|thumb|right|Путь с препятствиями через трапецоидную карту]]&lt;br /&gt;
|[[Файл:notShort.png|300px|thumb|right|Такой путь не самый короткий]]&lt;br /&gt;
|}&lt;br /&gt;
Для начала рассмотрим движение материальной точки. Случай, когда размером и формой движимого объекта пренебречь нельзя, будет рассмотрен [[Visibility graph и motion planning#Motion planning|позднее]]. &lt;br /&gt;
&lt;br /&gt;
Эту задачу можно решить с помощью [[Трапецоидная карта | трапецоидной карты]]. По ней строится граф, ребра которого соединяют центры трапедоидов, а также начальную и конечную вершины с серединами вертикальных сторон трапецоидов. В таком графе ищется путь между начальной и конечной вершинами.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм работает за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; и за линейное количество памяти и хорошо подходит для нахождения какого-нибудь пути между парой данных вершин. Но если нужно найти кратчайший путь, этот алгоритм не подходит, хоть и работает быстро. Однако, решения нахождения кратчайшего пути в лучшем случае работают за &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; времени и памяти (здесь и далее &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество всех вершин).&lt;br /&gt;
&lt;br /&gt;
== Нахождение кратчайшего пути между точками с препятствиями ==&lt;br /&gt;
=== Visibility graph ===&lt;br /&gt;
Рассмотрим точное решение нахождения кратчайшего пути на плоскости между двумя точками с полигональными препятствиями с помощью построения графа видимости. После его построения, как и в случае с трапецоидной картой, кратчайший путь ищется любым стандартным алгоритмом поиска (например, алгоритмом [[Алгоритм Дейкстры|Дейкстры]] или [[Алгоритм A*|A*]]).&lt;br /&gt;
&lt;br /&gt;
Для простоты рассуждений начальную и конечную вершины будем считать вершинами полигонов.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|about=О кратчайшем пути&lt;br /&gt;
|statement=&lt;br /&gt;
Любой кратчайший путь между двумя вершинами с полигональными препятствиями представляет собой ломаную, вершины которой {{---}} вершины полигонов.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:short.png|150px|thumb|right|Short cut]]&lt;br /&gt;
Пусть кратчайший путь {{---}} не ломаная. В таком случае, на пути существует такая точка &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, которая не принадлежит ни одному прямому отрезку. Это означает, что существует &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестность точки &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, в которую не попадает ни одно препятствие (случай, когда точка попала на ребро рассматривается аналогично). В таком случае, подпуть, который находится внутри &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности, по неравенству треугольника может быть сокращён по хорде, соединяющий точки пересечения границы &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности с путем. Раз часть пути может быть уменьшена, значит и весь путь может быть уменьшен, а значит исходное предположение некорректно.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
Говорят, что вершина &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; ''видна'' (англ. mutually visible) из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;, если отрезок &amp;lt;tex&amp;gt; uv &amp;lt;/tex&amp;gt; не пересекает ни одного препятствия.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
''Граф видимости'' (англ. visibility graph) {{---}} граф, вершины которого {{---}} вершины полигонов. Между вершинами &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; существует ребро, если из &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; видна &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
В худшем случае в таком графе может быть &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; ребер. Однако по некоторым ребрам кратчайший путь точно не пройдет, и такие ребра из графа можно удалить.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
[[Файл:edgeToDelete.png|150px|thumb|right|Удаляем &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Если существуют вершины &amp;lt;tex&amp;gt; A, B, C &amp;lt;/tex&amp;gt; одного препятствия и вершина &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; такая, что поворот &amp;lt;tex&amp;gt; DBA &amp;lt;/tex&amp;gt; не совпадает с поворотом &amp;lt;tex&amp;gt; DBC &amp;lt;/tex&amp;gt;, то ребро &amp;lt;tex&amp;gt; DB &amp;lt;/tex&amp;gt; не принадлежит кратчайшему пути и его можно удалить из графа. (См. поясняющую картинку справа)&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:edgeNotToDelete.png|200px|thumb|right|Не удаляем &amp;lt;tex&amp;gt; BS &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Путь проходящий через ребро &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt; будет длиннее, чем через соседей точки &amp;lt;tex&amp;gt; B &amp;lt;/tex&amp;gt;, так как по неравенству треугольника &amp;lt;tex&amp;gt; AB + BD &amp;gt; AD &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
По доказанным леммам любое ребро кратчайшего пути содержится в графе. Таким образом, для нахождения кратчайшего пути осталось найти кратчайший путь в этом графе от начальной до конечной вершины.&lt;br /&gt;
&lt;br /&gt;
=== Построение visibility графа ===&lt;br /&gt;
==== Наивный алгоритм. &amp;lt;tex&amp;gt; O(n ^ 3) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
Для каждой пары вершин проверяем, можно ли добавить ребро между ними, то есть нет ли пересечений с полигонами. &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; пар вершин и &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; ребер, то есть &amp;lt;tex&amp;gt; O(n^3) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Lee’s Algorithm. &amp;lt;tex&amp;gt; O(n ^ 2 \log n) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
{|&lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zam.png|300px|thumb|left|Заметание плоскости вращающимся лучом]]&lt;br /&gt;
Однако можно это сделать за &amp;lt;tex&amp;gt; O(n ^ 2 \log  n) &amp;lt;/tex&amp;gt;. Идея алгоритма проста : для каждой вершины найдем видимые из нее вершины. Если научиться делать это за &amp;lt;tex&amp;gt; O(n \log  n) &amp;lt;/tex&amp;gt;, задача решена, так как всего точек &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для каждой вершины будем рассматривать только правую половину плоскости, так как ребра, которые должны идти в левую половину, будут исходить из вершин, для которых текущая вершина будет справа.&lt;br /&gt;
&lt;br /&gt;
Переформулируем задачу. Дано : точка &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и множество отрезков {{---}} ребер препятствий. &lt;br /&gt;
Найти : множество концов отрезков, видимых из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для решения этой задачи будем использовать заметающий луч с началом в точке &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Его статусом будут отрезки, которые его пересекают, упорядоченные по возрастанию расстояния от точки &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; до точки пересечения. Точками событий будут концы отрезков. &lt;br /&gt;
&lt;br /&gt;
Пустим луч из рассматриваемой вершины &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вертикально вверх и добавим в статус все отрезки, которые он пересекает, по увеличению расстояния до них. Теперь будем рассматривать точки &amp;lt;tex&amp;gt; w \in V &amp;lt;/tex&amp;gt; в порядке сортировки по углу между &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и вертикальной полуосью &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt;. При таком обходе проверка видимости вершины будет выполняться за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;, так как достаточно проверить пересечение с отрезком, первым в статусе. Действительно, если вершина не видна, то отрезок &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; пересекает несколько отрезков, лежащих перед &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt;, а значит и ближайший, то есть первый в статусе. В противном случае все пересекаемые лучом отрезки лежат за вершиной &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; и пересечения отрезка &amp;lt;tex&amp;gt; uw &amp;lt;/tex&amp;gt; с ближайшим отрезком в статусе не будет. Вне зависимости от видимости вершины, необходимо изменить статус заметающего луча. Для этого необходимо удалить из статуса все отрезки, которые заканчиваются вершине &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; (лежат слева от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;) и добавить все отрезки, которые в ней начинаются (лежат справа от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Псевдокод =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
graph buildVisibilityGraph(Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
   Set&amp;lt;Vertex&amp;gt; vertices = getVertices(segments)       //получаем все вершины препятствий&lt;br /&gt;
   graph visibilityGraph(vertices)                    //изначально в графе только вершины&lt;br /&gt;
   for Vertex v in vertices                           //для каждой вершины&lt;br /&gt;
      for Vertex w in getVisibleVertices(v, segments) //добавляем в граф все видимые из нее вершины&lt;br /&gt;
         visibilityGraph.addEdge(v, w)&lt;br /&gt;
   return visibilityGraph&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Здесь функция getVisibleVertices(&amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;) возвращает все видимые из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вершины и выглядит так:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Set&amp;lt;Vertex&amp;gt; getVisibleVertices(vertex v, set&amp;lt;segment&amp;gt; segments)&lt;br /&gt;
   Set&amp;lt;Vertex&amp;gt; answer&lt;br /&gt;
// Инициализируем статус&lt;br /&gt;
   for segment s in segments&lt;br /&gt;
      if intersection s and ray from v to up exists&lt;br /&gt;
         status.add(s)&lt;br /&gt;
// Инициализируем множество вершин, которые нужно рассматривать&lt;br /&gt;
   for point w in segments&lt;br /&gt;
      if w.x &amp;gt;= v.x&lt;br /&gt;
         currentVertices.add(w)&lt;br /&gt;
   sort(currentVertices) by angle&lt;br /&gt;
// Для каждой вершины проверяем, видима ли она и обновляем статус&lt;br /&gt;
   for w in currentVertices&lt;br /&gt;
      if intersection vw and status.first not exists&lt;br /&gt;
         answer.add(w)&lt;br /&gt;
      delete from status all edges ending in w&lt;br /&gt;
      add in status all edges beginning in w&lt;br /&gt;
   return answer&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
В качестве статуса нужно использовать структуру данных, позволяющую добавлять и удалять из нее отрезки за &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; и извлекать минимум за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt;. В этом случае достигается асимптотика &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;, так как для каждой из &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; точек выполняется сортировка(&amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;), обновление статуса (суммарно &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, так как каждый отрезок добавляется и удаляется из статуса только один раз) и запросы ближайшего отрезка (&amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; на точку, то есть &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;). &lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zamrefr1.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr2.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr3.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Overmars and Welzl’s Algorithm &amp;lt;tex&amp;gt; O(n ^ 2) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
[http://igitur-archive.library.uu.nl/math/2006-1214-201604/overmars_88_new_methods.pdf visibility graph при помощи rotation tree]&lt;br /&gt;
&lt;br /&gt;
C помощью [http://bit.ly/1eEqTzk rotation tree] можно достичь асимптотики &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Motion planning ==&lt;br /&gt;
[[Файл:mink.png|200px|thumb|left|Изменяем препятствия]]&lt;br /&gt;
[[Файл:mink2.png|400px|thumb|right|Ищем путь для точки]]&lt;br /&gt;
Рассмотрим задачу нахождения кратчайшего пути, когда движимый объект {{---}} это выпуклый полигон. Например, робот, которого надо доставить из начальной в конечную точку.&lt;br /&gt;
&lt;br /&gt;
Если полигон вращать нельзя, задачу сводится к движению точки так : выбирается точка на полигоне, которая принимается за начало координат. В такой системе координат для каждого препятствия считается [[Сумма Минковского (определение, вычисление)|сумма Минковского]] с полигоном. Получаются бОльшие препятствия, но теперь достаточно двигать выбранную точку, что было описано выше.&lt;br /&gt;
&lt;br /&gt;
Если полигон можно вращать, задача нахождения ''кратчайшего'' пути становится достаточно ресурсоёмка, поэтому обычно рассматривают задачу нахождения какого-нибудь пути между конечными точками.&lt;br /&gt;
&lt;br /&gt;
Первый шаг решения этой задачи совпадает с предыдущим случаем : выберем точку и построим [[Сумма Минковского (определение, вычисление)|сумму Минковского]] препятствий с полигоном. Рассмотрим малый угол &amp;lt;tex&amp;gt; \epsilon &amp;lt;/tex&amp;gt;. Представим, что поворот полигона на этот угол {{---}} это движение вверх-вниз между слоями, на каждом из которых посчитана сумма Минковского с полигоном, повернутым на этот угол.&lt;br /&gt;
&lt;br /&gt;
На каждом слое построим трапецоидную карту и граф, как описано в [[Visibility graph и motion planning#Нахождение пути между точками с препятствиями|начале]]. Если [[Пересечение многоугольников (PSLG overlaying)|пересечь]] соседние слои и добавить между их графами ребра, получится один большой граф, в котором ищется кратчайший путь.&lt;br /&gt;
&lt;br /&gt;
При таком подходе может возникнуть ошибка при пересечении слоев : на каждом слое состояния будут допустимые, а осуществить поворот физически будет невозможно. Обычно, эту проблему решают двумя способами : измельчением угла поворота и изначальным сглаживанием углов полигона. Первый способ повышает не только точность решения, но и вычислительную сложность задачи. Второй подход практически исключает возможность нахождения пути, когда его нет, но повышает вероятность &amp;quot;ненахождения&amp;quot; пути, когда он есть.&lt;br /&gt;
&lt;br /&gt;
== Источники ==&lt;br /&gt;
* 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&lt;br /&gt;
* [http://www.academia.edu/2845047/3D_Visibility_Graph статья] про visibility graphs на academia.edu&lt;br /&gt;
* [http://habrahabr.ru/post/199256/ Хабр]&lt;br /&gt;
[[Категория: Вычислительная геометрия]]&lt;br /&gt;
&lt;br /&gt;
== Ссылки ==&lt;br /&gt;
* Моя [https://github.com/Igorjan94/cg/blob/master/include/cg/algorithms/visibilityGraph.h реализация] алгоритма за &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;. Далеко от идеального, но работает&lt;/div&gt;</summary>
		<author><name>Igorjan94</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44829</id>
		<title>Visibility graph и motion planning</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44829"/>
				<updated>2015-02-10T19:33:47Z</updated>
		
		<summary type="html">&lt;p&gt;Igorjan94: /* Нахождение пути между точками с препятствиями */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Нахождение пути между точками с препятствиями ==&lt;br /&gt;
{|align=&amp;quot;right&amp;quot;&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
|[[Файл:trap.png|200px|thumb|right|Путь с препятствиями через трапецоидную карту]]&lt;br /&gt;
|[[Файл:notShort.png|300px|thumb|right|Такой путь не самый короткий]]&lt;br /&gt;
|}&lt;br /&gt;
Для начала рассмотрим движение материальной точки. Случай, когда размером и формой движимого объекта пренебречь нельзя, будет рассмотрен [[Visibility graph и motion planning#Motion planning|позднее]]. &lt;br /&gt;
&lt;br /&gt;
Эту задачу можно решить с помощью [[Трапецоидная карта | трапецоидной карты]]. По ней строится граф, ребра которого соединяют центры трапедоидов, а также начальную и конечную вершины с серединами вертикальных сторон трапецоидов. В таком графе ищется путь между начальной и конечной вершинами.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм работает за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; и за линейное количество памяти и хорошо подходит для нахождения какого-нибудь пути между парой данных вершин. Но если нужно найти кратчайший путь, этот алгоритм не подходит, хоть и работает быстро. Однако, решения нахождения кратчайшего пути в лучшем случае работают за &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; времени и памяти (здесь и далее &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество всех вершин).&lt;br /&gt;
&lt;br /&gt;
== Visibility graph ==&lt;br /&gt;
Рассмотрим точное решение нахождения кратчайшего пути на плоскости между двумя точками с полигональными препятствиями с помощью построения графа видимости. После его построения, как и в случае с трапецоидной картой, кратчайший путь ищется любым стандартным алгоритмом поиска (например, алгоритмом [[Алгоритм Дейкстры|Дейкстры]] или [[Алгоритм A*|A*]]).&lt;br /&gt;
&lt;br /&gt;
Для простоты рассуждений начальную и конечную вершины будем считать вершинами полигонов.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|about=О кратчайшем пути&lt;br /&gt;
|statement=&lt;br /&gt;
Любой кратчайший путь между двумя вершинами с полигональными препятствиями представляет собой ломаную, вершины которой {{---}} вершины полигонов.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:short.png|150px|thumb|right|Short cut]]&lt;br /&gt;
Пусть кратчайший путь {{---}} не ломаная. В таком случае, на пути существует такая точка &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, которая не принадлежит ни одному прямому отрезку. Это означает, что существует &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестность точки &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, в которую не попадает ни одно препятствие (случай, когда точка попала на ребро рассматривается аналогично). В таком случае, подпуть, который находится внутри &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности, по неравенству треугольника может быть сокращён по хорде, соединяющий точки пересечения границы &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности с путем. Раз часть пути может быть уменьшена, значит и весь путь может быть уменьшен, а значит исходное предположение некорректно.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
Говорят, что вершина &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; ''видна'' (англ. mutually visible) из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;, если отрезок &amp;lt;tex&amp;gt; uv &amp;lt;/tex&amp;gt; не пересекает ни одного препятствия.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
''Граф видимости'' (англ. visibility graph) {{---}} граф, вершины которого {{---}} вершины полигонов. Между вершинами &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; существует ребро, если из &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; видна &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
В худшем случае в таком графе может быть &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; ребер. Однако по некоторым ребрам кратчайший путь точно не пройдет, и такие ребра из графа можно удалить.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
[[Файл:edgeToDelete.png|150px|thumb|right|Удаляем &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Если существуют вершины &amp;lt;tex&amp;gt; A, B, C &amp;lt;/tex&amp;gt; одного препятствия и вершина &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; такая, что поворот &amp;lt;tex&amp;gt; DBA &amp;lt;/tex&amp;gt; не совпадает с поворотом &amp;lt;tex&amp;gt; DBC &amp;lt;/tex&amp;gt;, то ребро &amp;lt;tex&amp;gt; DB &amp;lt;/tex&amp;gt; не принадлежит кратчайшему пути и его можно удалить из графа. (См. поясняющую картинку справа)&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:edgeNotToDelete.png|200px|thumb|right|Не удаляем &amp;lt;tex&amp;gt; BS &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Путь проходящий через ребро &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt; будет длиннее, чем через соседей точки &amp;lt;tex&amp;gt; B &amp;lt;/tex&amp;gt;, так как по неравенству треугольника &amp;lt;tex&amp;gt; AB + BD &amp;gt; AD &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
По доказанным леммам любое ребро кратчайшего пути содержится в графе. Таким образом, для нахождения кратчайшего пути осталось найти кратчайший путь в этом графе от начальной до конечной вершины.&lt;br /&gt;
&lt;br /&gt;
=== Построение visibility графа ===&lt;br /&gt;
==== Наивный алгоритм. &amp;lt;tex&amp;gt; O(n ^ 3) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
Для каждой пары вершин проверяем, можно ли добавить ребро между ними, то есть нет ли пересечений с полигонами. &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; пар вершин и &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; ребер, то есть &amp;lt;tex&amp;gt; O(n^3) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Lee’s Algorithm. &amp;lt;tex&amp;gt; O(n ^ 2 \log n) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
{|&lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zam.png|300px|thumb|left|Заметание плоскости вращающимся лучом]]&lt;br /&gt;
Однако можно это сделать за &amp;lt;tex&amp;gt; O(n ^ 2 \log  n) &amp;lt;/tex&amp;gt;. Идея алгоритма проста : для каждой вершины найдем видимые из нее вершины. Если научиться делать это за &amp;lt;tex&amp;gt; O(n \log  n) &amp;lt;/tex&amp;gt;, задача решена, так как всего точек &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для каждой вершины будем рассматривать только правую половину плоскости, так как ребра, которые должны идти в левую половину, будут исходить из вершин, для которых текущая вершина будет справа.&lt;br /&gt;
&lt;br /&gt;
Переформулируем задачу. Дано : точка &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и множество отрезков {{---}} ребер препятствий. &lt;br /&gt;
Найти : множество концов отрезков, видимых из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для решения этой задачи будем использовать заметающий луч с началом в точке &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Его статусом будут отрезки, которые его пересекают, упорядоченные по возрастанию расстояния от точки &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; до точки пересечения. Точками событий будут концы отрезков. &lt;br /&gt;
&lt;br /&gt;
Пустим луч из рассматриваемой вершины &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вертикально вверх и добавим в статус все отрезки, которые он пересекает, по увеличению расстояния до них. Теперь будем рассматривать точки &amp;lt;tex&amp;gt; w \in V &amp;lt;/tex&amp;gt; в порядке сортировки по углу между &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и вертикальной полуосью &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt;. При таком обходе проверка видимости вершины будет выполняться за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;, так как достаточно проверить пересечение с отрезком, первым в статусе. Действительно, если вершина не видна, то отрезок &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; пересекает несколько отрезков, лежащих перед &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt;, а значит и ближайший, то есть первый в статусе. В противном случае все пересекаемые лучом отрезки лежат за вершиной &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; и пересечения отрезка &amp;lt;tex&amp;gt; uw &amp;lt;/tex&amp;gt; с ближайшим отрезком в статусе не будет. Вне зависимости от видимости вершины, необходимо изменить статус заметающего луча. Для этого необходимо удалить из статуса все отрезки, которые заканчиваются вершине &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; (лежат слева от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;) и добавить все отрезки, которые в ней начинаются (лежат справа от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Псевдокод =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
graph buildVisibilityGraph(Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
   Set&amp;lt;Vertex&amp;gt; vertices = getVertices(segments)       //получаем все вершины препятствий&lt;br /&gt;
   graph visibilityGraph(vertices)                    //изначально в графе только вершины&lt;br /&gt;
   for Vertex v in vertices                           //для каждой вершины&lt;br /&gt;
      for Vertex w in getVisibleVertices(v, segments) //добавляем в граф все видимые из нее вершины&lt;br /&gt;
         visibilityGraph.addEdge(v, w)&lt;br /&gt;
   return visibilityGraph&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Здесь функция getVisibleVertices(&amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;) возвращает все видимые из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вершины и выглядит так:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Set&amp;lt;Vertex&amp;gt; getVisibleVertices(vertex v, set&amp;lt;segment&amp;gt; segments)&lt;br /&gt;
   Set&amp;lt;Vertex&amp;gt; answer&lt;br /&gt;
// Инициализируем статус&lt;br /&gt;
   for segment s in segments&lt;br /&gt;
      if intersection s and ray from v to up exists&lt;br /&gt;
         status.add(s)&lt;br /&gt;
// Инициализируем множество вершин, которые нужно рассматривать&lt;br /&gt;
   for point w in segments&lt;br /&gt;
      if w.x &amp;gt;= v.x&lt;br /&gt;
         currentVertices.add(w)&lt;br /&gt;
   sort(currentVertices) by angle&lt;br /&gt;
// Для каждой вершины проверяем, видима ли она и обновляем статус&lt;br /&gt;
   for w in currentVertices&lt;br /&gt;
      if intersection vw and status.first not exists&lt;br /&gt;
         answer.add(w)&lt;br /&gt;
      delete from status all edges ending in w&lt;br /&gt;
      add in status all edges beginning in w&lt;br /&gt;
   return answer&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
В качестве статуса нужно использовать структуру данных, позволяющую добавлять и удалять из нее отрезки за &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; и извлекать минимум за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt;. В этом случае достигается асимптотика &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;, так как для каждой из &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; точек выполняется сортировка(&amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;), обновление статуса (суммарно &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, так как каждый отрезок добавляется и удаляется из статуса только один раз) и запросы ближайшего отрезка (&amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; на точку, то есть &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;). &lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zamrefr1.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr2.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr3.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Overmars and Welzl’s Algorithm &amp;lt;tex&amp;gt; O(n ^ 2) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
[http://igitur-archive.library.uu.nl/math/2006-1214-201604/overmars_88_new_methods.pdf visibility graph при помощи rotation tree]&lt;br /&gt;
&lt;br /&gt;
C помощью [http://bit.ly/1eEqTzk rotation tree] можно достичь асимптотики &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Motion planning ==&lt;br /&gt;
[[Файл:mink.png|200px|thumb|left|Изменяем препятствия]]&lt;br /&gt;
[[Файл:mink2.png|400px|thumb|right|Ищем путь для точки]]&lt;br /&gt;
Рассмотрим задачу нахождения кратчайшего пути, когда движимый объект {{---}} это выпуклый полигон. Например, робот, которого надо доставить из начальной в конечную точку.&lt;br /&gt;
&lt;br /&gt;
Если полигон вращать нельзя, задачу сводится к движению точки так : выбирается точка на полигоне, которая принимается за начало координат. В такой системе координат для каждого препятствия считается [[Сумма Минковского (определение, вычисление)|сумма Минковского]] с полигоном. Получаются бОльшие препятствия, но теперь достаточно двигать выбранную точку, что было описано выше.&lt;br /&gt;
&lt;br /&gt;
Если полигон можно вращать, задача нахождения ''кратчайшего'' пути становится достаточно ресурсоёмка, поэтому обычно рассматривают задачу нахождения какого-нибудь пути между конечными точками.&lt;br /&gt;
&lt;br /&gt;
Первый шаг решения этой задачи совпадает с предыдущим случаем : выберем точку и построим [[Сумма Минковского (определение, вычисление)|сумму Минковского]] препятствий с полигоном. Рассмотрим малый угол &amp;lt;tex&amp;gt; \epsilon &amp;lt;/tex&amp;gt;. Представим, что поворот полигона на этот угол {{---}} это движение вверх-вниз между слоями, на каждом из которых посчитана сумма Минковского с полигоном, повернутым на этот угол.&lt;br /&gt;
&lt;br /&gt;
На каждом слое построим трапецоидную карту и граф, как описано в [[Visibility graph и motion planning#Нахождение пути между точками с препятствиями|начале]]. Если [[Пересечение многоугольников (PSLG overlaying)|пересечь]] соседние слои и добавить между их графами ребра, получится один большой граф, в котором ищется кратчайший путь.&lt;br /&gt;
&lt;br /&gt;
При таком подходе может возникнуть ошибка при пересечении слоев : на каждом слое состояния будут допустимые, а осуществить поворот физически будет невозможно. Обычно, эту проблему решают двумя способами : измельчением угла поворота и изначальным сглаживанием углов полигона. Первый способ повышает не только точность решения, но и вычислительную сложность задачи. Второй подход практически исключает возможность нахождения пути, когда его нет, но повышает вероятность &amp;quot;ненахождения&amp;quot; пути, когда он есть.&lt;br /&gt;
&lt;br /&gt;
== Источники ==&lt;br /&gt;
* 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&lt;br /&gt;
* [http://www.academia.edu/2845047/3D_Visibility_Graph статья] про visibility graphs на academia.edu&lt;br /&gt;
* [http://habrahabr.ru/post/199256/ Хабр]&lt;br /&gt;
[[Категория: Вычислительная геометрия]]&lt;br /&gt;
&lt;br /&gt;
== Ссылки ==&lt;br /&gt;
* Моя [https://github.com/Igorjan94/cg/blob/master/include/cg/algorithms/visibilityGraph.h реализация] алгоритма за &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;. Далеко от идеального, но работает&lt;/div&gt;</summary>
		<author><name>Igorjan94</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44828</id>
		<title>Visibility graph и motion planning</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44828"/>
				<updated>2015-02-10T19:30:25Z</updated>
		
		<summary type="html">&lt;p&gt;Igorjan94: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Нахождение пути между точками с препятствиями ==&lt;br /&gt;
{|align=&amp;quot;right&amp;quot;&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
|[[Файл:trap.png|200px|thumb|right|Путь с препятствиями через трапецоидную карту]]&lt;br /&gt;
|[[Файл:notShort.png|300px|thumb|right|Такой путь не самый короткий]]&lt;br /&gt;
|}&lt;br /&gt;
Для начала рассмотрим движение материальной точки. Случай, когда размером и формой движимого объекта пренебречь нельзя, будет рассмотрен [[Visibility graph и motion planning#Motion planning|позднее]]. &lt;br /&gt;
&lt;br /&gt;
Эту задачу можно решить с помощью [[Трапецоидная карта | трапецоидной карты]]. По ней строится граф, ребра которого соединяют центры трапедоидов, а также начальную и конечную вершины с серединами вертикальных сторон трапецоидов. В таком графе ищется путь между начальной и конечной вершинами.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм работает за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; и за линейное количество памяти и хорошо подходит для нахождения какого-нибудь пути между парой данных вершин. Но иногда нужно найти кратчайший путь, и этот алгоритм не подходит, хоть и работает быстро. Однако, решения нахождения кратчайшего пути в лучшем случае работают за &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; времени и памяти (здесь и далее &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество всех вершин).&lt;br /&gt;
&lt;br /&gt;
== Visibility graph ==&lt;br /&gt;
Рассмотрим точное решение нахождения кратчайшего пути на плоскости между двумя точками с полигональными препятствиями с помощью построения графа видимости. После его построения, как и в случае с трапецоидной картой, кратчайший путь ищется любым стандартным алгоритмом поиска (например, алгоритмом [[Алгоритм Дейкстры|Дейкстры]] или [[Алгоритм A*|A*]]).&lt;br /&gt;
&lt;br /&gt;
Для простоты рассуждений начальную и конечную вершины будем считать вершинами полигонов.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|about=О кратчайшем пути&lt;br /&gt;
|statement=&lt;br /&gt;
Любой кратчайший путь между двумя вершинами с полигональными препятствиями представляет собой ломаную, вершины которой {{---}} вершины полигонов.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:short.png|150px|thumb|right|Short cut]]&lt;br /&gt;
Пусть кратчайший путь {{---}} не ломаная. В таком случае, на пути существует такая точка &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, которая не принадлежит ни одному прямому отрезку. Это означает, что существует &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестность точки &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, в которую не попадает ни одно препятствие (случай, когда точка попала на ребро рассматривается аналогично). В таком случае, подпуть, который находится внутри &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности, по неравенству треугольника может быть сокращён по хорде, соединяющий точки пересечения границы &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности с путем. Раз часть пути может быть уменьшена, значит и весь путь может быть уменьшен, а значит исходное предположение некорректно.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
Говорят, что вершина &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; ''видна'' (англ. mutually visible) из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;, если отрезок &amp;lt;tex&amp;gt; uv &amp;lt;/tex&amp;gt; не пересекает ни одного препятствия.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
''Граф видимости'' (англ. visibility graph) {{---}} граф, вершины которого {{---}} вершины полигонов. Между вершинами &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; существует ребро, если из &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; видна &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
В худшем случае в таком графе может быть &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; ребер. Однако по некоторым ребрам кратчайший путь точно не пройдет, и такие ребра из графа можно удалить.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
[[Файл:edgeToDelete.png|150px|thumb|right|Удаляем &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Если существуют вершины &amp;lt;tex&amp;gt; A, B, C &amp;lt;/tex&amp;gt; одного препятствия и вершина &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; такая, что поворот &amp;lt;tex&amp;gt; DBA &amp;lt;/tex&amp;gt; не совпадает с поворотом &amp;lt;tex&amp;gt; DBC &amp;lt;/tex&amp;gt;, то ребро &amp;lt;tex&amp;gt; DB &amp;lt;/tex&amp;gt; не принадлежит кратчайшему пути и его можно удалить из графа. (См. поясняющую картинку справа)&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:edgeNotToDelete.png|200px|thumb|right|Не удаляем &amp;lt;tex&amp;gt; BS &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Путь проходящий через ребро &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt; будет длиннее, чем через соседей точки &amp;lt;tex&amp;gt; B &amp;lt;/tex&amp;gt;, так как по неравенству треугольника &amp;lt;tex&amp;gt; AB + BD &amp;gt; AD &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
По доказанным леммам любое ребро кратчайшего пути содержится в графе. Таким образом, для нахождения кратчайшего пути осталось найти кратчайший путь в этом графе от начальной до конечной вершины.&lt;br /&gt;
&lt;br /&gt;
=== Построение visibility графа ===&lt;br /&gt;
==== Наивный алгоритм. &amp;lt;tex&amp;gt; O(n ^ 3) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
Для каждой пары вершин проверяем, можно ли добавить ребро между ними, то есть нет ли пересечений с полигонами. &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; пар вершин и &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; ребер, то есть &amp;lt;tex&amp;gt; O(n^3) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Lee’s Algorithm. &amp;lt;tex&amp;gt; O(n ^ 2 \log n) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
{|&lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zam.png|300px|thumb|left|Заметание плоскости вращающимся лучом]]&lt;br /&gt;
Однако можно это сделать за &amp;lt;tex&amp;gt; O(n ^ 2 \log  n) &amp;lt;/tex&amp;gt;. Идея алгоритма проста : для каждой вершины найдем видимые из нее вершины. Если научиться делать это за &amp;lt;tex&amp;gt; O(n \log  n) &amp;lt;/tex&amp;gt;, задача решена, так как всего точек &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для каждой вершины будем рассматривать только правую половину плоскости, так как ребра, которые должны идти в левую половину, будут исходить из вершин, для которых текущая вершина будет справа.&lt;br /&gt;
&lt;br /&gt;
Переформулируем задачу. Дано : точка &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и множество отрезков {{---}} ребер препятствий. &lt;br /&gt;
Найти : множество концов отрезков, видимых из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для решения этой задачи будем использовать заметающий луч с началом в точке &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Его статусом будут отрезки, которые его пересекают, упорядоченные по возрастанию расстояния от точки &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; до точки пересечения. Точками событий будут концы отрезков. &lt;br /&gt;
&lt;br /&gt;
Пустим луч из рассматриваемой вершины &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вертикально вверх и добавим в статус все отрезки, которые он пересекает, по увеличению расстояния до них. Теперь будем рассматривать точки &amp;lt;tex&amp;gt; w \in V &amp;lt;/tex&amp;gt; в порядке сортировки по углу между &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и вертикальной полуосью &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt;. При таком обходе проверка видимости вершины будет выполняться за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;, так как достаточно проверить пересечение с отрезком, первым в статусе. Действительно, если вершина не видна, то отрезок &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; пересекает несколько отрезков, лежащих перед &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt;, а значит и ближайший, то есть первый в статусе. В противном случае все пересекаемые лучом отрезки лежат за вершиной &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; и пересечения отрезка &amp;lt;tex&amp;gt; uw &amp;lt;/tex&amp;gt; с ближайшим отрезком в статусе не будет. Вне зависимости от видимости вершины, необходимо изменить статус заметающего луча. Для этого необходимо удалить из статуса все отрезки, которые заканчиваются вершине &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; (лежат слева от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;) и добавить все отрезки, которые в ней начинаются (лежат справа от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Псевдокод =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
graph buildVisibilityGraph(Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
   Set&amp;lt;Vertex&amp;gt; vertices = getVertices(segments)       //получаем все вершины препятствий&lt;br /&gt;
   graph visibilityGraph(vertices)                    //изначально в графе только вершины&lt;br /&gt;
   for Vertex v in vertices                           //для каждой вершины&lt;br /&gt;
      for Vertex w in getVisibleVertices(v, segments) //добавляем в граф все видимые из нее вершины&lt;br /&gt;
         visibilityGraph.addEdge(v, w)&lt;br /&gt;
   return visibilityGraph&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Здесь функция getVisibleVertices(&amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;) возвращает все видимые из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вершины и выглядит так:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Set&amp;lt;Vertex&amp;gt; getVisibleVertices(vertex v, set&amp;lt;segment&amp;gt; segments)&lt;br /&gt;
   Set&amp;lt;Vertex&amp;gt; answer&lt;br /&gt;
// Инициализируем статус&lt;br /&gt;
   for segment s in segments&lt;br /&gt;
      if intersection s and ray from v to up exists&lt;br /&gt;
         status.add(s)&lt;br /&gt;
// Инициализируем множество вершин, которые нужно рассматривать&lt;br /&gt;
   for point w in segments&lt;br /&gt;
      if w.x &amp;gt;= v.x&lt;br /&gt;
         currentVertices.add(w)&lt;br /&gt;
   sort(currentVertices) by angle&lt;br /&gt;
// Для каждой вершины проверяем, видима ли она и обновляем статус&lt;br /&gt;
   for w in currentVertices&lt;br /&gt;
      if intersection vw and status.first not exists&lt;br /&gt;
         answer.add(w)&lt;br /&gt;
      delete from status all edges ending in w&lt;br /&gt;
      add in status all edges beginning in w&lt;br /&gt;
   return answer&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
В качестве статуса нужно использовать структуру данных, позволяющую добавлять и удалять из нее отрезки за &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; и извлекать минимум за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt;. В этом случае достигается асимптотика &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;, так как для каждой из &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; точек выполняется сортировка(&amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;), обновление статуса (суммарно &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, так как каждый отрезок добавляется и удаляется из статуса только один раз) и запросы ближайшего отрезка (&amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; на точку, то есть &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;). &lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zamrefr1.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr2.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr3.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Overmars and Welzl’s Algorithm &amp;lt;tex&amp;gt; O(n ^ 2) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
[http://igitur-archive.library.uu.nl/math/2006-1214-201604/overmars_88_new_methods.pdf visibility graph при помощи rotation tree]&lt;br /&gt;
&lt;br /&gt;
C помощью [http://bit.ly/1eEqTzk rotation tree] можно достичь асимптотики &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Motion planning ==&lt;br /&gt;
[[Файл:mink.png|200px|thumb|left|Изменяем препятствия]]&lt;br /&gt;
[[Файл:mink2.png|400px|thumb|right|Ищем путь для точки]]&lt;br /&gt;
Рассмотрим задачу нахождения кратчайшего пути, когда движимый объект {{---}} это выпуклый полигон. Например, робот, которого надо доставить из начальной в конечную точку.&lt;br /&gt;
&lt;br /&gt;
Если полигон вращать нельзя, задачу сводится к движению точки так : выбирается точка на полигоне, которая принимается за начало координат. В такой системе координат для каждого препятствия считается [[Сумма Минковского (определение, вычисление)|сумма Минковского]] с полигоном. Получаются бОльшие препятствия, но теперь достаточно двигать выбранную точку, что было описано выше.&lt;br /&gt;
&lt;br /&gt;
Если полигон можно вращать, задача нахождения ''кратчайшего'' пути становится достаточно ресурсоёмка, поэтому обычно рассматривают задачу нахождения какого-нибудь пути между конечными точками.&lt;br /&gt;
&lt;br /&gt;
Первый шаг решения этой задачи совпадает с предыдущим случаем : выберем точку и построим [[Сумма Минковского (определение, вычисление)|сумму Минковского]] препятствий с полигоном. Рассмотрим малый угол &amp;lt;tex&amp;gt; \epsilon &amp;lt;/tex&amp;gt;. Представим, что поворот полигона на этот угол {{---}} это движение вверх-вниз между слоями, на каждом из которых посчитана сумма Минковского с полигоном, повернутым на этот угол.&lt;br /&gt;
&lt;br /&gt;
На каждом слое построим трапецоидную карту и граф, как описано в [[Visibility graph и motion planning#Нахождение пути между точками с препятствиями|начале]]. Если [[Пересечение многоугольников (PSLG overlaying)|пересечь]] соседние слои и добавить между их графами ребра, получится один большой граф, в котором ищется кратчайший путь.&lt;br /&gt;
&lt;br /&gt;
При таком подходе может возникнуть ошибка при пересечении слоев : на каждом слое состояния будут допустимые, а осуществить поворот физически будет невозможно. Обычно, эту проблему решают двумя способами : измельчением угла поворота и изначальным сглаживанием углов полигона. Первый способ повышает не только точность решения, но и вычислительную сложность задачи. Второй подход практически исключает возможность нахождения пути, когда его нет, но повышает вероятность &amp;quot;ненахождения&amp;quot; пути, когда он есть.&lt;br /&gt;
&lt;br /&gt;
== Источники ==&lt;br /&gt;
* 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&lt;br /&gt;
* [http://www.academia.edu/2845047/3D_Visibility_Graph статья] про visibility graphs на academia.edu&lt;br /&gt;
* [http://habrahabr.ru/post/199256/ Хабр]&lt;br /&gt;
[[Категория: Вычислительная геометрия]]&lt;br /&gt;
&lt;br /&gt;
== Ссылки ==&lt;br /&gt;
* Моя [https://github.com/Igorjan94/cg/blob/master/include/cg/algorithms/visibilityGraph.h реализация] алгоритма за &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;. Далеко от идеального, но работает&lt;/div&gt;</summary>
		<author><name>Igorjan94</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44827</id>
		<title>Visibility graph и motion planning</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44827"/>
				<updated>2015-02-10T19:10:51Z</updated>
		
		<summary type="html">&lt;p&gt;Igorjan94: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Нахождение пути между точками с препятствиями ==&lt;br /&gt;
{|align=&amp;quot;right&amp;quot;&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
|[[Файл:trap.png|200px|thumb|right|Путь с препятствиями через трапецоидную карту]]&lt;br /&gt;
|[[Файл:notShort.png|300px|thumb|right|Такой путь не самый короткий]]&lt;br /&gt;
|}&lt;br /&gt;
Для начала рассмотрим движение материальной точки. Случай, когда размером и формой движимого объекта пренебречь нельзя, будет рассмотрен [[Visibility graph и motion planning#Motion planning|позднее]]. &lt;br /&gt;
&lt;br /&gt;
Эту задачу можно решить с помощью [[Трапецоидная карта | трапецоидной карты]]. По ней строится граф, ребра которого соединяют центры трапедоидов, а также начальную и конечную вершины с серединами вертикальных сторон трапецоидов. В таком графе ищется путь между начальной и конечной вершинами.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм работает за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; и за линейное количество памяти и хорошо подходит для нахождения какого-нибудь пути между конечными вершинами. Но иногда нужно найти кратчайший путь, и этот алгоритм не подходит, хоть и работает быстро. Однако, решения нахождения кратчайшего пути в лучшем случае работают за &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; времени и памяти (здесь и далее &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество всех вершин).&lt;br /&gt;
&lt;br /&gt;
== Visibility graph ==&lt;br /&gt;
Рассмотрим точное решение нахождения кратчайшего пути на плоскости между двумя точками с полигональными препятствиями с помощью построения графа видимости. После его построения, как и в случае с трапецоидной картой, кратчайший путь ищется любым стандартным алгоритмом поиска (например, алгоритмом [[Алгоритм Дейкстры|Дейкстры]] или [[Алгоритм A*|A*]]).&lt;br /&gt;
&lt;br /&gt;
Для простоты рассуждений начальную и конечную вершины будем считать вершинами полигонов.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|about=О кратчайшем пути&lt;br /&gt;
|statement=&lt;br /&gt;
Любой кратчайший путь между двумя вершинами с полигональными препятствиями представляет собой ломаную, вершины которой {{---}} вершины полигонов.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:short.png|150px|thumb|right|Short cut]]&lt;br /&gt;
Пусть кратчайший путь {{---}} не ломаная. В таком случае, на пути существует такая точка &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, которая не принадлежит ни одному прямому отрезку. Это означает, что существует &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестность точки &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, в которую не попадает ни одно препятствие (случай, когда точка попала на ребро рассматривается аналогично). В таком случае, подпуть, который находится внутри &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности, по неравенству треугольника может быть сокращён по хорде, соединяющий точки пересечения границы &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности с путем. Раз часть пути может быть уменьшена, значит и весь путь может быть уменьшен, а значит исходное предположение некорректно.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
Говорят, что вершина &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; ''видна'' (англ. mutually visible) из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;, если отрезок &amp;lt;tex&amp;gt; uv &amp;lt;/tex&amp;gt; не пересекает ни одного препятствия.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
''Граф видимости'' (англ. visibility graph) {{---}} граф, вершины которого {{---}} вершины полигонов. Между вершинами &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; существует ребро, если из &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; видна &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
В худшем случае в таком графе может быть &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; ребер. Однако по некоторым ребрам кратчайший путь точно не пройдет, и такие ребра из графа можно удалить.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
[[Файл:edgeToDelete.png|150px|thumb|right|Удаляем &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Если существуют вершины &amp;lt;tex&amp;gt; A, B, C &amp;lt;/tex&amp;gt; одного препятствия и вершина &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; такая, что поворот &amp;lt;tex&amp;gt; DBA &amp;lt;/tex&amp;gt; не совпадает с поворотом &amp;lt;tex&amp;gt; DBC &amp;lt;/tex&amp;gt;, то ребро &amp;lt;tex&amp;gt; DB &amp;lt;/tex&amp;gt; не принадлежит кратчайшему пути и его можно удалить из графа. (См. поясняющую картинку справа)&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:edgeNotToDelete.png|200px|thumb|right|Не удаляем &amp;lt;tex&amp;gt; BS &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Путь проходящий через ребро &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt; будет длиннее, чем через соседей точки &amp;lt;tex&amp;gt; B &amp;lt;/tex&amp;gt;, так как по неравенству треугольника &amp;lt;tex&amp;gt; AB + BD &amp;gt; AD &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
По доказанным леммам любое ребро кратчайшего пути содержится в графе. Таким образом, для нахождения кратчайшего пути осталось найти кратчайший путь в этом графе от начальной до конечной вершины.&lt;br /&gt;
&lt;br /&gt;
=== Построение visibility графа ===&lt;br /&gt;
==== Наивный алгоритм. &amp;lt;tex&amp;gt; O(n ^ 3) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
Для каждой пары вершин проверяем, можно ли добавить ребро между ними, то есть нет ли пересечений с полигонами. &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; пар вершин и &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; ребер, то есть &amp;lt;tex&amp;gt; O(n^3) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Lee’s Algorithm. &amp;lt;tex&amp;gt; O(n ^ 2 \log n) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
{|&lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zam.png|300px|thumb|left|Заметание плоскости вращающимся лучом]]&lt;br /&gt;
Однако можно это сделать за &amp;lt;tex&amp;gt; O(n ^ 2 \log  n) &amp;lt;/tex&amp;gt;. Идея алгоритма проста : для каждой вершины найдем видимые из нее вершины. Если научиться делать это за &amp;lt;tex&amp;gt; O(n \log  n) &amp;lt;/tex&amp;gt;, задача решена, так как всего точек &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для каждой вершины будем рассматривать только правую половину плоскости, так как ребра, которые должны идти в левую половину, будут исходить из вершин, для которых текущая вершина будет справа.&lt;br /&gt;
&lt;br /&gt;
Переформулируем задачу. Дано : точка &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и множество отрезков {{---}} ребер препятствий. &lt;br /&gt;
Найти : множество концов отрезков, видимых из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для решения этой задачи будем использовать заметающий луч с началом в точке &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Его статусом будут отрезки, которые его пересекают, упорядоченные по возрастанию расстояния от точки &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; до точки пересечения. Точками событий будут концы отрезков. &lt;br /&gt;
&lt;br /&gt;
Пустим луч из рассматриваемой вершины &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вертикально вверх и добавим в статус все отрезки, которые он пересекает, по увеличению расстояния до них. Теперь будем рассматривать точки &amp;lt;tex&amp;gt; w \in V &amp;lt;/tex&amp;gt; в порядке сортировки по углу между &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и вертикальной полуосью &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt;. При таком обходе проверка видимости вершины будет выполняться за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;, так как достаточно проверить пересечение с отрезком, первым в статусе. Действительно, если вершина не видна, то отрезок &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; пересекает несколько отрезков, лежащих перед &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt;, а значит и ближайший, то есть первый в статусе. В противном случае все пересекаемые лучом отрезки лежат за вершиной &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; и пересечения отрезка &amp;lt;tex&amp;gt; uw &amp;lt;/tex&amp;gt; с ближайшим отрезком в статусе не будет. Вне зависимости от видимости вершины, необходимо изменить статус заметающего луча. Для этого необходимо удалить из статуса все отрезки, которые заканчиваются вершине &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; (лежат слева от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;) и добавить все отрезки, которые в ней начинаются (лежат справа от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Псевдокод =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
graph buildVisibilityGraph(Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
   Set&amp;lt;Vertex&amp;gt; vertices = getVertices(segments)       //получаем все вершины препятствий&lt;br /&gt;
   graph visibilityGraph(vertices)                    //изначально в графе только вершины&lt;br /&gt;
   for Vertex v in vertices                           //для каждой вершины&lt;br /&gt;
      for Vertex w in getVisibleVertices(v, segments) //добавляем в граф все видимые из нее вершины&lt;br /&gt;
         visibilityGraph.addEdge(v, w)&lt;br /&gt;
   return visibilityGraph&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Здесь функция getVisibleVertices(&amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;) возвращает все видимые из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вершины и выглядит так:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Set&amp;lt;Vertex&amp;gt; getVisibleVertices(vertex v, set&amp;lt;segment&amp;gt; segments)&lt;br /&gt;
   Set&amp;lt;Vertex&amp;gt; answer&lt;br /&gt;
// Инициализируем статус&lt;br /&gt;
   for segment s in segments&lt;br /&gt;
      if intersection s and ray from v to up exists&lt;br /&gt;
         status.add(s)&lt;br /&gt;
// Инициализируем множество вершин, которые нужно рассматривать&lt;br /&gt;
   for point w in segments&lt;br /&gt;
      if w.x &amp;gt;= v.x&lt;br /&gt;
         currentVertices.add(w)&lt;br /&gt;
   sort(currentVertices) by angle&lt;br /&gt;
// Для каждой вершины проверяем, видима ли она и обновляем статус&lt;br /&gt;
   for w in currentVertices&lt;br /&gt;
      if intersection vw and status.first not exists&lt;br /&gt;
         answer.add(w)&lt;br /&gt;
      delete from status all edges ending in w&lt;br /&gt;
      add in status all edges beginning in w&lt;br /&gt;
   return answer&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
В качестве статуса нужно использовать структуру данных, позволяющую добавлять и удалять из нее отрезки за &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; и извлекать минимум за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt;. В этом случае достигается асимптотика &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;, так как для каждой из &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; точек выполняется сортировка(&amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;), обновление статуса (суммарно &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, так как каждый отрезок добавляется и удаляется из статуса только один раз) и запросы ближайшего отрезка (&amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; на точку, то есть &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;). &lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zamrefr1.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr2.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr3.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Overmars and Welzl’s Algorithm &amp;lt;tex&amp;gt; O(n ^ 2) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
[http://igitur-archive.library.uu.nl/math/2006-1214-201604/overmars_88_new_methods.pdf visibility graph при помощи rotation tree]&lt;br /&gt;
&lt;br /&gt;
C помощью [http://bit.ly/1eEqTzk rotation tree] можно достичь асимптотики &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Motion planning ==&lt;br /&gt;
[[Файл:mink.png|200px|thumb|left|Изменяем препятствия]]&lt;br /&gt;
[[Файл:mink2.png|400px|thumb|right|Ищем путь для точки]]&lt;br /&gt;
Рассмотрим задачу нахождения кратчайшего пути, когда движимый объект {{---}} это выпуклый полигон. Например, робот, которого надо доставить из начальной в конечную точку.&lt;br /&gt;
&lt;br /&gt;
Если полигон вращать нельзя, задачу сводится к движению точки так : выбирается точка на полигоне, которая принимается за начало координат. В такой системе координат для каждого препятствия считается [[Сумма Минковского (определение, вычисление)|сумма Минковского]] с полигоном. Получаются бОльшие препятствия, но теперь достаточно двигать выбранную точку, что было описано выше.&lt;br /&gt;
&lt;br /&gt;
Если полигон можно вращать, задача нахождения ''кратчайшего'' пути становится достаточно ресурсоёмка, поэтому обычно рассматривают задачу нахождения какого-нибудь пути между конечными точками.&lt;br /&gt;
&lt;br /&gt;
Первый шаг решения этой задачи совпадает с предыдущим случаем : выберем точку и построим [[Сумма Минковского (определение, вычисление)|сумму Минковского]] препятствий с полигоном. Рассмотрим малый угол &amp;lt;tex&amp;gt; \epsilon &amp;lt;/tex&amp;gt;. Представим, что поворот полигона на этот угол {{---}} это движение вверх-вниз между слоями, на каждом из которых посчитана сумма Минковского с полигоном, повернутым на этот угол.&lt;br /&gt;
&lt;br /&gt;
На каждом слое построим трапецоидную карту и граф, как описано в [[Visibility graph и motion planning#Нахождение пути между точками с препятствиями|начале]]. Если [[Пересечение многоугольников (PSLG overlaying)|пересечь]] соседние слои и добавить между их графами ребра, получится один большой граф, в котором ищется кратчайший путь.&lt;br /&gt;
&lt;br /&gt;
При таком подходе может возникнуть ошибка при пересечении слоев : на каждом слое состояния будут допустимые, а осуществить поворот физически будет невозможно. Обычно, эту проблему решают двумя способами : измельчением угла поворота и изначальным сглаживанием углов полигона. Первый способ повышает не только точность решения, но и вычислительную сложность задачи. Второй подход практически исключает возможность нахождения пути, когда его нет, но повышает вероятность &amp;quot;ненахождения&amp;quot; пути, когда он есть.&lt;br /&gt;
&lt;br /&gt;
== Источники ==&lt;br /&gt;
* 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&lt;br /&gt;
* [http://www.academia.edu/2845047/3D_Visibility_Graph статья] про visibility graphs на academia.edu&lt;br /&gt;
* [http://habrahabr.ru/post/199256/ Хабр]&lt;br /&gt;
[[Категория: Вычислительная геометрия]]&lt;br /&gt;
&lt;br /&gt;
== Ссылки ==&lt;br /&gt;
* Моя [https://github.com/Igorjan94/cg/blob/master/include/cg/algorithms/visibilityGraph.h реализация] алгоритма за &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;. Далеко от идеального, но работает&lt;/div&gt;</summary>
		<author><name>Igorjan94</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44826</id>
		<title>Visibility graph и motion planning</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44826"/>
				<updated>2015-02-10T19:07:41Z</updated>
		
		<summary type="html">&lt;p&gt;Igorjan94: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Нахождение пути между точками с препятствиями ==&lt;br /&gt;
{|align=&amp;quot;right&amp;quot;&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
|[[Файл:trap.png|200px|thumb|right|Путь с препятствиями через трапецоидную карту]]&lt;br /&gt;
|[[Файл:notShort.png|300px|thumb|right|Такой путь не самый короткий]]&lt;br /&gt;
|}&lt;br /&gt;
Для начала рассмотрим движение материальной точки. Случай, когда размером и формой движимого объекта пренебречь нельзя, будет рассмотрен [[Visibility graph и motion planning#Motion planning|позднее]]. &lt;br /&gt;
&lt;br /&gt;
Эту задачу можно решить с помощью [[Трапецоидная карта | трапецоидной карты]]. По ней строится граф, ребра которого соединяют центры трапедоидов, а также начальную и конечную вершины с серединами вертикальных сторон трапецоидов. В таком графе ищется путь между начальной и конечной вершинами.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм работает за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; и за линейное количество памяти и хорошо подходит для нахождения какого-нибудь пути между конечными вершинами. Но иногда нужно найти кратчайший путь, и этот алгоритм не подходит, хоть и работает быстро. Однако, решения нахождения кратчайшего пути в лучшем случае работают за &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; времени и памяти (здесь и далее &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество всех вершин).&lt;br /&gt;
&lt;br /&gt;
== Visibility graph ==&lt;br /&gt;
Рассмотрим точное решение нахождения кратчайшего пути на плоскости между двумя точками с полигональными препятствиями с помощью построения графа видимости. После его построения, как и в случае с трапецоидной картой, кратчайший путь ищется любым стандартным алгоритмом поиска (например, алгоритмом [[Алгоритм Дейкстры|Дейкстры]] или [[Алгоритм A*|A*]]).&lt;br /&gt;
&lt;br /&gt;
Для простоты рассуждений начальную и конечную вершины будем считать вершинами полигонов.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|about=О кратчайшем пути&lt;br /&gt;
|statement=&lt;br /&gt;
Любой кратчайший путь между двумя вершинами с полигональными препятствиями представляет собой ломаную, вершины которой {{---}} вершины полигонов.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:short.png|150px|thumb|right|Short cut]]&lt;br /&gt;
Пусть кратчайший путь {{---}} не ломаная. В таком случае, на пути существует такая точка &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, которая не принадлежит ни одному прямому отрезку. Это означает, что существует &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестность точки &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, в которую не попадает ни одно препятствие (случай, когда точка попала на ребро рассматривается аналогично). В таком случае, подпуть, который находится внутри &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности, по неравенству треугольника может быть сокращён по хорде, соединяющий точки пересечения границы &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности с путем. Раз часть пути может быть уменьшена, значит и весь путь может быть уменьшен, а значит исходное предположение некорректно.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
Говорят, что вершина &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; ''видна'' (англ. mutually visible) из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;, если отрезок &amp;lt;tex&amp;gt; uv &amp;lt;/tex&amp;gt; не пересекает ни одного препятствия.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
''Граф видимости'' (англ. visibility graph) {{---}} граф, вершины которого {{---}} вершины полигонов. Между вершинами &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; существует ребро, если из &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; видна &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
В худшем случае в таком графе может быть &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; ребер. Однако по некоторым ребрам кратчайший путь точно не пройдет, и такие ребра из графа можно удалить.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
[[Файл:edgeToDelete.png|150px|thumb|right|Удаляем &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Если существуют вершины &amp;lt;tex&amp;gt; A, B, C &amp;lt;/tex&amp;gt; одного препятствия и вершина &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; такая, что поворот &amp;lt;tex&amp;gt; DBA &amp;lt;/tex&amp;gt; не совпадает с поворотом &amp;lt;tex&amp;gt; DBC &amp;lt;/tex&amp;gt;, то ребро &amp;lt;tex&amp;gt; DB &amp;lt;/tex&amp;gt; не принадлежит кратчайшему пути и его можно удалить из графа. (См. поясняющую картинку справа)&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:edgeNotToDelete.png|200px|thumb|right|Не удаляем &amp;lt;tex&amp;gt; BS &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Путь проходящий через ребро &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt; будет длиннее, чем через соседей точки &amp;lt;tex&amp;gt; B &amp;lt;/tex&amp;gt;, так как по неравенству треугольника &amp;lt;tex&amp;gt; AB + BD &amp;gt; AD &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
По доказанным леммам любое ребро кратчайшего пути содержится в графе. Таким образом, для нахождения кратчайшего пути осталось найти кратчайший путь в этом графе от начальной до конечной вершины.&lt;br /&gt;
&lt;br /&gt;
=== Построение visibility графа ===&lt;br /&gt;
==== Наивный алгоритм. &amp;lt;tex&amp;gt; O(n ^ 3) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
Для каждой пары вершин проверяем, можно ли добавить ребро между ними, то есть нет ли пересечений с полигонами. &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; пар вершин и &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; ребер, то есть &amp;lt;tex&amp;gt; O(n^3) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Lee’s Algorithm. &amp;lt;tex&amp;gt; O(n ^ 2 \log n) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
{|&lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zam.png|300px|thumb|left|Заметание плоскости вращающимся лучом]]&lt;br /&gt;
Однако можно это сделать за &amp;lt;tex&amp;gt; O(n ^ 2 \log  n) &amp;lt;/tex&amp;gt;. Идея алгоритма проста : для каждой вершины найдем видимые из нее вершины. Если научиться делать это за &amp;lt;tex&amp;gt; O(n \log  n) &amp;lt;/tex&amp;gt;, задача решена, так как всего точек &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для каждой вершины будем рассматривать только правую половину плоскости, так как ребра, которые должны идти в левую половину, будут исходить из вершин, для которых текущая вершина будет справа.&lt;br /&gt;
&lt;br /&gt;
Переформулируем задачу. Дано : точка &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и множество отрезков {{---}} ребер препятствий. &lt;br /&gt;
Найти : множество концов отрезков, видимых из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для решения этой задачи будем использовать заметающий луч с началом в точке &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Его статусом будут отрезки, которые его пересекают, упорядоченные по возрастанию расстояния от точки &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; до точки пересечения. Точками событий будут концы отрезков. &lt;br /&gt;
&lt;br /&gt;
Пустим луч из рассматриваемой вершины &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вертикально вверх и добавим в статус все отрезки, которые он пересекает, по увеличению расстояния до них. Теперь будем рассматривать точки &amp;lt;tex&amp;gt; w \in V &amp;lt;/tex&amp;gt; в порядке сортировки по углу между &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и вертикальной полуосью &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt;. При таком обходе проверка видимости вершины будет выполняться за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;, так как достаточно проверить пересечение с отрезком, первым в статусе. Действительно, если вершина не видна, то отрезок &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; пересекает несколько отрезков, лежащих перед &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt;, а значит и ближайший, то есть первый в статусе. В противном случае все пересекаемые лучом отрезки лежат за вершиной &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; и пересечения отрезка &amp;lt;tex&amp;gt; uw &amp;lt;/tex&amp;gt; с ближайшим отрезком в статусе не будет. Вне зависимости от видимости вершины, необходимо изменить статус заметающего луча. Для этого необходимо удалить из статуса все отрезки, которые заканчиваются вершине &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; (лежат слева от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;) и добавить все отрезки, которые в ней начинаются (лежат справа от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Псевдокод =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
graph buildVisibilityGraph(Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
   Set&amp;lt;Vertex&amp;gt; vertices = getVertices(segments)       //получаем все вершины препятствий&lt;br /&gt;
   graph visibilityGraph(vertices)                    //изначально в графе только вершины&lt;br /&gt;
   for Vertex v in vertices                           //для каждой вершины&lt;br /&gt;
      for Vertex w in getVisibleVertices(v, segments) //добавляем в граф все видимые из нее вершины&lt;br /&gt;
         visibilityGraph.addEdge(v, w)&lt;br /&gt;
   return visibilityGraph&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Здесь функция getVisibleVertices(&amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;) возвращает все видимые из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вершины и выглядит так:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
vector&amp;lt;Vertex&amp;gt; getVisibleVertices(vertex v, set&amp;lt;segment&amp;gt; segments)&lt;br /&gt;
// Инициализируем статус&lt;br /&gt;
   for segment s in segments&lt;br /&gt;
      if intersection s and ray from v to up exists&lt;br /&gt;
         status.add(s)&lt;br /&gt;
// Инициализируем множество вершин, которые нужно рассматривать&lt;br /&gt;
   for point w in segments&lt;br /&gt;
      if w.x &amp;gt;= v.x&lt;br /&gt;
         currentVertices.add(w)&lt;br /&gt;
   sort(currentVertices) by angle&lt;br /&gt;
// Для каждой вершины проверяем, видима ли она и обновляем статус&lt;br /&gt;
   for w in currentVertices&lt;br /&gt;
      if intersection vw and status.first not exists&lt;br /&gt;
         answer.add(w)&lt;br /&gt;
      delete from status all edges ending in w&lt;br /&gt;
      add in status all edges beginning in w&lt;br /&gt;
   return answer&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
В качестве статуса нужно использовать структуру данных, позволяющую добавлять и удалять из нее отрезки за &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; и извлекать минимум за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt;. В этом случае достигается асимптотика &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;, так как для каждой из &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; точек выполняется сортировка(&amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;), обновление статуса (суммарно &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, так как каждый отрезок добавляется и удаляется из статуса только один раз) и запросы ближайшего отрезка (&amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; на точку, то есть &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;). &lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zamrefr1.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr2.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr3.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Overmars and Welzl’s Algorithm &amp;lt;tex&amp;gt; O(n ^ 2) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
[http://igitur-archive.library.uu.nl/math/2006-1214-201604/overmars_88_new_methods.pdf visibility graph при помощи rotation tree]&lt;br /&gt;
&lt;br /&gt;
C помощью [http://bit.ly/1eEqTzk rotation tree] можно достичь асимптотики &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Motion planning ==&lt;br /&gt;
[[Файл:mink.png|200px|thumb|left|Изменяем препятствия]]&lt;br /&gt;
[[Файл:mink2.png|400px|thumb|right|Ищем путь для точки]]&lt;br /&gt;
Рассмотрим задачу нахождения кратчайшего пути, когда движимый объект {{---}} это выпуклый полигон. Например, робот, которого надо доставить из начальной в конечную точку.&lt;br /&gt;
&lt;br /&gt;
Если полигон вращать нельзя, задачу сводится к движению точки так : выбирается точка на полигоне, которая принимается за начало координат. В такой системе координат для каждого препятствия считается [[Сумма Минковского (определение, вычисление)|сумма Минковского]] с полигоном. Получаются бОльшие препятствия, но теперь достаточно двигать выбранную точку, что было описано выше.&lt;br /&gt;
&lt;br /&gt;
Если полигон можно вращать, задача нахождения ''кратчайшего'' пути становится достаточно ресурсоёмка, поэтому обычно рассматривают задачу нахождения какого-нибудь пути между конечными точками.&lt;br /&gt;
&lt;br /&gt;
Первый шаг решения этой задачи совпадает с предыдущим случаем : выберем точку и построим [[Сумма Минковского (определение, вычисление)|сумму Минковского]] препятствий с полигоном. Рассмотрим малый угол &amp;lt;tex&amp;gt; \epsilon &amp;lt;/tex&amp;gt;. Представим, что поворот полигона на этот угол {{---}} это движение вверх-вниз между слоями, на каждом из которых посчитана сумма Минковского с полигоном, повернутым на этот угол.&lt;br /&gt;
&lt;br /&gt;
На каждом слое построим трапецоидную карту и граф, как описано в [[Visibility graph и motion planning#Нахождение пути между точками с препятствиями|начале]]. Если [[Пересечение многоугольников (PSLG overlaying)|пересечь]] соседние слои и добавить между их графами ребра, получится один большой граф, в котором ищется кратчайший путь.&lt;br /&gt;
&lt;br /&gt;
При таком подходе может возникнуть ошибка при пересечении слоев : на каждом слое состояния будут допустимые, а осуществить поворот физически будет невозможно. Обычно, эту проблему решают двумя способами : измельчением угла поворота и изначальным сглаживанием углов полигона. Первый способ повышает не только точность решения, но и вычислительную сложность задачи. Второй подход практически исключает возможность нахождения пути, когда его нет, но повышает вероятность &amp;quot;ненахождения&amp;quot; пути, когда он есть.&lt;br /&gt;
&lt;br /&gt;
== Источники ==&lt;br /&gt;
* 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&lt;br /&gt;
* [http://www.academia.edu/2845047/3D_Visibility_Graph статья] про visibility graphs на academia.edu&lt;br /&gt;
* [http://habrahabr.ru/post/199256/ Хабр]&lt;br /&gt;
[[Категория: Вычислительная геометрия]]&lt;br /&gt;
&lt;br /&gt;
== Ссылки ==&lt;br /&gt;
* Моя [https://github.com/Igorjan94/cg/blob/master/include/cg/algorithms/visibilityGraph.h реализация] алгоритма за &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;. Далеко от идеального, но работает&lt;/div&gt;</summary>
		<author><name>Igorjan94</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%9F%D0%B5%D1%80%D0%B5%D1%81%D0%B5%D1%87%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BF%D0%BE%D0%BB%D1%83%D0%BF%D0%BB%D0%BE%D1%81%D0%BA%D0%BE%D1%81%D1%82%D0%B5%D0%B9,_%D1%81%D0%B2%D1%8F%D0%B7%D1%8C_%D1%81_%D0%B2%D1%8B%D0%BF%D1%83%D0%BA%D0%BB%D1%8B%D0%BC%D0%B8_%D0%BE%D0%B1%D0%BE%D0%BB%D0%BE%D1%87%D0%BA%D0%B0%D0%BC%D0%B8&amp;diff=44821</id>
		<title>Пересечение полуплоскостей, связь с выпуклыми оболочками</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%9F%D0%B5%D1%80%D0%B5%D1%81%D0%B5%D1%87%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BF%D0%BE%D0%BB%D1%83%D0%BF%D0%BB%D0%BE%D1%81%D0%BA%D0%BE%D1%81%D1%82%D0%B5%D0%B9,_%D1%81%D0%B2%D1%8F%D0%B7%D1%8C_%D1%81_%D0%B2%D1%8B%D0%BF%D1%83%D0%BA%D0%BB%D1%8B%D0%BC%D0%B8_%D0%BE%D0%B1%D0%BE%D0%BB%D0%BE%D1%87%D0%BA%D0%B0%D0%BC%D0%B8&amp;diff=44821"/>
				<updated>2015-02-09T21:06:12Z</updated>
		
		<summary type="html">&lt;p&gt;Igorjan94: очепятки&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Файл:samplesHalfspaces.png|400px|thumb|right|Пересечение существует и выпукло, неограниченно или пусто]]&lt;br /&gt;
&lt;br /&gt;
Задача: есть конечное множество полуплоскостей, найти фигуру их пересечения или сообщить что оно пусто.&lt;br /&gt;
&lt;br /&gt;
Для начала заметим, что если пересечение не пусто, то оно выпукло. (Доказательство {{---}} Пересечение выпуклых фигур выпукло, а полуплоскость выпукла)&lt;br /&gt;
&lt;br /&gt;
Пусть полуплоскости заданы уравнениями прямых и ориентацией, с какой стороны от прямой лежит полуплоскость.&lt;br /&gt;
&lt;br /&gt;
Сначала рассмотрим все полуплоскости, которые &amp;quot;смотрят&amp;quot;, то есть ориентированны, вниз. Аналогично можно рассмотреть все полуплоскости, которые ориентированны вверх.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
[[Файл:halfSpaces.png|400px|thumb|right|Нужна ли полуплоскость &amp;lt;tex&amp;gt; l'' &amp;lt;/tex&amp;gt;?]]&lt;br /&gt;
Предикат проверки (см. рисунок) того, что прямая &amp;lt;tex&amp;gt; l'' : A''x + B''y + C'' = 0 &amp;lt;/tex&amp;gt; лежит над пересечением прямых &amp;lt;tex&amp;gt; l : Ax + By + C = 0 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; l' : A'x + B'y + C' = 0 &amp;lt;/tex&amp;gt; равен знаку определителя &amp;lt;tex&amp;gt;&lt;br /&gt;
\begin{vmatrix} &lt;br /&gt;
A &amp;amp; B &amp;amp; C \\ &lt;br /&gt;
A' &amp;amp; B' &amp;amp; C' \\ &lt;br /&gt;
A'' &amp;amp; B'' &amp;amp; C'' &lt;br /&gt;
\end{vmatrix}&lt;br /&gt;
&amp;lt;/tex&amp;gt;. &lt;br /&gt;
|proof=&lt;br /&gt;
Для проверки предиката нужно определить знак выражения &amp;lt;tex&amp;gt; A''x_0 + B''y_0 + C'' &amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; (x_0, y_0) &amp;lt;/tex&amp;gt; {{---}} точка пересечения прямых &amp;lt;tex&amp;gt; l' &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt;. Эта точка находится из уравнения &amp;lt;tex&amp;gt; \begin{pmatrix} &lt;br /&gt;
A &amp;amp; B\\ &lt;br /&gt;
A' &amp;amp; B' &lt;br /&gt;
\end{pmatrix}&lt;br /&gt;
\begin{pmatrix} &lt;br /&gt;
x_0\\ &lt;br /&gt;
y_0 &lt;br /&gt;
\end{pmatrix} =&lt;br /&gt;
\begin{pmatrix} &lt;br /&gt;
-C\\ &lt;br /&gt;
-C' &lt;br /&gt;
\end{pmatrix}&lt;br /&gt;
&amp;lt;/tex&amp;gt;. Решением будет &amp;lt;tex&amp;gt;&lt;br /&gt;
\begin{pmatrix} &lt;br /&gt;
x_0\\ &lt;br /&gt;
y_0 &lt;br /&gt;
\end{pmatrix} =&lt;br /&gt;
\frac{&lt;br /&gt;
\begin{pmatrix} &lt;br /&gt;
B' &amp;amp; -B\\ &lt;br /&gt;
-A' &amp;amp; A &lt;br /&gt;
\end{pmatrix}&lt;br /&gt;
\begin{pmatrix} &lt;br /&gt;
-C\\ &lt;br /&gt;
-C' &lt;br /&gt;
\end{pmatrix}}&lt;br /&gt;
{ &lt;br /&gt;
\begin{vmatrix} &lt;br /&gt;
A &amp;amp; B\\ &lt;br /&gt;
A' &amp;amp; B'&lt;br /&gt;
\end{vmatrix}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/tex&amp;gt;. Подставим это решение в &amp;lt;tex&amp;gt; A''x_0 + B''y_0 + C'' &amp;lt;/tex&amp;gt; и домножим на определитель.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;&lt;br /&gt;
A'' (B'; -B)(-C; -C') + B'' (-A'; A)(-C; -C') + C \begin{vmatrix} A &amp;amp; B \\ A' &amp;amp; B' \end{vmatrix} &lt;br /&gt;
= A'' \begin{vmatrix} B' &amp;amp; B \\ -C' &amp;amp; -C \end{vmatrix} - B'' \begin{vmatrix} A' &amp;amp; A \\ -C' &amp;amp; -C \end{vmatrix} + C'' \begin{vmatrix} A &amp;amp; A' \\ B &amp;amp; B' \end{vmatrix} &lt;br /&gt;
= \begin{vmatrix} A'' &amp;amp; A' &amp;amp; A \\ B'' &amp;amp; B' &amp;amp; B \\ -C'' &amp;amp; -C' &amp;amp; -C \end{vmatrix} &lt;br /&gt;
= \begin{vmatrix} A &amp;amp; B &amp;amp; C \\ A' &amp;amp; B' &amp;amp; C' \\ A'' &amp;amp; B'' &amp;amp; C'' \end{vmatrix} &lt;br /&gt;
&amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Таким образом, если представить прямую &amp;lt;tex&amp;gt; Ax + By + C = 0 &amp;lt;/tex&amp;gt; как точку с однородными координатами &amp;lt;tex&amp;gt; (A, B, C) &amp;lt;/tex&amp;gt;, то этот предикат {{---}} всего лишь поворот, а проверка предиката {{---}} проверка очередной точки в [[Статические выпуклые оболочки: Джарвис, Грэхем, Эндрю, Чен, QuickHull#Алгоритм Грэхема|обходе Грэхема]] для нахождения выпуклой оболочки.&lt;br /&gt;
&lt;br /&gt;
Алгоритм:&lt;br /&gt;
* Отсортировать все полуплоскости по углу наклона;&lt;br /&gt;
* Запустить обход Грэхема для полуплоскостей, смотрящих вниз (с предикатом-определителем);&lt;br /&gt;
* Запустить обход Грэхема для полуплоскостей, смотрящих вверх;&lt;br /&gt;
* Пересечь две цепочки.&lt;br /&gt;
&lt;br /&gt;
От пересечения цепочек напрямую зависит фигура пересечения: неограниченная область получается если одна из цепочек пуста, а ограниченная {{---}} когда обе цепочки не пусты и пересекаются.&lt;br /&gt;
&lt;br /&gt;
== Источники ==&lt;br /&gt;
* http://wwwisg.cs.uni-magdeburg.de/ag/lehre/SS2012/GAG/slides/V12.pdf&lt;br /&gt;
&lt;br /&gt;
[[Категория: Вычислительная геометрия]]&lt;/div&gt;</summary>
		<author><name>Igorjan94</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%9F%D0%B5%D1%80%D0%B5%D1%81%D0%B5%D1%87%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BF%D0%BE%D0%BB%D1%83%D0%BF%D0%BB%D0%BE%D1%81%D0%BA%D0%BE%D1%81%D1%82%D0%B5%D0%B9,_%D1%81%D0%B2%D1%8F%D0%B7%D1%8C_%D1%81_%D0%B2%D1%8B%D0%BF%D1%83%D0%BA%D0%BB%D1%8B%D0%BC%D0%B8_%D0%BE%D0%B1%D0%BE%D0%BB%D0%BE%D1%87%D0%BA%D0%B0%D0%BC%D0%B8&amp;diff=44820</id>
		<title>Пересечение полуплоскостей, связь с выпуклыми оболочками</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%9F%D0%B5%D1%80%D0%B5%D1%81%D0%B5%D1%87%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BF%D0%BE%D0%BB%D1%83%D0%BF%D0%BB%D0%BE%D1%81%D0%BA%D0%BE%D1%81%D1%82%D0%B5%D0%B9,_%D1%81%D0%B2%D1%8F%D0%B7%D1%8C_%D1%81_%D0%B2%D1%8B%D0%BF%D1%83%D0%BA%D0%BB%D1%8B%D0%BC%D0%B8_%D0%BE%D0%B1%D0%BE%D0%BB%D0%BE%D1%87%D0%BA%D0%B0%D0%BC%D0%B8&amp;diff=44820"/>
				<updated>2015-02-09T18:42:27Z</updated>
		
		<summary type="html">&lt;p&gt;Igorjan94: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Файл:samplesHalfspaces.png|400px|thumb|right|Пересечение существует и выпукло, неограничено или пусто]]&lt;br /&gt;
&lt;br /&gt;
Задача: есть конечное множество полуплоскотей, найти фигуру их пересечения или сообщить что оно пусто.&lt;br /&gt;
&lt;br /&gt;
Для начала заметим, что если пересечение не пусто, то оно выпукло. (Доказательство {{---}} Пересечение выпуклых фигур выпукло, а полуплоскость выпукла)&lt;br /&gt;
&lt;br /&gt;
Пусть полуплоскости заданы уравнениями прямых и ориентацией, с какой стороны от прямой лежит полуплоскость.&lt;br /&gt;
&lt;br /&gt;
Сначала рассмотрим все полуплоскости, которые &amp;quot;смотрят&amp;quot;, то есть ориентированны, вниз. Аналогично можно рассмотреть все полуплоскости, которые ориентированны вверх.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
[[Файл:halfSpaces.png|400px|thumb|right|Нужна ли полуплоскость &amp;lt;tex&amp;gt; l'' &amp;lt;/tex&amp;gt;?]]&lt;br /&gt;
Предикат проверки (см. рисунок) того, что прямая &amp;lt;tex&amp;gt; l'' : A''x + B''y + C'' = 0 &amp;lt;/tex&amp;gt; лежит над пересечением прямых &amp;lt;tex&amp;gt; l : Ax + By + C = 0 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; l' : A'x + B'y + C' = 0 &amp;lt;/tex&amp;gt; равен знаку определителя &amp;lt;tex&amp;gt;&lt;br /&gt;
\begin{vmatrix} &lt;br /&gt;
A &amp;amp; B &amp;amp; C \\ &lt;br /&gt;
A' &amp;amp; B' &amp;amp; C' \\ &lt;br /&gt;
A'' &amp;amp; B'' &amp;amp; C'' &lt;br /&gt;
\end{vmatrix}&lt;br /&gt;
&amp;lt;/tex&amp;gt;. &lt;br /&gt;
|proof=&lt;br /&gt;
Для проверки предиката нужно определить знак выражения &amp;lt;tex&amp;gt; A''x_0 + B''y_0 + C'' &amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; (x_0, y_0) &amp;lt;/tex&amp;gt; {{---}} точка пересечения прямых &amp;lt;tex&amp;gt; l' &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt;. Эту точку находится из уравнения &amp;lt;tex&amp;gt; \begin{pmatrix} &lt;br /&gt;
A &amp;amp; B\\ &lt;br /&gt;
A' &amp;amp; B' &lt;br /&gt;
\end{pmatrix}&lt;br /&gt;
\begin{pmatrix} &lt;br /&gt;
x_0\\ &lt;br /&gt;
y_0 &lt;br /&gt;
\end{pmatrix} =&lt;br /&gt;
\begin{pmatrix} &lt;br /&gt;
-C\\ &lt;br /&gt;
-C' &lt;br /&gt;
\end{pmatrix}&lt;br /&gt;
&amp;lt;/tex&amp;gt;. Решением будет &amp;lt;tex&amp;gt;&lt;br /&gt;
\begin{pmatrix} &lt;br /&gt;
x_0\\ &lt;br /&gt;
y_0 &lt;br /&gt;
\end{pmatrix} =&lt;br /&gt;
\frac{&lt;br /&gt;
\begin{pmatrix} &lt;br /&gt;
B' &amp;amp; -B\\ &lt;br /&gt;
-A' &amp;amp; A &lt;br /&gt;
\end{pmatrix}&lt;br /&gt;
\begin{pmatrix} &lt;br /&gt;
-C\\ &lt;br /&gt;
-C' &lt;br /&gt;
\end{pmatrix}}&lt;br /&gt;
{ &lt;br /&gt;
\begin{vmatrix} &lt;br /&gt;
A &amp;amp; B\\ &lt;br /&gt;
A' &amp;amp; B'&lt;br /&gt;
\end{vmatrix}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/tex&amp;gt;. Подставим это решение в &amp;lt;tex&amp;gt; A''x_0 + B''y_0 + C'' &amp;lt;/tex&amp;gt; и домножим на определитель.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;&lt;br /&gt;
A'' (B'; -B)(-C; -C') + B'' (-A'; A)(-C; -C') + C \begin{vmatrix} A &amp;amp; B \\ A' &amp;amp; B' \end{vmatrix} &lt;br /&gt;
= A'' \begin{vmatrix} B' &amp;amp; B \\ -C' &amp;amp; -C \end{vmatrix} - B'' \begin{vmatrix} A' &amp;amp; A \\ -C' &amp;amp; -C \end{vmatrix} + C'' \begin{vmatrix} A &amp;amp; A' \\ B &amp;amp; B' \end{vmatrix} &lt;br /&gt;
= \begin{vmatrix} A'' &amp;amp; A' &amp;amp; A \\ B'' &amp;amp; B' &amp;amp; B \\ -C'' &amp;amp; -C' &amp;amp; -C \end{vmatrix} &lt;br /&gt;
= \begin{vmatrix} A &amp;amp; B &amp;amp; C \\ A' &amp;amp; B' &amp;amp; C' \\ A'' &amp;amp; B'' &amp;amp; C'' \end{vmatrix} &lt;br /&gt;
&amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Таким образом, если представить прямую &amp;lt;tex&amp;gt; Ax + By + C = 0 &amp;lt;/tex&amp;gt; как точку с однородными координатами &amp;lt;tex&amp;gt; (A, B, C) &amp;lt;/tex&amp;gt;, то этот предикат {{---}} всего лишь поворот, а проверка предиката {{---}} проверка очередной точки в [[Статические выпуклые оболочки: Джарвис, Грэхем, Эндрю, Чен, QuickHull#Алгоритм Грэхема|обходе Грэхема]] для нахождения выпуклой оболочки.&lt;br /&gt;
&lt;br /&gt;
Алгоритм:&lt;br /&gt;
* Отсортировать все полуплоскости по углу наклона;&lt;br /&gt;
* Запустить обход Грэхема для полуплоскостей, смотрящих вниз (с предикатом-определителем);&lt;br /&gt;
* Запустить обход Грэхема для полуплоскостей, смотрящих вверх;&lt;br /&gt;
* Пересечь две цепочки.&lt;br /&gt;
&lt;br /&gt;
От пересечения цепочек напрямую зависит фигура пересечения: неограниченная область получается если одна из цепочек пуста, а ограниченная {{---}} когда обе цепочки не пусты и пересекаются.&lt;br /&gt;
&lt;br /&gt;
== Источники ==&lt;br /&gt;
* http://wwwisg.cs.uni-magdeburg.de/ag/lehre/SS2012/GAG/slides/V12.pdf&lt;br /&gt;
&lt;br /&gt;
[[Категория: Вычислительная геометрия]]&lt;/div&gt;</summary>
		<author><name>Igorjan94</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%9F%D0%B5%D1%80%D0%B5%D1%81%D0%B5%D1%87%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BF%D0%BE%D0%BB%D1%83%D0%BF%D0%BB%D0%BE%D1%81%D0%BA%D0%BE%D1%81%D1%82%D0%B5%D0%B9,_%D1%81%D0%B2%D1%8F%D0%B7%D1%8C_%D1%81_%D0%B2%D1%8B%D0%BF%D1%83%D0%BA%D0%BB%D1%8B%D0%BC%D0%B8_%D0%BE%D0%B1%D0%BE%D0%BB%D0%BE%D1%87%D0%BA%D0%B0%D0%BC%D0%B8&amp;diff=44819</id>
		<title>Пересечение полуплоскостей, связь с выпуклыми оболочками</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%9F%D0%B5%D1%80%D0%B5%D1%81%D0%B5%D1%87%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BF%D0%BE%D0%BB%D1%83%D0%BF%D0%BB%D0%BE%D1%81%D0%BA%D0%BE%D1%81%D1%82%D0%B5%D0%B9,_%D1%81%D0%B2%D1%8F%D0%B7%D1%8C_%D1%81_%D0%B2%D1%8B%D0%BF%D1%83%D0%BA%D0%BB%D1%8B%D0%BC%D0%B8_%D0%BE%D0%B1%D0%BE%D0%BB%D0%BE%D1%87%D0%BA%D0%B0%D0%BC%D0%B8&amp;diff=44819"/>
				<updated>2015-02-09T18:38:55Z</updated>
		
		<summary type="html">&lt;p&gt;Igorjan94: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Файл:samplesHalfspaces.png|400px|thumb|right|Пересечение существует и выпукло, неограничено или пусто]]&lt;br /&gt;
&lt;br /&gt;
Задача: есть конечное множество полуплоскотей, найти фигуру их пересечения или сообщить что оно пусто.&lt;br /&gt;
&lt;br /&gt;
Для начала заметим, что если пересечение не пусто, то оно выпукло. (Доказательство {{---}} Пересечение выпуклых фигур выпукло, а полуплоскость выпукла)&lt;br /&gt;
&lt;br /&gt;
Пусть полуплоскости заданы уравнениями прямых и ориентацией, с какой стороны от прямой лежит полуплоскость.&lt;br /&gt;
&lt;br /&gt;
Сначала рассмотрим все полуплоскости, которые &amp;quot;смотрят&amp;quot;, то есть ориентированны, вниз. Аналогично можно рассмотреть все полуплоскости, которые ориентированны вверх.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
[[Файл:halfSpaces.png|400px|thumb|right|Нужна ли полуплоскость &amp;lt;tex&amp;gt; l'' &amp;lt;/tex&amp;gt;?]]&lt;br /&gt;
Предикат проверки (см. рисунок) того, что прямая &amp;lt;tex&amp;gt; l'' : A''x + B''y + C'' = 0 &amp;lt;/tex&amp;gt; лежит над пересечением прямых &amp;lt;tex&amp;gt; l : Ax + By + C = 0 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; l' : A'x + B'y + C' = 0 &amp;lt;/tex&amp;gt; равен знаку определителя &amp;lt;tex&amp;gt;&lt;br /&gt;
\begin{vmatrix} &lt;br /&gt;
A &amp;amp; B &amp;amp; C \\ &lt;br /&gt;
A' &amp;amp; B' &amp;amp; C' \\ &lt;br /&gt;
A'' &amp;amp; B'' &amp;amp; C'' &lt;br /&gt;
\end{vmatrix}&lt;br /&gt;
&amp;lt;/tex&amp;gt;. &lt;br /&gt;
|proof=&lt;br /&gt;
Для проверки предиката нужно определить знак выражения &amp;lt;tex&amp;gt; A''x_0 + B''y_0 + C'' &amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; (x_0, y_0) &amp;lt;/tex&amp;gt; {{---}} точка пересечения прямых &amp;lt;tex&amp;gt; l' &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt;. Эту точку находится из уравнения &amp;lt;tex&amp;gt; \begin{pmatrix} &lt;br /&gt;
A &amp;amp; B\\ &lt;br /&gt;
A' &amp;amp; B' &lt;br /&gt;
\end{pmatrix}&lt;br /&gt;
\begin{pmatrix} &lt;br /&gt;
x_0\\ &lt;br /&gt;
y_0 &lt;br /&gt;
\end{pmatrix} =&lt;br /&gt;
\begin{pmatrix} &lt;br /&gt;
-C\\ &lt;br /&gt;
-C' &lt;br /&gt;
\end{pmatrix}&lt;br /&gt;
&amp;lt;/tex&amp;gt;. Решением будет &amp;lt;tex&amp;gt;&lt;br /&gt;
\begin{pmatrix} &lt;br /&gt;
x_0\\ &lt;br /&gt;
y_0 &lt;br /&gt;
\end{pmatrix} =&lt;br /&gt;
\frac{&lt;br /&gt;
\begin{pmatrix} &lt;br /&gt;
B' &amp;amp; -B\\ &lt;br /&gt;
-A' &amp;amp; A &lt;br /&gt;
\end{pmatrix}&lt;br /&gt;
\begin{pmatrix} &lt;br /&gt;
-C\\ &lt;br /&gt;
-C' &lt;br /&gt;
\end{pmatrix}}&lt;br /&gt;
{ &lt;br /&gt;
\begin{vmatrix} &lt;br /&gt;
A &amp;amp; B\\ &lt;br /&gt;
A' &amp;amp; B'&lt;br /&gt;
\end{vmatrix}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/tex&amp;gt;. Подставим это решение в &amp;lt;tex&amp;gt; A''x_0 + B''y_0 + C'' &amp;lt;/tex&amp;gt; и домножим на определитель.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;&lt;br /&gt;
A'' (B'; -B)(-C; -C') + B'' (-A'; A)(-C; -C') + C \begin{vmatrix} A &amp;amp; B \\ A' &amp;amp; B' \end{vmatrix} &lt;br /&gt;
= A'' \begin{vmatrix} B' &amp;amp; B \\ -C' &amp;amp; -C \end{vmatrix} - B'' \begin{vmatrix} A' &amp;amp; A \\ -C' &amp;amp; -C \end{vmatrix} + C'' \begin{vmatrix} A &amp;amp; A' \\ B &amp;amp; B' \end{vmatrix} &lt;br /&gt;
= \begin{vmatrix} A'' &amp;amp; A' &amp;amp; A \\ B'' &amp;amp; B' &amp;amp; B \\ -C'' &amp;amp; -C' &amp;amp; -C \end{vmatrix} &lt;br /&gt;
= \begin{vmatrix} A &amp;amp; B &amp;amp; C \\ A' &amp;amp; B' &amp;amp; C' \\ A'' &amp;amp; B'' &amp;amp; C'' \end{vmatrix} &lt;br /&gt;
&amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Таким образом если представить прямую &amp;lt;tex&amp;gt; Ax + By + C = 0 &amp;lt;/tex&amp;gt; как точку с координатами &amp;lt;tex&amp;gt; (A, B, C) &amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; C &amp;lt;/tex&amp;gt; {{---}} однородная координата, то этот предикат {{---}} всего лишь поворот, а проверка предиката {{---}} проверка очередной точки в [[Статические выпуклые оболочки: Джарвис, Грэхем, Эндрю, Чен, QuickHull#Алгоритм Грэхема|обходе Грэхема]] для нахождения выпуклой оболочки.&lt;br /&gt;
&lt;br /&gt;
Алгоритм:&lt;br /&gt;
* Отсортировать все полуплоскости по углу наклона;&lt;br /&gt;
* Запустить обход Грэхема для полуплоскостей, смотрящих вниз (с предикатом-определителем);&lt;br /&gt;
* Запустить обход Грэхема для полуплоскостей, смотрящих вверх;&lt;br /&gt;
* Пересечь две цепочки.&lt;br /&gt;
&lt;br /&gt;
От пересечения цепочек напрямую зависит фигура пересечения: неограниченная область получается если одна из цепочек пуста, а ограниченная {{---}} когда обе цепочки не пусты и пересекаются.&lt;br /&gt;
&lt;br /&gt;
== Источники ==&lt;br /&gt;
* http://wwwisg.cs.uni-magdeburg.de/ag/lehre/SS2012/GAG/slides/V12.pdf&lt;br /&gt;
&lt;br /&gt;
[[Категория: Вычислительная геометрия]]&lt;/div&gt;</summary>
		<author><name>Igorjan94</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%9F%D0%B5%D1%80%D0%B5%D1%81%D0%B5%D1%87%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BF%D0%BE%D0%BB%D1%83%D0%BF%D0%BB%D0%BE%D1%81%D0%BA%D0%BE%D1%81%D1%82%D0%B5%D0%B9,_%D1%81%D0%B2%D1%8F%D0%B7%D1%8C_%D1%81_%D0%B2%D1%8B%D0%BF%D1%83%D0%BA%D0%BB%D1%8B%D0%BC%D0%B8_%D0%BE%D0%B1%D0%BE%D0%BB%D0%BE%D1%87%D0%BA%D0%B0%D0%BC%D0%B8&amp;diff=44818</id>
		<title>Пересечение полуплоскостей, связь с выпуклыми оболочками</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%9F%D0%B5%D1%80%D0%B5%D1%81%D0%B5%D1%87%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BF%D0%BE%D0%BB%D1%83%D0%BF%D0%BB%D0%BE%D1%81%D0%BA%D0%BE%D1%81%D1%82%D0%B5%D0%B9,_%D1%81%D0%B2%D1%8F%D0%B7%D1%8C_%D1%81_%D0%B2%D1%8B%D0%BF%D1%83%D0%BA%D0%BB%D1%8B%D0%BC%D0%B8_%D0%BE%D0%B1%D0%BE%D0%BB%D0%BE%D1%87%D0%BA%D0%B0%D0%BC%D0%B8&amp;diff=44818"/>
				<updated>2015-02-09T18:33:46Z</updated>
		
		<summary type="html">&lt;p&gt;Igorjan94: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Файл:samplesHalfspaces.png|400px|thumb|right|Пересечение существует и выпукло, неограничено или пусто]]&lt;br /&gt;
&lt;br /&gt;
Задача: есть конечное множество полуплоскотей, найти фигуру их пересечения или сообщить что оно пусто.&lt;br /&gt;
&lt;br /&gt;
Для начала заметим, что если пересечение не пусто, то оно выпукло. (Доказательство {{---}} Пересечение выпуклых фигур выпукло, а полуплоскость выпукла)&lt;br /&gt;
&lt;br /&gt;
Пусть полуплоскости заданы уравнениями прямых и ориентацией, с какой стороны от прямой лежит полуплоскость.&lt;br /&gt;
&lt;br /&gt;
Сначала рассмотрим все полуплоскости, которые &amp;quot;смотрят&amp;quot;, то есть ориентированны, вниз. Аналогично можно рассмотреть все полуплоскости, которые ориентированны вверх.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
[[Файл:halfSpaces.png|400px|thumb|right|Нужна ли полуплоскость &amp;lt;tex&amp;gt; l'' &amp;lt;/tex&amp;gt;?]]&lt;br /&gt;
Предикат проверки (см. рисунок) того, что прямая &amp;lt;tex&amp;gt; l'' : A''x + B''y + C'' = 0 &amp;lt;/tex&amp;gt; лежит над пересечением прямых &amp;lt;tex&amp;gt; l : Ax + By + C = 0 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; l' : A'x + B'y + C' = 0 &amp;lt;/tex&amp;gt; равен знаку определителя &amp;lt;tex&amp;gt;&lt;br /&gt;
\begin{vmatrix} &lt;br /&gt;
A &amp;amp; B &amp;amp; C \\ &lt;br /&gt;
A' &amp;amp; B' &amp;amp; C' \\ &lt;br /&gt;
A'' &amp;amp; B'' &amp;amp; C'' &lt;br /&gt;
\end{vmatrix}&lt;br /&gt;
&amp;lt;/tex&amp;gt;. &lt;br /&gt;
|proof=&lt;br /&gt;
Для проверки предиката нужно определить знак выражения &amp;lt;tex&amp;gt; A''x_0 + B''y_0 + C'' &amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; (x_0, y_0) &amp;lt;/tex&amp;gt; {{---}} точка пересечения прямых &amp;lt;tex&amp;gt; l' &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt;. Эту точку находится из уравнения &amp;lt;tex&amp;gt; \begin{pmatrix} &lt;br /&gt;
A &amp;amp; B\\ &lt;br /&gt;
A' &amp;amp; B' &lt;br /&gt;
\end{pmatrix}&lt;br /&gt;
\begin{pmatrix} &lt;br /&gt;
x_0\\ &lt;br /&gt;
y_0 &lt;br /&gt;
\end{pmatrix} =&lt;br /&gt;
\begin{pmatrix} &lt;br /&gt;
-C\\ &lt;br /&gt;
-C' &lt;br /&gt;
\end{pmatrix}&lt;br /&gt;
&amp;lt;/tex&amp;gt;. Решением будет &amp;lt;tex&amp;gt;&lt;br /&gt;
\begin{pmatrix} &lt;br /&gt;
x_0\\ &lt;br /&gt;
y_0 &lt;br /&gt;
\end{pmatrix} =&lt;br /&gt;
\frac{&lt;br /&gt;
\begin{pmatrix} &lt;br /&gt;
B' &amp;amp; -B\\ &lt;br /&gt;
-A' &amp;amp; A &lt;br /&gt;
\end{pmatrix}&lt;br /&gt;
\begin{pmatrix} &lt;br /&gt;
-C\\ &lt;br /&gt;
-C' &lt;br /&gt;
\end{pmatrix}}&lt;br /&gt;
{ &lt;br /&gt;
\begin{vmatrix} &lt;br /&gt;
A &amp;amp; B\\ &lt;br /&gt;
A' &amp;amp; B'&lt;br /&gt;
\end{vmatrix}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/tex&amp;gt;. Подставим это решение в &amp;lt;tex&amp;gt; A''x_0 + B''y_0 + C'' &amp;lt;/tex&amp;gt; и домножим на определитель.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt; A'' (B'; -B)(-C; -C') + B'' (-A'; A)(-C; -C') + C \begin{vmatrix} A &amp;amp; B \\ A' &amp;amp; B' \end{vmatrix} = A'' \begin{vmatrix} B' &amp;amp; B \\ -C' &amp;amp; -C \end{vmatrix} - B'' \begin{vmatrix} A' &amp;amp; A \\ -C' &amp;amp; -C \end{vmatrix} + C'' \begin{vmatrix} A &amp;amp; A' \\ B &amp;amp; B' \end{vmatrix} = \begin{vmatrix} A'' &amp;amp; A' &amp;amp; A \\ B'' &amp;amp; B' &amp;amp; B \\ -C'' &amp;amp; -C' &amp;amp; -C \end{vmatrix} = \begin{vmatrix} A &amp;amp; B &amp;amp; C \\ &lt;br /&gt;
A' &amp;amp; B' &amp;amp; C' \\ &lt;br /&gt;
A'' &amp;amp; B'' &amp;amp; C'' \end{vmatrix} &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Таким образом если представить прямую &amp;lt;tex&amp;gt; Ax + By + C = 0 &amp;lt;/tex&amp;gt; как точку с координатами &amp;lt;tex&amp;gt; (A, B, C) &amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; C &amp;lt;/tex&amp;gt; {{---}} однородная координата, то этот предикат {{---}} всего лишь поворот, а проверка предиката {{---}} проверка очередной точки в [[Статические выпуклые оболочки: Джарвис, Грэхем, Эндрю, Чен, QuickHull#Алгоритм Грэхема|обходе Грэхема]] для нахождения выпуклой оболочки.&lt;br /&gt;
&lt;br /&gt;
Алгоритм:&lt;br /&gt;
* Отсортировать все полуплоскости по углу наклона;&lt;br /&gt;
* Запустить обход Грэхема для полуплоскостей, смотрящих вниз (с предикатом-определителем);&lt;br /&gt;
* Запустить обход Грэхема для полуплоскостей, смотрящих вверх;&lt;br /&gt;
* Пересечь две цепочки.&lt;br /&gt;
&lt;br /&gt;
От пересечения цепочек напрямую зависит фигура пересечения: неограниченная область получается если одна из цепочек пуста, а ограниченная {{---}} когда обе цепочки не пусты и пересекаются.&lt;br /&gt;
&lt;br /&gt;
== Источники ==&lt;br /&gt;
* http://wwwisg.cs.uni-magdeburg.de/ag/lehre/SS2012/GAG/slides/V12.pdf&lt;br /&gt;
&lt;br /&gt;
[[Категория: Вычислительная геометрия]]&lt;/div&gt;</summary>
		<author><name>Igorjan94</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44817</id>
		<title>Visibility graph и motion planning</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44817"/>
				<updated>2015-02-09T17:59:07Z</updated>
		
		<summary type="html">&lt;p&gt;Igorjan94: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Нахождение пути между точками с препятствиями ==&lt;br /&gt;
{|align=&amp;quot;right&amp;quot;&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
|[[Файл:trap.png|200px|thumb|right|Путь с препятствиями через трапецоидную карту]]&lt;br /&gt;
|[[Файл:notShort.png|300px|thumb|right|Такой путь не самый короткий]]&lt;br /&gt;
|}&lt;br /&gt;
Для начала рассмотрим движение материальной точки. Случай, когда размером и формой движимого объекта пренебречь нельзя, будет рассмотрен [[Visibility graph и motion planning#Motion planning|позднее]]. &lt;br /&gt;
&lt;br /&gt;
Эта задача решается с помощью [[Трапецоидная карта | трапецоидной карты]]. По ней строится граф, ребра которого соединяют центры трапедоидов, а также начальную и конечную вершины с серединами вертикальных сторон трапецоидов. В таком графе ищется путь между начальной и конечной вершинами.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм работает за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; и за линейное количество памяти и хорошо подходит для нахождения какого-нибудь пути между конечными вершинами. Но иногда нужно найти кратчайший путь, и этот алгоритм не подходит, хоть и работает быстро. Однако, решения нахождения кратчайшего пути в лучшем случае работают за &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; времени и памяти (здесь и далее &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество всех вершин).&lt;br /&gt;
&lt;br /&gt;
== Visibility graph ==&lt;br /&gt;
Рассмотрим точное решение нахождения кратчайшего пути на плоскости между двумя точками с полигональными препятствиями с помощью построения графа видимости. После его построения, как и в случае с трапецоидной картой, кратчайший путь ищется любым стандартным алгоритмом поиска (например, алгоритмом [[Алгоритм Дейкстры|Дейкстры]] или [[Алгоритм A*|A*]]).&lt;br /&gt;
&lt;br /&gt;
Для простоты рассуждений начальную и конечную вершины будем считать вершинами полигонов.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|about=О кратчайшем пути&lt;br /&gt;
|statement=&lt;br /&gt;
Любой кратчайший путь между двумя вершинами с полигональными препятствиями представляет собой ломаную, вершины которой {{---}} вершины полигонов.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:short.png|150px|thumb|right|Short cut]]&lt;br /&gt;
Пусть кратчайший путь {{---}} не ломаная. В таком случае, на пути существует такая точка &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, которая не принадлежит ни одному прямому отрезку. Это означает, что существует &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестность точки &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, в которую не попадает ни одно препятствие (случай, когда точка попала на ребро рассматривается аналогично). В таком случае, подпуть, который находится внутри &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности, по неравенству треугольника может быть сокращён по хорде, соединяющий точки пересечения границы &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности с путем. Раз часть пути может быть уменьшена, значит и весь путь может быть уменьшен, а значит исходное предположение некорректно.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
Говорят, что вершина &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; ''видна'' (англ. mutually visible) из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;, если отрезок &amp;lt;tex&amp;gt; uv &amp;lt;/tex&amp;gt; не пересекает ни одного препятствия.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
''Граф видимости'' (англ. visibility graph) {{---}} граф, вершины которого {{---}} вершины полигонов. Между вершинами &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; существует ребро, если из &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; видна &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
В худшем случае в таком графе может быть &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; ребер. Однако по некоторым ребрам кратчайший путь точно не пройдет, и такие ребра из графа можно удалить.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
[[Файл:edgeToDelete.png|150px|thumb|right|Удаляем &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Если существуют вершины &amp;lt;tex&amp;gt; A, B, C &amp;lt;/tex&amp;gt; одного препятствия и вершина &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; такая, что поворот &amp;lt;tex&amp;gt; DBA &amp;lt;/tex&amp;gt; не совпадает с поворотом &amp;lt;tex&amp;gt; DBC &amp;lt;/tex&amp;gt;, то ребро &amp;lt;tex&amp;gt; DB &amp;lt;/tex&amp;gt; не принадлежит кратчайшему пути и его можно удалить из графа. (См. поясняющую картинку справа)&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:edgeNotToDelete.png|200px|thumb|right|Не удаляем &amp;lt;tex&amp;gt; BS &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Путь проходящий через ребро &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt; будет длиннее, чем через соседей точки &amp;lt;tex&amp;gt; B &amp;lt;/tex&amp;gt;, так как по неравенству треугольника &amp;lt;tex&amp;gt; AB + BD &amp;lt; AD &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
По доказанным леммам любое ребро кратчайшего пути содержится в графе. Таким образом, для нахождения кратчайшего пути осталось найти кратчайший путь в этом графе от начальной до конечной вершины.&lt;br /&gt;
&lt;br /&gt;
=== Построение visibility графа ===&lt;br /&gt;
==== Наивный алгоритм. &amp;lt;tex&amp;gt; O(n ^ 3) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
Для каждой пары вершин проверяем, можно ли добавить ребро между ними, то есть нет ли пересечений с полигонами. &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; пар вершин и &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; ребер, то есть &amp;lt;tex&amp;gt; O(n^3) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Lee’s Algorithm. &amp;lt;tex&amp;gt; O(n ^ 2 \log n) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
{|&lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zam.png|300px|thumb|left|Заметание плоскости вращающимся лучом]]&lt;br /&gt;
Однако можно это сделать за &amp;lt;tex&amp;gt; O(n ^ 2 \log  n) &amp;lt;/tex&amp;gt;. Идея алгоритма проста : для каждой вершины найдем видимые из нее вершины. Если научиться делать это за &amp;lt;tex&amp;gt; O(n \log  n) &amp;lt;/tex&amp;gt;, задача решена, так как всего точек &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для каждой вершины будем рассматривать только правую половину плоскости, так как ребра, которые должны идти в левую половину, будут исходить из вершин, для которых текущая вершина будет справа.&lt;br /&gt;
&lt;br /&gt;
Переформулируем задачу. Дано : точка &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и множество отрезков {{---}} ребер препятствий. &lt;br /&gt;
Найти : множество концов отрезков, видимых из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для решения этой задачи будем использовать заметающий луч с началом в точке &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Его статусом будут отрезки, которые его пересекают, упорядоченные по возрастанию расстояния от точки &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; до точки пересечения. Точками событий будут концы отрезков. &lt;br /&gt;
&lt;br /&gt;
Пустим луч из рассматриваемой вершины &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вертикально вверх и добавим в статус все отрезки, которые он пересекает, по увеличению расстояния до них. Теперь будем рассматривать точки &amp;lt;tex&amp;gt; w \in V &amp;lt;/tex&amp;gt; в порядке сортировки по углу между &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и вертикальной полуосью &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt;. При таком обходе проверка видимости вершины будет выполняться за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;, так как достаточно проверить пересечение с отрезком, первым в статусе. Действительно, если вершина не видна, то отрезок &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; пересекает несколько отрезков, лежащих перед &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt;, а значит и ближайший, то есть первый в статусе. В противном случае все пересекаемые лучом отрезки лежат за вершиной &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; и пересечения отрезка &amp;lt;tex&amp;gt; uw &amp;lt;/tex&amp;gt; с ближайшим отрезком в статусе не будет. Вне зависимости от видимости вершины, необходимо изменить статус заметающего луча. Для этого необходимо удалить из статуса все отрезки, которые заканчиваются вершине &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; (лежат слева от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;) и добавить все отрезки, которые в ней начинаются (лежат справа от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Псевдокод =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
graph buildVisibilityGraph(Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
   Set&amp;lt;Vertex&amp;gt; vertices = getVertices(segments)       //получаем все вершины препятствий&lt;br /&gt;
   graph visibilityGraph(vertices)                    //изначально в графе только вершины&lt;br /&gt;
   for Vertex v in vertices                           //для каждой вершины&lt;br /&gt;
      for Vertex w in getVisibleVertices(v, segments) //добавляем в граф все видимые из нее вершины&lt;br /&gt;
         visibilityGraph.addEdge(v, w)&lt;br /&gt;
   return visibilityGraph&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Здесь функция getVisibleVertices(&amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;) возвращает все видимые из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вершины и выглядит так:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
vector&amp;lt;Vertex&amp;gt; getVisibleVertices(vertex v, set&amp;lt;segment&amp;gt; segments)&lt;br /&gt;
// Инициализируем статус&lt;br /&gt;
   for segment s in segments&lt;br /&gt;
      if intersection s and ray from v to up exists&lt;br /&gt;
         status.add(s)&lt;br /&gt;
// Инициализируем множество вершин, которые нужно рассматривать&lt;br /&gt;
   for point w in segments&lt;br /&gt;
      if w.x &amp;gt;= v.x&lt;br /&gt;
         currentVertices.add(w)&lt;br /&gt;
   sort(currentVertices) by angle&lt;br /&gt;
// Для каждой вершины проверяем, видима ли она и обновляем статус&lt;br /&gt;
   for w in currentVertices&lt;br /&gt;
      if intersection vw and status.first not exists&lt;br /&gt;
         answer.add(w)&lt;br /&gt;
      delete from status all edges ending in w&lt;br /&gt;
      add in status all edges beginning in w&lt;br /&gt;
   return answer&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
В качестве статуса нужно использовать структуру данных, позволяющую добавлять и удалять из нее отрезки за &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; и извлекать минимум за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt;. В этом случае достигается асимптотика &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;, так как для каждой из &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; точек выполняется сортировка(&amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;), обновление статуса (суммарно &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, так как каждый отрезок добавляется и удаляется из статуса только один раз) и запросы ближайшего отрезка (&amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; на точку, то есть &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;). &lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zamrefr1.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr2.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr3.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Overmars and Welzl’s Algorithm &amp;lt;tex&amp;gt; O(n ^ 2) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
[http://igitur-archive.library.uu.nl/math/2006-1214-201604/overmars_88_new_methods.pdf visibility graph при помощи rotation tree]&lt;br /&gt;
&lt;br /&gt;
C помощью [http://bit.ly/1eEqTzk rotation tree] можно достичь асимптотики &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Motion planning ==&lt;br /&gt;
[[Файл:mink.png|200px|thumb|left|Изменяем препятствия]]&lt;br /&gt;
[[Файл:mink2.png|400px|thumb|right|Ищем путь для точки]]&lt;br /&gt;
Рассмотрим задачу нахождения кратчайшего пути, когда движимый объект {{---}} это выпуклый полигон. Например, робот, которого надо доставить из начальной в конечную точку.&lt;br /&gt;
&lt;br /&gt;
Если полигон вращать нельзя, задачу сводится к движению точки так : выбирается точка на полигоне, которая принимается за начало координат. В такой системе координат для каждого препятствия считается [[Сумма Минковского (определение, вычисление)|сумма Минковского]] с полигоном. Получаются бОльшие препятствия, но теперь достаточно двигать выбранную точку, что было описано выше.&lt;br /&gt;
&lt;br /&gt;
Если полигон можно вращать, задача нахождения ''кратчайшего'' пути становится достаточно ресурсоёмка, поэтому обычно рассматривают задачу нахождения какого-нибудь пути между конечными точками.&lt;br /&gt;
&lt;br /&gt;
Первый шаг решения этой задачи совпадает с предыдущим случаем : выберем точку и построим [[Сумма Минковского (определение, вычисление)|сумму Минковского]] препятствий с полигоном. Рассмотрим малый угол &amp;lt;tex&amp;gt; \epsilon &amp;lt;/tex&amp;gt;. Представим, что поворот полигона на этот угол {{---}} это движение вверх-вниз между слоями, на каждом из которых посчитана сумма Минковского с полигоном, повернутым на этот угол.&lt;br /&gt;
&lt;br /&gt;
На каждом слое построим трапецоидную карту и граф, как описано в [[Visibility graph и motion planning#Нахождение пути между точками с препятствиями|начале]]. Если [[Пересечение многоугольников (PSLG overlaying)|пересечь]] соседние слои и добавить между их графами ребра, получится один большой граф, в котором ищется кратчайший путь.&lt;br /&gt;
&lt;br /&gt;
При таком подходе может возникнуть ошибка при пересечении слоев : на каждом слое состояния будут допустимые, а осуществить поворот физически будет невозможно. Обычно, эту проблему решают двумя способами : измельчением угла поворота и изначальным сглаживанием углов полигона. Первый способ повышает не только точность решения, но и вычислительную сложность задачи. Второй подход практически исключает возможность нахождения пути, когда его нет, но повышает вероятность &amp;quot;ненахождения&amp;quot; пути, когда он есть.&lt;br /&gt;
&lt;br /&gt;
== Источники ==&lt;br /&gt;
* 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&lt;br /&gt;
* [http://www.academia.edu/2845047/3D_Visibility_Graph статья] про visibility graphs на academia.edu&lt;br /&gt;
* [http://habrahabr.ru/post/199256/ Хабр]&lt;br /&gt;
[[Категория: Вычислительная геометрия]]&lt;br /&gt;
&lt;br /&gt;
== Ссылки ==&lt;br /&gt;
* Моя [https://github.com/Igorjan94/cg/blob/master/include/cg/algorithms/visibilityGraph.h реализация] алгоритма за &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;. Далеко от идеального, но работает&lt;/div&gt;</summary>
		<author><name>Igorjan94</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44816</id>
		<title>Visibility graph и motion planning</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44816"/>
				<updated>2015-02-09T16:31:45Z</updated>
		
		<summary type="html">&lt;p&gt;Igorjan94: /* Motion planning */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Нахождение пути между точками с препятствиями ==&lt;br /&gt;
{|align=&amp;quot;right&amp;quot;&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
|[[Файл:trap.png|200px|thumb|right|Путь с препятствиями через трапецоидную карту]]&lt;br /&gt;
|[[Файл:notShort.png|300px|thumb|right|Такой путь не самый короткий]]&lt;br /&gt;
|}&lt;br /&gt;
Для начала рассмотрим движение материальной точки. Случай, когда размером и формой движимого объекта пренебречь нельзя, будет рассмотрен [[Visibility graph и motion planning#Motion planning|позднее]]. &lt;br /&gt;
&lt;br /&gt;
Обычно эта задача решается с помощью [[Трапецоидная карта | трапецоидной карты]]. По ней строится граф, ребра которого соединяют центры трапедоидов, а также начальную и конечную вершины с серединами вертикальных сторон трапецоидов. В таком графе ищется путь между начальной и конечной вершинами.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм работает за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; и за линейное количество памяти и идеально подходит для нахождения какого-нибудь пути между конечными вершинами. Но иногда нужно найти кратчайший путь, и этот алгоритм не подходит, хоть и дает хорошее приближение. Однако, решения нахождения кратчайшего пути в лучшем случае работают за &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; времени и памяти (здесь и далее &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество всех вершин).&lt;br /&gt;
&lt;br /&gt;
== Visibility graph ==&lt;br /&gt;
Рассмотрим точное решение нахождения кратчайшего пути на плоскости между двумя точками с полигональными препятствиями с помощью построения графа видимости. После его построения, как и в случае с трапецоидной картой, кратчайший путь ищется любым стандартным алгоритмом поиска (например, алгоритмом [[Алгоритм Дейкстры|Дейкстры]] или [[Алгоритм A*|A*]]).&lt;br /&gt;
&lt;br /&gt;
Для простоты рассуждений начальную и конечную вершины будем считать вершинами полигонов.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|about=О кратчайшем пути&lt;br /&gt;
|statement=&lt;br /&gt;
Любой кратчайший путь между двумя вершинами с полигональными препятствиями представляет собой ломаную, вершины которой {{---}} вершины полигонов.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:short.png|150px|thumb|right|Short cut]]&lt;br /&gt;
Пусть кратчайший путь {{---}} не ломаная. В таком случае, на пути существует такая точка &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, которая не принадлежит ни одному прямому отрезку. Это означает, что существует &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестность точки &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, в которую не попадает ни одно препятствие (случай, когда точка попала на ребро рассматривается аналогично). В таком случае, подпуть, который находится внутри &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности, по неравенству треугольника может быть сокращён по хорде, соединяющий точки пересечения границы &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности с путем. Раз часть пути может быть уменьшена, значит и весь путь может быть уменьшен, а значит исходное предположение некорректно.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
Говорят, что вершина &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; ''видна'' (англ. mutually visible) из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;, если отрезок &amp;lt;tex&amp;gt; uv &amp;lt;/tex&amp;gt; не пересекает ни одного препятствия.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
''Граф видимости'' (англ. visibility graph) {{---}} граф, вершины которого {{---}} вершины полигонов. Между вершинами &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; существует ребро, если из &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; видна &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
В худшем случае в таком графе может быть &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; ребер. Однако по некоторым ребрам кратчайший путь точно не пройдет, и такие ребра из графа можно удалить.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
[[Файл:edgeToDelete.png|150px|thumb|right|Удаляем &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Если существуют вершины &amp;lt;tex&amp;gt; A, B, C &amp;lt;/tex&amp;gt; одного препятствия и вершина &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; такая, что поворот &amp;lt;tex&amp;gt; DBA &amp;lt;/tex&amp;gt; не совпадает с поворотом &amp;lt;tex&amp;gt; DBC &amp;lt;/tex&amp;gt;, то ребро &amp;lt;tex&amp;gt; DB &amp;lt;/tex&amp;gt; не принадлежит кратчайшему пути и его можно удалить из графа. (См. поясняющую картинку справа)&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:edgeNotToDelete.png|200px|thumb|right|Не удаляем &amp;lt;tex&amp;gt; BS &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Путь проходящий через ребро &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt; будет длиннее, чем через соседей точки &amp;lt;tex&amp;gt; B &amp;lt;/tex&amp;gt;, так как по неравенству треугольника &amp;lt;tex&amp;gt; AB + BD &amp;lt; AD &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
По доказанным леммам любое ребро кратчайшего пути содержится в графе. Таким образом, для нахождения кратчайшего пути осталось найти кратчайший путь в этом графе от начальной до конечной вершины.&lt;br /&gt;
&lt;br /&gt;
=== Построение visibility графа ===&lt;br /&gt;
==== Наивный алгоритм. &amp;lt;tex&amp;gt; O(n ^ 3) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
Для каждой пары вершин проверяем, можно ли добавить ребро между ними, то есть нет ли пересечений с полигонами. &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; пар вершин и &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; ребер, то есть &amp;lt;tex&amp;gt; O(n^3) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Lee’s Algorithm. &amp;lt;tex&amp;gt; O(n ^ 2 \log n) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
{|&lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zam.png|300px|thumb|left|Заметание плоскости вращающимся лучом]]&lt;br /&gt;
Однако можно это сделать за &amp;lt;tex&amp;gt; O(n ^ 2 \log  n) &amp;lt;/tex&amp;gt;. Идея алгоритма проста : для каждой вершины найдем видимые из нее вершины. Если научиться делать это за &amp;lt;tex&amp;gt; O(n \log  n) &amp;lt;/tex&amp;gt;, задача решена, так как всего точек &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для каждой вершины будем рассматривать только правую половину плоскости, так как ребра, которые должны идти в левую половину, будут исходить из вершин, для которых текущая вершина будет справа.&lt;br /&gt;
&lt;br /&gt;
Переформулируем задачу. Дано : точка &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и множество отрезков {{---}} ребер препятствий. &lt;br /&gt;
Найти : множество концов отрезков, видимых из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для решения этой задачи будем использовать заметающий луч с началом в точке &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Его статусом будут отрезки, которые его пересекают, упорядоченные по возрастанию расстояния от точки &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; до точки пересечения. Точками событий будут концы отрезков. &lt;br /&gt;
&lt;br /&gt;
Пустим луч из рассматриваемой вершины &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вертикально вверх и добавим в статус все отрезки, которые он пересекает, по увеличению расстояния до них. Теперь будем рассматривать точки &amp;lt;tex&amp;gt; w \in V &amp;lt;/tex&amp;gt; в порядке сортировки по углу между &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и вертикальной полуосью &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt;. При таком обходе проверка видимости вершины будет выполняться за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;, так как достаточно проверить пересечение с отрезком, первым в статусе. Действительно, если вершина не видна, то отрезок &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; пересекает несколько отрезков, лежащих перед &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt;, а значит и ближайший, то есть первый в статусе. В противном случае все пересекаемые лучом отрезки лежат за вершиной &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; и пересечения отрезка &amp;lt;tex&amp;gt; uw &amp;lt;/tex&amp;gt; с ближайшим отрезком в статусе не будет. Вне зависимости от видимости вершины, необходимо изменить статус заметающего луча. Для этого необходимо удалить из статуса все отрезки, которые заканчиваются вершине &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; (лежат слева от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;) и добавить все отрезки, которые в ней начинаются (лежат справа от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Псевдокод =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
graph buildVisibilityGraph(Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
   Set&amp;lt;Vertex&amp;gt; vertices = getVertices(segments)       //получаем все вершины препятствий&lt;br /&gt;
   graph visibilityGraph(vertices)                    //изначально в графе только вершины&lt;br /&gt;
   for Vertex v in vertices                           //для каждой вершины&lt;br /&gt;
      for Vertex w in getVisibleVertices(v, segments) //добавляем в граф все видимые из нее вершины&lt;br /&gt;
         visibilityGraph.addEdge(v, w)&lt;br /&gt;
   return visibilityGraph&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Здесь функция getVisibleVertices(&amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;) возвращет все видимые из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вершины и выглядит так:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
vector&amp;lt;Vertex&amp;gt; getVisibleVertices(vertex v, set&amp;lt;segment&amp;gt; segments)&lt;br /&gt;
// Инициализируем статус&lt;br /&gt;
   for segment s in segments&lt;br /&gt;
      if intersection s and ray from v to up exists&lt;br /&gt;
         status.add(s)&lt;br /&gt;
// Инициализируем множество вершин, которые нужно рассматривать&lt;br /&gt;
   for point w in segments&lt;br /&gt;
      if w.x &amp;gt;= v.x&lt;br /&gt;
         currentVertices.add(w)&lt;br /&gt;
   sort(currentVertices) by angle&lt;br /&gt;
// Для каждой вершины проверяем, видима ли она и обновляем статус&lt;br /&gt;
   for w in currentVertices&lt;br /&gt;
      if intersection vw and status.first not exists&lt;br /&gt;
         answer.add(w)&lt;br /&gt;
      delete from status all edges ending in w&lt;br /&gt;
      add in status all edges beginning in w&lt;br /&gt;
   return answer&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
В качестве статуса нужно использовать структуру данных, позволяющую добавлять и удалять из нее отрезки за &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; и извлекать минимум за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt;. В этом случае достигается асимптотика &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;, так как для каждой из &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; точек выполняется сортировка(&amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;), обновление статуса (суммарно &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, так как каждый отрезок добавляется и удаляется из статуса только один раз) и запросы ближайшего отрезка (&amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; на точку, то есть &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;). &lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zamrefr1.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr2.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr3.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Overmars and Welzl’s Algorithm &amp;lt;tex&amp;gt; O(n ^ 2) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
[http://igitur-archive.library.uu.nl/math/2006-1214-201604/overmars_88_new_methods.pdf visibility graph при помощи rotation tree]&lt;br /&gt;
&lt;br /&gt;
C помощью [http://bit.ly/1eEqTzk rotation tree] можно достичь асимптотики &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Motion planning ==&lt;br /&gt;
[[Файл:mink.png|200px|thumb|left|Изменяем препятствия]]&lt;br /&gt;
[[Файл:mink2.png|400px|thumb|right|Ищем путь для точки]]&lt;br /&gt;
Рассмотрим задачу нахождения кратчайшиго пути, когда движимый объект {{---}} это выпуклый полигон. Например, робот, которого надо доставить из начальной в конечную точку.&lt;br /&gt;
&lt;br /&gt;
Если полигон вращать нельзя, задачу сводится к движению точки так : выбирается точка на полигоне, которая принимается за начало координат. В такой системе координат для каждого препятствия считается [[Сумма Минковского (определение, вычисление)|сумма Минковского]] с полигоном. Получаются бОльшие препятствия, но теперь достаточно двигать выбранную точку, что было описано выше.&lt;br /&gt;
&lt;br /&gt;
Если полигон можно вращать, задача нахождения ''кратчайшего'' пути становится достаточно ресурсоёмка, поэтому обычно рассматривают задачу нахождения какого-нибудь пути между конечными точками.&lt;br /&gt;
&lt;br /&gt;
Первый шаг решения этой задачи совпадает с предыдущим случаем : выберем точку и построим [[Сумма Минковского (определение, вычисление)|сумму Минковского]] препятствий с полигоном. Рассмотрим малый угол &amp;lt;tex&amp;gt; \epsilon &amp;lt;/tex&amp;gt;. Представим, что поворот полигона на этот угол {{---}} это движение вверх-вниз между слоями, на каждом из которых посчитана сумма Минковского с полигоном, повернутым на этот угол.&lt;br /&gt;
&lt;br /&gt;
На каждом слое построим трапецоидную карту и граф, как описано в [[Visibility graph и motion planning#Нахождение пути между точками с препятствиями|начале]]. Если [[Пересечение многоугольников (PSLG overlaying)|пересечь]] соседние слои и добавить между их графами ребра, получится один большой граф, в котором ищется кратчайший путь.&lt;br /&gt;
&lt;br /&gt;
При таком подходе может возникнуть ошибка при пересечении слоев : на каждом слое состояния будут допустимые, а осуществить поворот физически будет невозможно. Обычно, эту проблему решают двумя способами : измельчением угла поворота и изначальным сглаживанием углов полигона. Первый способ повышает не только точность решения, но и вычислительную сложность задачи. Второй подход практически исключает возможность нахождения пути, когда его нет, но повышает вероятность &amp;quot;ненахождения&amp;quot; пути, когда он есть.&lt;br /&gt;
&lt;br /&gt;
== Источники ==&lt;br /&gt;
* 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&lt;br /&gt;
* [http://www.academia.edu/2845047/3D_Visibility_Graph статья] про visibility graphs на academia.edu&lt;br /&gt;
* [http://habrahabr.ru/post/199256/ Хабр]&lt;br /&gt;
[[Категория: Вычислительная геометрия]]&lt;br /&gt;
&lt;br /&gt;
== Ссылки ==&lt;br /&gt;
* Моя [https://github.com/Igorjan94/cg/blob/master/include/cg/algorithms/visibilityGraph.h реализация] алгоритма за &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;. Далеко от идеального, но работает&lt;/div&gt;</summary>
		<author><name>Igorjan94</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44815</id>
		<title>Visibility graph и motion planning</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44815"/>
				<updated>2015-02-09T16:28:54Z</updated>
		
		<summary type="html">&lt;p&gt;Igorjan94: /* Motion planning */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Нахождение пути между точками с препятствиями ==&lt;br /&gt;
{|align=&amp;quot;right&amp;quot;&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
|[[Файл:trap.png|200px|thumb|right|Путь с препятствиями через трапецоидную карту]]&lt;br /&gt;
|[[Файл:notShort.png|300px|thumb|right|Такой путь не самый короткий]]&lt;br /&gt;
|}&lt;br /&gt;
Для начала рассмотрим движение материальной точки. Случай, когда размером и формой движимого объекта пренебречь нельзя, будет рассмотрен [[Visibility graph и motion planning#Motion planning|позднее]]. &lt;br /&gt;
&lt;br /&gt;
Обычно эта задача решается с помощью [[Трапецоидная карта | трапецоидной карты]]. По ней строится граф, ребра которого соединяют центры трапедоидов, а также начальную и конечную вершины с серединами вертикальных сторон трапецоидов. В таком графе ищется путь между начальной и конечной вершинами.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм работает за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; и за линейное количество памяти и идеально подходит для нахождения какого-нибудь пути между конечными вершинами. Но иногда нужно найти кратчайший путь, и этот алгоритм не подходит, хоть и дает хорошее приближение. Однако, решения нахождения кратчайшего пути в лучшем случае работают за &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; времени и памяти (здесь и далее &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество всех вершин).&lt;br /&gt;
&lt;br /&gt;
== Visibility graph ==&lt;br /&gt;
Рассмотрим точное решение нахождения кратчайшего пути на плоскости между двумя точками с полигональными препятствиями с помощью построения графа видимости. После его построения, как и в случае с трапецоидной картой, кратчайший путь ищется любым стандартным алгоритмом поиска (например, алгоритмом [[Алгоритм Дейкстры|Дейкстры]] или [[Алгоритм A*|A*]]).&lt;br /&gt;
&lt;br /&gt;
Для простоты рассуждений начальную и конечную вершины будем считать вершинами полигонов.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|about=О кратчайшем пути&lt;br /&gt;
|statement=&lt;br /&gt;
Любой кратчайший путь между двумя вершинами с полигональными препятствиями представляет собой ломаную, вершины которой {{---}} вершины полигонов.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:short.png|150px|thumb|right|Short cut]]&lt;br /&gt;
Пусть кратчайший путь {{---}} не ломаная. В таком случае, на пути существует такая точка &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, которая не принадлежит ни одному прямому отрезку. Это означает, что существует &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестность точки &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, в которую не попадает ни одно препятствие (случай, когда точка попала на ребро рассматривается аналогично). В таком случае, подпуть, который находится внутри &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности, по неравенству треугольника может быть сокращён по хорде, соединяющий точки пересечения границы &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности с путем. Раз часть пути может быть уменьшена, значит и весь путь может быть уменьшен, а значит исходное предположение некорректно.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
Говорят, что вершина &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; ''видна'' (англ. mutually visible) из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;, если отрезок &amp;lt;tex&amp;gt; uv &amp;lt;/tex&amp;gt; не пересекает ни одного препятствия.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
''Граф видимости'' (англ. visibility graph) {{---}} граф, вершины которого {{---}} вершины полигонов. Между вершинами &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; существует ребро, если из &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; видна &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
В худшем случае в таком графе может быть &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; ребер. Однако по некоторым ребрам кратчайший путь точно не пройдет, и такие ребра из графа можно удалить.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
[[Файл:edgeToDelete.png|150px|thumb|right|Удаляем &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Если существуют вершины &amp;lt;tex&amp;gt; A, B, C &amp;lt;/tex&amp;gt; одного препятствия и вершина &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; такая, что поворот &amp;lt;tex&amp;gt; DBA &amp;lt;/tex&amp;gt; не совпадает с поворотом &amp;lt;tex&amp;gt; DBC &amp;lt;/tex&amp;gt;, то ребро &amp;lt;tex&amp;gt; DB &amp;lt;/tex&amp;gt; не принадлежит кратчайшему пути и его можно удалить из графа. (См. поясняющую картинку справа)&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:edgeNotToDelete.png|200px|thumb|right|Не удаляем &amp;lt;tex&amp;gt; BS &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Путь проходящий через ребро &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt; будет длиннее, чем через соседей точки &amp;lt;tex&amp;gt; B &amp;lt;/tex&amp;gt;, так как по неравенству треугольника &amp;lt;tex&amp;gt; AB + BD &amp;lt; AD &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
По доказанным леммам любое ребро кратчайшего пути содержится в графе. Таким образом, для нахождения кратчайшего пути осталось найти кратчайший путь в этом графе от начальной до конечной вершины.&lt;br /&gt;
&lt;br /&gt;
=== Построение visibility графа ===&lt;br /&gt;
==== Наивный алгоритм. &amp;lt;tex&amp;gt; O(n ^ 3) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
Для каждой пары вершин проверяем, можно ли добавить ребро между ними, то есть нет ли пересечений с полигонами. &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; пар вершин и &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; ребер, то есть &amp;lt;tex&amp;gt; O(n^3) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Lee’s Algorithm. &amp;lt;tex&amp;gt; O(n ^ 2 \log n) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
{|&lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zam.png|300px|thumb|left|Заметание плоскости вращающимся лучом]]&lt;br /&gt;
Однако можно это сделать за &amp;lt;tex&amp;gt; O(n ^ 2 \log  n) &amp;lt;/tex&amp;gt;. Идея алгоритма проста : для каждой вершины найдем видимые из нее вершины. Если научиться делать это за &amp;lt;tex&amp;gt; O(n \log  n) &amp;lt;/tex&amp;gt;, задача решена, так как всего точек &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для каждой вершины будем рассматривать только правую половину плоскости, так как ребра, которые должны идти в левую половину, будут исходить из вершин, для которых текущая вершина будет справа.&lt;br /&gt;
&lt;br /&gt;
Переформулируем задачу. Дано : точка &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и множество отрезков {{---}} ребер препятствий. &lt;br /&gt;
Найти : множество концов отрезков, видимых из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для решения этой задачи будем использовать заметающий луч с началом в точке &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Его статусом будут отрезки, которые его пересекают, упорядоченные по возрастанию расстояния от точки &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; до точки пересечения. Точками событий будут концы отрезков. &lt;br /&gt;
&lt;br /&gt;
Пустим луч из рассматриваемой вершины &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вертикально вверх и добавим в статус все отрезки, которые он пересекает, по увеличению расстояния до них. Теперь будем рассматривать точки &amp;lt;tex&amp;gt; w \in V &amp;lt;/tex&amp;gt; в порядке сортировки по углу между &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и вертикальной полуосью &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt;. При таком обходе проверка видимости вершины будет выполняться за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;, так как достаточно проверить пересечение с отрезком, первым в статусе. Действительно, если вершина не видна, то отрезок &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; пересекает несколько отрезков, лежащих перед &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt;, а значит и ближайший, то есть первый в статусе. В противном случае все пересекаемые лучом отрезки лежат за вершиной &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; и пересечения отрезка &amp;lt;tex&amp;gt; uw &amp;lt;/tex&amp;gt; с ближайшим отрезком в статусе не будет. Вне зависимости от видимости вершины, необходимо изменить статус заметающего луча. Для этого необходимо удалить из статуса все отрезки, которые заканчиваются вершине &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; (лежат слева от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;) и добавить все отрезки, которые в ней начинаются (лежат справа от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Псевдокод =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
graph buildVisibilityGraph(Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
   Set&amp;lt;Vertex&amp;gt; vertices = getVertices(segments)       //получаем все вершины препятствий&lt;br /&gt;
   graph visibilityGraph(vertices)                    //изначально в графе только вершины&lt;br /&gt;
   for Vertex v in vertices                           //для каждой вершины&lt;br /&gt;
      for Vertex w in getVisibleVertices(v, segments) //добавляем в граф все видимые из нее вершины&lt;br /&gt;
         visibilityGraph.addEdge(v, w)&lt;br /&gt;
   return visibilityGraph&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Здесь функция getVisibleVertices(&amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;) возвращет все видимые из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вершины и выглядит так:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
vector&amp;lt;Vertex&amp;gt; getVisibleVertices(vertex v, set&amp;lt;segment&amp;gt; segments)&lt;br /&gt;
// Инициализируем статус&lt;br /&gt;
   for segment s in segments&lt;br /&gt;
      if intersection s and ray from v to up exists&lt;br /&gt;
         status.add(s)&lt;br /&gt;
// Инициализируем множество вершин, которые нужно рассматривать&lt;br /&gt;
   for point w in segments&lt;br /&gt;
      if w.x &amp;gt;= v.x&lt;br /&gt;
         currentVertices.add(w)&lt;br /&gt;
   sort(currentVertices) by angle&lt;br /&gt;
// Для каждой вершины проверяем, видима ли она и обновляем статус&lt;br /&gt;
   for w in currentVertices&lt;br /&gt;
      if intersection vw and status.first not exists&lt;br /&gt;
         answer.add(w)&lt;br /&gt;
      delete from status all edges ending in w&lt;br /&gt;
      add in status all edges beginning in w&lt;br /&gt;
   return answer&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
В качестве статуса нужно использовать структуру данных, позволяющую добавлять и удалять из нее отрезки за &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; и извлекать минимум за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt;. В этом случае достигается асимптотика &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;, так как для каждой из &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; точек выполняется сортировка(&amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;), обновление статуса (суммарно &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, так как каждый отрезок добавляется и удаляется из статуса только один раз) и запросы ближайшего отрезка (&amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; на точку, то есть &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;). &lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zamrefr1.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr2.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr3.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Overmars and Welzl’s Algorithm &amp;lt;tex&amp;gt; O(n ^ 2) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
[http://igitur-archive.library.uu.nl/math/2006-1214-201604/overmars_88_new_methods.pdf visibility graph при помощи rotation tree]&lt;br /&gt;
&lt;br /&gt;
C помощью [http://bit.ly/1eEqTzk rotation tree] можно достичь асимптотики &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Motion planning ==&lt;br /&gt;
[[Файл:mink.png|200px|thumb|left|Изменяем препятствия]]&lt;br /&gt;
[[Файл:mink2.png|400px|thumb|right|Ищем путь для точки]]&lt;br /&gt;
Рассмотрим задачу нахождения кратчайшиго пути, когда движимый объект {{---}} это выпуклый полигон. Например, робот, которого надо доставить из начальной в конечную точку.&lt;br /&gt;
&lt;br /&gt;
Если полигон вращать нельзя, задачу сводится к движению точки так : выбирается точка на полигоне, которая принимается за начало координат. В такой системе координат для каждого препятствия считается [[Сумма Минковского (определение, вычисление)|сумма Минковского]] с полигоном. Получаются бОльшие препятствия, но теперь достаточно двигать выбранную точку, что было описано выше.&lt;br /&gt;
&lt;br /&gt;
Если полигон можно вращать, задача нахождения ''кратчайшего'' пути становится достаточно ресурсоёмка, поэтому обычно рассматривают нахождение какого-нибудь пути между конечными точками.&lt;br /&gt;
&lt;br /&gt;
Первый шаг решения этой задачи совпадает с предыдущим случаем : выберем точку и построим [[Сумма Минковского (определение, вычисление)|сумма Минковского]] препятствий с полигоном. Рассмотрим малый угол &amp;lt;tex&amp;gt; \epsilon &amp;lt;/tex&amp;gt;. Представим, что поворот полигона на этот угол {{---}} это движение вверх-вниз между слоями, на каждом из которых посчитана сумма Минковского с полигоном, повернутым на этот угол.&lt;br /&gt;
&lt;br /&gt;
На каждом слое построим трапецоидную карту и граф, как описано в [[Visibility graph и motion planning#Нахождение пути между точками с препятствиями|начале]]. Если [[Пересечение многоугольников (PSLG overlaying)|пересечь]] соседние слои и добавить между их графами ребра, получится один большой граф, в котором ищется кратчайший путь.&lt;br /&gt;
&lt;br /&gt;
При таком подходе может возникнуть ошибка при пересечении слоев : на каждом слое состояния будут допустимые, а осуществить поворот физически будет невозможно. Обычно, эту проблему решают двумя способами : измельчением угла поворота и изначальным сглаживанием углов полигона. Первый способ повышает не только точность решения, но вычислительную сложность задачи. Второй подход практически исключает возможность нахождения пути, когда его нет, но повышает вероятность &amp;quot;ненахождения&amp;quot; пути, когда он есть.&lt;br /&gt;
&lt;br /&gt;
== Источники ==&lt;br /&gt;
* 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&lt;br /&gt;
* [http://www.academia.edu/2845047/3D_Visibility_Graph статья] про visibility graphs на academia.edu&lt;br /&gt;
* [http://habrahabr.ru/post/199256/ Хабр]&lt;br /&gt;
[[Категория: Вычислительная геометрия]]&lt;br /&gt;
&lt;br /&gt;
== Ссылки ==&lt;br /&gt;
* Моя [https://github.com/Igorjan94/cg/blob/master/include/cg/algorithms/visibilityGraph.h реализация] алгоритма за &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;. Далеко от идеального, но работает&lt;/div&gt;</summary>
		<author><name>Igorjan94</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44814</id>
		<title>Visibility graph и motion planning</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44814"/>
				<updated>2015-02-09T15:56:10Z</updated>
		
		<summary type="html">&lt;p&gt;Igorjan94: /* Motion planning */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Нахождение пути между точками с препятствиями ==&lt;br /&gt;
{|align=&amp;quot;right&amp;quot;&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
|[[Файл:trap.png|200px|thumb|right|Путь с препятствиями через трапецоидную карту]]&lt;br /&gt;
|[[Файл:notShort.png|300px|thumb|right|Такой путь не самый короткий]]&lt;br /&gt;
|}&lt;br /&gt;
Для начала рассмотрим движение материальной точки. Случай, когда размером и формой движимого объекта пренебречь нельзя, будет рассмотрен [[Visibility graph и motion planning#Motion planning|позднее]]. &lt;br /&gt;
&lt;br /&gt;
Обычно эта задача решается с помощью [[Трапецоидная карта | трапецоидной карты]]. По ней строится граф, ребра которого соединяют центры трапедоидов, а также начальную и конечную вершины с серединами вертикальных сторон трапецоидов. В таком графе ищется путь между начальной и конечной вершинами.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм работает за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; и за линейное количество памяти и идеально подходит для нахождения какого-нибудь пути между конечными вершинами. Но иногда нужно найти кратчайший путь, и этот алгоритм не подходит, хоть и дает хорошее приближение. Однако, решения нахождения кратчайшего пути в лучшем случае работают за &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; времени и памяти (здесь и далее &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество всех вершин).&lt;br /&gt;
&lt;br /&gt;
== Visibility graph ==&lt;br /&gt;
Рассмотрим точное решение нахождения кратчайшего пути на плоскости между двумя точками с полигональными препятствиями с помощью построения графа видимости. После его построения, как и в случае с трапецоидной картой, кратчайший путь ищется любым стандартным алгоритмом поиска (например, алгоритмом [[Алгоритм Дейкстры|Дейкстры]] или [[Алгоритм A*|A*]]).&lt;br /&gt;
&lt;br /&gt;
Для простоты рассуждений начальную и конечную вершины будем считать вершинами полигонов.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|about=О кратчайшем пути&lt;br /&gt;
|statement=&lt;br /&gt;
Любой кратчайший путь между двумя вершинами с полигональными препятствиями представляет собой ломаную, вершины которой {{---}} вершины полигонов.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:short.png|150px|thumb|right|Short cut]]&lt;br /&gt;
Пусть кратчайший путь {{---}} не ломаная. В таком случае, на пути существует такая точка &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, которая не принадлежит ни одному прямому отрезку. Это означает, что существует &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестность точки &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, в которую не попадает ни одно препятствие (случай, когда точка попала на ребро рассматривается аналогично). В таком случае, подпуть, который находится внутри &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности, по неравенству треугольника может быть сокращён по хорде, соединяющий точки пересечения границы &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности с путем. Раз часть пути может быть уменьшена, значит и весь путь может быть уменьшен, а значит исходное предположение некорректно.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
Говорят, что вершина &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; ''видна'' (англ. mutually visible) из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;, если отрезок &amp;lt;tex&amp;gt; uv &amp;lt;/tex&amp;gt; не пересекает ни одного препятствия.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
''Граф видимости'' (англ. visibility graph) {{---}} граф, вершины которого {{---}} вершины полигонов. Между вершинами &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; существует ребро, если из &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; видна &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
В худшем случае в таком графе может быть &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; ребер. Однако по некоторым ребрам кратчайший путь точно не пройдет, и такие ребра из графа можно удалить.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
[[Файл:edgeToDelete.png|150px|thumb|right|Удаляем &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Если существуют вершины &amp;lt;tex&amp;gt; A, B, C &amp;lt;/tex&amp;gt; одного препятствия и вершина &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; такая, что поворот &amp;lt;tex&amp;gt; DBA &amp;lt;/tex&amp;gt; не совпадает с поворотом &amp;lt;tex&amp;gt; DBC &amp;lt;/tex&amp;gt;, то ребро &amp;lt;tex&amp;gt; DB &amp;lt;/tex&amp;gt; не принадлежит кратчайшему пути и его можно удалить из графа. (См. поясняющую картинку справа)&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:edgeNotToDelete.png|200px|thumb|right|Не удаляем &amp;lt;tex&amp;gt; BS &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Путь проходящий через ребро &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt; будет длиннее, чем через соседей точки &amp;lt;tex&amp;gt; B &amp;lt;/tex&amp;gt;, так как по неравенству треугольника &amp;lt;tex&amp;gt; AB + BD &amp;lt; AD &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
По доказанным леммам любое ребро кратчайшего пути содержится в графе. Таким образом, для нахождения кратчайшего пути осталось найти кратчайший путь в этом графе от начальной до конечной вершины.&lt;br /&gt;
&lt;br /&gt;
=== Построение visibility графа ===&lt;br /&gt;
==== Наивный алгоритм. &amp;lt;tex&amp;gt; O(n ^ 3) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
Для каждой пары вершин проверяем, можно ли добавить ребро между ними, то есть нет ли пересечений с полигонами. &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; пар вершин и &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; ребер, то есть &amp;lt;tex&amp;gt; O(n^3) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Lee’s Algorithm. &amp;lt;tex&amp;gt; O(n ^ 2 \log n) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
{|&lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zam.png|300px|thumb|left|Заметание плоскости вращающимся лучом]]&lt;br /&gt;
Однако можно это сделать за &amp;lt;tex&amp;gt; O(n ^ 2 \log  n) &amp;lt;/tex&amp;gt;. Идея алгоритма проста : для каждой вершины найдем видимые из нее вершины. Если научиться делать это за &amp;lt;tex&amp;gt; O(n \log  n) &amp;lt;/tex&amp;gt;, задача решена, так как всего точек &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для каждой вершины будем рассматривать только правую половину плоскости, так как ребра, которые должны идти в левую половину, будут исходить из вершин, для которых текущая вершина будет справа.&lt;br /&gt;
&lt;br /&gt;
Переформулируем задачу. Дано : точка &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и множество отрезков {{---}} ребер препятствий. &lt;br /&gt;
Найти : множество концов отрезков, видимых из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для решения этой задачи будем использовать заметающий луч с началом в точке &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Его статусом будут отрезки, которые его пересекают, упорядоченные по возрастанию расстояния от точки &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; до точки пересечения. Точками событий будут концы отрезков. &lt;br /&gt;
&lt;br /&gt;
Пустим луч из рассматриваемой вершины &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вертикально вверх и добавим в статус все отрезки, которые он пересекает, по увеличению расстояния до них. Теперь будем рассматривать точки &amp;lt;tex&amp;gt; w \in V &amp;lt;/tex&amp;gt; в порядке сортировки по углу между &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и вертикальной полуосью &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt;. При таком обходе проверка видимости вершины будет выполняться за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;, так как достаточно проверить пересечение с отрезком, первым в статусе. Действительно, если вершина не видна, то отрезок &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; пересекает несколько отрезков, лежащих перед &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt;, а значит и ближайший, то есть первый в статусе. В противном случае все пересекаемые лучом отрезки лежат за вершиной &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; и пересечения отрезка &amp;lt;tex&amp;gt; uw &amp;lt;/tex&amp;gt; с ближайшим отрезком в статусе не будет. Вне зависимости от видимости вершины, необходимо изменить статус заметающего луча. Для этого необходимо удалить из статуса все отрезки, которые заканчиваются вершине &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; (лежат слева от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;) и добавить все отрезки, которые в ней начинаются (лежат справа от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Псевдокод =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
graph buildVisibilityGraph(Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
   Set&amp;lt;Vertex&amp;gt; vertices = getVertices(segments)       //получаем все вершины препятствий&lt;br /&gt;
   graph visibilityGraph(vertices)                    //изначально в графе только вершины&lt;br /&gt;
   for Vertex v in vertices                           //для каждой вершины&lt;br /&gt;
      for Vertex w in getVisibleVertices(v, segments) //добавляем в граф все видимые из нее вершины&lt;br /&gt;
         visibilityGraph.addEdge(v, w)&lt;br /&gt;
   return visibilityGraph&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Здесь функция getVisibleVertices(&amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;) возвращет все видимые из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вершины и выглядит так:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
vector&amp;lt;Vertex&amp;gt; getVisibleVertices(vertex v, set&amp;lt;segment&amp;gt; segments)&lt;br /&gt;
// Инициализируем статус&lt;br /&gt;
   for segment s in segments&lt;br /&gt;
      if intersection s and ray from v to up exists&lt;br /&gt;
         status.add(s)&lt;br /&gt;
// Инициализируем множество вершин, которые нужно рассматривать&lt;br /&gt;
   for point w in segments&lt;br /&gt;
      if w.x &amp;gt;= v.x&lt;br /&gt;
         currentVertices.add(w)&lt;br /&gt;
   sort(currentVertices) by angle&lt;br /&gt;
// Для каждой вершины проверяем, видима ли она и обновляем статус&lt;br /&gt;
   for w in currentVertices&lt;br /&gt;
      if intersection vw and status.first not exists&lt;br /&gt;
         answer.add(w)&lt;br /&gt;
      delete from status all edges ending in w&lt;br /&gt;
      add in status all edges beginning in w&lt;br /&gt;
   return answer&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
В качестве статуса нужно использовать структуру данных, позволяющую добавлять и удалять из нее отрезки за &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; и извлекать минимум за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt;. В этом случае достигается асимптотика &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;, так как для каждой из &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; точек выполняется сортировка(&amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;), обновление статуса (суммарно &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, так как каждый отрезок добавляется и удаляется из статуса только один раз) и запросы ближайшего отрезка (&amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; на точку, то есть &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;). &lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zamrefr1.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr2.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr3.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Overmars and Welzl’s Algorithm &amp;lt;tex&amp;gt; O(n ^ 2) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
[http://igitur-archive.library.uu.nl/math/2006-1214-201604/overmars_88_new_methods.pdf visibility graph при помощи rotation tree]&lt;br /&gt;
&lt;br /&gt;
C помощью [http://bit.ly/1eEqTzk rotation tree] можно достичь асимптотики &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Motion planning ==&lt;br /&gt;
[[Файл:mink.png|200px|thumb|left|Изменяем препятствия]]&lt;br /&gt;
[[Файл:mink2.png|400px|thumb|right|Ищем путь для точки]]&lt;br /&gt;
Рассмотрим задачу нахождения кратчайшиго пути, когда движимый объект {{---}} это выпуклый полигон. Например, робот, которого надо доставить из начальной в конечную точку.&lt;br /&gt;
&lt;br /&gt;
Если полигон вращать нельзя, задача сводится к движению точки. Выбирается точка на полигоне, которая принимается за начало координат. В такой системе координат для каждого препятствия считается [[Сумма Минковского (определение, вычисление)|сумма Минковского]] с полигоном. Получаются бОльшие препятствия, но теперь достаточно двигать точку, что было описано выше.&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим случай, когда мы можем вращать полигон. Для начала построим [[Трапецоидная карта|трапецоидную карту]], как будто мы не можем вращать полигон. Теперь будем вращать полигон на малый угол, пока он не сделает полный оборот вокруг своей оси, и для каждого угла сделаем трапецоидную карту. Теперь разместим(мысленно) все карты друг над другом. Таким образом получится, что поворот на малый угол {{---}} это движение вверх/вниз между слоями. Осталось [[Пересечение многоугольников (PSLG overlaying)|попересекать]] соседние слои и добавить между ними ребра (помним что первый и последний слои одинаковы) и уже в этом графе найти путь.&lt;br /&gt;
&lt;br /&gt;
При такой реализации в некоторых случаях у нас может возникнуть ошибка в повороте, так как в одной плоскости мы все можем делать точно: положения на соседних слоях могут допускаться, а повернуть мы не сможем. Это лечится в основном двумя способами: измельчением угла поворота и изначальным сглаживанием углов полигона {{---}} повращать полигон на &amp;lt;tex&amp;gt; +\epsilon &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; -\epsilon &amp;lt;/tex&amp;gt; и объединить с исходным, получив новый полигон.&lt;br /&gt;
&lt;br /&gt;
Так как эта задача достаточно ресурсоемка, мы рассматриваем только наличие пути, а не нахождение кратчайшего.&lt;br /&gt;
&lt;br /&gt;
== Источники ==&lt;br /&gt;
* 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&lt;br /&gt;
* [http://www.academia.edu/2845047/3D_Visibility_Graph статья] про visibility graphs на academia.edu&lt;br /&gt;
* [http://habrahabr.ru/post/199256/ Хабр]&lt;br /&gt;
[[Категория: Вычислительная геометрия]]&lt;br /&gt;
&lt;br /&gt;
== Ссылки ==&lt;br /&gt;
* Моя [https://github.com/Igorjan94/cg/blob/master/include/cg/algorithms/visibilityGraph.h реализация] алгоритма за &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;. Далеко от идеального, но работает&lt;/div&gt;</summary>
		<author><name>Igorjan94</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44813</id>
		<title>Visibility graph и motion planning</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44813"/>
				<updated>2015-02-08T20:09:57Z</updated>
		
		<summary type="html">&lt;p&gt;Igorjan94: /* Visibility graph */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Нахождение пути между точками с препятствиями ==&lt;br /&gt;
{|align=&amp;quot;right&amp;quot;&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
|[[Файл:trap.png|200px|thumb|right|Путь с препятствиями через трапецоидную карту]]&lt;br /&gt;
|[[Файл:notShort.png|300px|thumb|right|Такой путь не самый короткий]]&lt;br /&gt;
|}&lt;br /&gt;
Для начала рассмотрим движение материальной точки. Случай, когда размером и формой движимого объекта пренебречь нельзя, будет рассмотрен [[Visibility graph и motion planning#Motion planning|позднее]]. &lt;br /&gt;
&lt;br /&gt;
Обычно эта задача решается с помощью [[Трапецоидная карта | трапецоидной карты]]. По ней строится граф, ребра которого соединяют центры трапедоидов, а также начальную и конечную вершины с серединами вертикальных сторон трапецоидов. В таком графе ищется путь между начальной и конечной вершинами.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм работает за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; и за линейное количество памяти и идеально подходит для нахождения какого-нибудь пути между конечными вершинами. Но иногда нужно найти кратчайший путь, и этот алгоритм не подходит, хоть и дает хорошее приближение. Однако, решения нахождения кратчайшего пути в лучшем случае работают за &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; времени и памяти (здесь и далее &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество всех вершин).&lt;br /&gt;
&lt;br /&gt;
== Visibility graph ==&lt;br /&gt;
Рассмотрим точное решение нахождения кратчайшего пути на плоскости между двумя точками с полигональными препятствиями с помощью построения графа видимости. После его построения, как и в случае с трапецоидной картой, кратчайший путь ищется любым стандартным алгоритмом поиска (например, алгоритмом [[Алгоритм Дейкстры|Дейкстры]] или [[Алгоритм A*|A*]]).&lt;br /&gt;
&lt;br /&gt;
Для простоты рассуждений начальную и конечную вершины будем считать вершинами полигонов.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|about=О кратчайшем пути&lt;br /&gt;
|statement=&lt;br /&gt;
Любой кратчайший путь между двумя вершинами с полигональными препятствиями представляет собой ломаную, вершины которой {{---}} вершины полигонов.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:short.png|150px|thumb|right|Short cut]]&lt;br /&gt;
Пусть кратчайший путь {{---}} не ломаная. В таком случае, на пути существует такая точка &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, которая не принадлежит ни одному прямому отрезку. Это означает, что существует &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестность точки &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, в которую не попадает ни одно препятствие (случай, когда точка попала на ребро рассматривается аналогично). В таком случае, подпуть, который находится внутри &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности, по неравенству треугольника может быть сокращён по хорде, соединяющий точки пересечения границы &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности с путем. Раз часть пути может быть уменьшена, значит и весь путь может быть уменьшен, а значит исходное предположение некорректно.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
Говорят, что вершина &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; ''видна'' (англ. mutually visible) из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;, если отрезок &amp;lt;tex&amp;gt; uv &amp;lt;/tex&amp;gt; не пересекает ни одного препятствия.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
''Граф видимости'' (англ. visibility graph) {{---}} граф, вершины которого {{---}} вершины полигонов. Между вершинами &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; существует ребро, если из &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; видна &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
В худшем случае в таком графе может быть &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; ребер. Однако по некоторым ребрам кратчайший путь точно не пройдет, и такие ребра из графа можно удалить.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
[[Файл:edgeToDelete.png|150px|thumb|right|Удаляем &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Если существуют вершины &amp;lt;tex&amp;gt; A, B, C &amp;lt;/tex&amp;gt; одного препятствия и вершина &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; такая, что поворот &amp;lt;tex&amp;gt; DBA &amp;lt;/tex&amp;gt; не совпадает с поворотом &amp;lt;tex&amp;gt; DBC &amp;lt;/tex&amp;gt;, то ребро &amp;lt;tex&amp;gt; DB &amp;lt;/tex&amp;gt; не принадлежит кратчайшему пути и его можно удалить из графа. (См. поясняющую картинку справа)&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:edgeNotToDelete.png|200px|thumb|right|Не удаляем &amp;lt;tex&amp;gt; BS &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Путь проходящий через ребро &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt; будет длиннее, чем через соседей точки &amp;lt;tex&amp;gt; B &amp;lt;/tex&amp;gt;, так как по неравенству треугольника &amp;lt;tex&amp;gt; AB + BD &amp;lt; AD &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
По доказанным леммам любое ребро кратчайшего пути содержится в графе. Таким образом, для нахождения кратчайшего пути осталось найти кратчайший путь в этом графе от начальной до конечной вершины.&lt;br /&gt;
&lt;br /&gt;
=== Построение visibility графа ===&lt;br /&gt;
==== Наивный алгоритм. &amp;lt;tex&amp;gt; O(n ^ 3) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
Для каждой пары вершин проверяем, можно ли добавить ребро между ними, то есть нет ли пересечений с полигонами. &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; пар вершин и &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; ребер, то есть &amp;lt;tex&amp;gt; O(n^3) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Lee’s Algorithm. &amp;lt;tex&amp;gt; O(n ^ 2 \log n) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
{|&lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zam.png|300px|thumb|left|Заметание плоскости вращающимся лучом]]&lt;br /&gt;
Однако можно это сделать за &amp;lt;tex&amp;gt; O(n ^ 2 \log  n) &amp;lt;/tex&amp;gt;. Идея алгоритма проста : для каждой вершины найдем видимые из нее вершины. Если научиться делать это за &amp;lt;tex&amp;gt; O(n \log  n) &amp;lt;/tex&amp;gt;, задача решена, так как всего точек &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для каждой вершины будем рассматривать только правую половину плоскости, так как ребра, которые должны идти в левую половину, будут исходить из вершин, для которых текущая вершина будет справа.&lt;br /&gt;
&lt;br /&gt;
Переформулируем задачу. Дано : точка &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и множество отрезков {{---}} ребер препятствий. &lt;br /&gt;
Найти : множество концов отрезков, видимых из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для решения этой задачи будем использовать заметающий луч с началом в точке &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Его статусом будут отрезки, которые его пересекают, упорядоченные по возрастанию расстояния от точки &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; до точки пересечения. Точками событий будут концы отрезков. &lt;br /&gt;
&lt;br /&gt;
Пустим луч из рассматриваемой вершины &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вертикально вверх и добавим в статус все отрезки, которые он пересекает, по увеличению расстояния до них. Теперь будем рассматривать точки &amp;lt;tex&amp;gt; w \in V &amp;lt;/tex&amp;gt; в порядке сортировки по углу между &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и вертикальной полуосью &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt;. При таком обходе проверка видимости вершины будет выполняться за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;, так как достаточно проверить пересечение с отрезком, первым в статусе. Действительно, если вершина не видна, то отрезок &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; пересекает несколько отрезков, лежащих перед &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt;, а значит и ближайший, то есть первый в статусе. В противном случае все пересекаемые лучом отрезки лежат за вершиной &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; и пересечения отрезка &amp;lt;tex&amp;gt; uw &amp;lt;/tex&amp;gt; с ближайшим отрезком в статусе не будет. Вне зависимости от видимости вершины, необходимо изменить статус заметающего луча. Для этого необходимо удалить из статуса все отрезки, которые заканчиваются вершине &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; (лежат слева от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;) и добавить все отрезки, которые в ней начинаются (лежат справа от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Псевдокод =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
graph buildVisibilityGraph(Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
   Set&amp;lt;Vertex&amp;gt; vertices = getVertices(segments)       //получаем все вершины препятствий&lt;br /&gt;
   graph visibilityGraph(vertices)                    //изначально в графе только вершины&lt;br /&gt;
   for Vertex v in vertices                           //для каждой вершины&lt;br /&gt;
      for Vertex w in getVisibleVertices(v, segments) //добавляем в граф все видимые из нее вершины&lt;br /&gt;
         visibilityGraph.addEdge(v, w)&lt;br /&gt;
   return visibilityGraph&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Здесь функция getVisibleVertices(&amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;) возвращет все видимые из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вершины и выглядит так:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
vector&amp;lt;Vertex&amp;gt; getVisibleVertices(vertex v, set&amp;lt;segment&amp;gt; segments)&lt;br /&gt;
// Инициализируем статус&lt;br /&gt;
   for segment s in segments&lt;br /&gt;
      if intersection s and ray from v to up exists&lt;br /&gt;
         status.add(s)&lt;br /&gt;
// Инициализируем множество вершин, которые нужно рассматривать&lt;br /&gt;
   for point w in segments&lt;br /&gt;
      if w.x &amp;gt;= v.x&lt;br /&gt;
         currentVertices.add(w)&lt;br /&gt;
   sort(currentVertices) by angle&lt;br /&gt;
// Для каждой вершины проверяем, видима ли она и обновляем статус&lt;br /&gt;
   for w in currentVertices&lt;br /&gt;
      if intersection vw and status.first not exists&lt;br /&gt;
         answer.add(w)&lt;br /&gt;
      delete from status all edges ending in w&lt;br /&gt;
      add in status all edges beginning in w&lt;br /&gt;
   return answer&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
В качестве статуса нужно использовать структуру данных, позволяющую добавлять и удалять из нее отрезки за &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; и извлекать минимум за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt;. В этом случае достигается асимптотика &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;, так как для каждой из &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; точек выполняется сортировка(&amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;), обновление статуса (суммарно &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, так как каждый отрезок добавляется и удаляется из статуса только один раз) и запросы ближайшего отрезка (&amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; на точку, то есть &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;). &lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zamrefr1.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr2.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr3.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Overmars and Welzl’s Algorithm &amp;lt;tex&amp;gt; O(n ^ 2) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
[http://igitur-archive.library.uu.nl/math/2006-1214-201604/overmars_88_new_methods.pdf visibility graph при помощи rotation tree]&lt;br /&gt;
&lt;br /&gt;
C помощью [http://bit.ly/1eEqTzk rotation tree] можно достичь асимптотики &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Motion planning ==&lt;br /&gt;
[[Файл:mink.png|200px|thumb|left|Раздуваем препятствия]]&lt;br /&gt;
[[Файл:mink2.png|400px|thumb|right|Ищем путь для точки]]&lt;br /&gt;
Тут мы двигаем не точку, а произвольный выпуклый полигон. Если мы его не можем вращать, просто считаем configuration space, т. е. &amp;quot;обводим&amp;quot; препятствия нашим полигоном (делаем [[Сумма Минковского (определение, вычисление)|сумму Минковского]] препятствий и полигона, сдвинутого в начало координат какой-нибудь точкой) и получаем другие препятствия, но зато теперь мы двигаем точку. А это мы уже научились делать выше.&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим случай, когда мы можем вращать полигон. Для начала построим [[Трапецоидная карта|трапецоидную карту]], как будто мы не можем вращать полигон. Теперь будем вращать полигон на малый угол, пока он не сделает полный оборот вокруг своей оси, и для каждого угла сделаем трапецоидную карту. Теперь разместим(мысленно) все карты друг над другом. Таким образом получится, что поворот на малый угол {{---}} это движение вверх/вниз между слоями. Осталось [[Пересечение многоугольников (PSLG overlaying)|попересекать]] соседние слои и добавить между ними ребра (помним что первый и последний слои одинаковы) и уже в этом графе найти путь.&lt;br /&gt;
&lt;br /&gt;
При такой реализации в некоторых случаях у нас может возникнуть ошибка в повороте, так как в одной плоскости мы все можем делать точно: положения на соседних слоях могут допускаться, а повернуть мы не сможем. Это лечится в основном двумя способами: измельчением угла поворота и изначальным сглаживанием углов полигона {{---}} повращать полигон на &amp;lt;tex&amp;gt; +\epsilon &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; -\epsilon &amp;lt;/tex&amp;gt; и объединить с исходным, получив новый полигон.&lt;br /&gt;
&lt;br /&gt;
Так как эта задача достаточно ресурсоемка, мы рассматриваем только наличие пути, а не нахождение кратчайшего.&lt;br /&gt;
&lt;br /&gt;
== Источники ==&lt;br /&gt;
* 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&lt;br /&gt;
* [http://www.academia.edu/2845047/3D_Visibility_Graph статья] про visibility graphs на academia.edu&lt;br /&gt;
* [http://habrahabr.ru/post/199256/ Хабр]&lt;br /&gt;
[[Категория: Вычислительная геометрия]]&lt;br /&gt;
&lt;br /&gt;
== Ссылки ==&lt;br /&gt;
* Моя [https://github.com/Igorjan94/cg/blob/master/include/cg/algorithms/visibilityGraph.h реализация] алгоритма за &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;. Далеко от идеального, но работает&lt;/div&gt;</summary>
		<author><name>Igorjan94</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44811</id>
		<title>Visibility graph и motion planning</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44811"/>
				<updated>2015-02-08T19:46:02Z</updated>
		
		<summary type="html">&lt;p&gt;Igorjan94: /* Visibility graph */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Нахождение пути между точками с препятствиями ==&lt;br /&gt;
{|align=&amp;quot;right&amp;quot;&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
|[[Файл:trap.png|200px|thumb|right|Путь с препятствиями через трапецоидную карту]]&lt;br /&gt;
|[[Файл:notShort.png|300px|thumb|right|Такой путь не самый короткий]]&lt;br /&gt;
|}&lt;br /&gt;
Для начала рассмотрим движение материальной точки. Случай, когда размером и формой движимого объекта пренебречь нельзя, будет рассмотрен [[Visibility graph и motion planning#Motion planning|позднее]]. &lt;br /&gt;
&lt;br /&gt;
Обычно эта задача решается с помощью [[Трапецоидная карта | трапецоидной карты]]. По ней строится граф, ребра которого соединяют центры трапедоидов, а также начальную и конечную вершины с серединами вертикальных сторон трапецоидов. В таком графе ищется путь между начальной и конечной вершинами.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм работает за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; и за линейное количество памяти и идеально подходит для нахождения какого-нибудь пути между конечными вершинами. Но иногда нужно найти кратчайший путь, и этот алгоритм не подходит, хоть и дает хорошее приближение. Однако, решения нахождения кратчайшего пути в лучшем случае работают за &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; времени и памяти (здесь и далее &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество всех вершин).&lt;br /&gt;
&lt;br /&gt;
== Visibility graph ==&lt;br /&gt;
Рассмотрим точное решение нахождения кратчайшего пути на плоскости между двумя точками с полигональными препятствиями с помощью построения графа видимости. После его построения, как и в случае с трапецоидной картой, кратчайший путь ищется любым стандартным алгоритмом поиска (например, алгоритмом [[Алгоритм Дейкстры|Дейкстры]] или [[Алгоритм A*|A*]]).&lt;br /&gt;
&lt;br /&gt;
Для простоты рассуждений начальную и конечную вершины будем считать вершинами полигонов.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|about=О кратчайшем пути&lt;br /&gt;
|statement=&lt;br /&gt;
Любой кратчайший путь между двумя вершинами с полигональными препятствиями представляет собой ломаную, вершины которой {{---}} вершины полигонов.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:short.png|150px|thumb|right|Short cut]]&lt;br /&gt;
Пусть кратчайший путь {{---}} не ломаная. В таком случае, на пути существует такая точка &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, которая не принадлежит ни одному прямому отрезку. Это означает, что существует &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестность точки &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, в которую не попадает ни одно препятствие (случай, когда точка попала на ребро рассматривается аналогично). В таком случае, подпуть, который находится внутри &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности, по неравенству треугольника может быть сокращён по хорде, соединяющий точки пересечения границы &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности с путем. Раз часть пути может быть уменьшена, значит и весь путь может быть уменьшен, а значит исходное предположение некорректно.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
Говорят, что вершина &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; ''видна'' (англ. mutually visible) из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;, если отрезок &amp;lt;tex&amp;gt; uv &amp;lt;/tex&amp;gt; не пересекает ни одного препятствия.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
''Граф видимости'' (англ. visibility graph) {{---}} граф, вершины которого {{---}} вершины полигонов. Между вершинами &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; существует ребро, если из &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; видна &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
В худшем случае в таком графе может быть &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; ребер. Однако по некоторым ребрам кратчайший путь точно не пройдет, и такие ребра из графа можно удалить.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
[[Файл:edgeToDelete.png|150px|thumb|right|Удаляем &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Если существуют вершины &amp;lt;tex&amp;gt; A, B, C &amp;lt;/tex&amp;gt; одного препятствия и вершина &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; такая, что поворот &amp;lt;tex&amp;gt; DBA &amp;lt;/tex&amp;gt; не совпадает с поворотом &amp;lt;tex&amp;gt; DBC &amp;lt;/tex&amp;gt;, то ребро &amp;lt;tex&amp;gt; DB &amp;lt;/tex&amp;gt; не принадлежит кратчайшему пути и его можно удалить из графа. (См. поясняющую картинку справа)&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:edgeNotToDelete.png|200px|thumb|right|Не удаляем &amp;lt;tex&amp;gt; BS &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Путь проходящий через ребро &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt; будет длиннее, чем через соседей точки &amp;lt;tex&amp;gt; B &amp;lt;/tex&amp;gt;, так как по неравенству треугольника &amp;lt;tex&amp;gt; AB + BD &amp;lt; AD &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
По доказанным леммам любое ребро кратчайшего пути содержится в графе. Таким образом, для нахождения кратчайшего пути осталось найти кратчайший путь в этом графе от начальной до конечной вершины.&lt;br /&gt;
&lt;br /&gt;
=== Построение visibility графа ===&lt;br /&gt;
==== Наивный алгоритм. &amp;lt;tex&amp;gt; O(n ^ 3) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
Для каждой пары вершин проверяем, можно ли добавить ребро между ними, то есть нет ли пересечений с полигонами. &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; пар вершин и &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; ребер, то есть &amp;lt;tex&amp;gt; O(n^3) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Lee’s Algorithm. &amp;lt;tex&amp;gt; O(n ^ 2 \log n) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
{|&lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zam.png|300px|thumb|left|Заметание плоскости вращающимся лучом]]&lt;br /&gt;
Однако можно это сделать за &amp;lt;tex&amp;gt; O(n ^ 2 \log  n) &amp;lt;/tex&amp;gt;. Идея алгоритма проста : для каждой вершины найдем видимые из нее вершины. Если научиться делать это за &amp;lt;tex&amp;gt; O(n \log  n) &amp;lt;/tex&amp;gt;, задача решена, так как всего точек &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Переформулируем задачу : дана точка &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и множество отрезков {{---}} ребер препятствий. &lt;br /&gt;
Найти : множество концов отрезков, видимых из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для решения этой задачи будем использовать заметающий луч с началом в точке &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Его статусом будут отрезки, которые его пересекают, упорядоченные по возрастанию расстояния от точки &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; до точки пересечения. Точками событий будут концы отрезков. &lt;br /&gt;
&lt;br /&gt;
Изначально, пустим луч из рассматриваемой вершины вертикально вверх и добавим в статус все отрезки, которые он пересекает, по увеличению расстояния до них. Теперь будем рассматривать точки &amp;lt;tex&amp;gt; w \in V &amp;lt;/tex&amp;gt; в порядке сортировки по углу между &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и вертикальной полуосью &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt;. При таком обходе проверка видимости вершины будет выполняться за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;, так как достаточно проверить пересечение с отрезком, первым в статусе. Действительно, если вершина не видна, то отрезок &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; пересекает несколько отрезков, лежащих перед &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt;, а значит и ближайший, то есть первый в статусе. В противном случае все пересекаемые лучом отрезки лежат за вершиной &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; и пересечения отрезка &amp;lt;tex&amp;gt; uw &amp;lt;/tex&amp;gt; с ближайшим отрезком в статусе не будет. Вне зависимости от видимости вершины, необходимо изменить статус заметающего луча. Для этого необходимо удалить из статуса все отрезки, которые заканчиваются вершине &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; (лежат слева от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;) и добавить все отрезки, которые в ней начинаются (лежат справа от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Псевдокод =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
graph buildVisibilityGraph(Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
   Set&amp;lt;Vertex&amp;gt; vertices = getVertices(segments)       //получаем все вершины препятствий&lt;br /&gt;
   graph visibilityGraph(vertices)                    //изначально в графе только вершины&lt;br /&gt;
   for Vertex v in vertices                           //для каждой вершины&lt;br /&gt;
      for Vertex w in getVisibleVertices(v, segments) //добавляем в граф все видимые из нее вершины&lt;br /&gt;
         visibilityGraph.addEdge(v, w)&lt;br /&gt;
   return visibilityGraph&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Здесь функция getVisibleVertices(&amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;) возвращет все видимые из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вершины и выглядит так:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
vector&amp;lt;Vertex&amp;gt; getVisibleVertices(vertex v, set&amp;lt;segment&amp;gt; segments)&lt;br /&gt;
// Инициализируем статус&lt;br /&gt;
   for segment s in segments&lt;br /&gt;
      if intersection s and ray from v to up exists&lt;br /&gt;
         status.add(s)&lt;br /&gt;
// Инициализируем множество вершин, которые нужно рассматривать&lt;br /&gt;
   for point w in segments&lt;br /&gt;
      if w.x &amp;gt;= v.x&lt;br /&gt;
         currentVertices.add(w)&lt;br /&gt;
   sort(currentVertices) by angle&lt;br /&gt;
// Для каждой вершины проверяем, видима ли она и обновляем статус&lt;br /&gt;
   for w in currentVertices&lt;br /&gt;
      if intersection vw and status.first not exists&lt;br /&gt;
         answer.add(w)&lt;br /&gt;
      delete from status all edges ending in w&lt;br /&gt;
      add in status all edges beginning in w&lt;br /&gt;
   return answer&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
В качестве статуса нужно использовать структуру данных, позволяющую добавлять и удалять из нее отрезки за &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; и извлекать минимум за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt;. В этом случае достигается асимптотика &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;, так как для каждой из &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; точек выполняется сортировка(&amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;), обновление статуса (суммарно &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, так как каждый отрезок добавляется и удаляется из статуса только один раз) и запросы ближайшего отрезка (&amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; на точку, то есть &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;). &lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zamrefr1.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr2.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr3.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Overmars and Welzl’s Algorithm &amp;lt;tex&amp;gt; O(n ^ 2) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
[http://igitur-archive.library.uu.nl/math/2006-1214-201604/overmars_88_new_methods.pdf visibility graph при помощи rotation tree]&lt;br /&gt;
&lt;br /&gt;
C помощью [http://bit.ly/1eEqTzk rotation tree] можно достичь асимптотики &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Motion planning ==&lt;br /&gt;
[[Файл:mink.png|200px|thumb|left|Раздуваем препятствия]]&lt;br /&gt;
[[Файл:mink2.png|400px|thumb|right|Ищем путь для точки]]&lt;br /&gt;
Тут мы двигаем не точку, а произвольный выпуклый полигон. Если мы его не можем вращать, просто считаем configuration space, т. е. &amp;quot;обводим&amp;quot; препятствия нашим полигоном (делаем [[Сумма Минковского (определение, вычисление)|сумму Минковского]] препятствий и полигона, сдвинутого в начало координат какой-нибудь точкой) и получаем другие препятствия, но зато теперь мы двигаем точку. А это мы уже научились делать выше.&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим случай, когда мы можем вращать полигон. Для начала построим [[Трапецоидная карта|трапецоидную карту]], как будто мы не можем вращать полигон. Теперь будем вращать полигон на малый угол, пока он не сделает полный оборот вокруг своей оси, и для каждого угла сделаем трапецоидную карту. Теперь разместим(мысленно) все карты друг над другом. Таким образом получится, что поворот на малый угол {{---}} это движение вверх/вниз между слоями. Осталось [[Пересечение многоугольников (PSLG overlaying)|попересекать]] соседние слои и добавить между ними ребра (помним что первый и последний слои одинаковы) и уже в этом графе найти путь.&lt;br /&gt;
&lt;br /&gt;
При такой реализации в некоторых случаях у нас может возникнуть ошибка в повороте, так как в одной плоскости мы все можем делать точно: положения на соседних слоях могут допускаться, а повернуть мы не сможем. Это лечится в основном двумя способами: измельчением угла поворота и изначальным сглаживанием углов полигона {{---}} повращать полигон на &amp;lt;tex&amp;gt; +\epsilon &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; -\epsilon &amp;lt;/tex&amp;gt; и объединить с исходным, получив новый полигон.&lt;br /&gt;
&lt;br /&gt;
Так как эта задача достаточно ресурсоемка, мы рассматриваем только наличие пути, а не нахождение кратчайшего.&lt;br /&gt;
&lt;br /&gt;
== Источники ==&lt;br /&gt;
* 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&lt;br /&gt;
* [http://www.academia.edu/2845047/3D_Visibility_Graph статья] про visibility graphs на academia.edu&lt;br /&gt;
* [http://habrahabr.ru/post/199256/ Хабр]&lt;br /&gt;
[[Категория: Вычислительная геометрия]]&lt;br /&gt;
&lt;br /&gt;
== Ссылки ==&lt;br /&gt;
* Моя [https://github.com/Igorjan94/cg/blob/master/include/cg/algorithms/visibilityGraph.h реализация] алгоритма за &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;. Далеко от идеального, но работает&lt;/div&gt;</summary>
		<author><name>Igorjan94</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44810</id>
		<title>Visibility graph и motion planning</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44810"/>
				<updated>2015-02-08T19:14:55Z</updated>
		
		<summary type="html">&lt;p&gt;Igorjan94: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Нахождение пути между точками с препятствиями ==&lt;br /&gt;
{|align=&amp;quot;right&amp;quot;&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
|[[Файл:trap.png|200px|thumb|right|Путь с препятствиями через трапецоидную карту]]&lt;br /&gt;
|[[Файл:notShort.png|300px|thumb|right|Такой путь не самый короткий]]&lt;br /&gt;
|}&lt;br /&gt;
Для начала рассмотрим движение материальной точки. Случай, когда размером и формой движимого объекта пренебречь нельзя, будет рассмотрен [[Visibility graph и motion planning#Motion planning|позднее]]. &lt;br /&gt;
&lt;br /&gt;
Обычно эта задача решается с помощью [[Трапецоидная карта | трапецоидной карты]]. По ней строится граф, ребра которого соединяют центры трапедоидов, а также начальную и конечную вершины с серединами вертикальных сторон трапецоидов. В таком графе ищется путь между начальной и конечной вершинами.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм работает за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; и за линейное количество памяти и идеально подходит для нахождения какого-нибудь пути между конечными вершинами. Но иногда нужно найти кратчайший путь, и этот алгоритм не подходит, хоть и дает хорошее приближение. Однако, решения нахождения кратчайшего пути в лучшем случае работают за &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; времени и памяти (здесь и далее &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество всех вершин).&lt;br /&gt;
&lt;br /&gt;
== Visibility graph ==&lt;br /&gt;
Рассмотрим точное решение нахождения кратчайшего пути на плоскости между двумя точками с полигональными препятствиями с помощью построения графа видимости. После его построения, как и в случае с трапецоидной картой, кратчайший путь ищется любым стандартным алгоритмом поиска (например, алгоритмом [[Алгоритм Дейкстры|Дейкстры]] или [[Алгоритм A*|A*]]).&lt;br /&gt;
&lt;br /&gt;
Для простоты рассуждений начальную и конечную вершины будем считать вершинами полигонов.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|about=О кратчайшем пути&lt;br /&gt;
|statement=&lt;br /&gt;
Любой кратчайший путь между двумя вершинами с полигональными препятствиями представляет собой ломаную, вершины которой {{---}} вершины полигонов.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:short.png|150px|thumb|right|Short cut]]&lt;br /&gt;
Пусть кратчайший путь {{---}} не ломаная. В таком случае, на пути существует такая точка &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, которая не принадлежит ни одному прямому отрезку. Это означает, что существует &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестность точки &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, в которую не попадает ни одно препятствие (случай, когда точка попала на ребро рассматривается аналогично). В таком случае, подпуть, который находится внутри &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности, по неравенству треугольника может быть сокращён по хорде, соединяющий точки пересечения границы &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности с путем. Раз часть пути может быть уменьшена, значит и весь путь может быть уменьшен, а значит исходное предположение некорректно.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
Говорят, что вершина &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; &amp;lt;i&amp;gt; видна &amp;lt;/i&amp;gt;(англ. mutually visible) из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;, если отрезок &amp;lt;tex&amp;gt; uv &amp;lt;/tex&amp;gt; не пересекает ни одного препятствия.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
'''visibility graph''' {{---}} граф, вершины которого {{---}} вершины полигонов. Между вершинами &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; существует ребро, если из &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; видна &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
В худшем случае в таком графе может быть &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; ребер. Однако по некоторым ребрам кратчайший путь точно не пройдет, и такие ребра из графа можно удалить.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
[[Файл:edgeToDelete.png|150px|thumb|right|Удаляем &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Если существуют вершины &amp;lt;tex&amp;gt; A, B, C &amp;lt;/tex&amp;gt; одного препятствия и вершина &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; такая, что поворот &amp;lt;tex&amp;gt; DBA &amp;lt;/tex&amp;gt; не совпадает с поворотом &amp;lt;tex&amp;gt; DBC &amp;lt;/tex&amp;gt;, то ребро &amp;lt;tex&amp;gt; DB &amp;lt;/tex&amp;gt; не принадлежит кратчайшему пути и его можно удалить из графа. (См. поясняющую картинку справа)&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:edgeNotToDelete.png|200px|thumb|right|Не удаляем &amp;lt;tex&amp;gt; BS &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Путь проходящий через ребро &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt; будет длиннее, чем через соседей точки &amp;lt;tex&amp;gt; B &amp;lt;/tex&amp;gt;, так как по неравенству треугольника &amp;lt;tex&amp;gt; AB + BD &amp;lt; AD &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
По доказанным леммам любое ребро кратчайшего пути содержится в графе, таким образом для нахождения кратчайшего пути осталось найти кратчайший путь в этом графе от &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Построение visibility графа ===&lt;br /&gt;
==== Наивный алгоритм. &amp;lt;tex&amp;gt; O(n ^ 3) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
Если делать наивно, то есть для каждой пары вершин проверять можно ли добавить ли такое ребро(нет ли пересечений с полигонами), будет &amp;lt;tex&amp;gt; O(n^3) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Lee’s Algorithm. &amp;lt;tex&amp;gt; O(n ^ 2 \log n) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
{|&lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zam.png|300px|thumb|left|Заметание плоскости вращающимся лучом]]&lt;br /&gt;
Однако можно это сделать за &amp;lt;tex&amp;gt; O(n ^ 2 \log  n) &amp;lt;/tex&amp;gt;. Идея алгоритма проста : для каждой вершины найдем видимые из нее вершины независимо. Если научиться делать это за &amp;lt;tex&amp;gt; O(n \log  n) &amp;lt;/tex&amp;gt;, задача решена, так как всего точек &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Будем рассматривать точки слева направо, таким образом потребуется рассматривать только правую половину плоскости, так как ребра, которые должны идти в левую будут уже добавлены ранее.&lt;br /&gt;
&lt;br /&gt;
Переформулируем задачу : дана точка &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и множество отрезков {{---}} ребер препятствий. &lt;br /&gt;
Найти : множество концов отрезков, видимых из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для решения этой задачи будем использовать заметающий луч с началом в точке &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Его статусом будут отрезки, которые его пересекают, упорядоченные по возрастанию расстояния от точки &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; до точки пересечения. Точками событий будут концы отрезков. &lt;br /&gt;
&lt;br /&gt;
Изначально, пустим луч из рассматриваемой вершины вертикально вверх и добавим в статус все отрезки, которые он пересекает, по увеличению расстояния до них. Теперь будем рассматривать точки &amp;lt;tex&amp;gt; w \in V &amp;lt;/tex&amp;gt; в порядке сортировки по углу между &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и вертикальной полуосью &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt;. При таком обходе проверка видимости вершины будет выполняться за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;, так как достаточно проверить пересечение с отрезком, первым в статусе. Действительно, если вершина не видна, то отрезок &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; пересекает несколько отрезков, лежащих перед &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt;, а значит и ближайший, то есть первый в статусе. В противном случае все пересекаемые лучом отрезки лежат за вершиной &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; и пересечения отрезка &amp;lt;tex&amp;gt; uw &amp;lt;/tex&amp;gt; с ближайшим отрезком в статусе не будет. Вне зависимости от видимости вершины, необходимо изменить статус заметающего луча. Для этого необходимо удалить из статуса все отрезки, которые заканчиваются вершине &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; (лежат слева от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;) и добавить все отрезки, которые в ней начинаются (лежат справа от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Псевдокод =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
graph buildVisibilityGraph(Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
   Set&amp;lt;Vertex&amp;gt; vertices = getVertices(segments)       //получаем все вершины препятствий&lt;br /&gt;
   graph visibilityGraph(vertices)                    //изначально в графе только вершины&lt;br /&gt;
   for Vertex v in vertices                           //для каждой вершины&lt;br /&gt;
      for Vertex w in getVisibleVertices(v, segments) //добавляем в граф все видимые из нее вершины&lt;br /&gt;
         visibilityGraph.addEdge(v, w)&lt;br /&gt;
   return visibilityGraph&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Здесь функция getVisibleVertices(&amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;) возвращет все видимые из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вершины и выглядит так:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
vector&amp;lt;Vertex&amp;gt; getVisibleVertices(vertex v, set&amp;lt;segment&amp;gt; segments)&lt;br /&gt;
// Инициализируем статус&lt;br /&gt;
   for segment s in segments&lt;br /&gt;
      if intersection s and ray from v to up exists&lt;br /&gt;
         status.add(s)&lt;br /&gt;
// Инициализируем множество вершин, которые нужно рассматривать&lt;br /&gt;
   for point w in segments&lt;br /&gt;
      if w.x &amp;gt;= v.x&lt;br /&gt;
         currentVertices.add(w)&lt;br /&gt;
   sort(currentVertices) by angle&lt;br /&gt;
// Для каждой вершины проверяем, видима ли она и обновляем статус&lt;br /&gt;
   for w in currentVertices&lt;br /&gt;
      if intersection vw and status.first not exists&lt;br /&gt;
         answer.add(w)&lt;br /&gt;
      delete from status all edges ending in w&lt;br /&gt;
      add in status all edges beginning in w&lt;br /&gt;
   return answer&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
В качестве статуса нужно использовать структуру данных, позволяющую добавлять и удалять из нее отрезки за &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; и извлекать минимум за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt;. В этом случае достигается асимптотика &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;, так как для каждой из &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; точек выполняется сортировка(&amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;), обновление статуса (суммарно &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, так как каждый отрезок добавляется и удаляется из статуса только один раз) и запросы ближайшего отрезка (&amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; на точку, то есть &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;). &lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zamrefr1.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr2.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr3.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Overmars and Welzl’s Algorithm &amp;lt;tex&amp;gt; O(n ^ 2) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
[http://igitur-archive.library.uu.nl/math/2006-1214-201604/overmars_88_new_methods.pdf visibility graph при помощи rotation tree]&lt;br /&gt;
&lt;br /&gt;
C помощью [http://bit.ly/1eEqTzk rotation tree] можно достичь асимптотики &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Motion planning ==&lt;br /&gt;
[[Файл:mink.png|200px|thumb|left|Раздуваем препятствия]]&lt;br /&gt;
[[Файл:mink2.png|400px|thumb|right|Ищем путь для точки]]&lt;br /&gt;
Тут мы двигаем не точку, а произвольный выпуклый полигон. Если мы его не можем вращать, просто считаем configuration space, т. е. &amp;quot;обводим&amp;quot; препятствия нашим полигоном (делаем [[Сумма Минковского (определение, вычисление)|сумму Минковского]] препятствий и полигона, сдвинутого в начало координат какой-нибудь точкой) и получаем другие препятствия, но зато теперь мы двигаем точку. А это мы уже научились делать выше.&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим случай, когда мы можем вращать полигон. Для начала построим [[Трапецоидная карта|трапецоидную карту]], как будто мы не можем вращать полигон. Теперь будем вращать полигон на малый угол, пока он не сделает полный оборот вокруг своей оси, и для каждого угла сделаем трапецоидную карту. Теперь разместим(мысленно) все карты друг над другом. Таким образом получится, что поворот на малый угол {{---}} это движение вверх/вниз между слоями. Осталось [[Пересечение многоугольников (PSLG overlaying)|попересекать]] соседние слои и добавить между ними ребра (помним что первый и последний слои одинаковы) и уже в этом графе найти путь.&lt;br /&gt;
&lt;br /&gt;
При такой реализации в некоторых случаях у нас может возникнуть ошибка в повороте, так как в одной плоскости мы все можем делать точно: положения на соседних слоях могут допускаться, а повернуть мы не сможем. Это лечится в основном двумя способами: измельчением угла поворота и изначальным сглаживанием углов полигона {{---}} повращать полигон на &amp;lt;tex&amp;gt; +\epsilon &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; -\epsilon &amp;lt;/tex&amp;gt; и объединить с исходным, получив новый полигон.&lt;br /&gt;
&lt;br /&gt;
Так как эта задача достаточно ресурсоемка, мы рассматриваем только наличие пути, а не нахождение кратчайшего.&lt;br /&gt;
&lt;br /&gt;
== Источники ==&lt;br /&gt;
* 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&lt;br /&gt;
* [http://www.academia.edu/2845047/3D_Visibility_Graph статья] про visibility graphs на academia.edu&lt;br /&gt;
* [http://habrahabr.ru/post/199256/ Хабр]&lt;br /&gt;
[[Категория: Вычислительная геометрия]]&lt;br /&gt;
&lt;br /&gt;
== Ссылки ==&lt;br /&gt;
* Моя [https://github.com/Igorjan94/cg/blob/master/include/cg/algorithms/visibilityGraph.h реализация] алгоритма за &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;. Далеко от идеального, но работает&lt;/div&gt;</summary>
		<author><name>Igorjan94</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44809</id>
		<title>Visibility graph и motion planning</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44809"/>
				<updated>2015-02-08T18:36:29Z</updated>
		
		<summary type="html">&lt;p&gt;Igorjan94: /* Visibility graph */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Нахождение пути между точками с препятствиями ==&lt;br /&gt;
{|align=&amp;quot;right&amp;quot;&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
|[[Файл:trap.png|200px|thumb|right|Путь с препятствиями через трапецоидную карту]]&lt;br /&gt;
|[[Файл:notShort.png|300px|thumb|right|Такой путь не самый короткий]]&lt;br /&gt;
|}&lt;br /&gt;
Рассмотрим задачу нахождения пути от точки &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt; с препятствиями. Для начала рассмотрим движение материальной точки, случай, когда размером и формой движимого объекта пренебречь нельзя, будет [[Visibility graph и motion planning#Motion planning|позднее]]. &lt;br /&gt;
&lt;br /&gt;
Обычно эта задача решается с помощью [[Трапецоидная карта | трапецоидной карты]], по которой строится граф, ребра которого соединяют центры трапедоидов и вершины &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt; с серединами вертикальных сторон трапецоидов. В этом графе любым алгоритмом поиска кратчайших путей (например, алгоритмом [[Алгоритм Дейкстры|Дейкстры]] или [[Алгоритм A*|A*]]) находится путь от &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм работает за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; и за линейное количество памяти и идеально подходит для нахождения какого-нибудь пути между конечными вершинами. Но иногда нужно найти кратчайший путь, и этот алгоритм не подходит, хоть и дает хорошее приближение. Однако решения нахождения кратчайшего пути в лучшем случае работают за &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; времени и памяти (здесь и далее &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество всех вершин).&lt;br /&gt;
&lt;br /&gt;
== Visibility graph ==&lt;br /&gt;
Рассмотрим точное решение нахождения кратчайшего пути на плоскости от точки &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt; с полигональными препятствиями с помощью построения графа видимости. После его построения, как и в случае с трапецоидной картой, путь ищется стандартными алгоритмами.&lt;br /&gt;
&lt;br /&gt;
Для простоты рассуждений вершины &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt; будем считать вершинами полигонов.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|about=О кратчайшем пути&lt;br /&gt;
|statement=&lt;br /&gt;
Любой кратчайший путь между двумя вершинами с полигональными препятствиями представляет собой ломаную, вершины которой {{---}} вершины полигонов.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:short.png|150px|thumb|right|Short cut]]&lt;br /&gt;
Пусть кратчайший путь {{---}} не ломаная. В таком случае, на пути существует такая точка &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, которая не принадлежит ни одному прямому отрезку. Это означает, что существует &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестность точки &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, в которую не попадает ни одно препятствие (случай, когда точка попала на ребро рассматривается аналогично). В таком случае, подпуть, который находится внутри &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности, по неравенству треугольника может быть сокращён по хорде, соединяющий точки пересечения границы &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности с путем. Раз часть пути может быть уменьшена, значит и весь путь может быть уменьшен, а значит исходное предположение некорректно.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
Говорят, что вершина &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; &amp;lt;i&amp;gt; видна &amp;lt;/i&amp;gt;(англ. mutually visible) из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;, если отрезок &amp;lt;tex&amp;gt; uv &amp;lt;/tex&amp;gt; не пересекает ни одного препятствия.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
'''visibility graph''' {{---}} граф, вершины которого {{---}} вершины полигонов. Между вершинами &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; существует ребро, если из &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; видна &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
В худшем случае в таком графе может быть &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; ребер. Однако по некоторым ребрам кратчайший путь точно не пройдет, и такие ребра из графа можно удалить.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
[[Файл:edgeToDelete.png|150px|thumb|right|Удаляем &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Если существуют вершины &amp;lt;tex&amp;gt; A, B, C &amp;lt;/tex&amp;gt; одного препятствия и вершина &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; такая, что поворот &amp;lt;tex&amp;gt; DBA &amp;lt;/tex&amp;gt; не совпадает с поворотом &amp;lt;tex&amp;gt; DBC &amp;lt;/tex&amp;gt;, то ребро &amp;lt;tex&amp;gt; DB &amp;lt;/tex&amp;gt; не принадлежит кратчайшему пути и его можно удалить из графа. (См. поясняющую картинку справа)&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:edgeNotToDelete.png|200px|thumb|right|Не удаляем &amp;lt;tex&amp;gt; BS &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Путь проходящий через ребро &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt; будет длиннее, чем через соседей точки &amp;lt;tex&amp;gt; B &amp;lt;/tex&amp;gt;, так как по неравенству треугольника &amp;lt;tex&amp;gt; AB + BD &amp;lt; AD &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
По доказанным леммам любое ребро кратчайшего пути содержится в графе, таким образом для нахождения кратчайшего пути осталось найти кратчайший путь в этом графе от &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Построение visibility графа ===&lt;br /&gt;
==== Наивный алгоритм. &amp;lt;tex&amp;gt; O(n ^ 3) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
Если делать наивно, то есть для каждой пары вершин проверять можно ли добавить ли такое ребро(нет ли пересечений с полигонами), будет &amp;lt;tex&amp;gt; O(n^3) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Lee’s Algorithm. &amp;lt;tex&amp;gt; O(n ^ 2 \log n) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
{|&lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zam.png|300px|thumb|left|Заметание плоскости вращающимся лучом]]&lt;br /&gt;
Однако можно это сделать за &amp;lt;tex&amp;gt; O(n ^ 2 \log  n) &amp;lt;/tex&amp;gt;. Идея алгоритма проста : для каждой вершины найдем видимые из нее вершины независимо. Если научиться делать это за &amp;lt;tex&amp;gt; O(n \log  n) &amp;lt;/tex&amp;gt;, задача решена, так как всего точек &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Будем рассматривать точки слева направо, таким образом потребуется рассматривать только правую половину плоскости, так как ребра, которые должны идти в левую будут уже добавлены ранее.&lt;br /&gt;
&lt;br /&gt;
Переформулируем задачу : дана точка &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и множество отрезков {{---}} ребер препятствий. &lt;br /&gt;
Найти : множество концов отрезков, видимых из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для решения этой задачи будем использовать заметающий луч с началом в точке &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Его статусом будут отрезки, которые его пересекают, упорядоченные по возрастанию расстояния от точки &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; до точки пересечения. Точками событий будут концы отрезков. &lt;br /&gt;
&lt;br /&gt;
Изначально, пустим луч из рассматриваемой вершины вертикально вверх и добавим в статус все отрезки, которые он пересекает, по увеличению расстояния до них. Теперь будем рассматривать точки &amp;lt;tex&amp;gt; w \in V &amp;lt;/tex&amp;gt; в порядке сортировки по углу между &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и вертикальной полуосью &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt;. При таком обходе проверка видимости вершины будет выполняться за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;, так как достаточно проверить пересечение с отрезком, первым в статусе. Действительно, если вершина не видна, то отрезок &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; пересекает несколько отрезков, лежащих перед &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt;, а значит и ближайший, то есть первый в статусе. В противном случае все пересекаемые лучом отрезки лежат за вершиной &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; и пересечения отрезка &amp;lt;tex&amp;gt; uw &amp;lt;/tex&amp;gt; с ближайшим отрезком в статусе не будет. Вне зависимости от видимости вершины, необходимо изменить статус заметающего луча. Для этого необходимо удалить из статуса все отрезки, которые заканчиваются вершине &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; (лежат слева от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;) и добавить все отрезки, которые в ней начинаются (лежат справа от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Псевдокод =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
graph buildVisibilityGraph(Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
   Set&amp;lt;Vertex&amp;gt; vertices = getVertices(segments)       //получаем все вершины препятствий&lt;br /&gt;
   graph visibilityGraph(vertices)                    //изначально в графе только вершины&lt;br /&gt;
   for Vertex v in vertices                           //для каждой вершины&lt;br /&gt;
      for Vertex w in getVisibleVertices(v, segments) //добавляем в граф все видимые из нее вершины&lt;br /&gt;
         visibilityGraph.addEdge(v, w)&lt;br /&gt;
   return visibilityGraph&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Здесь функция getVisibleVertices(&amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;) возвращет все видимые из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вершины и выглядит так:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
vector&amp;lt;Vertex&amp;gt; getVisibleVertices(vertex v, set&amp;lt;segment&amp;gt; segments)&lt;br /&gt;
// Инициализируем статус&lt;br /&gt;
   for segment s in segments&lt;br /&gt;
      if intersection s and ray from v to up exists&lt;br /&gt;
         status.add(s)&lt;br /&gt;
// Инициализируем множество вершин, которые нужно рассматривать&lt;br /&gt;
   for point w in segments&lt;br /&gt;
      if w.x &amp;gt;= v.x&lt;br /&gt;
         currentVertices.add(w)&lt;br /&gt;
   sort(currentVertices) by angle&lt;br /&gt;
// Для каждой вершины проверяем, видима ли она и обновляем статус&lt;br /&gt;
   for w in currentVertices&lt;br /&gt;
      if intersection vw and status.first not exists&lt;br /&gt;
         answer.add(w)&lt;br /&gt;
      delete from status all edges ending in w&lt;br /&gt;
      add in status all edges beginning in w&lt;br /&gt;
   return answer&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
В качестве статуса нужно использовать структуру данных, позволяющую добавлять и удалять из нее отрезки за &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; и извлекать минимум за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt;. В этом случае достигается асимптотика &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;, так как для каждой из &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; точек выполняется сортировка(&amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;), обновление статуса (суммарно &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, так как каждый отрезок добавляется и удаляется из статуса только один раз) и запросы ближайшего отрезка (&amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; на точку, то есть &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;). &lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zamrefr1.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr2.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr3.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Overmars and Welzl’s Algorithm &amp;lt;tex&amp;gt; O(n ^ 2) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
[http://igitur-archive.library.uu.nl/math/2006-1214-201604/overmars_88_new_methods.pdf visibility graph при помощи rotation tree]&lt;br /&gt;
&lt;br /&gt;
C помощью [http://bit.ly/1eEqTzk rotation tree] можно достичь асимптотики &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Motion planning ==&lt;br /&gt;
[[Файл:mink.png|200px|thumb|left|Раздуваем препятствия]]&lt;br /&gt;
[[Файл:mink2.png|400px|thumb|right|Ищем путь для точки]]&lt;br /&gt;
Тут мы двигаем не точку, а произвольный выпуклый полигон. Если мы его не можем вращать, просто считаем configuration space, т. е. &amp;quot;обводим&amp;quot; препятствия нашим полигоном (делаем [[Сумма Минковского (определение, вычисление)|сумму Минковского]] препятствий и полигона, сдвинутого в начало координат какой-нибудь точкой) и получаем другие препятствия, но зато теперь мы двигаем точку. А это мы уже научились делать выше.&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим случай, когда мы можем вращать полигон. Для начала построим [[Трапецоидная карта|трапецоидную карту]], как будто мы не можем вращать полигон. Теперь будем вращать полигон на малый угол, пока он не сделает полный оборот вокруг своей оси, и для каждого угла сделаем трапецоидную карту. Теперь разместим(мысленно) все карты друг над другом. Таким образом получится, что поворот на малый угол {{---}} это движение вверх/вниз между слоями. Осталось [[Пересечение многоугольников (PSLG overlaying)|попересекать]] соседние слои и добавить между ними ребра (помним что первый и последний слои одинаковы) и уже в этом графе найти путь.&lt;br /&gt;
&lt;br /&gt;
При такой реализации в некоторых случаях у нас может возникнуть ошибка в повороте, так как в одной плоскости мы все можем делать точно: положения на соседних слоях могут допускаться, а повернуть мы не сможем. Это лечится в основном двумя способами: измельчением угла поворота и изначальным сглаживанием углов полигона {{---}} повращать полигон на &amp;lt;tex&amp;gt; +\epsilon &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; -\epsilon &amp;lt;/tex&amp;gt; и объединить с исходным, получив новый полигон.&lt;br /&gt;
&lt;br /&gt;
Так как эта задача достаточно ресурсоемка, мы рассматриваем только наличие пути, а не нахождение кратчайшего.&lt;br /&gt;
&lt;br /&gt;
== Источники ==&lt;br /&gt;
* 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&lt;br /&gt;
* [http://www.academia.edu/2845047/3D_Visibility_Graph статья] про visibility graphs на academia.edu&lt;br /&gt;
* [http://habrahabr.ru/post/199256/ Хабр]&lt;br /&gt;
[[Категория: Вычислительная геометрия]]&lt;br /&gt;
&lt;br /&gt;
== Ссылки ==&lt;br /&gt;
* Моя [https://github.com/Igorjan94/cg/blob/master/include/cg/algorithms/visibilityGraph.h реализация] алгоритма за &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;. Далеко от идеального, но работает&lt;/div&gt;</summary>
		<author><name>Igorjan94</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44808</id>
		<title>Visibility graph и motion planning</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44808"/>
				<updated>2015-02-08T18:21:26Z</updated>
		
		<summary type="html">&lt;p&gt;Igorjan94: /* Lee’s Algorithm.  O(n ^ 2 \log n)  */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Visibility graph ==&lt;br /&gt;
{|align=&amp;quot;right&amp;quot;&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
|[[Файл:trap.png|200px|thumb|right|Путь с препятствиями через трапецоидную карту]]&lt;br /&gt;
|[[Файл:notShort.png|300px|thumb|right|Такой путь не самый короткий]]&lt;br /&gt;
|}&lt;br /&gt;
Рассмотрим задачу нахождения пути от точки &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt; с препятствиями. Для начала рассмотрим движение материальной точки, случай, когда размером и формой движимого объекта пренебречь нельзя, будет [[Visibility graph и motion planning#Motion planning|позднее]]. &lt;br /&gt;
&lt;br /&gt;
Обычно эта задача решается с помощью [[Трапецоидная карта | трапецоидной карты]], по которой строится граф, ребра которого соединяют центры трапедоидов и вершины &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt; с серединами вертикальных сторон трапецоидов. В этом графе любым алгоритмом поиска кратчайших путей (например, алгоритмом [[Алгоритм Дейкстры|Дейкстры]] или [[Алгоритм A*|A*]]) находится путь от &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм работает за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; и за линейное количество памяти и идеально подходит для нахождения какого-нибудь пути между конечными вершинами. Но иногда нужно найти кратчайший путь, и этот алгоритм не подходит, хоть и дает хорошее приближение.&lt;br /&gt;
&lt;br /&gt;
На сегодняшний день точные решения в лучшем случае работают за &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; времени и памяти (здесь и далее &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество всех вершин).&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим точное решение с помощью построения графа видимости. После его построения, как и в случае с трапецоидной картой, путь ищется стандартными алгоритмами.&lt;br /&gt;
&lt;br /&gt;
Для простоты рассуждений вершины &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt; будем считать вершинами полигонов.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|about=О кратчайшем пути&lt;br /&gt;
|statement=&lt;br /&gt;
Любой кратчайший путь между двумя вершинами с полигональными препятствиями представляет собой ломаную, вершины которой {{---}} вершины полигонов.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:short.png|150px|thumb|right|Short cut]]&lt;br /&gt;
Пусть кратчайший путь {{---}} не ломаная. В таком случае, на пути существует такая точка &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, которая не принадлежит ни одному прямому отрезку. Это означает, что существует &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестность точки &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, в которую не попадает ни одно препятствие (случай, когда точка попала на ребро рассматривается аналогично). В таком случае, подпуть, который находится внутри &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности, по неравенству треугольника может быть сокращён по хорде, соединяющий точки пересечения границы &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности с путем. Раз часть пути может быть уменьшена, значит и весь путь может быть уменьшен, а значит исходное предположение некорректно.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
Говорят, что вершина &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; &amp;lt;i&amp;gt; видна &amp;lt;/i&amp;gt;(англ. mutually visible) из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;, если отрезок &amp;lt;tex&amp;gt; uv &amp;lt;/tex&amp;gt; не пересекает ни одного препятствия.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
'''visibility graph''' {{---}} граф, вершины которого {{---}} вершины полигонов. Между вершинами &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; существует ребро, если из &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; видна &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
В худшем случае в таком графе может быть &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; ребер. Однако по некоторым ребрам кратчайший путь точно не пройдет, и такие ребра из графа можно удалить.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
[[Файл:edgeToDelete.png|150px|thumb|right|Удаляем &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Если существуют вершины &amp;lt;tex&amp;gt; A, B, C &amp;lt;/tex&amp;gt; одного препятствия и вершина &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; такая, что поворот &amp;lt;tex&amp;gt; DBA &amp;lt;/tex&amp;gt; не совпадает с поворотом &amp;lt;tex&amp;gt; DBC &amp;lt;/tex&amp;gt;, то ребро &amp;lt;tex&amp;gt; DB &amp;lt;/tex&amp;gt; не принадлежит кратчайшему пути и его можно удалить из графа. (См. поясняющую картинку справа)&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:edgeNotToDelete.png|200px|thumb|right|Не удаляем &amp;lt;tex&amp;gt; BS &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Путь проходящий через ребро &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt; будет длиннее, чем через соседей точки &amp;lt;tex&amp;gt; B &amp;lt;/tex&amp;gt;, так как по неравенству треугольника &amp;lt;tex&amp;gt; AB + BD &amp;lt; AD &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
По доказанным леммам любое ребро кратчайшего пути содержится в графе, таким образом для нахождения кратчайшего пути осталось найти кратчайший путь в этом графе от &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt;. Рассмотрим алгоритмы построения графа видимости.&lt;br /&gt;
&lt;br /&gt;
=== Построение visibility графа ===&lt;br /&gt;
==== Наивный алгоритм. &amp;lt;tex&amp;gt; O(n ^ 3) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
Если делать наивно, т. е. для каждой пары вершин проверять можно ли добавить ли такое ребро(нет ли пересечений с полигонами), будет &amp;lt;tex&amp;gt; O(n^3) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Lee’s Algorithm. &amp;lt;tex&amp;gt; O(n ^ 2 \log n) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
{|&lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zam.png|300px|thumb|left|Заметание плоскости вращающимся лучом]]&lt;br /&gt;
Однако можно это сделать за &amp;lt;tex&amp;gt; O(n ^ 2 \log  n) &amp;lt;/tex&amp;gt;. Идея алгоритма проста : для каждой вершины найдем видимые из нее вершины независимо. Если научиться делать это за &amp;lt;tex&amp;gt; O(n \log  n) &amp;lt;/tex&amp;gt;, задача решена, так как всего точек &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Будем рассматривать точки слева направо, таким образом потребуется рассматривать только правую половину плоскости, так как ребра, которые должны идти в левую будут уже добавлены ранее.&lt;br /&gt;
&lt;br /&gt;
Переформулируем задачу : дана точка &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и множество отрезков {{---}} ребер препятствий. &lt;br /&gt;
Найти : множество концов отрезков, видимых из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для решения этой задачи будем использовать заметающий луч с началом в точке &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Его статусом будут отрезки, которые его пересекают, упорядоченные по возрастанию расстояния от точки &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; до точки пересечения. Точками событий будут концы отрезков. &lt;br /&gt;
&lt;br /&gt;
Изначально, пустим луч из рассматриваемой вершины вертикально вверх и добавим в статус все отрезки, которые он пересекает, по увеличению расстояния до них. Теперь будем рассматривать точки &amp;lt;tex&amp;gt; w \in V &amp;lt;/tex&amp;gt; в порядке сортировки по углу между &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и вертикальной полуосью &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt;. При таком обходе проверка видимости вершины будет выполняться за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;, так как достаточно проверить пересечение с отрезком, первым в статусе. Действительно, если вершина не видна, то отрезок &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; пересекает несколько отрезков, лежащих перед &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt;, а значит и ближайший, то есть первый в статусе. В противном случае все пересекаемые лучом отрезки лежат за вершиной &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; и пересечения отрезка &amp;lt;tex&amp;gt; uw &amp;lt;/tex&amp;gt; с ближайшим отрезком в статусе не будет. Вне зависимости от видимости вершины, необходимо изменить статус заметающего луча. Для этого необходимо удалить из статуса все отрезки, которые заканчиваются вершине &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; (лежат слева от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;) и добавить все отрезки, которые в ней начинаются (лежат справа от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Псевдокод =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
graph buildVisibilityGraph(Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
   Set&amp;lt;Vertex&amp;gt; vertices = getVertices(segments)       //получаем все вершины препятствий&lt;br /&gt;
   graph visibilityGraph(vertices)                    //изначально в графе только вершины&lt;br /&gt;
   for Vertex v in vertices                           //для каждой вершины&lt;br /&gt;
      for Vertex w in getVisibleVertices(v, segments) //добавляем в граф все видимые из нее вершины&lt;br /&gt;
         visibilityGraph.addEdge(v, w)&lt;br /&gt;
   return visibilityGraph&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Здесь функция getVisibleVertices(&amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;) возвращет все видимые из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вершины и выглядит так:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
vector&amp;lt;Vertex&amp;gt; getVisibleVertices(vertex v, set&amp;lt;segment&amp;gt; segments)&lt;br /&gt;
// Инициализируем статус&lt;br /&gt;
   for segment s in segments&lt;br /&gt;
      if intersection s and ray from v to up exists&lt;br /&gt;
         status.add(s)&lt;br /&gt;
// Инициализируем множество вершин, которые нужно рассматривать&lt;br /&gt;
   for point w in segments&lt;br /&gt;
      if w.x &amp;gt;= v.x&lt;br /&gt;
         currentVertices.add(w)&lt;br /&gt;
   sort(currentVertices) by angle&lt;br /&gt;
// Для каждой вершины проверяем, видима ли она и обновляем статус&lt;br /&gt;
   for w in currentVertices&lt;br /&gt;
      if intersection vw and status.first not exists&lt;br /&gt;
         answer.add(w)&lt;br /&gt;
      delete from status all edges ending in w&lt;br /&gt;
      add in status all edges beginning in w&lt;br /&gt;
   return answer&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
В качестве статуса нужно использовать структуру данных, позволяющую добавлять и удалять из нее отрезки за &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; и извлекать минимум за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt;. В этом случае достигается асимптотика &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;, так как для каждой из &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; точек выполняется сортировка(&amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;), обновление статуса (суммарно &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, так как каждый отрезок добавляется и удаляется из статуса только один раз) и запросы ближайшего отрезка (&amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; на точку, то есть &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;). &lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zamrefr1.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr2.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr3.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Overmars and Welzl’s Algorithm &amp;lt;tex&amp;gt; O(n ^ 2) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
[http://igitur-archive.library.uu.nl/math/2006-1214-201604/overmars_88_new_methods.pdf visibility graph при помощи rotation tree]&lt;br /&gt;
&lt;br /&gt;
C помощью [http://bit.ly/1eEqTzk rotation tree] можно достичь асимптотики &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Motion planning ==&lt;br /&gt;
[[Файл:mink.png|200px|thumb|left|Раздуваем препятствия]]&lt;br /&gt;
[[Файл:mink2.png|400px|thumb|right|Ищем путь для точки]]&lt;br /&gt;
Тут мы двигаем не точку, а произвольный выпуклый полигон. Если мы его не можем вращать, просто считаем configuration space, т. е. &amp;quot;обводим&amp;quot; препятствия нашим полигоном (делаем [[Сумма Минковского (определение, вычисление)|сумму Минковского]] препятствий и полигона, сдвинутого в начало координат какой-нибудь точкой) и получаем другие препятствия, но зато теперь мы двигаем точку. А это мы уже научились делать выше.&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим случай, когда мы можем вращать полигон. Для начала построим [[Трапецоидная карта|трапецоидную карту]], как будто мы не можем вращать полигон. Теперь будем вращать полигон на малый угол, пока он не сделает полный оборот вокруг своей оси, и для каждого угла сделаем трапецоидную карту. Теперь разместим(мысленно) все карты друг над другом. Таким образом получится, что поворот на малый угол {{---}} это движение вверх/вниз между слоями. Осталось [[Пересечение многоугольников (PSLG overlaying)|попересекать]] соседние слои и добавить между ними ребра (помним что первый и последний слои одинаковы) и уже в этом графе найти путь.&lt;br /&gt;
&lt;br /&gt;
При такой реализации в некоторых случаях у нас может возникнуть ошибка в повороте, так как в одной плоскости мы все можем делать точно: положения на соседних слоях могут допускаться, а повернуть мы не сможем. Это лечится в основном двумя способами: измельчением угла поворота и изначальным сглаживанием углов полигона {{---}} повращать полигон на &amp;lt;tex&amp;gt; +\epsilon &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; -\epsilon &amp;lt;/tex&amp;gt; и объединить с исходным, получив новый полигон.&lt;br /&gt;
&lt;br /&gt;
Так как эта задача достаточно ресурсоемка, мы рассматриваем только наличие пути, а не нахождение кратчайшего.&lt;br /&gt;
&lt;br /&gt;
== Источники ==&lt;br /&gt;
* 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&lt;br /&gt;
* [http://www.academia.edu/2845047/3D_Visibility_Graph статья] про visibility graphs на academia.edu&lt;br /&gt;
* [http://habrahabr.ru/post/199256/ Хабр]&lt;br /&gt;
[[Категория: Вычислительная геометрия]]&lt;br /&gt;
&lt;br /&gt;
== Ссылки ==&lt;br /&gt;
* Моя [https://github.com/Igorjan94/cg/blob/master/include/cg/algorithms/visibilityGraph.h реализация] алгоритма за &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;. Далеко от идеального, но работает&lt;/div&gt;</summary>
		<author><name>Igorjan94</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44807</id>
		<title>Visibility graph и motion planning</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44807"/>
				<updated>2015-02-08T18:09:48Z</updated>
		
		<summary type="html">&lt;p&gt;Igorjan94: /* Ссылки */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Visibility graph ==&lt;br /&gt;
{|align=&amp;quot;right&amp;quot;&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
|[[Файл:trap.png|200px|thumb|right|Путь с препятствиями через трапецоидную карту]]&lt;br /&gt;
|[[Файл:notShort.png|300px|thumb|right|Такой путь не самый короткий]]&lt;br /&gt;
|}&lt;br /&gt;
Рассмотрим задачу нахождения пути от точки &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt; с препятствиями. Для начала рассмотрим движение материальной точки, случай, когда размером и формой движимого объекта пренебречь нельзя, будет [[Visibility graph и motion planning#Motion planning|позднее]]. &lt;br /&gt;
&lt;br /&gt;
Обычно эта задача решается с помощью [[Трапецоидная карта | трапецоидной карты]], по которой строится граф, ребра которого соединяют центры трапедоидов и вершины &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt; с серединами вертикальных сторон трапецоидов. В этом графе любым алгоритмом поиска кратчайших путей (например, алгоритмом [[Алгоритм Дейкстры|Дейкстры]] или [[Алгоритм A*|A*]]) находится путь от &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм работает за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; и за линейное количество памяти и идеально подходит для нахождения какого-нибудь пути между конечными вершинами. Но иногда нужно найти кратчайший путь, и этот алгоритм не подходит, хоть и дает хорошее приближение.&lt;br /&gt;
&lt;br /&gt;
На сегодняшний день точные решения в лучшем случае работают за &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; времени и памяти (здесь и далее &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество всех вершин).&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим точное решение с помощью построения графа видимости. После его построения, как и в случае с трапецоидной картой, путь ищется стандартными алгоритмами.&lt;br /&gt;
&lt;br /&gt;
Для простоты рассуждений вершины &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt; будем считать вершинами полигонов.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|about=О кратчайшем пути&lt;br /&gt;
|statement=&lt;br /&gt;
Любой кратчайший путь между двумя вершинами с полигональными препятствиями представляет собой ломаную, вершины которой {{---}} вершины полигонов.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:short.png|150px|thumb|right|Short cut]]&lt;br /&gt;
Пусть кратчайший путь {{---}} не ломаная. В таком случае, на пути существует такая точка &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, которая не принадлежит ни одному прямому отрезку. Это означает, что существует &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестность точки &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, в которую не попадает ни одно препятствие (случай, когда точка попала на ребро рассматривается аналогично). В таком случае, подпуть, который находится внутри &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности, по неравенству треугольника может быть сокращён по хорде, соединяющий точки пересечения границы &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности с путем. Раз часть пути может быть уменьшена, значит и весь путь может быть уменьшен, а значит исходное предположение некорректно.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
Говорят, что вершина &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; &amp;lt;i&amp;gt; видна &amp;lt;/i&amp;gt;(англ. mutually visible) из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;, если отрезок &amp;lt;tex&amp;gt; uv &amp;lt;/tex&amp;gt; не пересекает ни одного препятствия.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
'''visibility graph''' {{---}} граф, вершины которого {{---}} вершины полигонов. Между вершинами &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; существует ребро, если из &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; видна &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
В худшем случае в таком графе может быть &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; ребер. Однако по некоторым ребрам кратчайший путь точно не пройдет, и такие ребра из графа можно удалить.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
[[Файл:edgeToDelete.png|150px|thumb|right|Удаляем &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Если существуют вершины &amp;lt;tex&amp;gt; A, B, C &amp;lt;/tex&amp;gt; одного препятствия и вершина &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; такая, что поворот &amp;lt;tex&amp;gt; DBA &amp;lt;/tex&amp;gt; не совпадает с поворотом &amp;lt;tex&amp;gt; DBC &amp;lt;/tex&amp;gt;, то ребро &amp;lt;tex&amp;gt; DB &amp;lt;/tex&amp;gt; не принадлежит кратчайшему пути и его можно удалить из графа. (См. поясняющую картинку справа)&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:edgeNotToDelete.png|200px|thumb|right|Не удаляем &amp;lt;tex&amp;gt; BS &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Путь проходящий через ребро &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt; будет длиннее, чем через соседей точки &amp;lt;tex&amp;gt; B &amp;lt;/tex&amp;gt;, так как по неравенству треугольника &amp;lt;tex&amp;gt; AB + BD &amp;lt; AD &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
По доказанным леммам любое ребро кратчайшего пути содержится в графе, таким образом для нахождения кратчайшего пути осталось найти кратчайший путь в этом графе от &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt;. Рассмотрим алгоритмы построения графа видимости.&lt;br /&gt;
&lt;br /&gt;
=== Построение visibility графа ===&lt;br /&gt;
==== Наивный алгоритм. &amp;lt;tex&amp;gt; O(n ^ 3) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
Если делать наивно, т. е. для каждой пары вершин проверять можно ли добавить ли такое ребро(нет ли пересечений с полигонами), будет &amp;lt;tex&amp;gt; O(n^3) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Lee’s Algorithm. &amp;lt;tex&amp;gt; O(n ^ 2 \log n) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
{|&lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zam.png|300px|thumb|left|Заметание плоскости вращающимся лучом]]&lt;br /&gt;
Однако можно это сделать за &amp;lt;tex&amp;gt; O(n ^ 2 \log  n) &amp;lt;/tex&amp;gt;. Идея алгоритма проста : для каждой вершины найдем видимые из нее вершины независимо. Если научиться делать это за &amp;lt;tex&amp;gt; O(n \log  n) &amp;lt;/tex&amp;gt;, задача решена, так как всего точек &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Переформулируем задачу : дана точка &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и множество отрезков {{---}} ребер препятствий. &lt;br /&gt;
Найти : множество концов отрезков, видимых из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для решения этой задачи будем использовать заметающий луч с началом в точке &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Его статусом будут отрезки, которые его пересекают, упорядоченные по возрастанию расстояния от точки &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; до точки пересечения. Точками событий будут концы отрезков. &lt;br /&gt;
&lt;br /&gt;
Будем рассматривать точки слева направо, таким образом потребуется заметать только правую половину плоскости, так как ребра, которые должны идти в левую будут уже добавлены ранее.&lt;br /&gt;
&lt;br /&gt;
Изначально, пустим луч из рассматриваемой вершины вертикально вверх и добавим в статус все отрезки, которые он пересекает, по увеличению расстояния до них. Теперь будем рассматривать точки &amp;lt;tex&amp;gt; w \in V &amp;lt;/tex&amp;gt; в порядке сортировки по углу между &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и вертикальной полуосью &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt;. При таком обходе проверка видимости вершины будет выполняться за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;, так как достаточно проверить пересечение с отрезком, первым в статусе. Действительно, если вершина не видна, то отрезок &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; пересекает несколько отрезков, лежащих перед &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt;, а значит и ближайший, то есть первый в статусе. В противном случае все пересекаемые лучом отрезки лежат за вершиной &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; и пересечения отрезка &amp;lt;tex&amp;gt; uw &amp;lt;/tex&amp;gt; с ближайшим отрезком в статусе не будет. Вне зависимости от видимости вершины, необходимо изменить статус заметающего луча. Для этого необходимо удалить из статуса все отрезки, которые заканчиваются вершине &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; (лежат слева от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;) и добавить все отрезки, которые в ней начинаются (лежат справа от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Псевдокод =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
graph buildVisibilityGraph(Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
   Set&amp;lt;Vertex&amp;gt; vertices = getVertices(segments)       //получаем все вершины препятствий&lt;br /&gt;
   vertices.add(s, t)                                 //добавляем начальную и конечную вершину&lt;br /&gt;
   graph visibilityGraph(vertices)                    //изначально в графе только вершины&lt;br /&gt;
   for Vertex v in vertices                           //для каждой вершины&lt;br /&gt;
      for Vertex w in getVisibleVertices(v, segments) //добавляем в граф все видимые из нее вершины&lt;br /&gt;
         visibilityGraph.addEdge(v, w)&lt;br /&gt;
   return visibilityGraph&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Здесь функция getVisibleVertices(&amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;) возвращет все видимые из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вершины и выглядит так:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
vector&amp;lt;Vertex&amp;gt; getVisibleVertices(vertex v, set&amp;lt;segment&amp;gt; segments)&lt;br /&gt;
// Инициализируем статус&lt;br /&gt;
   for segment s in segments&lt;br /&gt;
      if intersection s and ray from v to up exists&lt;br /&gt;
         status.add(s)&lt;br /&gt;
// Инициализируем множество вершин, которые нужно рассматривать&lt;br /&gt;
   for point p in segments&lt;br /&gt;
      if p.x &amp;gt;= v.x&lt;br /&gt;
         currentVertices.add(p)&lt;br /&gt;
   sort(currentVertices) by angle&lt;br /&gt;
// Для каждой вершины проверяем, видима ли она и обновляем статус&lt;br /&gt;
   for w in currentVertices&lt;br /&gt;
      if intersection vw and status.first not exists&lt;br /&gt;
         answer.add(w)&lt;br /&gt;
      delete from status all edges ending in w&lt;br /&gt;
      add in status all edges beginning in w&lt;br /&gt;
   return answer&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
В качестве статуса нужно использовать структуру данных, позволяющую добавлять и удалять из нее отрезки за &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; и извлекать минимум за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt;. В этом случае достигается асимптотика &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;, так как для каждой из &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; точек выполняется сортировка(&amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;), обновление статуса (суммарно &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, так как каждый отрезок добавляется и удаляется из статуса только один раз) и запросы ближайшего отрезка (&amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; на точку, то есть &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;). &lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zamrefr1.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr2.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr3.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Overmars and Welzl’s Algorithm &amp;lt;tex&amp;gt; O(n ^ 2) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
[http://igitur-archive.library.uu.nl/math/2006-1214-201604/overmars_88_new_methods.pdf visibility graph при помощи rotation tree]&lt;br /&gt;
&lt;br /&gt;
C помощью [http://bit.ly/1eEqTzk rotation tree] можно достичь асимптотики &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Motion planning ==&lt;br /&gt;
[[Файл:mink.png|200px|thumb|left|Раздуваем препятствия]]&lt;br /&gt;
[[Файл:mink2.png|400px|thumb|right|Ищем путь для точки]]&lt;br /&gt;
Тут мы двигаем не точку, а произвольный выпуклый полигон. Если мы его не можем вращать, просто считаем configuration space, т. е. &amp;quot;обводим&amp;quot; препятствия нашим полигоном (делаем [[Сумма Минковского (определение, вычисление)|сумму Минковского]] препятствий и полигона, сдвинутого в начало координат какой-нибудь точкой) и получаем другие препятствия, но зато теперь мы двигаем точку. А это мы уже научились делать выше.&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим случай, когда мы можем вращать полигон. Для начала построим [[Трапецоидная карта|трапецоидную карту]], как будто мы не можем вращать полигон. Теперь будем вращать полигон на малый угол, пока он не сделает полный оборот вокруг своей оси, и для каждого угла сделаем трапецоидную карту. Теперь разместим(мысленно) все карты друг над другом. Таким образом получится, что поворот на малый угол {{---}} это движение вверх/вниз между слоями. Осталось [[Пересечение многоугольников (PSLG overlaying)|попересекать]] соседние слои и добавить между ними ребра (помним что первый и последний слои одинаковы) и уже в этом графе найти путь.&lt;br /&gt;
&lt;br /&gt;
При такой реализации в некоторых случаях у нас может возникнуть ошибка в повороте, так как в одной плоскости мы все можем делать точно: положения на соседних слоях могут допускаться, а повернуть мы не сможем. Это лечится в основном двумя способами: измельчением угла поворота и изначальным сглаживанием углов полигона {{---}} повращать полигон на &amp;lt;tex&amp;gt; +\epsilon &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; -\epsilon &amp;lt;/tex&amp;gt; и объединить с исходным, получив новый полигон.&lt;br /&gt;
&lt;br /&gt;
Так как эта задача достаточно ресурсоемка, мы рассматриваем только наличие пути, а не нахождение кратчайшего.&lt;br /&gt;
&lt;br /&gt;
== Источники ==&lt;br /&gt;
* 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&lt;br /&gt;
* [http://www.academia.edu/2845047/3D_Visibility_Graph статья] про visibility graphs на academia.edu&lt;br /&gt;
* [http://habrahabr.ru/post/199256/ Хабр]&lt;br /&gt;
[[Категория: Вычислительная геометрия]]&lt;br /&gt;
&lt;br /&gt;
== Ссылки ==&lt;br /&gt;
* Моя [https://github.com/Igorjan94/cg/blob/master/include/cg/algorithms/visibilityGraph.h реализация] алгоритма за &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;. Далеко от идеального, но работает&lt;/div&gt;</summary>
		<author><name>Igorjan94</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44806</id>
		<title>Visibility graph и motion planning</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44806"/>
				<updated>2015-02-08T18:08:00Z</updated>
		
		<summary type="html">&lt;p&gt;Igorjan94: источники облагорожены и добавлена ссылка на реализацию&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Visibility graph ==&lt;br /&gt;
{|align=&amp;quot;right&amp;quot;&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
|[[Файл:trap.png|200px|thumb|right|Путь с препятствиями через трапецоидную карту]]&lt;br /&gt;
|[[Файл:notShort.png|300px|thumb|right|Такой путь не самый короткий]]&lt;br /&gt;
|}&lt;br /&gt;
Рассмотрим задачу нахождения пути от точки &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt; с препятствиями. Для начала рассмотрим движение материальной точки, случай, когда размером и формой движимого объекта пренебречь нельзя, будет [[Visibility graph и motion planning#Motion planning|позднее]]. &lt;br /&gt;
&lt;br /&gt;
Обычно эта задача решается с помощью [[Трапецоидная карта | трапецоидной карты]], по которой строится граф, ребра которого соединяют центры трапедоидов и вершины &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt; с серединами вертикальных сторон трапецоидов. В этом графе любым алгоритмом поиска кратчайших путей (например, алгоритмом [[Алгоритм Дейкстры|Дейкстры]] или [[Алгоритм A*|A*]]) находится путь от &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм работает за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; и за линейное количество памяти и идеально подходит для нахождения какого-нибудь пути между конечными вершинами. Но иногда нужно найти кратчайший путь, и этот алгоритм не подходит, хоть и дает хорошее приближение.&lt;br /&gt;
&lt;br /&gt;
На сегодняшний день точные решения в лучшем случае работают за &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; времени и памяти (здесь и далее &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество всех вершин).&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим точное решение с помощью построения графа видимости. После его построения, как и в случае с трапецоидной картой, путь ищется стандартными алгоритмами.&lt;br /&gt;
&lt;br /&gt;
Для простоты рассуждений вершины &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt; будем считать вершинами полигонов.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|about=О кратчайшем пути&lt;br /&gt;
|statement=&lt;br /&gt;
Любой кратчайший путь между двумя вершинами с полигональными препятствиями представляет собой ломаную, вершины которой {{---}} вершины полигонов.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:short.png|150px|thumb|right|Short cut]]&lt;br /&gt;
Пусть кратчайший путь {{---}} не ломаная. В таком случае, на пути существует такая точка &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, которая не принадлежит ни одному прямому отрезку. Это означает, что существует &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестность точки &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, в которую не попадает ни одно препятствие (случай, когда точка попала на ребро рассматривается аналогично). В таком случае, подпуть, который находится внутри &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности, по неравенству треугольника может быть сокращён по хорде, соединяющий точки пересечения границы &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности с путем. Раз часть пути может быть уменьшена, значит и весь путь может быть уменьшен, а значит исходное предположение некорректно.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
Говорят, что вершина &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; &amp;lt;i&amp;gt; видна &amp;lt;/i&amp;gt;(англ. mutually visible) из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;, если отрезок &amp;lt;tex&amp;gt; uv &amp;lt;/tex&amp;gt; не пересекает ни одного препятствия.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
'''visibility graph''' {{---}} граф, вершины которого {{---}} вершины полигонов. Между вершинами &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; существует ребро, если из &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; видна &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
В худшем случае в таком графе может быть &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; ребер. Однако по некоторым ребрам кратчайший путь точно не пройдет, и такие ребра из графа можно удалить.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
[[Файл:edgeToDelete.png|150px|thumb|right|Удаляем &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Если существуют вершины &amp;lt;tex&amp;gt; A, B, C &amp;lt;/tex&amp;gt; одного препятствия и вершина &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; такая, что поворот &amp;lt;tex&amp;gt; DBA &amp;lt;/tex&amp;gt; не совпадает с поворотом &amp;lt;tex&amp;gt; DBC &amp;lt;/tex&amp;gt;, то ребро &amp;lt;tex&amp;gt; DB &amp;lt;/tex&amp;gt; не принадлежит кратчайшему пути и его можно удалить из графа. (См. поясняющую картинку справа)&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:edgeNotToDelete.png|200px|thumb|right|Не удаляем &amp;lt;tex&amp;gt; BS &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Путь проходящий через ребро &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt; будет длиннее, чем через соседей точки &amp;lt;tex&amp;gt; B &amp;lt;/tex&amp;gt;, так как по неравенству треугольника &amp;lt;tex&amp;gt; AB + BD &amp;lt; AD &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
По доказанным леммам любое ребро кратчайшего пути содержится в графе, таким образом для нахождения кратчайшего пути осталось найти кратчайший путь в этом графе от &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt;. Рассмотрим алгоритмы построения графа видимости.&lt;br /&gt;
&lt;br /&gt;
=== Построение visibility графа ===&lt;br /&gt;
==== Наивный алгоритм. &amp;lt;tex&amp;gt; O(n ^ 3) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
Если делать наивно, т. е. для каждой пары вершин проверять можно ли добавить ли такое ребро(нет ли пересечений с полигонами), будет &amp;lt;tex&amp;gt; O(n^3) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Lee’s Algorithm. &amp;lt;tex&amp;gt; O(n ^ 2 \log n) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
{|&lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zam.png|300px|thumb|left|Заметание плоскости вращающимся лучом]]&lt;br /&gt;
Однако можно это сделать за &amp;lt;tex&amp;gt; O(n ^ 2 \log  n) &amp;lt;/tex&amp;gt;. Идея алгоритма проста : для каждой вершины найдем видимые из нее вершины независимо. Если научиться делать это за &amp;lt;tex&amp;gt; O(n \log  n) &amp;lt;/tex&amp;gt;, задача решена, так как всего точек &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Переформулируем задачу : дана точка &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и множество отрезков {{---}} ребер препятствий. &lt;br /&gt;
Найти : множество концов отрезков, видимых из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для решения этой задачи будем использовать заметающий луч с началом в точке &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Его статусом будут отрезки, которые его пересекают, упорядоченные по возрастанию расстояния от точки &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; до точки пересечения. Точками событий будут концы отрезков. &lt;br /&gt;
&lt;br /&gt;
Будем рассматривать точки слева направо, таким образом потребуется заметать только правую половину плоскости, так как ребра, которые должны идти в левую будут уже добавлены ранее.&lt;br /&gt;
&lt;br /&gt;
Изначально, пустим луч из рассматриваемой вершины вертикально вверх и добавим в статус все отрезки, которые он пересекает, по увеличению расстояния до них. Теперь будем рассматривать точки &amp;lt;tex&amp;gt; w \in V &amp;lt;/tex&amp;gt; в порядке сортировки по углу между &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и вертикальной полуосью &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt;. При таком обходе проверка видимости вершины будет выполняться за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;, так как достаточно проверить пересечение с отрезком, первым в статусе. Действительно, если вершина не видна, то отрезок &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; пересекает несколько отрезков, лежащих перед &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt;, а значит и ближайший, то есть первый в статусе. В противном случае все пересекаемые лучом отрезки лежат за вершиной &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; и пересечения отрезка &amp;lt;tex&amp;gt; uw &amp;lt;/tex&amp;gt; с ближайшим отрезком в статусе не будет. Вне зависимости от видимости вершины, необходимо изменить статус заметающего луча. Для этого необходимо удалить из статуса все отрезки, которые заканчиваются вершине &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; (лежат слева от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;) и добавить все отрезки, которые в ней начинаются (лежат справа от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Псевдокод =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
graph buildVisibilityGraph(Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
   Set&amp;lt;Vertex&amp;gt; vertices = getVertices(segments)       //получаем все вершины препятствий&lt;br /&gt;
   vertices.add(s, t)                                 //добавляем начальную и конечную вершину&lt;br /&gt;
   graph visibilityGraph(vertices)                    //изначально в графе только вершины&lt;br /&gt;
   for Vertex v in vertices                           //для каждой вершины&lt;br /&gt;
      for Vertex w in getVisibleVertices(v, segments) //добавляем в граф все видимые из нее вершины&lt;br /&gt;
         visibilityGraph.addEdge(v, w)&lt;br /&gt;
   return visibilityGraph&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Здесь функция getVisibleVertices(&amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;) возвращет все видимые из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вершины и выглядит так:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
vector&amp;lt;Vertex&amp;gt; getVisibleVertices(vertex v, set&amp;lt;segment&amp;gt; segments)&lt;br /&gt;
// Инициализируем статус&lt;br /&gt;
   for segment s in segments&lt;br /&gt;
      if intersection s and ray from v to up exists&lt;br /&gt;
         status.add(s)&lt;br /&gt;
// Инициализируем множество вершин, которые нужно рассматривать&lt;br /&gt;
   for point p in segments&lt;br /&gt;
      if p.x &amp;gt;= v.x&lt;br /&gt;
         currentVertices.add(p)&lt;br /&gt;
   sort(currentVertices) by angle&lt;br /&gt;
// Для каждой вершины проверяем, видима ли она и обновляем статус&lt;br /&gt;
   for w in currentVertices&lt;br /&gt;
      if intersection vw and status.first not exists&lt;br /&gt;
         answer.add(w)&lt;br /&gt;
      delete from status all edges ending in w&lt;br /&gt;
      add in status all edges beginning in w&lt;br /&gt;
   return answer&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
В качестве статуса нужно использовать структуру данных, позволяющую добавлять и удалять из нее отрезки за &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; и извлекать минимум за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt;. В этом случае достигается асимптотика &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;, так как для каждой из &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; точек выполняется сортировка(&amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;), обновление статуса (суммарно &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, так как каждый отрезок добавляется и удаляется из статуса только один раз) и запросы ближайшего отрезка (&amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; на точку, то есть &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;). &lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zamrefr1.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr2.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr3.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Overmars and Welzl’s Algorithm &amp;lt;tex&amp;gt; O(n ^ 2) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
[http://igitur-archive.library.uu.nl/math/2006-1214-201604/overmars_88_new_methods.pdf visibility graph при помощи rotation tree]&lt;br /&gt;
&lt;br /&gt;
C помощью [http://bit.ly/1eEqTzk rotation tree] можно достичь асимптотики &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Motion planning ==&lt;br /&gt;
[[Файл:mink.png|200px|thumb|left|Раздуваем препятствия]]&lt;br /&gt;
[[Файл:mink2.png|400px|thumb|right|Ищем путь для точки]]&lt;br /&gt;
Тут мы двигаем не точку, а произвольный выпуклый полигон. Если мы его не можем вращать, просто считаем configuration space, т. е. &amp;quot;обводим&amp;quot; препятствия нашим полигоном (делаем [[Сумма Минковского (определение, вычисление)|сумму Минковского]] препятствий и полигона, сдвинутого в начало координат какой-нибудь точкой) и получаем другие препятствия, но зато теперь мы двигаем точку. А это мы уже научились делать выше.&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим случай, когда мы можем вращать полигон. Для начала построим [[Трапецоидная карта|трапецоидную карту]], как будто мы не можем вращать полигон. Теперь будем вращать полигон на малый угол, пока он не сделает полный оборот вокруг своей оси, и для каждого угла сделаем трапецоидную карту. Теперь разместим(мысленно) все карты друг над другом. Таким образом получится, что поворот на малый угол {{---}} это движение вверх/вниз между слоями. Осталось [[Пересечение многоугольников (PSLG overlaying)|попересекать]] соседние слои и добавить между ними ребра (помним что первый и последний слои одинаковы) и уже в этом графе найти путь.&lt;br /&gt;
&lt;br /&gt;
При такой реализации в некоторых случаях у нас может возникнуть ошибка в повороте, так как в одной плоскости мы все можем делать точно: положения на соседних слоях могут допускаться, а повернуть мы не сможем. Это лечится в основном двумя способами: измельчением угла поворота и изначальным сглаживанием углов полигона {{---}} повращать полигон на &amp;lt;tex&amp;gt; +\epsilon &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; -\epsilon &amp;lt;/tex&amp;gt; и объединить с исходным, получив новый полигон.&lt;br /&gt;
&lt;br /&gt;
Так как эта задача достаточно ресурсоемка, мы рассматриваем только наличие пути, а не нахождение кратчайшего.&lt;br /&gt;
&lt;br /&gt;
== Источники ==&lt;br /&gt;
* 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&lt;br /&gt;
* [http://www.academia.edu/2845047/3D_Visibility_Graph статья] про visibility graphs на academia.edu&lt;br /&gt;
* [http://habrahabr.ru/post/199256/ Хабр]&lt;br /&gt;
[[Категория: Вычислительная геометрия]]&lt;br /&gt;
&lt;br /&gt;
== Ссылки ==&lt;br /&gt;
* Моя [https://github.com/Igorjan94/cg/blob/master/include/cg/algorithms/visibilityGraph.h реализация] на github.com. Далеко от идеального, но работает&lt;/div&gt;</summary>
		<author><name>Igorjan94</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44803</id>
		<title>Visibility graph и motion planning</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44803"/>
				<updated>2015-02-06T14:38:02Z</updated>
		
		<summary type="html">&lt;p&gt;Igorjan94: /* Lee’s Algorithm.  O(n ^ 2 \log n)  */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Visibility graph ==&lt;br /&gt;
{|align=&amp;quot;right&amp;quot;&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
|[[Файл:trap.png|200px|thumb|right|Путь с препятствиями через трапецоидную карту]]&lt;br /&gt;
|[[Файл:notShort.png|300px|thumb|right|Такой путь не самый короткий]]&lt;br /&gt;
|}&lt;br /&gt;
Рассмотрим задачу нахождения пути от точки &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt; с препятствиями. Для начала рассмотрим движение материальной точки, случай, когда размером и формой движимого объекта пренебречь нельзя, будет [[Visibility graph и motion planning#Motion planning|позднее]]. &lt;br /&gt;
&lt;br /&gt;
Обычно эта задача решается с помощью [[Трапецоидная карта | трапецоидной карты]], по которой строится граф, ребра которого соединяют центры трапедоидов и вершины &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt; с серединами вертикальных сторон трапецоидов. В этом графе любым алгоритмом поиска кратчайших путей (например, алгоритмом [[Алгоритм Дейкстры|Дейкстры]] или [[Алгоритм A*|A*]]) находится путь от &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм работает за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; и за линейное количество памяти и идеально подходит для нахождения какого-нибудь пути между конечными вершинами. Но иногда нужно найти кратчайший путь, и этот алгоритм не подходит, хоть и дает хорошее приближение.&lt;br /&gt;
&lt;br /&gt;
На сегодняшний день точные решения в лучшем случае работают за &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; времени и памяти (здесь и далее &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество всех вершин).&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим точное решение с помощью построения графа видимости. После его построения, как и в случае с трапецоидной картой, путь ищется стандартными алгоритмами.&lt;br /&gt;
&lt;br /&gt;
Для простоты рассуждений вершины &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt; будем считать вершинами полигонов.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|about=О кратчайшем пути&lt;br /&gt;
|statement=&lt;br /&gt;
Любой кратчайший путь между двумя вершинами с полигональными препятствиями представляет собой ломаную, вершины которой {{---}} вершины полигонов.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:short.png|150px|thumb|right|Short cut]]&lt;br /&gt;
Пусть кратчайший путь {{---}} не ломаная. В таком случае, на пути существует такая точка &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, которая не принадлежит ни одному прямому отрезку. Это означает, что существует &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестность точки &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, в которую не попадает ни одно препятствие (случай, когда точка попала на ребро рассматривается аналогично). В таком случае, подпуть, который находится внутри &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности, по неравенству треугольника может быть сокращён по хорде, соединяющий точки пересечения границы &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности с путем. Раз часть пути может быть уменьшена, значит и весь путь может быть уменьшен, а значит исходное предположение некорректно.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
Говорят, что вершина &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; &amp;lt;i&amp;gt; видна &amp;lt;/i&amp;gt;(англ. mutually visible) из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;, если отрезок &amp;lt;tex&amp;gt; uv &amp;lt;/tex&amp;gt; не пересекает ни одного препятствия.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
'''visibility graph''' {{---}} граф, вершины которого {{---}} вершины полигонов. Между вершинами &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; существует ребро, если из &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; видна &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
В худшем случае в таком графе может быть &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; ребер. Однако по некоторым ребрам кратчайший путь точно не пройдет, и такие ребра из графа можно удалить.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
[[Файл:edgeToDelete.png|150px|thumb|right|Удаляем &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Если существуют вершины &amp;lt;tex&amp;gt; A, B, C &amp;lt;/tex&amp;gt; одного препятствия и вершина &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; такая, что поворот &amp;lt;tex&amp;gt; DBA &amp;lt;/tex&amp;gt; не совпадает с поворотом &amp;lt;tex&amp;gt; DBC &amp;lt;/tex&amp;gt;, то ребро &amp;lt;tex&amp;gt; DB &amp;lt;/tex&amp;gt; не принадлежит кратчайшему пути и его можно удалить из графа. (См. поясняющую картинку справа)&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:edgeNotToDelete.png|200px|thumb|right|Не удаляем &amp;lt;tex&amp;gt; BS &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Путь проходящий через ребро &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt; будет длиннее, чем через соседей точки &amp;lt;tex&amp;gt; B &amp;lt;/tex&amp;gt;, так как по неравенству треугольника &amp;lt;tex&amp;gt; AB + BD &amp;lt; AD &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
По доказанным леммам любое ребро кратчайшего пути содержится в графе, таким образом для нахождения кратчайшего пути осталось найти кратчайший путь в этом графе от &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt;. Рассмотрим алгоритмы построения графа видимости.&lt;br /&gt;
&lt;br /&gt;
=== Построение visibility графа ===&lt;br /&gt;
==== Наивный алгоритм. &amp;lt;tex&amp;gt; O(n ^ 3) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
Если делать наивно, т. е. для каждой пары вершин проверять можно ли добавить ли такое ребро(нет ли пересечений с полигонами), будет &amp;lt;tex&amp;gt; O(n^3) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Lee’s Algorithm. &amp;lt;tex&amp;gt; O(n ^ 2 \log n) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
{|&lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zam.png|300px|thumb|left|Заметание плоскости вращающимся лучом]]&lt;br /&gt;
Однако можно это сделать за &amp;lt;tex&amp;gt; O(n ^ 2 \log  n) &amp;lt;/tex&amp;gt;. Идея алгоритма проста : для каждой вершины найдем видимые из нее вершины независимо. Если научиться делать это за &amp;lt;tex&amp;gt; O(n \log  n) &amp;lt;/tex&amp;gt;, задача решена, так как всего точек &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Переформулируем задачу : дана точка &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и множество отрезков {{---}} ребер препятствий. &lt;br /&gt;
Найти : множество концов отрезков, видимых из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для решения этой задачи будем использовать заметающий луч с началом в точке &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Его статусом будут отрезки, которые его пересекают, упорядоченные по возрастанию расстояния от точки &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; до точки пересечения. Точками событий будут концы отрезков. &lt;br /&gt;
&lt;br /&gt;
Будем рассматривать точки слева направо, таким образом потребуется заметать только правую половину плоскости, так как ребра, которые должны идти в левую будут уже добавлены ранее.&lt;br /&gt;
&lt;br /&gt;
Изначально, пустим луч из рассматриваемой вершины вертикально вверх и добавим в статус все отрезки, которые он пересекает, по увеличению расстояния до них. Теперь будем рассматривать точки &amp;lt;tex&amp;gt; w \in V &amp;lt;/tex&amp;gt; в порядке сортировки по углу между &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и вертикальной полуосью &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt;. При таком обходе проверка видимости вершины будет выполняться за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;, так как достаточно проверить пересечение с отрезком, первым в статусе. Действительно, если вершина не видна, то отрезок &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; пересекает несколько отрезков, лежащих перед &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt;, а значит и ближайший, то есть первый в статусе. В противном случае все пересекаемые лучом отрезки лежат за вершиной &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; и пересечения отрезка &amp;lt;tex&amp;gt; uw &amp;lt;/tex&amp;gt; с ближайшим отрезком в статусе не будет. Вне зависимости от видимости вершины, необходимо изменить статус заметающего луча. Для этого необходимо удалить из статуса все отрезки, которые заканчиваются вершине &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; (лежат слева от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;) и добавить все отрезки, которые в ней начинаются (лежат справа от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Псевдокод =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
graph buildVisibilityGraph(Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
   Set&amp;lt;Vertex&amp;gt; vertices = getVertices(segments)       //получаем все вершины препятствий&lt;br /&gt;
   vertices.add(s, t)                                 //добавляем начальную и конечную вершину&lt;br /&gt;
   graph visibilityGraph(vertices)                    //изначально в графе только вершины&lt;br /&gt;
   for Vertex v in vertices                           //для каждой вершины&lt;br /&gt;
      for Vertex w in getVisibleVertices(v, segments) //добавляем в граф все видимые из нее вершины&lt;br /&gt;
         visibilityGraph.addEdge(v, w)&lt;br /&gt;
   return visibilityGraph&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Здесь функция getVisibleVertices(&amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;) возвращет все видимые из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вершины и выглядит так:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
vector&amp;lt;Vertex&amp;gt; getVisibleVertices(vertex v, set&amp;lt;segment&amp;gt; segments)&lt;br /&gt;
// Инициализируем статус&lt;br /&gt;
   for segment s in segments&lt;br /&gt;
      if intersection s and ray from v to up exists&lt;br /&gt;
         status.add(s)&lt;br /&gt;
// Инициализируем множество вершин, которые нужно рассматривать&lt;br /&gt;
   for point p in segments&lt;br /&gt;
      if p.x &amp;gt;= v.x&lt;br /&gt;
         currentVertices.add(p)&lt;br /&gt;
   sort(currentVertices) by angle&lt;br /&gt;
// Для каждой вершины проверяем, видима ли она и обновляем статус&lt;br /&gt;
   for w in currentVertices&lt;br /&gt;
      if intersection vw and status.first not exists&lt;br /&gt;
         answer.add(w)&lt;br /&gt;
      delete from status all edges ending in w&lt;br /&gt;
      add in status all edges beginning in w&lt;br /&gt;
   return answer&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
В качестве статуса нужно использовать структуру данных, позволяющую добавлять и удалять из нее отрезки за &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; и извлекать минимум за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt;. В этом случае достигается асимптотика &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;, так как для каждой из &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; точек выполняется сортировка(&amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;), обновление статуса (суммарно &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, так как каждый отрезок добавляется и удаляется из статуса только один раз) и запросы ближайшего отрезка (&amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt; на точку, то есть &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;). &lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zamrefr1.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr2.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr3.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Overmars and Welzl’s Algorithm &amp;lt;tex&amp;gt; O(n ^ 2) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
[http://igitur-archive.library.uu.nl/math/2006-1214-201604/overmars_88_new_methods.pdf visibility graph при помощи rotation tree]&lt;br /&gt;
&lt;br /&gt;
C помощью [http://bit.ly/1eEqTzk rotation tree] можно достичь асимптотики &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Motion planning ==&lt;br /&gt;
[[Файл:mink.png|200px|thumb|left|Раздуваем препятствия]]&lt;br /&gt;
[[Файл:mink2.png|400px|thumb|right|Ищем путь для точки]]&lt;br /&gt;
Тут мы двигаем не точку, а произвольный выпуклый полигон. Если мы его не можем вращать, просто считаем configuration space, т. е. &amp;quot;обводим&amp;quot; препятствия нашим полигоном (делаем [[Сумма Минковского (определение, вычисление)|сумму Минковского]] препятствий и полигона, сдвинутого в начало координат какой-нибудь точкой) и получаем другие препятствия, но зато теперь мы двигаем точку. А это мы уже научились делать выше.&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим случай, когда мы можем вращать полигон. Для начала построим [[Трапецоидная карта|трапецоидную карту]], как будто мы не можем вращать полигон. Теперь будем вращать полигон на малый угол, пока он не сделает полный оборот вокруг своей оси, и для каждого угла сделаем трапецоидную карту. Теперь разместим(мысленно) все карты друг над другом. Таким образом получится, что поворот на малый угол {{---}} это движение вверх/вниз между слоями. Осталось [[Пересечение многоугольников (PSLG overlaying)|попересекать]] соседние слои и добавить между ними ребра (помним что первый и последний слои одинаковы) и уже в этом графе найти путь.&lt;br /&gt;
&lt;br /&gt;
При такой реализации в некоторых случаях у нас может возникнуть ошибка в повороте, так как в одной плоскости мы все можем делать точно: положения на соседних слоях могут допускаться, а повернуть мы не сможем. Это лечится в основном двумя способами: измельчением угла поворота и изначальным сглаживанием углов полигона {{---}} повращать полигон на &amp;lt;tex&amp;gt; +\epsilon &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; -\epsilon &amp;lt;/tex&amp;gt; и объединить с исходным, получив новый полигон.&lt;br /&gt;
&lt;br /&gt;
Так как эта задача достаточно ресурсоемка, мы рассматриваем только наличие пути, а не нахождение кратчайшего.&lt;br /&gt;
&lt;br /&gt;
== Источники ==&lt;br /&gt;
* 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&lt;br /&gt;
* [http://www.academia.edu/2845047/3D_Visibility_Graph статья про visibility graphs]&lt;br /&gt;
* [http://habrahabr.ru/post/199256/ Хабр]&lt;br /&gt;
[[Категория: Вычислительная геометрия]]&lt;/div&gt;</summary>
		<author><name>Igorjan94</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44801</id>
		<title>Visibility graph и motion planning</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44801"/>
				<updated>2015-02-05T21:17:13Z</updated>
		
		<summary type="html">&lt;p&gt;Igorjan94: /* Построение visibility графа */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Visibility graph ==&lt;br /&gt;
{|align=&amp;quot;right&amp;quot;&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
|[[Файл:trap.png|200px|thumb|right|Путь с препятствиями через трапецоидную карту]]&lt;br /&gt;
|[[Файл:notShort.png|300px|thumb|right|Такой путь не самый короткий]]&lt;br /&gt;
|}&lt;br /&gt;
Рассмотрим задачу нахождения пути от точки &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt; с препятствиями. Для начала рассмотрим движение материальной точки, случай, когда размером и формой движимого объекта пренебречь нельзя, будет [[Visibility graph и motion planning#Motion planning|позднее]]. &lt;br /&gt;
&lt;br /&gt;
Обычно эта задача решается с помощью [[Трапецоидная карта | трапецоидной карты]], по которой строится граф, ребра которого соединяют центры трапедоидов и вершины &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt; с серединами вертикальных сторон трапецоидов. В этом графе любым алгоритмом поиска кратчайших путей (например, алгоритмом [[Алгоритм Дейкстры|Дейкстры]] или [[Алгоритм A*|A*]]) находится путь от &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм работает за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; и за линейное количество памяти и идеально подходит для нахождения какого-нибудь пути между конечными вершинами. Но иногда нужно найти кратчайший путь, и этот алгоритм не подходит, хоть и дает хорошее приближение.&lt;br /&gt;
&lt;br /&gt;
На сегодняшний день точные решения в лучшем случае работают за &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; времени и памяти (здесь и далее &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество всех вершин).&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим точное решение с помощью построения графа видимости. После его построения, как и в случае с трапецоидной картой, путь ищется стандартными алгоритмами.&lt;br /&gt;
&lt;br /&gt;
Для простоты рассуждений вершины &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt; будем считать вершинами полигонов.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|about=О кратчайшем пути&lt;br /&gt;
|statement=&lt;br /&gt;
Любой кратчайший путь между двумя вершинами с полигональными препятствиями представляет собой ломаную, вершины которой {{---}} вершины полигонов.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:short.png|150px|thumb|right|Short cut]]&lt;br /&gt;
Пусть кратчайший путь {{---}} не ломаная. В таком случае, на пути существует такая точка &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, которая не принадлежит ни одному прямому отрезку. Это означает, что существует &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестность точки &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, в которую не попадает ни одно препятствие (случай, когда точка попала на ребро рассматривается аналогично). В таком случае, подпуть, который находится внутри &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности, по неравенству треугольника может быть сокращён по хорде, соединяющий точки пересечения границы &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности с путем. Раз часть пути может быть уменьшена, значит и весь путь может быть уменьшен, а значит исходное предположение некорректно.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
Говорят, что вершина &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; &amp;lt;i&amp;gt; видна &amp;lt;/i&amp;gt;(англ. mutually visible) из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;, если отрезок &amp;lt;tex&amp;gt; uv &amp;lt;/tex&amp;gt; не пересекает ни одного препятствия.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
'''visibility graph''' {{---}} граф, вершины которого {{---}} вершины полигонов. Между вершинами &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; существует ребро, если из &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; видна &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
В худшем случае в таком графе может быть &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; ребер. Однако по некоторым ребрам кратчайший путь точно не пройдет, и такие ребра из графа можно удалить.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
[[Файл:edgeToDelete.png|150px|thumb|right|Удаляем &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Если существуют вершины &amp;lt;tex&amp;gt; A, B, C &amp;lt;/tex&amp;gt; одного препятствия и вершина &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; такая, что поворот &amp;lt;tex&amp;gt; DBA &amp;lt;/tex&amp;gt; не совпадает с поворотом &amp;lt;tex&amp;gt; DBC &amp;lt;/tex&amp;gt;, то ребро &amp;lt;tex&amp;gt; DB &amp;lt;/tex&amp;gt; не принадлежит кратчайшему пути и его можно удалить из графа. (См. поясняющую картинку справа)&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:edgeNotToDelete.png|200px|thumb|right|Не удаляем &amp;lt;tex&amp;gt; BS &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Путь проходящий через ребро &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt; будет длиннее, чем через соседей точки &amp;lt;tex&amp;gt; B &amp;lt;/tex&amp;gt;, так как по неравенству треугольника &amp;lt;tex&amp;gt; AB + BD &amp;lt; AD &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
По доказанным леммам любое ребро кратчайшего пути содержится в графе, таким образом для нахождения кратчайшего пути осталось найти кратчайший путь в этом графе от &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt;. Рассмотрим алгоритмы построения графа видимости.&lt;br /&gt;
&lt;br /&gt;
=== Построение visibility графа ===&lt;br /&gt;
==== Наивный алгоритм. &amp;lt;tex&amp;gt; O(n ^ 3) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
Если делать наивно, т. е. для каждой пары вершин проверять можно ли добавить ли такое ребро(нет ли пересечений с полигонами), будет &amp;lt;tex&amp;gt; O(n^3) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Lee’s Algorithm. &amp;lt;tex&amp;gt; O(n ^ 2 \log n) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
{|&lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zam.png|300px|thumb|left|Заметание плоскости вращающимся лучом]]&lt;br /&gt;
Однако можно это сделать за &amp;lt;tex&amp;gt; O(n ^ 2 \log  n) &amp;lt;/tex&amp;gt;. Идея алгоритма проста : для каждой вершины найдем видимые из нее вершины независимо. Если научиться делать это за &amp;lt;tex&amp;gt; O(n \log  n) &amp;lt;/tex&amp;gt;, задача решена, так как всего точек &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Переформулируем задачу : дана точка &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и множество отрезков {{---}} ребер препятствий. &lt;br /&gt;
Найти : множество концов отрезков, видимых из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для решения этой задачи будем использовать заметающий луч с началом в точке &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Его статусом будут отрезки, которые его пересекают, упорядоченные по возрастанию расстояния от точки &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; до точки пересечения. Точками событий будут концы отрезков. &lt;br /&gt;
&lt;br /&gt;
Будем рассматривать точки слева направо, таким образом потребуется заметать только правую половину плоскости, так как ребра, которые должны идти в левую будут уже добавлены ранее.&lt;br /&gt;
&lt;br /&gt;
Итак, первым делом вершины &amp;lt;tex&amp;gt; w \in V &amp;lt;/tex&amp;gt; сортируются по углу между лучом &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; и вертикальной полуосью, проходящей через &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; {{---}} луч &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt;. Затем инициализируем статус отрезками, которые пересекают луч &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt;. Далее начинается заметание плоскости. В порядке сортировки вершин для каждой из них выполняется проверка: видна ли вершина &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; из вершины &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Для этого нам достаточно проверить только пересечение заметающего луча с ближайшим отрезком в статусе. Если вершина видима, необходимо добавить её в список видимых вершин. И, наконец, вне зависимости от видимости вершины, необходимо изменить статус заметающего луча. Для этого для текущей вершины &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; необходимо удалить из статуса все рёбра (отрезки), которые заканчиваются в этой вершине (лежат слева от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;) и добавить все рёбра (отрезки), которые в ней начинаются (лежат справа от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Псевдокод =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
graph buildVisibilityGraph(Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
   Set&amp;lt;Vertex&amp;gt; vertices = getVertices(segments)       //получаем все вершины препятствий&lt;br /&gt;
   vertices.add(s, t)                                 //добавляем начальную и конечную вершину&lt;br /&gt;
   graph visibilityGraph(vertices)                    //изначально в графе только вершины&lt;br /&gt;
   for Vertex v in vertices                           //для каждой вершины&lt;br /&gt;
      for Vertex w in getVisibleVertices(v)           //добавляем в граф все видимые из нее вершины&lt;br /&gt;
         visibilityGraph.addEdge(v, w)&lt;br /&gt;
   return visibilityGraph&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Здесь функция getVisibleVertices(&amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;) возвращет все видимые из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вершины и выглядит так:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
vector&amp;lt;Vertex&amp;gt; getVisibleVertices(vertex v)&lt;br /&gt;
   vector&amp;lt;Vertex&amp;gt; answer, currentVertices&lt;br /&gt;
   currentVertices.add(all w in vertices : w.x &amp;gt;= v.x)   //рассматриваем только вершины правее v&lt;br /&gt;
   sort vertexes by angle                                //в порядке увеличения угла с &lt;br /&gt;
                                                         //вертикальной прямой, проходящей через v&lt;br /&gt;
   heap&amp;lt;Segment&amp;gt; status&lt;br /&gt;
   status.add(all e in Edges : intersection(e, l) != null)  //инициализируем статус&lt;br /&gt;
   for w in currentVertices&lt;br /&gt;
      if intersection(vw, status.closest) == null        //если отрезок vw не пересекает ближайший &lt;br /&gt;
                                                         //  отрезок в статусе&lt;br /&gt;
         answer.add(w)                                   //  добавляем в ответ&lt;br /&gt;
      delete from status all edges ending in w           //обновляем статус&lt;br /&gt;
      add in status all edges beginning in w&lt;br /&gt;
   return answer&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Вершин у нас &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;, для каждой вершины мы выполяеем следующие шаги: сортировка (&amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;), проверка пересечения (&amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;), обновление статуса (суммарно выполняется за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, так как мы имеем &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; ребер и каждое ребро мы добавляем и удаляем один раз (вставка происходит за &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt;, удаление можно сделать за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;, например, для каждой вершины сохраняя позицию входящих в нее отрезков). Итого получаеем &amp;lt;tex&amp;gt; O(n) * O(n \log n) = O(n^2 \log n) &amp;lt;/tex&amp;gt;. Что и требовалось доказать.&lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zamrefr1.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr2.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr3.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Overmars and Welzl’s Algorithm &amp;lt;tex&amp;gt; O(n ^ 2) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
[http://igitur-archive.library.uu.nl/math/2006-1214-201604/overmars_88_new_methods.pdf visibility graph при помощи rotation tree]&lt;br /&gt;
&lt;br /&gt;
C помощью [http://bit.ly/1eEqTzk rotation tree] можно достичь асимптотики &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Motion planning ==&lt;br /&gt;
[[Файл:mink.png|200px|thumb|left|Раздуваем препятствия]]&lt;br /&gt;
[[Файл:mink2.png|400px|thumb|right|Ищем путь для точки]]&lt;br /&gt;
Тут мы двигаем не точку, а произвольный выпуклый полигон. Если мы его не можем вращать, просто считаем configuration space, т. е. &amp;quot;обводим&amp;quot; препятствия нашим полигоном (делаем [[Сумма Минковского (определение, вычисление)|сумму Минковского]] препятствий и полигона, сдвинутого в начало координат какой-нибудь точкой) и получаем другие препятствия, но зато теперь мы двигаем точку. А это мы уже научились делать выше.&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим случай, когда мы можем вращать полигон. Для начала построим [[Трапецоидная карта|трапецоидную карту]], как будто мы не можем вращать полигон. Теперь будем вращать полигон на малый угол, пока он не сделает полный оборот вокруг своей оси, и для каждого угла сделаем трапецоидную карту. Теперь разместим(мысленно) все карты друг над другом. Таким образом получится, что поворот на малый угол {{---}} это движение вверх/вниз между слоями. Осталось [[Пересечение многоугольников (PSLG overlaying)|попересекать]] соседние слои и добавить между ними ребра (помним что первый и последний слои одинаковы) и уже в этом графе найти путь.&lt;br /&gt;
&lt;br /&gt;
При такой реализации в некоторых случаях у нас может возникнуть ошибка в повороте, так как в одной плоскости мы все можем делать точно: положения на соседних слоях могут допускаться, а повернуть мы не сможем. Это лечится в основном двумя способами: измельчением угла поворота и изначальным сглаживанием углов полигона {{---}} повращать полигон на &amp;lt;tex&amp;gt; +\epsilon &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; -\epsilon &amp;lt;/tex&amp;gt; и объединить с исходным, получив новый полигон.&lt;br /&gt;
&lt;br /&gt;
Так как эта задача достаточно ресурсоемка, мы рассматриваем только наличие пути, а не нахождение кратчайшего.&lt;br /&gt;
&lt;br /&gt;
== Источники ==&lt;br /&gt;
* 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&lt;br /&gt;
* [http://www.academia.edu/2845047/3D_Visibility_Graph статья про visibility graphs]&lt;br /&gt;
* [http://habrahabr.ru/post/199256/ Хабр]&lt;br /&gt;
[[Категория: Вычислительная геометрия]]&lt;/div&gt;</summary>
		<author><name>Igorjan94</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44800</id>
		<title>Visibility graph и motion planning</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44800"/>
				<updated>2015-02-05T19:57:20Z</updated>
		
		<summary type="html">&lt;p&gt;Igorjan94: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Visibility graph ==&lt;br /&gt;
{|align=&amp;quot;right&amp;quot;&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
|[[Файл:trap.png|200px|thumb|right|Путь с препятствиями через трапецоидную карту]]&lt;br /&gt;
|[[Файл:notShort.png|300px|thumb|right|Такой путь не самый короткий]]&lt;br /&gt;
|}&lt;br /&gt;
Рассмотрим задачу нахождения пути от точки &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt; с препятствиями. Для начала рассмотрим движение материальной точки, случай, когда размером и формой движимого объекта пренебречь нельзя, будет [[Visibility graph и motion planning#Motion planning|позднее]]. &lt;br /&gt;
&lt;br /&gt;
Обычно эта задача решается с помощью [[Трапецоидная карта | трапецоидной карты]], по которой строится граф, ребра которого соединяют центры трапедоидов и вершины &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt; с серединами вертикальных сторон трапецоидов. В этом графе любым алгоритмом поиска кратчайших путей (например, алгоритмом [[Алгоритм Дейкстры|Дейкстры]] или [[Алгоритм A*|A*]]) находится путь от &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм работает за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; и за линейное количество памяти и идеально подходит для нахождения какого-нибудь пути между конечными вершинами. Но иногда нужно найти кратчайший путь, и этот алгоритм не подходит, хоть и дает хорошее приближение.&lt;br /&gt;
&lt;br /&gt;
На сегодняшний день точные решения в лучшем случае работают за &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; времени и памяти (здесь и далее &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество всех вершин).&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим точное решение с помощью построения графа видимости. После его построения, как и в случае с трапецоидной картой, путь ищется стандартными алгоритмами.&lt;br /&gt;
&lt;br /&gt;
Для простоты рассуждений вершины &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt; будем считать вершинами полигонов.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|about=О кратчайшем пути&lt;br /&gt;
|statement=&lt;br /&gt;
Любой кратчайший путь между двумя вершинами с полигональными препятствиями представляет собой ломаную, вершины которой {{---}} вершины полигонов.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:short.png|150px|thumb|right|Short cut]]&lt;br /&gt;
Пусть кратчайший путь {{---}} не ломаная. В таком случае, на пути существует такая точка &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, которая не принадлежит ни одному прямому отрезку. Это означает, что существует &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестность точки &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, в которую не попадает ни одно препятствие (случай, когда точка попала на ребро рассматривается аналогично). В таком случае, подпуть, который находится внутри &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности, по неравенству треугольника может быть сокращён по хорде, соединяющий точки пересечения границы &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности с путем. Раз часть пути может быть уменьшена, значит и весь путь может быть уменьшен, а значит исходное предположение некорректно.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
Говорят, что вершина &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; &amp;lt;i&amp;gt; видна &amp;lt;/i&amp;gt;(англ. mutually visible) из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;, если отрезок &amp;lt;tex&amp;gt; uv &amp;lt;/tex&amp;gt; не пересекает ни одного препятствия.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
'''visibility graph''' {{---}} граф, вершины которого {{---}} вершины полигонов. Между вершинами &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; существует ребро, если из &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; видна &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
В худшем случае в таком графе может быть &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; ребер. Однако по некоторым ребрам кратчайший путь точно не пройдет, и такие ребра из графа можно удалить.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
[[Файл:edgeToDelete.png|150px|thumb|right|Удаляем &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Если существуют вершины &amp;lt;tex&amp;gt; A, B, C &amp;lt;/tex&amp;gt; одного препятствия и вершина &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; такая, что поворот &amp;lt;tex&amp;gt; DBA &amp;lt;/tex&amp;gt; не совпадает с поворотом &amp;lt;tex&amp;gt; DBC &amp;lt;/tex&amp;gt;, то ребро &amp;lt;tex&amp;gt; DB &amp;lt;/tex&amp;gt; не принадлежит кратчайшему пути и его можно удалить из графа. (См. поясняющую картинку справа)&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:edgeNotToDelete.png|200px|thumb|right|Не удаляем &amp;lt;tex&amp;gt; BS &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Путь проходящий через ребро &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt; будет длиннее, чем через соседей точки &amp;lt;tex&amp;gt; B &amp;lt;/tex&amp;gt;, так как по неравенству треугольника &amp;lt;tex&amp;gt; AB + BD &amp;lt; AD &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
По доказанным леммам любое ребро кратчайшего пути содержится в графе, таким образом для нахождения кратчайшего пути осталось найти кратчайший путь в этом графе от &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt;. Рассмотрим алгоритмы построения графа видимости.&lt;br /&gt;
&lt;br /&gt;
=== Построение visibility графа ===&lt;br /&gt;
==== Наивный алгоритм. &amp;lt;tex&amp;gt; O(n ^ 3) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
Если делать наивно, т. е. для каждой пары вершин проверять можно ли добавить ли такое ребро(нет ли пересечений с полигонами), будет &amp;lt;tex&amp;gt; O(n^3) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Lee’s Algorithm. &amp;lt;tex&amp;gt; O(n ^ 2 \log n) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
{|&lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zam.png|300px|thumb|left|Заметание плоскости вращающимся лучом]]&lt;br /&gt;
Однако можно это сделать за &amp;lt;tex&amp;gt; O(n ^ 2 \log  n) &amp;lt;/tex&amp;gt;. Нам нужно решить следующую задачу: на плоскости дано множество отрезков (рёбер препятствий) и точка &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Найти все концы отрезков, видимые из точки &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Будем заметать плоскость вращающимся лучом с началом в точке &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Статусом заметающего луча будут отрезки, которые его пересекают, упорядоченные по возрастанию расстояния от точки &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; до точки пересечения. Точками событий будут концы отрезков. &lt;br /&gt;
&lt;br /&gt;
Итак, первым делом вершины &amp;lt;tex&amp;gt; w \in V &amp;lt;/tex&amp;gt; сортируются по углу между лучом &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; и вертикальной полуосью, проходящей через &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; {{---}} луч &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; (достаточно рассматривать только точки, которые лежат правее &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;, так как все точки левее мы уже рассмотрели). Затем инициализируем статус отрезками, которые пересекают луч &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt;. Далее начинается заметание плоскости. В порядке сортировки вершин для каждой из них выполняется проверка: видна ли вершина &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; из вершины &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Для этого нам достаточно проверить только пересечение заметающего луча с ближайшим отрезком в статусе. Если вершина видима, необходимо добавить её в список видимых вершин. И, наконец, вне зависимости от видимости вершины, необходимо изменить статус заметающего луча. Для этого для текущей вершины &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; необходимо удалить из статуса все рёбра (отрезки), которые заканчиваются в этой вершине (лежат слева от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;) и добавить все рёбра (отрезки), которые в ней начинаются (лежат справа от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Псевдокод =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
graph buildVisibilityGraph(Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
   Set&amp;lt;Vertex&amp;gt; vertices = getVertices(segments)       //получаем все вершины препятствий&lt;br /&gt;
   vertices.add(s, t)                                 //добавляем начальную и конечную вершину&lt;br /&gt;
   graph visibilityGraph(vertices)                    //изначально в графе только вершины&lt;br /&gt;
   for Vertex v in vertices                           //для каждой вершины&lt;br /&gt;
      for Vertex w in getVisibleVertices(v)           //  добавляем в граф все видимые из нее вершины&lt;br /&gt;
         visibilityGraph.addEdge(v, w)&lt;br /&gt;
   return visibilityGraph&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Здесь функция getVisibleVertices(&amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;) возвращет все видимые из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вершины и выглядит так:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
vector&amp;lt;Vertex&amp;gt; getVisibleVertices(vertex v)&lt;br /&gt;
   vector&amp;lt;Vertex&amp;gt; answer, currentVertices&lt;br /&gt;
   currentVertices.add(all w in vertices : w.x &amp;gt;= v.x)   //рассматриваем только вершины правее v&lt;br /&gt;
   sort vertexes by angle                                //в порядке увеличения угла с &lt;br /&gt;
                                                         //  вертикальной прямой, проходящей через v&lt;br /&gt;
   heap&amp;lt;Segment&amp;gt; status&lt;br /&gt;
   status.add(all e in Edges : intersection(e, l) != null)  //инициализируем статус&lt;br /&gt;
   for w in currentVertices&lt;br /&gt;
      if intersection(vw, status.closest) == null        //если отрезок vw не пересекает ближайший &lt;br /&gt;
                                                         //  отрезок в статусе&lt;br /&gt;
         answer.add(w)                                   //  добавляем в ответ&lt;br /&gt;
      delete from status all edges ending in w           //обновляем статус&lt;br /&gt;
      add in status all edges beginning in w&lt;br /&gt;
   return answer&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Вершин у нас &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;, для каждой вершины мы выполяеем следующие шаги: сортировка (&amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;), проверка пересечения (&amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;), обновление статуса (суммарно выполняется за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, так как мы имеем &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; ребер и каждое ребро мы добавляем и удаляем один раз (вставка происходит за &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt;, удаление можно сделать за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;, например, для каждой вершины сохраняя позицию входящих в нее отрезков). Итого получаеем &amp;lt;tex&amp;gt; O(n) * O(n \log n) = O(n^2 \log n) &amp;lt;/tex&amp;gt;. Что и требовалось доказать.&lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zamrefr1.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr2.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr3.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Overmars and Welzl’s Algorithm &amp;lt;tex&amp;gt; O(n ^ 2) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
[http://igitur-archive.library.uu.nl/math/2006-1214-201604/overmars_88_new_methods.pdf visibility graph при помощи rotation tree]&lt;br /&gt;
&lt;br /&gt;
C помощью [http://bit.ly/1eEqTzk rotation tree] можно достичь асимптотики &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Motion planning ==&lt;br /&gt;
[[Файл:mink.png|200px|thumb|left|Раздуваем препятствия]]&lt;br /&gt;
[[Файл:mink2.png|400px|thumb|right|Ищем путь для точки]]&lt;br /&gt;
Тут мы двигаем не точку, а произвольный выпуклый полигон. Если мы его не можем вращать, просто считаем configuration space, т. е. &amp;quot;обводим&amp;quot; препятствия нашим полигоном (делаем [[Сумма Минковского (определение, вычисление)|сумму Минковского]] препятствий и полигона, сдвинутого в начало координат какой-нибудь точкой) и получаем другие препятствия, но зато теперь мы двигаем точку. А это мы уже научились делать выше.&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим случай, когда мы можем вращать полигон. Для начала построим [[Трапецоидная карта|трапецоидную карту]], как будто мы не можем вращать полигон. Теперь будем вращать полигон на малый угол, пока он не сделает полный оборот вокруг своей оси, и для каждого угла сделаем трапецоидную карту. Теперь разместим(мысленно) все карты друг над другом. Таким образом получится, что поворот на малый угол {{---}} это движение вверх/вниз между слоями. Осталось [[Пересечение многоугольников (PSLG overlaying)|попересекать]] соседние слои и добавить между ними ребра (помним что первый и последний слои одинаковы) и уже в этом графе найти путь.&lt;br /&gt;
&lt;br /&gt;
При такой реализации в некоторых случаях у нас может возникнуть ошибка в повороте, так как в одной плоскости мы все можем делать точно: положения на соседних слоях могут допускаться, а повернуть мы не сможем. Это лечится в основном двумя способами: измельчением угла поворота и изначальным сглаживанием углов полигона {{---}} повращать полигон на &amp;lt;tex&amp;gt; +\epsilon &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; -\epsilon &amp;lt;/tex&amp;gt; и объединить с исходным, получив новый полигон.&lt;br /&gt;
&lt;br /&gt;
Так как эта задача достаточно ресурсоемка, мы рассматриваем только наличие пути, а не нахождение кратчайшего.&lt;br /&gt;
&lt;br /&gt;
== Источники ==&lt;br /&gt;
* 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&lt;br /&gt;
* [http://www.academia.edu/2845047/3D_Visibility_Graph статья про visibility graphs]&lt;br /&gt;
* [http://habrahabr.ru/post/199256/ Хабр]&lt;br /&gt;
[[Категория: Вычислительная геометрия]]&lt;/div&gt;</summary>
		<author><name>Igorjan94</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44798</id>
		<title>Visibility graph и motion planning</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=44798"/>
				<updated>2015-02-05T16:02:28Z</updated>
		
		<summary type="html">&lt;p&gt;Igorjan94: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Visibility graph ==&lt;br /&gt;
{|align=&amp;quot;right&amp;quot;&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
|[[Файл:trap.png|200px|thumb|right|Путь с препятствиями через трапецоидную карту]]&lt;br /&gt;
|[[Файл:notShort.png|300px|thumb|right|Такой путь не самый короткий]]&lt;br /&gt;
|}&lt;br /&gt;
Рассмотрим задачу нахождения пути от точки &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt; с препятствиями. Для начала рассмотрим движение материальной точки, случай, когда размером и формой движимого объекта пренебречь нельзя, будет [[Visibility graph и motion planning#Motion planning|позднее]]. &lt;br /&gt;
&lt;br /&gt;
Обычно эта задача решается с помощью [[Трапецоидная карта | трапецоидной карты]], по которой строится граф, ребра которого соединяют центры трапедоидов и вершины &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt; с серединами вертикальных сторон трапецоидов. В этом графе любым алгоритмом поиска кратчайших путей (например, алгоритмом [[Алгоритм Дейкстры|Дейкстры]] или [[Алгоритм A*|A*]]) находится путь от &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм работает за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; и за линейное количество памяти и идеально подходит для нахождения какого-нибудь пути между конечными вершинами. Но иногда нужно найти кратчайший путь, и этот алгоритм не подходит, хоть и дает хорошее приближение.&lt;br /&gt;
&lt;br /&gt;
На сегодняшний день, точные решения в лучшем случае работают за &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; времени и памяти (здесь и далее &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество всех вершин).&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим точное решение с помощью построения графа видимости. После его построения, как и в случае с трапецоидной картой, путь ищется стандартными алгоритмами.&lt;br /&gt;
&lt;br /&gt;
Для простоты рассуждений вершины &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt; будем считать вершинами полигонов.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|about=О кратчайшем пути&lt;br /&gt;
|statement=&lt;br /&gt;
Любой кратчайший путь между двумя вершинами с полигональными препятствиями представляет собой ломаную, вершины которой {{---}} вершины полигонов.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:short.png|150px|thumb|right|Short cut]]&lt;br /&gt;
Пусть кратчайший путь {{---}} не ломаная. В таком случае, на пути существует такая точка &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, которая не принадлежит ни одному прямому отрезку. Это означает, что существует &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестность точки &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, в которую не попадает ни одно препятствие (случай, когда точка попала на ребро рассматривается аналогично). В таком случае, подпуть, который находится внутри &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности, по неравенству треугольника может быть сокращён по хорде, соединяющий точки пересечения границы &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности с путем. Раз часть пути может быть уменьшена, значит и весь путь может быть уменьшен, а значит исходное предположение некорректно.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
'''visibility graph''' {{---}} граф, вершины которого {{---}} вершины полигонов. Между вершинами &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; существует ребро, если из &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; &amp;lt;i&amp;gt; видна &amp;lt;/i&amp;gt;(mutually visible) &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
[[Файл:edgeToDelete.png|150px|thumb|right|Удаляем &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Если существуют вершины &amp;lt;tex&amp;gt; A, B, C &amp;lt;/tex&amp;gt; одного препятствия и вершина &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; такая, что поворот &amp;lt;tex&amp;gt; DBA &amp;lt;/tex&amp;gt; не совпадает с поворотом &amp;lt;tex&amp;gt; DBC &amp;lt;/tex&amp;gt;, то ребро &amp;lt;tex&amp;gt; DB &amp;lt;/tex&amp;gt; не принадлежит кратчайшему пути и его можно удалить из графа. (См. поясняющую картинку справа)&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:edgeNotToDelete.png|200px|thumb|right|Не удаляем &amp;lt;tex&amp;gt; BS &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Путь проходящий через ребро &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt; будет длиннее, чем через соседей точки &amp;lt;tex&amp;gt; B &amp;lt;/tex&amp;gt;, так как по неравенству треугольника &amp;lt;tex&amp;gt; AB + BD &amp;lt; AD &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
По доказанным леммам любое ребро кратчайшего пути содержится в графе, таким образом для нахождения кратчайшего пути осталось найти кратчайший путь в этом графе от &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Построение visibility графа ===&lt;br /&gt;
==== Наивный алгоритм. &amp;lt;tex&amp;gt; O(n ^ 3) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
Если делать наивно, т. е. для каждой пары вершин проверять можно ли добавить ли такое ребро(нет ли пересечений с полигонами), будет &amp;lt;tex&amp;gt; O(n^3) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Lee’s Algorithm. &amp;lt;tex&amp;gt; O(n ^ 2 \log n) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
{|&lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zam.png|300px|thumb|left|Заметание плоскости вращающимся лучом]]&lt;br /&gt;
Однако можно это сделать за &amp;lt;tex&amp;gt; O(n ^ 2 \log  n) &amp;lt;/tex&amp;gt;. Нам нужно решить следующую задачу: на плоскости дано множество отрезков (рёбер препятствий) и точка &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Найти все концы отрезков, видимые из точки &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Будем заметать плоскость вращающимся лучом с началом в точке &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Статусом заметающего луча будут отрезки, которые его пересекают, упорядоченные по возрастанию расстояния от точки &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; до точки пересечения. Точками событий будут концы отрезков. &lt;br /&gt;
&lt;br /&gt;
Итак, первым делом вершины &amp;lt;tex&amp;gt; w \in V &amp;lt;/tex&amp;gt; сортируются по углу между лучом &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; и вертикальной полуосью, проходящей через &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; {{---}} луч &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; (достаточно рассматривать только точки, которые лежат правее &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;, так как все точки левее мы уже рассмотрели). Затем инициализируем статус отрезками, которые пересекают луч &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt;. Далее начинается заметание плоскости. В порядке сортировки вершин для каждой из них выполняется проверка: видна ли вершина &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; из вершины &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Для этого нам достаточно проверить только пересечение заметающего луча с ближайшим отрезком в статусе. Если вершина видима, необходимо добавить её в список видимых вершин. И, наконец, вне зависимости от видимости вершины, необходимо изменить статус заметающего луча. Для этого для текущей вершины &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; необходимо удалить из статуса все рёбра (отрезки), которые заканчиваются в этой вершине (лежат слева от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;) и добавить все рёбра (отрезки), которые в ней начинаются (лежат справа от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Псевдокод =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
graph buildVisibilityGraph(Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
   Set&amp;lt;Vertex&amp;gt; vertices = getVertices(segments)       //получаем все вершины препятствий&lt;br /&gt;
   vertices.add(s, t)                                 //добавляем начальную и конечную вершину&lt;br /&gt;
   graph visibilityGraph(vertices)                    //изначально в графе только вершины&lt;br /&gt;
   for Vertex v in vertices                           //для каждой вершины&lt;br /&gt;
      for Vertex w in getVisibleVertices(v)           //  добавляем в граф все видимые из нее вершины&lt;br /&gt;
         visibilityGraph.addEdge(v, w)&lt;br /&gt;
   return visibilityGraph&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Здесь функция getVisibleVertices(&amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;) возвращет все видимые из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вершины и выглядит так:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
vector&amp;lt;Vertex&amp;gt; getVisibleVertices(vertex v)&lt;br /&gt;
   vector&amp;lt;Vertex&amp;gt; answer, currentVertices&lt;br /&gt;
   currentVertices.add(all w in vertices : w.x &amp;gt;= v.x)   //рассматриваем только вершины правее v&lt;br /&gt;
   sort vertexes by angle                                //в порядке увеличения угла с &lt;br /&gt;
                                                         //  вертикальной прямой, проходящей через v&lt;br /&gt;
   heap&amp;lt;Segment&amp;gt; status&lt;br /&gt;
   status.add(all e in Edges : intersection(e, l) != null)  //инициализируем статус&lt;br /&gt;
   for w in currentVertices&lt;br /&gt;
      if intersection(vw, status.closest) == null        //если отрезок vw не пересекает ближайший &lt;br /&gt;
                                                         //  отрезок в статусе&lt;br /&gt;
         answer.add(w)                                   //  добавляем в ответ&lt;br /&gt;
      delete from status all edges ending in w           //обновляем статус&lt;br /&gt;
      add in status all edges beginning in w&lt;br /&gt;
   return answer&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Вершин у нас &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;, для каждой вершины мы выполяеем следующие шаги: сортировка (&amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;), проверка пересечения (&amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;), обновление статуса (суммарно выполняется за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, так как мы имеем &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; ребер и каждое ребро мы добавляем и удаляем один раз (вставка происходит за &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt;, удаление можно сделать за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;, например, для каждой вершины сохраняя позицию входящих в нее отрезков). Итого получаеем &amp;lt;tex&amp;gt; O(n) * O(n \log n) = O(n^2 \log n) &amp;lt;/tex&amp;gt;. Что и требовалось доказать.&lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zamrefr1.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr2.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr3.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Overmars and Welzl’s Algorithm &amp;lt;tex&amp;gt; O(n ^ 2) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
[http://igitur-archive.library.uu.nl/math/2006-1214-201604/overmars_88_new_methods.pdf visibility graph при помощи rotation tree]&lt;br /&gt;
&lt;br /&gt;
C помощью [http://bit.ly/1eEqTzk rotation tree] можно достичь асимптотики &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Motion planning ==&lt;br /&gt;
[[Файл:mink.png|200px|thumb|left|Раздуваем препятствия]]&lt;br /&gt;
[[Файл:mink2.png|400px|thumb|right|Ищем путь для точки]]&lt;br /&gt;
Тут мы двигаем не точку, а произвольный выпуклый полигон. Если мы его не можем вращать, просто считаем configuration space, т. е. &amp;quot;обводим&amp;quot; препятствия нашим полигоном (делаем [[Сумма Минковского (определение, вычисление)|сумму Минковского]] препятствий и полигона, сдвинутого в начало координат какой-нибудь точкой) и получаем другие препятствия, но зато теперь мы двигаем точку. А это мы уже научились делать выше.&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим случай, когда мы можем вращать полигон. Для начала построим [[Трапецоидная карта|трапецоидную карту]], как будто мы не можем вращать полигон. Теперь будем вращать полигон на малый угол, пока он не сделает полный оборот вокруг своей оси, и для каждого угла сделаем трапецоидную карту. Теперь разместим(мысленно) все карты друг над другом. Таким образом получится, что поворот на малый угол {{---}} это движение вверх/вниз между слоями. Осталось [[Пересечение многоугольников (PSLG overlaying)|попересекать]] соседние слои и добавить между ними ребра (помним что первый и последний слои одинаковы) и уже в этом графе найти путь.&lt;br /&gt;
&lt;br /&gt;
При такой реализации в некоторых случаях у нас может возникнуть ошибка в повороте, так как в одной плоскости мы все можем делать точно: положения на соседних слоях могут допускаться, а повернуть мы не сможем. Это лечится в основном двумя способами: измельчением угла поворота и изначальным сглаживанием углов полигона {{---}} повращать полигон на &amp;lt;tex&amp;gt; +\epsilon &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; -\epsilon &amp;lt;/tex&amp;gt; и объединить с исходным, получив новый полигон.&lt;br /&gt;
&lt;br /&gt;
Так как эта задача достаточно ресурсоемка, мы рассматриваем только наличие пути, а не нахождение кратчайшего.&lt;br /&gt;
&lt;br /&gt;
== Источники ==&lt;br /&gt;
* 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&lt;br /&gt;
* [http://www.academia.edu/2845047/3D_Visibility_Graph статья про visibility graphs]&lt;br /&gt;
* [http://habrahabr.ru/post/199256/ Хабр]&lt;br /&gt;
[[Категория: Вычислительная геометрия]]&lt;/div&gt;</summary>
		<author><name>Igorjan94</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%9F%D0%B5%D1%80%D0%B5%D1%81%D0%B5%D1%87%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BF%D0%BE%D0%BB%D1%83%D0%BF%D0%BB%D0%BE%D1%81%D0%BA%D0%BE%D1%81%D1%82%D0%B5%D0%B9,_%D1%81%D0%B2%D1%8F%D0%B7%D1%8C_%D1%81_%D0%B2%D1%8B%D0%BF%D1%83%D0%BA%D0%BB%D1%8B%D0%BC%D0%B8_%D0%BE%D0%B1%D0%BE%D0%BB%D0%BE%D1%87%D0%BA%D0%B0%D0%BC%D0%B8&amp;diff=36699</id>
		<title>Пересечение полуплоскостей, связь с выпуклыми оболочками</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%9F%D0%B5%D1%80%D0%B5%D1%81%D0%B5%D1%87%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BF%D0%BE%D0%BB%D1%83%D0%BF%D0%BB%D0%BE%D1%81%D0%BA%D0%BE%D1%81%D1%82%D0%B5%D0%B9,_%D1%81%D0%B2%D1%8F%D0%B7%D1%8C_%D1%81_%D0%B2%D1%8B%D0%BF%D1%83%D0%BA%D0%BB%D1%8B%D0%BC%D0%B8_%D0%BE%D0%B1%D0%BE%D0%BB%D0%BE%D1%87%D0%BA%D0%B0%D0%BC%D0%B8&amp;diff=36699"/>
				<updated>2014-05-06T07:51:45Z</updated>
		
		<summary type="html">&lt;p&gt;Igorjan94: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Файл:samplesHalfspaces.png|400px|thumb|right|Пересечение существует и выпукло, неограничено или пусто]]&lt;br /&gt;
[[Файл:halfSpaces.png|400px|thumb|right|Нужна ли нам полуплоскость &amp;lt;tex&amp;gt; l'' &amp;lt;/tex&amp;gt;?]]&lt;br /&gt;
&lt;br /&gt;
Задача: есть конечное множество полуплоскотей, найти фигуру их пересечения или сообщить что оно пусто.&lt;br /&gt;
&lt;br /&gt;
Для начала заметим, что если пересечение не пусто, то оно выпукло. (Доказательство {{---}} Пересечение выпуклых фигур выпукло, а полуплоскость выпукла)&lt;br /&gt;
&lt;br /&gt;
Пусть у нас прямые заданы уравнениями вида &amp;lt;tex&amp;gt; Ax + By + C = 0 &amp;lt;/tex&amp;gt;. Тогда предикат(см. рисунок) проверки того, что прямая &amp;lt;tex&amp;gt; l'' : A''x + B''y + C'' = 0 &amp;lt;/tex&amp;gt; лежит над пересечением прямых &amp;lt;tex&amp;gt; l : Ax + By + C = 0 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; l' : A'x + B'y + C' = 0 &amp;lt;/tex&amp;gt; будет равен &amp;lt;tex&amp;gt;&lt;br /&gt;
\begin{vmatrix} &lt;br /&gt;
A &amp;amp; B &amp;amp; C \\ &lt;br /&gt;
A' &amp;amp; B' &amp;amp; C' \\ &lt;br /&gt;
A'' &amp;amp; B'' &amp;amp; C'' &lt;br /&gt;
\end{vmatrix}&lt;br /&gt;
&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Докажем это. Для проверки предиката нам надо определить знак выражения &amp;lt;tex&amp;gt; A''x_0 + B''y_0 + C'' &amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; (x_0, y_0) &amp;lt;/tex&amp;gt; {{---}} точка пересечения прямых &amp;lt;tex&amp;gt; l' &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt;. Эту точку можно найти из уравнения &amp;lt;tex&amp;gt; \begin{pmatrix} &lt;br /&gt;
A &amp;amp; B\\ &lt;br /&gt;
A' &amp;amp; B' &lt;br /&gt;
\end{pmatrix}&lt;br /&gt;
\begin{pmatrix} &lt;br /&gt;
x_0\\ &lt;br /&gt;
y_0 &lt;br /&gt;
\end{pmatrix} =&lt;br /&gt;
\begin{pmatrix} &lt;br /&gt;
-C\\ &lt;br /&gt;
-C' &lt;br /&gt;
\end{pmatrix}&lt;br /&gt;
&amp;lt;/tex&amp;gt;. Решением будет &amp;lt;tex&amp;gt;&lt;br /&gt;
\begin{pmatrix} &lt;br /&gt;
x_0\\ &lt;br /&gt;
y_0 &lt;br /&gt;
\end{pmatrix} =&lt;br /&gt;
\frac{&lt;br /&gt;
\begin{pmatrix} &lt;br /&gt;
B' &amp;amp; -B\\ &lt;br /&gt;
-A' &amp;amp; A &lt;br /&gt;
\end{pmatrix}&lt;br /&gt;
\begin{pmatrix} &lt;br /&gt;
-C\\ &lt;br /&gt;
-C' &lt;br /&gt;
\end{pmatrix}}&lt;br /&gt;
{ &lt;br /&gt;
\begin{vmatrix} &lt;br /&gt;
A &amp;amp; B\\ &lt;br /&gt;
A' &amp;amp; B'&lt;br /&gt;
\end{vmatrix}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/tex&amp;gt;. Подставим его в &amp;lt;tex&amp;gt; A''x_0 + B''y_0 + C'' &amp;lt;/tex&amp;gt; и домножим на определитель.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt; A'' (B'; -B)(-C; -C') + B'' (-A'; A)(-C; -C') + C \begin{vmatrix} A &amp;amp; B \\ A' &amp;amp; B' \end{vmatrix} = A'' \begin{vmatrix} B' &amp;amp; B \\ -C' &amp;amp; -C \end{vmatrix} - B'' \begin{vmatrix} A' &amp;amp; A \\ -C' &amp;amp; -C \end{vmatrix} + C'' \begin{vmatrix} A &amp;amp; A' \\ B &amp;amp; B' \end{vmatrix} = \begin{vmatrix} A'' &amp;amp; A' &amp;amp; A \\ B'' &amp;amp; B' &amp;amp; B \\ -C'' &amp;amp; -C' &amp;amp; -C \end{vmatrix} = \begin{vmatrix} A &amp;amp; B &amp;amp; C \\ &lt;br /&gt;
A' &amp;amp; B' &amp;amp; C' \\ &lt;br /&gt;
A'' &amp;amp; B'' &amp;amp; C'' \end{vmatrix} &amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом если представить прямую &amp;lt;tex&amp;gt; Ax + By + C = 0 &amp;lt;/tex&amp;gt; как точку с координатами &amp;lt;tex&amp;gt; (A, B, C) &amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; C &amp;lt;/tex&amp;gt; {{---}} однородная координата, то этот предикат {{---}} всего лишь поворот, а проверка предиката {{---}} проверка очередной точки в [[Статические выпуклые оболочки: Джарвис, Грэхем, Эндрю, Чен, QuickHull#Алгоритм Грэхема|обходе Грэхема]] для нахождения выпуклой оболочки.&lt;br /&gt;
&lt;br /&gt;
Алгоритм:&lt;br /&gt;
* Отсортировать все полуплоскости по углу наклона;&lt;br /&gt;
* Запустить обход Грэхема для полуплоскостей, смотрящих вниз (с предикатом-определителем);&lt;br /&gt;
* То же самое для смотрящих вверх;&lt;br /&gt;
* Пересечь две цепочки.&lt;br /&gt;
&lt;br /&gt;
От пересечения цепочек напрямую зависит фигура пересечения: неограниченная область получается если одна из цепочек пуста, а ограниченная {{---}} когда обе цепочки не пусты и пересекаются.&lt;br /&gt;
&lt;br /&gt;
== Источники ==&lt;br /&gt;
* 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 11 page 253-254&lt;br /&gt;
* http://wwwisg.cs.uni-magdeburg.de/ag/lehre/SS2012/GAG/slides/V12.pdf&lt;br /&gt;
&lt;br /&gt;
[[Категория: Вычислительная геометрия]]&lt;/div&gt;</summary>
		<author><name>Igorjan94</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=36641</id>
		<title>Visibility graph и motion planning</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=36641"/>
				<updated>2014-05-04T18:39:35Z</updated>
		
		<summary type="html">&lt;p&gt;Igorjan94: /* Lee’s Algorithm.  O(n ^ 2 \log n)  */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Visibility graph ==&lt;br /&gt;
{|align=&amp;quot;right&amp;quot;&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
|[[Файл:trap.png|200px|thumb|right|Путь с препятствиями через трапецоидную карту]]&lt;br /&gt;
|[[Файл:notShort.png|300px|thumb|right|Такой путь не самый короткий]]&lt;br /&gt;
|}&lt;br /&gt;
Рассмотрим задачу нахождения кратчайшего пути от точки &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt; с препятствиями. Для начала рассмотрим движение материальной точки, случай произвольного полигона будет [[Visibility graph и motion planning#Motion planning|позднее]]. &lt;br /&gt;
&lt;br /&gt;
Для нахождения пути можно построить [[Трапецоидная карта | трапецоидную карту]], соединить ребрами середины вертикальных сторон трапецоидов с их центрами и в этом графе любым алгоритмом поиска кратчайших путей (например, алгоритмом [[Алгоритм Дейкстры|Дейкстры]] или [[Алгоритм A*|A*]]) найти путь от &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt;. Однако, этот путь не будет абсолютно кратчайшим. &lt;br /&gt;
&lt;br /&gt;
Этот алгоритм поиска пути через трапецоидную карту обширно используется, так как дает хорошее приближение, работает за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; и занимает линейное количество памяти, в то время как точные решения в лучшем случае работают за &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; времени и памяти (здесь и далее &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество всех вершин).&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим точное решение с помощью построения графа видимости. Для этого нам потребуется лемма:&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|about=О кратчайшем пути&lt;br /&gt;
|statement=&lt;br /&gt;
Любой кратчайший путь от &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt; с полигональными препятствиями представляет собой ломаную, вершины которой {{---}} вершины полигонов.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:short.png|150px|thumb|right|Short cut]]&lt;br /&gt;
Пусть кратчайший путь {{---}} не ломаная. В таком случае, на пути существует такая точка &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, которая не принадлежит ни одному прямому отрезку. Это означает, что существует &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестность точки &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, в которую не попадает ни одно препятствие (случай, когда точка попала на ребро рассматривается аналогично). В таком случае, подпуть, который находится внутри &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности, по неравенству треугольника может быть сокращён по хорде, соединяющий точки пересечения границы &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности с путем. Раз часть пути может быть уменьшена, значит и весь путь может быть уменьшен, а значит исходное предположение некорректно.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
'''visibility graph''' {{---}} граф, вершины которого {{---}} вершины полигонов, а также &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt;. Между вершинами &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; существует ребро, если из &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; &amp;lt;i&amp;gt; видна &amp;lt;/i&amp;gt;(mutually visible) &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
[[Файл:edgeToDelete.png|150px|thumb|right|Удаляем &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Если существуют вершины &amp;lt;tex&amp;gt; A, B, C &amp;lt;/tex&amp;gt; одного препятствия и вершина &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; такая, что поворот &amp;lt;tex&amp;gt; DBA &amp;lt;/tex&amp;gt; не совпадает с поворотом &amp;lt;tex&amp;gt; DBC &amp;lt;/tex&amp;gt;, то ребро &amp;lt;tex&amp;gt; DB &amp;lt;/tex&amp;gt; не принадлежит кратчайшему пути и его можно удалить из графа. (См. поясняющую картинку справа)&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:edgeNotToDelete.png|200px|thumb|right|Не удаляем &amp;lt;tex&amp;gt; BS &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Путь проходящий через ребро &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt; будет длиннее, чем через соседей точки &amp;lt;tex&amp;gt; B &amp;lt;/tex&amp;gt;, так как по неравенству треугольника &amp;lt;tex&amp;gt; AB + BD &amp;lt; AD &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
По доказанным леммам любое ребро кратчайшего пути содержится в графе, таким образом для нахождения кратчайшего пути осталось найти кратчайший путь в этом графе от &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Построение visibility графа ===&lt;br /&gt;
==== Наивный алгоритм. &amp;lt;tex&amp;gt; O(n ^ 3) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
Если делать наивно, т. е. для каждой пары вершин проверять можно ли добавить ли такое ребро(нет ли пересечений с полигонами), будет &amp;lt;tex&amp;gt; O(n^3) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Lee’s Algorithm. &amp;lt;tex&amp;gt; O(n ^ 2 \log n) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
{|&lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zam.png|300px|thumb|left|Заметание плоскости вращающимся лучом]]&lt;br /&gt;
Однако можно это сделать за &amp;lt;tex&amp;gt; O(n ^ 2 \log  n) &amp;lt;/tex&amp;gt;. Нам нужно решить следующую задачу: на плоскости дано множество отрезков (рёбер препятствий) и точка &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Найти все концы отрезков, видимые из точки &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Будем заметать плоскость вращающимся лучом с началом в точке &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Статусом заметающего луча будут отрезки, которые его пересекают, упорядоченные по возрастанию расстояния от точки &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; до точки пересечения. Точками событий будут концы отрезков. &lt;br /&gt;
&lt;br /&gt;
Итак, первым делом вершины &amp;lt;tex&amp;gt; w \in V &amp;lt;/tex&amp;gt; сортируются по углу между лучом &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; и вертикальной полуосью, проходящей через &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; {{---}} луч &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; (достаточно рассматривать только точки, которые лежат правее &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;, так как все точки левее мы уже рассмотрели). Затем инициализируем статус отрезками, которые пересекают луч &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt;. Далее начинается заметание плоскости. В порядке сортировки вершин для каждой из них выполняется проверка: видна ли вершина &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; из вершины &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Для этого нам достаточно проверить только пересечение заметающего луча с ближайшим отрезком в статусе. Если вершина видима, необходимо добавить её в список видимых вершин. И, наконец, вне зависимости от видимости вершины, необходимо изменить статус заметающего луча. Для этого для текущей вершины &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; необходимо удалить из статуса все рёбра (отрезки), которые заканчиваются в этой вершине (лежат слева от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;) и добавить все рёбра (отрезки), которые в ней начинаются (лежат справа от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Псевдокод =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
graph buildVisibilityGraph(Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
   Set&amp;lt;Vertex&amp;gt; vertices = getVertices(segments)       //получаем все вершины препятствий&lt;br /&gt;
   vertices.add(s, t)                                 //добавляем начальную и конечную вершину&lt;br /&gt;
   graph visibilityGraph(vertices)                    //изначально в графе только вершины&lt;br /&gt;
   for Vertex v in vertices                           //для каждой вершины&lt;br /&gt;
      for Vertex w in getVisibleVertices(v)           //  добавляем в граф все видимые из нее вершины&lt;br /&gt;
         visibilityGraph.addEdge(v, w)&lt;br /&gt;
   return visibilityGraph&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Здесь функция getVisibleVertices(&amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;) возвращет все видимые из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вершины и выглядит так:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
vector&amp;lt;Vertex&amp;gt; getVisibleVertices(vertex v)&lt;br /&gt;
   vector&amp;lt;Vertex&amp;gt; answer, currentVertices&lt;br /&gt;
   currentVertices.add(all w in vertices : w.x &amp;gt;= v.x)   //рассматриваем только вершины правее v&lt;br /&gt;
   sort vertexes by angle                                //в порядке увеличения угла с &lt;br /&gt;
                                                         //  вертикальной прямой, проходящей через v&lt;br /&gt;
   heap&amp;lt;Segment&amp;gt; status&lt;br /&gt;
   status.add(all e in Edges : intersection(e, l) != null)  //инициализируем статус&lt;br /&gt;
   for w in currentVertices&lt;br /&gt;
      if intersection(vw, status.closest) == null        //если отрезок vw не пересекает ближайший &lt;br /&gt;
                                                         //  отрезок в статусе&lt;br /&gt;
         answer.add(w)                                   //  добавляем в ответ&lt;br /&gt;
      delete from status all edges ending in w           //обновляем статус&lt;br /&gt;
      add in status all edges beginning in w&lt;br /&gt;
   return answer&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Вершин у нас &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;, для каждой вершины мы выполяеем следующие шаги: сортировка (&amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;), проверка пересечения (&amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;), обновление статуса (суммарно выполняется за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, так как мы имеем &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; ребер и каждое ребро мы добавляем и удаляем один раз (вставка происходит за &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt;, удаление можно сделать за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;, например, для каждой вершины сохраняя позицию входящих в нее отрезков). Итого получаеем &amp;lt;tex&amp;gt; O(n) * O(n \log n) = O(n^2 \log n) &amp;lt;/tex&amp;gt;. Что и требовалось доказать.&lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zamrefr1.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr2.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr3.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Overmars and Welzl’s Algorithm &amp;lt;tex&amp;gt; O(n ^ 2) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
[http://igitur-archive.library.uu.nl/math/2006-1214-201604/overmars_88_new_methods.pdf visibility graph при помощи rotation tree]&lt;br /&gt;
&lt;br /&gt;
C помощью [http://bit.ly/1eEqTzk rotation tree] можно достичь асимптотики &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Motion planning ==&lt;br /&gt;
[[Файл:mink.png|200px|thumb|left|Раздуваем препятствия]]&lt;br /&gt;
[[Файл:mink2.png|400px|thumb|right|Ищем путь для точки]]&lt;br /&gt;
Тут мы двигаем не точку, а произвольный выпуклый полигон. Если мы его не можем вращать, просто считаем configuration space, т. е. &amp;quot;обводим&amp;quot; препятствия нашим полигоном (делаем [[Сумма Минковского (определение, вычисление)|сумму Минковского]] препятствий и полигона, сдвинутого в начало координат какой-нибудь точкой) и получаем другие препятствия, но зато теперь мы двигаем точку. А это мы уже научились делать выше.&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим случай, когда мы можем вращать полигон. Для начала построим [[Трапецоидная карта|трапецоидную карту]], как будто мы не можем вращать полигон. Теперь будем вращать полигон на малый угол, пока он не сделает полный оборот вокруг своей оси, и для каждого угла сделаем трапецоидную карту. Теперь разместим(мысленно) все карты друг над другом. Таким образом получится, что поворот на малый угол {{---}} это движение вверх/вниз между слоями. Осталось [[Пересечение многоугольников (PSLG overlaying)|попересекать]] соседние слои и добавить между ними ребра (помним что первый и последний слои одинаковы) и уже в этом графе найти путь.&lt;br /&gt;
&lt;br /&gt;
При такой реализации в некоторых случаях у нас может возникнуть ошибка в повороте, так как в одной плоскости мы все можем делать точно: положения на соседних слоях могут допускаться, а повернуть мы не сможем. Это лечится в основном двумя способами: измельчением угла поворота и изначальным сглаживанием углов полигона {{---}} повращать полигон на &amp;lt;tex&amp;gt; +\epsilon &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; -\epsilon &amp;lt;/tex&amp;gt; и объединить с исходным, получив новый полигон.&lt;br /&gt;
&lt;br /&gt;
Так как эта задача достаточно ресурсоемка, мы рассматриваем только наличие пути, а не нахождение кратчайшего.&lt;br /&gt;
&lt;br /&gt;
== Источники ==&lt;br /&gt;
* 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&lt;br /&gt;
* [http://www.academia.edu/2845047/3D_Visibility_Graph статья про visibility graphs]&lt;br /&gt;
* [http://habrahabr.ru/post/199256/ Хабр]&lt;br /&gt;
[[Категория: Вычислительная геометрия]]&lt;/div&gt;</summary>
		<author><name>Igorjan94</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=36639</id>
		<title>Visibility graph и motion planning</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=36639"/>
				<updated>2014-05-04T18:37:48Z</updated>
		
		<summary type="html">&lt;p&gt;Igorjan94: /* Псевдокод */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Visibility graph ==&lt;br /&gt;
{|align=&amp;quot;right&amp;quot;&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
|[[Файл:trap.png|200px|thumb|right|Путь с препятствиями через трапецоидную карту]]&lt;br /&gt;
|[[Файл:notShort.png|300px|thumb|right|Такой путь не самый короткий]]&lt;br /&gt;
|}&lt;br /&gt;
Рассмотрим задачу нахождения кратчайшего пути от точки &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt; с препятствиями. Для начала рассмотрим движение материальной точки, случай произвольного полигона будет [[Visibility graph и motion planning#Motion planning|позднее]]. &lt;br /&gt;
&lt;br /&gt;
Для нахождения пути можно построить [[Трапецоидная карта | трапецоидную карту]], соединить ребрами середины вертикальных сторон трапецоидов с их центрами и в этом графе любым алгоритмом поиска кратчайших путей (например, алгоритмом [[Алгоритм Дейкстры|Дейкстры]] или [[Алгоритм A*|A*]]) найти путь от &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt;. Однако, этот путь не будет абсолютно кратчайшим. &lt;br /&gt;
&lt;br /&gt;
Этот алгоритм поиска пути через трапецоидную карту обширно используется, так как дает хорошее приближение, работает за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; и занимает линейное количество памяти, в то время как точные решения в лучшем случае работают за &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; времени и памяти (здесь и далее &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество всех вершин).&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим точное решение с помощью построения графа видимости. Для этого нам потребуется лемма:&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|about=О кратчайшем пути&lt;br /&gt;
|statement=&lt;br /&gt;
Любой кратчайший путь от &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt; с полигональными препятствиями представляет собой ломаную, вершины которой {{---}} вершины полигонов.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:short.png|150px|thumb|right|Short cut]]&lt;br /&gt;
Пусть кратчайший путь {{---}} не ломаная. В таком случае, на пути существует такая точка &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, которая не принадлежит ни одному прямому отрезку. Это означает, что существует &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестность точки &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, в которую не попадает ни одно препятствие (случай, когда точка попала на ребро рассматривается аналогично). В таком случае, подпуть, который находится внутри &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности, по неравенству треугольника может быть сокращён по хорде, соединяющий точки пересечения границы &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности с путем. Раз часть пути может быть уменьшена, значит и весь путь может быть уменьшен, а значит исходное предположение некорректно.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
'''visibility graph''' {{---}} граф, вершины которого {{---}} вершины полигонов, а также &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt;. Между вершинами &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; существует ребро, если из &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; &amp;lt;i&amp;gt; видна &amp;lt;/i&amp;gt;(mutually visible) &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
[[Файл:edgeToDelete.png|150px|thumb|right|Удаляем &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Если существуют вершины &amp;lt;tex&amp;gt; A, B, C &amp;lt;/tex&amp;gt; одного препятствия и вершина &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; такая, что поворот &amp;lt;tex&amp;gt; DBA &amp;lt;/tex&amp;gt; не совпадает с поворотом &amp;lt;tex&amp;gt; DBC &amp;lt;/tex&amp;gt;, то ребро &amp;lt;tex&amp;gt; DB &amp;lt;/tex&amp;gt; не принадлежит кратчайшему пути и его можно удалить из графа. (См. поясняющую картинку справа)&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:edgeNotToDelete.png|200px|thumb|right|Не удаляем &amp;lt;tex&amp;gt; BS &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Путь проходящий через ребро &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt; будет длиннее, чем через соседей точки &amp;lt;tex&amp;gt; B &amp;lt;/tex&amp;gt;, так как по неравенству треугольника &amp;lt;tex&amp;gt; AB + BD &amp;lt; AD &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
По доказанным леммам любое ребро кратчайшего пути содержится в графе, таким образом для нахождения кратчайшего пути осталось найти кратчайший путь в этом графе от &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Построение visibility графа ===&lt;br /&gt;
==== Наивный алгоритм. &amp;lt;tex&amp;gt; O(n ^ 3) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
Если делать наивно, т. е. для каждой пары вершин проверять можно ли добавить ли такое ребро(нет ли пересечений с полигонами), будет &amp;lt;tex&amp;gt; O(n^3) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Lee’s Algorithm. &amp;lt;tex&amp;gt; O(n ^ 2 \log n) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
{|&lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zam.png|300px|thumb|left|Заметание плоскости вращающимся лучом]]&lt;br /&gt;
Однако можно это сделать за &amp;lt;tex&amp;gt; O(n ^ 2 \log  n) &amp;lt;/tex&amp;gt;. Нам нужно решить следующую задачу: на плоскости дано множество отрезков (рёбер препятствий) и точка &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Найти все концы отрезков, видимые из точки &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Будем заметать плоскость вращающимся лучом с началом в точке &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Статусом заметающего луча будут отрезки, которые его пересекают, упорядоченные по возрастанию расстояния от точки &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; до точки пересечения. Точками событий будут концы отрезков. &lt;br /&gt;
&lt;br /&gt;
Итак, первым делом вершины &amp;lt;tex&amp;gt; w \in V &amp;lt;/tex&amp;gt; сортируются по углу между лучом &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; и вертикальной полуосью, проходящей через &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; {{---}} луч &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; (достаточно рассматривать только точки, которые лежат правее &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;, так как все точки левее мы уже рассмотрели). Затем инициализируем статус отрезками, которые пересекают луч &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt;. Далее начинается заметание плоскости. В порядке сортировки вершин для каждой из них выполняется проверка: видна ли вершина &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; из вершины &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Для этого нам достаточно проверить только пересечение заметающего луча с ближайшим отрезком в статусе. Если вершина видима, необходимо добавить её в список видимых вершин. И, наконец, вне зависимости от видимости вершины, необходимо изменить статус заметающего луча. Для этого для текущей вершины &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; необходимо удалить из статуса все рёбра (отрезки), которые заканчиваются в этой вершине (лежат слева от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;) и добавить все рёбра (отрезки), которые в ней начинаются (лежат справа от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Псевдокод =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
graph buildVisibilityGraph(Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
   Set&amp;lt;Vertex&amp;gt; vertices = getVertices(segments)             //получаем все вершины препятствий&lt;br /&gt;
   vertices.add(s, t)                                       //добавляем начальную и конечную вершину&lt;br /&gt;
   graph visibilityGraph(vertices)                          //изначально в графе только вершины&lt;br /&gt;
   for Vertex v in vertices                                 //для каждой вершины&lt;br /&gt;
      for Vertex w in getVisibleVertices(v)                 //  добавляем в граф все видимые из нее вершины&lt;br /&gt;
         visibilityGraph.addEdge(v, w)&lt;br /&gt;
   return visibilityGraph&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Здесь функция getVisibleVertices(&amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;) возвращет все видимые из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вершины и выглядит так:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
vector&amp;lt;Vertex&amp;gt; getVisibleVertices(vertex v)&lt;br /&gt;
   vector&amp;lt;Vertex&amp;gt; answer, currentVertices&lt;br /&gt;
   currentVertices.add(all w in vertices : w.x &amp;gt;= v.x)      //рассматриваем только вершины правее v&lt;br /&gt;
   sort vertexes by angle                                   //в порядке увеличения угла с &lt;br /&gt;
                                                            //  вертикальной прямой, проходящей через v&lt;br /&gt;
   heap&amp;lt;Segment&amp;gt; status&lt;br /&gt;
   status.add(all e in Edges : intersection(e, l) != null)  //инициализируем статус&lt;br /&gt;
   for w in currentVertices&lt;br /&gt;
      if intersection(vw, status.closest) == null           //если отрезок vw не пересекает ближайший &lt;br /&gt;
                                                            //  отрезок в статусе&lt;br /&gt;
         answer.add(w)                                      //  добавляем в ответ&lt;br /&gt;
      delete from status all edges ending in w              //обновляем статус&lt;br /&gt;
      add in status all edges beginning in w&lt;br /&gt;
   return answer&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Вершин у нас &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;, для каждой вершины мы выполяеем следующие шаги: сортировка (&amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;), проверка пересечения (&amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;), обновление статуса (суммарно выполняется за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, так как мы имеем &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; ребер и каждое ребро мы добавляем и удаляем один раз (вставка происходит за &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt;, удаление можно сделать за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;, например, для каждой вершины сохраняя позицию входящих в нее отрезков). Итого получаеем &amp;lt;tex&amp;gt; O(n) * O(n \log n) = O(n^2 \log n) &amp;lt;/tex&amp;gt;. Что и требовалось доказать.&lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zamrefr1.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr2.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr3.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Overmars and Welzl’s Algorithm &amp;lt;tex&amp;gt; O(n ^ 2) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
[http://igitur-archive.library.uu.nl/math/2006-1214-201604/overmars_88_new_methods.pdf visibility graph при помощи rotation tree]&lt;br /&gt;
&lt;br /&gt;
C помощью [http://bit.ly/1eEqTzk rotation tree] можно достичь асимптотики &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Motion planning ==&lt;br /&gt;
[[Файл:mink.png|200px|thumb|left|Раздуваем препятствия]]&lt;br /&gt;
[[Файл:mink2.png|400px|thumb|right|Ищем путь для точки]]&lt;br /&gt;
Тут мы двигаем не точку, а произвольный выпуклый полигон. Если мы его не можем вращать, просто считаем configuration space, т. е. &amp;quot;обводим&amp;quot; препятствия нашим полигоном (делаем [[Сумма Минковского (определение, вычисление)|сумму Минковского]] препятствий и полигона, сдвинутого в начало координат какой-нибудь точкой) и получаем другие препятствия, но зато теперь мы двигаем точку. А это мы уже научились делать выше.&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим случай, когда мы можем вращать полигон. Для начала построим [[Трапецоидная карта|трапецоидную карту]], как будто мы не можем вращать полигон. Теперь будем вращать полигон на малый угол, пока он не сделает полный оборот вокруг своей оси, и для каждого угла сделаем трапецоидную карту. Теперь разместим(мысленно) все карты друг над другом. Таким образом получится, что поворот на малый угол {{---}} это движение вверх/вниз между слоями. Осталось [[Пересечение многоугольников (PSLG overlaying)|попересекать]] соседние слои и добавить между ними ребра (помним что первый и последний слои одинаковы) и уже в этом графе найти путь.&lt;br /&gt;
&lt;br /&gt;
При такой реализации в некоторых случаях у нас может возникнуть ошибка в повороте, так как в одной плоскости мы все можем делать точно: положения на соседних слоях могут допускаться, а повернуть мы не сможем. Это лечится в основном двумя способами: измельчением угла поворота и изначальным сглаживанием углов полигона {{---}} повращать полигон на &amp;lt;tex&amp;gt; +\epsilon &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; -\epsilon &amp;lt;/tex&amp;gt; и объединить с исходным, получив новый полигон.&lt;br /&gt;
&lt;br /&gt;
Так как эта задача достаточно ресурсоемка, мы рассматриваем только наличие пути, а не нахождение кратчайшего.&lt;br /&gt;
&lt;br /&gt;
== Источники ==&lt;br /&gt;
* 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&lt;br /&gt;
* [http://www.academia.edu/2845047/3D_Visibility_Graph статья про visibility graphs]&lt;br /&gt;
* [http://habrahabr.ru/post/199256/ Хабр]&lt;br /&gt;
[[Категория: Вычислительная геометрия]]&lt;/div&gt;</summary>
		<author><name>Igorjan94</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=36637</id>
		<title>Visibility graph и motion planning</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=36637"/>
				<updated>2014-05-04T18:36:56Z</updated>
		
		<summary type="html">&lt;p&gt;Igorjan94: /* Lee’s Algorithm.  O(n ^ 2 \log n)  */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Visibility graph ==&lt;br /&gt;
{|align=&amp;quot;right&amp;quot;&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
|[[Файл:trap.png|200px|thumb|right|Путь с препятствиями через трапецоидную карту]]&lt;br /&gt;
|[[Файл:notShort.png|300px|thumb|right|Такой путь не самый короткий]]&lt;br /&gt;
|}&lt;br /&gt;
Рассмотрим задачу нахождения кратчайшего пути от точки &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt; с препятствиями. Для начала рассмотрим движение материальной точки, случай произвольного полигона будет [[Visibility graph и motion planning#Motion planning|позднее]]. &lt;br /&gt;
&lt;br /&gt;
Для нахождения пути можно построить [[Трапецоидная карта | трапецоидную карту]], соединить ребрами середины вертикальных сторон трапецоидов с их центрами и в этом графе любым алгоритмом поиска кратчайших путей (например, алгоритмом [[Алгоритм Дейкстры|Дейкстры]] или [[Алгоритм A*|A*]]) найти путь от &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt;. Однако, этот путь не будет абсолютно кратчайшим. &lt;br /&gt;
&lt;br /&gt;
Этот алгоритм поиска пути через трапецоидную карту обширно используется, так как дает хорошее приближение, работает за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; и занимает линейное количество памяти, в то время как точные решения в лучшем случае работают за &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; времени и памяти (здесь и далее &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество всех вершин).&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим точное решение с помощью построения графа видимости. Для этого нам потребуется лемма:&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|about=О кратчайшем пути&lt;br /&gt;
|statement=&lt;br /&gt;
Любой кратчайший путь от &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt; с полигональными препятствиями представляет собой ломаную, вершины которой {{---}} вершины полигонов.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:short.png|150px|thumb|right|Short cut]]&lt;br /&gt;
Пусть кратчайший путь {{---}} не ломаная. В таком случае, на пути существует такая точка &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, которая не принадлежит ни одному прямому отрезку. Это означает, что существует &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестность точки &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, в которую не попадает ни одно препятствие (случай, когда точка попала на ребро рассматривается аналогично). В таком случае, подпуть, который находится внутри &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности, по неравенству треугольника может быть сокращён по хорде, соединяющий точки пересечения границы &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности с путем. Раз часть пути может быть уменьшена, значит и весь путь может быть уменьшен, а значит исходное предположение некорректно.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
'''visibility graph''' {{---}} граф, вершины которого {{---}} вершины полигонов, а также &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt;. Между вершинами &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; существует ребро, если из &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; &amp;lt;i&amp;gt; видна &amp;lt;/i&amp;gt;(mutually visible) &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
[[Файл:edgeToDelete.png|150px|thumb|right|Удаляем &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Если существуют вершины &amp;lt;tex&amp;gt; A, B, C &amp;lt;/tex&amp;gt; одного препятствия и вершина &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; такая, что поворот &amp;lt;tex&amp;gt; DBA &amp;lt;/tex&amp;gt; не совпадает с поворотом &amp;lt;tex&amp;gt; DBC &amp;lt;/tex&amp;gt;, то ребро &amp;lt;tex&amp;gt; DB &amp;lt;/tex&amp;gt; не принадлежит кратчайшему пути и его можно удалить из графа. (См. поясняющую картинку справа)&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:edgeNotToDelete.png|200px|thumb|right|Не удаляем &amp;lt;tex&amp;gt; BS &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Путь проходящий через ребро &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt; будет длиннее, чем через соседей точки &amp;lt;tex&amp;gt; B &amp;lt;/tex&amp;gt;, так как по неравенству треугольника &amp;lt;tex&amp;gt; AB + BD &amp;lt; AD &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
По доказанным леммам любое ребро кратчайшего пути содержится в графе, таким образом для нахождения кратчайшего пути осталось найти кратчайший путь в этом графе от &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Построение visibility графа ===&lt;br /&gt;
==== Наивный алгоритм. &amp;lt;tex&amp;gt; O(n ^ 3) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
Если делать наивно, т. е. для каждой пары вершин проверять можно ли добавить ли такое ребро(нет ли пересечений с полигонами), будет &amp;lt;tex&amp;gt; O(n^3) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Lee’s Algorithm. &amp;lt;tex&amp;gt; O(n ^ 2 \log n) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
{|&lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zam.png|300px|thumb|left|Заметание плоскости вращающимся лучом]]&lt;br /&gt;
Однако можно это сделать за &amp;lt;tex&amp;gt; O(n ^ 2 \log  n) &amp;lt;/tex&amp;gt;. Нам нужно решить следующую задачу: на плоскости дано множество отрезков (рёбер препятствий) и точка &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Найти все концы отрезков, видимые из точки &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Будем заметать плоскость вращающимся лучом с началом в точке &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Статусом заметающего луча будут отрезки, которые его пересекают, упорядоченные по возрастанию расстояния от точки &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; до точки пересечения. Точками событий будут концы отрезков. &lt;br /&gt;
&lt;br /&gt;
Итак, первым делом вершины &amp;lt;tex&amp;gt; w \in V &amp;lt;/tex&amp;gt; сортируются по углу между лучом &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; и вертикальной полуосью, проходящей через &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; {{---}} луч &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; (достаточно рассматривать только точки, которые лежат правее &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;, так как все точки левее мы уже рассмотрели). Затем инициализируем статус отрезками, которые пересекают луч &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt;. Далее начинается заметание плоскости. В порядке сортировки вершин для каждой из них выполняется проверка: видна ли вершина &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; из вершины &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Для этого нам достаточно проверить только пересечение заметающего луча с ближайшим отрезком в статусе. Если вершина видима, необходимо добавить её в список видимых вершин. И, наконец, вне зависимости от видимости вершины, необходимо изменить статус заметающего луча. Для этого для текущей вершины &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; необходимо удалить из статуса все рёбра (отрезки), которые заканчиваются в этой вершине (лежат слева от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;) и добавить все рёбра (отрезки), которые в ней начинаются (лежат справа от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Псевдокод =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
graph buildVisibilityGraph(Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
   Set&amp;lt;Vertex&amp;gt; vertices = getVertices(segments)             //получаем все вершины препятствий&lt;br /&gt;
   vertices.add(s, t)                                      //добавляем начальную и конечную вершину&lt;br /&gt;
   graph visibilityGraph(vertices)                          //изначально в графе только вершины&lt;br /&gt;
   for Vertex v in vertices                                //для каждой вершины&lt;br /&gt;
      for Vertex w in getVisibleVertices(v)                 //  добавляем в граф все видимые из нее вершины&lt;br /&gt;
         visibilityGraph.addEdge(v, w)&lt;br /&gt;
   return visibilityGraph&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Здесь функция getVisibleVertices(&amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;) возвращет все видимые из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вершины и выглядит так:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
vector&amp;lt;Vertex&amp;gt; getVisibleVertices(vertex v)&lt;br /&gt;
   vector&amp;lt;Vertex&amp;gt; answer, currentVertices&lt;br /&gt;
   currentVertices.add(all w in vertices : w.x &amp;gt;= v.x)      //рассматриваем только вершины правее v&lt;br /&gt;
   sort vertexes by angle                                   //в порядке увеличения угла с &lt;br /&gt;
                                                            //  вертикальной прямой, проходящей через v&lt;br /&gt;
   heap&amp;lt;Segment&amp;gt; status&lt;br /&gt;
   status.add(all e in Edges : intersection(e, l) != null)  //инициализируем статус&lt;br /&gt;
   for w in currentVertices&lt;br /&gt;
      if intersection(vw, status.closest) == null           //если отрезок vw не пересекает ближайший &lt;br /&gt;
                                                            //  отрезок в статусе&lt;br /&gt;
         answer.add(w)                                      //  добавляем в ответ&lt;br /&gt;
      delete from status all edges ending in w              //обновляем статус&lt;br /&gt;
      add in status all edges beginning in w&lt;br /&gt;
   return answer&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Вершин у нас &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;, для каждой вершины мы выполяеем следующие шаги: сортировка (&amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;), проверка пересечения (&amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;), обновление статуса (суммарно выполняется за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, так как мы имеем &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; ребер и каждое ребро мы добавляем и удаляем один раз (вставка происходит за &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt;, удаление можно сделать за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;, например, для каждой вершины сохраняя позицию входящих в нее отрезков). Итого получаеем &amp;lt;tex&amp;gt; O(n) * O(n \log n) = O(n^2 \log n) &amp;lt;/tex&amp;gt;. Что и требовалось доказать.&lt;br /&gt;
|&lt;br /&gt;
[[Файл:Zamrefr1.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr2.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr3.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Overmars and Welzl’s Algorithm &amp;lt;tex&amp;gt; O(n ^ 2) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
[http://igitur-archive.library.uu.nl/math/2006-1214-201604/overmars_88_new_methods.pdf visibility graph при помощи rotation tree]&lt;br /&gt;
&lt;br /&gt;
C помощью [http://bit.ly/1eEqTzk rotation tree] можно достичь асимптотики &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Motion planning ==&lt;br /&gt;
[[Файл:mink.png|200px|thumb|left|Раздуваем препятствия]]&lt;br /&gt;
[[Файл:mink2.png|400px|thumb|right|Ищем путь для точки]]&lt;br /&gt;
Тут мы двигаем не точку, а произвольный выпуклый полигон. Если мы его не можем вращать, просто считаем configuration space, т. е. &amp;quot;обводим&amp;quot; препятствия нашим полигоном (делаем [[Сумма Минковского (определение, вычисление)|сумму Минковского]] препятствий и полигона, сдвинутого в начало координат какой-нибудь точкой) и получаем другие препятствия, но зато теперь мы двигаем точку. А это мы уже научились делать выше.&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим случай, когда мы можем вращать полигон. Для начала построим [[Трапецоидная карта|трапецоидную карту]], как будто мы не можем вращать полигон. Теперь будем вращать полигон на малый угол, пока он не сделает полный оборот вокруг своей оси, и для каждого угла сделаем трапецоидную карту. Теперь разместим(мысленно) все карты друг над другом. Таким образом получится, что поворот на малый угол {{---}} это движение вверх/вниз между слоями. Осталось [[Пересечение многоугольников (PSLG overlaying)|попересекать]] соседние слои и добавить между ними ребра (помним что первый и последний слои одинаковы) и уже в этом графе найти путь.&lt;br /&gt;
&lt;br /&gt;
При такой реализации в некоторых случаях у нас может возникнуть ошибка в повороте, так как в одной плоскости мы все можем делать точно: положения на соседних слоях могут допускаться, а повернуть мы не сможем. Это лечится в основном двумя способами: измельчением угла поворота и изначальным сглаживанием углов полигона {{---}} повращать полигон на &amp;lt;tex&amp;gt; +\epsilon &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; -\epsilon &amp;lt;/tex&amp;gt; и объединить с исходным, получив новый полигон.&lt;br /&gt;
&lt;br /&gt;
Так как эта задача достаточно ресурсоемка, мы рассматриваем только наличие пути, а не нахождение кратчайшего.&lt;br /&gt;
&lt;br /&gt;
== Источники ==&lt;br /&gt;
* 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&lt;br /&gt;
* [http://www.academia.edu/2845047/3D_Visibility_Graph статья про visibility graphs]&lt;br /&gt;
* [http://habrahabr.ru/post/199256/ Хабр]&lt;br /&gt;
[[Категория: Вычислительная геометрия]]&lt;/div&gt;</summary>
		<author><name>Igorjan94</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=36632</id>
		<title>Visibility graph и motion planning</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=36632"/>
				<updated>2014-05-04T18:17:46Z</updated>
		
		<summary type="html">&lt;p&gt;Igorjan94: /* Lee’s Algorithm.  O(n ^ 2 \log n)  */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Visibility graph ==&lt;br /&gt;
{|align=&amp;quot;right&amp;quot;&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
|[[Файл:trap.png|200px|thumb|right|Путь с препятствиями через трапецоидную карту]]&lt;br /&gt;
|[[Файл:notShort.png|300px|thumb|right|Такой путь не самый короткий]]&lt;br /&gt;
|}&lt;br /&gt;
Рассмотрим задачу нахождения кратчайшего пути от точки &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt; с препятствиями. Для начала рассмотрим движение материальной точки, случай произвольного полигона будет [[Visibility graph и motion planning#Motion planning|позднее]]. &lt;br /&gt;
&lt;br /&gt;
Для нахождения пути можно построить [[Трапецоидная карта | трапецоидную карту]], соединить ребрами середины вертикальных сторон трапецоидов с их центрами и в этом графе любым алгоритмом поиска кратчайших путей (например, алгоритмом [[Алгоритм Дейкстры|Дейкстры]] или [[Алгоритм A*|A*]]) найти путь от &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt;. Однако, этот путь не будет абсолютно кратчайшим. &lt;br /&gt;
&lt;br /&gt;
Этот алгоритм поиска пути через трапецоидную карту обширно используется, так как дает хорошее приближение, работает за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; и занимает линейное количество памяти, в то время как точные решения в лучшем случае работают за &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; времени и памяти (здесь и далее &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество всех вершин).&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим точное решение с помощью построения графа видимости. Для этого нам потребуется лемма:&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|about=О кратчайшем пути&lt;br /&gt;
|statement=&lt;br /&gt;
Любой кратчайший путь от &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt; с полигональными препятствиями представляет собой ломаную, вершины которой {{---}} вершины полигонов.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:short.png|150px|thumb|right|Short cut]]&lt;br /&gt;
Пусть кратчайший путь {{---}} не ломаная. В таком случае, на пути существует такая точка &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, которая не принадлежит ни одному прямому отрезку. Это означает, что существует &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестность точки &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, в которую не попадает ни одно препятствие (случай, когда точка попала на ребро рассматривается аналогично). В таком случае, подпуть, который находится внутри &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности, по неравенству треугольника может быть сокращён по хорде, соединяющий точки пересечения границы &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности с путем. Раз часть пути может быть уменьшена, значит и весь путь может быть уменьшен, а значит исходное предположение некорректно.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
'''visibility graph''' {{---}} граф, вершины которого {{---}} вершины полигонов, а также &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt;. Между вершинами &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; существует ребро, если из &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; &amp;lt;i&amp;gt; видна &amp;lt;/i&amp;gt;(mutually visible) &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
[[Файл:edgeToDelete.png|150px|thumb|right|Удаляем &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Если существуют вершины &amp;lt;tex&amp;gt; A, B, C &amp;lt;/tex&amp;gt; одного препятствия и вершина &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; такая, что поворот &amp;lt;tex&amp;gt; DBA &amp;lt;/tex&amp;gt; не совпадает с поворотом &amp;lt;tex&amp;gt; DBC &amp;lt;/tex&amp;gt;, то ребро &amp;lt;tex&amp;gt; DB &amp;lt;/tex&amp;gt; не принадлежит кратчайшему пути и его можно удалить из графа. (См. поясняющую картинку справа)&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:edgeNotToDelete.png|200px|thumb|right|Не удаляем &amp;lt;tex&amp;gt; BS &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Путь проходящий через ребро &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt; будет длиннее, чем через соседей точки &amp;lt;tex&amp;gt; B &amp;lt;/tex&amp;gt;, так как по неравенству треугольника &amp;lt;tex&amp;gt; AB + BD &amp;lt; AD &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
По доказанным леммам любое ребро кратчайшего пути содержится в графе, таким образом для нахождения кратчайшего пути осталось найти кратчайший путь в этом графе от &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Построение visibility графа ===&lt;br /&gt;
==== Наивный алгоритм. &amp;lt;tex&amp;gt; O(n ^ 3) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
Если делать наивно, т. е. для каждой пары вершин проверять можно ли добавить ли такое ребро(нет ли пересечений с полигонами), будет &amp;lt;tex&amp;gt; O(n^3) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Lee’s Algorithm. &amp;lt;tex&amp;gt; O(n ^ 2 \log n) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
[[Файл:Zam.png|300px|thumb|left|Заметание плоскости вращающимся лучом]]&lt;br /&gt;
[[Файл:Zamrefr1.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr2.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr3.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
Однако можно это сделать за &amp;lt;tex&amp;gt; O(n ^ 2 \log  n) &amp;lt;/tex&amp;gt;. Нам нужно решить следующую задачу: на плоскости дано множество отрезков (рёбер препятствий) и точка &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Найти все концы отрезков, видимые из точки &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Будем заметать плоскость вращающимся лучом с началом в точке &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Статусом заметающего луча будут отрезки, которые его пересекают, упорядоченные по возрастанию расстояния от точки &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; до точки пересечения. Точками событий будут концы отрезков. &lt;br /&gt;
&lt;br /&gt;
Итак, первым делом вершины &amp;lt;tex&amp;gt; w \in V &amp;lt;/tex&amp;gt; сортируются по углу между лучом &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; и вертикальной полуосью, проходящей через &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; {{---}} луч &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; (достаточно рассматривать только точки, которые лежат правее &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;, так как все точки левее мы уже рассмотрели). Затем инициализируем статус отрезками, которые пересекают луч &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt;. Далее начинается заметание плоскости. В порядке сортировки вершин для каждой из них выполняется проверка: видна ли вершина &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; из вершины &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Для этого нам достаточно проверить только пересечение заметающего луча с ближайшим отрезком в статусе. Если вершина видима, необходимо добавить её в список видимых вершин. И, наконец, вне зависимости от видимости вершины, необходимо изменить статус заметающего луча. Для этого для текущей вершины &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; необходимо удалить из статуса все рёбра (отрезки), которые заканчиваются в этой вершине (лежат слева от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;) и добавить все рёбра (отрезки), которые в ней начинаются (лежат справа от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Псевдокод =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
graph buildVisibilityGraph(Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
   Set&amp;lt;Vertex&amp;gt; vertices = getVertices(segments)             //получаем все вершины препятствий&lt;br /&gt;
   vertices.add(s, t)                                      //добавляем начальную и конечную вершину&lt;br /&gt;
   graph visibilityGraph(vertices)                          //изначально в графе только вершины&lt;br /&gt;
   for Vertex v in vertices                                //для каждой вершины&lt;br /&gt;
      for Vertex w in getVisibleVertices(v)                 //  добавляем в граф все видимые из нее вершины&lt;br /&gt;
         visibilityGraph.addEdge(v, w)&lt;br /&gt;
   return visibilityGraph&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Здесь функция getVisibleVertices(&amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;) возвращет все видимые из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вершины и выглядит так:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
vector&amp;lt;Vertex&amp;gt; getVisibleVertices(vertex v)&lt;br /&gt;
   vector&amp;lt;Vertex&amp;gt; answer, currentVertices&lt;br /&gt;
   currentVertices.add(all w in vertices : w.x &amp;gt;= v.x)      //рассматриваем только вершины правее v&lt;br /&gt;
   sort vertexes by angle                                   //в порядке увеличения угла с &lt;br /&gt;
                                                            //  вертикальной прямой, проходящей через v&lt;br /&gt;
   heap&amp;lt;Segment&amp;gt; status&lt;br /&gt;
   status.add(all e in Edges : intersection(e, l) != null)  //инициализируем статус&lt;br /&gt;
   for w in currentVertices&lt;br /&gt;
      if intersection(vw, status.closest) == null           //если отрезок vw не пересекает ближайший &lt;br /&gt;
                                                            //  отрезок в статусе&lt;br /&gt;
         answer.add(w)                                      //  добавляем в ответ&lt;br /&gt;
      delete from status all edges ending in w              //обновляем статус&lt;br /&gt;
      add in status all edges beginning in w&lt;br /&gt;
   return answer&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Вершин у нас &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;, для каждой вершины мы выполяеем следующие шаги: сортировка (&amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;), проверка пересечения (&amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;), обновление статуса (суммарно выполняется за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, так как мы имеем &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; ребер и каждое ребро мы добавляем и удаляем один раз (вставка происходит за &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt;, удаление можно сделать за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;, например, для каждой вершины сохраняя позицию входящих в нее отрезков)). Итого получаеем &amp;lt;tex&amp;gt; O(n) * O(n \log n) = O(n^2 \log n) &amp;lt;/tex&amp;gt;. Что и требовалось доказать.&lt;br /&gt;
&lt;br /&gt;
==== Overmars and Welzl’s Algorithm &amp;lt;tex&amp;gt; O(n ^ 2) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
[http://igitur-archive.library.uu.nl/math/2006-1214-201604/overmars_88_new_methods.pdf visibility graph при помощи rotation tree]&lt;br /&gt;
&lt;br /&gt;
C помощью [http://bit.ly/1eEqTzk rotation tree] можно достичь асимптотики &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Motion planning ==&lt;br /&gt;
[[Файл:mink.png|200px|thumb|left|Раздуваем препятствия]]&lt;br /&gt;
[[Файл:mink2.png|400px|thumb|right|Ищем путь для точки]]&lt;br /&gt;
Тут мы двигаем не точку, а произвольный выпуклый полигон. Если мы его не можем вращать, просто считаем configuration space, т. е. &amp;quot;обводим&amp;quot; препятствия нашим полигоном (делаем [[Сумма Минковского (определение, вычисление)|сумму Минковского]] препятствий и полигона, сдвинутого в начало координат какой-нибудь точкой) и получаем другие препятствия, но зато теперь мы двигаем точку. А это мы уже научились делать выше.&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим случай, когда мы можем вращать полигон. Для начала построим [[Трапецоидная карта|трапецоидную карту]], как будто мы не можем вращать полигон. Теперь будем вращать полигон на малый угол, пока он не сделает полный оборот вокруг своей оси, и для каждого угла сделаем трапецоидную карту. Теперь разместим(мысленно) все карты друг над другом. Таким образом получится, что поворот на малый угол {{---}} это движение вверх/вниз между слоями. Осталось [[Пересечение многоугольников (PSLG overlaying)|попересекать]] соседние слои и добавить между ними ребра (помним что первый и последний слои одинаковы) и уже в этом графе найти путь.&lt;br /&gt;
&lt;br /&gt;
При такой реализации в некоторых случаях у нас может возникнуть ошибка в повороте, так как в одной плоскости мы все можем делать точно: положения на соседних слоях могут допускаться, а повернуть мы не сможем. Это лечится в основном двумя способами: измельчением угла поворота и изначальным сглаживанием углов полигона {{---}} повращать полигон на &amp;lt;tex&amp;gt; +\epsilon &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; -\epsilon &amp;lt;/tex&amp;gt; и объединить с исходным, получив новый полигон.&lt;br /&gt;
&lt;br /&gt;
Так как эта задача достаточно ресурсоемка, мы рассматриваем только наличие пути, а не нахождение кратчайшего.&lt;br /&gt;
&lt;br /&gt;
== Источники ==&lt;br /&gt;
* 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&lt;br /&gt;
* [http://www.academia.edu/2845047/3D_Visibility_Graph статья про visibility graphs]&lt;br /&gt;
* [http://habrahabr.ru/post/199256/ Хабр]&lt;br /&gt;
[[Категория: Вычислительная геометрия]]&lt;/div&gt;</summary>
		<author><name>Igorjan94</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=36628</id>
		<title>Visibility graph и motion planning</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=36628"/>
				<updated>2014-05-04T18:07:52Z</updated>
		
		<summary type="html">&lt;p&gt;Igorjan94: /* Lee’s Algorithm.  O(n ^ 2 \log n)  */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Visibility graph ==&lt;br /&gt;
{|align=&amp;quot;right&amp;quot;&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
|[[Файл:trap.png|200px|thumb|right|Путь с препятствиями через трапецоидную карту]]&lt;br /&gt;
|[[Файл:notShort.png|300px|thumb|right|Такой путь не самый короткий]]&lt;br /&gt;
|}&lt;br /&gt;
Рассмотрим задачу нахождения кратчайшего пути от точки &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt; с препятствиями. Для начала рассмотрим движение материальной точки, случай произвольного полигона будет [[Visibility graph и motion planning#Motion planning|позднее]]. &lt;br /&gt;
&lt;br /&gt;
Для нахождения пути можно построить [[Трапецоидная карта | трапецоидную карту]], соединить ребрами середины вертикальных сторон трапецоидов с их центрами и в этом графе любым алгоритмом поиска кратчайших путей (например, алгоритмом [[Алгоритм Дейкстры|Дейкстры]] или [[Алгоритм A*|A*]]) найти путь от &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt;. Однако, этот путь не будет абсолютно кратчайшим. &lt;br /&gt;
&lt;br /&gt;
Этот алгоритм поиска пути через трапецоидную карту обширно используется, так как дает хорошее приближение, работает за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; и занимает линейное количество памяти, в то время как точные решения в лучшем случае работают за &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; времени и памяти (здесь и далее &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество всех вершин).&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим точное решение с помощью построения графа видимости. Для этого нам потребуется лемма:&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|about=О кратчайшем пути&lt;br /&gt;
|statement=&lt;br /&gt;
Любой кратчайший путь от &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt; с полигональными препятствиями представляет собой ломаную, вершины которой {{---}} вершины полигонов.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:short.png|150px|thumb|right|Short cut]]&lt;br /&gt;
Пусть кратчайший путь {{---}} не ломаная. В таком случае, на пути существует такая точка &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, которая не принадлежит ни одному прямому отрезку. Это означает, что существует &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестность точки &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, в которую не попадает ни одно препятствие (случай, когда точка попала на ребро рассматривается аналогично). В таком случае, подпуть, который находится внутри &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности, по неравенству треугольника может быть сокращён по хорде, соединяющий точки пересечения границы &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности с путем. Раз часть пути может быть уменьшена, значит и весь путь может быть уменьшен, а значит исходное предположение некорректно.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
'''visibility graph''' {{---}} граф, вершины которого {{---}} вершины полигонов, а также &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt;. Между вершинами &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; существует ребро, если из &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; &amp;lt;i&amp;gt; видна &amp;lt;/i&amp;gt;(mutually visible) &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
[[Файл:edgeToDelete.png|150px|thumb|right|Удаляем &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Если существуют вершины &amp;lt;tex&amp;gt; A, B, C &amp;lt;/tex&amp;gt; одного препятствия и вершина &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; такая, что поворот &amp;lt;tex&amp;gt; DBA &amp;lt;/tex&amp;gt; не совпадает с поворотом &amp;lt;tex&amp;gt; DBC &amp;lt;/tex&amp;gt;, то ребро &amp;lt;tex&amp;gt; DB &amp;lt;/tex&amp;gt; не принадлежит кратчайшему пути и его можно удалить из графа. (См. поясняющую картинку справа)&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:edgeNotToDelete.png|200px|thumb|right|Не удаляем &amp;lt;tex&amp;gt; BS &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Путь проходящий через ребро &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt; будет длиннее, чем через соседей точки &amp;lt;tex&amp;gt; B &amp;lt;/tex&amp;gt;, так как по неравенству треугольника &amp;lt;tex&amp;gt; AB + BD &amp;lt; AD &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
По доказанным леммам любое ребро кратчайшего пути содержится в графе, таким образом для нахождения кратчайшего пути осталось найти кратчайший путь в этом графе от &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Построение visibility графа ===&lt;br /&gt;
==== Наивный алгоритм. &amp;lt;tex&amp;gt; O(n ^ 3) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
Если делать наивно, т. е. для каждой пары вершин проверять можно ли добавить ли такое ребро(нет ли пересечений с полигонами), будет &amp;lt;tex&amp;gt; O(n^3) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Lee’s Algorithm. &amp;lt;tex&amp;gt; O(n ^ 2 \log n) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
[[Файл:Zam.png|300px|thumb|left|Заметание плоскости вращающимся лучом]]&lt;br /&gt;
[[Файл:Zamrefr1.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr2.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr3.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
Однако можно это сделать за &amp;lt;tex&amp;gt; O(n ^ 2 \log  n) &amp;lt;/tex&amp;gt;. Для каждой вершины найдём все видимые из неё вершины при помощи метода плоского заметания. Нам нужно решить следующую задачу: на плоскости дано множество отрезков (рёбер препятствий) и точка &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Найти все концы отрезков, видимые из точки &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. &lt;br /&gt;
Будем заметать плоскость вращающимся лучом с началом в точке &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Статусом заметающего луча будут отрезки, которые его пересекают, упорядоченные по возрастанию расстояния от точки &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; до точки пересечения. Точками событий будут концы отрезков. &lt;br /&gt;
Итак, первым делом вершины &amp;lt;tex&amp;gt; w \in V &amp;lt;/tex&amp;gt; сортируются по углу между лучом &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; и вертикальной полуосью, проходящей через &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; {{---}} луч &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; (достаточно рассматривать только точки, которые лежат правее &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;, так как все точки левее мы уже рассмотрели). Инициализируем статус отрезками, которые пересекают луч &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt;. Далее начинается заметание плоскости. В порядке сортировки вершин для каждой из них выполняется проверка: видна ли вершина &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; из вершины &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Для этого нам достаточно проверить только пересечение заметающего луча с ближайшим отрезком в статусе. Если вершина видима, необходимо добавить её в список видимых вершин. И, наконец, вне зависимости от видимости вершины, необходимо изменить статус заметающего луча. Для этого для текущей вершины &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; необходимо удалить из списка текущих пересечений все рёбра (отрезки), которые заканчиваются в этой вершине (лежат слева от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;) и добавить все рёбра (отрезки), которые в ней начинаются (лежат справа от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Псевдокод =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
graph buildVisibilityGraph(Set&amp;lt;Segment&amp;gt; segments)&lt;br /&gt;
   Set&amp;lt;Vertex&amp;gt; vertices = getVertices(segments)               //получаем все вершины препятствий&lt;br /&gt;
   vertices.add(s, t)                                         //добавляем начальную и конечную вершину&lt;br /&gt;
   graph visibilityGraph(vertices)                            //изначально в графе только вершины&lt;br /&gt;
   for Vertex v in vertices                                   //для каждой вершины&lt;br /&gt;
      for Vertex w in getVisibleVertices(v)                   //  добавляем в граф все видимые из нее&lt;br /&gt;
         visibilityGraph.addEdge(v, w)&lt;br /&gt;
   return visibilityGraph&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Здесь функция getVisibleVertices(&amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;) возвращет все видимые из &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; вершины и выглядит так:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
vector&amp;lt;Vertex&amp;gt; getVisibleVertices(vertex v)&lt;br /&gt;
   vector&amp;lt;Vertex&amp;gt; answer, currentVertices&lt;br /&gt;
   currentVertices.add(all w in vertices : w.x &amp;gt;= v.x)        //рассматриваем только вершины правее v&lt;br /&gt;
   sort vertexes by angle                                     //в порядке увеличения угла с вертикальной прямой, проходящей через v&lt;br /&gt;
   heap&amp;lt;Segment&amp;gt; status&lt;br /&gt;
   status.add(all e in Edges : intersection(e, l) != null)    //инициализируем статус&lt;br /&gt;
   for w in currentVertices&lt;br /&gt;
      if intersection(vw, status.closest) == null             //если отрезок vw не пересекает ближайший отрезок в статусе&lt;br /&gt;
         answer.add(w)                                        //  добавляем в ответ&lt;br /&gt;
      delete from status all edges ending in w                //обновляем статус&lt;br /&gt;
      add in status all edges beginning in w&lt;br /&gt;
   return answer&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Вершин у нас &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;, для каждой вершины мы выполяеем следующие шаги: сортировка (&amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;), проверка пересечения (&amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;), обновление статуса, которое суммарно выполняется за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, так как мы имеем &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; ребер и каждое ребро мы добавляем и удаляем один раз (вставка происходит за &amp;lt;tex&amp;gt; O(\log n) &amp;lt;/tex&amp;gt;, удаление можно сделать за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;, например, для каждой вершины сохраняя позицию входящих в нее отрезков). &lt;br /&gt;
Итого &amp;lt;tex&amp;gt; O(n) * O(n \log n) = O(n^2 \log n) &amp;lt;/tex&amp;gt;. Что и требовалось доказать.&lt;br /&gt;
&lt;br /&gt;
==== Overmars and Welzl’s Algorithm &amp;lt;tex&amp;gt; O(n ^ 2) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
[http://igitur-archive.library.uu.nl/math/2006-1214-201604/overmars_88_new_methods.pdf visibility graph при помощи rotation tree]&lt;br /&gt;
&lt;br /&gt;
C помощью [http://bit.ly/1eEqTzk rotation tree] можно достичь асимптотики &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Motion planning ==&lt;br /&gt;
[[Файл:mink.png|200px|thumb|left|Раздуваем препятствия]]&lt;br /&gt;
[[Файл:mink2.png|400px|thumb|right|Ищем путь для точки]]&lt;br /&gt;
Тут мы двигаем не точку, а произвольный выпуклый полигон. Если мы его не можем вращать, просто считаем configuration space, т. е. &amp;quot;обводим&amp;quot; препятствия нашим полигоном (делаем [[Сумма Минковского (определение, вычисление)|сумму Минковского]] препятствий и полигона, сдвинутого в начало координат какой-нибудь точкой) и получаем другие препятствия, но зато теперь мы двигаем точку. А это мы уже научились делать выше.&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим случай, когда мы можем вращать полигон. Для начала построим [[Трапецоидная карта|трапецоидную карту]], как будто мы не можем вращать полигон. Теперь будем вращать полигон на малый угол, пока он не сделает полный оборот вокруг своей оси, и для каждого угла сделаем трапецоидную карту. Теперь разместим(мысленно) все карты друг над другом. Таким образом получится, что поворот на малый угол {{---}} это движение вверх/вниз между слоями. Осталось [[Пересечение многоугольников (PSLG overlaying)|попересекать]] соседние слои и добавить между ними ребра (помним что первый и последний слои одинаковы) и уже в этом графе найти путь.&lt;br /&gt;
&lt;br /&gt;
При такой реализации в некоторых случаях у нас может возникнуть ошибка в повороте, так как в одной плоскости мы все можем делать точно: положения на соседних слоях могут допускаться, а повернуть мы не сможем. Это лечится в основном двумя способами: измельчением угла поворота и изначальным сглаживанием углов полигона {{---}} повращать полигон на &amp;lt;tex&amp;gt; +\epsilon &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; -\epsilon &amp;lt;/tex&amp;gt; и объединить с исходным, получив новый полигон.&lt;br /&gt;
&lt;br /&gt;
Так как эта задача достаточно ресурсоемка, мы рассматриваем только наличие пути, а не нахождение кратчайшего.&lt;br /&gt;
&lt;br /&gt;
== Источники ==&lt;br /&gt;
* 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&lt;br /&gt;
* [http://www.academia.edu/2845047/3D_Visibility_Graph статья про visibility graphs]&lt;br /&gt;
* [http://habrahabr.ru/post/199256/ Хабр]&lt;br /&gt;
[[Категория: Вычислительная геометрия]]&lt;/div&gt;</summary>
		<author><name>Igorjan94</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=36504</id>
		<title>Visibility graph и motion planning</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=Visibility_graph_%D0%B8_motion_planning&amp;diff=36504"/>
				<updated>2014-04-29T21:38:13Z</updated>
		
		<summary type="html">&lt;p&gt;Igorjan94: /* Lee’s Algorithm.  O(n ^ 2 \log n)  */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Visibility graph ==&lt;br /&gt;
{|align=&amp;quot;right&amp;quot;&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
|[[Файл:trap.png|200px|thumb|right|Путь с препятствиями через трапецоидную карту]]&lt;br /&gt;
|[[Файл:notShort.png|300px|thumb|right|Такой путь не самый короткий]]&lt;br /&gt;
|}&lt;br /&gt;
Рассмотрим задачу нахождения кратчайшего пути от точки &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt; с препятствиями. Для начала рассмотрим движение материальной точки, случай произвольного полигона будет [[Visibility graph и motion planning#Motion planning|позднее]]. &lt;br /&gt;
&lt;br /&gt;
Для нахождения пути можно построить [[Трапецоидная карта | трапецоидную карту]], соединить ребрами середины вертикальных сторон трапецоидов с их центрами и в этом графе любым алгоритмом поиска кратчайших путей (например, алгоритмом [[Алгоритм Дейкстры|Дейкстры]] или [[Алгоритм A*|A*]]) найти путь от &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt;. Однако, этот путь не будет абсолютно кратчайшим. &lt;br /&gt;
&lt;br /&gt;
Этот алгоритм поиска пути через трапецоидную карту обширно используется, так как дает хорошее приближение, работает за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; и занимает линейное количество памяти, в то время как точные решения в лучшем случае работают за &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; времени и памяти (здесь и далее &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество всех вершин).&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим точное решение с помощью построения графа видимости. Для этого нам потребуется лемма:&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|about=О кратчайшем пути&lt;br /&gt;
|statement=&lt;br /&gt;
Любой кратчайший путь от &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt; с полигональными препятствиями представляет собой ломаную, вершины которой {{---}} вершины полигонов.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:short.png|150px|thumb|right|Short cut]]&lt;br /&gt;
Пусть кратчайший путь {{---}} не ломаная. В таком случае, на пути существует такая точка &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, которая не принадлежит ни одному прямому отрезку. Это означает, что существует &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестность точки &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt;, в которую не попадает ни одно препятствие (случай, когда точка попала на ребро рассматривается аналогично). В таком случае, подпуть, который находится внутри &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности, по неравенству треугольника может быть сокращён по хорде, соединяющий точки пересечения границы &amp;lt;tex&amp;gt;\epsilon&amp;lt;/tex&amp;gt;-окрестности с путем. Раз часть пути может быть уменьшена, значит и весь путь может быть уменьшен, а значит исходное предположение некорректно.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
'''visibility graph''' {{---}} граф, вершины которого {{---}} вершины полигонов, а также &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt;. Между вершинами &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; существует ребро, если из &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; &amp;lt;i&amp;gt; видна &amp;lt;/i&amp;gt;(mutually visible) &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
[[Файл:edgeToDelete.png|150px|thumb|right|Удаляем &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Если существуют вершины &amp;lt;tex&amp;gt; A, B, C &amp;lt;/tex&amp;gt; одного препятствия и вершина &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; такая, что поворот &amp;lt;tex&amp;gt; DBA &amp;lt;/tex&amp;gt; не совпадает с поворотом &amp;lt;tex&amp;gt; DBC &amp;lt;/tex&amp;gt;, то ребро &amp;lt;tex&amp;gt; DB &amp;lt;/tex&amp;gt; не принадлежит кратчайшему пути и его можно удалить из графа. (См. поясняющую картинку справа)&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:edgeNotToDelete.png|200px|thumb|right|Не удаляем &amp;lt;tex&amp;gt; BS &amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Путь проходящий через ребро &amp;lt;tex&amp;gt; BD &amp;lt;/tex&amp;gt; будет длиннее, чем через соседей точки &amp;lt;tex&amp;gt; B &amp;lt;/tex&amp;gt;, так как по неравенству треугольника &amp;lt;tex&amp;gt; AB + BD &amp;lt; AD &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
По доказанным леммам любое ребро кратчайшего пути содержится в графе, таким образом для нахождения кратчайшего пути осталось найти кратчайший путь в этом графе от &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Построение visibility графа ===&lt;br /&gt;
==== Наивный алгоритм. &amp;lt;tex&amp;gt; O(n ^ 3) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
Если делать наивно, т. е. для каждой пары вершин проверять можно ли добавить ли такое ребро(нет ли пересечений с полигонами), будет &amp;lt;tex&amp;gt; O(n^3) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Lee’s Algorithm. &amp;lt;tex&amp;gt; O(n ^ 2 \log n) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
[[Файл:Zam.png|300px|thumb|left|Заметание плоскости вращающимся лучом]]&lt;br /&gt;
[[Файл:Zamrefr1.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr2.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
[[Файл:Zamrefr3.png|250px|thumb|right|Обновление статуса заметающего луча]]&lt;br /&gt;
Однако можно это сделать за &amp;lt;tex&amp;gt; O(n ^ 2 \log  n) &amp;lt;/tex&amp;gt;. Для каждой вершины найдём все видимые из неё вершины при помощи метода плоского заметания. Нам нужно решить следующую задачу: на плоскости дано множество отрезков (рёбер препятствий) и точка &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Найти все концы отрезков, видимые из точки &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Будем заметать плоскость вращающимся лучом с началом в точке &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Статусом заметающего луча будут отрезки, которые его пересекают, упорядоченные по возрастанию расстояния от точки &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; до точки пересечения. Точками событий будут концы отрезков. Итак, первым делом вершины &amp;lt;tex&amp;gt; w \in V &amp;lt;/tex&amp;gt; сортируются по углу между лучом &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt; и вертикальной полуосью, проходящей через &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; {{---}} луч &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; (достаточно рассматривать только точки, которые лежат правее &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;, так как все точки левее мы уже рассмотрели). Затем происходит инициализация множества видимых вершин (по умолчанию такое множество пустое). Далее начинается заметание плоскости. В порядке сортировки вершин для каждой из них выполняется проверка: видна ли вершина &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; из вершины &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Для этого нам достаточно проверить только пересечение заметающего луча с ближайшим отрезком в статусе, т. е. эта проверка выполняется за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;. Если вершина видима, необходимо добавить её в список видимых вершин. И, наконец, вне зависимости от видимости вершины, необходимо изменить статус заметающего луча. Для этого для текущей вершины &amp;lt;tex&amp;gt; w &amp;lt;/tex&amp;gt; необходимо удалить из списка текущих пересечений все рёбра (отрезки), которые заканчиваются в этой вершине (лежат слева от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;) и добавить все рёбра (отрезки), которые в ней начинаются (лежат справа от прямой &amp;lt;tex&amp;gt; vw &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Псевдокод =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
vector&amp;lt;Vertex&amp;gt; getVisibleVertexes(vertex v)&lt;br /&gt;
   vector&amp;lt;Vertex&amp;gt; ans&lt;br /&gt;
   vertexes.add(all w in Vertexes : w.x &amp;gt;= v.x)&lt;br /&gt;
   status.add(all e in Edges : intersection(e, l) != null)&lt;br /&gt;
   sort status by distance&lt;br /&gt;
   sort vertexes by angle&lt;br /&gt;
   for w in vertexes&lt;br /&gt;
      if intersection(vw, status.closest) == null&lt;br /&gt;
         ans.push(w)&lt;br /&gt;
      delete from status all edges ending in w&lt;br /&gt;
      add in status all edges beginning in w&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Вершин у нас &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;, сортируем за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt; плюс обновление статуса, которое суммарно выполняется за &amp;lt;tex&amp;gt; O(n \log n) &amp;lt;/tex&amp;gt;, так как у нас &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; ребер. Итого &amp;lt;tex&amp;gt; O(n^2 \log n) &amp;lt;/tex&amp;gt;. Что и требовалось доказать.&lt;br /&gt;
&lt;br /&gt;
==== Overmars and Welzl’s Algorithm &amp;lt;tex&amp;gt; O(n ^ 2) &amp;lt;/tex&amp;gt; ====&lt;br /&gt;
[http://igitur-archive.library.uu.nl/math/2006-1214-201604/overmars_88_new_methods.pdf visibility graph при помощи rotation tree]&lt;br /&gt;
&lt;br /&gt;
C помощью [http://bit.ly/1eEqTzk rotation tree] можно достичь асимптотики &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Motion planning ==&lt;br /&gt;
[[Файл:mink.png|200px|thumb|left|Раздуваем препятствия]]&lt;br /&gt;
[[Файл:mink2.png|400px|thumb|right|Ищем путь для точки]]&lt;br /&gt;
Тут мы двигаем не точку, а произвольный выпуклый полигон. Если мы его не можем вращать, просто считаем configuration space, т. е. &amp;quot;обводим&amp;quot; препятствия нашим полигоном (делаем [[Сумма Минковского (определение, вычисление)|сумму Минковского]] препятствий и полигона, сдвинутого в начало координат какой-нибудь точкой) и получаем другие препятствия, но зато теперь мы двигаем точку. А это мы уже научились делать выше.&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим случай, когда мы можем вращать полигон. Для начала построим [[Трапецоидная карта|трапецоидную карту]], как будто мы не можем вращать полигон. Теперь будем вращать полигон на малый угол, пока он не сделает полный оборот вокруг своей оси, и для каждого угла сделаем трапецоидную карту. Теперь разместим(мысленно) все карты друг над другом. Таким образом получится, что поворот на малый угол {{---}} это движение вверх/вниз между слоями. Осталось [[Пересечение многоугольников (PSLG overlaying)|попересекать]] соседние слои и добавить между ними ребра (помним что первый и последний слои одинаковы) и уже в этом графе найти путь.&lt;br /&gt;
&lt;br /&gt;
При такой реализации в некоторых случаях у нас может возникнуть ошибка в повороте, так как в одной плоскости мы все можем делать точно: положения на соседних слоях могут допускаться, а повернуть мы не сможем. Это лечится в основном двумя способами: измельчением угла поворота и изначальным сглаживанием углов полигона {{---}} повращать полигон на &amp;lt;tex&amp;gt; +\epsilon &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; -\epsilon &amp;lt;/tex&amp;gt; и объединить с исходным, получив новый полигон.&lt;br /&gt;
&lt;br /&gt;
Так как эта задача достаточно ресурсоемка, мы рассматриваем только наличие пути, а не нахождение кратчайшего.&lt;br /&gt;
&lt;br /&gt;
== Источники ==&lt;br /&gt;
* 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&lt;br /&gt;
* [http://www.academia.edu/2845047/3D_Visibility_Graph статья про visibility graphs]&lt;br /&gt;
* [http://habrahabr.ru/post/199256/ Хабр]&lt;br /&gt;
[[Категория: Вычислительная геометрия]]&lt;/div&gt;</summary>
		<author><name>Igorjan94</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Zamrefr3.png&amp;diff=36503</id>
		<title>Файл:Zamrefr3.png</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Zamrefr3.png&amp;diff=36503"/>
				<updated>2014-04-29T21:35:33Z</updated>
		
		<summary type="html">&lt;p&gt;Igorjan94: загружена новая версия «Файл:Zamrefr3.png»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Igorjan94</name></author>	</entry>

	</feed>