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