Наименьшая разница между двумя углами
-
18-09-2019 - |
Вопрос
Учитывая два угла в диапазоне -PI -> PI вокруг координаты, каково значение наименьшего из двух углов между ними?
Принимая во внимание, что разница между ПИ и -ПИ составляет не 2 ПИ, а ноль.
Пример:
Представьте себе круг с двумя линиями, выходящими из центра, между этими линиями есть два угла, угол, который они образуют внутри, он же меньший угол, и угол, который они образуют снаружи, то есть больший угол.Оба угла, сложенные, образуют полный круг.Учитывая, что каждый угол может укладываться в определенный диапазон, каково меньшее значение углов с учетом опрокидывания
Решение
Это дает угол со знаком для любых углов:
a = targetA - sourceA
a = (a + 180) % 360 - 180
Остерегайтесь на многих языках modulo
операция возвращает значение с тем же знаком, что и делимое (например, C, C++, C#, JavaScript, полный список здесь).Для этого требуется индивидуальный mod
функционируйте так:
mod = (a, n) -> a - floor(a/n) * n
Или так:
mod = (a, n) -> (a % n + n) % n
Если углы находятся в пределах [-180, 180], это также работает:
a = targetA - sourceA
a += (a>180) ? -360 : (a<-180) ? 360 : 0
Более подробно:
a = targetA - sourceA
a -= 360 if a > 180
a += 360 if a < -180
Другие советы
x — целевой угол.y — исходный или начальный угол:
atan2(sin(x-y), cos(x-y))
Он возвращает знак дельты.Обратите внимание: в зависимости от вашего API порядок параметров функции atan2() может отличаться.
Если ваши два угла — x и y, то один из углов между ними — abs(x — y).Другой угол: (2 * PI) – abs(x – y).Таким образом, значение наименьшего из двух углов равно:
min((2 * PI) - abs(x - y), abs(x - y))
Это дает вам абсолютное значение угла и предполагает, что входные данные нормализованы (т.е.:в пределах диапазона [0, 2π)
).
Если вы хотите сохранить знак (т.е.:направлении) угла, а также принимать углы вне диапазона [0, 2π)
Вы можете обобщить вышесказанное.Вот код Python для обобщенной версии:
PI = math.pi
TAU = 2*PI
def smallestSignedAngleBetween(x, y):
a = (x - y) % TAU
b = (y - x) % TAU
return -a if a < b else b
Обратите внимание, что %
Оператор не ведет себя одинаково на всех языках, особенно когда используются отрицательные значения, поэтому при переносе могут потребоваться некоторые корректировки знаков.
Я готов дать подписанный ответ:
def f(x,y):
import math
return min(y-x, y-x+2*math.pi, y-x-2*math.pi, key=abs)
Для пользователей UnityEngine простой способ — просто использовать Mathf.DeltaAngle.
Арифметическое (в отличие от алгоритмического) решение:
angle = Pi - abs(abs(a1 - a2) - Pi);
Нет необходимости вычислять тригонометрические функции.Простой код на языке C:
#include <math.h>
#define PIV2 M_PI+M_PI
#define C360 360.0000000000000000000
double difangrad(double x, double y)
{
double arg;
arg = fmod(y-x, PIV2);
if (arg < 0 ) arg = arg + PIV2;
if (arg > M_PI) arg = arg - PIV2;
return (-arg);
}
double difangdeg(double x, double y)
{
double arg;
arg = fmod(y-x, C360);
if (arg < 0 ) arg = arg + C360;
if (arg > 180) arg = arg - C360;
return (-arg);
}
пусть dif = a - b, в радианах
dif = difangrad(a,b);
пусть dif = a - b, в градусах
dif = difangdeg(a,b);
difangdeg(180.000000 , -180.000000) = 0.000000
difangdeg(-180.000000 , 180.000000) = -0.000000
difangdeg(359.000000 , 1.000000) = -2.000000
difangdeg(1.000000 , 359.000000) = 2.000000
Ни греха, ни косизны, ни загара....только геометрия!!!!
Эффективный код на C++:
inline double getAbsoluteDiff2Angles(const double x, const double y, const double c)
{
// c can be PI or 180;
return c - fabs(fmod(fabs(x - y), 2*c) - c);
}