#include #include #include #include #include #include static const unsigned int MAX_DIM = 5; class animate { private: unsigned int frameCount; unsigned int frameCountLog10; typedef std::pair< unsigned int, unsigned int > plane; typedef std::pair< unsigned int, unsigned int > range; typedef std::pair< range, range > motion; typedef std::multimap< plane, motion > motions; motions script; std::string base; public: animate( const char* motionFile, const char* baseFile, const char* name ) { if ( this->readMotionFile( motionFile ) && this->readBaseFile( baseFile ) ) { for ( unsigned int ii=0; ii < this->frameCount; ++ii ) { this->generateFrame( ii, name ); } } }; private: bool readMotionFile( const char* fileName ) { std::ifstream in( fileName ); in >> this->frameCount; if ( !in.good() || in.bad() ) { return false; } unsigned int fc = this->frameCount; this->frameCountLog10 = 0; while ( fc > 0 ) { ++this->frameCountLog10; fc /= 10; } while ( !in.eof() ) { char axis1; char axis2; in >> axis1 >> axis2; static std::string axisNames( "xyzwv" ); std::string::size_type an; an = axisNames.find( axis1 ); if ( an == std::string::npos ) { std::cerr << "Unknown axis: " << axis1 << std::endl; return false; } unsigned int a1 = (unsigned int)an; an = axisNames.find( axis2 ); if ( an == std::string::npos ) { std::cerr << "Unknown axis: " << axis2 << std::endl; return false; } unsigned int a2 = (unsigned int)an; unsigned int startAngle; unsigned int stopAngle; in >> startAngle >> stopAngle; unsigned int startFrame; unsigned int stopFrame; in >> startFrame >> stopFrame; if ( in.bad() ) { std::cerr << "Error parsing motion: " << axis1 << axis2 << std::endl; return false; } if ( startFrame >= stopFrame ) { std::cerr << "Skipping bad range: " << axis1 << axis2 << std::endl; continue; } plane pp( a1, a2 ); range aa( startAngle, stopAngle ); range ff( startFrame, stopFrame ); motion mm( aa, ff ); this->script.insert( motions::value_type( pp, mm ) ); } return true; }; bool readBaseFile( const char* fileName ) { std::ifstream in( fileName ); if ( !in.good() || in.bad() ) { return false; } std::ostringstream out; while ( !in.eof() ) { char buf[4096]; in.read( buf, sizeof(buf) ); if ( !in.bad() ) { unsigned int cc = in.gcount(); out.write( buf, cc ); } } this->base = out.str(); return true; }; void generateFrame( unsigned int nn, const char* name ) const { double matrix[ MAX_DIM ][ MAX_DIM ]; for ( unsigned int jj=0; jj < MAX_DIM; ++jj ) { for ( unsigned int ii=0; ii < jj; ++ii ) { matrix[ ii ][ jj ] = 0.0; matrix[ jj ][ ii ] = 0.0; } matrix[ jj ][ jj ] = 1.0; } for ( unsigned int a2 = 1; a2 < MAX_DIM; ++a2 ) { for ( unsigned int a1 = 0; a1 < a2; ++a1 ) { double angle = this->calculateAngle( nn, a1, a2 ); this->applyRotation( a1, a2, angle, matrix ); } } std::ostringstream mm; mm << "[" << MAX_DIM << "]< "; for ( unsigned int jj=0; jj < MAX_DIM; ++jj ) { if ( jj > 0 ) { mm << ", "; } mm << " [" << MAX_DIM << "]< "; for ( unsigned int ii=0; ii < MAX_DIM; ++ii ) { if ( ii > 0 ) { mm << ", "; } mm << matrix[ jj ][ ii ]; } mm << " >"; } mm << " >"; std::ostringstream fn; fn << name << std::setw( this->frameCountLog10 ) << std::setfill( '0' ) << nn ; static std::string BASENAME( "BASENAME" ); static std::string ORIENTATION( "ORIENTATION" ); std::string bc( this->base ); std::string::size_type pos = bc.find( BASENAME ); while ( pos != std::string::npos ) { bc.replace( pos, BASENAME.length(), fn.str() ); pos = bc.find( BASENAME ); } pos = bc.find( ORIENTATION ); while ( pos != std::string::npos ) { bc.replace( pos, ORIENTATION.length(), mm.str() ); pos = bc.find( ORIENTATION ); } fn << ".rt"; std::ofstream out( fn.str().c_str() ); out << bc; }; double calculateAngle( unsigned int nn, unsigned int a1, unsigned int a2 ) const { unsigned int start = 0; double result = 0.0; plane pp( a1, a2 ); motions::const_iterator lb = this->script.lower_bound( pp ); motions::const_iterator ub = this->script.upper_bound( pp ); for ( /*done*/; lb != ub; ++lb ) { motion mm = lb->second; range angles = mm.first; range frames = mm.second; if ( nn >= frames.first && frames.first >= start ) { double rr = (double)( frames.second - frames.first ); double theta = M_PI * (double) ( nn - frames.first ) / rr; if ( theta > M_PI ) { theta = M_PI; } double cc = ::cos( theta ); double ang1 = M_PI * (double)angles.first / 180.0; double ang2 = M_PI * (double)angles.second / 180.0; result = ( ang1 * ( 1.0 + cc ) + ang2 * ( 1.0 - cc ) ) / 2.0; start = frames.first; } } return result; }; void applyRotation( unsigned int a1, unsigned int a2, double angle, double matrix[ MAX_DIM ][ MAX_DIM ] ) const { double cc = ::cos( angle ); double ss = ::sin( angle ); for ( unsigned int jj=0; jj < MAX_DIM; ++jj ) { double v1 = matrix[ a1 ][ jj ]; double v2 = matrix[ a2 ][ jj ]; matrix[ a1 ][ jj ] = v1 * cc + v2 * ss; matrix[ a2 ][ jj ] = v1 * -ss + v2 * cc; } }; }; int main( int argc, const char* argv[] ) { if ( argc != 4 ) { std::cerr << "Usage: animate motion.txt basefile.rt name" << std::endl; return __LINE__; } animate anim( argv[1], argv[2], argv[3] ); return 0; }