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