Skip to content

Commit

Permalink
Add Quaternion.getEulerAnglesZXY()
Browse files Browse the repository at this point in the history
  • Loading branch information
httpdigest committed Dec 11, 2021
1 parent 9d1de33 commit 1c1922f
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 0 deletions.
7 changes: 7 additions & 0 deletions src/org/joml/Quaterniond.java
Original file line number Diff line number Diff line change
Expand Up @@ -2775,6 +2775,13 @@ public Vector3d getEulerAnglesZYX(Vector3d eulerAngles) {
return eulerAngles;
}

public Vector3d getEulerAnglesZXY(Vector3d eulerAngles) {
eulerAngles.x = Math.safeAsin(2.0 * (w * x + y * z));
eulerAngles.y = Math.atan2(w * y - x * z, 0.5 - y * y - x * x);
eulerAngles.z = Math.atan2(w * z - x * y, 0.5 - z * z - x * x);
return eulerAngles;
}

public Quaterniond rotateAxis(double angle, double axisX, double axisY, double axisZ, Quaterniond dest) {
double hangle = angle / 2.0;
double sinAngle = Math.sin(hangle);
Expand Down
13 changes: 13 additions & 0 deletions src/org/joml/Quaterniondc.java
Original file line number Diff line number Diff line change
Expand Up @@ -1774,6 +1774,19 @@ public interface Quaterniondc {
*/
Vector3d getEulerAnglesZYX(Vector3d eulerAngles);

/**
* Get the euler angles in radians in rotation sequence <code>ZXY</code> of this quaternion and store them in the
* provided parameter <code>eulerAngles</code>.
* <p>
* The Euler angles are always returned as the angle around X in the {@link Vector3d#x} field, the angle around Y in the {@link Vector3d#y}
* field and the angle around Z in the {@link Vector3d#z} field of the supplied {@link Vector3d} instance.
*
* @param eulerAngles
* will hold the euler angles in radians
* @return the passed in vector
*/
Vector3d getEulerAnglesZXY(Vector3d eulerAngles);

/**
* Apply a rotation to <code>this</code> quaternion rotating the given radians about the specified axis
* and store the result in <code>dest</code>.
Expand Down
7 changes: 7 additions & 0 deletions src/org/joml/Quaternionf.java
Original file line number Diff line number Diff line change
Expand Up @@ -1866,6 +1866,13 @@ public Vector3f getEulerAnglesZYX(Vector3f eulerAngles) {
return eulerAngles;
}

public Vector3f getEulerAnglesZXY(Vector3f eulerAngles) {
eulerAngles.x = Math.safeAsin(2.0f * (w * x + y * z));
eulerAngles.y = Math.atan2(w * y - x * z, 0.5f - y * y - x * x);
eulerAngles.z = Math.atan2(w * z - x * y, 0.5f - z * z - x * x);
return eulerAngles;
}

public float lengthSquared() {
return Math.fma(x, x, Math.fma(y, y, Math.fma(z, z, w * w)));
}
Expand Down
13 changes: 13 additions & 0 deletions src/org/joml/Quaternionfc.java
Original file line number Diff line number Diff line change
Expand Up @@ -1580,6 +1580,19 @@ public interface Quaternionfc {
*/
Vector3f getEulerAnglesZYX(Vector3f eulerAngles);

/**
* Get the euler angles in radians in rotation sequence <code>ZXY</code> of this quaternion and store them in the
* provided parameter <code>eulerAngles</code>.
* <p>
* The Euler angles are always returned as the angle around X in the {@link Vector3f#x} field, the angle around Y in the {@link Vector3f#y}
* field and the angle around Z in the {@link Vector3f#z} field of the supplied {@link Vector3f} instance.
*
* @param eulerAngles
* will hold the euler angles in radians
* @return the passed in vector
*/
Vector3f getEulerAnglesZXY(Vector3f eulerAngles);

/**
* Return the square of the length of this quaternion.
*
Expand Down
21 changes: 21 additions & 0 deletions test/org/joml/test/QuaternionDTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -135,4 +135,25 @@ public static void testGetEulerAnglesXYZ() {
if ((float)failure / N > 0.0001f) // <- allow for a failure rate of 0.01%
throw new AssertionError();
}

public static void testGetEulerAnglesZXY() {
Random rnd = new Random(1L);
int failure = 0;
int N = 3000000;
for (int i = 0; i < N; i++) {
double x = (rnd.nextFloat() * 2.0 - 1.0) * Math.PI;
double y = (rnd.nextFloat() * 2.0 - 1.0) * Math.PI;
double z = (rnd.nextFloat() * 2.0 - 1.0) * Math.PI;
Quaterniond p = new Quaterniond().rotateZ(z).rotateX(x).rotateY(y);
Vector3d a = p.getEulerAnglesZXY(new Vector3d());
Quaterniond q = new Quaterniond().rotateZ(a.z).rotateX(a.x).rotateY(a.y);
Vector3d v = new Vector3d(rnd.nextFloat()*2-1, rnd.nextFloat()*2-1, rnd.nextFloat()*2-1);
Vector3d t1 = p.transform(v, new Vector3d());
Vector3d t2 = q.transform(v, new Vector3d());
if (!t1.equals(t2, 1E-10f))
failure++;
}
if ((float)failure / N > 0.0001f) // <- allow for a failure rate of 0.01%
throw new AssertionError();
}
}
21 changes: 21 additions & 0 deletions test/org/joml/test/QuaternionfTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -194,4 +194,25 @@ public static void testGetEulerAnglesXYZ() {
if ((float)failure / N > 0.0001f) // <- allow for a failure rate of 0.01%
throw new AssertionError();
}

public static void testGetEulerAnglesZXY() {
Random rnd = new Random(1L);
int failure = 0;
int N = 3000000;
for (int i = 0; i < N; i++) {
float x = (rnd.nextFloat() * 2f - 1f) * (float) Math.PI;
float y = (rnd.nextFloat() * 2f - 1f) * (float) Math.PI;
float z = (rnd.nextFloat() * 2f - 1f) * (float) Math.PI;
Quaternionf p = new Quaternionf().rotateZ(z).rotateX(x).rotateY(y);
Vector3f a = p.getEulerAnglesZXY(new Vector3f());
Quaternionf q = new Quaternionf().rotateZ(a.z).rotateX(a.x).rotateY(a.y);
Vector3f v = new Vector3f(rnd.nextFloat()*2-1, rnd.nextFloat()*2-1, rnd.nextFloat()*2-1);
Vector3f t1 = p.transform(v, new Vector3f());
Vector3f t2 = q.transform(v, new Vector3f());
if (!t1.equals(t2, 1E-3f))
failure++;
}
if ((float)failure / N > 0.0001f) // <- allow for a failure rate of 0.01%
throw new AssertionError();
}
}

0 comments on commit 1c1922f

Please sign in to comment.