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
57const std::bitset<4> HIERARCHY (static_cast<int>(0));
58const std::bitset<4> ROOT_DEFINITION (static_cast<int>(1));
59const std::bitset<4> OPENED_BRACKET (static_cast<int>(2));
60const std::bitset<4> CLOSED_BRACKET (static_cast<int>(3));
61const std::bitset<4> OFFSET (static_cast<int>(4));
62const std::bitset<4> CHANNELS (static_cast<int>(5));
63const std::bitset<4> JOINT (static_cast<int>(6));
64const std::bitset<4> ENDSITE (static_cast<int>(7));
65const std::bitset<4> MOTION (static_cast<int>(8));
66const std::bitset<4> FRAMES (static_cast<int>(9));
67const std::bitset<4> FRAME_TIME (static_cast<int>(10));
68const std::bitset<4> CHANNEL_DATA (static_cast<int>(11));
69
70//-----------------------------------------------------------------------------
71//data structures used for parsing
72enum ChannelType{NotGiven,XP,YP,ZP,XR,YR,ZR}; //contains the informations about the use of this datafield
73
74class 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
132void 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
146int 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
476bool 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
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
528ACG::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
553bool 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
711ACG::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
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
765QWidget* FileBVHPlugin::saveOptionsWidget(QString /*_currentFilter*/) {
766 return 0;
767}
768
769//-----------------------------------------------------------------------------------------------------
770
771QWidget* 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
Functions for geometric operations related to angles.
DLLEXPORT OpenFlipperQSettings & OpenFlipperSettings()
QSettings object containing all program settings of OpenFlipper.
@ LOGERR
@ LOGINFO
#define DATA_SKELETON
Definition: Skeleton.hh:64
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
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
void translate(Scalar _x, Scalar _y, Scalar _z, MultiplyFrom _mult_from=MULT_FROM_RIGHT)
multiply self with translation matrix (x,y,z)
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
void identity()
setup an identity matrix
void transpose()
transpose matrix
A handle used to refer to an animation or to a specific frame in an animation.
void setFrame(size_t _iFrame)
Sets the current animation frame (not failsafe)
QString filename() const
return the filename of the object
Definition: BaseObject.cc:704
bool dataType(DataType _type) const
Definition: BaseObject.cc:219
int id() const
Definition: BaseObject.cc:188
Predefined datatypes.
Definition: DataTypes.hh:83
QString name()
Return a name for the plugin.
Definition: FileBVH.hh:104
void slotLoadDefault()
Slot called when user wants to save the given Load options as default.
Definition: FileBVH.cc:797
QWidget * loadOptionsWidget(QString)
Definition: FileBVH.cc:771
FileBVHPlugin()
Constructor.
Definition: FileBVH.cc:98
void initializePlugin()
Initialize Plugin.
Definition: FileBVH.cc:108
QString getSaveFilters()
Definition: FileBVH.cc:119
QString getLoadFilters()
Definition: FileBVH.cc:113
DataType supportedType()
Return your supported object type( e.g. DATA_TRIANGLE_MESH )
Definition: FileBVH.cc:125
QWidget * saveOptionsWidget(QString)
Definition: FileBVH.cc:765
int loadObject(QString _filename)
Loads Object.
Definition: FileBVH.cc:146
Represents a single joint in the skeleton.
Definition: JointT.hh:61
size_t id() const
returns the joint id
Definition: JointT_impl.hh:97
std::string name() const
Access the name of the joint.
Definition: JointT_impl.hh:247
Joint * parent()
Returns the parent joint.
Definition: JointT_impl.hh:156
QVariant value(const QString &key, const QVariant &defaultValue=QVariant()) const
void setValue(const QString &key, const QVariant &value)
Wrapper function which makes it possible to enable Debugging output with -DOPENFLIPPER_SETTINGS_DEBUG...
A general pose, used to store the frames of the animation.
Definition: PoseT.hh:59
void setLocalMatrix(unsigned int _joint, const Matrix &_local, bool _keepLocalChildPositions=true)
Sets the local coordinate system.
Definition: PoseT_impl.hh:120
Matrix localMatrixInv(unsigned int _joint) const
Simply returns the inverse of the local matrix.
Definition: PoseT_impl.hh:176
const Matrix & localMatrix(unsigned int _joint) const
Returns the local matrix for the given joint.
Definition: PoseT_impl.hh:104
void setLocalTranslation(unsigned int _joint, const Vector &_position, bool _keepLocalChildPositions=true)
Sets the local translation vector.
Definition: PoseT_impl.hh:161
Vector globalTranslation(unsigned int _joint)
Returns the global translation vector.
Definition: PoseT_impl.hh:227
Iterator class for the skeleton.
Definition: SkeletonT.hh:83
Pose * referencePose()
Returns a pointer to the reference pose.
Iterator begin()
Iterator over joints of the skeletal tree in TOP-DOWN order (from root to leafs)
size_t jointCount()
Returns the number of joints.
void addJoint(typename SkeletonT< PointT >::Joint *_pParent, typename SkeletonT< PointT >::Joint *_pJoint)
Adds a joint as child of a given parent joint.
size_t animationCount()
Returns the number of animations stored in this skeleton.
AnimationHandle addAnimation(std::string _name, Animation *_animation)
Adds a new animation to the list.
AnimationHandle animationHandle(std::string _name)
Get an AnimationHandle to the animation with the given name.
Animation * animation(std::string _name)
Returns a pointer to the animation to the given name.
Pose * pose(const AnimationHandle &_hAni)
Returns a pointer to the pose with the given animation handle.
Joint * joint(const size_t &_index)
Returns the joint with the given index.
const std::string & animationName(size_t _index)
Returns the name of the animation with the given index.
Iterator end()
Compare an iterator with the return value of this method to test if it is done.
const UpdateType UPDATE_ALL(UpdateTypeSet(1))
Identifier for all updates.
bool getObject(const int _identifier, BaseObject *&_object)
Get the object which has the given identifier.
int objectCount()
Get the number of available objects.
Skeleton * skeleton(BaseObjectData *_object)
Get a skeleton from an object.