/*
* Copyright 2016 Nathan Howard
*
* This file is part of OpenGrave
*
* OpenGrave is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenGrave is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenGrave. If not, see <http://www.gnu.org/licenses/>.
*/
package com.opengrave.og.util;
public class Quaternion {
public float x;
public float y;
public float z;
public float w;
public Quaternion() {
reset();
}
public Quaternion(float x, float y, float z, float w) {
set(x, y, z, w);
}
public Quaternion(float angle, Vector3f vec) {
float s = (float) Math.sin(angle / 2);
x = vec.x() * s;
y = vec.y() * s;
z = vec.z() * s;
w = (float) Math.cos(angle / 2);
}
public Quaternion(Quaternion q) {
set(q);
}
public float x() {
return x;
}
public Quaternion x(float x) {
this.x = x;
return this;
}
public float y() {
return y;
}
public Quaternion y(float y) {
this.y = y;
return this;
}
public float z() {
return z;
}
public Quaternion z(float z) {
this.z = z;
return this;
}
public float w() {
return w;
}
public Quaternion w(float w) {
this.w = w;
return this;
}
public Quaternion set(float x, float y, float z, float w) {
this.x = x;
this.y = y;
this.z = z;
this.w = w;
return this;
}
public Quaternion set(Quaternion q) {
return set(q.x, q.y, q.z, q.w);
}
public Quaternion reset() {
x = 0;
y = 0;
z = 0;
w = 1;
return this;
}
public float length() {
return (float) Math.sqrt(x * x + y * y + z * z + w * w);
}
public Quaternion normalise(Quaternion res) {
if (res == null) {
res = new Quaternion();
}
float length = 1f / length();
res.x = x * length;
res.y = y * length;
res.z = z * length;
res.w = w * length;
return res;
}
public float dot(Quaternion q) {
return x * q.x + y * q.y + z * q.z + w * q.w;
}
public Vector3f mult3(Vector3f v, Vector3f result) {
Vector3f quatVector = new Vector3f(x, y, z);
Vector3f uv = quatVector.cross(v, new Vector3f());
Vector3f uuv = quatVector.cross(uv, new Vector3f());
uv.mult(w * 2, uv);
uuv.mult(2, uuv);
return result.set(v).add(uv, null).add(uuv, null);
}
public Quaternion mult(Quaternion q, Quaternion res) {
if (res == null) {
res = new Quaternion();
}
float xx = w * q.x + x * q.w + y * q.z - z * q.y;
float yy = w * q.y + y * q.w + z * q.x - x * q.z;
float zz = w * q.z + z * q.w + x * q.y - y * q.x;
float ww = w * q.w - x * q.x - y * q.y - z * q.z;
res.x = xx;
res.y = yy;
res.z = zz;
res.w = ww;
return res;
}
public Quaternion conjugate(Quaternion res) {
if (res == null) {
res = new Quaternion();
}
res.x = x * -1;
res.y = y * -1;
res.z = z * -1;
return res;
}
public Quaternion inverse() {
return normalise(null).conjugate(null);
}
public Matrix4f toMatrix(Matrix4f mat4) {
if (mat4 == null) {
mat4 = new Matrix4f();
}
return mat4.set(new float[] { 1 - 2 * y * y - 2 * z * z, 2 * x * y + 2 * w * z, 2 * x * z - 2 * w * y, 0, 2 * x * y - 2 * w * z,
1 - 2 * x * x - 2 * z * z, 2 * y * z + 2 * w * x, 0, 2 * x * z + 2 * w * y, 2 * y * z - 2 * w * x, 1 - 2 * x * x - 2 * y * y, 0, 0, 0, 0, 1, });
}
public void setFromMatrix(Matrix4f mat) {
setFromMatrix(mat.get(0, 0), mat.get(0, 1), mat.get(0, 2), mat.get(1, 0), mat.get(1, 1), mat.get(1, 2), mat.get(2, 0), mat.get(2, 1), mat.get(2, 2));
}
private void setFromMatrix(float m00, float m01, float m02, float m10, float m11, float m12, float m20, float m21, float m22) {
float s;
float tr = m00 + m11 + m22;
if (tr >= 0.0) {
s = (float) Math.sqrt(tr + 1.0);
w = s * 0.5f;
s = 0.5f / s;
x = (m21 - m12) * s;
y = (m02 - m20) * s;
z = (m10 - m01) * s;
} else {
float max = Math.max(Math.max(m00, m11), m22);
if (max == m00) {
s = (float) Math.sqrt(m00 - (m11 + m22) + 1.0);
x = s * 0.5f;
s = 0.5f / s;
y = (m01 + m10) * s;
z = (m20 + m02) * s;
w = (m21 - m12) * s;
} else if (max == m11) {
s = (float) Math.sqrt(m11 - (m22 + m00) + 1.0);
y = s * 0.5f;
s = 0.5f / s;
z = (m12 + m21) * s;
x = (m01 + m10) * s;
w = (m02 - m20) * s;
} else {
s = (float) Math.sqrt(m22 - (m00 + m11) + 1.0);
z = s * 0.5f;
s = 0.5f / s;
x = (m20 + m02) * s;
y = (m12 + m21) * s;
w = (m10 - m01) * s;
}
}
}
}