Developer Documentation
FileBVH.cc
1 /*===========================================================================*\
2  * *
3  * OpenFlipper *
4  * Copyright (c) 2001-2015, RWTH-Aachen University *
5  * Department of Computer Graphics and Multimedia *
6  * All rights reserved. *
7  * www.openflipper.org *
8  * *
9  *---------------------------------------------------------------------------*
10  * This file is part of OpenFlipper. *
11  *---------------------------------------------------------------------------*
12  * *
13  * Redistribution and use in source and binary forms, with or without *
14  * modification, are permitted provided that the following conditions *
15  * are met: *
16  * *
17  * 1. Redistributions of source code must retain the above copyright notice, *
18  * this list of conditions and the following disclaimer. *
19  * *
20  * 2. Redistributions in binary form must reproduce the above copyright *
21  * notice, this list of conditions and the following disclaimer in the *
22  * documentation and/or other materials provided with the distribution. *
23  * *
24  * 3. Neither the name of the copyright holder nor the names of its *
25  * contributors may be used to endorse or promote products derived from *
26  * this software without specific prior written permission. *
27  * *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39  * *
40 \*===========================================================================*/
41 
42 #ifdef _MSC_VER
43  #if (_MSC_VER <= 1916)
44  #define QT_NO_FLOAT16_OPERATORS
45  #endif
46 #endif
47 
48 #include "FileBVH.hh"
50 
51 #include <QtWidgets>
52 
53 #include <sstream>
54 
56 
57 const std::bitset<4> HIERARCHY (static_cast<int>(0));
58 const std::bitset<4> ROOT_DEFINITION (static_cast<int>(1));
59 const std::bitset<4> OPENED_BRACKET (static_cast<int>(2));
60 const std::bitset<4> CLOSED_BRACKET (static_cast<int>(3));
61 const std::bitset<4> OFFSET (static_cast<int>(4));
62 const std::bitset<4> CHANNELS (static_cast<int>(5));
63 const std::bitset<4> JOINT (static_cast<int>(6));
64 const std::bitset<4> ENDSITE (static_cast<int>(7));
65 const std::bitset<4> MOTION (static_cast<int>(8));
66 const std::bitset<4> FRAMES (static_cast<int>(9));
67 const std::bitset<4> FRAME_TIME (static_cast<int>(10));
68 const std::bitset<4> CHANNEL_DATA (static_cast<int>(11));
69 
70 //-----------------------------------------------------------------------------
71 //data structures used for parsing
72 enum ChannelType{NotGiven,XP,YP,ZP,XR,YR,ZR}; //contains the informations about the use of this datafield
73 
74 class JointInfo{ //for every Joint we will create one such instance during Hirachy parsing. It will contain the informations needed to generate the Transformation from the frame values
75  public:
76  ChannelType dataChannels[6]; //will state which channels information is stored in the current datafields value.
77  unsigned int dataOffset[6]; //will contain the index of the channel in the frame data
78 
79  unsigned int channelOffset; //used top keep track of the highest channel currently used
80 
81  //constructor
82  //will set proper default values (as the dataChannels will only be written if an according option is found in the file)
83  JointInfo(){
84  channelOffset=0; //we assign the first channelType to the first entry
85  for(int i=0;i<6;i++){ //all channels that are not overwritten are Unused
86  dataChannels[i]=NotGiven;
87  dataOffset[i]=0;
88  }
89  } //end ctor()
90 }; //end class
91 
92 //end of data structure
93 //-----------------------------------------------------------------------------
94 
95 
96 
99  : ignoreJointScaling_(true),
100  loadOptions_(0),
101  checkJointScaling_(0),
102  loadDefaultButton_(0)
103 {
104 }
105 
106 //-----------------------------------------------------------------------------------------------------
107 
109 }
110 
111 //-----------------------------------------------------------------------------------------------------
112 
114  return QString( tr("Biovision Format files ( *.bvh )") );
115 }
116 
117 //-----------------------------------------------------------------------------------------------------
118 
120  return QString( tr("Biovision Format files ( *.bvh )") );
121 }
122 
123 //-----------------------------------------------------------------------------------------------------
124 
126  DataType type = DATA_SKELETON;
127  return type;
128 }
129 
130 //-----------------------------------------------------------------------------------------------------
131 
132 void trimString( std::string& _string) {
133  // Trim Both leading and trailing spaces
134 
135  size_t start = _string.find_first_not_of(" \t\r\n");
136  size_t end = _string.find_last_not_of(" \t\r\n");
137 
138  if(( std::string::npos == start ) || ( std::string::npos == end))
139  _string = "";
140  else
141  _string = _string.substr( start, end-start+1 );
142 }
143 
144 //-----------------------------------------------------------------------------------------------------
145 
146 int FileBVHPlugin::loadObject(QString _filename) {
147 
148  if ( checkJointScaling_ != 0 )
149  ignoreJointScaling_ = checkJointScaling_->isChecked();
150  else
151  ignoreJointScaling_ = OpenFlipperSettings().value("FileBVH/Load/JointScaling",true).toBool();
152 
153  //setup filestream
154 
155  std::fstream input( _filename.toUtf8(), std::ios_base::in );
156 
157  if ( !input.is_open() || !input.good() ){
158  emit log(LOGERR, tr("Error: cannot open file %1").arg(_filename) );
159  return -1;
160  }
161 
162  //add a skeleton
163  int id = -1;
164  emit addEmptyObject(DATA_SKELETON, id);
165 
166  BaseObjectData* object = 0;
167  Skeleton* skeleton = 0;
168 
169  if(PluginFunctions::getObject( id, object)){
170  skeleton = PluginFunctions::skeleton( object );
171  object->setFromFileName(_filename);
172  object->setName(object->filename());
173  }
174 
175  if (skeleton == 0){
176  emit log(LOGERR, tr("Error: Unable to add skeleton!"));
177  return -1;
178  }
179 
180  Skeleton::Joint* currentParent = 0;
181  Skeleton::Pose* refPose = skeleton->referencePose();
182 
183 
184  std::string line;
185  std::string keyWrd;
186  std::bitset<4> waitingFor = HIERARCHY;
187 
188  std::map< Skeleton::Joint* , JointInfo> jointInfos;
189 
190  uint dataOffset = 0; //Offset of the current channel in the frame data
191 
192  AnimationHandle animHandle;
193  uint currentFrame = 0;
194  uint frameCount = 0;
195 
196  while( input && !input.eof() )
197  {
198  std::getline(input,line);
199  if ( input.bad() ){
200  emit log(LOGERR, tr("Error: could not read file properly!"));
201  return -1;
202  }
203 
204  // Trim Both leading and trailing spaces
205  trimString(line);
206 
207  // ignore empty lines
208  if ( line.size() == 0 )
209  continue;
210 
211  std::stringstream stream(line);
212 
213  //read keyword from stream
214  stream >> keyWrd;
215 
216  //HIERARCHY
217  if ( (waitingFor == HIERARCHY) && (keyWrd == "HIERARCHY") ){
218  waitingFor = ROOT_DEFINITION;
219  continue;
220  }
221 
222  //ROOT_DEFINITION
223  if ( (waitingFor == ROOT_DEFINITION) && (keyWrd == "ROOT") ){
224 
225  std::string name;
226  stream >> name;
227 
228  Skeleton::Joint* rootJoint = new Skeleton::Joint(0, name);
229  skeleton->addJoint(0, rootJoint);
230  JointInfo info; //we found a new Joint, hence we need an ne JointInfo to store the channel inforamtions.
231  jointInfos[rootJoint]=info; //store Joint info for later use in case of CHANNELS
232  currentParent = rootJoint;
233 
234  waitingFor = OPENED_BRACKET;
235  continue;
236  }
237 
238  //OPENED_BRACKET
239  if ( (waitingFor == OPENED_BRACKET) && (keyWrd == "{") ){
240 
241  waitingFor = OFFSET | CHANNELS | JOINT | ENDSITE | CLOSED_BRACKET;
242 
243  continue;
244  }
245 
246  //CLOSED_BRACKET
247  if ( (!(waitingFor&CLOSED_BRACKET).none()) && (keyWrd == "}") ){
248 
249  if ( currentParent->parent() == 0 )
250  waitingFor = MOTION;
251  else{
252  waitingFor = JOINT | CLOSED_BRACKET;
253  }
254 
255  currentParent = currentParent->parent();
256  continue;
257  }
258 
259  //JOINT
260  if ( (!(waitingFor&JOINT).none()) && (keyWrd == "JOINT") ){
261 
262  std::string name;
263  stream >> name;
264 
265  Skeleton::Joint* newJoint = new Skeleton::Joint(currentParent, name);
266  skeleton->addJoint(currentParent, newJoint);
267  JointInfo info; //we found a new Joint, hence we need an ne JointInfo to store the channel inforamtions.
268  jointInfos[newJoint]=info; //store Joint info for later use in case of CHANNELS
269  currentParent = newJoint;
270 
271  waitingFor = OPENED_BRACKET;
272  continue;
273  }
274 
275  //OFFSET
276  if ( (!(waitingFor&OFFSET).none()) && (keyWrd == "OFFSET") ){
277 
278  ACG::Vec3d translation;
279 
280  stream >> translation[0];
281  stream >> translation[1];
282  stream >> translation[2];
283 
284  refPose->setLocalTranslation(currentParent->id(), translation );
285 
286  continue;
287  }
288 
289  //CHANNELS
290  if ( (!(waitingFor&CHANNELS).none()) && (keyWrd == "CHANNELS") ){
291 
292  uint channelCount;
293  stream >> channelCount;
294 
295  JointInfo& info=jointInfos[ currentParent ];
296 
297  if(channelCount>6) //well somethings wrong here...
298  std::cerr << "Error: channel count to big, will crash very soon" << std::endl;
299 
300  for (uint i=0; i < channelCount; i++){ //parse channel informations
301  std::string channelType;
302  stream >> channelType;
303 
304  //extract Channel position info and store in info.dataChannels
305  if (channelType == "Xposition")
306  info.dataChannels[info.channelOffset]=XP;
307  else if (channelType == "Yposition")
308  info.dataChannels[info.channelOffset]=YP;
309  else if (channelType == "Zposition")
310  info.dataChannels[info.channelOffset]=ZP;
311  else if (channelType == "Xrotation")
312  info.dataChannels[info.channelOffset]=XR;
313  else if (channelType == "Yrotation")
314  info.dataChannels[info.channelOffset]=YR;
315  else if (channelType == "Zrotation")
316  info.dataChannels[info.channelOffset]=ZR;
317  else
318  {std::cerr << "Error: Unknown channelType. Ignoring." << std::endl;}
319 
320  if(info.dataChannels[info.channelOffset]!=NotGiven){ //if there is a channel assigned
321  info.dataOffset[info.channelOffset]=dataOffset; //the value for this channel will be found this data position
322  info.channelOffset++; //write next info into the next index
323  }
324  dataOffset++; // the data will be read even if there is no channel assigned to this data (e.g. unknown channel type)
325  }
326  continue;
327  }
328 
329  // ENDSITE
330  if ( (!(waitingFor&ENDSITE).none()) && (keyWrd == "End") ){
331 
332  std::string site;
333  stream >> site;
334 
335  std::string name = "End";
336 
337  Skeleton::Joint* newJoint = new Skeleton::Joint(currentParent, currentParent->name() + name);
338  skeleton->addJoint(currentParent, newJoint);
339  currentParent = newJoint;
340 
341  waitingFor = OPENED_BRACKET;
342  continue;
343  }
344 
345  //MOTION
346  if ( (waitingFor == MOTION) && (keyWrd == "MOTION") ){
347  waitingFor = FRAMES;
348  continue;
349  }
350 
351  //Frames
352  if ( (waitingFor == FRAMES) && (keyWrd == "Frames:") ){
353 
354  stream >> frameCount;
355 
356  if (frameCount > 0){
357  FrameAnimationT<ACG::Vec3d>* animation = new FrameAnimationT<ACG::Vec3d>(skeleton, frameCount);
358  animHandle = skeleton->addAnimation(object->filename().toStdString(), animation);
359  }
360 
361  waitingFor = FRAME_TIME;
362  continue;
363  }
364 
365  //Frame Time
366  if ( (waitingFor == FRAME_TIME) && (keyWrd == "Frame") ){
367 
368  std::string time;
369  stream >> time;
370 
371  double frameTime;
372  stream >> frameTime;
373 
374  if (frameCount > 0)
375  skeleton->animation(animHandle)->setFps( frameTime * 1000 );
376 
377  waitingFor = CHANNEL_DATA;
378  continue;
379  }
380 
381  //Channel Data
382  if ( (waitingFor == CHANNEL_DATA) ){
383 
384  // a vector to store all the data for this frame
385  std::vector<double> data(dataOffset,0.0);
386 
387  Skeleton::Pose* pose = 0;
388 
389  if ( currentFrame < frameCount ){
390  animHandle.setFrame( currentFrame );
391  pose = skeleton->pose(animHandle);
392  }
393  else
394  std::cerr << "Warning: Too many frames specified in file." << std::endl;
395 
396  //since we dont have a keyWrd here
397  // keyWrd is already the first data
398  data[0] = QString( keyWrd.c_str() ).toDouble();
399  //read the data for this frame
400  for (uint i=1; i < data.size(); i++){
401  stream >> data[i];
402  }
403 
404  //now the channel for this timeFrame is complete
405  //apply them to the joints
406 
407  if ( currentFrame < frameCount )
408  for (unsigned long jointID=0; jointID < skeleton->jointCount(); jointID++ ){
409 
410  Skeleton::Joint* joint = skeleton->joint( jointID );
411 
412  // special case: end-effector joints
413  // they don't have animation data
414  if ( jointInfos.find(joint) == jointInfos.end() ){
415  ACG::Matrix4x4d matRef = refPose->localMatrix(jointID);
416  pose->setLocalMatrix(jointID, matRef);
417  continue;
418  }
419 
420  JointInfo& info=jointInfos[joint]; //get the cahnnels info for the current joint
421 
422  ACG::Vec3d translation(0.0,0.0,0.0); //setup translation
423 
424  ACG::GLMatrixd matRot; //setup rotation
425  matRot.identity();
426 
427  for(int i=0;i<6;i++) //iterate over the cannels, applying the transformations in order
428  {
429  if(info.dataChannels[i]==NotGiven) break; //stop at the first empty channel
430 
431  double val=data[info.dataOffset[i]]; //read one value from the data
432 
433  switch(info.dataChannels[i]){ //apply the transformation
434  case XP: translation[0]=val; break; //translation (order doesnt matter)
435  case YP: translation[1]=val; break;
436  case ZP: translation[2]=val; break;
437  case XR: matRot.rotateX(val); break; //rotation (order does matter)
438  case YR: matRot.rotateY(val); break;
439  case ZR: matRot.rotateZ(val); break;
440  default: break; //stop at the first empty channel
441  }
442  }
443 
444  ACG::GLMatrixd matTrans;
445  matTrans.identity();
446 
447  if ( (!ignoreJointScaling_) || //translate only if there is no need to preserve the scale
448  (joint->parent() == 0) ) //or if the joint is the rootjoint
449  matTrans.translate(translation);
450 
451  ACG::Matrix4x4d matRef = refPose->localMatrix(jointID);
452  pose->setLocalMatrix(jointID, matRef * matTrans * matRot);
453  }
454 
455  currentFrame++;
456 
457  continue;
458 
459  }
460 
461  std::cerr << "Error: No match for keyword '" << keyWrd << "' ";
462  std::cerr << "waiting for : " << waitingFor.to_string<char,std::char_traits<char>,std::allocator<char> >() << std::endl;
463  }
464 
465 
466  //general stuff
467  object->source( PluginFunctions::objectCount() > 4 );
468  emit updatedObject( object->id(), UPDATE_ALL );
469  emit openedFile( object->id() );
470 
471  return object->id();
472 }
473 
474 //-----------------------------------------------------------------------------------------------------
475 
476 bool FileBVHPlugin::saveObject(int _id, QString _filename)
477 {
478 
479  BaseObjectData* object;
480  PluginFunctions::getObject(_id,object);
481 
482 
483  //open output stream
484  std::string filename = std::string( _filename.toUtf8() );
485 
486  std::fstream stream( filename.c_str(), std::ios_base::out );
487 
488  if ( !stream ){
489  emit log(LOGERR, tr("saveObject : cannot not open file %1").arg(_filename) );
490  QFile( QString(filename.c_str()) ).remove();
491  return false;
492  }
493 
494  //write object
495  if ( object->dataType( DATA_SKELETON ) ) {
496 
497  object->setFromFileName(_filename);
498  object->setName(object->filename());
499 
500  Skeleton* skeleton = PluginFunctions::skeleton(object);
501 
502  if ( writeSkeleton( stream, *skeleton ) ){
503 
504  emit log(LOGINFO, tr("Saved object to ") + _filename );
505  stream.close();
506  return true;
507 
508  } else {
509 
510  emit log(LOGERR, tr("Unable to save ") + _filename);
511  stream.close();
512  QFile( QString(filename.c_str()) ).remove();
513  return false;
514  }
515 
516  } else {
517 
518  emit log(LOGERR, tr("Unable to save (object is not a skeleton)"));
519  stream.close();
520  QFile( QString(filename.c_str()) ).remove();
521  return false;
522  }
523 }
524 
525 //-----------------------------------------------------------------------------------------------------
526 
527 
528 ACG::Vec3d MatrixToEuler(ACG::Matrix4x4d _matrix){
529  ACG::Vec3d v(0.0, 0.0, 0.0);
530 
531  if(_matrix(1,0) > 0.998) { // singularity at north pole
532  v[0] = atan2(_matrix(0,2), _matrix(2,2));
533  v[1] = M_PI / 2.0;
534  v[2] = 0;
535  return v;
536  }
537 
538  if(_matrix(1,0) < -0.998) { // singularity at south pole
539  v[0] = atan2(_matrix(0,2), _matrix(2,2));
540  v[1] = - M_PI / 2.0;
541  v[2] = 0;
542  return v;
543  }
544 
545  v[0] = atan2(-_matrix(2,0), _matrix(0,0));
546  v[1] = atan2(-_matrix(1,2), _matrix(1,1));
547  v[2] = asin(_matrix(1,0));
548  return v;
549 }
550 
551 //-----------------------------------------------------------------------------------------------------
552 
553 bool FileBVHPlugin::writeSkeleton( std::ostream& _out, Skeleton& _skeleton ) {
554 
555  Skeleton::Pose* refPose = _skeleton.referencePose();
556 
557  _out << "HIERARCHY" << std::endl;
558 
559  std::string indent = "";
560 
561  Skeleton::Joint* lastJoint = 0;
562 
563  for (Skeleton::Iterator it = _skeleton.begin(); it != _skeleton.end(); ++it )
564  {
565 
566  //close brackets
567  while ( (*it)->parent() != lastJoint ){
568  indent = indent.substr(0, indent.size()-1);
569  _out << indent << "}" << std::endl;
570 
571  lastJoint = lastJoint->parent();
572  }
573 
574  ACG::Vec3d translation;
575 
576  if ( (*it)->parent() == 0 ){
577  //ROOT Joint
578  _out << "ROOT " << (*it)->name() << std::endl;
579 
580  translation = refPose->globalTranslation( (*it)->id() );
581 
582  } else if ( (*it)->size() > 0 ){
583 
584  //normal joint
585  _out << indent << "JOINT " << (*it)->name() << std::endl;
586 
587  translation = refPose->globalTranslation( (*it)->id() ) - refPose->globalTranslation( (*it)->parent()->id() );
588 
589  } else {
590 
591  //end-effector
592  _out << indent << "End Site" << std::endl;
593 
594  translation = refPose->globalTranslation( (*it)->id() ) - refPose->globalTranslation( (*it)->parent()->id() );
595  }
596 
597  _out << indent << "{" << std::endl;
598  indent += "\t";
599 
600  _out << indent << "OFFSET " << translation[0] << " " << translation[1] << " " << translation[2] << std::endl;
601 
602  if ( (*it)->size() > 0 ){ //end-effectors have no channel
603 
604  if ( (*it)->parent() == 0)
605  _out << indent << "CHANNELS 6 Xposition Yposition Zposition Zrotation Yrotation Xrotation" << std::endl;
606  else
607  _out << indent << "CHANNELS 3 Zrotation Yrotation Xrotation" << std::endl;
608 
609  lastJoint = *it;
610 
611  } else {
612  indent = indent.substr(0, indent.size()-1);
613  _out << indent << "}" << std::endl;
614  lastJoint = (*it)->parent();
615  }
616  }
617 
618  //close brackets
619  while ( lastJoint->parent() != 0 ){
620  indent = indent.substr(0, indent.size()-1);
621  _out << indent << "}" << std::endl;
622 
623  lastJoint = lastJoint->parent();
624  }
625  _out << "}" << std::endl;
626 
627  //now hierarchy is set up
628  // save the motion
629  AnimationT<ACG::Vec3d>* animation = 0;
630  uint iAnimation;
631  //get first animation with name
632  for (uint i = 0; i < _skeleton.animationCount(); i++){
633  animation = _skeleton.animation( AnimationHandle(i, 0 ) );
634 
635  if (animation->name() == "")
636  animation = 0;
637  else{
638  iAnimation = i;
639  break;
640  }
641  }
642 
643  if (animation == 0){
644 
645  _out << "MOTION" << std::endl;
646  _out << "Frames: 0" << std::endl;
647  _out << "Frame Time: 0.1" << std::endl;
648 
649  return true;
650  }
651 
652  _out << "MOTION" << std::endl;
653  _out << "Frames: " << animation->frameCount() << std::endl;
654  _out << "Frame Time: " << animation->fps() / 1000.0 << std::endl;
655 
656  std::string name = _skeleton.animationName(iAnimation);
657  AnimationHandle animHandle = _skeleton.animationHandle(name);
658 
659 
660  // and every frame of that animation
661  for(unsigned long k = 0; k < animation->frameCount(); ++k)
662  {
663 
664  animHandle.setFrame(k);
665 
666  Skeleton::Pose* pose = _skeleton.pose( animHandle );
667 
668  for (Skeleton::Iterator it = _skeleton.begin(); it != _skeleton.end(); ++it )
669  {
670  //skip end-effectors
671  if ( (*it)->size() == 0)
672  continue;
673 
674  if ( (*it)->parent() == 0 ){
675  //root joint
676  ACG::Vec3d translation = pose->globalTranslation( (*it)->id() ) - refPose->globalTranslation( (*it)->id() );
677 
678  _out << translation[0] << " " << translation[1] << " " << translation[2];
679  }
680 
681  ACG::Matrix4x4d rotMat = _skeleton.referencePose()->localMatrixInv( (*it)->id() ) * pose->localMatrix( (*it)->id() );
682 
683  ACG::Vec3d angles = convertToAxisRotation(rotMat);
684 
685  _out << " " << angles[2] << " " << angles[1] << " " << angles[0];
686 
687 // ACG::GLMatrixd testMat( _skeleton.referencePose()->localMatrix( (*it)->id() ).raw() );
688 //
689 // if ( (*it)->isRoot() )
690 // testMat.translate( pose->globalTranslation( (*it)->id() ) );
691 //
692 // testMat.rotateZ( angles[2] );
693 // testMat.rotateY( angles[1] );
694 // testMat.rotateX( angles[0] );
695 //
696 //
697 // if ( testMat != pose->localMatrix( (*it)->id() ) ){
698 // std::cerr << "Decomposition failed (frame : " << k << " joint: " << (*it)->id() << ")" << std::endl;
699 // std::cerr << "Original:" << pose->localMatrix( (*it)->id() ) << std::endl;
700 // std::cerr << "Test :" << testMat << std::endl;
701 // }
702  }
703  _out << std::endl;
704  }
705 
706  return true;
707 }
708 
709 //-----------------------------------------------------------------------------------------------------
710 
711 ACG::Vec3d FileBVHPlugin::convertToAxisRotation(ACG::Matrix4x4d& _rotationMatrix)
712 {
713  // conversion to quaternion
714  ACG::Quaterniond quat(_rotationMatrix);
715 
716  double x,y,z,w;
717  w = quat[0];
718  x = quat[1];
719  y = quat[2];
720  z = quat[3];
721 
722  // convert quaternion to euler
723  // create special rotation matrix
724  ACG::GLMatrixT<double> matrix;
725 
726  matrix(0,0) = 1.0f - 2.0f * (y * y +z * z);
727  matrix(0,1) = 2.0f * (x * y +z * w);
728  matrix(0,2) = 2.0f * (z * x -y * w);
729 
730  matrix(1,0) = 2.0f * (x * y -z * w);
731  matrix(1,1) = 1.0f - 2.0f * (z * z +x * x);
732  matrix(1,2) = 2.0f * (y * z +x * w);
733 
734  matrix(2,0) = 2.0f * (z * x +y * w);
735  matrix(2,1) = 2.0f * (y * z -x * w);
736  matrix(2,2) = 1.0f - 2.0f * (y * y +x * x);
737 
738  matrix.transpose();
739 
740  // decompose the rotation matrix
741  double cosY = sqrt(matrix(0,0)*matrix(0,0)+matrix(1,0)*matrix(1,0));
742 
743  ACG::Vec3d result;
744 
745  if (cosY > 16 * FLT_EPSILON) {
746  result[0] = atan2( 1.0*matrix(2,1), matrix(2,2));
747  result[1] = atan2(-1.0*matrix(2,0), cosY);
748  result[2] = atan2( 1.0*matrix(1,0), matrix(0,0));
749  } else {
750  result[0] = atan2(-1.0*matrix(1,2), matrix(1,1));
751  result[1] = atan2(-1.0*matrix(2,0), cosY);
752  result[2] = 0.0;
753  }
754 
755  // finally convert angles to degree
756  result[0] *= 180/M_PI;
757  result[1] *= 180/M_PI;
758  result[2] *= 180/M_PI;
759 
760  return result;
761 }
762 
763 //-----------------------------------------------------------------------------------------------------
764 
765 QWidget* FileBVHPlugin::saveOptionsWidget(QString /*_currentFilter*/) {
766  return 0;
767 }
768 
769 //-----------------------------------------------------------------------------------------------------
770 
771 QWidget* FileBVHPlugin::loadOptionsWidget(QString /*_currentFilter*/) {
772 
773  if (loadOptions_ == 0){
774  //generate widget
775  loadOptions_ = new QWidget();
776  QVBoxLayout* layout = new QVBoxLayout();
777  layout->setAlignment(Qt::AlignTop);
778 
779  checkJointScaling_ = new QCheckBox("Ignore Joint Scaling");
780  layout->addWidget(checkJointScaling_);
781 
782  loadDefaultButton_ = new QPushButton("Make Default");
783  layout->addWidget(loadDefaultButton_);
784 
785  loadOptions_->setLayout(layout);
786 
787  connect(loadDefaultButton_, SIGNAL(clicked()), this, SLOT(slotLoadDefault()));
788 
789  checkJointScaling_->setChecked( OpenFlipperSettings().value("FileBVH/Load/JointScaling",true).toBool() );
790  }
791 
792  return loadOptions_;
793 }
794 
795 //-----------------------------------------------------------------------------------------------------
796 
798 
799  OpenFlipperSettings().setValue( "FileBVH/Load/JointScaling", checkJointScaling_->isChecked() );
800 
801  OpenFlipperSettings().setValue( "Core/File/UseLoadDefaults", true );
802 }
803 
804 //-----------------------------------------------------------------------------------------------------
805 
void initializePlugin()
Initialize Plugin.
Definition: FileBVH.cc:108
QWidget * loadOptionsWidget(QString)
Definition: FileBVH.cc:771
Iterator end()
Compare an iterator with the return value of this method to test if it is done.
Matrix localMatrixInv(unsigned int _joint) const
Simply returns the inverse of the local matrix.
Definition: PoseT_impl.hh:176
size_t id() const
returns the joint id
Definition: JointT_impl.hh:97
QString getLoadFilters()
Definition: FileBVH.cc:113
const UpdateType UPDATE_ALL(UpdateTypeSet(1))
Identifier for all updates.
void rotateX(Scalar _angle, MultiplyFrom _mult_from=MULT_FROM_RIGHT)
multiply self with a rotation matrix (angle in degree, x-axis)
Definition: GLMatrixT.hh:190
size_t jointCount()
Returns the number of joints.
int objectCount()
Get the number of available objects.
void transpose()
transpose matrix
bool getObject(const int _identifier, BaseObject *&_object)
Get the object which has the given identifier.
Joint * joint(const size_t &_index)
Returns the joint with the given index.
#define DATA_SKELETON
Definition: Skeleton.hh:64
void translate(Scalar _x, Scalar _y, Scalar _z, MultiplyFrom _mult_from=MULT_FROM_RIGHT)
multiply self with translation matrix (x,y,z)
void identity()
setup an identity matrix
FileBVHPlugin()
Constructor.
Definition: FileBVH.cc:98
void rotateZ(Scalar _angle, MultiplyFrom _mult_from=MULT_FROM_RIGHT)
multiply self with a rotation matrix (angle in degree, z-axis)
Definition: GLMatrixT.hh:202
A general pose, used to store the frames of the animation.
Definition: PoseT.hh:58
Predefined datatypes.
Definition: DataTypes.hh:83
QString filename() const
return the filename of the object
Definition: BaseObject.cc:706
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.
Definition: PoseT_impl.hh:161
int id() const
Definition: BaseObject.cc:190
bool dataType(DataType _type) const
Definition: BaseObject.cc:221
std::string name() const
Access the name of the joint.
Definition: JointT_impl.hh:247
void setFrame(size_t _iFrame)
Sets the current animation frame (not failsafe)
void rotateY(Scalar _angle, MultiplyFrom _mult_from=MULT_FROM_RIGHT)
multiply self with a rotation matrix (angle in degree, y-axis)
Definition: GLMatrixT.hh:196
Functions for geometric operations related to angles.
Represents a single joint in the skeleton.
Definition: JointT.hh:60
Pose * referencePose()
Returns a pointer to the reference pose.
void addJoint(typename SkeletonT< PointT >::Joint *_pParent, typename SkeletonT< PointT >::Joint *_pJoint)
Adds a joint as child of a given parent joint.
const Matrix & localMatrix(unsigned int _joint) const
Returns the local matrix for the given joint.
Definition: PoseT_impl.hh:104
QVariant value(const QString &key, const QVariant &defaultValue=QVariant()) const
Skeleton * skeleton(BaseObjectData *_object)
Get a skeleton from an object.
QString name()
Return a name for the plugin.
Definition: FileBVH.hh:104
const std::string & animationName(size_t _index)
Returns the name of the animation with the given index.
QString getSaveFilters()
Definition: FileBVH.cc:119
void slotLoadDefault()
Slot called when user wants to save the given Load options as default.
Definition: FileBVH.cc:797
Pose * pose(const AnimationHandle &_hAni)
Returns a pointer to the pose with the given animation handle.
DataType supportedType()
Return your supported object type( e.g. DATA_TRIANGLE_MESH )
Definition: FileBVH.cc:125
Iterator class for the skeleton.
Definition: SkeletonT.hh:82
Animation * animation(std::string _name)
Returns a pointer to the animation to the given name.
Joint * parent()
Returns the parent joint.
Definition: JointT_impl.hh:156
size_t animationCount()
Returns the number of animations stored in this skeleton.
int loadObject(QString _filename)
Loads Object.
Definition: FileBVH.cc:146
AnimationHandle animationHandle(std::string _name)
Get an AnimationHandle to the animation with the given name.
void setValue(const QString &key, const QVariant &value)
Wrapper function which makes it possible to enable Debugging output with -DOPENFLIPPER_SETTINGS_DEBUG...
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.
Definition: PoseT_impl.hh:120
QWidget * saveOptionsWidget(QString)
Definition: FileBVH.cc:765
A handle used to refer to an animation or to a specific frame in an animation.
Vector globalTranslation(unsigned int _joint)
Returns the global translation vector.
Definition: PoseT_impl.hh:227