Convert rotation system

Hello,

I am (still) writing a CAD-Program (Computer Aided Design) using JME and it works fine.
But there is still one thing that makes me crazy.
All my rotations are extrinsic.
Every object has a rotation in degrees over the angles x,y and z that are done one after the other with the following method (which works fine):

Quaternion quatLocal = new Quaternion();        // actual local rotation
Quaternion quatRotation = new Quaternion();     // rotation to add

// the extrinsic rotations round X, Y und Z-Axis are done one afther the other
quatLocal = this.node.getLocalRotation();        // actual rotation

quatRotation.fromAngleAxis(FastMath.DEG_TO_RAD * this.getRotX(), Vector3f.UNIT_X);
quatLocal = quatRotation.mult(quatLocal);   

quatRotation.fromAngleAxis(FastMath.DEG_TO_RAD * this.getRotEwY(), Vector3f.UNIT_Y);
quatLocal = quatRotation.mult(quatLocal);   

quatRotation.fromAngleAxis(FastMath.DEG_TO_RAD * this.getRotZ(), Vector3f.UNIT_Z);
quatLocal = quatRotation.mult(quatLocal);   

node.setLocalRotation(quatLocal);           

the problem is, that when I try to read the actual rotation from an existing node I get angles back in a different system.

node.getLocalRotation 
float[] angles = node.getLocalRotation().toAngles(angles);
float x = Math.toDegrees(angles[0]); 
float y = Math.toDegrees(angles[1]);
float z = Math.toDegrees(angles[2]);

I think it’s because JME ist rotating in xzy-order and not in xyz-order like I do.
That’s why i have to do the rotation axis after axis and can not use the method node.setLocalRotation()

For example in my system the rotation is (0,30,270)
But when I read the rotation from the node I get (150,180,90).

I would be very very happy if somebody would know a method how to transform the (150,180,90)(JME-system) into the (0,30,270)(my system).
It doesn’t even matter if the result is different as long it fits into my system (because there are always several ways to get the same result when rotating.)

1 Like

No. It’s because euler-style angles are ambiguous and quaternions are compact rotations. Every quaterion is unique (excluding the negative form) but euler-style angles are not unique. You can never really expect to get the same angle-triple back out of a quaternion that you put into it. It’s just part of the math.

Order does also come into play but that’s inherent in the quaterion… where there is no order. It’s a compact rotation in axes at once.

Especially in an example like this. If you are already allowing angles to be something other than +/- 180 then you are going to have an infinite variation in what angle-triple can produce a particular quaternion. And even in that case, you can imagine how 0, 180, 0 could be the same as 180, 0, 180. Both would produce the same quaternion.

If you need the original angle-triple then you will have to keep the angle-triple and then never use JME to transform the rotation… always reconstruct that rotation from your own. You lose the ability to compose rotations using Quaterions, though.

My description was wrong. Im not using 0°…360° but -180°…+180°.
But my problem stays the same.
It would be ok for me if I get back 0,180,0 or 180,0,180.
But I think the mathematics would be very complicated to transform that.
At the Moment I just use a table with which I translate the JME values into “my” values.
Gladly I only need values in 15° or 30° steps. Example:

6:297:38:135:225:240
6:332:303:30:345:300
7:17:29:15:15:30
7:31:13:15:30:15
7:49:339:165:135:150
7:131:21:165:45:150
7:149:347:15:150:15
7:163:331:15:165:30
7:197:29:15:195:330
7:211:13:15:210:345
7:229:339:165:315:210
7:311:21:165:225:210
7:329:347:15:330:345
7:343:331:15:345:330
8:17:331:0:15:330

first tree numbers are the JME-value (x,y,z via getLocalRotation())
last three numbers are the equivalent values in my system (x,y,z).

Okay, so you’re applying the angles extrinsically in X,Y,Z order and you want to find some angles that would reproduce a given quaternion. The simple solution would be to store the angles alongside the quaternion, for instance in the node’s user data:

node.setLocalRotation(quatLocal);
node.setUserData("xDegrees", this.getRotX());
node.setUserData("yDegrees", this.getRotEwY());
node.setUserData("zDegrees", this.getRotZ());

Then you can get the angles back using (Float)node.getUserData("xDegrees") and so on.

But let’s assume you have some reason not to do it that way. To avoid doing a ton of trigonometry, my next suggestion would be to convert the quaternion to an equivalent 3x3 rotation matrix, then use textbook formulas to find suitable angles:

Matrix3f r = new Matrix3f();
//...
quatLocal.toRotationMatrix(r);

float r11 = r.get(0, 0); // textbook indices are 1,2,3 not 0,1,2
float r21 = r.get(1, 0);
float r31 = r.get(2, 0);
float r32 = r.get(2, 1);
float r33 = r.get(2, 2);

float cr31 = FastMath.sqrt(1f - r31 * r31);
       
float zRadians = FastMath.atan2(r21, r11);
float yRadians = FastMath.atan2(-r31, cr31);
float xRadians = FastMath.atan2(r32, r33);

float xDegrees = FastMath.RAD_TO_DEG * xRadians;
float yDegrees = FastMath.RAD_TO_DEG * yRadians;
float zDegrees = FastMath.RAD_TO_DEG * zRadians;

My “textbook” in this case was Wikipedia.