43 #if (_MSC_VER <= 1916)
44 #define QT_NO_FLOAT16_OPERATORS
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));
72enum ChannelType{NotGiven,XP,YP,ZP,XR,YR,ZR};
76 ChannelType dataChannels[6];
77 unsigned int dataOffset[6];
79 unsigned int channelOffset;
86 dataChannels[i]=NotGiven;
99 : ignoreJointScaling_(true),
101 checkJointScaling_(0),
102 loadDefaultButton_(0)
114 return QString( tr(
"Biovision Format files ( *.bvh )") );
120 return QString( tr(
"Biovision Format files ( *.bvh )") );
132void trimString( std::string& _string) {
135 size_t start = _string.find_first_not_of(
" \t\r\n");
136 size_t end = _string.find_last_not_of(
" \t\r\n");
138 if(( std::string::npos == start ) || ( std::string::npos == end))
141 _string = _string.substr( start, end-start+1 );
148 if ( checkJointScaling_ != 0 )
149 ignoreJointScaling_ = checkJointScaling_->isChecked();
155 std::fstream input( _filename.toUtf8(), std::ios_base::in );
157 if ( !input.is_open() || !input.good() ){
158 emit log(
LOGERR, tr(
"Error: cannot open file %1").arg(_filename) );
171 object->setFromFileName(_filename);
172 object->setName(object->
filename());
176 emit log(
LOGERR, tr(
"Error: Unable to add skeleton!"));
186 std::bitset<4> waitingFor = HIERARCHY;
188 std::map< Skeleton::Joint* , JointInfo> jointInfos;
193 uint currentFrame = 0;
196 while( input && !input.eof() )
198 std::getline(input,line);
200 emit log(
LOGERR, tr(
"Error: could not read file properly!"));
208 if ( line.size() == 0 )
211 std::stringstream stream(line);
217 if ( (waitingFor == HIERARCHY) && (keyWrd ==
"HIERARCHY") ){
218 waitingFor = ROOT_DEFINITION;
223 if ( (waitingFor == ROOT_DEFINITION) && (keyWrd ==
"ROOT") ){
231 jointInfos[rootJoint]=info;
232 currentParent = rootJoint;
234 waitingFor = OPENED_BRACKET;
239 if ( (waitingFor == OPENED_BRACKET) && (keyWrd ==
"{") ){
241 waitingFor = OFFSET | CHANNELS | JOINT | ENDSITE | CLOSED_BRACKET;
247 if ( (!(waitingFor&CLOSED_BRACKET).none()) && (keyWrd ==
"}") ){
249 if ( currentParent->
parent() == 0 )
252 waitingFor = JOINT | CLOSED_BRACKET;
255 currentParent = currentParent->
parent();
260 if ( (!(waitingFor&JOINT).none()) && (keyWrd ==
"JOINT") ){
266 skeleton->
addJoint(currentParent, newJoint);
268 jointInfos[newJoint]=info;
269 currentParent = newJoint;
271 waitingFor = OPENED_BRACKET;
276 if ( (!(waitingFor&OFFSET).none()) && (keyWrd ==
"OFFSET") ){
280 stream >> translation[0];
281 stream >> translation[1];
282 stream >> translation[2];
290 if ( (!(waitingFor&CHANNELS).none()) && (keyWrd ==
"CHANNELS") ){
293 stream >> channelCount;
295 JointInfo& info=jointInfos[ currentParent ];
298 std::cerr <<
"Error: channel count to big, will crash very soon" << std::endl;
300 for (uint i=0; i < channelCount; i++){
301 std::string channelType;
302 stream >> channelType;
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;
318 {std::cerr <<
"Error: Unknown channelType. Ignoring." << std::endl;}
320 if(info.dataChannels[info.channelOffset]!=NotGiven){
321 info.dataOffset[info.channelOffset]=dataOffset;
322 info.channelOffset++;
330 if ( (!(waitingFor&ENDSITE).none()) && (keyWrd ==
"End") ){
335 std::string
name =
"End";
338 skeleton->
addJoint(currentParent, newJoint);
339 currentParent = newJoint;
341 waitingFor = OPENED_BRACKET;
346 if ( (waitingFor == MOTION) && (keyWrd ==
"MOTION") ){
352 if ( (waitingFor == FRAMES) && (keyWrd ==
"Frames:") ){
354 stream >> frameCount;
361 waitingFor = FRAME_TIME;
366 if ( (waitingFor == FRAME_TIME) && (keyWrd ==
"Frame") ){
375 skeleton->
animation(animHandle)->setFps( frameTime * 1000 );
377 waitingFor = CHANNEL_DATA;
382 if ( (waitingFor == CHANNEL_DATA) ){
385 std::vector<double> data(dataOffset,0.0);
389 if ( currentFrame < frameCount ){
390 animHandle.
setFrame( currentFrame );
391 pose = skeleton->
pose(animHandle);
394 std::cerr <<
"Warning: Too many frames specified in file." << std::endl;
398 data[0] = QString( keyWrd.c_str() ).toDouble();
400 for (uint i=1; i < data.size(); i++){
407 if ( currentFrame < frameCount )
408 for (
unsigned long jointID=0; jointID < skeleton->
jointCount(); jointID++ ){
414 if ( jointInfos.find(joint) == jointInfos.end() ){
429 if(info.dataChannels[i]==NotGiven)
break;
431 double val=data[info.dataOffset[i]];
433 switch(info.dataChannels[i]){
434 case XP: translation[0]=val;
break;
435 case YP: translation[1]=val;
break;
436 case ZP: translation[2]=val;
break;
437 case XR: matRot.
rotateX(val);
break;
438 case YR: matRot.
rotateY(val);
break;
439 case ZR: matRot.
rotateZ(val);
break;
447 if ( (!ignoreJointScaling_) ||
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;
469 emit openedFile( object->
id() );
476bool FileBVHPlugin::saveObject(
int _id, QString _filename)
484 std::string filename = std::string( _filename.toUtf8() );
486 std::fstream stream( filename.c_str(), std::ios_base::out );
489 emit log(
LOGERR, tr(
"saveObject : cannot not open file %1").arg(_filename) );
490 QFile( QString(filename.c_str()) ).remove();
497 object->setFromFileName(_filename);
498 object->setName(object->
filename());
502 if ( writeSkeleton( stream, *skeleton ) ){
504 emit log(
LOGINFO, tr(
"Saved object to ") + _filename );
510 emit log(
LOGERR, tr(
"Unable to save ") + _filename);
512 QFile( QString(filename.c_str()) ).remove();
518 emit log(
LOGERR, tr(
"Unable to save (object is not a skeleton)"));
520 QFile( QString(filename.c_str()) ).remove();
531 if(_matrix(1,0) > 0.998) {
532 v[0] = atan2(_matrix(0,2), _matrix(2,2));
538 if(_matrix(1,0) < -0.998) {
539 v[0] = atan2(_matrix(0,2), _matrix(2,2));
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));
553bool FileBVHPlugin::writeSkeleton( std::ostream& _out,
Skeleton& _skeleton ) {
557 _out <<
"HIERARCHY" << std::endl;
559 std::string indent =
"";
567 while ( (*it)->parent() != lastJoint ){
568 indent = indent.substr(0, indent.size()-1);
569 _out << indent <<
"}" << std::endl;
571 lastJoint = lastJoint->
parent();
576 if ( (*it)->parent() == 0 ){
578 _out <<
"ROOT " << (*it)->name() << std::endl;
582 }
else if ( (*it)->size() > 0 ){
585 _out << indent <<
"JOINT " << (*it)->name() << std::endl;
592 _out << indent <<
"End Site" << std::endl;
597 _out << indent <<
"{" << std::endl;
600 _out << indent <<
"OFFSET " << translation[0] <<
" " << translation[1] <<
" " << translation[2] << std::endl;
602 if ( (*it)->size() > 0 ){
604 if ( (*it)->parent() == 0)
605 _out << indent <<
"CHANNELS 6 Xposition Yposition Zposition Zrotation Yrotation Xrotation" << std::endl;
607 _out << indent <<
"CHANNELS 3 Zrotation Yrotation Xrotation" << std::endl;
612 indent = indent.substr(0, indent.size()-1);
613 _out << indent <<
"}" << std::endl;
614 lastJoint = (*it)->
parent();
619 while ( lastJoint->
parent() != 0 ){
620 indent = indent.substr(0, indent.size()-1);
621 _out << indent <<
"}" << std::endl;
623 lastJoint = lastJoint->
parent();
625 _out <<
"}" << std::endl;
635 if (animation->name() ==
"")
645 _out <<
"MOTION" << std::endl;
646 _out <<
"Frames: 0" << std::endl;
647 _out <<
"Frame Time: 0.1" << std::endl;
652 _out <<
"MOTION" << std::endl;
653 _out <<
"Frames: " << animation->frameCount() << std::endl;
654 _out <<
"Frame Time: " << animation->fps() / 1000.0 << std::endl;
661 for(
unsigned long k = 0; k < animation->frameCount(); ++k)
671 if ( (*it)->size() == 0)
674 if ( (*it)->parent() == 0 ){
678 _out << translation[0] <<
" " << translation[1] <<
" " << translation[2];
683 ACG::Vec3d angles = convertToAxisRotation(rotMat);
685 _out <<
" " << angles[2] <<
" " << angles[1] <<
" " << angles[0];
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);
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);
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);
741 double cosY = sqrt(matrix(0,0)*matrix(0,0)+matrix(1,0)*matrix(1,0));
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));
750 result[0] = atan2(-1.0*matrix(1,2), matrix(1,1));
751 result[1] = atan2(-1.0*matrix(2,0), cosY);
756 result[0] *= 180/M_PI;
757 result[1] *= 180/M_PI;
758 result[2] *= 180/M_PI;
773 if (loadOptions_ == 0){
775 loadOptions_ =
new QWidget();
776 QVBoxLayout* layout =
new QVBoxLayout();
777 layout->setAlignment(Qt::AlignTop);
779 checkJointScaling_ =
new QCheckBox(
"Ignore Joint Scaling");
780 layout->addWidget(checkJointScaling_);
782 loadDefaultButton_ =
new QPushButton(
"Make Default");
783 layout->addWidget(loadDefaultButton_);
785 loadOptions_->setLayout(layout);
787 connect(loadDefaultButton_, SIGNAL(clicked()),
this, SLOT(
slotLoadDefault()));
789 checkJointScaling_->setChecked(
OpenFlipperSettings().value(
"FileBVH/Load/JointScaling",
true).toBool() );
Functions for geometric operations related to angles.
DLLEXPORT OpenFlipperQSettings & OpenFlipperSettings()
QSettings object containing all program settings of OpenFlipper.
void rotateX(Scalar _angle, MultiplyFrom _mult_from=MULT_FROM_RIGHT)
multiply self with a rotation matrix (angle in degree, x-axis)
void rotateY(Scalar _angle, MultiplyFrom _mult_from=MULT_FROM_RIGHT)
multiply self with a rotation matrix (angle in degree, y-axis)
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)
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
bool dataType(DataType _type) const
QString name()
Return a name for the plugin.
void slotLoadDefault()
Slot called when user wants to save the given Load options as default.
QWidget * loadOptionsWidget(QString)
FileBVHPlugin()
Constructor.
void initializePlugin()
Initialize Plugin.
DataType supportedType()
Return your supported object type( e.g. DATA_TRIANGLE_MESH )
QWidget * saveOptionsWidget(QString)
int loadObject(QString _filename)
Loads Object.
Represents a single joint in the skeleton.
size_t id() const
returns the joint id
std::string name() const
Access the name of the joint.
Joint * parent()
Returns the parent joint.
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.
void setLocalMatrix(unsigned int _joint, const Matrix &_local, bool _keepLocalChildPositions=true)
Sets the local coordinate system.
Matrix localMatrixInv(unsigned int _joint) const
Simply returns the inverse of the local matrix.
const Matrix & localMatrix(unsigned int _joint) const
Returns the local matrix for the given joint.
void setLocalTranslation(unsigned int _joint, const Vector &_position, bool _keepLocalChildPositions=true)
Sets the local translation vector.
Vector globalTranslation(unsigned int _joint)
Returns the global translation vector.
Iterator class for the skeleton.
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.