Программа для поиска пересечения отрезка и кривой Безье - PullRequest
0 голосов
/ 02 мая 2018

Рассмотрим данное изображение футбольного поля

enter image description here

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

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

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

если да, то как преобразовать кривую Безье в уравнение для лучшего решения

с учетом заданного как

beizer curve eqaution -> a(x*x) + b*x + c
and line segment equation -> y = y1 + m(x-x1)

// maxCurvedPoint является самой верхней частью кривой

var getIntersectionPoint = function (room, ballFromPosition, ballToPosition, maxCurvePoint) 
{
    var linepoints = [[m1,n1], [m2, n2], [m3, n3], [m4, n4]];

    //converting three points(ballFromPosition, maxCurvePoint, ballToPosition) into the quadratic equation (Bezier curve) --(1)
    //getting the equation of the line segment using the linepoints --(2)

    //equating (1) and (2) and getting a quadratic equation and solving and finding intersection points
    return intersectionPoint;
}

// solves //(-b(+-)sqrt(b*b - 4ac)/2ac)
function solve(a, b, c) 
{        
 //check curve intersects line or not
   if((Math.pow(b, 2) - (4 * a * c)) >= 0) 
   {
       result1 = (-1 * b + Math.sqrt(Math.pow(b, 2) - (4 * a * c))) / (2 * a);
       result2 = (-1 * b - Math.sqrt(Math.pow(b, 2) - (4 * a * c))) / (2 * a);
       return [result1, result2];
   } 

   return [];
}

Может ли кто-нибудь помочь мне с этим? Также разве самая кривая точка может называться вершиной кривой?

Ответы [ 2 ]

0 голосов
/ 02 мая 2018

Если перевести и повернуть все конечные точки таким образом, чтобы отрезок линии стал (0, 0)-(d, 0), проблема упрощается.

Пусть контрольными точками будут (Xk, Yk), k= 0, 1, 2. Пересечения с осью X получаются путем решения для t квадратного уравнения

Y0 (1-t)² + 2 Y1 t(1-t) + Y2 t² = 0.

Соответствующие абсциссы даны

X0 (1-t)² + 2 X1 t(1-t) + X2 t² = 0.

Вы можете проверить, относятся ли они к интервалу [0, d]. Затем примените обратное вращение и перевод.


Приложение: пересечение двух квадратичных Безье

Векторное уравнение одной из кривых можно записать

P = P0 (1 - t)² + 2 P1 t (1 - t) + P2 t²
  = P0 + 2 (P1 - P0) t + (P0 - 2 P1 + P2) t².

Если применить аффинное изменение координат так, чтобы система отсчета стала (P0, P1 - P0, P0 - 2 P1 + P2), уравнение упрощается до

X = 2t
Y = t²

которое является неявным уравнением

X² = 4Y.

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

Существуют формулы замкнутой формы для корней квартического уравнения, и их может быть четыре. После выбора действительных корней в [0, 1], вы оцениваете параметр t первой кривой, а также проверяете членство в [0, 1].

Не забудьте восстановить исходные координаты.

0 голосов
/ 02 мая 2018

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


1. Представление кривой + тест пересечения

Рассмотрим квадратичную кривую Безье с конечными точками A, C, контрольной точкой B и параметром t:

image

enter image description here

И бесконечная линия с источником O, направлением D и параметром s:

enter image description here

Приравнивая P и R, получим пару квадратичных одновременных уравнений, которые можно переставить так, чтобы исключить s и найти параболический параметр t:

enter image description here

Решите это квадратное уравнение для t, и принимайте только реальные корни в диапазоне [0, 1]. Это гарантирует, что любая точка пересечения будет всегда на самом сегменте.


2. Работа с отрезками

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


3. Вычисление контрольной точки B

Обратите внимание, что общее значение контрольной точки B не даст симметричную параболу. Чтобы вычислить B для общей симметричной кривой:

enter image description here

Определение переменных:

  • M: средняя точка AB
  • n: по часовой стрелке, нормальный в направлении AC
  • q: расстояние до выпуклости со знаком - абсолютное значение - это расстояние от M до средней точки кривой
  • k: расстояние от M до B

enter image description here

Удивительно простой результат.


4. Пример кода C # (стиль)

public static Vector2[] computeIntersection
(
   Vector2 A, Vector2 C, double q,    // parabola segment
   Vector2 O, Vector2 P               // line segment
)
{
   // quadratic solve
   double[] solve(double a, double b, double c)
   {
      double d = b * b - 4.0 * a * c;
      if (d < 0.0) // imaginary roots - no intersection at all
         return null;

      if (d > 0.0) // two distinct real roots
      {
         double sd = Math.Sqrt(d);
         return new double[2] { (-b + sd) / (2.0 * a),
                                (-b - sd) / (2.0 * a) };
      }
      else // only one (line segment is tangent to curve)
      {
         return new double[1] { -b / (2.0 * a) };
      }
   }

   // cross product (in-case undefined)
   double cross(Vector2 i, Vector2 j)
   {
      return i.x * j.y - i.y * j.x;
   }

   // validity check for t and s
   bool valid(double v)
   {
      return (v >= 0.0) && (v <= 1.0);
   }

   // compute control point B
   Vector2 E = C - A;
   Vector2 M = 0.5 * (A + C);
   Vector2 N = (new Vector2(E.y, -E.x)).normalize();
   Vector2 B = M + (2.0 * q) * N;

   // solving for t
   Vector2 D = P - O;
   bool useX = Math.Abs(D.X) > Math.Abs(D.Y);
   double[] T = solve(cross(A + C - 2.0 * B, D),
                      cross(B - A, D) * 2.0,
                      cross(A - O, D));
   if (T == null) return null;

   Vector2[] I = new Vector2[2];
   int c = 0;

   for (int i = 0; i < T.Length; i++)
   {
      // check if t is within curve range
      double t = T[i];
      if (!valid(t)) continue;

      // solve for s and check if is within line range
      double u = (1 - t) * (1 - t);
      double v = 2 * t * (1 - t);
      double w = t * t;
      double s = useX ? ((u * A.X + v * B.X + w * C.X - O.X) / D.X)
                      : ((u * A.Y + v * B.Y + w * C.Y - O.Y) / D.Y);
      if (!valid(s)) continue;

      // compute the corresponding intersection point
      I[c++] = O + s * D;
   }

   // only return valid solutions
   if (c == 0) return null;
   Array.Resize(ref I, c);
   return I;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...