root/OpenSceneGraph/trunk/src/osg/AnimationPath.cpp @ 3046

Revision 3046, 6.3 kB (checked in by robert, 10 years ago)

Improved the precision of animation paths.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2003 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under 
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version.  The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * OpenSceneGraph Public License for more details.
12*/
13#include <osg/AnimationPath>
14#include <osg/MatrixTransform>
15#include <osg/PositionAttitudeTransform>
16
17using namespace osg;
18
19void AnimationPath::insert(double time,const ControlPoint& controlPoint)
20{
21    _timeControlPointMap[time] = controlPoint;
22}
23
24bool AnimationPath::getInterpolatedControlPoint(double time,ControlPoint& controlPoint) const
25{
26    if (_timeControlPointMap.empty()) return false;
27   
28    switch(_loopMode)
29    {
30        case(SWING):
31        {
32            double modulated_time = (time - getFirstTime())/(getPeriod()*2.0);
33            double fraction_part = modulated_time - floor(modulated_time);
34            if (fraction_part>0.5) fraction_part = 1.0-fraction_part;
35           
36            time = getFirstTime()+(fraction_part*2.0) * getPeriod();
37            break;
38        }
39        case(LOOP):
40        {
41            double modulated_time = (time - getFirstTime())/getPeriod();
42            double fraction_part = modulated_time - floor(modulated_time);
43            time = getFirstTime()+fraction_part * getPeriod();
44            break;
45        }
46        case(NO_LOOPING):
47            // no need to modulate the time.
48            break;
49    }
50   
51   
52
53    TimeControlPointMap::const_iterator second = _timeControlPointMap.lower_bound(time);
54    if (second==_timeControlPointMap.begin())
55    {
56        controlPoint = second->second;
57    }
58    else if (second!=_timeControlPointMap.end())
59    {
60        TimeControlPointMap::const_iterator first = second;
61        --first;       
62       
63        // we have both a lower bound and the next item.
64
65        // deta_time = second.time - first.time
66        double delta_time = second->first - first->first;
67
68        if (delta_time==0.0)
69            controlPoint = first->second;
70        else
71        {
72            controlPoint.interpolate((time - first->first)/delta_time,
73                            first->second,
74                            second->second);
75        }       
76    }
77    else // (second==_timeControlPointMap.end())
78    {
79        controlPoint = _timeControlPointMap.rbegin()->second;
80    }
81    return true;
82}
83
84
85void AnimationPath::read(std::istream& in)
86{
87    while (!in.eof())
88    {
89        double time;
90        osg::Vec3d position;
91        osg::Quat rotation;
92        in >> time >> position.x() >> position.y() >> position.z() >> rotation.x() >> rotation.y() >> rotation.z() >> rotation.w();
93        if(!in.eof())
94            insert(time,osg::AnimationPath::ControlPoint(position,rotation));
95    }
96}
97
98void AnimationPath::write(std::ostream& fout) const
99{
100    int prec = fout.precision();
101    fout.precision(15);
102
103    const TimeControlPointMap& tcpm = getTimeControlPointMap();
104    for(TimeControlPointMap::const_iterator tcpmitr=tcpm.begin();
105        tcpmitr!=tcpm.end();
106        ++tcpmitr)
107    {
108        const ControlPoint& cp = tcpmitr->second;
109        fout<<tcpmitr->first<<" "<<cp._position<<" "<<cp._rotation<<std::endl;
110    }
111
112    fout.precision(prec);
113}
114
115class AnimationPathCallbackVisitor : public NodeVisitor
116{
117    public:
118
119        AnimationPathCallbackVisitor(const AnimationPath::ControlPoint& cp, const osg::Vec3d& pivotPoint, bool useInverseMatrix):
120            _cp(cp),
121            _pivotPoint(pivotPoint),
122            _useInverseMatrix(useInverseMatrix) {}
123
124        virtual void apply(MatrixTransform& mt)
125        {
126            Matrix matrix;
127            if (_useInverseMatrix)
128                _cp.getInverse(matrix);
129            else
130                _cp.getMatrix(matrix);
131               
132            mt.setMatrix(osg::Matrix::translate(-_pivotPoint)*matrix);
133        }
134       
135        virtual void apply(PositionAttitudeTransform& pat)
136        {
137            if (_useInverseMatrix)
138            {
139                Matrix matrix;
140                _cp.getInverse(matrix);
141                pat.setPosition(matrix.getTrans());
142                pat.setAttitude(_cp._rotation.inverse());
143                pat.setScale(osg::Vec3(1.0f/_cp._scale.x(),1.0f/_cp._scale.y(),1.0f/_cp._scale.z()));
144                pat.setPivotPoint(_pivotPoint);
145               
146            }
147            else
148            {
149                pat.setPosition(_cp._position);
150                pat.setAttitude(_cp._rotation);
151                pat.setScale(_cp._scale);
152                pat.setPivotPoint(_pivotPoint);
153            }
154        }
155       
156        AnimationPath::ControlPoint _cp;
157        osg::Vec3d _pivotPoint;
158        bool _useInverseMatrix;     
159};
160
161void AnimationPathCallback::operator()(Node* node, NodeVisitor* nv)
162{
163    if (_animationPath.valid() &&
164        nv->getVisitorType()==NodeVisitor::UPDATE_VISITOR &&
165        nv->getFrameStamp())
166    {
167        double time = nv->getFrameStamp()->getReferenceTime();
168        _latestTime = time;
169
170        if (!_pause)
171        {
172            // Only update _firstTime the first time, when its value is still DBL_MAX
173            if (_firstTime==DBL_MAX) _firstTime = time;
174            update(*node);
175        }
176    }
177   
178    // must call any nested node callbacks and continue subgraph traversal.
179    NodeCallback::traverse(node,nv);
180}
181
182double AnimationPathCallback::getAnimationTime() const
183{
184    return ((_latestTime-_firstTime)-_timeOffset)*_timeMultiplier;
185}
186
187void AnimationPathCallback::update(osg::Node& node)
188{
189    AnimationPath::ControlPoint cp;
190    if (_animationPath->getInterpolatedControlPoint(getAnimationTime(),cp))
191    {
192        AnimationPathCallbackVisitor apcv(cp,_pivotPoint,_useInverseMatrix);
193        node.accept(apcv);
194    }
195}
196
197
198void AnimationPathCallback::reset()
199{
200    _firstTime = _latestTime;
201    _pauseTime = _latestTime;
202}
203
204void AnimationPathCallback::setPause(bool pause)
205{
206    if (_pause==pause)
207    {
208        return;
209    }
210   
211    _pause = pause;
212    if (_pause)
213    {
214        _pauseTime = _latestTime;
215    }
216    else
217    {
218        _firstTime += (_latestTime-_pauseTime);
219    }
220}
Note: See TracBrowser for help on using the browser.