Быстрая точка в тесте многоугольника с использованием дерева разбиения двоичного пространства

0

Я пытаюсь закодировать алгоритм литья лучей (http://en.wikipedia.org/wiki/Point_in_polygon) таким образом, который будет эффективен, если:

  • алгоритм будет вызываться много раз с одним и тем же полигоном, но другой точкой
  • многоугольник имеет большое количество вершин

Многоугольник прост, но не обязательно выпуклый.

Я буду использовать горизонтальный луч из точки (xp, yp), идущей вправо: xr = xp + a, a> = 0, yr = yp.

Вместо того, чтобы зацикливаться на всех краях многоугольника и проверить, находится ли точка в пределах диапазона y, я хочу использовать технику дерева двоичного пространства для разбиения пространства (http://en.wikipedia.org/wiki/Binary_space_partitioning), чтобы быстро находит такие ребра.

Я представляю себе двоичное дерево ящиков:

struct Box {
    float               min, max;
    Box               *leftChild; // [min,mid]
    Box              *rightChild; // [mid,max]
    std::vector<int> edgeIndices; // edges that are completely within the box
};
  1. Все ребра помещаются в корневую коробку, которая имеет min = min y (многоугольник) и max = max y (многоугольник). Это станет текущим полем.
  2. Текущее поле (min, max) разделено на: left: (min, mid) и right: (mid, max). Края, которые полностью находятся внутри или слева или справа, перемещаются в этот дочерний ящик.

Шаг 2 повторяется для левого и правого дочерних элементов, пока каждый ящик не содержит меньше предопределенного количества ребер или глубина этого дочернего элемента превышает предопределенную максимальную глубину.

Теперь, чтобы найти, какие ребра пересекают значение yp: начните с корневого поля и перемещайтесь вниз, суммируя все ребра вдоль пути.

Как найти оптимальные средние значения? Я хочу, чтобы дерево было ровным и сбалансированным. То есть количество ребер должно быть примерно одинаковым в левом и правом дочерних элементах.

Я мог бы, например, отсортировать края по min y или max y и использовать средний y медианного края в качестве точки разделения (середина).

  • 0
    Что вы подразумеваете под «какое дерево BSP»? Разве это не похоже на вопрос «какой бинарный поиск»?
  • 2
    Есть лучшие способы сделать это.
Показать ещё 3 комментария
Теги:
algorithm
computational-geometry
geometry

4 ответа

1

Вы можете использовать treemap вместо дерева bsp. Трек-карта разделяется вдоль оси x и y, и вы можете сортировать ребра в порядке убывания.

1

Вы можете использовать дерево BSP с узлами, являющимися 2D-плоскостями, разделяющими пространство на две области. В этом подходе листья всегда являются выпуклыми многоугольниками, которые находятся либо снаружи, либо внутри основного многоугольника. Это похоже на то, как Quake и все клоны FPS были сделаны (ищите PVS - Возможный видимый набор). Обратите внимание, что для создания этой структуры потребуется много полигонов, поскольку каждый узел делит основной многоугольник на подполигоны. Использование этой структуры довольно просто: начиная с корня, вы проверяете свою точку с плоскостью узла и выбираете одного из его дочерних элементов. Наконец, вы достигаете листьев, которые находятся внутри или снаружи. Однако основной проблемой является выбор разделительных плоскостей. К сожалению, у меня нет ответа на это. Очевидно, можно выбрать края многоугольника вместо произвольных линий и учитывать несколько других факторов. Наиболее распространенными являются: минимизация числа будущих разделов или разделение пространства наиболее равномерно. Но, честно говоря, я не уверен в этой структуре, поскольку она предназначена для игр и других интерактивных проходов. Я думаю, что он будет подходящим для полисов с действительно большим количеством ребер.

1

Если у вас есть невыпуклый многоугольник, где большинство ребер пересекает определенное значение y, тогда при запросе точки с этим значением y вы получите по существу линейное время в количестве ребер, чтобы решить вашу точку в запросе полигона. Если у вас много времени предварительной обработки и пространства предварительной обработки, вы можете сортировать вершины в соответствии с координатой y и определять горизонтальную линию резки между каждой парой смежных вершин y-координат и ребрами порядка в соответствии с значениями x, где они пересечь горизонтальную линию резки. Это даст структуру данных размера в худшем O (n ^ 2), но потенциально намного меньше. Затем, учитывая точку запроса, вы можете найти двоичный поиск, чтобы найти две вершины, y-координаты которых находятся ближе всего и ниже y-координаты точки запроса, а затем двоичный поиск на этих ребрах, чтобы найти, где точка запроса x- координата лежит в списке ребер, а затем сообщается внутри или снаружи в зависимости от того, является ли x-позиция точки четной или нечетной. В отсортированном списке ребер. Время запроса: O (log n)

  • 0
    Я не уверен, что понимаю ваше предложение. Сортировка вершин отлично подходит для поиска ближайших соседей, но не подходит для поиска пересечений. В качестве примера рассмотрим треугольник: {(-1, -1), (- 1, + 1), (+ 1,0)} и точка (0,0). Самая близкая вершина согласно вашему предложению (+1,0). Однако пересечение с ребром {(-1, -1), (- 1, + 1)} не найдено.
0

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

http://en.wikipedia.org/wiki/Bounding_volume_hierarchy

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

Этот вопрос имеет ссылку на тезис, описывающий алгоритм: KDTree Splitting

Ещё вопросы

Сообщество Overcoder
Наверх
Меню