source: OGRE/trunk/ogrenew/OgreMain/src/OgreRotationSpline.cpp @ 692

Revision 692, 6.9 KB checked in by mattausch, 18 years ago (diff)

adding ogre 1.2 and dependencies

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