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); } }