Первый способ, который мне приходит в голову, - это проверить каждую пару из трех из [node_a, node_b, wall_start, wall_end]
и посмотреть, проходит ли третья точка вдоль отрезка между двумя другими. Быстрый и точный способ сделать это - сначала создать вектор между каждой из точек и взять два точечных произведения, чтобы убедиться, что «средняя» точка действительно лежит в середине. Кроме того, необходимо также проверить направление векторов, чтобы убедиться, что они параллельны, что одинаково быстро. Если оба пройдут, то третья точка лежит вдоль отрезка между двумя другими.
В питоне
def intersect(a, b, c):
(ax, ay), (bx, by), (cx, cy) = a, b, c
bax, bay = bx-ax, by-ay
bcx, bcy = bx-cx, by-cy
acx, acy = ax-cx, ay-cy
if bax*bcx + bay*bcy < 0: return False
if bax*acx + bay*acy > 0: return False
return bax*bcy == bay*bcx
На практике, возможно, лучше сначала проверить bax*bcy == bay*bcx
, поскольку он такой же быстрый, но, скорее всего, скорее всего потерпит неудачу (и рано сломается) для непересекающихся точек.
Чтобы затем проверить, пересекаются ли какие-либо две точки с данной стеной-
def wall_hit(node1, node2, wall_start, wall_end):
return intersect(node1, node2, wall_start) or \
intersect(node1, node2, wall_end) or \
intersect(wall_start, wall_end, node1) or \
intersect(wall_start, wall_end, node2)
Поскольку большинство проверок будут эффективно "закорачиваться" после первой или второй проверки в каждом вызове intersect()
, и каждый wall_hit()
будет закорачивать, если какая-либо из них попадет, я не думаю, что это было бы слишком дорого для реализации.
Если вам нужно оптимизировать его, вы всегда можете вычислить + повторно использовать вычисления bax, bay = bx-ax, by-ay; ...
, либо вставляя все вызовы функций и переупорядочивая их, либо вычисляя их в отдельной функции, а затем кэшируя с помощью декоратора lru_cache
из functools
. Кроме того, если вы используете метод встраивания, вы, вероятно, можете изменить порядок условных выражений и bax, bay = ...
вычислений, чтобы лениво оценивать их, так что вам может не понадобиться вычислять все промежуточные значения для утверждения hit / no_hit.