Я пытаюсь закодировать алгоритм литья лучей (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
};
Шаг 2 повторяется для левого и правого дочерних элементов, пока каждый ящик не содержит меньше предопределенного количества ребер или глубина этого дочернего элемента превышает предопределенную максимальную глубину.
Теперь, чтобы найти, какие ребра пересекают значение yp: начните с корневого поля и перемещайтесь вниз, суммируя все ребра вдоль пути.
Как найти оптимальные средние значения? Я хочу, чтобы дерево было ровным и сбалансированным. То есть количество ребер должно быть примерно одинаковым в левом и правом дочерних элементах.
Я мог бы, например, отсортировать края по min y или max y и использовать средний y медианного края в качестве точки разделения (середина).
Вы можете использовать treemap вместо дерева bsp. Трек-карта разделяется вдоль оси x и y, и вы можете сортировать ребра в порядке убывания.
Вы можете использовать дерево BSP с узлами, являющимися 2D-плоскостями, разделяющими пространство на две области. В этом подходе листья всегда являются выпуклыми многоугольниками, которые находятся либо снаружи, либо внутри основного многоугольника. Это похоже на то, как Quake и все клоны FPS были сделаны (ищите PVS - Возможный видимый набор). Обратите внимание, что для создания этой структуры потребуется много полигонов, поскольку каждый узел делит основной многоугольник на подполигоны. Использование этой структуры довольно просто: начиная с корня, вы проверяете свою точку с плоскостью узла и выбираете одного из его дочерних элементов. Наконец, вы достигаете листьев, которые находятся внутри или снаружи. Однако основной проблемой является выбор разделительных плоскостей. К сожалению, у меня нет ответа на это. Очевидно, можно выбрать края многоугольника вместо произвольных линий и учитывать несколько других факторов. Наиболее распространенными являются: минимизация числа будущих разделов или разделение пространства наиболее равномерно. Но, честно говоря, я не уверен в этой структуре, поскольку она предназначена для игр и других интерактивных проходов. Я думаю, что он будет подходящим для полисов с действительно большим количеством ребер.
Если у вас есть невыпуклый многоугольник, где большинство ребер пересекает определенное значение y, тогда при запросе точки с этим значением y вы получите по существу линейное время в количестве ребер, чтобы решить вашу точку в запросе полигона. Если у вас много времени предварительной обработки и пространства предварительной обработки, вы можете сортировать вершины в соответствии с координатой y и определять горизонтальную линию резки между каждой парой смежных вершин y-координат и ребрами порядка в соответствии с значениями x, где они пересечь горизонтальную линию резки. Это даст структуру данных размера в худшем O (n ^ 2), но потенциально намного меньше. Затем, учитывая точку запроса, вы можете найти двоичный поиск, чтобы найти две вершины, y-координаты которых находятся ближе всего и ниже y-координаты точки запроса, а затем двоичный поиск на этих ребрах, чтобы найти, где точка запроса x- координата лежит в списке ребер, а затем сообщается внутри или снаружи в зависимости от того, является ли x-позиция точки четной или нечетной. В отсортированном списке ребер. Время запроса: O (log n)
Структура, которую вы строите, на самом деле представляет собой ограниченную иерархию томов, которая может использоваться для трассировки лучей. Идея состоит в том, чтобы иметь края в листах иерархии ограниченных томов и спускаться по дереву, когда луч взаимодействует с коробкой.
http://en.wikipedia.org/wiki/Bounding_volume_hierarchy
Чтобы эффективно спускаться в дерево, вы можете использовать эвристику поверхности (SAH). Он также может использоваться для иерархии ограничивающих томов. Идея состоит в том, чтобы оценить стоимость прохождения иерархии с использованием вероятности либо спускаться влево, либо на ту же сторону, а затем минимизировать эту стоимость. SAH также может реализовать условие остановки, когда стоимость спуска в иерархию будет выше, чем просто цикл, охватывающий все остальные ребра.
Этот вопрос имеет ссылку на тезис, описывающий алгоритм: KDTree Splitting