1 /* 2 ----------------------------------------------------------------------------- 3 This source file is part of OGRE 4 (Object-oriented Graphics Rendering Engine) 5 For the latest info, see http://www.ogre3d.org/ 6 7 Copyright (c) 2000-2014 Torus Knot Software Ltd 8 9 Permission is hereby granted, free of charge, to any person obtaining a copy 10 of this software and associated documentation files (the "Software"), to deal 11 in the Software without restriction, including without limitation the rights 12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 copies of the Software, and to permit persons to whom the Software is 14 furnished to do so, subject to the following conditions: 15 16 The above copyright notice and this permission notice shall be included in 17 all copies or substantial portions of the Software. 18 19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 THE SOFTWARE. 26 ----------------------------------------------------------------------------- 27 */ 28 #include "OgreStableHeaders.h" 29 30 namespace Ogre { 31 32 //--------------------------------------------------------------------- SimpleSpline()33 SimpleSpline::SimpleSpline() 34 { 35 // Set up matrix 36 // Hermite polynomial 37 mCoeffs[0][0] = 2; 38 mCoeffs[0][1] = -2; 39 mCoeffs[0][2] = 1; 40 mCoeffs[0][3] = 1; 41 mCoeffs[1][0] = -3; 42 mCoeffs[1][1] = 3; 43 mCoeffs[1][2] = -2; 44 mCoeffs[1][3] = -1; 45 mCoeffs[2][0] = 0; 46 mCoeffs[2][1] = 0; 47 mCoeffs[2][2] = 1; 48 mCoeffs[2][3] = 0; 49 mCoeffs[3][0] = 1; 50 mCoeffs[3][1] = 0; 51 mCoeffs[3][2] = 0; 52 mCoeffs[3][3] = 0; 53 54 mAutoCalc = true; 55 } 56 //--------------------------------------------------------------------- ~SimpleSpline()57 SimpleSpline::~SimpleSpline() 58 { 59 } 60 //--------------------------------------------------------------------- addPoint(const Vector3 & p)61 void SimpleSpline::addPoint(const Vector3& p) 62 { 63 mPoints.push_back(p); 64 if (mAutoCalc) 65 { 66 recalcTangents(); 67 } 68 } 69 //--------------------------------------------------------------------- interpolate(Real t) const70 Vector3 SimpleSpline::interpolate(Real t) const 71 { 72 // Currently assumes points are evenly spaced, will cause velocity 73 // change where this is not the case 74 // TODO: base on arclength? 75 76 77 // Work out which segment this is in 78 Real fSeg = t * (mPoints.size() - 1); 79 unsigned int segIdx = (unsigned int)fSeg; 80 // Apportion t 81 t = fSeg - segIdx; 82 83 return interpolate(segIdx, t); 84 85 } 86 //--------------------------------------------------------------------- interpolate(unsigned int fromIndex,Real t) const87 Vector3 SimpleSpline::interpolate(unsigned int fromIndex, Real t) const 88 { 89 // Bounds check 90 assert (fromIndex < mPoints.size() && 91 "fromIndex out of bounds"); 92 93 if ((fromIndex + 1) == mPoints.size()) 94 { 95 // Duff request, cannot blend to nothing 96 // Just return source 97 return mPoints[fromIndex]; 98 99 } 100 101 // Fast special cases 102 if (t == 0.0f) 103 { 104 return mPoints[fromIndex]; 105 } 106 else if(t == 1.0f) 107 { 108 return mPoints[fromIndex + 1]; 109 } 110 111 // Real interpolation 112 // Form a vector of powers of t 113 Real t2, t3; 114 t2 = t * t; 115 t3 = t2 * t; 116 Vector4 powers(t3, t2, t, 1); 117 118 119 // Algorithm is ret = powers * mCoeffs * Matrix4(point1, point2, tangent1, tangent2) 120 const Vector3& point1 = mPoints[fromIndex]; 121 const Vector3& point2 = mPoints[fromIndex+1]; 122 const Vector3& tan1 = mTangents[fromIndex]; 123 const Vector3& tan2 = mTangents[fromIndex+1]; 124 Matrix4 pt; 125 126 pt[0][0] = point1.x; 127 pt[0][1] = point1.y; 128 pt[0][2] = point1.z; 129 pt[0][3] = 1.0f; 130 pt[1][0] = point2.x; 131 pt[1][1] = point2.y; 132 pt[1][2] = point2.z; 133 pt[1][3] = 1.0f; 134 pt[2][0] = tan1.x; 135 pt[2][1] = tan1.y; 136 pt[2][2] = tan1.z; 137 pt[2][3] = 1.0f; 138 pt[3][0] = tan2.x; 139 pt[3][1] = tan2.y; 140 pt[3][2] = tan2.z; 141 pt[3][3] = 1.0f; 142 143 Vector4 ret = powers * mCoeffs * pt; 144 145 146 return Vector3(ret.x, ret.y, ret.z); 147 148 149 150 151 } 152 //--------------------------------------------------------------------- recalcTangents(void)153 void SimpleSpline::recalcTangents(void) 154 { 155 // Catmull-Rom approach 156 // 157 // tangent[i] = 0.5 * (point[i+1] - point[i-1]) 158 // 159 // Assume endpoint tangents are parallel with line with neighbour 160 161 size_t i, numPoints; 162 bool isClosed; 163 164 numPoints = mPoints.size(); 165 if (numPoints < 2) 166 { 167 // Can't do anything yet 168 return; 169 } 170 171 // Closed or open? 172 if (mPoints[0] == mPoints[numPoints-1]) 173 { 174 isClosed = true; 175 } 176 else 177 { 178 isClosed = false; 179 } 180 181 mTangents.resize(numPoints); 182 183 184 185 for(i = 0; i < numPoints; ++i) 186 { 187 if (i ==0) 188 { 189 // Special case start 190 if (isClosed) 191 { 192 // Use numPoints-2 since numPoints-1 is the last point and == [0] 193 mTangents[i] = 0.5 * (mPoints[1] - mPoints[numPoints-2]); 194 } 195 else 196 { 197 mTangents[i] = 0.5 * (mPoints[1] - mPoints[0]); 198 } 199 } 200 else if (i == numPoints-1) 201 { 202 // Special case end 203 if (isClosed) 204 { 205 // Use same tangent as already calculated for [0] 206 mTangents[i] = mTangents[0]; 207 } 208 else 209 { 210 mTangents[i] = 0.5 * (mPoints[i] - mPoints[i-1]); 211 } 212 } 213 else 214 { 215 mTangents[i] = 0.5 * (mPoints[i+1] - mPoints[i-1]); 216 } 217 218 } 219 220 221 222 } 223 //--------------------------------------------------------------------- getPoint(unsigned short index) const224 const Vector3& SimpleSpline::getPoint(unsigned short index) const 225 { 226 assert (index < mPoints.size() && "Point index is out of bounds!!"); 227 228 return mPoints[index]; 229 } 230 //--------------------------------------------------------------------- getNumPoints(void) const231 unsigned short SimpleSpline::getNumPoints(void) const 232 { 233 return (unsigned short)mPoints.size(); 234 } 235 //--------------------------------------------------------------------- clear(void)236 void SimpleSpline::clear(void) 237 { 238 mPoints.clear(); 239 mTangents.clear(); 240 } 241 //--------------------------------------------------------------------- updatePoint(unsigned short index,const Vector3 & value)242 void SimpleSpline::updatePoint(unsigned short index, const Vector3& value) 243 { 244 assert (index < mPoints.size() && "Point index is out of bounds!!"); 245 246 mPoints[index] = value; 247 if (mAutoCalc) 248 { 249 recalcTangents(); 250 } 251 } 252 //--------------------------------------------------------------------- setAutoCalculate(bool autoCalc)253 void SimpleSpline::setAutoCalculate(bool autoCalc) 254 { 255 mAutoCalc = autoCalc; 256 } 257 258 259 260 261 } 262 263 264 265 266