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