Search code examples
pythonnumpyrotationquaternions

quaternion generation with non minimal rotation arc


The quaternion module of numpy can generate quaternion from sperical coordinates. Example:

theta = np.pi  / 3.0
phi = np.pi / 3.0
qRot = q.from_spherical_coords(theta,phi)

qRot quaternion(0.75, -0.25, 0.433012701892219, 0.433012701892219)

This quaternion rotates Z axis to a unit vector V pointing to theta,phi coords. This quaternion does not produces a minimal rotation arc. The minimal rotation arc axis lies in the xy plane. Since the non minimal rotations moving Z to V are infinite, what is the underlying criteria that produces the quaternion qRot?

Thanks for any reply.


Solution

  • I assume you are using the numpy-quaternion package.

    In [2]: theta = np.pi  / 3.0
       ...: phi = np.pi / 3.0
       ...: 
    

    The (theta, phi) quaternion can be composed from 2 quaternions, one the rotations about the y axis (your previous question), and another about the z axis:

    In [3]: q1 = q.from_spherical_coords(theta,0)
    In [4]: q1
    Out[4]: quaternion(0.866025403784439, -0, 0.5, 0)
    In [5]: q2 = q.from_spherical_coords(0,phi)
    In [6]: q2
    Out[6]: quaternion(0.866025403784439, -0, 0, 0.5)
    In [7]: q12 = q.from_spherical_coords(theta,phi)
    In [8]: q12
    Out[8]: quaternion(0.75, -0.25, 0.433012701892219, 0.433012701892219)
    
    In [9]: q1*q2
    Out[9]: quaternion(0.75, 0.25, 0.433012701892219, 0.433012701892219)
    

    It can also be composed of a sequence of smaller rotations

    In [11]: qn = q12**.1
    In [12]: qn
    Out[12]: quaternion(0.997389412687609, -0.0272930118179609, 0.0472728831602861, 0.0472728831602861)
    In [13]: qn*qn
    Out[13]: quaternion(0.989571281082665, -0.0544435220551839, 0.0942989463425753, 0.0942989463425753)
    In [14]: qn**10
    Out[14]: quaternion(0.75, -0.25, 0.433012701892219, 0.433012701892219)
    

    I'm guessing that what you call a minimal rotation arc can be approximated by the rotations produced by such a sequence of small quaternions.

    I don't understand why you claim this arc's 'axis lies in the xy plane'.

    And rotating the unit Z axis:

    In [17]: v=np.array([0,0,1])
    In [23]: q.as_rotation_matrix(q1).dot(v)
    Out[23]: array([0.8660254, 0.       , 0.5      ])
    
    In [24]: q.as_rotation_matrix(q2).dot(_)
    Out[24]: array([0.4330127, 0.75     , 0.5      ])
    
    In [25]: q.as_rotation_matrix(q12).dot(v)
    Out[25]: array([0.4330127, 0.75     , 0.5      ])
    

    Or as a sequence of qn rotations:

    In [26]: q.as_rotation_matrix(qn).dot(v)
    Out[26]: array([0.09171851, 0.05891297, 0.99404073])
    In [27]: q.as_rotation_matrix(qn**2).dot(v)
    Out[27]: array([0.17636312, 0.12553607, 0.97628722])
    In [28]: q.as_rotation_matrix(qn**3).dot(v)
    Out[28]: array([0.25216838, 0.19847972, 0.94710977])
    In [29]: q.as_rotation_matrix(qn**10).dot(v)
    Out[29]: array([0.4330127, 0.75     , 0.5      ])
    

    I'm still trying to figure out the best ways of doing calculations and rotations with this class. And periodically I'm getting a core dump, so it's probably not the most robust quaternion package for numpy.

    https://math.stackexchange.com/q/7187


    My qn powers produce the same quaternions as the slerp function: q.slerp_evaluate(q1,q3,x)

    https://en.wikipedia.org/wiki/Slerp#Quaternion_Slerp,

    spherical linear interpolation, introduced by Ken Shoemake in the context of quaternion interpolation for the purpose of animating 3D rotation. It refers to constant-speed motion along a unit-radius great circle arc, given the ends and an interpolation parameter between 0 and 1.

    I sort of stumbled on this by drawing on earlier reading on Geometric Algebra rotations, . It refers to constant-speed motion along a unit-radius great circle arc, given the ends and an interpolation parameter between 0 and 1.

    pyquaternion

    I got tired of segmentation errors, and have switched to pyquaternion. The documentation is better too.

    http://kieranwynn.github.io/pyquaternion/

    Defining a quaternion with the same (w,x,y,z) values:

    In [10]: q=Quaternion(np.array([0.75, -0.25, 0.433012701892219, 0.433012701892219]))
    In [13]: q.rotation_matrix
    Out[13]: 
    array([[ 0.25     , -0.8660254,  0.4330127],
           [ 0.4330127,  0.5      ,  0.75     ],
           [-0.8660254, -0.       ,  0.5      ]])
    

    The rotation axis is:

    In [16]: q.axis
    Out[16]: array([-0.37796447,  0.65465367,  0.65465367])
    

    This quaternion rotates the a unit vertical to:

    In [17]: z=np.array([0,0,1])
    In [18]: q.rotate(z)
    Out[18]: array([0.4330127, 0.75     , 0.5      ])   # cf Out[25]
    

    The q1 (In[3]) (previous question) is:

    In [28]: a1 = np.array([0.866025403784439, -0, 0.5, 0])
    In [29]: q1 = Quaternion(a1)
    In [30]: q1.axis
    Out[30]: array([0., 1., 0.])
    In [31]: q1.degrees
    Out[31]: 59.999999999999986
    

    That is, a 60 degree rotation about the y axis.

    And a rotation arc can be calculated with:

    In [32]: qn = q**.1
    In [38]: np.array([(qn**n).rotate(z) for n in range(0,11)])
    Out[38]: 
    array([[0.        , 0.        , 1.        ],
           [0.09171851, 0.05891297, 0.99404073],
           [0.17636312, 0.12553607, 0.97628722],
           [0.25216838, 0.19847972, 0.94710977],
           [0.31755317, 0.27622248, 0.90711693],
           [0.37115374, 0.35714286, 0.85714286],
           [0.41185212, 0.43955305, 0.79822988],
           [0.43879944, 0.52173419, 0.73160678],
           [0.45143365, 0.6019722 , 0.65866314],
           [0.44949123, 0.67859351, 0.58092037],
           [0.4330127 , 0.75      , 0.5       ]])
    

    Picturing this arc is a little tricky. The plane is perpendicular to q.axis, but does not go through the (0,0,0) origin.

    enter image description here

    lined up