/* Quaternion.java Copyright (c) 2015 NTT DOCOMO,INC. Released under the MIT license http://opensource.org/licenses/mit-license.php */ package org.deviceconnect.android.deviceplugin.theta.utils; public class Quaternion { private final float mReal; private final Vector3D mImaginary; public Quaternion(final Quaternion q) { this(q.real(), q.imaginary()); } public Quaternion(final float real, final Vector3D imaginary) { mReal = real; mImaginary = imaginary; } public float real() { return mReal; } public Vector3D imaginary() { return mImaginary; } public Quaternion conjugate() { return new Quaternion(real(), imaginary().multiply(-1)); } public Quaternion multiply(final Quaternion a) { final Quaternion b = this; // NOTE: // if Q = (q; V) and R = (r; W), // Q x R = (q * r - V * W; q * W + r * V + V x W) float real = a.real() * b.real() - Vector3D.innerProduct(a.imaginary(), b.imaginary()); Vector3D imaginary = Vector3D.add( a.imaginary().multiply(b.real()), b.imaginary().multiply(a.real()), Vector3D.outerProduct(a.imaginary(), b.imaginary())); return new Quaternion(real, imaginary); } public static Quaternion multiply(final Quaternion... args) { Quaternion v = args[args.length - 1]; for (int i = args.length - 2; i >= 0; i--) { v = v.multiply(args[i]); } return v; } public Vector3D rotate(final Vector3D target) { Quaternion P = new Quaternion(0, target); Quaternion Q = this; Quaternion R = this.conjugate(); return R.multiply(P).multiply(Q).imaginary(); } public static Vector3D rotate(final Vector3D point, final Vector3D nonNormalizedAxis, final float radian) { Quaternion Q = quaternionFromAxisAndAngle(nonNormalizedAxis.normalize(), radian); return Q.rotate(point); } public static Vector3D rotateXYZ(final Vector3D point, final float rotateX, final float rotateY, final float rotateZ) { Vector3D axisX = new Vector3D(1, 0, 0); Vector3D axisY = new Vector3D(0, 1, 0); Vector3D axisZ = new Vector3D(0, 0, 1); Vector3D result = point; result = Quaternion.rotate(result, axisX, rotateX); result = Quaternion.rotate(result, axisY, rotateY); result = Quaternion.rotate(result, axisZ, rotateZ); return result; } public static Quaternion quaternionFromAxisAndAngle(final Vector3D normalizedAxis, final float radian) { float c = (float) Math.cos(radian / 2.0f); float s = (float) Math.sin(radian / 2.0f); return new Quaternion(c, normalizedAxis.multiply(s)); } }