Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

OgreRotationSpline.cpp

Go to the documentation of this file.
00001 /*
00002 -----------------------------------------------------------------------------
00003 This source file is part of OGRE
00004     (Object-oriented Graphics Rendering Engine)
00005 For the latest info, see http://www.ogre3d.org/
00006 
00007 Copyright © 2000-2002 The OGRE Team
00008 Also see acknowledgements in Readme.html
00009 
00010 This program is free software; you can redistribute it and/or modify it under
00011 the terms of the GNU Lesser General Public License as published by the Free Software
00012 Foundation; either version 2 of the License, or (at your option) any later
00013 version.
00014 
00015 This program is distributed in the hope that it will be useful, but WITHOUT
00016 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00017 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
00018 
00019 You should have received a copy of the GNU Lesser General Public License along with
00020 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
00021 Place - Suite 330, Boston, MA 02111-1307, USA, or go to
00022 http://www.gnu.org/copyleft/lesser.txt.
00023 -----------------------------------------------------------------------------
00024 */
00025 #include "OgreStableHeaders.h"
00026 #include "OgreRotationalSpline.h"
00027 
00028 
00029 
00030 namespace Ogre {
00031 
00032     //---------------------------------------------------------------------
00033     RotationalSpline::RotationalSpline()
00034     {
00035     }
00036     //---------------------------------------------------------------------
00037     RotationalSpline::~RotationalSpline()
00038     {
00039     }
00040     //---------------------------------------------------------------------
00041     void RotationalSpline::addPoint(const Quaternion& p)
00042     {
00043         mPoints.push_back(p);
00044         if (mAutoCalc)
00045         {
00046             recalcTangents();
00047         }
00048     }
00049     //---------------------------------------------------------------------
00050     Quaternion RotationalSpline::interpolate(Real t, bool useShortestPath)
00051     {
00052         // Work out which segment this is in
00053         Real fSeg = t * mPoints.size();
00054         unsigned int segIdx = (unsigned int)fSeg;
00055         // Apportion t 
00056         t = fSeg - segIdx;
00057 
00058         return interpolate(segIdx, t, useShortestPath);
00059 
00060     }
00061     //---------------------------------------------------------------------
00062     Quaternion RotationalSpline::interpolate(unsigned int fromIndex, Real t,
00063         bool useShortestPath)
00064     {
00065         // Bounds check
00066         assert (fromIndex >= 0 && fromIndex < mPoints.size() &&
00067             "fromIndex out of bounds");
00068 
00069         if ((fromIndex + 1) == mPoints.size())
00070         {
00071             // Duff request, cannot blend to nothing
00072             // Just return source
00073             return mPoints[fromIndex];
00074 
00075         }
00076         // Fast special cases
00077         if (t == 0.0f)
00078         {
00079             return mPoints[fromIndex];
00080         }
00081         else if(t == 1.0f)
00082         {
00083             return mPoints[fromIndex + 1];
00084         }
00085 
00086         // Real interpolation
00087         // Use squad using tangents we've already set up
00088         Quaternion &p = mPoints[fromIndex];
00089         Quaternion &q = mPoints[fromIndex+1];
00090         Quaternion &a = mTangents[fromIndex];
00091         Quaternion &b = mTangents[fromIndex+1];
00092 
00093         // NB interpolate to nearest rotation
00094         return Quaternion::Squad(t, p, a, b, q, useShortestPath);
00095 
00096     }
00097     //---------------------------------------------------------------------
00098     void RotationalSpline::recalcTangents(void)
00099     {
00100         // ShoeMake (1987) approach
00101         // Just like Catmull-Rom really, just more gnarly
00102         // And no, I don't understand how to derive this!
00103         //
00104         // let p = point[i], pInv = p.Inverse
00105         // tangent[i] = p * exp( -0.25 * ( log(pInv * point[i+1]) + log(pInv * point[i-1]) ) )
00106         //
00107         // Assume endpoint tangents are parallel with line with neighbour
00108 
00109         unsigned int i, numPoints;
00110         bool isClosed;
00111 
00112         numPoints = (unsigned int)mPoints.size();
00113 
00114         if (numPoints < 2)
00115         {
00116             // Can't do anything yet
00117             return;
00118         }
00119 
00120         mTangents.resize(numPoints);
00121 
00122         if (mPoints[0] == mPoints[numPoints-1])
00123         {
00124             isClosed = true;
00125         }
00126         else
00127         {
00128             isClosed = false;
00129         }
00130 
00131         Quaternion invp, part1, part2, preExp;
00132         for(i = 0; i < numPoints; ++i)
00133         {
00134             Quaternion &p = mPoints[i];
00135             invp = p.Inverse();
00136 
00137             if (i ==0)
00138             {
00139                 // special case start
00140                 part1 = (invp * mPoints[i+1]).Log();
00141                 if (isClosed)
00142                 {
00143                     // Use numPoints-2 since numPoints-1 == end == start == this one
00144                     part2 = (invp * mPoints[numPoints-2]).Log();
00145                 }
00146                 else
00147                 {
00148                     part2 = (invp * p).Log();
00149                 }
00150             }
00151             else if (i == numPoints-1)
00152             {
00153                 // special case end
00154                 if (isClosed)
00155                 {
00156                     // Wrap to [1] (not [0], this is the same as end == this one)
00157                     part1 = (invp * mPoints[1]).Log();
00158                 }
00159                 else
00160                 {
00161                     part1 = (invp * p).Log();
00162                 }
00163                 part2 = (invp * mPoints[i-1]).Log();
00164             }
00165             else
00166             {
00167                 part1 = (invp * mPoints[i+1]).Log();
00168                 part2 = (invp * mPoints[i-1]).Log();
00169             }
00170 
00171             preExp = -0.25 * (part1 + part2);
00172             mTangents[i] = p * preExp.Exp();
00173             
00174         }
00175 
00176 
00177 
00178     }
00179     //---------------------------------------------------------------------
00180     const Quaternion& RotationalSpline::getPoint(unsigned short index) const
00181     {
00182         assert (index < mPoints.size() && "Point index is out of bounds!!");
00183 
00184         return mPoints[index];
00185     }
00186     //---------------------------------------------------------------------
00187     unsigned short RotationalSpline::getNumPoints(void) const
00188     {
00189         return (unsigned short)mPoints.size();
00190     }
00191     //---------------------------------------------------------------------
00192     void RotationalSpline::clear(void)
00193     {
00194         mPoints.clear();
00195         mTangents.clear();
00196     }
00197     //---------------------------------------------------------------------
00198     void RotationalSpline::updatePoint(unsigned short index, const Quaternion& value)
00199     {
00200         assert (index < mPoints.size() && "Point index is out of bounds!!");
00201 
00202         mPoints[index] = value;
00203         if (mAutoCalc)
00204         {
00205             recalcTangents();
00206         }
00207     }
00208     //---------------------------------------------------------------------
00209     void RotationalSpline::setAutoCalculate(bool autoCalc)
00210     {
00211         mAutoCalc = autoCalc;
00212     }
00213     //---------------------------------------------------------------------
00214 
00215 
00216 
00217 }
00218 
00219 
00220 
00221 

Copyright © 2002-2003 by The OGRE Team
Last modified Sun Nov 28 19:48:43 2004