I have a computer device - a 3D pointer (Sensable Phantom Omni). It returns cartesian position (X,Y,Z) and orientation quaternion (x,y,z,w).

Now I have a 3D visualization software (PyMOL) and I need to draw a pointer that has the same position and orientation as my device.

I had no problem with position, that is ok.

But I have some trouble with converting device orientation (returned as quaternion) to PyMOL object orientation (which needs to be represented as axis-angle as described here: http://www.pymolwiki.org/index.php/Rotate).

I have a library for transformations (in Python) (http://www.lfd.uci.edu/~gohlke/code/transformations.py.html) and I've done some standard computation on converting quaternion to axis-angle form, but it doesn't work properly. It rotates continuously (with different speeds and directions), no matter if I rotate my device or not.

Maybe I shouldn't pass directly converted value (quaternion -> axis-angle) to Rotate function in PyMOL, but I should calculate a delta between current and previous orientation? Or maybe I'm totally wrong, do you have any suggestions?

I'm a little desperate with this problem ;)

  • $\begingroup$ I don't see a concrete mathematical question here. If your question is generally how to convert a quaternion representation of an orientation to an axis/angle representation, you'll find lots of answers on the Web, e.g. on Wikipedia (see also here and here). If your question is about what you're doing wrong, you need to tell us more concretely what you're doing. $\endgroup$ – joriki Feb 16 '16 at 9:44

Use SetView() instead of Rotate(). You can use GetView() to obtain the initial view. The nine first components of the view information form the current view orientation matrix, in column major order second item is the leftmost component on second row). Rotate() applies a rotation to that, so it is cumulative, but using SetView() you can set it.

Python uses zero-based indexing, and PyMol uses column-major order for the components in that matrix, i.e. $$(m_0, m_1, m_2, m_3, m_4, m_5, m_6, m_7, m_8 ) \; = \; \left[\begin{matrix}m_0&m_3&m_6\\m_1&m_4&m_7\\m_2&m_5&m_8\end{matrix}\right]$$

In practice, you should use an initial orientation (quaternion), which you rotate by the orientation of your control device; by taking the Hamilton product of the device quaternion and the initial rotation quaternion, and normalizing the result to unit length. (This lets you define the default orientation the device rotates; if the device has a suitable button or something, you could use it to store the current orientation as the target orientation when pressed, and when released, define the new initial orientation as the target orientation rotated by the inverse of the device rotation. In practice, the user could then release muscle strain by "freezing" the current orientation by pressing the button.)

Convert the quaternion result of above to a rotation matrix. Note, $q_r=w$, $q_i=x$, $q_j=y$, $q_k=z$, on that Wikipedia example, compared to your notation.

In PyMol, use v = cmd.get_view(output=1,quiet=1) to get the current view information into v, replace the nine first elements in v by your new rotation matrix, and use cmd.set_view(*v) to update the view.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.