Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

interpolating a rotation through an angle with numpy

I have a single point

x = ..
y = ..
p = np.matrix([[x],[y]])

and I wish to rotate that point around the origin in increments of d degrees to get N = 360/d points. For example I imagine the following function.

points = interpolate360(d, p)

The shape of points should be (2,N)

I can do the code in a loop using a new rotation matrix for each rotation and then concatenating the results but I was hoping for some kind of vectorized solution.

like image 791
bradgonesurfing Avatar asked Jan 09 '13 10:01

bradgonesurfing


1 Answers

Using numpy's matrix is probably not the best idea in most settings. One way to solve your problem is creating a 3D array, where [n, :, :] holds the rotation matrix for the n-th angle. You cannot have a 3D matrix, so it can get messy if you mix array and matrix types and still want to rely on * doing matrix multiplication. If you stick with arrays, and np.dot to handle the matrix multiplications predictably, the following code works nicely. It will actually also take a matrix, but first convert it to an ndarray:

def interpolate360(d, p):
    p = np.array(p)
    angles = np.arange(0, 2 * np.pi, d * np.pi / 180)
    sin = np.sin(angles)
    cos = np.cos(angles)

    rot_matrices = np.empty((angles.shape[0], 2, 2))
    rot_matrices[..., 0, 0] = cos
    rot_matrices[..., 0, 1] = -sin
    rot_matrices[..., 1, 0] = sin
    rot_matrices[..., 1, 1] = cos

    return np.dot(rot_matrices, p)

As the examples below show, this works if your input is a 1D row vector, a 2D single column vector, or a 2D array holding several column vectors:

>>> interpolate360(90, [0, 1])
array([[  0.00000000e+00,   1.00000000e+00],
       [ -1.00000000e+00,   6.12323400e-17],
       [ -1.22464680e-16,  -1.00000000e+00],
       [  1.00000000e+00,  -1.83697020e-16]])
>>> interpolate360(90, [[0], [1]])
array([[[  0.00000000e+00],
        [  1.00000000e+00]],

       [[ -1.00000000e+00],
        [  6.12323400e-17]],

       [[ -1.22464680e-16],
        [ -1.00000000e+00]],

       [[  1.00000000e+00],
        [ -1.83697020e-16]]])
>>> interpolate360(90, [[1, 0], [0, 1]])
array([[[  1.00000000e+00,   0.00000000e+00],
        [  0.00000000e+00,   1.00000000e+00]],

       [[  6.12323400e-17,  -1.00000000e+00],
        [  1.00000000e+00,   6.12323400e-17]],

       [[ -1.00000000e+00,  -1.22464680e-16],
        [  1.22464680e-16,  -1.00000000e+00]],

       [[ -1.83697020e-16,   1.00000000e+00],
        [ -1.00000000e+00,  -1.83697020e-16]]])
like image 102
Jaime Avatar answered Nov 09 '22 20:11

Jaime