/**
* Copyright 2012 Jason Sorensen (sorensenj@smert.net)
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package net.smert.frameworkgl.math;
import java.nio.FloatBuffer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author Jason Sorensen <sorensenj@smert.net>
*/
public class Quaternion4f {
private final static Logger log = LoggerFactory.getLogger(Quaternion4f.class);
float w;
float x;
float y;
float z;
// Constructors
public Quaternion4f() {
identity();
}
public Quaternion4f(float w, float x, float y, float z) {
this.w = w;
this.x = x;
this.y = y;
this.z = z;
}
public Quaternion4f(float w, Vector3f vector) {
this.w = w;
this.x = vector.x;
this.y = vector.y;
this.z = vector.z;
}
public Quaternion4f(Matrix3f matrix) {
fromMatrix(matrix);
}
public Quaternion4f(Quaternion4f quaternion) {
w = quaternion.w;
x = quaternion.x;
y = quaternion.y;
z = quaternion.z;
}
// Conversion Operations
public void toFloatBuffer(FloatBuffer fbOut) {
fbOut.put(w);
fbOut.put(x);
fbOut.put(y);
fbOut.put(z);
}
public void toMatrix3(Matrix3f matrix) {
float wx = w * x;
float wy = w * y;
float wz = w * z;
float xx = x * x;
float xy = x * y;
float xz = x * z;
float yy = y * y;
float yz = y * z;
float zz = z * z;
matrix.setColumnMajor(
1f - 2f * (yy + zz),
2f * (xy - wz),
2f * (xz + wy),
2f * (xy + wz),
1f - 2f * (xx + zz),
2f * (yz - wx),
2f * (xz - wy),
2f * (yz + wx),
1f - 2f * (xx + yy));
}
// Scalar Operations
public float getAngle() {
return MathHelper.ArcCos(w) * 2f;
}
public float getW() {
return w;
}
public float getX() {
return x;
}
public float getY() {
return y;
}
public float getZ() {
return z;
}
public float magnitude() {
return MathHelper.Sqrt(w * w + x * x + y * y + z * z);
}
public float magnitudeSquared() {
return w * w + x * x + y * y + z * z;
}
// Quaternion Operations
public Quaternion4f fromAxisAngle(Vector3f vector, float degrees) {
float halftheta = MathHelper.ToRadians(degrees) * .5f;
float s = MathHelper.Sin(halftheta);
w = MathHelper.Cos(halftheta);
x = vector.x * s;
y = vector.y * s;
z = vector.z * s;
return this;
}
public final Quaternion4f fromMatrix(Matrix3f matrix) {
float t = matrix.xAxis.x + matrix.yAxis.y + matrix.zAxis.z;
if (t > MathHelper.ZERO_EPSILON) {
float s = MathHelper.Sqrt(t + 1f) * 2f;
w = .25f * s;
x = (matrix.zAxis.y - matrix.yAxis.z) / s;
y = (matrix.xAxis.z - matrix.zAxis.x) / s;
z = (matrix.yAxis.x - matrix.xAxis.y) / s;
} else if ((matrix.xAxis.x > matrix.yAxis.y) && (matrix.xAxis.x > matrix.zAxis.z)) {
float s = MathHelper.Sqrt(1f + matrix.xAxis.x - matrix.yAxis.y - matrix.zAxis.z) * 2f;
w = (matrix.zAxis.y - matrix.yAxis.z) / s;
x = .25f * s;
y = (matrix.xAxis.y + matrix.yAxis.x) / s;
z = (matrix.xAxis.z + matrix.zAxis.x) / s;
} else if (matrix.yAxis.y > matrix.zAxis.z) {
float s = MathHelper.Sqrt(1f + matrix.yAxis.y - matrix.xAxis.x - matrix.zAxis.z) * 2f;
w = (matrix.xAxis.z - matrix.zAxis.x) / s;
x = (matrix.xAxis.y + matrix.yAxis.x) / s;
y = .25f * s;
z = (matrix.yAxis.z + matrix.zAxis.y) / s;
} else {
float s = MathHelper.Sqrt(1f + matrix.zAxis.z - matrix.xAxis.x - matrix.yAxis.y) * 2f;
w = (matrix.yAxis.x - matrix.xAxis.y) / s;
x = (matrix.xAxis.z + matrix.zAxis.x) / s;
y = (matrix.yAxis.z + matrix.zAxis.y) / s;
z = .25f * s;
}
return this;
}
public final Quaternion4f identity() {
w = 1f;
x = 0f;
y = 0f;
z = 0f;
return this;
}
public Quaternion4f multiply(float value) {
w *= value;
x *= value;
y *= value;
z *= value;
return this;
}
public Quaternion4f multiply(Quaternion4f quaternion) {
set(
w * quaternion.w - x * quaternion.x - y * quaternion.y - z * quaternion.z,
w * quaternion.x + x * quaternion.w + y * quaternion.z - z * quaternion.y,
w * quaternion.y + y * quaternion.w + z * quaternion.x - x * quaternion.z,
w * quaternion.z + z * quaternion.w + x * quaternion.y - y * quaternion.x);
return this;
}
public Quaternion4f multiplyOut(Quaternion4f quaternion, Quaternion4f out) {
out.set(
w * quaternion.w - x * quaternion.x - y * quaternion.y - z * quaternion.z,
w * quaternion.x + x * quaternion.w + y * quaternion.z - z * quaternion.y,
w * quaternion.y + y * quaternion.w + z * quaternion.x - x * quaternion.z,
w * quaternion.z + z * quaternion.w + x * quaternion.y - y * quaternion.x);
return out;
}
public Quaternion4f normalize() {
float mag = magnitude();
if (mag < MathHelper.ZERO_EPSILON) {
log.warn("Divide By Zero. Magnitude: {} x: {} y: {} z: {} w: {}", mag, x, y, z, w);
return identity();
}
return multiply(1f / mag);
}
public Quaternion4f set(float w, float x, float y, float z) {
this.w = w;
this.x = x;
this.y = y;
this.z = z;
return this;
}
public Quaternion4f set(float w, Vector3f vector) {
this.w = w;
this.x = vector.x;
this.y = vector.y;
this.z = vector.z;
return this;
}
public Quaternion4f set(Quaternion4f quaternion) {
w = quaternion.w;
x = quaternion.x;
y = quaternion.y;
z = quaternion.z;
return this;
}
@Override
public int hashCode() {
int hash = 7;
hash = 37 * hash + Float.floatToIntBits(this.w);
hash = 37 * hash + Float.floatToIntBits(this.x);
hash = 37 * hash + Float.floatToIntBits(this.y);
hash = 37 * hash + Float.floatToIntBits(this.z);
return hash;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Quaternion4f other = (Quaternion4f) obj;
if (Float.floatToIntBits(this.w) != Float.floatToIntBits(other.w)) {
return false;
}
if (Float.floatToIntBits(this.x) != Float.floatToIntBits(other.x)) {
return false;
}
if (Float.floatToIntBits(this.y) != Float.floatToIntBits(other.y)) {
return false;
}
return Float.floatToIntBits(this.z) == Float.floatToIntBits(other.z);
}
@Override
public String toString() {
return "(x: " + x + " y: " + y + " z: " + z + " w: " + w + ")";
}
}