package com.jme.math;
/*
* Copyright (c) 2003-2008 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
/**
* <code>Quaternion</code> defines a single example of a more general class of
* hypercomplex numbers. Quaternions extends a rotation in three dimensions to a
* rotation in four dimensions. This avoids "gimbal lock" and allows for smooth
* continuous rotation.
*
* <code>Quaternion</code> is defined by four floating point numbers: {x y z
* w}.
*
* @author Mark Powell
* @author Joshua Slack
*/
public class Quaternion<region R> implements Externalizable {
private static final long serialVersionUID = 1L;
public float x in R, y in R, z in R, w in R;
/**
* Constructor instantiates a new <code>Quaternion</code> object
* initializing all values to zero, except w which is initialized to 1.
*
*/
public Quaternion() /*writes R*/ {
x = 0;
y = 0;
z = 0;
w = 1;
}
/**
* <code>toRotationMatrix</code> converts this quaternion to a rotational
* matrix. The result is stored in result.
*
* @param result
* The Matrix3f to store the result in.
* @return the rotation matrix representation of this quaternion.
*/
public <region Rresult> Matrix3f<Rresult>
toRotationMatrix(Matrix3f<Rresult> result)
reads R writes Rresult {
float norm = norm();
// we explicitly test norm against one here, saving a division
// at the cost of a test and branch. Is it worth it?
float s = (norm==1f) ? 2f : (norm > 0f) ? 2f/norm : 0;
// compute xs/ys/zs first to save 6 multiplications, since xs/ys/zs
// will be used 2-4 times each.
float xs = x * s;
float ys = y * s;
float zs = z * s;
float xx = x * xs;
float xy = x * ys;
float xz = x * zs;
float xw = w * xs;
float yy = y * ys;
float yz = y * zs;
float yw = w * ys;
float zz = z * zs;
float zw = w * zs;
// using s=2/norm (instead of 1/norm) saves 9 multiplications by 2 here
result.m00 = 1 - ( yy + zz );
result.m01 = ( xy - zw );
result.m02 = ( xz + yw );
result.m10 = ( xy + zw );
result.m11 = 1 - ( xx + zz );
result.m12 = ( yz - xw );
result.m20 = ( xz - yw );
result.m21 = ( yz + xw );
result.m22 = 1 - ( xx + yy );
return result;
}
/**
* <code>mult</code> multiplies this quaternion by a parameter vector. The
* result is returned as a new vector.
*
* @param v
* the vector to multiply this quaternion by.
* @param store
* the vector to store the result in. It IS safe for v and store
* to be the same object.
* @return the result vector.
*/
public <region Rv, Rstore> Vector3f<Rstore>
mult(Vector3f<Rv> v, Vector3f<Rstore> store)
reads R, Rv writes Rstore {
if (store == null)
store = new Vector3f<Rstore>();
if (v.x == 0 && v.y == 0 && v.z == 0) {
store.set(0, 0, 0);
} else {
float vx = v.x, vy = v.y, vz = v.z;
store.x = w * w * vx + 2 * y * w * vz - 2 * z * w * vy + x * x
* vx + 2 * y * x * vy + 2 * z * x * vz - z * z * vx - y
* y * vx;
store.y = 2 * x * y * vx + y * y * vy + 2 * z * y * vz + 2 * w
* z * vx - z * z * vy + w * w * vy - 2 * x * w * vz - x
* x * vy;
store.z = 2 * x * z * vx + 2 * y * z * vy + z * z * vz - 2 * w
* y * vx - y * y * vz + 2 * w * x * vy - x * x * vz + w
* w * vz;
}
return store;
}
/**
* <code>norm</code> returns the norm of this quaternion. This is the dot
* product of this quaternion with itself.
*
* @return the norm of the quaternion.
*/
public float norm() reads R {
return w * w + x * x + y * y + z * z;
}
/**
* <code>readExternal</code> builds a quaternion from an
* <code>ObjectInput</code> object. <br>
* NOTE: Used with serialization. Not to be called manually.
*
* @param in
* the ObjectInput value to read from.
* @throws IOException
* if the ObjectInput value has problems reading a float.
* @see java.io.Externalizable
*/
public void readExternal(ObjectInput in) throws IOException {
x = in.readFloat();
y = in.readFloat();
z = in.readFloat();
w = in.readFloat();
}
/**
* <code>writeExternal</code> writes this quaternion out to a
* <code>ObjectOutput</code> object. NOTE: Used with serialization. Not to
* be called manually.
*
* @param out
* the object to write to.
* @throws IOException
* if writing to the ObjectOutput fails.
* @see java.io.Externalizable
*/
public void writeExternal(ObjectOutput out) throws IOException {
out.writeFloat(x);
out.writeFloat(y);
out.writeFloat(z);
out.writeFloat(w);
}
}