Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/OgreMain/src/OgreSimpleSpline.cpp @ 3

Last change on this file since 3 was 3, checked in by anonymous, 17 years ago

=update

File size: 7.4 KB
Line 
1/*
2-----------------------------------------------------------------------------
3This source file is part of OGRE
4    (Object-oriented Graphics Rendering Engine)
5For the latest info, see http://www.ogre3d.org/
6
7Copyright (c) 2000-2006 Torus Knot Software Ltd
8Also see acknowledgements in Readme.html
9
10This program is free software; you can redistribute it and/or modify it under
11the terms of the GNU Lesser General Public License as published by the Free Software
12Foundation; either version 2 of the License, or (at your option) any later
13version.
14
15This program is distributed in the hope that it will be useful, but WITHOUT
16ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
18
19You should have received a copy of the GNU Lesser General Public License along with
20this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22http://www.gnu.org/copyleft/lesser.txt.
23
24You may alternatively use this source under the terms of a specific version of
25the OGRE Unrestricted License provided you have obtained such a license from
26Torus Knot Software Ltd.
27-----------------------------------------------------------------------------
28*/
29#include "OgreStableHeaders.h"
30#include "OgreSimpleSpline.h"
31#include "OgreVector4.h"
32#include "OgreMatrix4.h"
33
34
35
36namespace Ogre {
37
38    //---------------------------------------------------------------------
39    SimpleSpline::SimpleSpline()
40    {
41        // Set up matrix
42        // Hermite polynomial
43        mCoeffs[0][0] = 2;
44        mCoeffs[0][1] = -2;
45        mCoeffs[0][2] = 1;
46        mCoeffs[0][3] = 1;
47        mCoeffs[1][0] = -3;
48        mCoeffs[1][1] = 3;
49        mCoeffs[1][2] = -2;
50        mCoeffs[1][3] = -1;
51        mCoeffs[2][0] = 0;
52        mCoeffs[2][1] = 0;
53        mCoeffs[2][2] = 1;
54        mCoeffs[2][3] = 0;
55        mCoeffs[3][0] = 1;
56        mCoeffs[3][1] = 0;
57        mCoeffs[3][2] = 0;
58        mCoeffs[3][3] = 0;
59
60        mAutoCalc = true;
61    }
62    //---------------------------------------------------------------------
63    SimpleSpline::~SimpleSpline()
64    {
65    }
66    //---------------------------------------------------------------------
67    void SimpleSpline::addPoint(const Vector3& p)
68    {
69        mPoints.push_back(p);
70        if (mAutoCalc)
71        {
72            recalcTangents();
73        }
74    }
75    //---------------------------------------------------------------------
76    Vector3 SimpleSpline::interpolate(Real t)
77    {
78        // Currently assumes points are evenly spaced, will cause velocity
79        // change where this is not the case
80        // TODO: base on arclength?
81
82       
83        // Work out which segment this is in
84        Real fSeg = t * (mPoints.size() - 1);
85        unsigned int segIdx = (unsigned int)fSeg;
86        // Apportion t
87        t = fSeg - segIdx;
88
89        return interpolate(segIdx, t);
90
91    }
92    //---------------------------------------------------------------------
93    Vector3 SimpleSpline::interpolate(unsigned int fromIndex, Real t)
94    {
95        // Bounds check
96        assert (fromIndex < mPoints.size() &&
97            "fromIndex out of bounds");
98
99        if ((fromIndex + 1) == mPoints.size())
100        {
101            // Duff request, cannot blend to nothing
102            // Just return source
103            return mPoints[fromIndex];
104
105        }
106
107        // Fast special cases
108        if (t == 0.0f)
109        {
110            return mPoints[fromIndex];
111        }
112        else if(t == 1.0f)
113        {
114            return mPoints[fromIndex + 1];
115        }
116
117        // Real interpolation
118        // Form a vector of powers of t
119        Real t2, t3;
120        t2 = t * t;
121        t3 = t2 * t;
122        Vector4 powers(t3, t2, t, 1);
123
124
125        // Algorithm is ret = powers * mCoeffs * Matrix4(point1, point2, tangent1, tangent2)
126        Vector3& point1 = mPoints[fromIndex];
127        Vector3& point2 = mPoints[fromIndex+1];
128        Vector3& tan1 = mTangents[fromIndex];
129        Vector3& tan2 = mTangents[fromIndex+1];
130        Matrix4 pt;
131
132        pt[0][0] = point1.x;
133        pt[0][1] = point1.y;
134        pt[0][2] = point1.z;
135        pt[0][3] = 1.0f;
136        pt[1][0] = point2.x;
137        pt[1][1] = point2.y;
138        pt[1][2] = point2.z;
139        pt[1][3] = 1.0f;
140        pt[2][0] = tan1.x;
141        pt[2][1] = tan1.y;
142        pt[2][2] = tan1.z;
143        pt[2][3] = 1.0f;
144        pt[3][0] = tan2.x;
145        pt[3][1] = tan2.y;
146        pt[3][2] = tan2.z;
147        pt[3][3] = 1.0f;
148
149        Vector4 ret = powers * mCoeffs * pt;
150
151
152        return Vector3(ret.x, ret.y, ret.z);
153
154
155
156
157    }
158    //---------------------------------------------------------------------
159    void SimpleSpline::recalcTangents(void)
160    {
161        // Catmull-Rom approach
162        //
163        // tangent[i] = 0.5 * (point[i+1] - point[i-1])
164        //
165        // Assume endpoint tangents are parallel with line with neighbour
166
167        size_t i, numPoints;
168        bool isClosed;
169
170        numPoints = mPoints.size();
171        if (numPoints < 2)
172        {
173            // Can't do anything yet
174            return;
175        }
176
177        // Closed or open?
178        if (mPoints[0] == mPoints[numPoints-1])
179        {
180            isClosed = true;
181        }
182        else
183        {
184            isClosed = false;
185        }
186
187        mTangents.resize(numPoints);
188
189
190
191        for(i = 0; i < numPoints; ++i)
192        {
193            if (i ==0)
194            {
195                // Special case start
196                if (isClosed)
197                {
198                    // Use numPoints-2 since numPoints-1 is the last point and == [0]
199                    mTangents[i] = 0.5 * (mPoints[1] - mPoints[numPoints-2]);
200                }
201                else
202                {
203                    mTangents[i] = 0.5 * (mPoints[1] - mPoints[0]);
204                }
205            }
206            else if (i == numPoints-1)
207            {
208                // Special case end
209                if (isClosed)
210                {
211                    // Use same tangent as already calculated for [0]
212                    mTangents[i] = mTangents[0];
213                }
214                else
215                {
216                    mTangents[i] = 0.5 * (mPoints[i] - mPoints[i-1]);
217                }
218            }
219            else
220            {
221                mTangents[i] = 0.5 * (mPoints[i+1] - mPoints[i-1]);
222            }
223           
224        }
225
226
227
228    }
229    //---------------------------------------------------------------------
230    const Vector3& SimpleSpline::getPoint(unsigned short index) const
231    {
232        assert (index < mPoints.size() && "Point index is out of bounds!!");
233
234        return mPoints[index];
235    }
236    //---------------------------------------------------------------------
237    unsigned short SimpleSpline::getNumPoints(void) const
238    {
239        return (unsigned short)mPoints.size();
240    }
241    //---------------------------------------------------------------------
242    void SimpleSpline::clear(void)
243    {
244        mPoints.clear();
245        mTangents.clear();
246    }
247    //---------------------------------------------------------------------
248    void SimpleSpline::updatePoint(unsigned short index, const Vector3& value)
249    {
250        assert (index < mPoints.size() && "Point index is out of bounds!!");
251
252        mPoints[index] = value;
253        if (mAutoCalc)
254        {
255            recalcTangents();
256        }
257    }
258    //---------------------------------------------------------------------
259    void SimpleSpline::setAutoCalculate(bool autoCalc)
260    {
261        mAutoCalc = autoCalc;
262    }
263
264
265
266
267}
268
269
270
271
Note: See TracBrowser for help on using the repository browser.