Попытка вычислить разницу между двумя углами (atan2)

Atan2(y,x) вернет число с плавающей запятой между -pi и pi. Я хочу вычислить расстояние между двумя углами, но прерывность сбивает меня с толку.

См. это для лучшего понимания.

Я хочу иметь возможность рассчитать расстояние между углом 1 и углом 2.

Весь смысл в том, чтобы иметь возможность создать конус от центра до заданного угла. По сути, я буду оценивать:

if(DistanceFromAngle1 < pi/4 [45°])
{
  Angle2 is part of cone
}

person ATD    schedule 25.01.2013    source источник
comment
Как движение против часовой стрелки из верхнего левого квадранта в нижний левый квадрант переходит от положительного к отрицательному, не пересекая 0. (Тем не менее, движение по часовой стрелке будет отрицательным, 0, положительным.)   -  person ATD    schedule 25.01.2013
comment
Ах. Я понимаю. Это был бы простой расчет, если бы вы сначала перевели в градусы.   -  person Sam Axe    schedule 25.01.2013
comment
Под расстоянием вы подразумеваете прямую линию, соединяющую две точки пересечения?   -  person António Almeida    schedule 25.01.2013
comment
@ Dan-o Как было бы проще в градусах? Вы все равно получите прыжок с -179, 180/-180, 179... или 359 360/0, 1   -  person ATD    schedule 25.01.2013
comment
@ToniAlmeida - я имею в виду наименьший угол между двумя углами. Таким образом, разница в вращении между Angle1 = -3pi/4 и Angle2 = 3pi/4 должна быть pi/2, а не 3pi/2.   -  person ATD    schedule 25.01.2013
comment
@ATD: см. мой ответ ниже   -  person Sam Axe    schedule 25.01.2013


Ответы (6)


Если под расстоянием вы подразумеваете прямую линию, соединяющую две точки пересечения, вы можете рассчитать расстояние, выполнив следующие действия:

SQRT( ( ABS|cos(A) - cos(B)| )^2 + ( ABS|sin(A) - sin(B)| )^2 )

SQRT = квадратный корень

АБС = абсолютное значение

Если расстояние представляет собой угол, вы вычисляете его, выполняя (псевдокод)

var angle = ABS(A - B)
if(angle > pi) angle = 2*pi - angle
return angle
person António Almeida    schedule 25.01.2013

π/2 равно 90°, а не 45°. Я предполагаю, что вы хотите знать, находится ли Угол 2 в интервале с центром вокруг Угла 1, который простирается на 45° от него в обоих направлениях.

Вы можете взять разницу между углом 2 и углом 1 и уменьшить по модулю 2π, пока разница не будет равна [-π, π). Это даст расстояние со знаком между углом 2 и углом 1. Затем проверьте, находится ли он в (-π/4, π/4). Поскольку значение, возвращаемое atan2, всегда находится между -π и π, исходная разница всегда будет между -2π и 2π, так что вы можете объединить все это в одну проверку:

 if (angle2 - angle1 < -7π/4 || 
     (angle2 - angle1 > -π/4 && angle2 - angle1 < π/4) ||
     angle2 - angle1 > 7π/4)
 {
   angle2 is less than 45° away from angle1
 }
person David Moews    schedule 25.01.2013

Два варианта расчета разницы углов:

procedure TForm1.sButton1Click(Sender: TObject);
Var a, b, dif : Extended;
begin
  a := sCalcEdit1.Value;
  b := sCalcEdit2.Value;
  If ((a < 180) and (b >= 180) or
      (a >= 180) and (b < 180)) and (abs(a - b) < 180)  then
  Begin
  End else
  If (a < 180) and (b >= 180) then
  Begin
    b := b - 360;
  End else
  If ((a >= 180) and (b < 180)) then
  Begin
    a := a - 360;
  End;
  dif := abs(a - b);
  sCalcEdit3.Value := dif;
end;

procedure TForm1.sButton2Click(Sender: TObject);
Var a, b, dif : Extended;
begin
  a := sCalcEdit1.Value * pi / 180;
  b := sCalcEdit2.Value * pi / 180;
  dif := arccos(cos(a - b));
  sCalcEdit3.Value := dif * 180 / pi;
end;
person Shamr    schedule 29.03.2021

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

Учитывая два нормализованных вектора, a и b, угол между ними просто становится acos(dot(a, b)) = acos(ax*bx + ay*by).

Чтобы получить нормализованный вектор из угла, alpha, вы можете использовать, например, a = vec2(cos(alpha), sin(alpha)).

Чтобы нормализовать денормальный вектор, используйте na = a / length(a) = a / sqrt(dot(a, a)).

person rasmus    schedule 25.01.2013
comment
Что такое точка? Это на С#? - person ATD; 25.01.2013
comment
Dot — это скалярное произведение двух векторов: dot(a, b) = ax*bx + ay*by, если a = (ax, ay) и b = (bx, by). - person rasmus; 25.01.2013
comment
Ах хорошо. Только что нашел. Спасибо! - person ATD; 25.01.2013

РЕДАКТИРОВАТЬ: я не уверен, что это сработает. Я перевел его из кода Python, но не уверен, что divmod(radians, math.pi*2)[1] ведет себя так же, как System.Math.IEEERemainder(radians, Math.PI*2.0). Нужно протестировать...

EDIT2: я думаю, что использование% правильно

EDIT3: Бла, это неправильно, потому что возвращает отрицательное значение для отрицательных чисел. Кто-нибудь знает, как получить python divmod на С#?

Как вычислить угол между двумя углами:

public static double NormalizeAngle(double radians)
{
 return fmod(radians,Math.PI*2.0); # this method doesn't exist, see above
}

public static double ArcLength(double radians1, double radians2)
{
 radians1 = NormalizeAngle(radians1);
 radians2 = NormalizeAngle(radians2);
 return Math.Min(NormalizeAngle(radians1 - radians2, NormalizeAngle(radians2 - radians1));
}

Как это работает, он пробует оба варианта, все расчеты по модулю 2pi, и выбирает вариант с меньшим расстоянием.

person Patashu    schedule 25.01.2013

person    schedule
comment
Слева: 0 | Верх: 90 | Вправо 180 | Внизу 270 Предполагая, что ваш круг такой... если Угол1 = 45 и Угол2 = 315, то дельта = 90 (верно). Однако если Angle1 = 0 и Angle2 = 225, то дельта = 45 (неверно). Расстояние между 0 и 225 такое же, как (360 - 225) и должно быть 135. Близко, но не совсем правильно. - person ATD; 25.01.2013
comment
Я отредактировал свой ответ примерно в то время, когда вы сделали этот комментарий. Я считаю, что редактирование правильное. - person Sam Axe; 25.01.2013
comment
Да, теперь это работает. Кроме того, просто чтобы отметить это, вы можете использовать Math.abs(dAngle1 - dAngle2) вместо max/min. - person ATD; 31.01.2013