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