| package universalelectricity.core.vector; |
| |
| /** |
| * Quaternion class designed to be used for the rotation of objects. |
| * |
| * Do not use in MC 1.6.4, subject to change! |
| * |
| * @author DarkGuardsman, Calclavia |
| */ |
| public class Quaternion implements Cloneable |
| { |
| public static final float TOLERANCE = 0.00001f; |
| public double x, y, z, w; |
| |
| public Quaternion() |
| { |
| this(0, 0, 0, 1); |
| } |
| |
| public Quaternion(Quaternion copy) |
| { |
| this(copy.x, copy.y, copy.z, copy.w); |
| } |
| |
| public Quaternion(double x, double y, double z, double w) |
| { |
| this.x = x; |
| this.y = y; |
| this.z = z; |
| this.w = w; |
| } |
| |
| /** |
| * Convert from Euler Angles. Basically we create 3 Quaternions, one for pitch, one for yaw, one |
| * for roll and multiply those together. the calculation below does the same, just shorter |
| */ |
| public Quaternion(float pitch, float yaw, float roll) |
| { |
| float p = (float) (pitch * (Math.PI / 180) / 2.0); |
| float y = (float) (yaw * (Math.PI / 180) / 2.0); |
| float r = (float) (roll * (Math.PI / 180) / 2.0); |
| |
| float sinp = (float) Math.sin(p); |
| float siny = (float) Math.sin(y); |
| float sinr = (float) Math.sin(r); |
| float cosp = (float) Math.cos(p); |
| float cosy = (float) Math.cos(y); |
| float cosr = (float) Math.cos(r); |
| |
| this.x = sinr * cosp * cosy - cosr * sinp * siny; |
| this.y = cosr * sinp * cosy + sinr * cosp * siny; |
| this.z = cosr * cosp * siny - sinr * sinp * cosy; |
| this.w = cosr * cosp * cosy + sinr * sinp * siny; |
| |
| this.normalize(); |
| } |
| |
| public Quaternion(Vector3 vector, double w) |
| { |
| this(vector.x, vector.y, vector.z, w); |
| } |
| |
| public static Quaternion IDENTITY() |
| { |
| return new Quaternion(); |
| } |
| |
| public Quaternion set(Quaternion quaternion) |
| { |
| this.w = quaternion.w; |
| this.x = quaternion.x; |
| this.y = quaternion.y; |
| this.z = quaternion.z; |
| return this; |
| } |
| |
| public Quaternion set(double x, double y, double z, double w) |
| { |
| return this.set(new Quaternion(x, y, z, w)); |
| } |
| |
| public Quaternion normalize() |
| { |
| double magnitude = this.magnitude(); |
| this.x /= magnitude; |
| this.y /= magnitude; |
| this.z /= magnitude; |
| this.w /= magnitude; |
| return this; |
| } |
| |
| public double magnitude() |
| { |
| return Math.sqrt(this.magnitudeSquared()); |
| } |
| |
| public double magnitudeSquared() |
| { |
| return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w; |
| } |
| |
| public Quaternion inverse() |
| { |
| double d = this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w; |
| return new Quaternion(this.x / d, -this.y / d, -this.z / d, -this.w / d); |
| } |
| |
| /** |
| * Gets the conjugate of this Quaternion |
| */ |
| public Quaternion getConjugate() |
| { |
| return this.clone().conjugate(); |
| } |
| |
| public Quaternion conjugate() |
| { |
| this.y = -this.y; |
| this.z = -this.z; |
| this.w = -this.w; |
| return this; |
| } |
| |
| /** |
| * Let the current quaternion be "a". Multiplying the a with b applies the rotation a to b. |
| */ |
| public Quaternion getMultiply(Quaternion b) |
| { |
| return this.clone().multiply(b); |
| } |
| |
| public Quaternion multiply(Quaternion b) |
| { |
| Quaternion a = this; |
| double newX = a.x * b.x - a.y * b.y - a.z * b.z - a.w * b.w; |
| double newY = a.x * b.y + a.y * b.x + a.z * b.w - a.w * b.z; |
| double newZ = a.x * b.z - a.y * b.w + a.z * b.x + a.w * b.y; |
| double newW = a.x * b.w + a.y * b.z - a.z * b.y + a.w * b.x; |
| this.set(newX, newY, newZ, newW); |
| return this; |
| } |
| |
| public Quaternion divide(Quaternion b) |
| { |
| Quaternion a = this; |
| return a.inverse().multiply(b); |
| } |
| |
| /** Multi a vector against this in other words applying rotation */ |
| public Vector3 multi(Vector3 vec) |
| { |
| Vector3 vn = vec.clone(); |
| |
| Quaternion vecQuat = new Quaternion(0, 0, 0, 1), resQuat; |
| vecQuat.x = (float) vn.x; |
| vecQuat.y = (float) vn.y; |
| vecQuat.z = (float) vn.z; |
| vecQuat.w = 0.0f; |
| |
| resQuat = vecQuat.multiply(this.getConjugate()); |
| resQuat = this.multiply(resQuat); |
| |
| return new Vector3(resQuat.x, resQuat.y, resQuat.z); |
| } |
| |
| public static Quaternion fromAxis(Vector3 vector, double angle) |
| { |
| angle *= 0.5f; |
| Vector3 vn = vector.clone().normalize(); |
| float sinAngle = (float) Math.sin(angle); |
| return new Quaternion(vn.x * sinAngle, vn.y * sinAngle, vn.z * sinAngle, Math.cos(angle)); |
| } |
| |
| /* |
| * Convert to Matrix public Matrix4 getMatrix() { float x2 = (float) (x * x); float y2 = (float) |
| * (y * y); float z2 = (float) (z * z); float xy = (float) (x * y); float xz = (float) (x * z); |
| * float yz = (float) (y * z); float wx = (float) (w * x); float wy = (float) (w * y); float wz |
| * = (float) (w * z); |
| * |
| * // This calculation would be a lot more complicated for non-unit length quaternions // Note: |
| * The constructor of Matrix4 expects the Matrix in column-major format like expected // by // |
| * OpenGL return new Matrix4(1.0f - 2.0f * (y2 + z2), 2.0f * (xy - wz), 2.0f * (xz + wy), 0.0f, |
| * 2.0f * (xy + wz), 1.0f - 2.0f * (x2 + z2), 2.0f * (yz - wx), 0.0f, 2.0f * (xz - wy), 2.0f * |
| * (yz + wx), 1.0f - 2.0f * (x2 + y2), 0.0f, 0.0f, 0.0f, 0.0f, 1.0f); } |
| */ |
| |
| /** |
| * Convert to Axis/Angles |
| * |
| * @param axis - The axis of rotation |
| * @param angle - The angle of rotation |
| */ |
| public void getAxisAngle(Vector3 axis, float angle) |
| { |
| float scale = (float) axis.getMagnitude(); |
| this.x = this.x / scale; |
| this.y = this.y / scale; |
| this.z = this.z / scale; |
| angle = (float) (Math.acos(this.w) * 2.0f); |
| } |
| |
| @Override |
| public Quaternion clone() |
| { |
| return new Quaternion(this); |
| } |
| |
| @Override |
| public String toString() |
| { |
| return "Quaternion [" + x + ", " + y + ", " + z + ", " + w + "]"; |
| } |
| } |