53 #if QT_VERSION >= 0x050000
63 const std::bitset<4> HIERARCHY (static_cast<int>(0));
64 const std::bitset<4> ROOT_DEFINITION (static_cast<int>(1));
65 const std::bitset<4> OPENED_BRACKET (static_cast<int>(2));
66 const std::bitset<4> CLOSED_BRACKET (static_cast<int>(3));
67 const std::bitset<4> OFFSET (static_cast<int>(4));
68 const std::bitset<4> CHANNELS (static_cast<int>(5));
69 const std::bitset<4> JOINT (static_cast<int>(6));
70 const std::bitset<4> ENDSITE (static_cast<int>(7));
71 const std::bitset<4> MOTION (static_cast<int>(8));
72 const std::bitset<4> FRAMES (static_cast<int>(9));
73 const std::bitset<4> FRAME_TIME (static_cast<int>(10));
74 const std::bitset<4> CHANNEL_DATA (static_cast<int>(11));
78 enum ChannelType{NotGiven,XP,YP,ZP,XR,YR,ZR};
82 ChannelType dataChannels[6];
83 unsigned int dataOffset[6];
85 unsigned int channelOffset;
92 dataChannels[i]=NotGiven;
105 : ignoreJointScaling_(true),
107 checkJointScaling_(0),
108 loadDefaultButton_(0)
120 return QString( tr(
"Biovision Format files ( *.bvh )") );
126 return QString( tr(
"Biovision Format files ( *.bvh )") );
138 void trimString( std::string& _string) {
141 size_t start = _string.find_first_not_of(
" \t\r\n");
142 size_t end = _string.find_last_not_of(
" \t\r\n");
144 if(( std::string::npos == start ) || ( std::string::npos == end))
147 _string = _string.substr( start, end-start+1 );
154 if ( checkJointScaling_ != 0 )
155 ignoreJointScaling_ = checkJointScaling_->isChecked();
161 std::fstream input( _filename.toUtf8(), std::ios_base::in );
163 if ( !input.is_open() || !input.good() ){
164 emit log(
LOGERR, tr(
"Error: cannot open file %1").arg(_filename) );
177 object->setFromFileName(_filename);
178 object->setName(object->
filename());
182 emit log(
LOGERR, tr(
"Error: Unable to add skeleton!"));
192 std::bitset<4> waitingFor = HIERARCHY;
194 std::map< Skeleton::Joint* , JointInfo> jointInfos;
199 uint currentFrame = 0;
202 while( input && !input.eof() )
204 std::getline(input,line);
206 emit log(
LOGERR, tr(
"Error: could not read file properly!"));
214 if ( line.size() == 0 )
217 std::stringstream stream(line);
223 if ( (waitingFor == HIERARCHY) && (keyWrd ==
"HIERARCHY") ){
224 waitingFor = ROOT_DEFINITION;
229 if ( (waitingFor == ROOT_DEFINITION) && (keyWrd ==
"ROOT") ){
237 jointInfos[rootJoint]=info;
238 currentParent = rootJoint;
240 waitingFor = OPENED_BRACKET;
245 if ( (waitingFor == OPENED_BRACKET) && (keyWrd ==
"{") ){
247 waitingFor = OFFSET | CHANNELS | JOINT | ENDSITE | CLOSED_BRACKET;
253 if ( (!(waitingFor&CLOSED_BRACKET).none()) && (keyWrd ==
"}") ){
255 if ( currentParent->
parent() == 0 )
258 waitingFor = JOINT | CLOSED_BRACKET;
261 currentParent = currentParent->
parent();
266 if ( (!(waitingFor&JOINT).none()) && (keyWrd ==
"JOINT") ){
272 skeleton->
addJoint(currentParent, newJoint);
274 jointInfos[newJoint]=info;
275 currentParent = newJoint;
277 waitingFor = OPENED_BRACKET;
282 if ( (!(waitingFor&OFFSET).none()) && (keyWrd ==
"OFFSET") ){
286 stream >> translation[0];
287 stream >> translation[1];
288 stream >> translation[2];
296 if ( (!(waitingFor&CHANNELS).none()) && (keyWrd ==
"CHANNELS") ){
299 stream >> channelCount;
301 JointInfo& info=jointInfos[ currentParent ];
304 std::cerr <<
"Error: channel count to big, will crash very soon" << std::endl;
306 for (uint i=0; i < channelCount; i++){
307 std::string channelType;
308 stream >> channelType;
311 if (channelType ==
"Xposition")
312 info.dataChannels[info.channelOffset]=XP;
313 else if (channelType ==
"Yposition")
314 info.dataChannels[info.channelOffset]=YP;
315 else if (channelType ==
"Zposition")
316 info.dataChannels[info.channelOffset]=ZP;
317 else if (channelType ==
"Xrotation")
318 info.dataChannels[info.channelOffset]=XR;
319 else if (channelType ==
"Yrotation")
320 info.dataChannels[info.channelOffset]=YR;
321 else if (channelType ==
"Zrotation")
322 info.dataChannels[info.channelOffset]=ZR;
324 {std::cerr <<
"Error: Unknown channelType. Ignoring." << std::endl;}
326 if(info.dataChannels[info.channelOffset]!=NotGiven){
327 info.dataOffset[info.channelOffset]=dataOffset;
328 info.channelOffset++;
336 if ( (!(waitingFor&ENDSITE).none()) && (keyWrd ==
"End") ){
341 std::string
name =
"End";
344 skeleton->
addJoint(currentParent, newJoint);
345 currentParent = newJoint;
347 waitingFor = OPENED_BRACKET;
352 if ( (waitingFor == MOTION) && (keyWrd ==
"MOTION") ){
358 if ( (waitingFor == FRAMES) && (keyWrd ==
"Frames:") ){
360 stream >> frameCount;
364 animHandle = skeleton->addAnimation(object->
filename().toStdString(), animation);
367 waitingFor = FRAME_TIME;
372 if ( (waitingFor == FRAME_TIME) && (keyWrd ==
"Frame") ){
381 skeleton->
animation(animHandle)->setFps( frameTime * 1000 );
383 waitingFor = CHANNEL_DATA;
388 if ( (waitingFor == CHANNEL_DATA) ){
391 std::vector<double> data(dataOffset,0.0);
395 if ( currentFrame < frameCount ){
396 animHandle.
setFrame( currentFrame );
397 pose = skeleton->
pose(animHandle);
400 std::cerr <<
"Warning: Too many frames specified in file." << std::endl;
404 data[0] = QString( keyWrd.c_str() ).toDouble();
406 for (uint i=1; i < data.size(); i++){
413 if ( currentFrame < frameCount )
414 for (
unsigned long jointID=0; jointID < skeleton->
jointCount(); jointID++ ){
420 if ( jointInfos.find(joint) == jointInfos.end() ){
435 if(info.dataChannels[i]==NotGiven)
break;
437 double val=data[info.dataOffset[i]];
439 switch(info.dataChannels[i]){
440 case XP: translation[0]=val;
break;
441 case YP: translation[1]=val;
break;
442 case ZP: translation[2]=val;
break;
443 case XR: matRot.
rotateX(val);
break;
444 case YR: matRot.
rotateY(val);
break;
445 case ZR: matRot.
rotateZ(val);
break;
453 if ( (!ignoreJointScaling_) ||
467 std::cerr <<
"Error: No match for keyword '" << keyWrd <<
"' ";
468 std::cerr <<
"waiting for : " << waitingFor.to_string<char,std::char_traits<char>,std::allocator<char> >() << std::endl;
475 emit openedFile( object->
id() );
482 bool FileBVHPlugin::saveObject(
int _id, QString _filename)
490 std::string filename = std::string( _filename.toUtf8() );
492 std::fstream stream( filename.c_str(), std::ios_base::out );
495 emit log(
LOGERR, tr(
"saveObject : cannot not open file %1").arg(_filename) );
496 QFile( QString(filename.c_str()) ).remove();
503 object->setFromFileName(_filename);
504 object->setName(object->
filename());
508 if ( writeSkeleton( stream, *skeleton ) ){
510 emit log(
LOGINFO, tr(
"Saved object to ") + _filename );
516 emit log(
LOGERR, tr(
"Unable to save ") + _filename);
518 QFile( QString(filename.c_str()) ).remove();
524 emit log(
LOGERR, tr(
"Unable to save (object is not a skeleton)"));
526 QFile( QString(filename.c_str()) ).remove();
537 if(_matrix(1,0) > 0.998) {
538 v[0] = atan2(_matrix(0,2), _matrix(2,2));
544 if(_matrix(1,0) < -0.998) {
545 v[0] = atan2(_matrix(0,2), _matrix(2,2));
551 v[0] = atan2(-_matrix(2,0), _matrix(0,0));
552 v[1] = atan2(-_matrix(1,2), _matrix(1,1));
553 v[2] = asin(_matrix(1,0));
559 bool FileBVHPlugin::writeSkeleton( std::ostream& _out,
Skeleton& _skeleton ) {
563 _out <<
"HIERARCHY" << std::endl;
565 std::string indent =
"";
573 while ( (*it)->parent() != lastJoint ){
574 indent = indent.substr(0, indent.size()-1);
575 _out << indent <<
"}" << std::endl;
577 lastJoint = lastJoint->
parent();
582 if ( (*it)->parent() == 0 ){
584 _out <<
"ROOT " << (*it)->name() << std::endl;
588 }
else if ( (*it)->size() > 0 ){
591 _out << indent <<
"JOINT " << (*it)->name() << std::endl;
598 _out << indent <<
"End Site" << std::endl;
603 _out << indent <<
"{" << std::endl;
606 _out << indent <<
"OFFSET " << translation[0] <<
" " << translation[1] <<
" " << translation[2] << std::endl;
608 if ( (*it)->size() > 0 ){
610 if ( (*it)->parent() == 0)
611 _out << indent <<
"CHANNELS 6 Xposition Yposition Zposition Zrotation Yrotation Xrotation" << std::endl;
613 _out << indent <<
"CHANNELS 3 Zrotation Yrotation Xrotation" << std::endl;
618 indent = indent.substr(0, indent.size()-1);
619 _out << indent <<
"}" << std::endl;
620 lastJoint = (*it)->
parent();
625 while ( lastJoint->
parent() != 0 ){
626 indent = indent.substr(0, indent.size()-1);
627 _out << indent <<
"}" << std::endl;
629 lastJoint = lastJoint->
parent();
631 _out <<
"}" << std::endl;
641 if (animation->name() ==
"")
651 _out <<
"MOTION" << std::endl;
652 _out <<
"Frames: 0" << std::endl;
653 _out <<
"Frame Time: 0.1" << std::endl;
658 _out <<
"MOTION" << std::endl;
659 _out <<
"Frames: " << animation->frameCount() << std::endl;
660 _out <<
"Frame Time: " << animation->fps() / 1000.0 << std::endl;
667 for(
unsigned long k = 0; k < animation->frameCount(); ++k)
677 if ( (*it)->size() == 0)
680 if ( (*it)->parent() == 0 ){
684 _out << translation[0] <<
" " << translation[1] <<
" " << translation[2];
689 ACG::Vec3d angles = convertToAxisRotation(rotMat);
691 _out <<
" " << angles[2] <<
" " << angles[1] <<
" " << angles[0];
732 matrix(0,0) = 1.0f - 2.0f * (y * y +z * z);
733 matrix(0,1) = 2.0f * (x * y +z * w);
734 matrix(0,2) = 2.0f * (z * x -y * w);
736 matrix(1,0) = 2.0f * (x * y -z * w);
737 matrix(1,1) = 1.0f - 2.0f * (z * z +x * x);
738 matrix(1,2) = 2.0f * (y * z +x * w);
740 matrix(2,0) = 2.0f * (z * x +y * w);
741 matrix(2,1) = 2.0f * (y * z -x * w);
742 matrix(2,2) = 1.0f - 2.0f * (y * y +x * x);
747 double cosY = sqrt(matrix(0,0)*matrix(0,0)+matrix(1,0)*matrix(1,0));
751 if (cosY > 16 * FLT_EPSILON) {
752 result[0] = atan2( 1.0*matrix(2,1), matrix(2,2));
753 result[1] = atan2(-1.0*matrix(2,0), cosY);
754 result[2] = atan2( 1.0*matrix(1,0), matrix(0,0));
756 result[0] = atan2(-1.0*matrix(1,2), matrix(1,1));
757 result[1] = atan2(-1.0*matrix(2,0), cosY);
762 result[0] *= 180/M_PI;
763 result[1] *= 180/M_PI;
764 result[2] *= 180/M_PI;
779 if (loadOptions_ == 0){
781 loadOptions_ =
new QWidget();
782 QVBoxLayout* layout =
new QVBoxLayout();
783 layout->setAlignment(Qt::AlignTop);
785 checkJointScaling_ =
new QCheckBox(
"Ignore Joint Scaling");
786 layout->addWidget(checkJointScaling_);
788 loadDefaultButton_ =
new QPushButton(
"Make Default");
789 layout->addWidget(loadDefaultButton_);
791 loadOptions_->setLayout(layout);
793 connect(loadDefaultButton_, SIGNAL(clicked()),
this, SLOT(
slotLoadDefault()));
795 checkJointScaling_->setChecked(
OpenFlipperSettings().value(
"FileBVH/Load/JointScaling",
true).toBool() );
811 #if QT_VERSION < 0x050000
DLLEXPORT OpenFlipperQSettings & OpenFlipperSettings()
QSettings object containing all program settings of OpenFlipper.
QString name()
Return a name for the plugin.
void addJoint(typename SkeletonT< PointT >::Joint *_pParent, typename SkeletonT< PointT >::Joint *_pJoint)
Adds a joint as child of a given parent joint.
QString filename() const
return the filename of the object
QWidget * saveOptionsWidget(QString)
const UpdateType UPDATE_ALL(UpdateTypeSet(1))
Identifier for all updates.
bool getObject(int _identifier, BSplineCurveObject *&_object)
Pose * pose(const AnimationHandle &_hAni)
Returns a pointer to the pose with the given animation handle.
std::string name()
Access the name of the joint.
Pose * referencePose()
Returns a pointer to the reference pose.
Animation * animation(std::string _name)
Returns a pointer to the animation to the given name.
A general pose, used to store the frames of the animation.
unsigned int jointCount()
Returns the number of joints.
QWidget * loadOptionsWidget(QString)
Iterator end()
Compare an iterator with the return value of this method to test if it is done.
Iterator class for the skeleton.
bool dataType(DataType _type) const
Joint * joint(const unsigned int &_index)
Returns the joint with the given index.
AnimationHandle animationHandle(std::string _name)
Get an AnimationHandle to the animation with the given name.
void rotateZ(Scalar _angle, MultiplyFrom _mult_from=MULT_FROM_RIGHT)
multiply self with a rotation matrix (angle in degree, z-axis)
void translate(Scalar _x, Scalar _y, Scalar _z, MultiplyFrom _mult_from=MULT_FROM_RIGHT)
multiply self with translation matrix (x,y,z)
Iterator begin()
Iterator over joints of the skeletal tree in TOP-DOWN order (from root to leafs)
const Matrix & localMatrix(unsigned int _joint) const
Returns the local matrix for the given joint.
void initializePlugin()
Initialize Plugin.
void rotateX(Scalar _angle, MultiplyFrom _mult_from=MULT_FROM_RIGHT)
multiply self with a rotation matrix (angle in degree, x-axis)
Joint * parent()
Returns the parent joint.
unsigned int animationCount()
Returns the number of animations stored in this skeleton.
void setLocalTranslation(unsigned int _joint, const Vector &_position, bool _keepLocalChildPositions=true)
Sets the local translation vector.
DataType supportedType()
Return your supported object type( e.g. DATA_TRIANGLE_MESH )
int loadObject(QString _filename)
Loads Object.
Vector globalTranslation(unsigned int _joint)
Returns the global translation vector.
void rotateY(Scalar _angle, MultiplyFrom _mult_from=MULT_FROM_RIGHT)
multiply self with a rotation matrix (angle in degree, y-axis)
Matrix localMatrixInv(unsigned int _joint) const
Simply returns the inverse of the local matrix.
Functions for geometric operations related to angles.
void identity()
setup an identity matrix
void setLocalMatrix(unsigned int _joint, const Matrix &_local, bool _keepLocalChildPositions=true)
Sets the local coordinate system.
unsigned int id()
returns the joint id
QVariant value(const QString &key, const QVariant &defaultValue=QVariant()) const
A handle used to refer to an animation or to a specific frame in an animation.
FileBVHPlugin()
Constructor.
int objectCount()
Get the number of available objects.
void transpose()
transpose matrix
void slotLoadDefault()
Slot called when user wants to save the given Load options as default.
void setFrame(unsigned int _iFrame)
Sets the current animation frame (not failsafe)
void setValue(const QString &key, const QVariant &value)
Wrapper function which makes it possible to enable Debugging output with -DOPENFLIPPER_SETTINGS_DEBUG...
const std::string & animationName(unsigned int _index)
Returns the name of the animation with the given index.
Skeleton * skeleton(BaseObjectData *_object)
Get a skeleton from an object.
Represents a single joint in the skeleton.