| /*********************************************************************** | |
| quaternion.cpp - A quaternion class | |
| ------------------------------------------------------------------- | |
| GLUI User Interface Toolkit (LGPL) | |
| Copyright (c) 1998 Paul Rademacher | |
| WWW: http://sourceforge.net/projects/glui/ | |
| Forums: http://sourceforge.net/forum/?group_id=92496 | |
| This library is free software; you can redistribute it and/or | |
| modify it under the terms of the GNU Lesser General Public | |
| License as published by the Free Software Foundation; either | |
| version 2.1 of the License, or (at your option) any later version. | |
| This library 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 | |
| Lesser General Public License for more details. | |
| You should have received a copy of the GNU Lesser General Public | |
| License along with this library; if not, write to the Free Software | |
| Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| ************************************************************************ | |
| Feb 1998, Paul Rademacher (rademach@cs.unc.edu) | |
| Oct 2003, Nigel Stewart - GLUI Code Cleaning | |
| ************************************************************************/ | |
| #include "quaternion.h" | |
| #include <cmath> | |
| #include "glui_internal.h" | |
| /******************************************* constructors **************/ | |
| quat::quat() | |
| { | |
| *this = quat_identity(); | |
| } | |
| quat::quat(const float x, const float y, const float z, const float w) | |
| { | |
| v.set( x, y, z ); | |
| s = w; | |
| } | |
| quat::quat(const vec3 &_v, const float _s) | |
| { | |
| set( _v, _s ); | |
| } | |
| quat::quat(const float _s, const vec3 &_v) | |
| { | |
| set( _v, _s ); | |
| } | |
| quat::quat(const float *d) | |
| { | |
| v[0] = d[0]; | |
| v[1] = d[1]; | |
| v[2] = d[2]; | |
| s = d[3]; | |
| } | |
| quat::quat(const double *d) | |
| { | |
| v[0] = (float) d[0]; | |
| v[1] = (float) d[1]; | |
| v[2] = (float) d[2]; | |
| s = (float) d[3]; | |
| } | |
| quat::quat(const quat &q) | |
| { | |
| v = q.v; | |
| s = q.s; | |
| } | |
| void quat::set(const vec3 &_v, const float _s) | |
| { | |
| v = _v; | |
| s = _s; | |
| } | |
| quat &quat::operator=(const quat &q) | |
| { | |
| v = q.v; | |
| s = q.s; | |
| return *this; | |
| } | |
| /******** quat friends ************/ | |
| quat operator + (const quat &a, const quat &b) | |
| { | |
| return quat( a.s+b.s, a.v+b.v ); | |
| } | |
| quat operator - (const quat &a, const quat &b) | |
| { | |
| return quat( a.s-b.s, a.v-b.v ); | |
| } | |
| quat operator - (const quat &a ) | |
| { | |
| return quat( -a.s, -a.v ); | |
| } | |
| quat operator * ( const quat &a, const quat &b) | |
| { | |
| return quat( a.s*b.s - a.v*b.v, a.s*b.v + b.s*a.v + a.v^b.v ); | |
| } | |
| quat operator * ( const quat &a, const float t) | |
| { | |
| return quat( a.v * t, a.s * t ); | |
| } | |
| quat operator * ( const float t, const quat &a ) | |
| { | |
| return quat( a.v * t, a.s * t ); | |
| } | |
| mat4 quat::to_mat4() const | |
| { | |
| float xs, ys, zs, wx, wy, wz, xx, xy, xz, yy, yz, zz; | |
| float t = 2.0f / (v*v + s*s); | |
| xs = v[VX]*t; ys = v[VY]*t; zs = v[VZ]*t; | |
| wx = s*xs; wy = s*ys; wz = s*zs; | |
| xx = v[VX]*xs; xy = v[VX]*ys; xz = v[VX]*zs; | |
| yy = v[VY]*ys; yz = v[VY]*zs; zz = v[VZ]*zs; | |
| mat4 matrix( | |
| 1.0f-(yy+zz), xy+wz, xz-wy, 0.0f, | |
| xy-wz, 1.0f-(xx+zz), yz+wx, 0.0f, | |
| xz+wy, yz-wx, 1.0f-(xx+yy), 0.0f, | |
| 0.0f, 0.0f, 0.0f, 1.0f ); | |
| return matrix; | |
| } | |
| /************************************************* quat_identity() *****/ | |
| /* Returns quaternion identity element */ | |
| quat quat_identity() | |
| { | |
| return quat( vec3( 0.0, 0.0, 0.0 ), 1.0 ); | |
| } | |
| /************************************************ quat_slerp() ********/ | |
| /* Quaternion spherical interpolation */ | |
| quat quat_slerp(const quat &from, const quat &to, float t) | |
| { | |
| quat to1; | |
| float omega, cosom, sinom, scale0, scale1; | |
| /* calculate cosine */ | |
| cosom = from.v * to.v + from.s + to.s; | |
| /* Adjust signs (if necessary) */ | |
| if ( cosom < 0.0 ) | |
| { | |
| cosom = -cosom; | |
| to1 = -to; | |
| } | |
| else | |
| { | |
| to1 = to; | |
| } | |
| /* Calculate coefficients */ | |
| if ((1.0 - cosom) > FUDGE ) | |
| { | |
| /* standard case (slerp) */ | |
| omega = (float) acos( cosom ); | |
| sinom = (float) sin( omega ); | |
| scale0 = (float) sin((1.0 - t) * omega) / sinom; | |
| scale1 = (float) sin(t * omega) / sinom; | |
| } | |
| else | |
| { | |
| /* 'from' and 'to' are very close - just do linear interpolation */ | |
| scale0 = 1.0f - t; | |
| scale1 = t; | |
| } | |
| return scale0 * from + scale1 * to1; | |
| } | |
| /********************************************** set_angle() ************/ | |
| /* set rot angle (degrees) */ | |
| void quat::set_angle(float f) | |
| { | |
| vec3 axis = get_axis(); | |
| s = (float) cos( DEG2RAD( f ) / 2.0 ); | |
| v = axis * (float) sin(DEG2RAD(f) / 2.0); | |
| } | |
| /********************************************** scale_angle() ************/ | |
| /* scale rot angle (degrees) */ | |
| void quat::scale_angle(float f) | |
| { | |
| set_angle( f * get_angle() ); | |
| } | |
| /********************************************** get_angle() ************/ | |
| /* get rot angle (degrees). Assumes s is between -1 and 1 */ | |
| float quat::get_angle() const | |
| { | |
| return (float) RAD2DEG( 2.0 * acos( s ) ); | |
| } | |
| /********************************************* get_axis() **************/ | |
| vec3 quat::get_axis() const | |
| { | |
| float scale = (float) sin( acos( s ) ); | |
| if ( scale < FUDGE AND scale > -FUDGE ) | |
| return vec3( 0.0, 0.0, 0.0 ); | |
| else | |
| return v / scale; | |
| } | |
| /******************************************* quat::print() ************/ | |
| void quat::print(FILE *dest, const char *name) const | |
| { | |
| fprintf( dest, "%s: v:<%3.2f %3.2f %3.2f> s:%3.2f\n", | |
| name, v[0], v[1], v[2], s ); | |
| } |