Редактировать: Комментарий ОП скептически относился к эффективности предлагаемой проверки отрицательной круговой границы для улучшения алгоритма, чтобы проверить, находится ли произвольная 2D-точка в повернутом и / или движущемся прямоугольнике. Немного покопавшись в моем 2D игровом движке (OpenGL / C ++), я дополняю свой ответ, предоставляя тест производительности моего алгоритма по сравнению с текущими алгоритмами проверки точки-прямоугольника ОП (и их вариациями).
Первоначально я предложил оставить алгоритм на месте (так как он почти оптимален), но упростил с помощью простой игровой логики: (1) использование предварительно обработанного круга вокруг исходного прямоугольника; (2) сделать проверку расстояния и находится ли точка в заданном круге; (3) использовать OP или любой другой простой алгоритм (я рекомендую алгоритм isLeft, как указано в другом ответе). Логика, лежащая в основе моего предложения, заключается в том, что проверка, находится ли точка внутри круга, значительно эффективнее, чем проверка границы повернутого прямоугольника или любого другого многоугольника.
Мой первоначальный сценарий для теста производительности состоит в том, чтобы запустить большое количество появляющихся и исчезающих точек (чье положение меняется в каждом игровом цикле) в ограниченном пространстве, которое будет заполнено примерно 20 вращающимися / движущимися квадратами. Я опубликовал видео ( ссылка на YouTube ) в целях иллюстрации. Обратите внимание на параметры: количество случайно появляющихся точек, число или прямоугольники. Я сравню со следующими параметрами:
OFF : простой алгоритм, предоставляемый OP, без отрицательных проверок границы круга
НА : использование обработанных (граничных) окружностей вокруг прямоугольников в качестве первой проверки исключения
ON + Стек : создание круговых границ во время выполнения в цикле в стеке
ON + квадратное расстояние : использование квадратного расстояния в качестве дополнительной оптимизации, чтобы избежать использования более дорогого алгоритма квадратного корня (Pieter Geerkens).
Вот краткое изложение различных характеристик различных алгоритмов, показывающее время, необходимое для итерации цикла.
Ось X показывает повышенную сложность, добавляя больше точек (и таким образом замедляя цикл). (Например, при 1000 случайно появляющихся точечных проверках в конфиденциальном пространстве с 20 прямоугольниками цикл повторяется и вызывает алгоритм 20000 раз.) Ось Y показывает время (мс), необходимое для завершения всего цикла с использованием высокого разрешения Таймер производительности. Более 20 мс было бы проблематично для приличной игры, так как для интерполяции плавной анимации не использовались бы высокие fps, и игра иногда могла бы выглядеть таким образом «бурной».
Результат 1 : Предварительно обработанный алгоритм с круговой границей с быстрой отрицательной проверкой в цикле повышает производительность на 1900% по сравнению с обычным алгоритмом (5% от исходного времени цикла без проверки). Результат примерно пропорционален числу итераций в цикле, поэтому не имеет значения, проверяем ли мы 10 или 10000 случайно появляющихся точек. Таким образом, на этой иллюстрации можно безопасно увеличить количество объектов до 10 тыс. Без потери производительности.
Результат 2 : В предыдущем комментарии было высказано предположение, что алгоритм может быть быстрее, но интенсивнее использовать память. Однако обратите внимание, что сохранение числа с плавающей запятой для предварительно обработанного размера круга занимает всего 4 байта. Это не должно создавать никаких проблем, если ОП не планирует запускать одновременно более 100 000 объектов. Альтернативный и эффективный подход к памяти заключается в том, чтобы вычислить максимальный размер круга в стеке в цикле и позволить ему выходить из области действия при каждой итерации и, таким образом, практически не использовать память при неизвестной цене скорости. Действительно, результат показывает, что этот подход действительно медленнее, чем использование предварительно обработанного размера круга, но он все еще показывает значительное улучшение производительности примерно на 1150% (т.е. 8% от первоначального времени обработки).
Результат 3 : я дополнительно улучшаю алгоритм результата 1, используя квадратные расстояния вместо реальных расстояний и, таким образом, используя вычислительно дорогую операцию квадратного корня. Это лишь незначительно повышает производительность (2400%). (Примечание: я также пробую хеш-таблицы для предварительно обработанных массивов для приближений квадратных корней с похожим, но немного худшим результатом)
Результат 4 : я также проверяю перемещение / столкновение прямоугольников вокруг; однако это не меняет основных результатов (как и ожидалось), поскольку логическая проверка остается практически неизменной.
Результат 5 : я изменяю количество прямоугольников и нахожу, что алгоритм становится тем эффективнее, чем меньше переполнено пространство (не показано в демонстрации). Результат также несколько ожидаем, поскольку вероятность появления точки в крошечном пространстве между кругом и границами объекта уменьшается. С другой стороны, я пытаюсь увеличить количество прямоугольников слишком на 100 в одном и том же ограниченном крошечном пространстве и динамически изменять их размер во время выполнения внутри цикла (sin (итератор)). Это все еще работает очень хорошо с увеличением производительности на 570% (или 15% от первоначального времени цикла).
Результат 6 : я тестирую альтернативные алгоритмы, предложенные здесь, и нахожу очень небольшую, но незначительную разницу в производительности (2%). Интересный и более простой алгоритм IsLeft работает очень хорошо с повышением производительности на 17% (85% от первоначального времени расчета), но далеко от эффективности алгоритма быстрой отрицательной проверки.
Моя цель - сначала рассмотреть бережливый дизайн и игровую логику, особенно когда речь идет о границах и столкновениях. Текущий алгоритм OP уже достаточно эффективен, и дальнейшая оптимизация не так важна, как оптимизация самой концепции. Более того, хорошо сообщить объем и цель игры, так как эффективность алгоритма критически зависит от них.
Я предлагаю всегда пытаться тестировать любой сложный алгоритм на этапе разработки игры, поскольку простое рассмотрение простого кода может не раскрыть правду о фактической производительности во время выполнения. Предложенный алгоритм может даже не понадобиться здесь, если, например, кто-то хочет просто проверить, находится ли курсор мыши внутри прямоугольника или нет, или когда большинство объектов уже касаются. Если большинство проверок точек находятся внутри прямоугольника, алгоритм будет менее эффективным. (Однако тогда можно было бы установить границу «внутреннего круга» как вторичную отрицательную проверку.) Проверка границ круга / сферы очень полезна для любого приличного обнаружения столкновений большого числа объектов, которые, естественно, имеют некоторое пространство между ними. ,
Rec Points Iter OFF ON ON_Stack ON_SqrDist Ileft Algorithm (Wondra)
(ms) (ms) (ms) (ms) (ms) (ms)
20 10 200 0.29 0.02 0.04 0.02 0.17
20 100 2000 2.23 0.10 0.20 0.09 1.69
20 1000 20000 24.48 1.25 1.99 1.05 16.95
20 10000 200000 243.85 12.54 19.61 10.85 160.58