Как вычислить угол вектора от вертикали?

Я пытаюсь выяснить угол (в градусах) между двумя 2D векторами. Я знаю, что мне нужно использовать триг, но я не слишком хорош в этом. Это то, что я пытаюсь решить (ось Y увеличивается вниз): alt text

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

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

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

10
задан Glorfindel 5 August 2019 в 13:12
поделиться

9 ответов

Ага! Оказывается, мне просто нужно было перевернуть угол и использовать 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;
}

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

13
ответ дан 3 December 2019 в 14:10
поделиться

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

  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))

Теперь вы решаете для угол (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 / пи.

15
ответ дан 3 December 2019 в 14:10
поделиться

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

  • Отсутствует возможное деление на ноль внутри 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;
}
2
ответ дан 3 December 2019 в 14:10
поделиться

Должно быть:

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

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

0
ответ дан 3 December 2019 в 14:10
поделиться

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

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 (theta). Следовательно, theta равно acos ((V1 dot V2) / (| V1 | | V2 |)). V1 точка V2 - это V1.x V2.x + V1.y V2.y. Величина V (то есть | V |) - это патогорейская теорема ... sqrt (V.x ^ 2 + V.y ^ 2)

1
ответ дан 3 December 2019 в 14:10
поделиться

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

abs (атан (y / x) - атан (y1 / x1))

0
ответ дан 3 December 2019 в 14:10
поделиться

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

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

0
ответ дан 3 December 2019 в 14:10
поделиться

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

5
ответ дан 3 December 2019 в 14:10
поделиться

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

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

0
ответ дан 3 December 2019 в 14:10
поделиться
Другие вопросы по тегам:

Похожие вопросы: