Developer Documentation
SkeletonTransform.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 #include "SkeletonTransform.hh"
46 //-----------------------------------------------------------------------------
47 
49 SkeletonTransform::SkeletonTransform(Skeleton& _skeleton) : skeleton_(_skeleton)
50 {
51  refPose_ = skeleton_.referencePose();
52 }
53 
54 //-----------------------------------------------------------------------------
55 
65 void SkeletonTransform::scaleSkeleton(double _factor, Skeleton::Pose* _pose) {
66 
67  // note: scaling the root joints is important since this controls e.g. the size of foot steps
68 
69  if ( _pose == 0)
70  _pose = refPose_;
71 
72  //scale bones in the given pose
73  for (Skeleton::Iterator it = skeleton_.begin(); it != skeleton_.end(); ++it )
74  _pose->setLocalTranslation( (*it)->id(), _pose->localTranslation((*it)->id()) * _factor );
75 
76  // if given pose is refPose
77  if ( _pose == refPose_){
78  //scale bones in the animations
79  for (size_t a=0; a < skeleton_.animationCount(); a++)
80  for (unsigned int iFrame = 0; iFrame < skeleton_.animation(a)->frameCount(); iFrame++){
81 
82  Skeleton::Pose* pose = skeleton_.animation(a)->pose( iFrame );
83 
84  if ( pose == refPose_ )
85  continue;
86 
87  for (Skeleton::Iterator it = skeleton_.begin(); it != skeleton_.end(); ++it )
88  pose->setLocalTranslation( (*it)->id(), pose->localTranslation((*it)->id()) * _factor );
89  }
90  }
91 }
92 
93 //-----------------------------------------------------------------------------
94 
107 
108  if ( _pose == 0)
109  _pose = refPose_;
110 
111  //apply the transformation to given pose
112  ACG::Vec3d position = _pose->globalTranslation( 0 );
113  _pose->setGlobalTranslation( 0, position + _translation );
114 
115  // apply to all animations if the refpose was changed
116  if ( _pose == refPose_ ){
117 
118  // apply transformation to all frames of all animations
119  for (unsigned int a=0; a < skeleton_.animationCount(); a++)
120  for (unsigned int iFrame = 0; iFrame < skeleton_.animation(a)->frameCount(); iFrame++){
121 
122  Skeleton::Pose* pose = skeleton_.animation(a)->pose( iFrame );
123 
124  if ( pose == refPose_ )
125  continue;
126 
127  ACG::Vec3d position = pose->globalTranslation( 0 );
128  pose->setGlobalTranslation( 0, position + _translation );
129  }
130  }
131 }
132 
133 //-----------------------------------------------------------------------------
134 
144 
145  if ( _pose == 0)
146  _pose = refPose_;
147 
148  //apply the transformation to given pose
149  ACG::Matrix4x4d local = _pose->localMatrix( 0 );
150  _pose->setLocalMatrix( 0, _transformation * local );
151 
152  // apply to all animations if the refpose was changed
153  if ( _pose == refPose_ ){
154 
155  // apply transformation to all frames of all animations
156  for (unsigned int a=0; a < skeleton_.animationCount(); a++)
157  for (unsigned int iFrame = 0; iFrame < skeleton_.animation(a)->frameCount(); iFrame++){
158 
159  Skeleton::Pose* pose = skeleton_.animation(a)->pose( iFrame );
160 
161  if ( pose == refPose_ )
162  continue;
163 
164  ACG::Matrix4x4d local = pose->localMatrix( 0 );
165  pose->setLocalMatrix( 0, _transformation * local );
166  }
167  }
168 }
169 
170 //-----------------------------------------------------------------------------
171 
186 void SkeletonTransform::transformJoint(Skeleton::Joint* _joint, Matrix4x4 _matrix, bool _keepChildPositions) {
187 
188  if (_joint == 0)
189  return;
190 
191  Matrix4x4 transform;
192  transform.identity();
193 
194  //get transformation matrix
195  Skeleton::Joint* parent = _joint->parent();
196 
197  if ( parent != 0 )
198  // new GlobalMatrix after application of _matrix is: newGlobal = _matrix * activePose->getGlobal( joint )
199  // new LocalMatrix : activePose->getGlobalInv( parent->getID() ) * newGlobal
200  // Transformation from LocalMatrix to new LocalMatrix:
201  transform = refPose_->globalMatrixInv( parent->id() ) * _matrix * refPose_->globalMatrix( _joint->id() ) * refPose_->localMatrixInv( _joint->id() );
202  else
203  // the transformation for the root joint has to be applied directly
204  // _matrix defines a post-multiplication but we need a pre-multiplication matrix X in order to apply
205  // the transformation to all frames: _matrix * Global = Global * X --> X = GlobalInverse * _matrix * global
206  transform = refPose_->globalMatrixInv( _joint->id() ) * _matrix * refPose_->globalMatrix( _joint->id() );
207 
208 
209  //transform refPose
210  if ( parent != 0 ){
211 
212  Matrix4x4 newMatrix = transform * refPose_->localMatrix( _joint->id() );
213  refPose_->setLocalMatrix( _joint->id(), newMatrix, !_keepChildPositions); //keep child for local means !keepChild global
214 
215  } else {
216  //directly apply the global transformation
217  Matrix4x4 newMatrix = refPose_->globalMatrix( _joint->id() ) * transform;
218  refPose_->setLocalMatrix( _joint->id(), newMatrix, !_keepChildPositions);
219  }
220 
221  // apply transformation to all frames of all animations
222  for (unsigned int a=0; a < skeleton_.animationCount(); a++)
223  for (unsigned int iFrame = 0; iFrame < skeleton_.animation(a)->frameCount(); iFrame++){
224 
225  Skeleton::Pose* pose = skeleton_.animation(a)->pose( iFrame );
226 
227  if ( parent != 0 ){
228 
229  //transform the local matrix
230  Matrix4x4 newMatrix = transform * pose->localMatrix( _joint->id() );
231  pose->setLocalMatrix( _joint->id(), newMatrix, !_keepChildPositions);
232 
233  // the transformation may have changed two things
234  // 1. due to the changed length of neighboring bones the rotation
235  // angle changes this has to be corrected by rotating the coord-frame
236  // 2. the length of the bone to a child may have changed. Check that
237  // the length is the same like in the refPose
238 
239  } else {
240 
241  //directly apply the global transformation
242  Matrix4x4 newMatrix = pose->globalMatrix( _joint->id() ) * transform;
243 
244  pose->setLocalMatrix( _joint->id(), newMatrix, !_keepChildPositions);
245  }
246  }
247 }
248 
249 //-----------------------------------------------------------------------------
250 
265 void SkeletonTransform::translateJoint(Skeleton::Joint* _joint, ACG::Vec3d _translation, bool _keepChildPositions) {
266  ACG::GLMatrixd transformation;
267  transformation.identity();
268  transformation.translate( _translation );
269 
270  transformJoint(_joint, transformation, _keepChildPositions);
271 }
272 
273 //-----------------------------------------------------------------------------
274 
285 void SkeletonTransform::rotateJoint(Skeleton::Joint* _joint, Skeleton::Pose* _pose, Matrix4x4 _rotation, bool _applyToWholeAnimation) {
286 
287  if (_joint == 0)
288  return;
289 
290  if ( fabs(1.0 - determinant(_rotation)) > 1E-6 ){
291  std::cerr << "Cannot rotate joint. Matrix is not a rotation matrix (det:" << determinant(_rotation) << ")" << std::endl;
292  return;
293  }
294 
295  Matrix4x4 transform;
296  transform.identity();
297 
298  //get transformation matrix
299  Skeleton::Joint* parent = _joint->parent();
300 
301  if ( parent != 0 )
302  // new GlobalMatrix after application of _matrix is: newGlobal = _matrix * activePose->getGlobal( joint )
303  // new LocalMatrix : activePose->getGlobalInv( parent->getID() ) * newGlobal
304  // Transformation from LocalMatrix to new LocalMatrix:
305  transform = _pose->globalMatrixInv( parent->id() ) * _rotation * _pose->globalMatrix( _joint->id() ) * _pose->localMatrixInv( _joint->id() );
306  else
307  // the transformation for the root joint has to be applied directly
308  // _matrix defines a post-multiplication but we need a pre-multiplication matrix X in order to apply
309  // the transformation to all frames: _matrix * Global = Global * X --> X = GlobalInverse * _matrix * global
310  transform = _pose->globalMatrixInv( _joint->id() ) * _rotation * _pose->globalMatrix( _joint->id() );
311 
312 
313  //transform pose
314  if ( (_pose == refPose_) || !_applyToWholeAnimation ){
315 
316  if ( parent != 0 ){
317 
318  Matrix4x4 newMatrix = transform * _pose->localMatrix( _joint->id() );
319  _pose->setLocalMatrix( _joint->id(), newMatrix);
320 
321  } else {
322 
323  //directly apply the global transformation
324  Matrix4x4 newMatrix = _pose->globalMatrix( _joint->id() ) * transform;
325  _pose->setLocalMatrix( _joint->id(), newMatrix);
326  }
327  }
328 
329  //TODO don't apply to all frames but only to those belonging to the same animation as _pose
330  if ( _applyToWholeAnimation ){
331  // apply transformation to all frames of all animations
332  for (unsigned int a=0; a < skeleton_.animationCount(); a++)
333  for (unsigned int iFrame = 0; iFrame < skeleton_.animation(a)->frameCount(); iFrame++){
334 
335  Skeleton::Pose* pose = skeleton_.animation(a)->pose( iFrame );
336 
337  if ( parent != 0 ){
338  //transform the local matrix
339  Matrix4x4 newMatrix = transform * pose->localMatrix( _joint->id() );
340 
341  pose->setLocalMatrix( _joint->id(), newMatrix);
342 
343  } else {
344 
345  //directly apply the global transformation
346  Matrix4x4 newMatrix = pose->globalMatrix( _joint->id() ) * transform;
347 
348  pose->setLocalMatrix( _joint->id(), newMatrix);
349  }
350  }
351  }
352 }
353 
354 //-----------------------------------------------------------------------------
355 
356 
358  double value;
359 
360  value =
361  _m(0,3) * _m(1,2) * _m(2,1) * _m(3,0)-_m(0,2) * _m(1,3) * _m(2,1) * _m(3,0)-_m(0,3) * _m(1,1) * _m(2,2) * _m(3,0)+_m(0,1) * _m(1,3) * _m(2,2) * _m(3,0)+
362  _m(0,2) * _m(1,1) * _m(2,3) * _m(3,0)-_m(0,1) * _m(1,2) * _m(2,3) * _m(3,0)-_m(0,3) * _m(1,2) * _m(2,0) * _m(3,1)+_m(0,2) * _m(1,3) * _m(2,0) * _m(3,1)+
363  _m(0,3) * _m(1,0) * _m(2,2) * _m(3,1)-_m(0,0) * _m(1,3) * _m(2,2) * _m(3,1)-_m(0,2) * _m(1,0) * _m(2,3) * _m(3,1)+_m(0,0) * _m(1,2) * _m(2,3) * _m(3,1)+
364  _m(0,3) * _m(1,1) * _m(2,0) * _m(3,2)-_m(0,1) * _m(1,3) * _m(2,0) * _m(3,2)-_m(0,3) * _m(1,0) * _m(2,1) * _m(3,2)+_m(0,0) * _m(1,3) * _m(2,1) * _m(3,2)+
365  _m(0,1) * _m(1,0) * _m(2,3) * _m(3,2)-_m(0,0) * _m(1,1) * _m(2,3) * _m(3,2)-_m(0,2) * _m(1,1) * _m(2,0) * _m(3,3)+_m(0,1) * _m(1,2) * _m(2,0) * _m(3,3)+
366  _m(0,2) * _m(1,0) * _m(2,1) * _m(3,3)-_m(0,0) * _m(1,2) * _m(2,1) * _m(3,3)-_m(0,1) * _m(1,0) * _m(2,2) * _m(3,3)+_m(0,0) * _m(1,1) * _m(2,2) * _m(3,3);
367 
368  return value;
369 }
void translateSkeleton(ACG::Vec3d _translation, Skeleton::Pose *_pose=0)
translate the skeleton
virtual Matrix globalMatrixInv(unsigned int _joint) const
Simply returns the inverse of the global matrix.
Definition: PoseT_impl.hh:267
Iterator end()
Compare an iterator with the return value of this method to test if it is done.
void scaleSkeleton(double _factor, Skeleton::Pose *_pose=0)
scale all bones of the skeleton by the given factor
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
void setGlobalTranslation(unsigned int _joint, const Vector &_position, bool _keepGlobalChildPositions=true)
Sets the global translation vector.
Definition: PoseT_impl.hh:249
void transformJoint(Skeleton::Joint *_joint, Matrix4x4 _matrix, bool _keepChildPositions=true)
apply a transformation to a joint in the refPose
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
A general pose, used to store the frames of the animation.
Definition: PoseT.hh:58
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
static double determinant(Matrix4x4 &_m)
compute determinant to check if matrix is rotation matrix
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.
const Matrix & localMatrix(unsigned int _joint) const
Returns the local matrix for the given joint.
Definition: PoseT_impl.hh:104
SkeletonTransform(Skeleton &_skeleton)
Le constructeur.
Iterator class for the skeleton.
Definition: SkeletonT.hh:82
void translateJoint(Skeleton::Joint *_joint, ACG::Vec3d _translation, bool _keepChildPositions=true)
apply a translation to a joint in the refPose
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.
Vector localTranslation(unsigned int _joint)
Returns the local translation vector.
Definition: PoseT_impl.hh:139
const Matrix & globalMatrix(unsigned int _joint) const
Returns the global matrix for the given joint.
Definition: PoseT_impl.hh:193
void setLocalMatrix(unsigned int _joint, const Matrix &_local, bool _keepLocalChildPositions=true)
Sets the local coordinate system.
Definition: PoseT_impl.hh:120
void rotateJoint(Skeleton::Joint *_joint, Skeleton::Pose *_pose, Matrix4x4 _rotation, bool _applyToWholeAnimation=true)
rotate a joint in an arbitrary Pose
void transformSkeleton(Matrix4x4 _transformation, Skeleton::Pose *_pose=0)
transform the skeleton
Vector globalTranslation(unsigned int _joint)
Returns the global translation vector.
Definition: PoseT_impl.hh:227