Как рассчитать угол вектора от вертикали? - PullRequest
10 голосов
/ 09 августа 2010

Я пытаюсь выяснить угол (в градусах) между двумя 2D векторами. Я знаю, что мне нужно использовать триг, но я не слишком хорош в этом. Это то, что я пытаюсь решить (ось Y увеличивается вниз): альтернативный текст http://i38.tinypic.com/2dcefch.png

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

private float calcAngle(float x, float y, float x1, float y1)
{
    float _angle = (float)Math.toDegrees(Math.atan2(Math.abs(x1-x), Math.abs(y1-y)));
    Log.d("Angle","Angle: "+_angle+" x: "+x+" y: "+y+" x1: "+x1+" y1: "+y1);
    return _angle;
}

Это мои результаты (константа при предоставлении постоянной позиции, но когда я меняю позицию, угол меняется, и я не могу найти никакой связи между двумя углами):

Позиция 1: х: 100 у: 100 х1: 50 у1: 50 Угол обзора: 45

Позиция 2: х: 92 у: 85 х1: 24 у1: 16 Угол обзора: 44,58

Позиция 3: х: 44 у: 16 х1: 106 у1: 132 Угол: 28.12

Редактировать: Спасибо всем, кто ответил и помог мне понять, что это неправильно! Извините, заголовок и вопрос сбивают с толку.

Ответы [ 9 ]

15 голосов
/ 09 августа 2010

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

  1. Дано v1 и v2 , их точечное произведение равно: v1x * v2x + v1y * v2y
  2. Норма вектора v задается как: sqtr (vx ^ 2 + vy ^ 2)

С этой информацией, пожалуйста, примите это определение:

dot(v1, v2) = norm(v1) * norm(v2) * cos(angle(v1, v2))

Теперь вы решаете за angle(v1, v2):

angle(v1, v2) = acos( dot(v1, v2) / (norm(v1) * norm(v2)) )

Наконец, взяв определения, данные в начале, вы получите:

angle(v1, v2) = acos( (v1x * v2x + v1y * v2y) / (sqrt(v1x^2+v1y^2) * sqrt(v2x^2+v2y^2)) )

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

Ответ будет в радианах, но вы знаете, что радианы пи (то есть 3,14 радиана) равны 180 градусам, поэтому вы просто умножаете на коэффициент преобразования 180 / пи.

13 голосов
/ 09 августа 2010

Aha!Оказывается, мне просто нужно было изменить угол и использовать atan2.Это мой окончательный код:

private float calcAngle(float x, float y, float x1, float y1)
{
    float _angle = (float)Math.toDegrees(Math.atan2(x1-x, y-y1));
    return _angle;
}

Спасибо всем, кто помог мне разобраться в этом, а также за то, что помог мне понять, что я на самом деле делаю!:)

5 голосов
/ 09 августа 2010

Не принимайте абсолютное значение аргументов до atan2. Весь смысл atan2 в том, что он использует знаки своих аргументов, чтобы определить, в каком квадранте находится угол. Взяв абсолютные значения, вы заставляете atan2 возвращать значения только от 0 до pi / 2 вместо - пи в пи.

2 голосов
/ 09 августа 2010

Похоже, Найл понял это, но я все равно закончу объяснение.В дополнение к объяснению, почему решение работает, мое решение имеет два преимущества:

  • Избегание деления потенциала на ноль в atan2 ()
  • Возвращаемое значение всегдаположительное в диапазоне от 0 до 360 градусов

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

Следующая функция адаптирована из моей игры астероидов, где я хотелчтобы вычислить направление, на которое судно / вектор скорости "указывал":

// Calculate angle between vector from (x1,y1) to (x2,y2) & +Y axis in degrees.
// Essentially gives a compass reading, where N is 0 degrees and E is 90 degrees.

double bearing(double x1, double y1, double x2, double y2)
{
    // x and y args to atan2() swapped to rotate resulting angle 90 degrees
    // (Thus angle in respect to +Y axis instead of +X axis)
    double angle = Math.toDegrees(atan2(x1 - x2, y2 - y1));

    // Ensure result is in interval [0, 360)
    // Subtract because positive degree angles go clockwise
    return (360 - angle) %  360;
}
1 голос
/ 09 августа 2010

Я считаю, что уравнение для угла между двумя векторами должно выглядеть примерно так:

toDegrees(acos((x*x1+y*y1)/(sqrt(x*x+y*y)*sqrt(x1*x1+y1*y1))))

Вышеупомянутое уравнение вычислит угол между вектором p1-p2 и линией, проведенной путем расширения ортогональной точки p2 к вектору p1.

Точечное произведение двух векторов V1 и V2 равно | V1 | * | V2 | cos (тета). Следовательно, тета равен acos ((V1 точка V2) / (| V1 | | V2 |)). Точка V1 V2 - это V1.x V2.x + V1.y V2.y. Величина V (т. Е. | V |) является патогорейской теоремой ... sqrt (V.x ^ 2 + V.y ^ 2)

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

Угол второго вектора относительно первого = atan2(y2,x2) - atan2(y1,x1).

http://www.euclideanspace.com/maths/algebra/vectors/angleBetween/index.htm

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

Моим первым предположением было бы вычислить угол каждого вектора с осями, используя atan (y / x), а затем вычесть этих ангелов и принять абсолютное значение, а именно:

abs (atan (y)/ х) - атан (у1 / х1))

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

Вы используете целые числа?Приведите аргументы как двойные, и я буду использовать fabs для результата, а не аргументов.Результат будет в радианах;для получения степеней используйте:

res * = (360.0 / (2.0 * Math.PI));

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

Должно быть:

atan( abs(x1 - x)/abs(y1 - y) ) 

abs обозначает абсолют (чтобы избежать отрицательных значений)

...