OpenWalnut  1.4.0
WGEAnimationManipulator.cpp
00001 //---------------------------------------------------------------------------
00002 //
00003 // Project: OpenWalnut ( http://www.openwalnut.org )
00004 //
00005 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
00006 // For more information see http://www.openwalnut.org/copying
00007 //
00008 // This file is part of OpenWalnut.
00009 //
00010 // OpenWalnut is free software: you can redistribute it and/or modify
00011 // it under the terms of the GNU Lesser General Public License as published by
00012 // the Free Software Foundation, either version 3 of the License, or
00013 // (at your option) any later version.
00014 //
00015 // OpenWalnut is distributed in the hope that it will be useful,
00016 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 // GNU Lesser General Public License for more details.
00019 //
00020 // You should have received a copy of the GNU Lesser General Public License
00021 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
00022 //
00023 //---------------------------------------------------------------------------
00024 
00025 #include <cmath>
00026 #include <iostream>
00027 
00028 #include "../../common/math/WMath.h"
00029 #include "../../common/math/linearAlgebra/WVectorFixed.h"
00030 
00031 #include "../../common/WTimer.h"
00032 
00033 #include "WGEAnimationManipulator.h"
00034 
00035 WGEAnimationManipulator::WGEAnimationManipulator( WTimer::ConstSPtr timer ):
00036     m_matrix( osg::Matrixd::identity() ),
00037     m_timer( timer ),
00038     m_homeOffsetTime( timer->elapsed() ),
00039     m_paused( true )
00040 {
00041     // initialize
00042 }
00043 
00044 WGEAnimationManipulator::~WGEAnimationManipulator()
00045 {
00046     // clean up
00047 }
00048 
00049 void WGEAnimationManipulator::setByMatrix( const osg::Matrixd& matrix )
00050 {
00051     m_matrix.invert( matrix );
00052 }
00053 
00054 void WGEAnimationManipulator::setByInverseMatrix( const osg::Matrixd& matrix )
00055 {
00056     m_matrix = matrix;
00057 }
00058 
00059 osg::Matrixd WGEAnimationManipulator::getMatrix() const
00060 {
00061     return osg::Matrixd::inverse( m_matrix );
00062 }
00063 
00064 osg::Matrixd WGEAnimationManipulator::getInverseMatrix() const
00065 {
00066     return m_matrix;
00067 }
00068 
00069 bool WGEAnimationManipulator::handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& /* us */ )
00070 {
00071     switch( ea.getEventType() )
00072     {
00073     case osgGA::GUIEventAdapter::FRAME:
00074         handleFrame();
00075         return false;
00076     case osgGA::GUIEventAdapter::KEYDOWN:
00077         // if ( ea.getKey() == ' ' )   // space resets
00078         // {
00079         //     home( 0 );
00080         //     return true;
00081         // }
00082     default:
00083         break;
00084     }
00085     return false;
00086 }
00087 
00088 void WGEAnimationManipulator::init( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us )
00089 {
00090     home( ea, us );
00091 }
00092 
00093 void WGEAnimationManipulator::home( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& /* us */ )
00094 {
00095     home( ea.getTime() );
00096 }
00097 
00098 void WGEAnimationManipulator::home( double /* currentTime */ )
00099 {
00100     m_homeOffsetTime = m_timer->elapsed();
00101 }
00102 
00103 void WGEAnimationManipulator::setTimer( WTimer::ConstSPtr timer )
00104 {
00105     m_timer = timer;
00106     home( 0 );
00107 }
00108 
00109 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
00110 // Utility functions
00111 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
00112 
00113 double degToRad( double deg )
00114 {
00115     return deg * ( piDouble / 180.0 );
00116 }
00117 
00118 double radToDeg( double rad )
00119 {
00120     return rad * ( 180.0 / piDouble );
00121 }
00122 
00123 template < typename T >
00124 T sign( T value )
00125 {
00126     if( value > T( 0 ) )
00127     {
00128         return 1;
00129     }
00130     if( value < T( 0 ) )
00131     {
00132         return -1;
00133     }
00134     return T( 0 );
00135 }
00136 
00137 template < typename T >
00138 T positive( T value )
00139 {
00140     return value > T( 0 ) ? 1 : 0;
00141 }
00142 
00143 /**
00144  * 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
00145  * value is smaller then min, min is returned. In between, the function looks like $$cos( pi + x )$$ with $$x \in [0, pi]$$.
00146  *
00147  * \param value the value.
00148  * \param min minimum, used for clamping.
00149  * \param max maximum, used for clamping.
00150  *
00151  * \return
00152  */
00153 double smooth( double value, double min, double max )
00154 {
00155     if( value >= max )
00156     {
00157         return max;
00158     }
00159     if( value < min )
00160     {
00161         return min;
00162     }
00163 
00164     double scaledValue = ( value - min ) / max;
00165     return min + max * ( 0.5 * ( 1.0 + cos( piDouble + ( scaledValue * piDouble ) ) ) );
00166 }
00167 
00168 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
00169 // Transformators
00170 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
00171 
00172 /**
00173  * Base class for all further transformations.
00174  */
00175 class Transformation: public osg::Matrixd       // NOTE: yes this is a bad idea since osg::Matrixd does not provide a virtual destructor.
00176 {
00177 public:
00178     /**
00179      * The time in seconds when this transformation is finished.
00180      *
00181      * \return finish time in seconds.
00182      */
00183     virtual double finish() const
00184     {
00185         return m_finishTime;
00186     }
00187 
00188     /**
00189      * The time in seconds this transformation is running.
00190      *
00191      * \return duration in seconds
00192      */
00193     virtual double duration() const
00194     {
00195         return m_duration;
00196     }
00197 
00198     /**
00199      * Vector representing the X axe
00200      */
00201     static WVector3d axeX;
00202 
00203     /**
00204      * Vector representing the Y axe
00205      */
00206     static WVector3d axeY;
00207 
00208     /**
00209      * Vector representing the Z axe
00210      */
00211     static WVector3d axeZ;
00212 
00213 protected:
00214     /**
00215      * The time this is finished.
00216      */
00217     double m_finishTime;
00218 
00219     /**
00220      * Duration time.
00221      */
00222     double m_duration;
00223 };
00224 
00225 // Initialize the statics
00226 WVector3d Transformation::axeX = WVector3d( 1.0, 0.0, 0.0 );
00227 WVector3d Transformation::axeY = WVector3d( 0.0, 1.0, 0.0 );
00228 WVector3d Transformation::axeZ = WVector3d( 0.0, 0.0, 1.0 );
00229 
00230 /**
00231  * Provides a time dependent rotation around a specified axis.
00232  */
00233 class Rotator: public Transformation
00234 {
00235 public:
00236     /**
00237      * 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
00238      * and degree.
00239      *
00240      * \param degree rotate this number of degree
00241      * \param speed  rotation speed in degree per second
00242      * \param time   current time in seconds
00243      * \param startTime time offset. When to start rotation
00244      * \param axes the axes to rotate
00245      *
00246      * \return the rotation matrix at the current time.
00247      */
00248     Rotator( double time, double startTime, WVector3d axes, double degree, double speed ):
00249         Transformation()
00250     {
00251         m_duration = degree / speed;
00252         m_finishTime = startTime + m_duration;
00253 
00254         double rtime = positive( time - startTime ) * ( time - startTime );
00255         double rangle = smooth( speed * rtime, 0.0, degree );
00256         makeRotate( degToRad( rangle ), axes[0], axes[1], axes[2] );
00257     }
00258 };
00259 
00260 /**
00261  * Provides a comfortable zoomer lens.
00262  */
00263 class Zoomer: public Transformation
00264 {
00265 public:
00266     /**
00267      * 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.
00268      * Negative values are handled by their absolute value.
00269      *
00270      * \param time current time
00271      * \param startTime when to start the transformation
00272      * \param factor zooming factor.
00273      * \param speed the speed in zoom / second
00274      */
00275     Zoomer( double time, double startTime, double factor, double speed ):
00276         Transformation()
00277     {
00278         // get a scaling factor
00279         double zfactor = abs( factor );
00280         if( factor < 1.0 )
00281         {
00282             zfactor = 1.0 / factor;
00283         }
00284         zfactor -= 1.0;
00285 
00286         m_duration = zfactor / speed;
00287         m_finishTime = startTime + m_duration;
00288 
00289         double rtime = time - startTime;
00290         double sfactor = 1.0 + smooth( ( speed * rtime ), 0.0, zfactor );
00291 
00292         if( factor < 1.0 )
00293         {
00294             makeScale( 1.0 / sfactor, 1.0 / sfactor, 1.0 / sfactor );
00295         }
00296         else
00297         {
00298             makeScale( sfactor, sfactor, sfactor );
00299         }
00300     }
00301 };
00302 
00303 /**
00304  * Provides a time-dependent translation.
00305  */
00306 class Translator: public Transformation
00307 {
00308 public:
00309     /**
00310      * Translates the scene using the given direction. The speed is given as units per second.
00311      *
00312      * \param time current time
00313      * \param startTime the time when to start the transformation
00314      * \param direction the direction. Length is important here.
00315      * \param speed speed in direction-vector per second
00316      */
00317     Translator( double time, double startTime, WVector3d direction, double speed ):
00318         Transformation()
00319     {
00320         m_duration = 1.0 / speed;
00321         m_finishTime = startTime + m_duration;
00322 
00323         double rtime = time - startTime;
00324         double scaler = smooth( speed * rtime, 0.0, 1.0 );
00325         makeTranslate( ( direction * scaler ).operator osg::Vec3d() );
00326     }
00327 };
00328 
00329 void WGEAnimationManipulator::handleFrame()
00330 {
00331     // calculate the proper sec:frame coordinate:
00332 
00333     // time in seconds, it always relates to a 24 frames per second system
00334     double elapsed = m_timer->elapsed() - m_homeOffsetTime;
00335 
00336     // this brings the BBox to the center, makes it larger and rotates the front towards the camera
00337     osg::Matrixd mBBTranslate = osg::Matrixd::translate( -159.0 / 2.0, -199.0 / 2.0, -159.0 / 2.0 );
00338     osg::Matrixd mBBScale     = osg::Matrixd::scale( 1.5, 1.5, 1.5 );
00339     osg::Matrixd mBBRotate    = osg::Matrixd::rotate( -piDouble / 2.0, 1.0, 0.0, 0.0 ) *
00340                                 osg::Matrixd::rotate(  piDouble, 0.0, 1.0, 0.0 );
00341     // Scene 1:
00342     // construct the animation here.
00343     Rotator rotateToBack =          Rotator( elapsed, 0.0, Transformation::axeY, 360.0, 22.5 );
00344     Rotator rotateToBottom =        Rotator( elapsed, rotateToBack.finish() - 3.0, -1.0 * Transformation::axeX, 15.0, 5.0 );
00345     Zoomer  zoomToIrgendwas =        Zoomer( elapsed, rotateToBottom.finish() - 2.0, 2.0, 0.25 );
00346     Translator translateABitUp = Translator( elapsed, rotateToBottom.finish() - 2.0, Transformation::axeY * 90.0, 0.25 );
00347 
00348     Zoomer  zoomToNei1 =              Zoomer( elapsed, translateABitUp.finish() - 2.0, 2.0, 0.15 );
00349     Zoomer  zoomToNaus =             Zoomer( elapsed, zoomToNei1.finish() + 1.0, 0.1, 3.0 );
00350     Zoomer  zoomToNei2 =              Zoomer( elapsed, zoomToNaus.finish(), 5.0, 1.5 );
00351 
00352     m_matrix = mBBTranslate * mBBScale * mBBRotate * rotateToBack
00353                                                    * rotateToBottom
00354                                                    * zoomToIrgendwas
00355                                                    * translateABitUp
00356                                                    * zoomToNei1
00357                                                    * zoomToNaus
00358                                                    * zoomToNei2;
00359 
00360     // Scene 2:
00361     // this brings the BBox to the center, makes it larger and rotates the front towards the camera
00362     // osg::Matrixd mBBTranslate = osg::Matrixd::translate( -159.0 / 2.0, -199.0 / 2.0, -179.0 / 2.0 );
00363     // osg::Matrixd mBBScale     = osg::Matrixd::scale( 2.0, 2.0, 2.0 );
00364     // osg::Matrixd mBBRotate    = osg::Matrixd::rotate( -piDouble / 2.0, 1.0, 0.0, 0.0 ) *
00365     //                             osg::Matrixd::rotate(  piDouble, 0.0, 1.0, 0.0 );
00366     // Transformation rotateToBack =          Rotator( elapsed, 0.0, Transformation::axeY, 360.0, 22.5 );
00367     // Transformation translateABitUp = Translator( elapsed, rotateToBack.finish() - 5.0, Transformation::axeY * -45.0, 0.25 );
00368     // Transformation zoomNei = Zoomer( elapsed,  rotateToBack.finish() - 5.0, 2.00, 0.25 );
00369     // Transformation rotateABit = Rotator( elapsed, zoomNei.finish() -1.0, Transformation::axeY, 360.0 + 45.0, 12.0 );
00370     //
00371     // m_matrix = mBBTranslate * mBBScale * mBBRotate * rotateToBack
00372     //                                                * translateABitUp
00373     //                                                * zoomNei
00374     //                                                * rotateABit;
00375 }
00376