Path: blob/master/3rdparty/openexr/Imath/ImathMatrixAlgo.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///////////////////////////////////////////////////////////////////////////333435#ifndef INCLUDED_IMATHMATRIXALGO_H36#define INCLUDED_IMATHMATRIXALGO_H3738//-------------------------------------------------------------------------39//40// This file contains algorithms applied to or in conjunction with41// transformation matrices (Imath::Matrix33 and Imath::Matrix44).42// The assumption made is that these functions are called much less43// often than the basic point functions or these functions require44// more support classes.45//46// This file also defines a few predefined constant matrices.47//48//-------------------------------------------------------------------------4950#include "ImathMatrix.h"51#include "ImathQuat.h"52#include "ImathEuler.h"53#include "ImathExc.h"54#include "ImathVec.h"55#include "ImathLimits.h"56#include <math.h>575859#ifdef OPENEXR_DLL60#ifdef IMATH_EXPORTS61#define IMATH_EXPORT_CONST extern __declspec(dllexport)62#else63#define IMATH_EXPORT_CONST extern __declspec(dllimport)64#endif65#else66#define IMATH_EXPORT_CONST extern const67#endif686970namespace Imath {7172//------------------73// Identity matrices74//------------------7576IMATH_EXPORT_CONST M33f identity33f;77IMATH_EXPORT_CONST M44f identity44f;78IMATH_EXPORT_CONST M33d identity33d;79IMATH_EXPORT_CONST M44d identity44d;8081//----------------------------------------------------------------------82// Extract scale, shear, rotation, and translation values from a matrix:83//84// Notes:85//86// This implementation follows the technique described in the paper by87// Spencer W. Thomas in the Graphics Gems II article: "Decomposing a88// Matrix into Simple Transformations", p. 320.89//90// - Some of the functions below have an optional exc parameter91// that determines the functions' behavior when the matrix'92// scaling is very close to zero:93//94// If exc is true, the functions throw an Imath::ZeroScale exception.95//96// If exc is false:97//98// extractScaling (m, s) returns false, s is invalid99// sansScaling (m) returns m100// removeScaling (m) returns false, m is unchanged101// sansScalingAndShear (m) returns m102// removeScalingAndShear (m) returns false, m is unchanged103// extractAndRemoveScalingAndShear (m, s, h)104// returns false, m is unchanged,105// (sh) are invalid106// checkForZeroScaleInRow () returns false107// extractSHRT (m, s, h, r, t) returns false, (shrt) are invalid108//109// - Functions extractEuler(), extractEulerXYZ() and extractEulerZYX()110// assume that the matrix does not include shear or non-uniform scaling,111// but they do not examine the matrix to verify this assumption.112// Matrices with shear or non-uniform scaling are likely to produce113// meaningless results. Therefore, you should use the114// removeScalingAndShear() routine, if necessary, prior to calling115// extractEuler...() .116//117// - All functions assume that the matrix does not include perspective118// transformation(s), but they do not examine the matrix to verify119// this assumption. Matrices with perspective transformations are120// likely to produce meaningless results.121//122//----------------------------------------------------------------------123124125//126// Declarations for 4x4 matrix.127//128129template <class T> bool extractScaling130(const Matrix44<T> &mat,131Vec3<T> &scl,132bool exc = true);133134template <class T> Matrix44<T> sansScaling (const Matrix44<T> &mat,135bool exc = true);136137template <class T> bool removeScaling138(Matrix44<T> &mat,139bool exc = true);140141template <class T> bool extractScalingAndShear142(const Matrix44<T> &mat,143Vec3<T> &scl,144Vec3<T> &shr,145bool exc = true);146147template <class T> Matrix44<T> sansScalingAndShear148(const Matrix44<T> &mat,149bool exc = true);150151template <class T> void sansScalingAndShear152(Matrix44<T> &result,153const Matrix44<T> &mat,154bool exc = true);155156template <class T> bool removeScalingAndShear157(Matrix44<T> &mat,158bool exc = true);159160template <class T> bool extractAndRemoveScalingAndShear161(Matrix44<T> &mat,162Vec3<T> &scl,163Vec3<T> &shr,164bool exc = true);165166template <class T> void extractEulerXYZ167(const Matrix44<T> &mat,168Vec3<T> &rot);169170template <class T> void extractEulerZYX171(const Matrix44<T> &mat,172Vec3<T> &rot);173174template <class T> Quat<T> extractQuat (const Matrix44<T> &mat);175176template <class T> bool extractSHRT177(const Matrix44<T> &mat,178Vec3<T> &s,179Vec3<T> &h,180Vec3<T> &r,181Vec3<T> &t,182bool exc /*= true*/,183typename Euler<T>::Order rOrder);184185template <class T> bool extractSHRT186(const Matrix44<T> &mat,187Vec3<T> &s,188Vec3<T> &h,189Vec3<T> &r,190Vec3<T> &t,191bool exc = true);192193template <class T> bool extractSHRT194(const Matrix44<T> &mat,195Vec3<T> &s,196Vec3<T> &h,197Euler<T> &r,198Vec3<T> &t,199bool exc = true);200201//202// Internal utility function.203//204205template <class T> bool checkForZeroScaleInRow206(const T &scl,207const Vec3<T> &row,208bool exc = true);209210template <class T> Matrix44<T> outerProduct211( const Vec4<T> &a,212const Vec4<T> &b);213214215//216// Returns a matrix that rotates "fromDirection" vector to "toDirection"217// vector.218//219220template <class T> Matrix44<T> rotationMatrix (const Vec3<T> &fromDirection,221const Vec3<T> &toDirection);222223224225//226// Returns a matrix that rotates the "fromDir" vector227// so that it points towards "toDir". You may also228// specify that you want the up vector to be pointing229// in a certain direction "upDir".230//231232template <class T> Matrix44<T> rotationMatrixWithUpDir233(const Vec3<T> &fromDir,234const Vec3<T> &toDir,235const Vec3<T> &upDir);236237238//239// Constructs a matrix that rotates the z-axis so that it240// points towards "targetDir". You must also specify241// that you want the up vector to be pointing in a242// certain direction "upDir".243//244// Notes: The following degenerate cases are handled:245// (a) when the directions given by "toDir" and "upDir"246// are parallel or opposite;247// (the direction vectors must have a non-zero cross product)248// (b) when any of the given direction vectors have zero length249//250251template <class T> void alignZAxisWithTargetDir252(Matrix44<T> &result,253Vec3<T> targetDir,254Vec3<T> upDir);255256257// Compute an orthonormal direct frame from : a position, an x axis direction and a normal to the y axis258// If the x axis and normal are perpendicular, then the normal will have the same direction as the z axis.259// Inputs are :260// -the position of the frame261// -the x axis direction of the frame262// -a normal to the y axis of the frame263// Return is the orthonormal frame264template <class T> Matrix44<T> computeLocalFrame( const Vec3<T>& p,265const Vec3<T>& xDir,266const Vec3<T>& normal);267268// Add a translate/rotate/scale offset to an input frame269// and put it in another frame of reference270// Inputs are :271// - input frame272// - translate offset273// - rotate offset in degrees274// - scale offset275// - frame of reference276// Output is the offsetted frame277template <class T> Matrix44<T> addOffset( const Matrix44<T>& inMat,278const Vec3<T>& tOffset,279const Vec3<T>& rOffset,280const Vec3<T>& sOffset,281const Vec3<T>& ref);282283// Compute Translate/Rotate/Scale matrix from matrix A with the Rotate/Scale of Matrix B284// Inputs are :285// -keepRotateA : if true keep rotate from matrix A, use B otherwise286// -keepScaleA : if true keep scale from matrix A, use B otherwise287// -Matrix A288// -Matrix B289// Return Matrix A with tweaked rotation/scale290template <class T> Matrix44<T> computeRSMatrix( bool keepRotateA,291bool keepScaleA,292const Matrix44<T>& A,293const Matrix44<T>& B);294295296//----------------------------------------------------------------------297298299//300// Declarations for 3x3 matrix.301//302303304template <class T> bool extractScaling305(const Matrix33<T> &mat,306Vec2<T> &scl,307bool exc = true);308309template <class T> Matrix33<T> sansScaling (const Matrix33<T> &mat,310bool exc = true);311312template <class T> bool removeScaling313(Matrix33<T> &mat,314bool exc = true);315316template <class T> bool extractScalingAndShear317(const Matrix33<T> &mat,318Vec2<T> &scl,319T &h,320bool exc = true);321322template <class T> Matrix33<T> sansScalingAndShear323(const Matrix33<T> &mat,324bool exc = true);325326template <class T> bool removeScalingAndShear327(Matrix33<T> &mat,328bool exc = true);329330template <class T> bool extractAndRemoveScalingAndShear331(Matrix33<T> &mat,332Vec2<T> &scl,333T &shr,334bool exc = true);335336template <class T> void extractEuler337(const Matrix33<T> &mat,338T &rot);339340template <class T> bool extractSHRT (const Matrix33<T> &mat,341Vec2<T> &s,342T &h,343T &r,344Vec2<T> &t,345bool exc = true);346347template <class T> bool checkForZeroScaleInRow348(const T &scl,349const Vec2<T> &row,350bool exc = true);351352template <class T> Matrix33<T> outerProduct353( const Vec3<T> &a,354const Vec3<T> &b);355356357//-----------------------------------------------------------------------------358// Implementation for 4x4 Matrix359//------------------------------360361362template <class T>363bool364extractScaling (const Matrix44<T> &mat, Vec3<T> &scl, bool exc)365{366Vec3<T> shr;367Matrix44<T> M (mat);368369if (! extractAndRemoveScalingAndShear (M, scl, shr, exc))370return false;371372return true;373}374375376template <class T>377Matrix44<T>378sansScaling (const Matrix44<T> &mat, bool exc)379{380Vec3<T> scl;381Vec3<T> shr;382Vec3<T> rot;383Vec3<T> tran;384385if (! extractSHRT (mat, scl, shr, rot, tran, exc))386return mat;387388Matrix44<T> M;389390M.translate (tran);391M.rotate (rot);392M.shear (shr);393394return M;395}396397398template <class T>399bool400removeScaling (Matrix44<T> &mat, bool exc)401{402Vec3<T> scl;403Vec3<T> shr;404Vec3<T> rot;405Vec3<T> tran;406407if (! extractSHRT (mat, scl, shr, rot, tran, exc))408return false;409410mat.makeIdentity ();411mat.translate (tran);412mat.rotate (rot);413mat.shear (shr);414415return true;416}417418419template <class T>420bool421extractScalingAndShear (const Matrix44<T> &mat,422Vec3<T> &scl, Vec3<T> &shr, bool exc)423{424Matrix44<T> M (mat);425426if (! extractAndRemoveScalingAndShear (M, scl, shr, exc))427return false;428429return true;430}431432433template <class T>434Matrix44<T>435sansScalingAndShear (const Matrix44<T> &mat, bool exc)436{437Vec3<T> scl;438Vec3<T> shr;439Matrix44<T> M (mat);440441if (! extractAndRemoveScalingAndShear (M, scl, shr, exc))442return mat;443444return M;445}446447448template <class T>449void450sansScalingAndShear (Matrix44<T> &result, const Matrix44<T> &mat, bool exc)451{452Vec3<T> scl;453Vec3<T> shr;454455if (! extractAndRemoveScalingAndShear (result, scl, shr, exc))456result = mat;457}458459460template <class T>461bool462removeScalingAndShear (Matrix44<T> &mat, bool exc)463{464Vec3<T> scl;465Vec3<T> shr;466467if (! extractAndRemoveScalingAndShear (mat, scl, shr, exc))468return false;469470return true;471}472473474template <class T>475bool476extractAndRemoveScalingAndShear (Matrix44<T> &mat,477Vec3<T> &scl, Vec3<T> &shr, bool exc)478{479//480// This implementation follows the technique described in the paper by481// Spencer W. Thomas in the Graphics Gems II article: "Decomposing a482// Matrix into Simple Transformations", p. 320.483//484485Vec3<T> row[3];486487row[0] = Vec3<T> (mat[0][0], mat[0][1], mat[0][2]);488row[1] = Vec3<T> (mat[1][0], mat[1][1], mat[1][2]);489row[2] = Vec3<T> (mat[2][0], mat[2][1], mat[2][2]);490491T maxVal = 0;492for (int i=0; i < 3; i++)493for (int j=0; j < 3; j++)494if (Imath::abs (row[i][j]) > maxVal)495maxVal = Imath::abs (row[i][j]);496497//498// We normalize the 3x3 matrix here.499// It was noticed that this can improve numerical stability significantly,500// especially when many of the upper 3x3 matrix's coefficients are very501// close to zero; we correct for this step at the end by multiplying the502// scaling factors by maxVal at the end (shear and rotation are not503// affected by the normalization).504505if (maxVal != 0)506{507for (int i=0; i < 3; i++)508if (! checkForZeroScaleInRow (maxVal, row[i], exc))509return false;510else511row[i] /= maxVal;512}513514// Compute X scale factor.515scl.x = row[0].length ();516if (! checkForZeroScaleInRow (scl.x, row[0], exc))517return false;518519// Normalize first row.520row[0] /= scl.x;521522// An XY shear factor will shear the X coord. as the Y coord. changes.523// There are 6 combinations (XY, XZ, YZ, YX, ZX, ZY), although we only524// extract the first 3 because we can effect the last 3 by shearing in525// XY, XZ, YZ combined rotations and scales.526//527// shear matrix < 1, YX, ZX, 0,528// XY, 1, ZY, 0,529// XZ, YZ, 1, 0,530// 0, 0, 0, 1 >531532// Compute XY shear factor and make 2nd row orthogonal to 1st.533shr[0] = row[0].dot (row[1]);534row[1] -= shr[0] * row[0];535536// Now, compute Y scale.537scl.y = row[1].length ();538if (! checkForZeroScaleInRow (scl.y, row[1], exc))539return false;540541// Normalize 2nd row and correct the XY shear factor for Y scaling.542row[1] /= scl.y;543shr[0] /= scl.y;544545// Compute XZ and YZ shears, orthogonalize 3rd row.546shr[1] = row[0].dot (row[2]);547row[2] -= shr[1] * row[0];548shr[2] = row[1].dot (row[2]);549row[2] -= shr[2] * row[1];550551// Next, get Z scale.552scl.z = row[2].length ();553if (! checkForZeroScaleInRow (scl.z, row[2], exc))554return false;555556// Normalize 3rd row and correct the XZ and YZ shear factors for Z scaling.557row[2] /= scl.z;558shr[1] /= scl.z;559shr[2] /= scl.z;560561// At this point, the upper 3x3 matrix in mat is orthonormal.562// Check for a coordinate system flip. If the determinant563// is less than zero, then negate the matrix and the scaling factors.564if (row[0].dot (row[1].cross (row[2])) < 0)565for (int i=0; i < 3; i++)566{567scl[i] *= -1;568row[i] *= -1;569}570571// Copy over the orthonormal rows into the returned matrix.572// The upper 3x3 matrix in mat is now a rotation matrix.573for (int i=0; i < 3; i++)574{575mat[i][0] = row[i][0];576mat[i][1] = row[i][1];577mat[i][2] = row[i][2];578}579580// Correct the scaling factors for the normalization step that we581// performed above; shear and rotation are not affected by the582// normalization.583scl *= maxVal;584585return true;586}587588589template <class T>590void591extractEulerXYZ (const Matrix44<T> &mat, Vec3<T> &rot)592{593//594// Normalize the local x, y and z axes to remove scaling.595//596597Vec3<T> i (mat[0][0], mat[0][1], mat[0][2]);598Vec3<T> j (mat[1][0], mat[1][1], mat[1][2]);599Vec3<T> k (mat[2][0], mat[2][1], mat[2][2]);600601i.normalize();602j.normalize();603k.normalize();604605Matrix44<T> M (i[0], i[1], i[2], 0,606j[0], j[1], j[2], 0,607k[0], k[1], k[2], 0,6080, 0, 0, 1);609610//611// Extract the first angle, rot.x.612//613614rot.x = Math<T>::atan2 (M[1][2], M[2][2]);615616//617// Remove the rot.x rotation from M, so that the remaining618// rotation, N, is only around two axes, and gimbal lock619// cannot occur.620//621622Matrix44<T> N;623N.rotate (Vec3<T> (-rot.x, 0, 0));624N = N * M;625626//627// Extract the other two angles, rot.y and rot.z, from N.628//629630T cy = Math<T>::sqrt (N[0][0]*N[0][0] + N[0][1]*N[0][1]);631rot.y = Math<T>::atan2 (-N[0][2], cy);632rot.z = Math<T>::atan2 (-N[1][0], N[1][1]);633}634635636template <class T>637void638extractEulerZYX (const Matrix44<T> &mat, Vec3<T> &rot)639{640//641// Normalize the local x, y and z axes to remove scaling.642//643644Vec3<T> i (mat[0][0], mat[0][1], mat[0][2]);645Vec3<T> j (mat[1][0], mat[1][1], mat[1][2]);646Vec3<T> k (mat[2][0], mat[2][1], mat[2][2]);647648i.normalize();649j.normalize();650k.normalize();651652Matrix44<T> M (i[0], i[1], i[2], 0,653j[0], j[1], j[2], 0,654k[0], k[1], k[2], 0,6550, 0, 0, 1);656657//658// Extract the first angle, rot.x.659//660661rot.x = -Math<T>::atan2 (M[1][0], M[0][0]);662663//664// Remove the x rotation from M, so that the remaining665// rotation, N, is only around two axes, and gimbal lock666// cannot occur.667//668669Matrix44<T> N;670N.rotate (Vec3<T> (0, 0, -rot.x));671N = N * M;672673//674// Extract the other two angles, rot.y and rot.z, from N.675//676677T cy = Math<T>::sqrt (N[2][2]*N[2][2] + N[2][1]*N[2][1]);678rot.y = -Math<T>::atan2 (-N[2][0], cy);679rot.z = -Math<T>::atan2 (-N[1][2], N[1][1]);680}681682683template <class T>684Quat<T>685extractQuat (const Matrix44<T> &mat)686{687Matrix44<T> rot;688689T tr, s;690T q[4];691int i, j, k;692Quat<T> quat;693694int nxt[3] = {1, 2, 0};695tr = mat[0][0] + mat[1][1] + mat[2][2];696697// check the diagonal698if (tr > 0.0) {699s = Math<T>::sqrt (tr + T(1.0));700quat.r = s / T(2.0);701s = T(0.5) / s;702703quat.v.x = (mat[1][2] - mat[2][1]) * s;704quat.v.y = (mat[2][0] - mat[0][2]) * s;705quat.v.z = (mat[0][1] - mat[1][0]) * s;706}707else {708// diagonal is negative709i = 0;710if (mat[1][1] > mat[0][0])711i=1;712if (mat[2][2] > mat[i][i])713i=2;714715j = nxt[i];716k = nxt[j];717s = Math<T>::sqrt ((mat[i][i] - (mat[j][j] + mat[k][k])) + T(1.0));718719q[i] = s * T(0.5);720if (s != T(0.0))721s = T(0.5) / s;722723q[3] = (mat[j][k] - mat[k][j]) * s;724q[j] = (mat[i][j] + mat[j][i]) * s;725q[k] = (mat[i][k] + mat[k][i]) * s;726727quat.v.x = q[0];728quat.v.y = q[1];729quat.v.z = q[2];730quat.r = q[3];731}732733return quat;734}735736template <class T>737bool738extractSHRT (const Matrix44<T> &mat,739Vec3<T> &s,740Vec3<T> &h,741Vec3<T> &r,742Vec3<T> &t,743bool exc /* = true */ ,744typename Euler<T>::Order rOrder /* = Euler<T>::XYZ */ )745{746Matrix44<T> rot;747748rot = mat;749if (! extractAndRemoveScalingAndShear (rot, s, h, exc))750return false;751752extractEulerXYZ (rot, r);753754t.x = mat[3][0];755t.y = mat[3][1];756t.z = mat[3][2];757758if (rOrder != Euler<T>::XYZ)759{760Imath::Euler<T> eXYZ (r, Imath::Euler<T>::XYZ);761Imath::Euler<T> e (eXYZ, rOrder);762r = e.toXYZVector ();763}764765return true;766}767768template <class T>769bool770extractSHRT (const Matrix44<T> &mat,771Vec3<T> &s,772Vec3<T> &h,773Vec3<T> &r,774Vec3<T> &t,775bool exc)776{777return extractSHRT(mat, s, h, r, t, exc, Imath::Euler<T>::XYZ);778}779780template <class T>781bool782extractSHRT (const Matrix44<T> &mat,783Vec3<T> &s,784Vec3<T> &h,785Euler<T> &r,786Vec3<T> &t,787bool exc /* = true */)788{789return extractSHRT (mat, s, h, r, t, exc, r.order ());790}791792793template <class T>794bool795checkForZeroScaleInRow (const T& scl,796const Vec3<T> &row,797bool exc /* = true */ )798{799for (int i = 0; i < 3; i++)800{801if ((abs (scl) < 1 && abs (row[i]) >= limits<T>::max() * abs (scl)))802{803if (exc)804throw Imath::ZeroScaleExc ("Cannot remove zero scaling "805"from matrix.");806else807return false;808}809}810811return true;812}813814template <class T>815Matrix44<T>816outerProduct (const Vec4<T> &a, const Vec4<T> &b )817{818return Matrix44<T> (a.x*b.x, a.x*b.y, a.x*b.z, a.x*b.w,819a.y*b.x, a.y*b.y, a.y*b.z, a.x*b.w,820a.z*b.x, a.z*b.y, a.z*b.z, a.x*b.w,821a.w*b.x, a.w*b.y, a.w*b.z, a.w*b.w);822}823824template <class T>825Matrix44<T>826rotationMatrix (const Vec3<T> &from, const Vec3<T> &to)827{828Quat<T> q;829q.setRotation(from, to);830return q.toMatrix44();831}832833834template <class T>835Matrix44<T>836rotationMatrixWithUpDir (const Vec3<T> &fromDir,837const Vec3<T> &toDir,838const Vec3<T> &upDir)839{840//841// The goal is to obtain a rotation matrix that takes842// "fromDir" to "toDir". We do this in two steps and843// compose the resulting rotation matrices;844// (a) rotate "fromDir" into the z-axis845// (b) rotate the z-axis into "toDir"846//847848// The from direction must be non-zero; but we allow zero to and up dirs.849if (fromDir.length () == 0)850return Matrix44<T> ();851852else853{854Matrix44<T> zAxis2FromDir( Imath::UNINITIALIZED );855alignZAxisWithTargetDir (zAxis2FromDir, fromDir, Vec3<T> (0, 1, 0));856857Matrix44<T> fromDir2zAxis = zAxis2FromDir.transposed ();858859Matrix44<T> zAxis2ToDir( Imath::UNINITIALIZED );860alignZAxisWithTargetDir (zAxis2ToDir, toDir, upDir);861862return fromDir2zAxis * zAxis2ToDir;863}864}865866867template <class T>868void869alignZAxisWithTargetDir (Matrix44<T> &result, Vec3<T> targetDir, Vec3<T> upDir)870{871//872// Ensure that the target direction is non-zero.873//874875if ( targetDir.length () == 0 )876targetDir = Vec3<T> (0, 0, 1);877878//879// Ensure that the up direction is non-zero.880//881882if ( upDir.length () == 0 )883upDir = Vec3<T> (0, 1, 0);884885//886// Check for degeneracies. If the upDir and targetDir are parallel887// or opposite, then compute a new, arbitrary up direction that is888// not parallel or opposite to the targetDir.889//890891if (upDir.cross (targetDir).length () == 0)892{893upDir = targetDir.cross (Vec3<T> (1, 0, 0));894if (upDir.length() == 0)895upDir = targetDir.cross(Vec3<T> (0, 0, 1));896}897898//899// Compute the x-, y-, and z-axis vectors of the new coordinate system.900//901902Vec3<T> targetPerpDir = upDir.cross (targetDir);903Vec3<T> targetUpDir = targetDir.cross (targetPerpDir);904905//906// Rotate the x-axis into targetPerpDir (row 0),907// rotate the y-axis into targetUpDir (row 1),908// rotate the z-axis into targetDir (row 2).909//910911Vec3<T> row[3];912row[0] = targetPerpDir.normalized ();913row[1] = targetUpDir .normalized ();914row[2] = targetDir .normalized ();915916result.x[0][0] = row[0][0];917result.x[0][1] = row[0][1];918result.x[0][2] = row[0][2];919result.x[0][3] = (T)0;920921result.x[1][0] = row[1][0];922result.x[1][1] = row[1][1];923result.x[1][2] = row[1][2];924result.x[1][3] = (T)0;925926result.x[2][0] = row[2][0];927result.x[2][1] = row[2][1];928result.x[2][2] = row[2][2];929result.x[2][3] = (T)0;930931result.x[3][0] = (T)0;932result.x[3][1] = (T)0;933result.x[3][2] = (T)0;934result.x[3][3] = (T)1;935}936937938// Compute an orthonormal direct frame from : a position, an x axis direction and a normal to the y axis939// If the x axis and normal are perpendicular, then the normal will have the same direction as the z axis.940// Inputs are :941// -the position of the frame942// -the x axis direction of the frame943// -a normal to the y axis of the frame944// Return is the orthonormal frame945template <class T>946Matrix44<T>947computeLocalFrame( const Vec3<T>& p,948const Vec3<T>& xDir,949const Vec3<T>& normal)950{951Vec3<T> _xDir(xDir);952Vec3<T> x = _xDir.normalize();953Vec3<T> y = (normal % x).normalize();954Vec3<T> z = (x % y).normalize();955956Matrix44<T> L;957L[0][0] = x[0];958L[0][1] = x[1];959L[0][2] = x[2];960L[0][3] = 0.0;961962L[1][0] = y[0];963L[1][1] = y[1];964L[1][2] = y[2];965L[1][3] = 0.0;966967L[2][0] = z[0];968L[2][1] = z[1];969L[2][2] = z[2];970L[2][3] = 0.0;971972L[3][0] = p[0];973L[3][1] = p[1];974L[3][2] = p[2];975L[3][3] = 1.0;976977return L;978}979980// Add a translate/rotate/scale offset to an input frame981// and put it in another frame of reference982// Inputs are :983// - input frame984// - translate offset985// - rotate offset in degrees986// - scale offset987// - frame of reference988// Output is the offsetted frame989template <class T>990Matrix44<T>991addOffset( const Matrix44<T>& inMat,992const Vec3<T>& tOffset,993const Vec3<T>& rOffset,994const Vec3<T>& sOffset,995const Matrix44<T>& ref)996{997Matrix44<T> O;998999Vec3<T> _rOffset(rOffset);1000_rOffset *= M_PI / 180.0;1001O.rotate (_rOffset);10021003O[3][0] = tOffset[0];1004O[3][1] = tOffset[1];1005O[3][2] = tOffset[2];10061007Matrix44<T> S;1008S.scale (sOffset);10091010Matrix44<T> X = S * O * inMat * ref;10111012return X;1013}10141015// Compute Translate/Rotate/Scale matrix from matrix A with the Rotate/Scale of Matrix B1016// Inputs are :1017// -keepRotateA : if true keep rotate from matrix A, use B otherwise1018// -keepScaleA : if true keep scale from matrix A, use B otherwise1019// -Matrix A1020// -Matrix B1021// Return Matrix A with tweaked rotation/scale1022template <class T>1023Matrix44<T>1024computeRSMatrix( bool keepRotateA,1025bool keepScaleA,1026const Matrix44<T>& A,1027const Matrix44<T>& B)1028{1029Vec3<T> as, ah, ar, at;1030extractSHRT (A, as, ah, ar, at);10311032Vec3<T> bs, bh, br, bt;1033extractSHRT (B, bs, bh, br, bt);10341035if (!keepRotateA)1036ar = br;10371038if (!keepScaleA)1039as = bs;10401041Matrix44<T> mat;1042mat.makeIdentity();1043mat.translate (at);1044mat.rotate (ar);1045mat.scale (as);10461047return mat;1048}1049105010511052//-----------------------------------------------------------------------------1053// Implementation for 3x3 Matrix1054//------------------------------105510561057template <class T>1058bool1059extractScaling (const Matrix33<T> &mat, Vec2<T> &scl, bool exc)1060{1061T shr;1062Matrix33<T> M (mat);10631064if (! extractAndRemoveScalingAndShear (M, scl, shr, exc))1065return false;10661067return true;1068}106910701071template <class T>1072Matrix33<T>1073sansScaling (const Matrix33<T> &mat, bool exc)1074{1075Vec2<T> scl;1076T shr;1077T rot;1078Vec2<T> tran;10791080if (! extractSHRT (mat, scl, shr, rot, tran, exc))1081return mat;10821083Matrix33<T> M;10841085M.translate (tran);1086M.rotate (rot);1087M.shear (shr);10881089return M;1090}109110921093template <class T>1094bool1095removeScaling (Matrix33<T> &mat, bool exc)1096{1097Vec2<T> scl;1098T shr;1099T rot;1100Vec2<T> tran;11011102if (! extractSHRT (mat, scl, shr, rot, tran, exc))1103return false;11041105mat.makeIdentity ();1106mat.translate (tran);1107mat.rotate (rot);1108mat.shear (shr);11091110return true;1111}111211131114template <class T>1115bool1116extractScalingAndShear (const Matrix33<T> &mat, Vec2<T> &scl, T &shr, bool exc)1117{1118Matrix33<T> M (mat);11191120if (! extractAndRemoveScalingAndShear (M, scl, shr, exc))1121return false;11221123return true;1124}112511261127template <class T>1128Matrix33<T>1129sansScalingAndShear (const Matrix33<T> &mat, bool exc)1130{1131Vec2<T> scl;1132T shr;1133Matrix33<T> M (mat);11341135if (! extractAndRemoveScalingAndShear (M, scl, shr, exc))1136return mat;11371138return M;1139}114011411142template <class T>1143bool1144removeScalingAndShear (Matrix33<T> &mat, bool exc)1145{1146Vec2<T> scl;1147T shr;11481149if (! extractAndRemoveScalingAndShear (mat, scl, shr, exc))1150return false;11511152return true;1153}11541155template <class T>1156bool1157extractAndRemoveScalingAndShear (Matrix33<T> &mat,1158Vec2<T> &scl, T &shr, bool exc)1159{1160Vec2<T> row[2];11611162row[0] = Vec2<T> (mat[0][0], mat[0][1]);1163row[1] = Vec2<T> (mat[1][0], mat[1][1]);11641165T maxVal = 0;1166for (int i=0; i < 2; i++)1167for (int j=0; j < 2; j++)1168if (Imath::abs (row[i][j]) > maxVal)1169maxVal = Imath::abs (row[i][j]);11701171//1172// We normalize the 2x2 matrix here.1173// It was noticed that this can improve numerical stability significantly,1174// especially when many of the upper 2x2 matrix's coefficients are very1175// close to zero; we correct for this step at the end by multiplying the1176// scaling factors by maxVal at the end (shear and rotation are not1177// affected by the normalization).11781179if (maxVal != 0)1180{1181for (int i=0; i < 2; i++)1182if (! checkForZeroScaleInRow (maxVal, row[i], exc))1183return false;1184else1185row[i] /= maxVal;1186}11871188// Compute X scale factor.1189scl.x = row[0].length ();1190if (! checkForZeroScaleInRow (scl.x, row[0], exc))1191return false;11921193// Normalize first row.1194row[0] /= scl.x;11951196// An XY shear factor will shear the X coord. as the Y coord. changes.1197// There are 2 combinations (XY, YX), although we only extract the XY1198// shear factor because we can effect the an YX shear factor by1199// shearing in XY combined with rotations and scales.1200//1201// shear matrix < 1, YX, 0,1202// XY, 1, 0,1203// 0, 0, 1 >12041205// Compute XY shear factor and make 2nd row orthogonal to 1st.1206shr = row[0].dot (row[1]);1207row[1] -= shr * row[0];12081209// Now, compute Y scale.1210scl.y = row[1].length ();1211if (! checkForZeroScaleInRow (scl.y, row[1], exc))1212return false;12131214// Normalize 2nd row and correct the XY shear factor for Y scaling.1215row[1] /= scl.y;1216shr /= scl.y;12171218// At this point, the upper 2x2 matrix in mat is orthonormal.1219// Check for a coordinate system flip. If the determinant1220// is -1, then flip the rotation matrix and adjust the scale(Y)1221// and shear(XY) factors to compensate.1222if (row[0][0] * row[1][1] - row[0][1] * row[1][0] < 0)1223{1224row[1][0] *= -1;1225row[1][1] *= -1;1226scl[1] *= -1;1227shr *= -1;1228}12291230// Copy over the orthonormal rows into the returned matrix.1231// The upper 2x2 matrix in mat is now a rotation matrix.1232for (int i=0; i < 2; i++)1233{1234mat[i][0] = row[i][0];1235mat[i][1] = row[i][1];1236}12371238scl *= maxVal;12391240return true;1241}124212431244template <class T>1245void1246extractEuler (const Matrix33<T> &mat, T &rot)1247{1248//1249// Normalize the local x and y axes to remove scaling.1250//12511252Vec2<T> i (mat[0][0], mat[0][1]);1253Vec2<T> j (mat[1][0], mat[1][1]);12541255i.normalize();1256j.normalize();12571258//1259// Extract the angle, rot.1260//12611262rot = - Math<T>::atan2 (j[0], i[0]);1263}126412651266template <class T>1267bool1268extractSHRT (const Matrix33<T> &mat,1269Vec2<T> &s,1270T &h,1271T &r,1272Vec2<T> &t,1273bool exc)1274{1275Matrix33<T> rot;12761277rot = mat;1278if (! extractAndRemoveScalingAndShear (rot, s, h, exc))1279return false;12801281extractEuler (rot, r);12821283t.x = mat[2][0];1284t.y = mat[2][1];12851286return true;1287}128812891290template <class T>1291bool1292checkForZeroScaleInRow (const T& scl,1293const Vec2<T> &row,1294bool exc /* = true */ )1295{1296for (int i = 0; i < 2; i++)1297{1298if ((abs (scl) < 1 && abs (row[i]) >= limits<T>::max() * abs (scl)))1299{1300if (exc)1301throw Imath::ZeroScaleExc ("Cannot remove zero scaling "1302"from matrix.");1303else1304return false;1305}1306}13071308return true;1309}131013111312template <class T>1313Matrix33<T>1314outerProduct (const Vec3<T> &a, const Vec3<T> &b )1315{1316return Matrix33<T> (a.x*b.x, a.x*b.y, a.x*b.z,1317a.y*b.x, a.y*b.y, a.y*b.z,1318a.z*b.x, a.z*b.y, a.z*b.z );1319}132013211322// Computes the translation and rotation that brings the 'from' points1323// as close as possible to the 'to' points under the Frobenius norm.1324// To be more specific, let x be the matrix of 'from' points and y be1325// the matrix of 'to' points, we want to find the matrix A of the form1326// [ R t ]1327// [ 0 1 ]1328// that minimizes1329// || (A*x - y)^T * W * (A*x - y) ||_F1330// If doScaling is true, then a uniform scale is allowed also.1331template <typename T>1332Imath::M44d1333procrustesRotationAndTranslation (const Imath::Vec3<T>* A, // From these1334const Imath::Vec3<T>* B, // To these1335const T* weights,1336const size_t numPoints,1337const bool doScaling = false);13381339// Unweighted:1340template <typename T>1341Imath::M44d1342procrustesRotationAndTranslation (const Imath::Vec3<T>* A,1343const Imath::Vec3<T>* B,1344const size_t numPoints,1345const bool doScaling = false);13461347// Compute the SVD of a 3x3 matrix using Jacobi transformations. This method1348// should be quite accurate (competitive with LAPACK) even for poorly1349// conditioned matrices, and because it has been written specifically for the1350// 3x3/4x4 case it is much faster than calling out to LAPACK.1351//1352// The SVD of a 3x3/4x4 matrix A is defined as follows:1353// A = U * S * V^T1354// where S is the diagonal matrix of singular values and both U and V are1355// orthonormal. By convention, the entries S are all positive and sorted from1356// the largest to the smallest. However, some uses of this function may1357// require that the matrix U*V^T have positive determinant; in this case, we1358// may make the smallest singular value negative to ensure that this is1359// satisfied.1360//1361// Currently only available for single- and double-precision matrices.1362template <typename T>1363void1364jacobiSVD (const Imath::Matrix33<T>& A,1365Imath::Matrix33<T>& U,1366Imath::Vec3<T>& S,1367Imath::Matrix33<T>& V,1368const T tol = Imath::limits<T>::epsilon(),1369const bool forcePositiveDeterminant = false);13701371template <typename T>1372void1373jacobiSVD (const Imath::Matrix44<T>& A,1374Imath::Matrix44<T>& U,1375Imath::Vec4<T>& S,1376Imath::Matrix44<T>& V,1377const T tol = Imath::limits<T>::epsilon(),1378const bool forcePositiveDeterminant = false);13791380// Compute the eigenvalues (S) and the eigenvectors (V) of1381// a real symmetric matrix using Jacobi transformation.1382//1383// Jacobi transformation of a 3x3/4x4 matrix A outputs S and V:1384// A = V * S * V^T1385// where V is orthonormal and S is the diagonal matrix of eigenvalues.1386// Input matrix A must be symmetric. A is also modified during1387// the computation so that upper diagonal entries of A become zero.1388//1389template <typename T>1390void1391jacobiEigenSolver (Matrix33<T>& A,1392Vec3<T>& S,1393Matrix33<T>& V,1394const T tol);13951396template <typename T>1397inline1398void1399jacobiEigenSolver (Matrix33<T>& A,1400Vec3<T>& S,1401Matrix33<T>& V)1402{1403jacobiEigenSolver(A,S,V,limits<T>::epsilon());1404}14051406template <typename T>1407void1408jacobiEigenSolver (Matrix44<T>& A,1409Vec4<T>& S,1410Matrix44<T>& V,1411const T tol);14121413template <typename T>1414inline1415void1416jacobiEigenSolver (Matrix44<T>& A,1417Vec4<T>& S,1418Matrix44<T>& V)1419{1420jacobiEigenSolver(A,S,V,limits<T>::epsilon());1421}14221423// Compute a eigenvector corresponding to the abs max/min eigenvalue1424// of a real symmetric matrix using Jacobi transformation.1425template <typename TM, typename TV>1426void1427maxEigenVector (TM& A, TV& S);1428template <typename TM, typename TV>1429void1430minEigenVector (TM& A, TV& S);14311432} // namespace Imath14331434#endif143514361437