OpenWalnut  1.4.0
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  m_paused( true )
40 {
41  // initialize
42 }
43 
45 {
46  // clean up
47 }
48 
49 void WGEAnimationManipulator::setByMatrix( const osg::Matrixd& matrix )
50 {
51  m_matrix.invert( matrix );
52 }
53 
54 void WGEAnimationManipulator::setByInverseMatrix( const osg::Matrixd& matrix )
55 {
56  m_matrix = matrix;
57 }
58 
60 {
61  return osg::Matrixd::inverse( m_matrix );
62 }
63 
65 {
66  return m_matrix;
67 }
68 
69 bool WGEAnimationManipulator::handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& /* us */ )
70 {
71  switch( ea.getEventType() )
72  {
73  case osgGA::GUIEventAdapter::FRAME:
74  handleFrame();
75  return false;
76  case osgGA::GUIEventAdapter::KEYDOWN:
77  // if ( ea.getKey() == ' ' ) // space resets
78  // {
79  // home( 0 );
80  // return true;
81  // }
82  default:
83  break;
84  }
85  return false;
86 }
87 
88 void WGEAnimationManipulator::init( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us )
89 {
90  home( ea, us );
91 }
92 
93 void WGEAnimationManipulator::home( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& /* us */ )
94 {
95  home( ea.getTime() );
96 }
97 
98 void WGEAnimationManipulator::home( double /* currentTime */ )
99 {
100  m_homeOffsetTime = m_timer->elapsed();
101 }
102 
104 {
105  m_timer = timer;
106  home( 0 );
107 }
108 
109 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
110 // Utility functions
111 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
112 
113 double degToRad( double deg )
114 {
115  return deg * ( piDouble / 180.0 );
116 }
117 
118 double radToDeg( double rad )
119 {
120  return rad * ( 180.0 / piDouble );
121 }
122 
123 template < typename T >
124 T sign( T value )
125 {
126  if( value > T( 0 ) )
127  {
128  return 1;
129  }
130  if( value < T( 0 ) )
131  {
132  return -1;
133  }
134  return T( 0 );
135 }
136 
137 template < typename T >
138 T positive( T value )
139 {
140  return value > T( 0 ) ? 1 : 0;
141 }
142 
143 /**
144  * 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
145  * value is smaller then min, min is returned. In between, the function looks like $$cos( pi + x )$$ with $$x \in [0, pi]$$.
146  *
147  * \param value the value.
148  * \param min minimum, used for clamping.
149  * \param max maximum, used for clamping.
150  *
151  * \return
152  */
153 double smooth( double value, double min, double max )
154 {
155  if( value >= max )
156  {
157  return max;
158  }
159  if( value < min )
160  {
161  return min;
162  }
163 
164  double scaledValue = ( value - min ) / max;
165  return min + max * ( 0.5 * ( 1.0 + cos( piDouble + ( scaledValue * piDouble ) ) ) );
166 }
167 
168 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
169 // Transformators
170 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
171 
172 /**
173  * Base class for all further transformations.
174  */
175 class Transformation: public osg::Matrixd // NOTE: yes this is a bad idea since osg::Matrixd does not provide a virtual destructor.
176 {
177 public:
178  /**
179  * The time in seconds when this transformation is finished.
180  *
181  * \return finish time in seconds.
182  */
183  virtual double finish() const
184  {
185  return m_finishTime;
186  }
187 
188  /**
189  * The time in seconds this transformation is running.
190  *
191  * \return duration in seconds
192  */
193  virtual double duration() const
194  {
195  return m_duration;
196  }
197 
198  /**
199  * Vector representing the X axe
200  */
201  static WVector3d axeX;
202 
203  /**
204  * Vector representing the Y axe
205  */
206  static WVector3d axeY;
207 
208  /**
209  * Vector representing the Z axe
210  */
211  static WVector3d axeZ;
212 
213 protected:
214  /**
215  * The time this is finished.
216  */
217  double m_finishTime;
218 
219  /**
220  * Duration time.
221  */
222  double m_duration;
223 };
224 
225 // Initialize the statics
226 WVector3d Transformation::axeX = WVector3d( 1.0, 0.0, 0.0 );
227 WVector3d Transformation::axeY = WVector3d( 0.0, 1.0, 0.0 );
228 WVector3d Transformation::axeZ = WVector3d( 0.0, 0.0, 1.0 );
229 
230 /**
231  * Provides a time dependent rotation around a specified axis.
232  */
233 class Rotator: public Transformation
234 {
235 public:
236  /**
237  * Create a rotation matrix which rotates a certain number of degree with a given speed. This means, that the time interval is defined by speed
238  * and degree.
239  *
240  * \param degree rotate this number of degree
241  * \param speed rotation speed in degree per second
242  * \param time current time in seconds
243  * \param startTime time offset. When to start rotation
244  * \param axes the axes to rotate
245  *
246  * \return the rotation matrix at the current time.
247  */
248  Rotator( double time, double startTime, WVector3d axes, double degree, double speed ):
250  {
251  m_duration = degree / speed;
252  m_finishTime = startTime + m_duration;
253 
254  double rtime = positive( time - startTime ) * ( time - startTime );
255  double rangle = smooth( speed * rtime, 0.0, degree );
256  makeRotate( degToRad( rangle ), axes[0], axes[1], axes[2] );
257  }
258 };
259 
260 /**
261  * Provides a comfortable zoomer lens.
262  */
263 class Zoomer: public Transformation
264 {
265 public:
266  /**
267  * 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.
268  * Negative values are handled by their absolute value.
269  *
270  * \param time current time
271  * \param startTime when to start the transformation
272  * \param factor zooming factor.
273  * \param speed the speed in zoom / second
274  */
275  Zoomer( double time, double startTime, double factor, double speed ):
277  {
278  // get a scaling factor
279  double zfactor = abs( factor );
280  if( factor < 1.0 )
281  {
282  zfactor = 1.0 / factor;
283  }
284  zfactor -= 1.0;
285 
286  m_duration = zfactor / speed;
287  m_finishTime = startTime + m_duration;
288 
289  double rtime = time - startTime;
290  double sfactor = 1.0 + smooth( ( speed * rtime ), 0.0, zfactor );
291 
292  if( factor < 1.0 )
293  {
294  makeScale( 1.0 / sfactor, 1.0 / sfactor, 1.0 / sfactor );
295  }
296  else
297  {
298  makeScale( sfactor, sfactor, sfactor );
299  }
300  }
301 };
302 
303 /**
304  * Provides a time-dependent translation.
305  */
307 {
308 public:
309  /**
310  * Translates the scene using the given direction. The speed is given as units per second.
311  *
312  * \param time current time
313  * \param startTime the time when to start the transformation
314  * \param direction the direction. Length is important here.
315  * \param speed speed in direction-vector per second
316  */
317  Translator( double time, double startTime, WVector3d direction, double speed ):
319  {
320  m_duration = 1.0 / speed;
321  m_finishTime = startTime + m_duration;
322 
323  double rtime = time - startTime;
324  double scaler = smooth( speed * rtime, 0.0, 1.0 );
325  makeTranslate( ( direction * scaler ).operator osg::Vec3d() );
326  }
327 };
328 
330 {
331  // calculate the proper sec:frame coordinate:
332 
333  // time in seconds, it always relates to a 24 frames per second system
334  double elapsed = m_timer->elapsed() - m_homeOffsetTime;
335 
336  // this brings the BBox to the center, makes it larger and rotates the front towards the camera
337  osg::Matrixd mBBTranslate = osg::Matrixd::translate( -159.0 / 2.0, -199.0 / 2.0, -159.0 / 2.0 );
338  osg::Matrixd mBBScale = osg::Matrixd::scale( 1.5, 1.5, 1.5 );
339  osg::Matrixd mBBRotate = osg::Matrixd::rotate( -piDouble / 2.0, 1.0, 0.0, 0.0 ) *
340  osg::Matrixd::rotate( piDouble, 0.0, 1.0, 0.0 );
341  // Scene 1:
342  // construct the animation here.
343  Rotator rotateToBack = Rotator( elapsed, 0.0, Transformation::axeY, 360.0, 22.5 );
344  Rotator rotateToBottom = Rotator( elapsed, rotateToBack.finish() - 3.0, -1.0 * Transformation::axeX, 15.0, 5.0 );
345  Zoomer zoomToIrgendwas = Zoomer( elapsed, rotateToBottom.finish() - 2.0, 2.0, 0.25 );
346  Translator translateABitUp = Translator( elapsed, rotateToBottom.finish() - 2.0, Transformation::axeY * 90.0, 0.25 );
347 
348  Zoomer zoomToNei1 = Zoomer( elapsed, translateABitUp.finish() - 2.0, 2.0, 0.15 );
349  Zoomer zoomToNaus = Zoomer( elapsed, zoomToNei1.finish() + 1.0, 0.1, 3.0 );
350  Zoomer zoomToNei2 = Zoomer( elapsed, zoomToNaus.finish(), 5.0, 1.5 );
351 
352  m_matrix = mBBTranslate * mBBScale * mBBRotate * rotateToBack
353  * rotateToBottom
354  * zoomToIrgendwas
355  * translateABitUp
356  * zoomToNei1
357  * zoomToNaus
358  * zoomToNei2;
359 
360  // Scene 2:
361  // this brings the BBox to the center, makes it larger and rotates the front towards the camera
362  // osg::Matrixd mBBTranslate = osg::Matrixd::translate( -159.0 / 2.0, -199.0 / 2.0, -179.0 / 2.0 );
363  // osg::Matrixd mBBScale = osg::Matrixd::scale( 2.0, 2.0, 2.0 );
364  // osg::Matrixd mBBRotate = osg::Matrixd::rotate( -piDouble / 2.0, 1.0, 0.0, 0.0 ) *
365  // osg::Matrixd::rotate( piDouble, 0.0, 1.0, 0.0 );
366  // Transformation rotateToBack = Rotator( elapsed, 0.0, Transformation::axeY, 360.0, 22.5 );
367  // Transformation translateABitUp = Translator( elapsed, rotateToBack.finish() - 5.0, Transformation::axeY * -45.0, 0.25 );
368  // Transformation zoomNei = Zoomer( elapsed, rotateToBack.finish() - 5.0, 2.00, 0.25 );
369  // Transformation rotateABit = Rotator( elapsed, zoomNei.finish() -1.0, Transformation::axeY, 360.0 + 45.0, 12.0 );
370  //
371  // m_matrix = mBBTranslate * mBBScale * mBBRotate * rotateToBack
372  // * translateABitUp
373  // * zoomNei
374  // * rotateABit;
375 }
376