Skip to content

Instantly share code, notes, and snippets.

@jayfella
Last active October 19, 2020 15:36
Show Gist options
  • Save jayfella/d1cb54a3f0b75bfd9b2d05a4bfd97588 to your computer and use it in GitHub Desktop.
Save jayfella/d1cb54a3f0b75bfd9b2d05a4bfd97588 to your computer and use it in GitHub Desktop.
A class to simplify rotations and quaternions.
package com.jayfella.jme.vehicle;
import com.jme3.math.FastMath;
import com.jme3.math.Quaternion;
/**
* Provides functionality to get and set rotations, limit the rotation to avoid large angles and convert them into
* a quaternion for scene rotation.
*
* @author jayfella
*
*/
public class AxisRotation {
public enum Axis {
X, Y, Z
}
private Quaternion quaternion = null;
private final float[] angles;
private boolean truncateRotation = true;
/**
* Create a new AxisRotation with the angles initialized to 0, 0, 0.
*/
public AxisRotation() {
this(0, 0, 0);
}
private AxisRotation(float x, float y, float z) {
angles = new float[] { x, y, z };
}
/**
* Create a new AxisRotation with the angles initialized to the specified values.
* @param x the X axis in radians.
* @param y the Y axis in radians.
* @param z the Z axis in radians.
*/
public static AxisRotation fromRadians(float x, float y, float z) {
return new AxisRotation(x, y, z);
}
/**
* Create a new AxisRotation with the angles initialized to the specified values.
* @param x the X axis in degrees.
* @param y the Y axis in degrees.
* @param z the Z axis in degrees.
*/
public static AxisRotation fromDegrees(float x, float y, float z) {
return new AxisRotation(x * FastMath.DEG_TO_RAD, y * FastMath.DEG_TO_RAD, z * FastMath.DEG_TO_RAD);
}
/**
* Gets the rotation of the given axis.
* @param axis the axis to get.
* @return the angle of rotation in radians.
*/
public float get(Axis axis) {
switch (axis) {
case X: return getX();
case Y: return getY();
case Z: return getZ();
default: throw new IllegalArgumentException("Unknown axis: " + axis);
}
}
/**
* Set the rotation of the given axis.
* @param axis the axis to set.
* @param value the angle of rotation in radians.
*/
public void set(Axis axis, float value) {
switch (axis) {
case X: setX(value); break;
case Y: setY(value); break;
case Z: setZ(value); break;
}
}
/**
* Gets the rotation of the given axis.
* @param axis the axis to get.
* @return the angle of rotation in degrees.
*/
public float getInDegrees(Axis axis) {
switch (axis) {
case X: return getInDegreesX();
case Y: return getInDegreesY();
case Z: return getInDegreesZ();
default: throw new IllegalArgumentException("Unknown axis: " + axis);
}
}
/**
* Set the rotation of the given axis.
* @param axis the axis to set.
* @param value the angle of rotation in degrees.
*/
public void setInDegrees(Axis axis, float value) {
switch (axis) {
case X: setInDegreesX(value); break;
case Y: setInDegreesY(value); break;
case Z: setInDegreesZ(value); break;
}
}
/**
* Rotates the axis by the given value.
* @param axis the axis to rotate.
* @param value the angle of rotation in radians.
*/
public void rotate(Axis axis, float value) {
switch (axis) {
case X: rotateX(value); break;
case Y: rotateY(value); break;
case Z: rotateZ(value); break;
}
}
/**
* Rotates the axis by the given value.
* @param axis the axis to rotate.
* @param value the angle of rotation in degrees.
*/
public void rotateInDegrees(Axis axis, float value) {
switch (axis) {
case X: rotateInDegreesX(value); break;
case Y: rotateInDegreesY(value); break;
case Z: rotateInDegreesZ(value); break;
}
}
/**
* Get the rotation of the X axis.
* @return the angle of rotation in radians.
*/
public float getX() {
return angles[0];
}
/**
* Set the rotation of the X axis.
* @param x the rotation in radians.
*/
public void setX(float x) {
angles[0] = enforceRotationLimit(x);
}
/**
* Get the rotation of the X axis.
* @return the angle of rotation in degrees.
*/
public float getInDegreesX() {
return angles[0] * FastMath.RAD_TO_DEG;
}
/**
* Set the rotation of the X axis.
* @param x the rotation in degrees.
*/
public void setInDegreesX(float x) {
angles[0] = enforceRotationLimit(x * FastMath.DEG_TO_RAD);
}
/**
* Rotates the X axis by the given value.
* @param x the angle of rotation in radians.
*/
public void rotateX(float x) {
angles[0] = enforceRotationLimit(angles[0] + x);
}
/**
* Rotates the X axis by the given value.
* @param x the angle of rotation in degrees.
*/
public void rotateInDegreesX(float x) {
angles[0] = enforceRotationLimit(angles[0] + (x * FastMath.DEG_TO_RAD));
}
/**
* Get the rotation of the Y axis.
* @return the angle of rotation in radians.
*/
public float getY() {
return angles[1];
}
/**
* Set the rotation of the Y axis.
* @param y the rotation in radians.
*/
public void setY(float y) {
angles[1] = enforceRotationLimit(y);
}
/**
* Get the rotation of the Y axis.
* @return the angle of rotation in degrees.
*/
public float getInDegreesY() {
return angles[1] * FastMath.RAD_TO_DEG;
}
/**
* Set the rotation of the Y axis.
* @param y the rotation in degrees.
*/
public void setInDegreesY(float y) {
angles[1] = enforceRotationLimit(y * FastMath.DEG_TO_RAD);
}
/**
* Rotates the Y axis by the given value.
* @param y the angle of rotation in radians.
*/
public void rotateY(float y) {
angles[1] = enforceRotationLimit(angles[1] + y);
}
/**
* Rotates the X axis by the given value.
* @param y the angle of rotation in degrees.
*/
public void rotateInDegreesY(float y) {
angles[1] = enforceRotationLimit(angles[1] + (y * FastMath.DEG_TO_RAD));
}
/**
* Get the rotation of the Z axis.
* @return the angle of rotation in radians.
*/
public float getZ() {
return angles[2];
}
/**
* Set the rotation of the Z axis.
* @param z the rotation in radians.
*/
public void setZ(float z) {
angles[2] = enforceRotationLimit(z);
}
/**
* Get the rotation of the z axis.
* @return the angle of rotation in degrees.
*/
public float getInDegreesZ() {
return angles[2] * FastMath.RAD_TO_DEG;
}
/**
* Set the rotation of the Z axis.
* @param z the rotation in degrees.
*/
public void setInDegreesZ(float z) {
angles[2] = enforceRotationLimit(z * FastMath.DEG_TO_RAD);
}
/**
* Rotates the Z axis by the given value.
* @param z the angle of rotation in radians.
*/
public void rotateZ(float z) {
angles[2] = enforceRotationLimit(angles[2] + z);
}
/**
* Rotates the X axis by the given value.
* @param z the angle of rotation in degrees.
*/
public void rotateInDegreesZ(float z) {
angles[2] = enforceRotationLimit(angles[2] + (z * FastMath.DEG_TO_RAD));
}
/**
* Rotates all axis by the given values.
* @param x the X axis rotation in radians.
* @param y the Y axis rotation in radians.
* @param z the Z axis rotation in radians.
*/
public void rotate(float x, float y, float z) {
angles[0] = enforceRotationLimit(angles[0] + x);
angles[1] = enforceRotationLimit(angles[1] + y);
angles[2] = enforceRotationLimit(angles[2] + z);
}
/**
* Rotates all axis by the given values in radians.
* @param x the X axis rotation in degrees.
* @param y the Y axis rotation in degrees.
* @param z the Z axis rotation in degrees.
*/
public void rotateInDegrees(float x, float y, float z) {
angles[0] = enforceRotationLimit(angles[0] + (x * FastMath.DEG_TO_RAD));
angles[1] = enforceRotationLimit(angles[1] + (y * FastMath.DEG_TO_RAD));
angles[2] = enforceRotationLimit(angles[2] + (z * FastMath.DEG_TO_RAD));
}
/**
* Sets all axis rotations by the given values in radians.
* @param x the X axis rotation in radians.
* @param y the Y axis rotation in radians.
* @param z the Z axis rotation in radians.
*/
public void set(float x, float y, float z) {
angles[0] = enforceRotationLimit(x);
angles[1] = enforceRotationLimit(y);
angles[2] = enforceRotationLimit(z);
}
/**
* Converts the angles to a quaternion.
* @return a quaternion of the angles.
*/
public Quaternion toQuaternion() {
if (quaternion == null) {
quaternion = new Quaternion();
}
quaternion.fromAngles(angles);
return quaternion;
}
/**
* Returns whether rotations are truncated to -FastMath.TWO_PI and FastMath.TWO_PI
* @return whether the rotations are truncated.
*/
public boolean isTruncateRotation() {
return truncateRotation;
}
/**
* Returns whether rotations are truncated to -FastMath.TWO_PI and FastMath.TWO_PI
*/
public void setTruncateRotation(boolean truncateRotation) {
this.truncateRotation = truncateRotation;
}
/**
* Ensures that all angles set by the user are between -FastMath.TWO_PI and FastMath.TWO_PI.
* @param input the angle in radians.
* @return an angle between -FastMath.TWO_PI and FastMath.TWO_PI.
*/
private float enforceRotationLimit(float input) {
if (!truncateRotation) {
return input;
}
// the input could be a potentially huge number, so continually reduce it until it's in the range we accept.
if (input > FastMath.TWO_PI) {
while (input > FastMath.TWO_PI) {
input -= FastMath.TWO_PI;
}
}
else if (input < -FastMath.TWO_PI) {
while (input < -FastMath.TWO_PI) {
input += FastMath.TWO_PI;
}
}
return input;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment