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

OgreSimpleSpline.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 "OgreSimpleSpline.h"
00027 #include "OgreVector4.h"
00028 #include "OgreMatrix4.h"
00029 
00030 
00031 
00032 namespace Ogre {
00033 
00034     //---------------------------------------------------------------------
00035     SimpleSpline::SimpleSpline()
00036     {
00037         // Set up matrix
00038         // Hermite polynomial
00039         mCoeffs[0][0] = 2;
00040         mCoeffs[0][1] = -2;
00041         mCoeffs[0][2] = 1;
00042         mCoeffs[0][3] = 1;
00043         mCoeffs[1][0] = -3;
00044         mCoeffs[1][1] = 3;
00045         mCoeffs[1][2] = -2;
00046         mCoeffs[1][3] = -1;
00047         mCoeffs[2][0] = 0;
00048         mCoeffs[2][1] = 0;
00049         mCoeffs[2][2] = 1;
00050         mCoeffs[2][3] = 0;
00051         mCoeffs[3][0] = 1;
00052         mCoeffs[3][1] = 0;
00053         mCoeffs[3][2] = 0;
00054         mCoeffs[3][3] = 0;
00055 
00056         mAutoCalc = true;
00057     }
00058     //---------------------------------------------------------------------
00059     SimpleSpline::~SimpleSpline()
00060     {
00061     }
00062     //---------------------------------------------------------------------
00063     void SimpleSpline::addPoint(const Vector3& p)
00064     {
00065         mPoints.push_back(p);
00066         if (mAutoCalc)
00067         {
00068             recalcTangents();
00069         }
00070     }
00071     //---------------------------------------------------------------------
00072     Vector3 SimpleSpline::interpolate(Real t)
00073     {
00074         // Currently assumes points are evenly spaced, will cause velocity
00075         // change where this is not the case
00076         // TODO: base on arclength?
00077 
00078         
00079         // Work out which segment this is in
00080         Real fSeg = t * mPoints.size();
00081         unsigned int segIdx = (unsigned int)fSeg;
00082         // Apportion t 
00083         t = fSeg - segIdx;
00084 
00085         return interpolate(segIdx, t);
00086 
00087     }
00088     //---------------------------------------------------------------------
00089     Vector3 SimpleSpline::interpolate(unsigned int fromIndex, Real t)
00090     {
00091         // Bounds check
00092         assert (fromIndex >= 0 && fromIndex < mPoints.size() &&
00093             "fromIndex out of bounds");
00094 
00095         if ((fromIndex + 1) == mPoints.size())
00096         {
00097             // Duff request, cannot blend to nothing
00098             // Just return source
00099             return mPoints[fromIndex];
00100 
00101         }
00102 
00103         // Fast special cases
00104         if (t == 0.0f)
00105         {
00106             return mPoints[fromIndex];
00107         }
00108         else if(t == 1.0f)
00109         {
00110             return mPoints[fromIndex + 1];
00111         }
00112 
00113         // Real interpolation
00114         // Form a vector of powers of t
00115         Real t2, t3;
00116         t2 = t * t;
00117         t3 = t2 * t;
00118         Vector4 powers(t3, t2, t, 1);
00119 
00120 
00121         // Algorithm is ret = powers * mCoeffs * Matrix4(point1, point2, tangent1, tangent2)
00122         Vector3& point1 = mPoints[fromIndex];
00123         Vector3& point2 = mPoints[fromIndex+1];
00124         Vector3& tan1 = mTangents[fromIndex];
00125         Vector3& tan2 = mTangents[fromIndex+1];
00126         Matrix4 pt;
00127 
00128         pt[0][0] = point1.x;
00129         pt[0][1] = point1.y;
00130         pt[0][2] = point1.z;
00131         pt[0][3] = 1.0f;
00132         pt[1][0] = point2.x;
00133         pt[1][1] = point2.y;
00134         pt[1][2] = point2.z;
00135         pt[1][3] = 1.0f;
00136         pt[2][0] = tan1.x;
00137         pt[2][1] = tan1.y;
00138         pt[2][2] = tan1.z;
00139         pt[2][3] = 1.0f;
00140         pt[3][0] = tan2.x;
00141         pt[3][1] = tan2.y;
00142         pt[3][2] = tan2.z;
00143         pt[3][3] = 1.0f;
00144 
00145         Vector4 ret = powers * mCoeffs * pt;
00146 
00147 
00148         return Vector3(ret.x, ret.y, ret.z);
00149 
00150 
00151 
00152 
00153     }
00154     //---------------------------------------------------------------------
00155     void SimpleSpline::recalcTangents(void)
00156     {
00157         // Catmull-Rom approach
00158         // 
00159         // tangent[i] = 0.5 * (point[i+1] - point[i-1])
00160         //
00161         // Assume endpoint tangents are parallel with line with neighbour
00162 
00163         size_t i, numPoints;
00164         bool isClosed;
00165 
00166         numPoints = mPoints.size();
00167         if (numPoints < 2)
00168         {
00169             // Can't do anything yet
00170             return;
00171         }
00172 
00173         // Closed or open?
00174         if (mPoints[0] == mPoints[numPoints-1])
00175         {
00176             isClosed = true;
00177         }
00178         else
00179         {
00180             isClosed = false;
00181         }
00182 
00183         mTangents.resize(numPoints);
00184 
00185 
00186 
00187         for(i = 0; i < numPoints; ++i)
00188         {
00189             if (i ==0)
00190             {
00191                 // Special case start
00192                 if (isClosed)
00193                 {
00194                     // Use numPoints-2 since numPoints-1 is the last point and == [0]
00195                     mTangents[i] = 0.5 * (mPoints[1] - mPoints[numPoints-2]);
00196                 }
00197                 else
00198                 {
00199                     mTangents[i] = 0.5 * (mPoints[1] - mPoints[0]);
00200                 }
00201             }
00202             else if (i == numPoints-1)
00203             {
00204                 // Special case end
00205                 if (isClosed)
00206                 {
00207                     // Use same tangent as already calculated for [0]
00208                     mTangents[i] = mTangents[0];
00209                 }
00210                 else
00211                 {
00212                     mTangents[i] = 0.5 * (mPoints[i] - mPoints[i-1]);
00213                 }
00214             }
00215             else
00216             {
00217                 mTangents[i] = 0.5 * (mPoints[i+1] - mPoints[i-1]);
00218             }
00219             
00220         }
00221 
00222 
00223 
00224     }
00225     //---------------------------------------------------------------------
00226     const Vector3& SimpleSpline::getPoint(unsigned short index) const
00227     {
00228         assert (index < mPoints.size() && "Point index is out of bounds!!");
00229 
00230         return mPoints[index];
00231     }
00232     //---------------------------------------------------------------------
00233     unsigned short SimpleSpline::getNumPoints(void) const
00234     {
00235         return (unsigned short)mPoints.size();
00236     }
00237     //---------------------------------------------------------------------
00238     void SimpleSpline::clear(void)
00239     {
00240         mPoints.clear();
00241         mTangents.clear();
00242     }
00243     //---------------------------------------------------------------------
00244     void SimpleSpline::updatePoint(unsigned short index, const Vector3& value)
00245     {
00246         assert (index < mPoints.size() && "Point index is out of bounds!!");
00247 
00248         mPoints[index] = value;
00249         if (mAutoCalc)
00250         {
00251             recalcTangents();
00252         }
00253     }
00254     //---------------------------------------------------------------------
00255     void SimpleSpline::setAutoCalculate(bool autoCalc)
00256     {
00257         mAutoCalc = autoCalc;
00258     }
00259 
00260 
00261 
00262 
00263 }
00264 
00265 
00266 
00267 

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