Подтвердить что ты не робот

Каков наиболее эффективный способ найти пересечение линии и круга в python?

У меня многоугольник состоит из множества точек. Я хочу найти пересечение многоугольника и круга. Предоставляя центр окружности [x0, y0] и радиус r0, я написал грубую функцию, чтобы просто решить квадратичное уравнение круга и прямой. Но как насчет эффективности найти пересечение каждого отрезка многоугольника один за другим? Есть ли более эффективный способ?

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

def LineIntersectCircle(p,lsp,lep):
# p is the circle parameter, lsp and lep is the two end of the line
  x0,y0,r0 = p
  x1,y1 = lsp
  x2,y2 = esp
  if x1 == x2:
    if abs(r0) >= abs(x1 - x0):
        p1 = x1, y0 - sqrt(r0**2 - (x1-x0)**2)
        p2 = x1, y0 + sqrt(r0**2 - (x1-x0)**2)
        inp = [p1,p2]
        # select the points lie on the line segment
        inp = [p for p in inp if p[1]>=min(y1,y2) and p[1]<=max(y1,y2)]
    else:
        inp = []
  else:
    k = (y1 - y2)/(x1 - x2)
    b0 = y1 - k*x1
    a = k**2 + 1
    b = 2*k*(b0 - y0) - 2*x0
    c = (b0 - y0)**2 + x0**2 - r0**2
    delta = b**2 - 4*a*c
    if delta >= 0:
        p1x = (-b - sqrt(delta))/(2*a)
        p2x = (-b + sqrt(delta))/(2*a)
        p1y = k*x1 + b0
        p2y = k*x2 + b0
        inp = [[p1x,p1y],[p2x,p2y]]
        # select the points lie on the line segment
        inp = [p for p in inp if p[0]>=min(x1,x2) and p[0]<=max(x1,x2)]
    else:
        inp = []
  return inp
4b9b3361

Ответ 1

Я думаю, может быть, ваш вопрос в том, как теоретически делать это самым быстрым образом. Но если вы хотите сделать это быстро, вы действительно должны использовать что-то, написанное на C/С++.

Я довольно привык к Shapely, поэтому я приведу пример того, как это сделать с этой библиотекой. Для python существует множество библиотек геометрии. Я перечислил их в конце этого ответа.

from shapely.geometry import LineString
from shapely.geometry import Point

p = Point(5,5)
c = p.buffer(3).boundary
l = LineString([(0,0), (10, 10)])
i = c.intersection(l)

print i.geoms[0].coords[0]
(2.8786796564403576, 2.8786796564403576)

print i.geoms[1].coords[0]
(7.121320343559642, 7.121320343559642)

Что является немного противоположным интуитивным в Shapely, так это то, что круги являются границами точек с буферными областями. Вот почему я делаю p.buffer(3).boundry

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

Существует fooobar.com/questions/78969/..., который подробно рассказывает об этих библиотеках для заинтересованных.

ИЗМЕНИТЬ, потому что комментарии:

Shapely основан на GEOS (trac.osgeo.org/geos), который построен на С++ и значительно быстрее, чем все, что вы пишете в python. SymPy, похоже, основан на mpmath (mpmath.org), который также кажется python, но, похоже, в него встроена довольно сложная математика. Реализация этого может потребовать много работы и, вероятно, будет не так быстро, как реализация GEOS С++.

Ответ 2

Низкозатратное пространственное разбиение может состоять в том, чтобы разделить плоскость на 9 частей

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

  | |
__|_|__
__|O|__
  | |
  | |

8 интересующих нас областей окружают круг. Квадрат в центре не очень полезен для дешевого теста, но вы можете поместить квадрат r/sqrt(2) внутри круга, поэтому его углы просто касаются круга.

Давайте назовите области

A |B| C
__|_|__
D_|O|_E
  | |
F |G| H

И квадрат r/sqrt(2) в центре мы будем называть J

Назовем множество точек в центральном квадрате, показанных на диаграмме, которые не находятся в J, Z

Назовите каждую вершину многоугольника буквенным кодом.

Теперь мы можем быстро увидеть

AA => Outside
AB => Outside
AC => Outside
...
AJ => Intersects
BJ => Intersects
...
JJ => Inside

Это может превратиться в таблицу поиска

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

Ответ 3

Я думаю, что формулу, которую вы используете, чтобы найти координаты двух пересечений, не может быть оптимизирована дальше. Единственное улучшение (которое является численно важным) заключается в том, чтобы различать два случая: |x_2-x_1| >= |y_2-y_1| и |x_2-x1| < |y_2-y1|, так что величина k всегда находится между -1 и 1 (при вычислении вы можете получить очень большие числовые ошибки, если | x_2-x_1 | очень мало). Вы можете поменять местами x-s и y-s, чтобы уменьшить один случай до другого.

Вы также можете выполнить предварительную проверку: если обе оконечные точки являются внутренними по отношению к кругу, пересечение отсутствует. Вычисляя квадрат расстояния от точек до центра круга, это становится простой формулой, которая не использует функцию квадратного корня. Другая проверка: "ли линия вне круга" уже реализована в вашем коде и соответствует delta < 0. Если у вас много мелких сегментов, в большинстве случаев эти две проверки должны дать короткий ответ (без перекрестка).