Проверить, находится ли точка в некотором прямоугольнике

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

использование R-деревьев, похоже, работает, но они действительно предназначены для прямоугольников, а не для точек. Я мог бы использовать модифицированную версию алгоритма R-tree, который также работает с точками, но я бы предпочел не изобретать колесо, если есть лучшее решение. Я не очень хорошо знаком с структурами данных, поэтому, возможно, уже существует какая-то структура, которая работает для моей проблемы?

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

edit: это в 2D, и прямоугольники не поворачиваются.

5 ответов


этот поток Reddit решает вашу проблему:

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

Если ваша вселенная целочисленна или если уровень точности хорошо известен и не слишком высок, вы можете использовать abelssonпредложение из потока, используя O (1) ПОИСК С помощью раскраски:

как обычно, вы можете обменять пространство на время.. вот поиск O(1) с очень низкая константа. init: создание растрового изображения достаточно большой, чтобы охватить все прямоугольники с достаточной точностью инициализируйте он черный. Цвет всех пикселей содержит любой прямоугольник белого цвета. O (1) поиск: является ли точка (x,y) белой? Если Итак, попал прямоугольник.

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

во-первых, проблемы микро. У вас есть произвольно повернутый прямоугольник, и точка. Смысл внутри прямоугольник?

есть много способов сделать это. Но лучше всего, я думаю, использовать 2d векторное перекрестное произведение. Во-первых, убедитесь, что точки прямоугольника сохраняются по часовой стрелке. Затем сделайте вектор перекрестное произведение с 1) вектором образованный двумя точками стороны и 2) вектор от первой точки из сторона к точке испытания. Проверять признак результата-положительный внутри (справа) сбоку, негатив снаружи. Если он внутри ... все четыре стороны, это внутри прямоугольник. Или эквивалентно, если это снаружи любой из сторон, это снаружи прямоугольник. больше объяснений здесь.

этот метод займет 3 вычитает в вектор * раз 2 вектора на сторону, плюс один перекрестный продукт в сторону которая есть три умножения и два сложения. Одиннадцать переметнется в сторону, 44 флопс в прямоугольник.

Если вам не нравится продукт кросс , тогда вы могли бы сделать что-то вроде: выясните надписи и описанные круги для каждого прямоугольник, проверьте, если точка внутри вписанные одна. Если так, то в и прямоугольник тоже. Если нет, проверьте, если это выходит за рамки дозволенного. прямоугольник. Если да, то это за пределами и прямоугольник тоже. Если он упадет между два круга, что ты Е****D и вы нужно проверить жесткий путь.

найти, если точка находится внутри круга в 2d принимает два вычитания и два квадратуры (=умножает), а затем вы сравните расстояние в квадрате, чтобы избежать нужно сделать квадратный корень. Это 4 flops, умножить на два круга-это 8 flops - но иногда ты все равно не узнаешь. Также это предполагает, что вы не платите любое время CPU для вычисления описанные или вписанные круги, который может быть или не быть истинным в зависимости от на сколько предвычислении ты готовы сделать на вашем прямоугольнике.

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

что подводит нас к проблеме макросов. Как избежать тестирования точки против каждый прямоугольник в наборе? В 2D, это наверное quad-tree проблема. В 3d, что generic_handle сказано - восьмеричного дерева набора. С вершины моей ... head, я бы, вероятно, реализовал его как а B + дерево. Заманчиво использовать d = 5, так что каждый узел может иметь до 4-х дети, так как это так красиво карты на абстракцию четырех деревьев. Но если набор прямоугольников слишком велик, чтобы поместиться в основную память (не очень вероятно в эти дни), то с узлами тот же размер, что и дисковые блоки, вероятно путь.

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

Почему эта проблема важна? Это полезно в компьютерной графике, чтобы проверить если луч пересекает многоугольник. Т. е., это снайперская винтовка стреляла в тебя? заставила ударить человека, в которого стреляла. на? Он также используется в режиме реального времени map программное обеспечение, например, GPS-устройства. система GPS говорит вам координаты вы на, но программное обеспечение map должно найти, где эта точка находится в огромном количестве карты данные, и сделайте это несколько раз за второй.

опять кредит ModernRonin...


для прямоугольников, которые выровнены с осями, вам нужно только две точки (четыре числа), чтобы определить Прямоугольник - Обычно, нижний левый и верхний правый углы. Чтобы установить, является ли данная точка (Xтест, Yтест) перекрывается прямоугольником (XBL, YBL, XTR, YTR) путем испытания как:

  • Xтест > = XBL & & XтестTR
  • Yтест > = YBL & & YтестTR

очевидно, что для достаточно большого набора точек для тестирования это может занять довольно много времени. Вопрос в том, как оптимизировать тестирование.

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

  • Xтест > = Xмин & & Xтестмакс
  • Yтест > = Yмин & & Yтестмакс

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

однако вы также можете произвольно разбейте ограничивающую область, скажем, на четверти (по половине в каждом направлении). Затем вы будете использовать список ящиков, который будет включать больше ящиков, чем в исходном наборе (два или четыре ящика для каждого ящика, перекрывающего одну из произвольных границ). Преимущество этого заключается в том, что вы можете исключить три из четырех кварталов из поиска, сократив объем поиска, который нужно сделать в общей сложности - за счет вспомогательного хранения.

Итак, есть пространство-время компромиссы, как всегда. И предварительные вычисления против компромиссов поиска. Если вам не повезло, предварительное вычисление ничего не дает (например, есть только два ящика, и они не перекрываются ни на одной оси). С другой стороны, это может принести значительную пользу во время поиска.


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

рассмотрим проекции всех прямоугольников на базовую линию вашего пространства. Обозначим этот набор интервалов строк как

 {[Rl1, Rr1], [Rl2, Rr2],..., [Rln, Rrn]}, ordered by increasing left coordinates. 

теперь предположим, что ваша точка (x, y), начните поиск слева от этого набора, пока не достигнете интервала строки, содержащего точку x.

если нет, ваша точка (x,y) находится вне всех прямоугольников.

Если некоторые, скажем [Rlk, Rrk], ..., [Rlh, Rrh], (k

сделано.

удачи.

Джон Денер


Я предлагаю вам взглянуть на деревья BSP (и возможные quadtrees или octrees, ссылки, доступные на этой странице). Они используются для рекурсивного разделения всего пространства и позволяют быстро проверить точку, прямоугольники которой вам нужно проверить вообще.

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

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

обратите внимание на перекрывающиеся прямоугольники. Поскольку дерево BSP должно быть предварительно вычислено в любом случае, вы можете также удалить перекрытия в течение этого времени, чтобы вы могли получить четкие разделы.


ваш подход к R-дереву-лучший подход, который я знаю (это подход, который я бы выбрал над quadtrees, B+ деревьями или деревьями BSP, поскольку R-деревья кажутся удобными для построения в вашем случае). Предостережение: я не эксперт, хотя я помню несколько вещей из моего старшего курса университета алгоритмического!