OpenWalnut
1.4.0
|
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