59 const std::bitset<4> HIERARCHY (static_cast<int>(0));
60 const std::bitset<4> ROOT_DEFINITION (static_cast<int>(1));
61 const std::bitset<4> OPENED_BRACKET (static_cast<int>(2));
62 const std::bitset<4> CLOSED_BRACKET (static_cast<int>(3));
63 const std::bitset<4> OFFSET (static_cast<int>(4));
64 const std::bitset<4> CHANNELS (static_cast<int>(5));
65 const std::bitset<4> JOINT (static_cast<int>(6));
66 const std::bitset<4> ENDSITE (static_cast<int>(7));
67 const std::bitset<4> MOTION (static_cast<int>(8));
68 const std::bitset<4> FRAMES (static_cast<int>(9));
69 const std::bitset<4> FRAME_TIME (static_cast<int>(10));
70 const std::bitset<4> CHANNEL_DATA (static_cast<int>(11));
74 enum ChannelType{NotGiven,XP,YP,ZP,XR,YR,ZR};
78 ChannelType dataChannels[6];
79 unsigned int dataOffset[6];
81 unsigned int channelOffset;
88 dataChannels[i]=NotGiven;
101 : ignoreJointScaling_(true),
103 checkJointScaling_(0),
104 loadDefaultButton_(0)
116 return QString( tr(
"Biovision Format files ( *.bvh )") );
122 return QString( tr(
"Biovision Format files ( *.bvh )") );
134 void trimString( std::string& _string) {
137 size_t start = _string.find_first_not_of(
" \t\r\n");
138 size_t end = _string.find_last_not_of(
" \t\r\n");
140 if(( std::string::npos == start ) || ( std::string::npos == end))
143 _string = _string.substr( start, end-start+1 );
150 if ( checkJointScaling_ != 0 )
151 ignoreJointScaling_ = checkJointScaling_->isChecked();
157 std::fstream input( _filename.toUtf8(), std::ios_base::in );
159 if ( !input.is_open() || !input.good() ){
160 emit log(
LOGERR, tr(
"Error: cannot open file %1").arg(_filename) );
173 object->setFromFileName(_filename);
174 object->setName(object->
filename());
178 emit log(
LOGERR, tr(
"Error: Unable to add skeleton!"));
188 std::bitset<4> waitingFor = HIERARCHY;
190 std::map< Skeleton::Joint* , JointInfo> jointInfos;
195 uint currentFrame = 0;
198 while( input && !input.eof() )
200 std::getline(input,line);
202 emit log(
LOGERR, tr(
"Error: could not read file properly!"));
210 if ( line.size() == 0 )
213 std::stringstream stream(line);
219 if ( (waitingFor == HIERARCHY) && (keyWrd ==
"HIERARCHY") ){
220 waitingFor = ROOT_DEFINITION;
225 if ( (waitingFor == ROOT_DEFINITION) && (keyWrd ==
"ROOT") ){
233 jointInfos[rootJoint]=info;
234 currentParent = rootJoint;
236 waitingFor = OPENED_BRACKET;
241 if ( (waitingFor == OPENED_BRACKET) && (keyWrd ==
"{") ){
243 waitingFor = OFFSET | CHANNELS | JOINT | ENDSITE | CLOSED_BRACKET;
249 if ( (!(waitingFor&CLOSED_BRACKET).none()) && (keyWrd ==
"}") ){
251 if ( currentParent->
parent() == 0 )
254 waitingFor = JOINT | CLOSED_BRACKET;
257 currentParent = currentParent->
parent();
262 if ( (!(waitingFor&JOINT).none()) && (keyWrd ==
"JOINT") ){
268 skeleton->
addJoint(currentParent, newJoint);
270 jointInfos[newJoint]=info;
271 currentParent = newJoint;
273 waitingFor = OPENED_BRACKET;
278 if ( (!(waitingFor&OFFSET).none()) && (keyWrd ==
"OFFSET") ){
282 stream >> translation[0];
283 stream >> translation[1];
284 stream >> translation[2];
292 if ( (!(waitingFor&CHANNELS).none()) && (keyWrd ==
"CHANNELS") ){
295 stream >> channelCount;
297 JointInfo& info=jointInfos[ currentParent ];
300 std::cerr <<
"Error: channel count to big, will crash very soon" << std::endl;
302 for (uint i=0; i < channelCount; i++){
303 std::string channelType;
304 stream >> channelType;
307 if (channelType ==
"Xposition")
308 info.dataChannels[info.channelOffset]=XP;
309 else if (channelType ==
"Yposition")
310 info.dataChannels[info.channelOffset]=YP;
311 else if (channelType ==
"Zposition")
312 info.dataChannels[info.channelOffset]=ZP;
313 else if (channelType ==
"Xrotation")
314 info.dataChannels[info.channelOffset]=XR;
315 else if (channelType ==
"Yrotation")
316 info.dataChannels[info.channelOffset]=YR;
317 else if (channelType ==
"Zrotation")
318 info.dataChannels[info.channelOffset]=ZR;
320 {std::cerr <<
"Error: Unknown channelType. Ignoring." << std::endl;}
322 if(info.dataChannels[info.channelOffset]!=NotGiven){
323 info.dataOffset[info.channelOffset]=dataOffset;
324 info.channelOffset++;
332 if ( (!(waitingFor&ENDSITE).none()) && (keyWrd ==
"End") ){
337 std::string
name =
"End";
340 skeleton->
addJoint(currentParent, newJoint);
341 currentParent = newJoint;
343 waitingFor = OPENED_BRACKET;
348 if ( (waitingFor == MOTION) && (keyWrd ==
"MOTION") ){
354 if ( (waitingFor == FRAMES) && (keyWrd ==
"Frames:") ){
356 stream >> frameCount;
360 animHandle = skeleton->addAnimation(object->
filename().toStdString(), animation);
363 waitingFor = FRAME_TIME;
368 if ( (waitingFor == FRAME_TIME) && (keyWrd ==
"Frame") ){
377 skeleton->
animation(animHandle)->setFps( frameTime * 1000 );
379 waitingFor = CHANNEL_DATA;
384 if ( (waitingFor == CHANNEL_DATA) ){
387 std::vector<double> data(dataOffset,0.0);
391 if ( currentFrame < frameCount ){
392 animHandle.
setFrame( currentFrame );
393 pose = skeleton->
pose(animHandle);
396 std::cerr <<
"Warning: Too many frames specified in file." << std::endl;
400 data[0] = QString( keyWrd.c_str() ).toDouble();
402 for (uint i=1; i < data.size(); i++){
409 if ( currentFrame < frameCount )
410 for (
unsigned long jointID=0; jointID < skeleton->
jointCount(); jointID++ ){
416 if ( jointInfos.find(joint) == jointInfos.end() ){
431 if(info.dataChannels[i]==NotGiven)
break;
433 double val=data[info.dataOffset[i]];
435 switch(info.dataChannels[i]){
436 case XP: translation[0]=val;
break;
437 case YP: translation[1]=val;
break;
438 case ZP: translation[2]=val;
break;
439 case XR: matRot.
rotateX(val);
break;
440 case YR: matRot.
rotateY(val);
break;
441 case ZR: matRot.
rotateZ(val);
break;
449 if ( (!ignoreJointScaling_) ||
463 std::cerr <<
"Error: No match for keyword '" << keyWrd <<
"' ";
464 std::cerr <<
"waiting for : " << waitingFor.to_string<char,std::char_traits<char>,std::allocator<char> >() << std::endl;
471 emit openedFile( object->
id() );
478 bool FileBVHPlugin::saveObject(
int _id, QString _filename)
486 std::string filename = std::string( _filename.toUtf8() );
488 std::fstream stream( filename.c_str(), std::ios_base::out );
491 emit log(
LOGERR, tr(
"saveObject : cannot not open file %1").arg(_filename) );
492 QFile( QString(filename.c_str()) ).remove();
499 object->setFromFileName(_filename);
500 object->setName(object->
filename());
504 if ( writeSkeleton( stream, *skeleton ) ){
506 emit log(
LOGINFO, tr(
"Saved object to ") + _filename );
512 emit log(
LOGERR, tr(
"Unable to save ") + _filename);
514 QFile( QString(filename.c_str()) ).remove();
520 emit log(
LOGERR, tr(
"Unable to save (object is not a skeleton)"));
522 QFile( QString(filename.c_str()) ).remove();
533 if(_matrix(1,0) > 0.998) {
534 v[0] = atan2(_matrix(0,2), _matrix(2,2));
540 if(_matrix(1,0) < -0.998) {
541 v[0] = atan2(_matrix(0,2), _matrix(2,2));
547 v[0] = atan2(-_matrix(2,0), _matrix(0,0));
548 v[1] = atan2(-_matrix(1,2), _matrix(1,1));
549 v[2] = asin(_matrix(1,0));
555 bool FileBVHPlugin::writeSkeleton( std::ostream& _out,
Skeleton& _skeleton ) {
559 _out <<
"HIERARCHY" << std::endl;
561 std::string indent =
"";
569 while ( (*it)->parent() != lastJoint ){
570 indent = indent.substr(0, indent.size()-1);
571 _out << indent <<
"}" << std::endl;
573 lastJoint = lastJoint->
parent();
578 if ( (*it)->parent() == 0 ){
580 _out <<
"ROOT " << (*it)->name() << std::endl;
584 }
else if ( (*it)->size() > 0 ){
587 _out << indent <<
"JOINT " << (*it)->name() << std::endl;
594 _out << indent <<
"End Site" << std::endl;
599 _out << indent <<
"{" << std::endl;
602 _out << indent <<
"OFFSET " << translation[0] <<
" " << translation[1] <<
" " << translation[2] << std::endl;
604 if ( (*it)->size() > 0 ){
606 if ( (*it)->parent() == 0)
607 _out << indent <<
"CHANNELS 6 Xposition Yposition Zposition Zrotation Yrotation Xrotation" << std::endl;
609 _out << indent <<
"CHANNELS 3 Zrotation Yrotation Xrotation" << std::endl;
614 indent = indent.substr(0, indent.size()-1);
615 _out << indent <<
"}" << std::endl;
616 lastJoint = (*it)->
parent();
621 while ( lastJoint->
parent() != 0 ){
622 indent = indent.substr(0, indent.size()-1);
623 _out << indent <<
"}" << std::endl;
625 lastJoint = lastJoint->
parent();
627 _out <<
"}" << std::endl;
637 if (animation->name() ==
"")
647 _out <<
"MOTION" << std::endl;
648 _out <<
"Frames: 0" << std::endl;
649 _out <<
"Frame Time: 0.1" << std::endl;
654 _out <<
"MOTION" << std::endl;
655 _out <<
"Frames: " << animation->frameCount() << std::endl;
656 _out <<
"Frame Time: " << animation->fps() / 1000.0 << std::endl;
663 for(
unsigned long k = 0; k < animation->frameCount(); ++k)
673 if ( (*it)->size() == 0)
676 if ( (*it)->parent() == 0 ){
680 _out << translation[0] <<
" " << translation[1] <<
" " << translation[2];
685 ACG::Vec3d angles = convertToAxisRotation(rotMat);
687 _out <<
" " << angles[2] <<
" " << angles[1] <<
" " << angles[0];
728 matrix(0,0) = 1.0f - 2.0f * (y * y +z * z);
729 matrix(0,1) = 2.0f * (x * y +z * w);
730 matrix(0,2) = 2.0f * (z * x -y * w);
732 matrix(1,0) = 2.0f * (x * y -z * w);
733 matrix(1,1) = 1.0f - 2.0f * (z * z +x * x);
734 matrix(1,2) = 2.0f * (y * z +x * w);
736 matrix(2,0) = 2.0f * (z * x +y * w);
737 matrix(2,1) = 2.0f * (y * z -x * w);
738 matrix(2,2) = 1.0f - 2.0f * (y * y +x * x);
743 double cosY = sqrt(matrix(0,0)*matrix(0,0)+matrix(1,0)*matrix(1,0));
747 if (cosY > 16 * FLT_EPSILON) {
748 result[0] = atan2( 1.0*matrix(2,1), matrix(2,2));
749 result[1] = atan2(-1.0*matrix(2,0), cosY);
750 result[2] = atan2( 1.0*matrix(1,0), matrix(0,0));
752 result[0] = atan2(-1.0*matrix(1,2), matrix(1,1));
753 result[1] = atan2(-1.0*matrix(2,0), cosY);
758 result[0] *= 180/M_PI;
759 result[1] *= 180/M_PI;
760 result[2] *= 180/M_PI;
775 if (loadOptions_ == 0){
777 loadOptions_ =
new QWidget();
778 QVBoxLayout* layout =
new QVBoxLayout();
779 layout->setAlignment(Qt::AlignTop);
781 checkJointScaling_ =
new QCheckBox(
"Ignore Joint Scaling");
782 layout->addWidget(checkJointScaling_);
784 loadDefaultButton_ =
new QPushButton(
"Make Default");
785 layout->addWidget(loadDefaultButton_);
787 loadOptions_->setLayout(layout);
789 connect(loadDefaultButton_, SIGNAL(clicked()),
this, SLOT(
slotLoadDefault()));
791 checkJointScaling_->setChecked(
OpenFlipperSettings().value(
"FileBVH/Load/JointScaling",
true).toBool() );
DLLEXPORT OpenFlipperQSettings & OpenFlipperSettings()
QSettings object containing all program settings of OpenFlipper.
void setLocalMatrix(unsigned int _joint, const Matrix &_local, bool _keepLocalChildPositions=true)
Sets the local coordinate system.
const UpdateType UPDATE_ALL(UpdateTypeSet(1))
Identifier for all updates.
int loadObject(QString _filename)
Loads Object.
Vector globalTranslation(unsigned int _joint)
Returns the global translation vector.
void slotLoadDefault()
Slot called when user wants to save the given Load options as default.
Functions for geometric operations related to angles.
const Matrix & localMatrix(unsigned int _joint) const
Returns the local matrix for the given joint.
QWidget * loadOptionsWidget(QString)
Skeleton * skeleton(BaseObjectData *_object)
Get a skeleton from an object.
std::string name() const
Access the name of the joint.
Matrix localMatrixInv(unsigned int _joint) const
Simply returns the inverse of the local matrix.
void setValue(const QString &key, const QVariant &value)
Wrapper function which makes it possible to enable Debugging output with -DOPENFLIPPER_SETTINGS_DEBUG...
bool dataType(DataType _type) const
A general pose, used to store the frames of the animation.
DataType supportedType()
Return your supported object type( e.g. DATA_TRIANGLE_MESH )
QString name()
Return a name for the plugin.
void transpose()
transpose matrix
size_t animationCount()
Returns the number of animations stored in this skeleton.
Iterator class for the skeleton.
Iterator end()
Compare an iterator with the return value of this method to test if it is done.
const std::string & animationName(size_t _index)
Returns the name of the animation with the given index.
void rotateZ(Scalar _angle, MultiplyFrom _mult_from=MULT_FROM_RIGHT)
multiply self with a rotation matrix (angle in degree, z-axis)
bool getObject(const int _identifier, BaseObject *&_object)
Get the object which has the given identifier.
A handle used to refer to an animation or to a specific frame in an animation.
Joint * parent()
Returns the parent joint.
Pose * referencePose()
Returns a pointer to the reference pose.
QString filename() const
return the filename of the object
void rotateY(Scalar _angle, MultiplyFrom _mult_from=MULT_FROM_RIGHT)
multiply self with a rotation matrix (angle in degree, y-axis)
Iterator begin()
Iterator over joints of the skeletal tree in TOP-DOWN order (from root to leafs)
void setLocalTranslation(unsigned int _joint, const Vector &_position, bool _keepLocalChildPositions=true)
Sets the local translation vector.
Pose * pose(const AnimationHandle &_hAni)
Returns a pointer to the pose with the given animation handle.
Represents a single joint in the skeleton.
void initializePlugin()
Initialize Plugin.
QWidget * saveOptionsWidget(QString)
QVariant value(const QString &key, const QVariant &defaultValue=QVariant()) const
void rotateX(Scalar _angle, MultiplyFrom _mult_from=MULT_FROM_RIGHT)
multiply self with a rotation matrix (angle in degree, x-axis)
AnimationHandle animationHandle(std::string _name)
Get an AnimationHandle to the animation with the given name.
void identity()
setup an identity matrix
size_t jointCount()
Returns the number of joints.
Animation * animation(std::string _name)
Returns a pointer to the animation to the given name.
void setFrame(size_t _iFrame)
Sets the current animation frame (not failsafe)
Joint * joint(const size_t &_index)
Returns the joint with the given index.
int objectCount()
Get the number of available objects.
FileBVHPlugin()
Constructor.
void addJoint(typename SkeletonT< PointT >::Joint *_pParent, typename SkeletonT< PointT >::Joint *_pJoint)
Adds a joint as child of a given parent joint.
void translate(Scalar _x, Scalar _y, Scalar _z, MultiplyFrom _mult_from=MULT_FROM_RIGHT)
multiply self with translation matrix (x,y,z)
size_t id() const
returns the joint id