Last active
October 19, 2020 15:36
-
-
Save jayfella/d1cb54a3f0b75bfd9b2d05a4bfd97588 to your computer and use it in GitHub Desktop.
A class to simplify rotations and quaternions.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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