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