Path: blob/master/3rdparty/openexr/Imath/ImathQuat.h
16337 views
///////////////////////////////////////////////////////////////////////////1//2// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas3// Digital Ltd. LLC4//5// All rights reserved.6//7// Redistribution and use in source and binary forms, with or without8// modification, are permitted provided that the following conditions are9// met:10// * Redistributions of source code must retain the above copyright11// notice, this list of conditions and the following disclaimer.12// * Redistributions in binary form must reproduce the above13// copyright notice, this list of conditions and the following disclaimer14// in the documentation and/or other materials provided with the15// distribution.16// * Neither the name of Industrial Light & Magic nor the names of17// its contributors may be used to endorse or promote products derived18// from this software without specific prior written permission.19//20// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS21// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT22// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR23// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT24// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,25// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT26// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,27// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY28// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT29// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE30// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.31//32///////////////////////////////////////////////////////////////////////////33343536#ifndef INCLUDED_IMATHQUAT_H37#define INCLUDED_IMATHQUAT_H3839//----------------------------------------------------------------------40//41// template class Quat<T>42//43// "Quaternions came from Hamilton ... and have been an unmixed44// evil to those who have touched them in any way. Vector is a45// useless survival ... and has never been of the slightest use46// to any creature."47//48// - Lord Kelvin49//50// This class implements the quaternion numerical type -- you51// will probably want to use this class to represent orientations52// in R3 and to convert between various euler angle reps. You53// should probably use Imath::Euler<> for that.54//55//----------------------------------------------------------------------5657#include "ImathExc.h"58#include "ImathMatrix.h"5960#include <iostream>6162namespace Imath {6364#if (defined _WIN32 || defined _WIN64) && defined _MSC_VER65// Disable MS VC++ warnings about conversion from double to float66#pragma warning(disable:4244)67#endif6869template <class T>70class Quat71{72public:7374T r; // real part75Vec3<T> v; // imaginary vector767778//-----------------------------------------------------79// Constructors - default constructor is identity quat80//-----------------------------------------------------8182Quat ();8384template <class S>85Quat (const Quat<S> &q);8687Quat (T s, T i, T j, T k);8889Quat (T s, Vec3<T> d);9091static Quat<T> identity ();929394//-------------------------------------------------95// Basic Algebra - Operators and Methods96// The operator return values are *NOT* normalized97//98// operator^ and euclideanInnnerProduct() both99// implement the 4D dot product100//101// operator/ uses the inverse() quaternion102//103// operator~ is conjugate -- if (S+V) is quat then104// the conjugate (S+V)* == (S-V)105//106// some operators (*,/,*=,/=) treat the quat as107// a 4D vector when one of the operands is scalar108//-------------------------------------------------109110const Quat<T> & operator = (const Quat<T> &q);111const Quat<T> & operator *= (const Quat<T> &q);112const Quat<T> & operator *= (T t);113const Quat<T> & operator /= (const Quat<T> &q);114const Quat<T> & operator /= (T t);115const Quat<T> & operator += (const Quat<T> &q);116const Quat<T> & operator -= (const Quat<T> &q);117T & operator [] (int index); // as 4D vector118T operator [] (int index) const;119120template <class S> bool operator == (const Quat<S> &q) const;121template <class S> bool operator != (const Quat<S> &q) const;122123Quat<T> & invert (); // this -> 1 / this124Quat<T> inverse () const;125Quat<T> & normalize (); // returns this126Quat<T> normalized () const;127T length () const; // in R4128Vec3<T> rotateVector(const Vec3<T> &original) const;129T euclideanInnerProduct(const Quat<T> &q) const;130131//-----------------------132// Rotation conversion133//-----------------------134135Quat<T> & setAxisAngle (const Vec3<T> &axis, T radians);136137Quat<T> & setRotation (const Vec3<T> &fromDirection,138const Vec3<T> &toDirection);139140T angle () const;141Vec3<T> axis () const;142143Matrix33<T> toMatrix33 () const;144Matrix44<T> toMatrix44 () const;145146Quat<T> log () const;147Quat<T> exp () const;148149150private:151152void setRotationInternal (const Vec3<T> &f0,153const Vec3<T> &t0,154Quat<T> &q);155};156157158template<class T>159Quat<T> slerp (const Quat<T> &q1, const Quat<T> &q2, T t);160161template<class T>162Quat<T> slerpShortestArc163(const Quat<T> &q1, const Quat<T> &q2, T t);164165166template<class T>167Quat<T> squad (const Quat<T> &q1, const Quat<T> &q2,168const Quat<T> &qa, const Quat<T> &qb, T t);169170template<class T>171void intermediate (const Quat<T> &q0, const Quat<T> &q1,172const Quat<T> &q2, const Quat<T> &q3,173Quat<T> &qa, Quat<T> &qb);174175template<class T>176Matrix33<T> operator * (const Matrix33<T> &M, const Quat<T> &q);177178template<class T>179Matrix33<T> operator * (const Quat<T> &q, const Matrix33<T> &M);180181template<class T>182std::ostream & operator << (std::ostream &o, const Quat<T> &q);183184template<class T>185Quat<T> operator * (const Quat<T> &q1, const Quat<T> &q2);186187template<class T>188Quat<T> operator / (const Quat<T> &q1, const Quat<T> &q2);189190template<class T>191Quat<T> operator / (const Quat<T> &q, T t);192193template<class T>194Quat<T> operator * (const Quat<T> &q, T t);195196template<class T>197Quat<T> operator * (T t, const Quat<T> &q);198199template<class T>200Quat<T> operator + (const Quat<T> &q1, const Quat<T> &q2);201202template<class T>203Quat<T> operator - (const Quat<T> &q1, const Quat<T> &q2);204205template<class T>206Quat<T> operator ~ (const Quat<T> &q);207208template<class T>209Quat<T> operator - (const Quat<T> &q);210211template<class T>212Vec3<T> operator * (const Vec3<T> &v, const Quat<T> &q);213214215//--------------------216// Convenient typedefs217//--------------------218219typedef Quat<float> Quatf;220typedef Quat<double> Quatd;221222223//---------------224// Implementation225//---------------226227template<class T>228inline229Quat<T>::Quat (): r (1), v (0, 0, 0)230{231// empty232}233234235template<class T>236template <class S>237inline238Quat<T>::Quat (const Quat<S> &q): r (q.r), v (q.v)239{240// empty241}242243244template<class T>245inline246Quat<T>::Quat (T s, T i, T j, T k): r (s), v (i, j, k)247{248// empty249}250251252template<class T>253inline254Quat<T>::Quat (T s, Vec3<T> d): r (s), v (d)255{256// empty257}258259260template<class T>261inline Quat<T>262Quat<T>::identity ()263{264return Quat<T>();265}266267template<class T>268inline const Quat<T> &269Quat<T>::operator = (const Quat<T> &q)270{271r = q.r;272v = q.v;273return *this;274}275276277template<class T>278inline const Quat<T> &279Quat<T>::operator *= (const Quat<T> &q)280{281T rtmp = r * q.r - (v ^ q.v);282v = r * q.v + v * q.r + v % q.v;283r = rtmp;284return *this;285}286287288template<class T>289inline const Quat<T> &290Quat<T>::operator *= (T t)291{292r *= t;293v *= t;294return *this;295}296297298template<class T>299inline const Quat<T> &300Quat<T>::operator /= (const Quat<T> &q)301{302*this = *this * q.inverse();303return *this;304}305306307template<class T>308inline const Quat<T> &309Quat<T>::operator /= (T t)310{311r /= t;312v /= t;313return *this;314}315316317template<class T>318inline const Quat<T> &319Quat<T>::operator += (const Quat<T> &q)320{321r += q.r;322v += q.v;323return *this;324}325326327template<class T>328inline const Quat<T> &329Quat<T>::operator -= (const Quat<T> &q)330{331r -= q.r;332v -= q.v;333return *this;334}335336337template<class T>338inline T &339Quat<T>::operator [] (int index)340{341return index ? v[index - 1] : r;342}343344345template<class T>346inline T347Quat<T>::operator [] (int index) const348{349return index ? v[index - 1] : r;350}351352353template <class T>354template <class S>355inline bool356Quat<T>::operator == (const Quat<S> &q) const357{358return r == q.r && v == q.v;359}360361362template <class T>363template <class S>364inline bool365Quat<T>::operator != (const Quat<S> &q) const366{367return r != q.r || v != q.v;368}369370371template<class T>372inline T373operator ^ (const Quat<T>& q1 ,const Quat<T>& q2)374{375return q1.r * q2.r + (q1.v ^ q2.v);376}377378379template <class T>380inline T381Quat<T>::length () const382{383return Math<T>::sqrt (r * r + (v ^ v));384}385386387template <class T>388inline Quat<T> &389Quat<T>::normalize ()390{391if (T l = length())392{393r /= l;394v /= l;395}396else397{398r = 1;399v = Vec3<T> (0);400}401402return *this;403}404405406template <class T>407inline Quat<T>408Quat<T>::normalized () const409{410if (T l = length())411return Quat (r / l, v / l);412413return Quat();414}415416417template<class T>418inline Quat<T>419Quat<T>::inverse () const420{421//422// 1 Q*423// - = ---- where Q* is conjugate (operator~)424// Q Q* Q and (Q* Q) == Q ^ Q (4D dot)425//426427T qdot = *this ^ *this;428return Quat (r / qdot, -v / qdot);429}430431432template<class T>433inline Quat<T> &434Quat<T>::invert ()435{436T qdot = (*this) ^ (*this);437r /= qdot;438v = -v / qdot;439return *this;440}441442443template<class T>444inline Vec3<T>445Quat<T>::rotateVector(const Vec3<T>& original) const446{447//448// Given a vector p and a quaternion q (aka this),449// calculate p' = qpq*450//451// Assumes unit quaternions (because non-unit452// quaternions cannot be used to rotate vectors453// anyway).454//455456Quat<T> vec (0, original); // temporarily promote grade of original457Quat<T> inv (*this);458inv.v *= -1; // unit multiplicative inverse459Quat<T> result = *this * vec * inv;460return result.v;461}462463464template<class T>465inline T466Quat<T>::euclideanInnerProduct (const Quat<T> &q) const467{468return r * q.r + v.x * q.v.x + v.y * q.v.y + v.z * q.v.z;469}470471472template<class T>473T474angle4D (const Quat<T> &q1, const Quat<T> &q2)475{476//477// Compute the angle between two quaternions,478// interpreting the quaternions as 4D vectors.479//480481Quat<T> d = q1 - q2;482T lengthD = Math<T>::sqrt (d ^ d);483484Quat<T> s = q1 + q2;485T lengthS = Math<T>::sqrt (s ^ s);486487return 2 * Math<T>::atan2 (lengthD, lengthS);488}489490491template<class T>492Quat<T>493slerp (const Quat<T> &q1, const Quat<T> &q2, T t)494{495//496// Spherical linear interpolation.497// Assumes q1 and q2 are normalized and that q1 != -q2.498//499// This method does *not* interpolate along the shortest500// arc between q1 and q2. If you desire interpolation501// along the shortest arc, and q1^q2 is negative, then502// consider calling slerpShortestArc(), below, or flipping503// the second quaternion explicitly.504//505// The implementation of squad() depends on a slerp()506// that interpolates as is, without the automatic507// flipping.508//509// Don Hatch explains the method we use here on his510// web page, The Right Way to Calculate Stuff, at511// http://www.plunk.org/~hatch/rightway.php512//513514T a = angle4D (q1, q2);515T s = 1 - t;516517Quat<T> q = sinx_over_x (s * a) / sinx_over_x (a) * s * q1 +518sinx_over_x (t * a) / sinx_over_x (a) * t * q2;519520return q.normalized();521}522523524template<class T>525Quat<T>526slerpShortestArc (const Quat<T> &q1, const Quat<T> &q2, T t)527{528//529// Spherical linear interpolation along the shortest530// arc from q1 to either q2 or -q2, whichever is closer.531// Assumes q1 and q2 are unit quaternions.532//533534if ((q1 ^ q2) >= 0)535return slerp (q1, q2, t);536else537return slerp (q1, -q2, t);538}539540541template<class T>542Quat<T>543spline (const Quat<T> &q0, const Quat<T> &q1,544const Quat<T> &q2, const Quat<T> &q3,545T t)546{547//548// Spherical Cubic Spline Interpolation -549// from Advanced Animation and Rendering550// Techniques by Watt and Watt, Page 366:551// A spherical curve is constructed using three552// spherical linear interpolations of a quadrangle553// of unit quaternions: q1, qa, qb, q2.554// Given a set of quaternion keys: q0, q1, q2, q3,555// this routine does the interpolation between556// q1 and q2 by constructing two intermediate557// quaternions: qa and qb. The qa and qb are558// computed by the intermediate function to559// guarantee the continuity of tangents across560// adjacent cubic segments. The qa represents in-tangent561// for q1 and the qb represents the out-tangent for q2.562//563// The q1 q2 is the cubic segment being interpolated.564// The q0 is from the previous adjacent segment and q3 is565// from the next adjacent segment. The q0 and q3 are used566// in computing qa and qb.567//568569Quat<T> qa = intermediate (q0, q1, q2);570Quat<T> qb = intermediate (q1, q2, q3);571Quat<T> result = squad (q1, qa, qb, q2, t);572573return result;574}575576577template<class T>578Quat<T>579squad (const Quat<T> &q1, const Quat<T> &qa,580const Quat<T> &qb, const Quat<T> &q2,581T t)582{583//584// Spherical Quadrangle Interpolation -585// from Advanced Animation and Rendering586// Techniques by Watt and Watt, Page 366:587// It constructs a spherical cubic interpolation as588// a series of three spherical linear interpolations589// of a quadrangle of unit quaternions.590//591592Quat<T> r1 = slerp (q1, q2, t);593Quat<T> r2 = slerp (qa, qb, t);594Quat<T> result = slerp (r1, r2, 2 * t * (1 - t));595596return result;597}598599600template<class T>601Quat<T>602intermediate (const Quat<T> &q0, const Quat<T> &q1, const Quat<T> &q2)603{604//605// From advanced Animation and Rendering606// Techniques by Watt and Watt, Page 366:607// computing the inner quadrangle608// points (qa and qb) to guarantee tangent609// continuity.610//611612Quat<T> q1inv = q1.inverse();613Quat<T> c1 = q1inv * q2;614Quat<T> c2 = q1inv * q0;615Quat<T> c3 = (T) (-0.25) * (c2.log() + c1.log());616Quat<T> qa = q1 * c3.exp();617qa.normalize();618return qa;619}620621622template <class T>623inline Quat<T>624Quat<T>::log () const625{626//627// For unit quaternion, from Advanced Animation and628// Rendering Techniques by Watt and Watt, Page 366:629//630631T theta = Math<T>::acos (std::min (r, (T) 1.0));632633if (theta == 0)634return Quat<T> (0, v);635636T sintheta = Math<T>::sin (theta);637638T k;639if (abs (sintheta) < 1 && abs (theta) >= limits<T>::max() * abs (sintheta))640k = 1;641else642k = theta / sintheta;643644return Quat<T> ((T) 0, v.x * k, v.y * k, v.z * k);645}646647648template <class T>649inline Quat<T>650Quat<T>::exp () const651{652//653// For pure quaternion (zero scalar part):654// from Advanced Animation and Rendering655// Techniques by Watt and Watt, Page 366:656//657658T theta = v.length();659T sintheta = Math<T>::sin (theta);660661T k;662if (abs (theta) < 1 && abs (sintheta) >= limits<T>::max() * abs (theta))663k = 1;664else665k = sintheta / theta;666667T costheta = Math<T>::cos (theta);668669return Quat<T> (costheta, v.x * k, v.y * k, v.z * k);670}671672673template <class T>674inline T675Quat<T>::angle () const676{677return 2 * Math<T>::atan2 (v.length(), r);678}679680681template <class T>682inline Vec3<T>683Quat<T>::axis () const684{685return v.normalized();686}687688689template <class T>690inline Quat<T> &691Quat<T>::setAxisAngle (const Vec3<T> &axis, T radians)692{693r = Math<T>::cos (radians / 2);694v = axis.normalized() * Math<T>::sin (radians / 2);695return *this;696}697698699template <class T>700Quat<T> &701Quat<T>::setRotation (const Vec3<T> &from, const Vec3<T> &to)702{703//704// Create a quaternion that rotates vector from into vector to,705// such that the rotation is around an axis that is the cross706// product of from and to.707//708// This function calls function setRotationInternal(), which is709// numerically accurate only for rotation angles that are not much710// greater than pi/2. In order to achieve good accuracy for angles711// greater than pi/2, we split large angles in half, and rotate in712// two steps.713//714715//716// Normalize from and to, yielding f0 and t0.717//718719Vec3<T> f0 = from.normalized();720Vec3<T> t0 = to.normalized();721722if ((f0 ^ t0) >= 0)723{724//725// The rotation angle is less than or equal to pi/2.726//727728setRotationInternal (f0, t0, *this);729}730else731{732//733// The angle is greater than pi/2. After computing h0,734// which is halfway between f0 and t0, we rotate first735// from f0 to h0, then from h0 to t0.736//737738Vec3<T> h0 = (f0 + t0).normalized();739740if ((h0 ^ h0) != 0)741{742setRotationInternal (f0, h0, *this);743744Quat<T> q;745setRotationInternal (h0, t0, q);746747*this *= q;748}749else750{751//752// f0 and t0 point in exactly opposite directions.753// Pick an arbitrary axis that is orthogonal to f0,754// and rotate by pi.755//756757r = T (0);758759Vec3<T> f02 = f0 * f0;760761if (f02.x <= f02.y && f02.x <= f02.z)762v = (f0 % Vec3<T> (1, 0, 0)).normalized();763else if (f02.y <= f02.z)764v = (f0 % Vec3<T> (0, 1, 0)).normalized();765else766v = (f0 % Vec3<T> (0, 0, 1)).normalized();767}768}769770return *this;771}772773774template <class T>775void776Quat<T>::setRotationInternal (const Vec3<T> &f0, const Vec3<T> &t0, Quat<T> &q)777{778//779// The following is equivalent to setAxisAngle(n,2*phi),780// where the rotation axis, n, is orthogonal to the f0 and781// t0 vectors, and 2*phi is the angle between f0 and t0.782//783// This function is called by setRotation(), above; it assumes784// that f0 and t0 are normalized and that the angle between785// them is not much greater than pi/2. This function becomes786// numerically inaccurate if f0 and t0 point into nearly787// opposite directions.788//789790//791// Find a normalized vector, h0, that is halfway between f0 and t0.792// The angle between f0 and h0 is phi.793//794795Vec3<T> h0 = (f0 + t0).normalized();796797//798// Store the rotation axis and rotation angle.799//800801q.r = f0 ^ h0; // f0 ^ h0 == cos (phi)802q.v = f0 % h0; // (f0 % h0).length() == sin (phi)803}804805806template<class T>807Matrix33<T>808Quat<T>::toMatrix33() const809{810return Matrix33<T> (1 - 2 * (v.y * v.y + v.z * v.z),8112 * (v.x * v.y + v.z * r),8122 * (v.z * v.x - v.y * r),8138142 * (v.x * v.y - v.z * r),8151 - 2 * (v.z * v.z + v.x * v.x),8162 * (v.y * v.z + v.x * r),8178182 * (v.z * v.x + v.y * r),8192 * (v.y * v.z - v.x * r),8201 - 2 * (v.y * v.y + v.x * v.x));821}822823template<class T>824Matrix44<T>825Quat<T>::toMatrix44() const826{827return Matrix44<T> (1 - 2 * (v.y * v.y + v.z * v.z),8282 * (v.x * v.y + v.z * r),8292 * (v.z * v.x - v.y * r),8300,8312 * (v.x * v.y - v.z * r),8321 - 2 * (v.z * v.z + v.x * v.x),8332 * (v.y * v.z + v.x * r),8340,8352 * (v.z * v.x + v.y * r),8362 * (v.y * v.z - v.x * r),8371 - 2 * (v.y * v.y + v.x * v.x),8380,8390,8400,8410,8421);843}844845846template<class T>847inline Matrix33<T>848operator * (const Matrix33<T> &M, const Quat<T> &q)849{850return M * q.toMatrix33();851}852853854template<class T>855inline Matrix33<T>856operator * (const Quat<T> &q, const Matrix33<T> &M)857{858return q.toMatrix33() * M;859}860861862template<class T>863std::ostream &864operator << (std::ostream &o, const Quat<T> &q)865{866return o << "(" << q.r867<< " " << q.v.x868<< " " << q.v.y869<< " " << q.v.z870<< ")";871}872873874template<class T>875inline Quat<T>876operator * (const Quat<T> &q1, const Quat<T> &q2)877{878return Quat<T> (q1.r * q2.r - (q1.v ^ q2.v),879q1.r * q2.v + q1.v * q2.r + q1.v % q2.v);880}881882883template<class T>884inline Quat<T>885operator / (const Quat<T> &q1, const Quat<T> &q2)886{887return q1 * q2.inverse();888}889890891template<class T>892inline Quat<T>893operator / (const Quat<T> &q, T t)894{895return Quat<T> (q.r / t, q.v / t);896}897898899template<class T>900inline Quat<T>901operator * (const Quat<T> &q, T t)902{903return Quat<T> (q.r * t, q.v * t);904}905906907template<class T>908inline Quat<T>909operator * (T t, const Quat<T> &q)910{911return Quat<T> (q.r * t, q.v * t);912}913914915template<class T>916inline Quat<T>917operator + (const Quat<T> &q1, const Quat<T> &q2)918{919return Quat<T> (q1.r + q2.r, q1.v + q2.v);920}921922923template<class T>924inline Quat<T>925operator - (const Quat<T> &q1, const Quat<T> &q2)926{927return Quat<T> (q1.r - q2.r, q1.v - q2.v);928}929930931template<class T>932inline Quat<T>933operator ~ (const Quat<T> &q)934{935return Quat<T> (q.r, -q.v);936}937938939template<class T>940inline Quat<T>941operator - (const Quat<T> &q)942{943return Quat<T> (-q.r, -q.v);944}945946947template<class T>948inline Vec3<T>949operator * (const Vec3<T> &v, const Quat<T> &q)950{951Vec3<T> a = q.v % v;952Vec3<T> b = q.v % a;953return v + T (2) * (q.r * a + b);954}955956#if (defined _WIN32 || defined _WIN64) && defined _MSC_VER957#pragma warning(default:4244)958#endif959960} // namespace Imath961962#endif963964965