Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/OgreMain/src/OgreRotationSpline.cpp @ 1

Last change on this file since 1 was 1, checked in by landauf, 17 years ago
File size: 7.1 KB
RevLine 
[1]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 "OgreRotationalSpline.h"
31
32
33
34namespace Ogre {
35
36    //---------------------------------------------------------------------
37    RotationalSpline::RotationalSpline()
38        : mAutoCalc(true)
39    {
40    }
41    //---------------------------------------------------------------------
42    RotationalSpline::~RotationalSpline()
43    {
44    }
45    //---------------------------------------------------------------------
46    void RotationalSpline::addPoint(const Quaternion& p)
47    {
48        mPoints.push_back(p);
49        if (mAutoCalc)
50        {
51            recalcTangents();
52        }
53    }
54    //---------------------------------------------------------------------
55    Quaternion RotationalSpline::interpolate(Real t, bool useShortestPath)
56    {
57        // Work out which segment this is in
58        Real fSeg = t * (mPoints.size() - 1);
59        unsigned int segIdx = (unsigned int)fSeg;
60        // Apportion t
61        t = fSeg - segIdx;
62
63        return interpolate(segIdx, t, useShortestPath);
64
65    }
66    //---------------------------------------------------------------------
67    Quaternion RotationalSpline::interpolate(unsigned int fromIndex, Real t,
68                bool useShortestPath)
69    {
70        // Bounds check
71        assert (fromIndex >= 0 && fromIndex < mPoints.size() &&
72            "fromIndex out of bounds");
73
74        if ((fromIndex + 1) == mPoints.size())
75        {
76            // Duff request, cannot blend to nothing
77            // Just return source
78            return mPoints[fromIndex];
79
80        }
81        // Fast special cases
82        if (t == 0.0f)
83        {
84            return mPoints[fromIndex];
85        }
86        else if(t == 1.0f)
87        {
88            return mPoints[fromIndex + 1];
89        }
90
91        // Real interpolation
92        // Use squad using tangents we've already set up
93        Quaternion &p = mPoints[fromIndex];
94        Quaternion &q = mPoints[fromIndex+1];
95        Quaternion &a = mTangents[fromIndex];
96        Quaternion &b = mTangents[fromIndex+1];
97
98        // NB interpolate to nearest rotation
99        return Quaternion::Squad(t, p, a, b, q, useShortestPath);
100
101    }
102    //---------------------------------------------------------------------
103    void RotationalSpline::recalcTangents(void)
104    {
105        // ShoeMake (1987) approach
106        // Just like Catmull-Rom really, just more gnarly
107        // And no, I don't understand how to derive this!
108        //
109        // let p = point[i], pInv = p.Inverse
110        // tangent[i] = p * exp( -0.25 * ( log(pInv * point[i+1]) + log(pInv * point[i-1]) ) )
111        //
112        // Assume endpoint tangents are parallel with line with neighbour
113
114        unsigned int i, numPoints;
115        bool isClosed;
116
117        numPoints = (unsigned int)mPoints.size();
118
119        if (numPoints < 2)
120        {
121            // Can't do anything yet
122            return;
123        }
124
125        mTangents.resize(numPoints);
126
127        if (mPoints[0] == mPoints[numPoints-1])
128        {
129            isClosed = true;
130        }
131        else
132        {
133            isClosed = false;
134        }
135
136        Quaternion invp, part1, part2, preExp;
137        for(i = 0; i < numPoints; ++i)
138        {
139            Quaternion &p = mPoints[i];
140            invp = p.Inverse();
141
142            if (i ==0)
143            {
144                // special case start
145                part1 = (invp * mPoints[i+1]).Log();
146                if (isClosed)
147                {
148                    // Use numPoints-2 since numPoints-1 == end == start == this one
149                    part2 = (invp * mPoints[numPoints-2]).Log();
150                }
151                else
152                {
153                    part2 = (invp * p).Log();
154                }
155            }
156            else if (i == numPoints-1)
157            {
158                // special case end
159                if (isClosed)
160                {
161                    // Wrap to [1] (not [0], this is the same as end == this one)
162                    part1 = (invp * mPoints[1]).Log();
163                }
164                else
165                {
166                    part1 = (invp * p).Log();
167                }
168                part2 = (invp * mPoints[i-1]).Log();
169            }
170            else
171            {
172                part1 = (invp * mPoints[i+1]).Log();
173                part2 = (invp * mPoints[i-1]).Log();
174            }
175
176            preExp = -0.25 * (part1 + part2);
177            mTangents[i] = p * preExp.Exp();
178           
179        }
180
181
182
183    }
184    //---------------------------------------------------------------------
185    const Quaternion& RotationalSpline::getPoint(unsigned short index) const
186    {
187        assert (index < mPoints.size() && "Point index is out of bounds!!");
188
189        return mPoints[index];
190    }
191    //---------------------------------------------------------------------
192    unsigned short RotationalSpline::getNumPoints(void) const
193    {
194        return (unsigned short)mPoints.size();
195    }
196    //---------------------------------------------------------------------
197    void RotationalSpline::clear(void)
198    {
199        mPoints.clear();
200        mTangents.clear();
201    }
202    //---------------------------------------------------------------------
203    void RotationalSpline::updatePoint(unsigned short index, const Quaternion& value)
204    {
205        assert (index < mPoints.size() && "Point index is out of bounds!!");
206
207        mPoints[index] = value;
208        if (mAutoCalc)
209        {
210            recalcTangents();
211        }
212    }
213    //---------------------------------------------------------------------
214    void RotationalSpline::setAutoCalculate(bool autoCalc)
215    {
216        mAutoCalc = autoCalc;
217    }
218    //---------------------------------------------------------------------
219
220
221
222}
223
224
225
226
Note: See TracBrowser for help on using the repository browser.