This code is in C++, but hopefully I managed to make it reasonably clear. Notice how the loop doesn't have any trigonometric functions at all. There are also basically no special cases.
#include <iostream>
#include <complex>
#include <cmath>
typedef std::complex<float> C;
float const pi = std::atan(1.0f)*4.0f;
C normalize(C z) {
return z/std::abs(z);
}
C limited_rotation_towards(C original, C target, C max_rotation) {
C rotation = normalize(target / original);
if (rotation.real() < max_rotation.real())
return rotation.imag() > 0.0f ? max_rotation : conj(max_rotation);
return rotation;
}
int main() {
C z = 1.0f;
C target (-1.0f, -1.0f);
float max_angle = pi*0.125f;
C max_rotation(std::cos(max_angle), std::sin(max_angle));
for (int i=0; i<20; ++i) {
std::cout << z << '\n';
z *= limited_rotation_towards(z, target, max_rotation);
}
}
The output is this:
(1,0)
(0.92388,-0.382683)
(0.707107,-0.707107)
(0.382683,-0.92388)
(-1.49012e-07,-1)
(-0.382684,-0.923879)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)