source: OGRE/trunk/ogrenew/OgreMain/src/OgreSimpleSpline.cpp @ 657

Revision 657, 7.5 KB checked in by mattausch, 19 years ago (diff)

added ogre dependencies and patched ogre sources

RevLine 
[657]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-2005 The OGRE Team
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-----------------------------------------------------------------------------
24*/
25#include "OgreStableHeaders.h"
26#include "OgreSimpleSpline.h"
27#include "OgreVector4.h"
28#include "OgreMatrix4.h"
29
30
31
32namespace Ogre {
33
34    //---------------------------------------------------------------------
35    SimpleSpline::SimpleSpline()
36    {
37        // Set up matrix
38        // Hermite polynomial
39        mCoeffs[0][0] = 2;
40        mCoeffs[0][1] = -2;
41        mCoeffs[0][2] = 1;
42        mCoeffs[0][3] = 1;
43        mCoeffs[1][0] = -3;
44        mCoeffs[1][1] = 3;
45        mCoeffs[1][2] = -2;
46        mCoeffs[1][3] = -1;
47        mCoeffs[2][0] = 0;
48        mCoeffs[2][1] = 0;
49        mCoeffs[2][2] = 1;
50        mCoeffs[2][3] = 0;
51        mCoeffs[3][0] = 1;
52        mCoeffs[3][1] = 0;
53        mCoeffs[3][2] = 0;
54        mCoeffs[3][3] = 0;
55
56        mAutoCalc = true;
57    }
58    //---------------------------------------------------------------------
59    SimpleSpline::~SimpleSpline()
60    {
61    }
62    //---------------------------------------------------------------------
63    void SimpleSpline::addPoint(const Vector3& p)
64    {
65        mPoints.push_back(p);
66        if (mAutoCalc)
67        {
68            recalcTangents();
69        }
70    }
71    //---------------------------------------------------------------------
72    Vector3 SimpleSpline::interpolate(Real t)
73    {
74        // Currently assumes points are evenly spaced, will cause velocity
75        // change where this is not the case
76        // TODO: base on arclength?
77
78       
79        // Work out which segment this is in
80        Real fSeg = t * (mPoints.size() - 1);
81        unsigned int segIdx = (unsigned int)fSeg;
82        // Apportion t
83        t = fSeg - segIdx;
84
85        return interpolate(segIdx, t);
86
87    }
88    //---------------------------------------------------------------------
89    Vector3 SimpleSpline::interpolate(unsigned int fromIndex, Real t)
90    {
91        // Bounds check
92        assert (fromIndex >= 0 && fromIndex < mPoints.size() &&
93            "fromIndex out of bounds");
94
95        if ((fromIndex + 1) == mPoints.size())
96        {
97            // Duff request, cannot blend to nothing
98            // Just return source
99            return mPoints[fromIndex];
100
101        }
102
103        // Fast special cases
104        if (t == 0.0f)
105        {
106            return mPoints[fromIndex];
107        }
108        else if(t == 1.0f)
109        {
110            return mPoints[fromIndex + 1];
111        }
112
113        // Real interpolation
114        // Form a vector of powers of t
115        Real t2, t3;
116        t2 = t * t;
117        t3 = t2 * t;
118        Vector4 powers(t3, t2, t, 1);
119
120
121        // Algorithm is ret = powers * mCoeffs * Matrix4(point1, point2, tangent1, tangent2)
122        Vector3& point1 = mPoints[fromIndex];
123        Vector3& point2 = mPoints[fromIndex+1];
124        Vector3& tan1 = mTangents[fromIndex];
125        Vector3& tan2 = mTangents[fromIndex+1];
126        Matrix4 pt;
127
128        pt[0][0] = point1.x;
129        pt[0][1] = point1.y;
130        pt[0][2] = point1.z;
131        pt[0][3] = 1.0f;
132        pt[1][0] = point2.x;
133        pt[1][1] = point2.y;
134        pt[1][2] = point2.z;
135        pt[1][3] = 1.0f;
136        pt[2][0] = tan1.x;
137        pt[2][1] = tan1.y;
138        pt[2][2] = tan1.z;
139        pt[2][3] = 1.0f;
140        pt[3][0] = tan2.x;
141        pt[3][1] = tan2.y;
142        pt[3][2] = tan2.z;
143        pt[3][3] = 1.0f;
144
145        Vector4 ret = powers * mCoeffs * pt;
146
147
148        return Vector3(ret.x, ret.y, ret.z);
149
150
151
152
153    }
154    //---------------------------------------------------------------------
155    void SimpleSpline::recalcTangents(void)
156    {
157        // Catmull-Rom approach
158        //
159        // tangent[i] = 0.5 * (point[i+1] - point[i-1])
160        //
161        // Assume endpoint tangents are parallel with line with neighbour
162
163        size_t i, numPoints;
164        bool isClosed;
165
166        numPoints = mPoints.size();
167        if (numPoints < 2)
168        {
169            // Can't do anything yet
170            return;
171        }
172
173        // Closed or open?
174        if (mPoints[0] == mPoints[numPoints-1])
175        {
176            isClosed = true;
177        }
178        else
179        {
180            isClosed = false;
181        }
182
183        mTangents.resize(numPoints);
184
185
186
187        for(i = 0; i < numPoints; ++i)
188        {
189            if (i ==0)
190            {
191                // Special case start
192                if (isClosed)
193                {
194                    // Use numPoints-2 since numPoints-1 is the last point and == [0]
195                    mTangents[i] = 0.5 * (mPoints[1] - mPoints[numPoints-2]);
196                }
197                else
198                {
199                    mTangents[i] = 0.5 * (mPoints[1] - mPoints[0]);
200                }
201            }
202            else if (i == numPoints-1)
203            {
204                // Special case end
205                if (isClosed)
206                {
207                    // Use same tangent as already calculated for [0]
208                    mTangents[i] = mTangents[0];
209                }
210                else
211                {
212                    mTangents[i] = 0.5 * (mPoints[i] - mPoints[i-1]);
213                }
214            }
215            else
216            {
217                mTangents[i] = 0.5 * (mPoints[i+1] - mPoints[i-1]);
218            }
219           
220        }
221
222
223
224    }
225    //---------------------------------------------------------------------
226    const Vector3& SimpleSpline::getPoint(unsigned short index) const
227    {
228        assert (index < mPoints.size() && "Point index is out of bounds!!");
229
230        return mPoints[index];
231    }
232    //---------------------------------------------------------------------
233    unsigned short SimpleSpline::getNumPoints(void) const
234    {
235        return (unsigned short)mPoints.size();
236    }
237    //---------------------------------------------------------------------
238    void SimpleSpline::clear(void)
239    {
240        mPoints.clear();
241        mTangents.clear();
242    }
243    //---------------------------------------------------------------------
244    void SimpleSpline::updatePoint(unsigned short index, const Vector3& value)
245    {
246        assert (index < mPoints.size() && "Point index is out of bounds!!");
247
248        mPoints[index] = value;
249        if (mAutoCalc)
250        {
251            recalcTangents();
252        }
253    }
254    //---------------------------------------------------------------------
255    void SimpleSpline::setAutoCalculate(bool autoCalc)
256    {
257        mAutoCalc = autoCalc;
258    }
259
260
261
262
263}
264
265
266
267
Note: See TracBrowser for help on using the repository browser.