Точечный и эллиптический (повернутый) позиционный тест: алгоритм

Как проверить, находится ли точка P = [xp, yp] внутри/вне некоторого повернутого эллипса, заданного центром C = [x, y], a, b и phi (угол поворота)?

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

Но есть много проверенных точек (тысяч), и я нахожу это решение медленным. Есть ли прямой и эффективный способ получить положение повернутого эллипса и точки?

Мне не нужен код, кроме алгоритма. Благодарим за помощь.

Ответ 1

Другой вариант - просто выбросить все в уравнение для двумерного повернутого эллипса и посмотреть, не меньше ли результат.

Итак, точка находится внутри эллипса, если верно следующее неравенство

ellipse equation

Где (xp, yp) - координаты точки, а (x0, y0) - центр эллипса.

Я реализовал небольшую программу Mathematica, демонстрирующую, что это действительно работает: Manipulate screen shot

Здесь он находится в действии:

Animation

И вот код:

ellipse[x_, y_, a_, b_, \[Alpha]_, x0_: 0, y0_: 0] := 
     (((x - x0)*Cos[\[Alpha]] + (y - y0)*Sin[\[Alpha]])/a)^2
   + (((x - x0)*Sin[\[Alpha]] - (y - y0)*Cos[\[Alpha]])/b)^2;

Manipulate[
 RegionPlot[
  ellipse[x, y, a, b, \[Alpha] \[Degree], Sequence @@ pos] < 1, {x, -5, 5}, {y, -5, 5}, 
  PlotStyle -> If[ellipse[Sequence @@ p, a, b, \[Alpha] \[Degree], Sequence @@ pos] <= 1, Orange, LightBlue], 
  PlotPoints -> 25]
, {{a, 2}, 1, 5, Appearance -> "Labeled"}
, {{b, 4}, 2, 5, Appearance -> "Labeled"}
, {\[Alpha], 0, 180,  Appearance -> "Labeled"}
, {{p, {3, 1}}, Automatic, ControlType -> Locator}
, {{pos, {0, 0}}, Automatic, ControlType -> Locator}]

Ответ 2

Вы можете просто подавать свои данные в формулу, указанную выше. Вот реализация python, которую я сделал по рекомендациям Ajasja:

def pointInEllipse(x,y,xp,yp,d,D,angle):
    #tests if a point[xp,yp] is within
    #boundaries defined by the ellipse
    #of center[x,y], diameter d D, and tilted at angle

    cosa=math.cos(angle)
    sina=math.sin(angle)
    dd=d/2*d/2
    DD=D/2*D/2

    a =math.pow(cosa*(xp-x)+sina*(yp-y),2)
    b =math.pow(sina*(xp-x)-cosa*(yp-y),2)
    ellipse=(a/dd)+(b/DD)

    if ellipse <= 1:
        return True
    else:
        return False

Ответ 3

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

Если вы видите эллипс как единичный круг (радиус 1), масштабированный (a, b), повернутый на phi и преобразованный (x, y), то жизнь становится намного проще. Если у вас есть эта матрица преобразования, вы можете использовать ее для упрощения запроса на сдерживание. Если вы преобразуете точку в координатную систему, где эллипс является единичным кругом, все, что вам нужно сделать, - это тест окружности в виде единицы измерения, который тривиален. Если "transform" - это матрица, которая преобразует единый круг в ваш эллипс, как описано, тогда

transformedPoint = transform.Invert().Transform(point);
pointInEllipse = transformedPoint.DistanceTo(0,0) < 1.0;

Ответ 4

Вот алгоритм, я позволю вам разработать код:

  • Определите вектор v1 между центром эллипса и вашей точкой.
  • Определить угол a1 между вектором v1 и осью x в мировых координатах
  • Substract phi из a1, чтобы получить a2, наш векторный угол в локальных координатах
  • Определите точку P2 на эллипсе под углом a2 в локальных координатах, а не смещен на (x, y)
  • Вычислите L1 и L2, длину вектора a1 и a2

Оценка:

  • Если L1 < L2 точка находится внутри
  • Если L1 = L2 (плюс/минус небольшой допуск), точка находится на эллипсе
  • Если L2 > L2, то точка находится вне

Эллиптическая параметрическая формула:

x = a * cos (u)
y = b * sin (u)

действует для u между -pi и + pi. Добавьте phi в u, чтобы повернуть ваш эллипс.

Алгоритм выше может быть упрощен и оптимизирован из уравнений эллипса.

Удачи!

Ответ 5

Matplotlib имеет метод Ellipse в классе патчей, который позволяет задать вопрос, находится ли точка внутри или вне патча. Проверьте здесь и найдите метод contains_point(). Вам нужно будет создать эллипс с классом Ellipse, а затем, как будто внутри есть точка. BTW, matplotlib - это пакет для python.