4

I am trying to find the Euler angles that allow the transformation from point A to point B in 3D space.

Consider the normalized vectors A = [1, 0, 0] and B = [0.32 0.88 -0.34].

I understand that by computing the cross product A × B I get the rotation axis. The angle between A and B is given by tan⁻¹(||cross||, A·B), where A·B is the dot product between A and B.

This gives me the rotation vector rotvec = [0 0.36 0.93 1.24359531111], which is rotvec = [A × B; angle] (the cross product is normalized).

Now my question is: How do I move from here to get the Euler angles that correspond to the transformation from A to B?

In MATLAB the function vrrotvec2mat receives as input a rotation vector and outputs a rotation matrix. Then the function rotm2eul should return the corresponding Euler angles. I get the following result (in radians): [0.2456 0.3490 1.2216], according to the XYZ convention. Yet, this is not the expected result.

The correct answer is [0 0.3490 1.2216] that corresponds to a rotation of 20° and 70° in Y and Z, respectively.

When I use eul2rot([0 0.3490 1.2216]) (with eul2rot taken from here) to verify the resulting rotation matrix, this one is different from the one I obtain when using vrrotvec2mat(rotvec).

I also have a Python spinet that yields the exactly same results as described above.

--- Python (2.7) using transform3d ---

import numpy as np
import transforms3d

cross = np.cross(A, B)
dot = np.dot(A, B.transpose())
angle = math.atan2(np.linalg.norm(cross), dot)
rotation_axes = sklearn.preprocessing.normalize(cross)
rotation_m = transforms3d.axangles.axangle2mat(rotation_axes[0], angle, True)
rotation_angles = transforms3d.euler.mat2euler(rotation_m, 'sxyz')

What I am missing here? What should I be doing instead?

Thank you

Rody Oldenhuis
  • 37,726
  • 7
  • 50
  • 96
jcampos
  • 67
  • 2
  • 7
  • 1
    Euler angles between 2 points are not unique. This is why quaterions exist – Ander Biguri Jul 28 '18 at 00:02
  • 1
    @AnderBiguri I don't really understand how quaternions are relevant to the question. Or are you proposing this is an [XY Problem](https://meta.stackexchange.com/questions/66377)? – jodag Jul 28 '18 at 00:30
  • Do I get a unique solution if I use a quaternion instead? In the end I still need to convert it to euler angles. – jcampos Jul 28 '18 at 00:46
  • 3
    No. A unit-quaternion is an alternative representation of a rotation in R3. It's more compact, numerically stable, and faster to apply in a computation than a rotation matrix but doesn't have any more representational power. It's less compact than Euler angles but doesn't suffer from the "gimbal lock" problem. The fact remains there are multiple rotations which satisfy your problem so you would need to come up with a way to impose further constraints to get the solution you desire. – jodag Jul 28 '18 at 00:51

2 Answers2

4

A rotation matrix has 3 degrees of freedom but the constraints of your problem only constrain 2 of those degrees.

This can be made more concrete by considering the case where we have a rotation matrix R which rotates from A to B so R*A == B. If we then construct another rotation matrix RB which rotates about vector B then applying this rotation to R*A won't have any effect, i.e. B == R*A == RB*R*A. It will, however, produce a different rotation matrix RB*R with different Euler angles.

Here's an example in MATLAB:

A = [1; 0; 0];
B = [0.32; 0.88; -0.34];

A = A / norm(A);
B = B / norm(B);

ax = cross(A, B);
ang = atan2(norm(ax), dot(A, B)); % ang = acos(dot(A, B)) works too
R = axang2rotm([ax; ang].');

ang_arbitrary = rand()*2*pi;
RB = axang2rotm([B; ang_arbitrary].');

R*A - B
RB*R*A - B

rotm2eul(R)
rotm2eul(RB*R)

Result

ans =
   1.0e-15 *

   -0.0555
    0.1110
         0

ans =
   1.0e-15 *

    0.2220
    0.7772
   -0.2776

ans =    
    1.2220    0.3483    0.2452

ans =    
    1.2220    0.3483    0.7549
jodag
  • 19,885
  • 5
  • 47
  • 66
  • Thank you very much for your response. I understand that in this example a vector rotating around itself is not problematic, but if I have a chain of vectors connected to each other, where their transformation is dependent on the previous one, I will have a problem as you illustrated above. Is it correct to ignore the rotation in X? Since the cross product tells me that there is no interaction between x and the other variables? – jcampos Jul 27 '18 at 23:42
  • I'm not sure I understand what you mean by "their transformation is dependent on the previous one." The example you posted is a special case, in fact if you change `A` to `[0; 1; 0]` you will find that the axis of rotation has a zero in the Y component, however all 3 Euler angles will differ between `R` and `RB*R`. The fact that we observe only the X axis changing in your example is a result of the convention chosen for the Euler angles (in your case XYZ). – jodag Jul 28 '18 at 00:05
  • @jcampos In case the answer it still isn't clear. The Euler angles you get will work in the sense that they will rotate point `A` to point `B`. They are just different from the ones you're expecting because there are multiple sets of Euler angles which will work. – jodag Jul 28 '18 at 00:35
1

I will give you a solution based on Euler's rotation theorem.

This solution gives you only the one angle, but the other angles can be derived.

import numpy as np


a_vec = np.array([1, 0, 0])/np.linalg.norm(np.array([1, 0, 0]))
b_vec = np.array([0.32, 0.88, -0.34])/np.linalg.norm(np.array([0.32, 0.88, -0.34]))

cross = np.cross(a_vec, b_vec)
ab_angle = np.arccos(np.dot(a_vec,b_vec))


vx = np.array([[0,-cross[2],cross[1]],[cross[2],0,-cross[0]],[-cross[1],cross[0],0]])
R = np.identity(3)*np.cos(ab_angle) + (1-np.cos(ab_angle))*np.outer(cross,cross) + np.sin(ab_angle)*vx


validation=np.matmul(R,a_vec)

This uses the common axis of rotation (eigenvector in this case), as the cross product.

The matrix R is then the rotation matrix.

This is a general way of doing it, and very simple.

CupinaCoffee
  • 457
  • 4
  • 14