2016-12-12 3 views
0

Я пытаюсь интерполировать 2D-угол и работает 99,9% времени. По некоторым причинам я получаю -nan (IND) для некоторых значений, например:Slerp интерполяция результатов угла в -nan (ind)

lastAngle = -0.0613451 
currentAngle = -0.061421 
alpha = 0.218813 

Это код:

inline float slerpRotation(const float& angle1, const float& angle2, const float& alpha) 
{ 
    auto v1 = b2Vec2{std::cos(angle1), std::sin(angle1)}; 
    auto v2 = b2Vec2{std::cos(angle2), std::sin(angle2)}; 
    auto v = this->slerp(v1, v2, alpha); 
    return std::atan2(v.y, v.x); 
} 

inline b2Vec2 slerp(const b2Vec2& v1, const b2Vec2& v2, const float& alpha) 
{ 
    auto cosAngle = v1.x * v2.x + v1.y * v2.y; 
    auto angle = std::acos(cosAngle); 
    auto angleAlpha = angle * alpha; 
    auto v3 = (v2 - (cosAngle * v1)).Normalize(); 
    auto x = v1.x * std::cos(angleAlpha) + v3 * std::sin(angleAlpha); 
    auto y = v1.y * std::cos(angleAlpha) + v3 * std::sin(angleAlpha); 
    return b2Vec2{x, y}; 
} 

Все эти примеры приводит инф NUM:

slerpRotation(-0.0613451f, -0.061421f, 0.218813f); 
slerpRotation(-1.63139f, -1.63139f, 0.723703f); 
slerpRotation(-0.0614404f, -0.0614034f, 0.199831f); 
slerpRotation(0.0194162f, 0.0194164f, 0.259074f); 

Я пытался решить эту проблему какое-то время, не зная, что вызывает эту проблему, вы, ребята, знаете, как это решить?

+0

Что делает 'b2Vec2 :: Normalize' с вектором {0,0}? – 1201ProgramAlarm

+0

@ 1201ProgramAlarm возвращает 0 – Saruman

+0

Хех, эта строка кажется проблемой: auto angle = std :: acos (cosAngle); Получение значения nan обратно – Saruman

ответ

2

В конце концов вы вычисление

angle1+alpha*(angle2-angle1) 

или если вы хотите, чтобы исключить некоторые случаи бахромы,

angle1+alpha*reduce2pi(angle2-angle1) 

где

reduce2pi(phi) = fmod(3*pi + fmod(phi, 2*pi), 2*pi)-pi 

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

В коде, который был бы

inline float slerpRotation(const float& angle1, const float& angle2, const float& alpha) 
{ 
    auto angleDiff = angle2-angle1; 
    angleDiff = std::fmod(angleDiff, 2*std::M_PI); 
    angleDiff = std::fmod(angleDiff + 3*std::M_PI, 2*std::M_PI)-std::M_PI; 
    return angle1+alpha*angleDiff; 
} 

(12/13/2016) комбинируя несколько замечаний: Если вы настаиваете на использовании именно этого интерфейса структуру, то вы можете получить особенность бесплатно метод следующим образом:

inline b2Vec2 slerp(const b2Vec2& v1, const b2Vec2& v2, const float& alpha) 
{ 
    auto angle = std::atan2(v1.x*v2.y - v1.y*v2.x, v1.x*v2.x + v1.y*v2.y); 
    auto angleAlpha = angle * alpha; 
    auto v3=b2Vec2{-v1.y, v1.x}; // rotation by 90° 
    return std::cos(angleAlpha)*v1 + std::sin(angleAlpha)*v3; 
} 
+0

Извините, но я этого не понимаю. В какой части я ошибался? – Saruman

+0

Вы делаете много сложного вычисления геометрии, чтобы получить результат простой линейной интерполяции углов. Для фактической ошибки сначала проверьте, что 'cosAlpha' никогда не превышает' 1.0'. Или используйте функцию 'atan2', чтобы получить угол от' cosAlpha' и 'sinAlpha = v1.x * v2.y-v1.y * v2.x'. – LutzL

+0

спасибо за обновление. Похоже, что этот работает точно так же, как мой пример с меньшим количеством кода. Когда вы говорите, настаиваете на использовании этого интерфейса, у вас есть лучшее решение о том, как интерполировать угол? – Saruman

Смежные вопросы