atan2
возвращает угол двухмерного вектора. Ваш код не обрабатывает такое масштабирование должным образом. Но не беспокойтесь, на самом деле очень легко уменьшить вашу проблему до atan2
, который бы все прекрасно справился.
Обратите внимание, что вычисление sin(x)
и sin(x + phase)
аналогично проекции точки (cos(x), sin(x))
на оси (0, 1)
и (sin(phase), cos(phase))
. Это то же самое, что брать точечные произведения с этими осями или преобразовывать систему координат из стандартного ортогонального основания в наклонное. Это предлагает простое решение: инвертировать преобразование, чтобы получить координаты в ортогональном базисе, а затем использовать atan2
.
Вот код, который делает это:
double super_atan2(double x0, double x1, double a0, double a1) {
double det = sin(a0 - a1);
double u = (x1*sin(a0) - x0*sin(a1))/det;
double v = (x0*cos(a1) - x1*cos(a0))/det;
return atan2(v, u);
}
double duper_atan2(double y0, double y1, double phase) {
const double tau = 6.28318530717958647692; // https://tauday.com/
return super_atan2(y0, y1, tau/4, tau/4 - phase);
}
super_atan2
получает углы двух проекционных осей, duper_atan2
решает проблему именно так, как вы заявили.
Также обратите внимание, что вычисление det
не является строго необходимым. Его можно заменить на fmod
и copysign
(нам все еще нужен правильный знак u
и v
).