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 Fri May 14 23:22:41 2004