Изменения

Перейти к: навигация, поиск

BSP-дерево

5095 байт добавлено, 19:31, 4 сентября 2022
м
rollbackEdits.php mass rollback
=== Алгоритм художника (painter's algorithm) ===
[[Файл:painters_algo.png|500px|right]]
Алгоритм художника избегает дополнительных затрат памяти, изначально сортируя объекты по расстоянию от них до точки обзора. Тогда объекты проверяются в так называемом порядке глубины, начиная от самого дальнего. В таком случае при рассмотрении объекта уже не нужна проверка его z-координаты, мы всегда пишем цвет в буфер кадра. Значения, хранимые в буфере ранее, просто перезаписываются.
[[Файл:triangle_cycle.png|150px|left]] Чтобы успешно применять данный метод, нужно уметь быстро сортировать объекты. К сожалению, это не всегда просто. Кроме того, порядок глубины не всегда существует: отношение "перед" может содержать циклы. Когда такое цикличное перекрытие происходит, объекты не могут быть корректно отсортированы. В таком случае мы должны разорвать циклы, разбив один или более объектов на части. (Картинка с примером)
Определение, какие объекты нужно разбить и где, затем сортировка их фрагментов {{---}} дорогой процесс, так как порядок зависит от положения точки обзора, и мы должны пересчитывать все при каждом ее смещении.
Чтобы использовать этот алгоритм в реальной жизни, например, в симуляторе полета, мы должны предпосчитать сцену так, чтобы можно было быстро найти корректный порядок отображения объектов для любой точки обзора.
Элегантная структура данных, которая позволяет это сделать {{---}} Данную задачу можно элегантно решить при помощи техники '''двоичное разбиение двоичного разбиения пространства''' (англ. ''binary dpace partitionspace partitioning, BSP'') или '''BSP-дерево'''.
== Определение Структура BSP-дерева ==Чтобы понять, что из себя представляет BSP-дереводвоичное разбиение пространства, рассмотрим рисунок. На нем показано двоичное разбиение множества объектов на плоскости и дерево, которое этому разбиению соответствует.В двумерном случае BSP строится с помощью рекурсивного разбиения плоскости прямыми. В данном примере это происходит так: сначала l1проводим прямую <tex>l_1</tex>, затем разбиваем разбивая полуплоскость выше l1 <tex>l_1</tex> прямой l2<tex>l_2</tex>, а ниже {{---}} прямой l3 <tex>l_3</tex> и так далее.
Прямые разбивают на фрагменты не только плоскость, но и объекты, расположенные на ней[[Файл:bsp_plane1. Разбиение продолжается до тех пор, пока внутри каждого фрагмента плоскости окажется не более одного фрагмента объекта.Этот процесс можно представить с помощью двоичного дерева. Каждый лист дерева соответствует фейсу разбиения, в нем хранится фрагмент объекта, находящийся внутри этого фейса. Каждый узел дерева соответсвует разбивающей прямой, которая хранится в этом узле.Если сцене присутствуют 1D-объекты (отрезки), то они могут лежать на прямой разбиения, в таком случае соответсвующий узел хранит их в листьяхpng|300px]][[Файл:bsp_tree1.png|300px]]
Рассмотрим гиперплоскость h: a_1*x_1 + a_2*x_2 + Прямые разбивают на части не только плоскость, но и объекты, расположенные на ней... + a_d*x_d + a_{d + 1} = 0Разбиение продолжается до тех пор, пока внутри каждой грани плоскости окажется не более одного фрагмента объекта.
Пусть h^+ Этот процесс можно представить с помощью двоичного дерева. Каждый лист дерева соответствует грани разбиения, в нем хранится фрагмент объекта, находящийся внутри этой грани. Каждый узел дерева соответсвует разбивающей прямой, которая хранится в этом узле.{{Определение| definition = '''BSP-дерево''' (англ. ''binary space partition tree'') {{---}} положительная полуплоскостьдерево, а h^- {{---отвечающее заданному двоичному разбиению пространства.}} отрицательная:Опишем подробней свойства BSP-дерева.
Рассмотрим гиперплоскость <tex>h^+ = {(x_1, x_2 ... x_d) : a_1*\cdot x_1 + a_2*\cdot x_2 + ... \ldots + a_d*\cdot x_d + a_{d + 1} = 0</tex> 0}.
Пусть <tex>h^+</tex> {{---}} положительное полупространство, а <tex>h^- = </tex> {(x_1, x_2 ... x_d) : a_1*x_1 + a_2*x_2 + ... + a_d*x_d + a_{d + 1---} < 0}отрицательное:
Пусть S - множество объектов<tex>h^+ = \{(x_1, для которого мы строим забиение в \ x_2,\ \dots,\ x_d) \mid a_1 \cdot x_1 + a_2 \cdot x_2 + \ldots + a_d \cdot x_d + a_{d-мерном пространстве.+ 1} > 0\}</tex>
Пусть v <tex>h^- какая-то вершина дерева= \{(x_1,\ x_2,\ \dots, тогда обозначим S(v) множество объектов (возможно пустое\ x_d), хранимых в этой вершине.\mid a_1 \cdot x_1 + a_2 \cdot x_2 + \ldots + a_d \cdot x_d + a_{d + 1} < 0\}</tex>
BSP-дерево T для этого множества обектов обладает следующими свойствами:*Если |Пусть <tex>S| <= 1, то T /tex> {{--- лист. Фрагмент объекта в S, если он существует, хранится в этом листе.*Если |S| > 1, то в корне дерева v хранится гиперплоскость h_v и }} множество S(v) объектов, которые полностью содержатся для которого мы строим разбиение в h_v<tex>d</tex>-мерном пространстве. * левый ребенок v является корнем BSP дерева T^- на множестве объектов S^- = {h_v^- \пересечь s : s \in S} * правый ребенок v является корнем BSP дерева T^+ на множестве объектов S^+ = {h_v^+ \пересечь s : s \in S}
Размер BSPПусть <tex>v</tex> {{-дерева равен суммарному размеру множеств во всех узлах. То есть, размер BSP--}} какая-то вершина дерева - это число фрагментов, на которые были разбиты объекты. Так как BSP-дерево не содержит бесполезные прямые тогда обозначим за <tex>S(v)</tex> множество объектов (прямые, которые разбивают пустой фейсвозможно пустое), то количество узлов пропорционально размеру деревахранимых в этой вершине.
В общемBSP-дерево <tex>T</tex> для этого множества обектов обладает следующими свойствами:*Если <tex>|S| \leqslant 1</tex>, то размер BSP<tex>T</tex> {{---дерева ни о чем не говорит}} лист. Фрагмент объекта в <tex>S</tex>, так как мы не знаем ничего об объеме памятиесли он существует, требуемой для его храненияхранится в этом листе.*Если <tex>|S| > 1</tex>, так как оно ничего не говорит об объеме памятито в корне дерева <tex>v</tex> хранится гиперплоскость <tex>h_v</tex> и множество <tex>S(v)</tex> объектов, требуемом для храния фрагмента объектакоторые полностью содержатся в <tex>h_v</tex>.Но размер **левый ребенок <tex>v</tex> является корнем BSP-дерева <tex>T^- неплохая мера для сравнения качества разных </tex> на множестве объектов <tex>S^- = \{h_v^- \cap s \mid s \in S\}</tex>;**правый ребенок <tex>v</tex> является корнем BSP-деревьев для данного множества дерева <tex>T^+</tex> на множестве объектов<tex>S^+ = \{h_v^+ \cap s \mid s \in S\}</tex>.
И еще рисунок про соответсвие нодов Размер BSP-дерева равен суммарному размеру множеств во всех узлах. Другими словами, размер BSP-дерева {{---}} число фрагментов, на которые были разбиты объекты. Так как BSP-дерево не содержит бесполезные прямые (прямые, которые разбивают пустую грань), то количество узлов пропорционально размеру дерева. [[Файл:bsp_plane2.png|300px]][[Файл:bsp_tree2.png|300px]] Листья BSP-дерева соответствуют граням, то есть мы можем каждой вершине <tex>v</tex> сопоставить полигональную область на плоскости, которая определяется как пересечение полуплоскостей <tex>h_{\mu}^{\Diamond}</tex>, где <tex>\mu</tex> {{---}} предок <tex>v</tex>, и регионов <tex> \Diamond = \left\{\begin{array}{llcl}- & \mathrm{if}\ v\ - \ \mathrm{left}\ \mathrm{child} \\+ & \mathrm{if}\ v\ - \ \mathrm{right}\ \mathrm{child} \\\end{array}\right.</tex>
Листья BSP-дерева соответствуют фейсам, то есть мы можем каждой вершине v сопоставить полигональную область на плоскости, которая определяется как пересечение полуплоскостей h_mu^ромбик, где mu - предок v, а ромбик = {-, если v левый ребенок; +, если v правый ребенок}
Корню дерева соответсвует все пространство.
Таким образом, серая область на рисунке соответствует региону <tex>l_1^+ \пересечь cap l_2^+ \пересечь cap l_3^+-</tex>. При построении BSP-дерева могут использоваться любые разбивающие гиперплоскости. В целях упрощения вычислений может быть удобно ограничить множество доступных разбивающих гиперплоскостей. Обычно используют авто-разбиения.{{Определение| definition = В двумерном случае для множества отрезков разбиение, в котором используются разбивающие прямые, проходящие через один из данных отрезков, называется '''авто-разбивающим''' (англ. ''auto-partition''). }} В трёхмерном случае авто-разбиение использует плоскости, которые содержат грани многогранников.
При построении BSP-дерева могут использоваться любые разбивающие гиперплоскости. В целях упрощения вычислений может быть удобно ограничить множество доступных разбивающих гиперплоскостей[[Файл:bsp_n2.png|130px]]
Обычно ограничивают следующим образом:ПредположимКак видно из рисунка, что мы хотим построить BSPразмер авто-дерево для множества отрезков на плоскостиразбивающего дерева может быть не минимальным. ОчевидноВозможен случай, что лучшими кандидатами разбивающих прямых являются продолжения данных отрезков. когда размер BSP-дерево, которое использует разбивающие прямые только такого видадерева может составлять <tex>\mathcal{O}(n^2) </tex>, называется авто-разбивающим. Для множества плоских полигонов в трехмерном пространстве авто-разбивающим является BSP-дерево, которое использует только полоскости, на которых лежат данные полигоны.Но авто-разбивающие деревья деревья имеют минимальный размергде <tex> n = |S| </tex>.
== BSP-деревья и алгоритм художника ==
Предположим, что мы построили BSP-дерево <tex>T </tex> для множества объектов <tex>S </tex> в трехмерном пространстве. Как нам следует использовать его, чтобы получить порядок глубины для алгоритма художника? Пусть p_view <tex>p_{view}</tex> {{- --}} точка обзора, и она лежит над разбивающей плоскостью, хранимой в корне <tex>T</tex>. Тогда ни один из объектов, лежащих под этой плоскостью, не может затемнить (мб перекрыть?) ни один из объектов, лежащих выше нее. Таким образом, мы можем безопасно показать отрисовать фрагменты объектов из поддерева <tex>T^- </tex> до показа отрисовки объектов из поддерва <tex>T^+</tex>.
Порядок фрагментов объектов в поддеревьях определяется таким же способом.
<code> '''void''' painters_algorithm(<tex>T</tex>, pview<tex>p_{view}</tex>): Let ν be the root of <tex>v \leftarrow T.root</tex> '''if ν is a leaf''' <tex>v</tex> {{---}} лист then Scan-convert the object fragments in отрисовать фрагменты объектов из <tex>S(νv).</tex> '''else if pview ''' <tex>p_{view} \in hh_v^+ν</tex> then painters_algorithm(T−<tex>T^-</tex>, pview<tex>p_{view}</tex>) Scan-convert the object fragments in отрисовать фрагменты объектов из <tex>S(νv).</tex> painters_algorithm(<tex>T^+</tex>, pview<tex>p_{view}</tex>) '''else if pview ''' <tex>p_{view} \in h−νh_v^-</tex> then painters_algorithm(<tex>T^+</tex>, pview<tex>p_{view}</tex>) Scan-convert the object fragments in отрисовать фрагменты объектов из <tex>S(νv).</tex> painters_algorithm(T−<tex>T^-</tex>, pview<tex>p_{view}</tex>) '''else (''' <font color="green">/pview <tex>p_{view} \in h_v</tex> )/</font> painters_algorithm(<tex>T^+</tex>, pview<tex>p_{view}</tex>) painters_algorithm(T−<tex>T^-</tex>, pview<tex>p_{view}</tex>)</code>
Заметим, что мы не рисуем полигоны объекты из <tex>S(v)</tex>, когда p_view <tex>p_{view}</tex> лежит на разбивающей плоскости <tex>h_v</tex>, потому что полигоны они являются плоскими двумерными объектамиполигонами.
Эффективность данного алгоритма, как и любого другого алгоритма для BSP-деревьев, зависит от размера BSP-дерева. То есть мы должны необходимо выбирать разбивающие плоскости таким образом, чтобы фрагментация объектов была минимальной.Перед тем, как разрабатывать стратегии разбиения, которые порождают маленькие BSP-деревья, мы должны решить, какие типы объектов допустимы.Мы заинтересовались BSP-деревьями потомуинтересны тем, что нам нужена была быстрая реализация позволяют достичь быстрой реализации удаления скрытых поверхностей для симулятора полетовотрисовки сцены (будь то симулятор полёта или персонаж в игре, осматривающий окружающий мир). Так как скорость {{-- наша -}} главная цель, мы должны следует упростить вид объектов нашего рассматриваемого пейзажа: не , поэтому далее будем использовать кривые поверхностисчитать, представив все что в 3D мы работаем только с помощью полигонов.Предположиммногогранниками, что фейсы грани которых уже [[Триангуляция полигонов (ушная + монотонная) | триангулированы, и мы хотим построить ]]. Таким образом множество <tex>S</tex> в трехмерном трёхмерном пространстве BSP-дерево наименьшего размера для данного множества будет состоять только из треугольников.
== Построение BSP-дерева ==
При решении задач Прежде чем переходить к задаче отрисовки сцены в трехмерном пространстве бывает полезно сначала рассмотреть трёхмерном случае, рассмотрим для простоты аналогичную задачу на плоскости, что мы и сделаем.Пусть S - множество из n непересекающихся отрезков на плоскости. Ограничимся авто-разбиением, рассматривая только прямые, содержащие один из отрезков. Пусть l(s) - прямая, содержащая отрезок s.На вход алгоритму подается S = {s1, s2, ... sn} - множество отрезков.
BSPTree 2D_BSP_tree(Пусть <tex>S)if |S| <= 1 then Create a tree T consisting of a single leaf node, where the set S is stored explicitly. return T else /* Use l(s1) as the splitting line */ S+ \leftarrow tex> {{s \пересечь l(s1)+ : s \in S---}; T+ \leftarrow 2D_BSP_tree(S+); S− \leftarrow {s \пересечь l(s1)− : s ∈ S}; T− \leftarrow 2D_BSP_tree(S−); Create a BSP tree T with root node ν, left subtree T−множество из <tex>n</tex> непересекающихся отрезков на плоскости. Ограничимся авто-разбиением, right subtree T+рассматривая только прямые, and with S(ν) = {s \in S : s \subset l(s1)}содержащие один из отрезков. return T
Понятно, что алгоритм создает BSP-дерево для множества S, но будет ли оно наименьшим?Наверное, стоит тщательней выбирать прямую разбиения, а не просто брать l(s1). Возможным подходом является выбор отрезка s \in S, такого что Пусть <tex>l(s) пересекает наименьшее число отрезков.Но этот жадный алгоритм, работает не на всех конфигурациях отрезков. Кроме того, поиск такого отрезка </tex> {{--- занятие затратное.Как и в других алгоритмах}} прямая, когда нужно сделать сложный выбор, просто выберем случайно. Это означает, что для разбиения мы будем использовать рандомный содержащая отрезок.Для этого расположим отрезки в S случайном порядке перед тем, как начинать построение дерева<tex>s</tex>.
2D_random_BSP_tree(На вход алгоритму подается <tex>S) Generate a random permutation S' = s1\{s_1,\ s_2, . . . \ \dots , sn of the set S\ s_n\}</tex> {{---}} множество отрезков. T \leftarrow 2D_BSP_tree(S�) return T
Перед тем<code> '''BSPTree''' 2D_BSP_tree(<tex>S</tex>): '''if''' <tex>|S| \leqslant 1</tex> <tex>T \leftarrow</tex> '''BSPTree'''(<tex>S</tex>) <font color="green">/* <tex>T</tex> будет листом, в котором хранится данное множество */</font> '''return''' <tex>T</tex> '''else''' <font color="green">/* используем <tex>l(s_1)</tex> как анализировать рандомизированный алгоритм, отметим, что здесь возможна одна простая оптимизация. разбивающую прямую */</tex></font> <tex>S^+ \leftarrow \{s \cap l^+(s_1) \mid s \in S\}</tex> <tex>T^+ \leftarrow</tex> 2D_BSP_tree(<tex>S^+</tex>)Предположим, что мы выбрали несколько первых разбивающих прямых. Эти прямые порождают разбиение плоскости, фейсы которой соответствуют каким <tex>S^-то узлам BSP\leftarrow \{s \cap l^-дерева. (s_1) \mid s \in S\}</tex> Рассмотрим одну из таких поверхностей f. В <tex>T^- \leftarrow</tex> 2D_BSP_tree(<tex>S могут быть отрезки, которые полностью пересекают f. Выбор одного из таких отрезков для разбиения f не вызовет фрагментации других отрезков внутри f, так как данный отрезок исключается из дальнейшего рассмотрения.^-</tex>)Назовем такое свободным разбиением. <tex>S_v \leftarrow \{s \in S \mid s \subset l(s_1)\}</tex>Нашей улучшенной стратегией будет использование свободных разбиений везде <tex>T \leftarrow</tex> '''BSPTree'''(<tex>S_v, где только можно\ T^-, и использование случайных разбиений \ T^+</tex>) <font color="green">// создаем BSP-дерево c корнем в противном случае. Для реализации данной оптимизации нужно уметь определятьвершине <tex>v</tex>, вызывает ли отрезок свободное разбиение.левым поддеревом <tex>T^-</tex> и правым поддеревом <tex>T^+</tex> </font>Для этого сопоставим каждому отрезку две булевых переменных, которые покажут, лежат ли правый <font color="green">// и левый концы отрезка на какоймножеством хранимых объектов <tex>S_v</tex></font> '''return''' <tex>T</tex> </code>Данный алгоритм создает BSP-то из дерево для множества <tex>S</tex>, но как уже добавленных разбивающих прямых.Обе переменных истинныизвестно, когда отрезок вызывает свободное разбиениеоно не будет наименьшим в общем случае.
Необходимо придумать стратегию выбора прямой разбиения, а не просто брать <tex>l(s_1)</tex>. Возможным подходом является выбор отрезка <tex>s \in S</tex>, такого что <tex>l(s)</tex> пересекает наименьшее число отрезков. Но такой жадный алгоритм работает не на всех конфигурациях отрезков. Кроме того, поиск такого отрезка {{---}} занятие затратное. Как и в других алгоритмах, когда нужно сделать сложный выбор, сделаем рандомный выбор. Это означает, что для разбиения мы будем использовать случайно выбранный отрезок. Для этого перед тем, как начинать построение дерева, расположим отрезки в <tex>S</tex> случайном порядке. <code> '''void''' 2D_random_BSP_tree(<tex>S</tex>): <tex>S \leftarrow </tex> random_permutation(<tex>S</tex>) <tex>T \leftarrow </tex> 2D_BSP_tree(<tex>S</tex>) '''return''' <tex>T</tex></code>Перед анализированием рандомизированного алгоритма рассмотрим одну простую оптимизацию.  Предположим, что мы выбрали несколько первых разбивающих прямых. Эти прямые порождают разбиение плоскости, грани которой соответствуют каким-то узлам BSP-дерева.  [[Файл:bsp_free.png|300px|right]]Рассмотрим одну из таких граней <tex>f</tex>. В <tex>S</tex> могут быть отрезки, которые полностью пересекают <tex>f</tex>. Выбор одного из таких отрезков для разбиения <tex>f</tex> не вызовет фрагментации других отрезков внутри <tex>f</tex>, так как данный отрезок исключается из дальнейшего рассмотрения. Назовем такое свободным разбиением. Нашей улучшенной стратегией будет использование свободных разбиений везде, где только можно, и использование случайных разбиений в противном случае. Для реализации данной оптимизации нужно уметь определять, вызывает ли отрезок свободное разбиение. Для этого сопоставим каждому отрезку две булевых переменных, которые покажут, лежат ли правый и левый концы отрезка на какой-то из уже добавленных разбивающих прямых. Обе переменных истинны, когда отрезок вызывает свободное разбиение. Теперь оценим производительность алгоритма '''2D_random_BSP_tree'''. Для упрощения рассуждений будем анализировать версию без свободных разбиений (асимптотической разницы они не даютмежду ними нет).Начнем с анализа размера BSP-дерева, равного числу полученных фрагментов, которое зависит от сгенерированной перестановки отрезков. Некоторые перестановки могут породить маленькие деревья, а другие {{--- }} большие.  [[Файл:bsp_three_segments.png|500px]] В качестве примера рассмотрим три отрезка, изображенные на рисунке. Если они рассматриваются в порядке (a), то мы получаем пять фрагментов, если же в порядке (b) {{-- -}} то всего три фрагмента. Так как размер BSP-дерева зависит от сгенерированной перестановки, будем анализировать ожидаемый размер BSP-дерева {{--- }} средний размер для всех <tex>n! </tex> перестановок. {{Лемма| statement = Ожидаемое число фрагментов, сгенерированных алгоритмом '''2D_random_BSP_tree''' есть <tex>\mathcal{O}(n \log n)</tex>.|proof = Пусть <tex>s_i</tex> {{---}} фиксированный отрезок из <tex>S</tex>. Проанализируем [[Математическое ожидание случайной величины | ожидаемое]] количество отрезков, которые мы разрежем, когда <tex>l(s_i)</tex> будет добавлена алгоритмом как следующая разбивающая прямая. Рассмотрим рисунок и постараемся понять, разрезается ли отрезок <tex>s_j</tex> при добавлении прямой <tex>l(s_i)</tex>, в зависимости от отрезков, которые разрезаны <tex>l(s_i)</tex>, но находятся между <tex>s_i</tex> и <tex>s_j</tex>.  В частности, когда прямая, пересекающая такой отрезок, добавляется раньше <tex>l(s_i)</tex>, она закрывает <tex>s_j</tex> от <tex>s_i</tex>. На рисунке (b) так происходит с отрезком <tex>s_3</tex>, который защищен отрезком <tex>s_1</tex> от <tex>s_2</tex>. Эти размышления приводят нас к определению расстояния от какого-то отрезка до фиксированного отрезка <tex>s_i</tex>. [[Файл:bsp_dist.png|300px|right]] <tex> \mathrm{dist}(s_i, s_j) = \left\{\begin{array}{llcl}|\{s\ \mathrm{between}\ s_i\ \mathrm{and}\ s_j \mid l(s_i) \cap s \ne \varnothing \}| & \mathrm{if}\ l(s_i) \cap s_j \ne \varnothing \\\infty & \mathrm{otherwise} \\\end{array}\right.</tex> Для всех конечных расстояний до отрезка <tex>s_i</tex> может быть только два отрезка с одинаковым расстоянием {{---}} те, что лежат по разные стороны от <tex>s_i</tex>. Пусть <tex>k = \mathrm{dist}(s_i, s_j)</tex> и <tex>s_{j_1},\ s_{j_2},\ \ldots ,\ s_{j_k}</tex> {{---}} отрезки между <tex>s_i</tex> и <tex>s_j</tex>. Найдём вероятность того, что при добавлении <tex>l(s_i)</tex> разрежет <tex>s_j</tex>. Чтобы это произошло, <tex>s_i</tex> должен быть рассмотрен перед <tex>s_j</tex> и перед любым из отрезков между <tex>s_i</tex> и <tex>s_j</tex>, иначе они бы защитили <tex>s_j</tex> от <tex>s_i</tex>. Другими словами, среди множества индексов <tex>\{i,\ j,\ j_1,\ \ldots ,\ j_k\}</tex> индекс <tex>i</tex> должен быть наименьшим.
Лемма. Ожидаемое число фрагментов, сгенерированных алгоритмом 2D_random_BSP_tree есть O(nlogn).
Доказательство.
Пусть s_i - фиксированный отрезок из S. Проанализируем ожидаемое количество отрезков, которые мы разрежем, когда l(s_i) будет добавлена алгоритмом как следующая разбивающая прямая.
Рассмотрим рисунок и постараемся понять разрезается ли отрезок s_j при добавлении прямой l(s_i), в зависимости от отрезков, которые разрезаны l(s_i), но находятся между s_i и s_j.
В частности, когда прямая, пересекающая такой отрезок, добавляется раньше l(s_i), она закрывает s_j от s_i. На рисунке (b) так происходит с отрезком s_3, который защищен отрезком s_1 от s_2.
Эти размышления приводят нас к определению расстояния от какого-то отрезка до фиксированного отрезка s_i.
dist_s_i(s_j) = {количество пересекаемых отрезков, если l(s_i) пересекает s_j; +inf, иначе}
Для всех конечных расстояний до отрезка s_i может быть только два отрезка с одинаковым расстоянием - те, что лежат по разные стороны от s_i.
Пусть k = dist_s_i(s_j) и s_j_1, s_j_2, ... s_j_k - отрезки между s_i и s_j. Какова вероятность того, что при добавлении l(s_i) разрежет s_j?
Чтобы это произошло, s_i должен быть рассмотрен перед s_j и перед любым из отрезков между s_i и s_j, иначе они бы защили s_j от s_i. Другими словами, среди множества индексов {i, j, j_1, ... , j_k} i должен быть наименьшим.
Так как отрезки расположены в случайном порядке, получаем:
<tex>P(l(s_i) разрезает \cap s_j\ne \varnothing) <= \leqslant \genfrac{}{}{}{0}{1 / (}{k + 2)}</tex> Так как существуют Существуют отрезки, которые не разрезаются <tex>l(s_i)</tex>, но расширение которых защитит <tex>s_j</tex>, так что выше записано неравенство. Теперь мы можем ограничить ожидаемое число разрезов, происходящих при добавлении <tex>s_i</tex><tex>E(</tex>число разрезов, происходящих при добавлении <tex>s_i) <= \leqslant \sum(\limits_{j \ne i != j, } \genfrac{}{}{}{0}{1 / }{\mathrm{dist}(k s_i, s_j) + 2)) <= } \leqslant 2 * \cdot \sum(\limits_{k=0..}^{n - 2, } \genfrac{}{}{}{0}{1/ (}{k + 2)) <= } \leqslant 2 * \ln n</tex>. По линейности ожиданий мы можем заключить, что ожидаемое число разрезов, вызванных добавлением всех отрезков составляет не более 2nlogn<tex>2n\log n</tex>.Так как изначально даны <tex>n </tex> отрезков, ожидаемое число фрагментов ограничено <tex>n + 2nlogn2n\log n</tex>.}} Было показано, что ожидаемый размер BSP-дерева, построенного с помощью алгоритма '''2D_random_BSP_tree''', составляет <tex>n + 2n\log n</tex>. Следовательно, мы доказали, что BSP-дерево размера <tex>n + 2n\log n</tex> существует для любого множества <tex>n</tex> отрезков. Кроме того, хотя бы половина перестановок приводит к BSP-дереву размера <tex>n + 4n\log n</tex>.
Мы показали, что ожидаемый размер BSP-дерева, построенного с помощью алгоритма 2D_random_BSP_tree, составляет n + 2nlogn. Следовательно, мы доказали, что BSP-дерево размера n + 2nlogn существует для любого множества n отрезков. Кроме того, хотя бы половина перестановок приводит к BSP-дереву размера n + 4nlogn.
Мы можем использовать этот факт, чтобы найти дерево такого размера: после запуска алгоритма сравним размер дерева с данной оценкой, если он превышает оценку, просто построим BSP-дерево еще раз, но для новой перестановки. Ожидаемое число запусков равняется двум.
Теперь проанализируем время работы алгоритма. Понятно, что оно зависит от используемой перестановки, так что опять рассмотрим ожидаемое время работы. Нахождение рандомной перестановки занимает <tex>\mathcal{O}(n)</tex> при помощи [[Метод генерации случайной перестановки, алгоритм Фишера-Йетса |алгоритма Фишера-Йетса]]. Если проигнорировать время рекурсивных вызовов, то время работы алгоритма линейно от количества фрагментов в <tex>S</tex>. Это число не превышает <tex>n</tex>, так как становится меньше с каждым рекурсивным вызовом.Число рекурсивных вызовов ограничено количеством сгенерированных фрагментов, которое составляет <tex>\mathcal{O}(nlognn\log n)</tex>. Таким образом, время построения дерева составляет <tex>\mathcal{O}(n^2\log n)</tex>. {{Теорема| statement = В двумерном пространстве BSP-дерево размера <tex>\mathcal{O}(n\log n)</tex> может быть построено за ожидаемое время <tex>\mathcal{O}(n^2logn2\log n)</tex>.}} Описанный выше алгоритм легко обобщается на трёхмерное пространство. Как было упомянуто выше, мы считаем, что работаем в 3D с триангуляцией граней многранников. Пусть <tex>S</tex> {{---}} множество непересекающихся треугольков в <tex>\mathbb{R}^3</tex>.  Снова ограничимся только авто-разбиениями, разбивая пространство плоскостями, содержащими какой-то из треугольников. Для треугольника <tex>t</tex> обозначим плоскость, содержащую его, как <tex>h(t)</tex>.На вход алгоритму подается множество треугольников <tex>S = \{t_1,\ t_2,\ \dots ,\ t_n\}</tex>, заданных в трехмерном пространстве.
Теорема. '''BSPTree''' 3D_BSP_tree(<tex>S</tex>): '''if''' <tex>|S| \leqslant 1</tex> <tex>T \leftarrow</tex> '''BSPTree'''(<tex>S</tex>) <font color="green">/* <tex>T</tex> будет листом, в котором хранится данное множество */</font> '''return''' <tex>T</tex> '''else''' <font color="green">/* используем <tex>h(t_1)</tex> как разбивающую плоскость */</font> <tex>S^+ \leftarrow \{t \cap h^+(t_1) \mid t \in S\}</tex> <tex>T^+ \leftarrow</tex> 3D_BSP_tree(<tex>S^+</tex>)BSP <tex>S^- \leftarrow \{t \cap h^-(t_1) \mid t \in S\}</tex> <tex>T^- \leftarrow</tex> 3D_BSP_tree(<tex>S^-дерево размера O</tex>) <tex>S_v \leftarrow \{t \in S \mid t \subset h(nlognt_1) может быть построено за ожидаемое время O\}</tex> <tex>T \leftarrow</tex> '''BSPTree'''(n<tex>S_v,\ T^2logn-,\ T^+</tex>) <font color="green">// создаем BSP-дерево c корнем в вершине <tex>v</tex>, левым поддеревом <tex>T^-</tex> и правым поддеревом <tex>T^+</tex> </font> <font color="green">// и множеством хранимых объектов <tex>S_v</tex></font> '''return''' <tex>T</tex>
Описанный выше алгоритм легко распространяется с двухмерного пространства на трехмерное. Пусть S Размер полученного BSP- множество непересекающихся треугольков в R^3. Снова ограничимся только авто-разбиениями, разбивая пространство плоскостями, содержащими какой-то из дерева снова зависит от порядка треугольников.Для треугольника t обозначим плоскостьКак и в двумерном случае, содержащую егомы можем попытаться получить хороший ожидаемый размер дерева, как h(t)переставив треугольники в случайном порядке.На вход алгоритму подается множество треугольников S = {t1, t2, . . . ,tn}, заданных в трехмерном пространствепрактике это дает хорошие результаты.
BSPTree 3DBSP(S)if |S| <= 1 then Create a tree T consisting of a single leaf node, where the set S is stored explicitly= См.также == return T else /* Use h[[Перечисление точек в произвольном прямоугольнике за n * log ^(t1d - 1) as the splitting plane. */ S+ \leftarrow {t \пересечь hn (t1range tree)+ : t ∈ S}]] T+ \leftarrow 3DBSP* [[Дерево интервалов (S+interval tree)и пересечение точки с множеством интервалов]] S− \leftarrow{t \пересечь h* [[Пересечение прямоугольника с множеством непересекающихся отрезков (t1segment tree)− : t ∈ S}]] T− \leftarrow 3DBSP(S−)== Источники иформации == Create a BSP tree T with root node ν* Mark de Berg, left subtree T−Marc van Kreveld, right subtree T+Mark Overmars, and with SOtfried Schwarzkopf (ν2000) = {t ∈ S : t ⊂ h, Computational Geometry (t12nd revised ed.)}, Springer-Verlag, ISBN 3-540-65620-0 Chapter 12: Binary Space Partition: pp.259–267. return T
Размер полученного BSP-дерева снова зависит от порядка треугольников. Как и в двухмерном случае, мы можем попытаться получить хороший ожидаемый размер дерева, переставив треугольники в случайном порядке. На практике это дает хорошие результаты.[[Категория: Вычислительная геометрия]][[Категория: Аффинное пространство]][[Категория: Структуры данных]]
1632
правки

Навигация