Пересечение параболической кривой и отрезка - PullRequest
4 голосов
/ 31 августа 2010

У меня есть уравнение для параболической кривой, пересекающей заданную точку, в моем случае, когда пользователь нажимал на график.

 // this would typically be mouse coords on the graph
 var _target:Point = new Point(100, 50);

 public static function plot(x:Number, target:Point):Number{
  return (x * x) / target.x * (target.y / target.x);
 }

Это дает такой график:

parabolic curve

У меня также есть ряд отрезков, определяемых начальными и конечными координатами:

startX:Number, startY:Number, endX:Number, endY:Number

Мне нужно выяснить, пересекает ли эта кривая эти сегменты (A):

alt text

Если это поможет, startX всегда < endX

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

ОБНОВЛЕНИЕ:

У меня работает пересечение, но мое решение дает мне координату для неправильной стороны оси Y.

Замена моих целевых координат на A и B соответственно дает следующее уравнение для графика:

(x * x) / A * (B/A)

// this simplifies down to:
(B * x * x) / (A * A)

// which i am the equating to the line's equation
(B * x * x) / (A * A) =  m * x + b

// i run this through wolfram alpha (because i have no idea what i'm doing) and get:
(A * A * m - A * Math.sqrt(A * A * m * m + 4 * b * B)) / (2 * B)

Этот является правильным ответом, но я хочу второй возможныйизменение.Мне удалось исправить это, умножив m на -1 перед вычислением и выполнив то же самое со значением x, которое возвращает последний расчет, но это похоже на взлом.

РЕШЕНИЕ:

 public static function intersectsSegment(targetX:Number, targetY:Number, startX:Number, startY:Number, endX:Number, endY:Number):Point {
  // slope of the line
  var m:Number = (endY - startY) / (endX - startX);

  // where the line intersects the y-axis
  var b:Number = startY - startX * m;

  // solve the two variatons of the equation, we may need both
  var ix1:Number = solve(targetX, targetY, m, b);
  var ix2:Number = solveInverse(targetX, targetY, m, b);

  var intersection1:Point;
  var intersection2:Point;

  // if the intersection is outside the line segment startX/endX it's discarded
  if (ix1 > startX && ix1 < endX) intersection1 = new Point(ix1, plot(ix1, targetX, targetY));
  if (ix2 > startX && ix2 < endX) intersection2 = new Point(ix2, plot(ix2, targetX, targetY));

  // somewhat fiddly code to return the smallest set intersection
  if (intersection1 && intersection2) {
   // return the intersection with the smaller x value
   return intersection1.x < intersection2.x ? intersection1 : intersection2;
  } else if (intersection1) {
   return intersection1;
  }

  // this effectively means that we return intersection2 or if that's unset, null
  return intersection2;
 }

 private static function solve(A:Number, B:Number, m:Number, b:Number):Number {
  return (m + Math.sqrt(4 * (B / (A * A)) * b + m * m)) / (2 * (B / (A * A)));
 }

 private static function solveInverse(A:Number, B:Number, m:Number, b:Number):Number {
  return (m - Math.sqrt(4 * (B / (A * A)) * b + m * m)) / (2 * (B / (A * A)));
 }

 public static function plot(x:Number, targetX:Number, targetY:Number):Number{
  return (targetY * x * x) / (targetX * targetX);
 }

Ответы [ 4 ]

6 голосов
/ 31 августа 2010

Или, более явно пока.

Если ваша параболическая кривая равна y(x)= A x<sup>2</sup>+ B x + C (Eq 1)</p> <p>

, а ваша линия равна y(x) = m x + b (Eq 2)

Два возможных решения (+ и -) для x:

x = ((-B + m +- Sqrt[4 A b + B^2 - 4 A C - 2 B m + m^2])/(2 A))   (Eq 3)

Вы должны проверить, содержит ли конечная точка вашего сегмента (в х) любую из этих двух точек.Если это так, просто замените соответствующий x в уравнении y = mx + b, чтобы получить координату y для пересечения

Редактировать>

Чтобы получить последнее уравнениеВы просто говорите, что «у» в уравнении 1 равно «у» в уравнении 2 (потому что вы ищете пересечение!).Это дает вам:

A x<sup>2</sup>+ B x + C = m x + b<br>

и перегруппировку

A x<sup>2</sup>+ (B-m) x + (C-b) = 0<br>
Что является квадратным уравнением.

Уравнение 3 - это простодва возможных решения для этого квадратичного.

Edit 2>

перечитывая ваш код, кажется, что ваша парабола определяется как y(x) = A x<sup>2</sup><br>

где
A = (target.y / (target.x)<sup>2</sup>) </p> <p>

Таким образом, в вашем случае уравнение 3 становится просто

 x = ((m +- Sqrt[4 A b + m^2])/(2 A))   (Eq 3b)  

HTH!

3 голосов
/ 31 августа 2010

Делаете ли вы это достаточно часто, чтобы провести отдельный тест, чтобы увидеть, существует ли пересечение, прежде чем вычислять точку пересечения?Если это так, учтите тот факт, что ваша парабола является уровнем, установленным для функции f (x, y) = y - (B * x * x) / (A * A), в частности, той, для которой f (x,y) = 0. Подключите ваши две конечные точки к f (x, y) - если они имеют одинаковый знак, они находятся на одной стороне параболы, а если они имеют разные знаки, они находятся на разных сторонахпарабола.

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

3 голосов
/ 31 августа 2010

Возьмите уравнение для кривой и поместите вашу линию в форму y = mx + b.Решите для x и затем определите, находится ли X между вашей начальной и конечной точками для вашего отрезка.

Проверьте: http://mathcentral.uregina.ca/QQ/database/QQ.09.03/senthil1.html

0 голосов
/ 31 августа 2010

Другими словами, вам нужно вычислить уравнение для каждого отрезка y = Ax + B, сравнить его с уравнением кривой y = Cx^2 + Dx + E, поэтому Ax + B - Cx^2 - Dx - E = 0 и посмотреть, есть ли решение между значениями startX и endX. 1006 *

...