OpenWalnut  1.5.0dev
WGEAnimationManipulator.cpp
1 //---------------------------------------------------------------------------
2 //
3 // Project: OpenWalnut ( http://www.openwalnut.org )
4 //
5 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
6 // For more information see http://www.openwalnut.org/copying
7 //
8 // This file is part of OpenWalnut.
9 //
10 // OpenWalnut is free software: you can redistribute it and/or modify
11 // it under the terms of the GNU Lesser General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // OpenWalnut is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public License
21 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
22 //
23 //---------------------------------------------------------------------------
24 
25 #include <cmath>
26 #include <iostream>
27 
28 #include "../../common/math/WMath.h"
29 #include "../../common/math/linearAlgebra/WVectorFixed.h"
30 
31 #include "../../common/WTimer.h"
32 
33 #include "WGEAnimationManipulator.h"
34 
36  m_matrix( osg::Matrixd::identity() ),
37  m_timer( timer ),
38  m_homeOffsetTime( timer->elapsed() )
39 {
40  // initialize
41 }
42 
44 {
45  // clean up
46 }
47 
48 void WGEAnimationManipulator::setByMatrix( const osg::Matrixd& matrix )
49 {
50  m_matrix.invert( matrix );
51 }
52 
53 void WGEAnimationManipulator::setByInverseMatrix( const osg::Matrixd& matrix )
54 {
55  m_matrix = matrix;
56 }
57 
59 {
60  return osg::Matrixd::inverse( m_matrix );
61 }
62 
64 {
65  return m_matrix;
66 }
67 
68 bool WGEAnimationManipulator::handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& /* us */ )
69 {
70  switch( ea.getEventType() )
71  {
72  case osgGA::GUIEventAdapter::FRAME:
73  handleFrame();
74  return false;
75  case osgGA::GUIEventAdapter::KEYDOWN:
76  // if ( ea.getKey() == ' ' ) // space resets
77  // {
78  // home( 0 );
79  // return true;
80  // }
81  default:
82  break;
83  }
84  return false;
85 }
86 
87 void WGEAnimationManipulator::init( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us )
88 {
89  home( ea, us );
90 }
91 
92 void WGEAnimationManipulator::home( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& /* us */ )
93 {
94  home( ea.getTime() );
95 }
96 
97 void WGEAnimationManipulator::home( double /* currentTime */ )
98 {
99  m_homeOffsetTime = m_timer->elapsed();
100 }
101 
103 {
104  m_timer = timer;
105  home( 0 );
106 }
107 
108 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
109 // Utility functions
110 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
111 
112 double degToRad( double deg )
113 {
114  return deg * ( pi() / 180.0 );
115 }
116 
117 double radToDeg( double rad )
118 {
119  return rad * ( 180.0 / pi() );
120 }
121 
122 template < typename T >
123 T sign( T value )
124 {
125  if( value > T( 0 ) )
126  {
127  return 1;
128  }
129  if( value < T( 0 ) )
130  {
131  return -1;
132  }
133  return T( 0 );
134 }
135 
136 template < typename T >
137 T positive( T value )
138 {
139  return value > T( 0 ) ? 1 : 0;
140 }
141 
142 /**
143  * Function which smooths the given value. It uses the cos function to do it. If the value is larger than the maximum, maximum is returned. If
144  * value is smaller then min, min is returned. In between, the function looks like $$cos( pi + x )$$ with $$x \in [0, pi]$$.
145  *
146  * \param value the value.
147  * \param min minimum, used for clamping.
148  * \param max maximum, used for clamping.
149  *
150  * \return
151  */
152 double smooth( double value, double min, double max )
153 {
154  if( value >= max )
155  {
156  return max;
157  }
158  if( value < min )
159  {
160  return min;
161  }
162 
163  double scaledValue = ( value - min ) / max;
164  return min + max * ( 0.5 * ( 1.0 + cos( pi() + ( scaledValue * pi() ) ) ) );
165 }
166 
167 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
168 // Transformators
169 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
170 
171 /**
172  * Base class for all further transformations.
173  */
174 class Transformation: public osg::Matrixd // NOTE: yes this is a bad idea since osg::Matrixd does not provide a virtual destructor.
175 {
176 public:
177  /**
178  * The time in seconds when this transformation is finished.
179  *
180  * \return finish time in seconds.
181  */
182  virtual double finish() const
183  {
184  return m_finishTime;
185  }
186 
187  /**
188  * The time in seconds this transformation is running.
189  *
190  * \return duration in seconds
191  */
192  virtual double duration() const
193  {
194  return m_duration;
195  }
196 
197  /**
198  * Vector representing the X axe
199  */
200  static WVector3d axeX;
201 
202  /**
203  * Vector representing the Y axe
204  */
205  static WVector3d axeY;
206 
207  /**
208  * Vector representing the Z axe
209  */
210  static WVector3d axeZ;
211 
212 protected:
213  /**
214  * The time this is finished.
215  */
216  double m_finishTime;
217 
218  /**
219  * Duration time.
220  */
221  double m_duration;
222 };
223 
224 // Initialize the statics
225 WVector3d Transformation::axeX = WVector3d( 1.0, 0.0, 0.0 );
226 WVector3d Transformation::axeY = WVector3d( 0.0, 1.0, 0.0 );
227 WVector3d Transformation::axeZ = WVector3d( 0.0, 0.0, 1.0 );
228 
229 /**
230  * Provides a time dependent rotation around a specified axis.
231  */
232 class Rotator: public Transformation
233 {
234 public:
235  /**
236  * Create a rotation matrix which rotates a certain number of degrees with a given speed. This means, that the time interval is defined by speed
237  * and degree.
238  *
239  * \param degree rotate this number of degree
240  * \param speed rotation speed in degrees per second
241  * \param time current time in seconds
242  * \param startTime time offset. When to start rotation
243  * \param axes the axes to rotate
244  */
245  Rotator( double time, double startTime, WVector3d axes, double degree, double speed ):
247  {
248  m_duration = degree / speed;
249  m_finishTime = startTime + m_duration;
250 
251  double rtime = positive( time - startTime ) * ( time - startTime );
252  double rangle = smooth( speed * rtime, 0.0, degree );
253  makeRotate( degToRad( rangle ), axes[0], axes[1], axes[2] );
254  }
255 };
256 
257 /**
258  * Provides a comfortable zoomer lens.
259  */
260 class Zoomer: public Transformation
261 {
262 public:
263  /**
264  * Zooms the scene with the given factor. This is a scaling on all axes. A factor < 1.0 is zooming out. A factor > 1.0 is zooming in.
265  * Negative values are handled by their absolute value.
266  *
267  * \param time current time
268  * \param startTime when to start the transformation
269  * \param factor zooming factor.
270  * \param speed the speed in zoom / second
271  */
272  Zoomer( double time, double startTime, double factor, double speed ):
274  {
275  // get a scaling factor
276  double zfactor = std::abs( factor );
277  if( factor < 1.0 )
278  {
279  zfactor = 1.0 / factor;
280  }
281  zfactor -= 1.0;
282 
283  m_duration = zfactor / speed;
284  m_finishTime = startTime + m_duration;
285 
286  double rtime = time - startTime;
287  double sfactor = 1.0 + smooth( ( speed * rtime ), 0.0, zfactor );
288 
289  if( factor < 1.0 )
290  {
291  makeScale( 1.0 / sfactor, 1.0 / sfactor, 1.0 / sfactor );
292  }
293  else
294  {
295  makeScale( sfactor, sfactor, sfactor );
296  }
297  }
298 };
299 
300 /**
301  * Provides a time-dependent translation.
302  */
304 {
305 public:
306  /**
307  * Translates the scene using the given direction. The speed is given as units per second.
308  *
309  * \param time current time
310  * \param startTime the time when to start the transformation
311  * \param direction the direction. Length is important here.
312  * \param speed speed in direction-vector per second
313  */
314  Translator( double time, double startTime, WVector3d direction, double speed ):
316  {
317  m_duration = 1.0 / speed;
318  m_finishTime = startTime + m_duration;
319 
320  double rtime = time - startTime;
321  double scaler = smooth( speed * rtime, 0.0, 1.0 );
322  makeTranslate( ( direction * scaler ).operator osg::Vec3d() );
323  }
324 };
325 
327 {
328  // calculate the proper sec:frame coordinate:
329 
330  // time in seconds, it always relates to a 24 frames per second system
331  double elapsed = m_timer->elapsed() - m_homeOffsetTime;
332 
333  // this brings the BBox to the center, makes it larger and rotates the front towards the camera
334  osg::Matrixd mBBTranslate = osg::Matrixd::translate( -159.0 / 2.0, -199.0 / 2.0, -159.0 / 2.0 );
335  osg::Matrixd mBBScale = osg::Matrixd::scale( 1.5, 1.5, 1.5 );
336  osg::Matrixd mBBRotate = osg::Matrixd::rotate( -pi() / 2.0, 1.0, 0.0, 0.0 ) *
337  osg::Matrixd::rotate( pi(), 0.0, 1.0, 0.0 );
338  // Scene 1:
339  // construct the animation here.
340  Rotator rotateToBack = Rotator( elapsed, 0.0, Transformation::axeY, 360.0, 22.5 );
341  Rotator rotateToBottom = Rotator( elapsed, rotateToBack.finish() - 3.0, -1.0 * Transformation::axeX, 15.0, 5.0 );
342  Zoomer zoomToIrgendwas = Zoomer( elapsed, rotateToBottom.finish() - 2.0, 2.0, 0.25 );
343  Translator translateABitUp = Translator( elapsed, rotateToBottom.finish() - 2.0, Transformation::axeY * 90.0, 0.25 );
344 
345  Zoomer zoomToNei1 = Zoomer( elapsed, translateABitUp.finish() - 2.0, 2.0, 0.15 );
346  Zoomer zoomToNaus = Zoomer( elapsed, zoomToNei1.finish() + 1.0, 0.1, 3.0 );
347  Zoomer zoomToNei2 = Zoomer( elapsed, zoomToNaus.finish(), 5.0, 1.5 );
348 
349  m_matrix = mBBTranslate * mBBScale * mBBRotate * rotateToBack
350  * rotateToBottom
351  * zoomToIrgendwas
352  * translateABitUp
353  * zoomToNei1
354  * zoomToNaus
355  * zoomToNei2;
356 
357  // Scene 2:
358  // this brings the BBox to the center, makes it larger and rotates the front towards the camera
359  // osg::Matrixd mBBTranslate = osg::Matrixd::translate( -159.0 / 2.0, -199.0 / 2.0, -179.0 / 2.0 );
360  // osg::Matrixd mBBScale = osg::Matrixd::scale( 2.0, 2.0, 2.0 );
361  // osg::Matrixd mBBRotate = osg::Matrixd::rotate( -pi() / 2.0, 1.0, 0.0, 0.0 ) *
362  // osg::Matrixd::rotate( pi(), 0.0, 1.0, 0.0 );
363  // Transformation rotateToBack = Rotator( elapsed, 0.0, Transformation::axeY, 360.0, 22.5 );
364  // Transformation translateABitUp = Translator( elapsed, rotateToBack.finish() - 5.0, Transformation::axeY * -45.0, 0.25 );
365  // Transformation zoomNei = Zoomer( elapsed, rotateToBack.finish() - 5.0, 2.00, 0.25 );
366  // Transformation rotateABit = Rotator( elapsed, zoomNei.finish() -1.0, Transformation::axeY, 360.0 + 45.0, 12.0 );
367  //
368  // m_matrix = mBBTranslate * mBBScale * mBBRotate * rotateToBack
369  // * translateABitUp
370  // * zoomNei
371  // * rotateABit;
372 }
373 
Provides a time dependent rotation around a specified axis.
Rotator(double time, double startTime, WVector3d axes, double degree, double speed)
Create a rotation matrix which rotates a certain number of degrees with a given speed.
Base class for all further transformations.
virtual double finish() const
The time in seconds when this transformation is finished.
static WVector3d axeY
Vector representing the Y axe.
double m_finishTime
The time this is finished.
virtual double duration() const
The time in seconds this transformation is running.
double m_duration
Duration time.
static WVector3d axeZ
Vector representing the Z axe.
static WVector3d axeX
Vector representing the X axe.
Provides a time-dependent translation.
Translator(double time, double startTime, WVector3d direction, double speed)
Translates the scene using the given direction.
virtual void setByMatrix(const osg::Matrixd &matrix)
Sets the current matrix of this animation manipulator.
virtual bool handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &us)
Handles incoming events send by the event dispatcher of the view.
void handleFrame()
This method updates m_matrix per frame according to time elapsed.
virtual osg::Matrixd getMatrix() const
Gets the current animation matrix for the current time-step.
virtual ~WGEAnimationManipulator()
Destructor.
double m_homeOffsetTime
If home() is called, the homeOffsetTime stores the timers current value.
virtual void init(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &us)
Initializes this manipulator.
WTimer::ConstSPtr m_timer
This timer keeps track of the current animation-time.
virtual void setTimer(WTimer::ConstSPtr timer)
Allows to switch the timer type.
osg::Matrixd m_matrix
The view matrix.
virtual void setByInverseMatrix(const osg::Matrixd &matrix)
Sets the current inverse matrix of this animation manipulator.
virtual osg::Matrixd getInverseMatrix() const
Gets the current inverse animation matrix for the current time-step.
virtual void home(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &us)
Sets the manipulator back to its default.
WGEAnimationManipulator(WTimer::ConstSPtr timer=WTimer::ConstSPtr(new WRealtimeTimer()))
Constructs a animation path manipulator using a realtime timer if not specified.
std::shared_ptr< const WTimer > ConstSPtr
Convenience typedef for a const shared_ptr.
Definition: WTimer.h:47
Provides a comfortable zoomer lens.
Zoomer(double time, double startTime, double factor, double speed)
Zooms the scene with the given factor.