Developer Documentation
SkeletonEditingScripting.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 "SkeletonEditingPlugin.hh"
45 
47 #include <ObjectTypes/Skeleton/Helper/SkeletonTransform.hh>
48 #include <ACG/Geometry/Algorithms.hh>
49 
50 //------------------------------------------------------------------------------
51 
56 
57  emit setSlotDescription("splitBone(int,int)",
58  tr("insert a joint in the middle of a bone."),
59  QString(tr("objectId,jointId")).split(","),
60  QString(tr("ID of an object,ID of tail joint")).split(","));
61 
62  emit
63  setSlotDescription(
64  "addJoint(int,int,Vector)",
65  tr("add a joint to the skeleton."),
66  QString(tr("objectId,jointId,Vector")).split(","),
67  QString(
68  tr(
69  "ID of an object,ID of parent joint,Position for the new joint")).split(
70  ","));
71 
72  emit setSlotDescription("deleteJoint(int,int)",
73  tr("delete a joint from the skeleton."),
74  QString(tr("objectId,jointId")).split(","),
75  QString(tr("ID of an object,ID of a joint")).split(","));
76 
77  emit setSlotDescription(
78  "transformJoint(int,int,Matrix4x4)",
79  tr("transform a joint with a matrix."),
80  QString(tr("objectId,jointId,Matrix")).split(","),
81  QString(tr("ID of an object,ID of a joint,transformation matrix")).split(
82  ","));
83 
84  emit setSlotDescription("globalMatrix(int,int)",
85  tr("get the global matrix of a joint in the active pose."),
86  QString(tr("objectId,jointId")).split(","),
87  QString(tr("ID of an object,ID of a joint")).split(","));
88 
89  emit setSlotDescription("localMatrix(int,int)",
90  tr("get the local matrix of a joint in the active pose."),
91  QString(tr("objectId,jointId")).split(","),
92  QString(tr("ID of an object,ID of a joint")).split(","));
93 
94  emit setSlotDescription("globalTranslation(int,int)",
95  tr("get the global translation of a joint in the active pose."),
96  QString(tr("objectId,jointId")).split(","),
97  QString(tr("ID of an object,ID of a joint")).split(","));
98 
99  emit setSlotDescription("localTranslation(int,int)",
100  tr("get the local translation of a joint in the active pose."),
101  QString(tr("objectId,jointId")).split(","),
102  QString(tr("ID of an object,ID of a joint")).split(","));
103 
104  emit setSlotDescription("animationCount(int)",
105  tr("get the number of animations the skeleton has."),
106  QString(tr("objectId")).split(","),
107  QString(tr("ID of an object")).split(","));
108 
109  emit setSlotDescription("frameCount(int,int)",
110  tr("get the number of frames a given animation has."),
111  QString(tr("objectId,animationIndex")).split(","),
112  QString(tr("ID of an object,Index of an animation")).split(","));
113 
114  emit setSlotDescription("activeAnimation(int)",
115  tr("get the animation which is currently active."),
116  QString(tr("objectId")).split(","),
117  QString(tr("ID of an object")).split(","));
118 
119  emit setSlotDescription("activeFrame(int)",
120  tr("get the frame which is currently active"),
121  QString(tr("objectId")).split(","),
122  QString(tr("ID of an object")).split(","));
123 
124  emit
125  setSlotDescription(
126  "setActivePose(int,int,int)",
127  tr("set the active pose of the skeleton."),
128  QString(tr("objectId,animationIndex,frame")).split(","),
129  QString(tr("ID of an object,Index of an animation,Index of a frame")).split(
130  ","));
131 
132  emit
133  setSlotDescription(
134  "addAnimation(int,QString,int)",
135  tr("add an animation to the skeleton."),
136  QString(tr("objectId,AnimationName,frameCount")).split(","),
137  QString(
138  tr(
139  "ID of an object,name for the animation,number of frames the animation should have")).split(
140  ","));
141 }
142 
143 //------------------------------------------------------------------------------
144 
146 void SkeletonEditingPlugin::splitBone(int _objectId, int _tailJoint) {
147 
148  BaseObjectData* baseObject = 0;
149  PluginFunctions::getObject(_objectId, baseObject);
150 
151  if (baseObject == 0)
152  return;
153 
154  Skeleton* skeleton = PluginFunctions::skeleton(baseObject);
155 
156  if (skeleton == 0)
157  return;
158 
159  Skeleton::Joint* tailJoint = skeleton->joint(_tailJoint);
160 
161  if (tailJoint == 0) {
162  emit log(
163  LOGERR,
164  tr("Cannot split bone. Unable to find joint with id ")
165  + QString::number(_tailJoint));
166  return;
167  }
168 
169  Skeleton::Joint* headJoint = tailJoint->parent();
170 
171  //add the new joint
172  Skeleton::Joint* jointNew = new Skeleton::Joint(headJoint);
173  skeleton->addJoint(headJoint, jointNew);
174  tailJoint->setParent(jointNew, *skeleton);
175 
176  //set position in refPose
177  Skeleton::Pose* refPose = skeleton->referencePose();
178  refPose->setGlobalTranslation(
179  jointNew->id(),
180  0.5 * refPose->globalTranslation(headJoint->id()) + 0.5
181  * refPose->globalTranslation(tailJoint->id()));
182 
183  //set position in animations
184  for (unsigned int a = 0; a < skeleton->animationCount(); a++)
185  if (AnimationHandle(a, 0).isValid()) {
186 
187  AnimationT<ACG::Vec3d> *animation = skeleton->animation(
188  AnimationHandle(a, 0));
189 
190  if (animation != 0) {
191 
192  //set initial joint translation
193  for (int iFrame = 0; iFrame < (int) animation->frameCount(); iFrame++) {
194 
195  PoseT<ACG::Vec3d>* pose = skeleton->pose(AnimationHandle(a, iFrame));
196 
197  pose->setGlobalMatrix(jointNew->id(),
198  pose->globalMatrix(headJoint->id()));
199  pose->setGlobalTranslation(
200  jointNew->id(),
201  0.5 * pose->globalTranslation(headJoint->id()) + 0.5
202  * pose->globalTranslation(tailJoint->id()));
203  }
204  }
205  }
206 
207  emit updatedObject(_objectId, UPDATE_GEOMETRY);
208 
209  emit scriptInfo("splitBone( ObjectId, " + QString::number(_tailJoint) + " )");
210 
211  // Create backup
212  emit createBackup(_objectId, "Split Bone", UPDATE_TOPOLOGY);
213 }
214 
215 //------------------------------------------------------------------------------
216 
218 void SkeletonEditingPlugin::addJoint(int _objectId, int _parent,
219  Vector _position) {
220 
221  BaseObjectData* baseObject = 0;
222  PluginFunctions::getObject(_objectId, baseObject);
223 
224  if (baseObject == 0)
225  return;
226 
227  Skeleton* skeleton = PluginFunctions::skeleton(baseObject);
228 
229  if (skeleton == 0)
230  return;
231 
232  Skeleton::Joint* parent = skeleton->joint(_parent);
233 
234  if (parent == 0) {
235  emit log(
236  LOGERR,
237  tr("Cannot add joint. Unable to find joint with id ")
238  + QString::number(_parent));
239  return;
240  }
241 
242  //add the new joint
243  Skeleton::Joint* jointNew = new Skeleton::Joint(parent);
244  skeleton->addJoint(parent, jointNew);
245 
246  //set the position
247 
248  setJointPosition(PluginFunctions::skeletonObject(baseObject), jointNew,
249  _position);
250  emit updatedObject(_objectId, UPDATE_ALL);
251 
252  emit scriptInfo(
253  "addJoint( ObjectId, " + QString::number(_parent) + ", Vector("
254  + QString::number(_position[0]) + "," + QString::number(_position[1])
255  + "," + QString::number(_position[2]) + ") )");
256 
257  // Create backup
258  emit createBackup(_objectId, "Add Joint", UPDATE_TOPOLOGY);
259 }
260 
261 //------------------------------------------------------------------------------
262 
264 void SkeletonEditingPlugin::deleteJoint(int _objectId, int _jointId) {
265 
266  BaseObjectData* baseObject = 0;
267  PluginFunctions::getObject(_objectId, baseObject);
268 
269  if (baseObject == 0)
270  return;
271 
272  Skeleton* skeleton = PluginFunctions::skeleton(baseObject);
273 
274  if (skeleton == 0)
275  return;
276 
277  Skeleton::Joint* joint = skeleton->joint(_jointId);
278 
279  if (joint == 0) {
280  emit log(
281  LOGERR,
282  tr("Cannot Remove joint. Unable to find joint with id ")
283  + QString::number(_jointId));
284  return;
285  }
286 
287  skeleton->removeJoint(joint);
288 
289  emit scriptInfo("deleteJoint( ObjectId, " + QString::number(_jointId) + " )");
290 
291  // Create backup
292  emit createBackup(_objectId, "Delete Joint", UPDATE_TOPOLOGY);
293 
294  emit updatedObject(_objectId, UPDATE_ALL);
295 }
296 
297 //------------------------------------------------------------------------------
298 
300 void SkeletonEditingPlugin::transformJoint(int _objectId, int _jointId,
301  Matrix4x4 _matrix) {
302 
303  BaseObjectData* obj = 0;
304 
305  PluginFunctions::getObject(_objectId, obj);
306 
307  if (obj == 0) {
308  emit log(LOGERR, tr("Unable to get object"));
309  return;
310  }
311 
313 
314  if (skeletonObj == 0) {
315  emit log(LOGERR, tr("Unable to get skeletonObject"));
316  return;
317  }
318 
319  Skeleton* skeleton = PluginFunctions::skeleton(obj);
320 
321  if (skeleton == 0) {
322  emit log(LOGERR, tr("Unable to get skeleton"));
323  return;
324  }
325 
326  Skeleton::Joint* joint = skeleton->joint(_jointId);
327 
328  if (joint == 0) {
329  emit log(LOGERR, tr("Unable to get joint"));
330  return;
331  }
332 
333  bool recursiveJointTransformation = transformChildJoints_;
334 
335  AnimationHandle handle = skeletonObj->skeletonNode()->activePose();
336 
337  Skeleton::Pose* activePose;
338 
339  if (!handle.isValid()) { // reference pose
340  activePose = skeleton->referencePose();
341  } else { // animation pose
342 
343  activePose = skeleton->animation(handle.animationIndex())->pose(
344  handle.frame());
345 
346  //always transform children otherwise only the local coordsys is rotated
347  recursiveJointTransformation = true;
348 
349  // translation changes the skeleton structure
350  // this is only allowed in refPose therefore delete translation
351  Matrix4x4 mat = _matrix;
352  mat(0, 3) = 0.0;
353  mat(1, 3) = 0.0;
354  mat(2, 3) = 0.0;
355  if (mat.is_identity())
356  _matrix = mat;
357  }
358 
359  SkeletonTransform transformer(*skeleton);
360 
361  if (handle.isValid()) { // animation pose
362 
363  //we are in an animation pose -> only rotation allowed
364  transformer.rotateJoint(joint, activePose, _matrix, transformAllFrames_);
365 
366  //update the skin
367  bool exists = false;
368 
369  emit functionExists("skeletalanimation", "updateSkin()", exists);
370 
371  if (exists)
372  RPC::callFunction("skeletalanimation", "updateSkin");
373 
374  } else { // reference pose
375 
376  // full transformation
377  if (_matrix(0, 0) != 1 || _matrix(1, 1) != 1 || _matrix(2, 2) != 1
378  || _matrix(0, 1) != 0 || _matrix(0, 2) != 0 || _matrix(1, 0) != 0
379  || _matrix(1, 2) != 0 || _matrix(2, 0) != 0 || _matrix(2, 1) != 0) {
380  // apply full transformation
381  transformer.transformJoint(joint, _matrix, !recursiveJointTransformation);
382 
383  } else { // translation only
384 
385  if (_matrix(0, 3) == 0 && _matrix(1, 3) == 0 && _matrix(2, 3) == 0) // no translation
386  return;
387 
388  if (joint->isRoot()) {
389 
390  /*
391  * Change translation of root joint.
392  */
393 
394  transformer.translateJoint(joint, ACG::Vec3d(_matrix(0, 3), _matrix(1, 3), _matrix(2, 3)), !transformChildJoints_);
395 
396  } else {
397 
398  /*
399  * Change translation of non-root joint.
400  *
401  * In these cases, the rotation of the coordinate frame of the parent
402  * joint (unless it is not a branching joint) as well as the
403  * the rotation of the coordinate frame of the current joint have to be
404  * corrected in the following way:
405  *
406  * We compute the rotation of the affected joints' coordinate system
407  * such that the local(!) translation of the respective child
408  * joint remains constant. So, in 2D, consider configuration
409  * A --> B --> C, where C is a child of B is a child of A.
410  * If C has translation (2, 0) and B has translation (3,5), then, after
411  * global translation of B, the coordinate frames of A and B have to be rotated
412  * such that the joint axes remain constant, so B lies on the line (0,0) + x*(3,5)
413  * with respect to A's coordinate system and C lies somewhere on the line (0,0) + y*(2,0)
414  * with respect to B's coordinate system.
415  *
416  */
417 
418  // init params
419  bool parentIsNotBranch = (joint->parent()->size() == 1);
420  bool hasOneChild = (joint->size() == 1);
421  ACG::Vec3d oldParentAxis(0.0, 0.0, 0.0);
422  ACG::Vec3d oldJointAxis(0.0, 0.0, 0.0);
423  ACG::Vec3d transParentAxis(0.0, 0.0, 0.0);
424  ACG::Vec3d transJointAxis(0.0, 0.0, 0.0);
425  ACG::Vec3d parentRotAxis(0.0, 0.0, 0.0);
426  ACG::Vec3d jointRotAxis(0.0, 0.0, 0.0);
427  double parentRotAngle = 0.0;
428  double jointRotAngle = 0.0;
429 
430  // get the original parent axis: parent joint -----> current joint
431  oldParentAxis = activePose->localTranslation(_jointId);
432  // get the original joint axis: current joint -----> child joint
433  if (hasOneChild)
434  oldJointAxis = activePose->localTranslation(joint->child(0)->id());
435 
436  // store the joint axes of all animations before the translation of the current joint
437  // so that the rotations can be calculated for the animation poses
438  std::vector<ACG::Vec3d> oldAnimJoint, oldAnimParent;
439  for (unsigned int a = 0; a < skeleton->animationCount(); ++a) {
440  for (unsigned int iFrame = 0; iFrame < skeleton->animation(a)->frameCount(); iFrame++) {
441  Skeleton::Pose* pose = skeleton->animation(a)->pose(iFrame);
442 
443  if (hasOneChild)
444  oldAnimJoint.push_back(pose->localTranslation(joint->child(0)->id()));
445 
446  oldAnimParent.push_back(pose->localTranslation(_jointId));
447  }
448  }
449 
450  // translate the joint
451  transformer.translateJoint(joint, ACG::Vec3d(_matrix(0, 3), _matrix(1, 3), _matrix(2, 3)), !transformChildJoints_);
452 
453  // get translated parent axis
454  transParentAxis = activePose->localTranslation(_jointId);
455 
456  if (hasOneChild) {
457  // get translated joint axis
458  transJointAxis = activePose->localTranslation(joint->child(0)->id());
459  }
460 
461  // now calculate the rotation that has to occur for a translation of the joint:
462 
463  // get the rotation axis and angle between the old and new parent axis
464  if (!ACG::Geometry::rotationOfTwoVectors<double>(oldParentAxis, transParentAxis, parentRotAxis, parentRotAngle))
465  return;
466 
467  // get rotation axis and angle between old and new joint axis
468  if (hasOneChild) {
469  if (!ACG::Geometry::rotationOfTwoVectors<double>(oldJointAxis, transJointAxis, jointRotAxis, jointRotAngle))
470  return;
471  }
472 
473  if (parentIsNotBranch) {
474  // parent rotation matrix
475  ACG::GLMatrixT<double> parentRotMatrix;
476  parentRotMatrix.identity();
477  parentRotMatrix.rotate(parentRotAngle, parentRotAxis);
478 
479  // apply rotation to parent joint
480  ACG::Matrix4x4d localParent = activePose->localMatrix(joint->parent()->id());
481  localParent *= parentRotMatrix;
482  activePose->setLocalMatrix(joint->parent()->id(), localParent, false);
483  }
484 
485  if (hasOneChild) {
486  // joint rotation matrix
487  ACG::GLMatrixT<double> jointRotMatrix;
488  jointRotMatrix.identity();
489  jointRotMatrix.rotate(jointRotAngle, jointRotAxis);
490 
491  // apply current joint
492  ACG::Matrix4x4d localJoint = activePose->localMatrix(joint->id());
493  localJoint *= jointRotMatrix;
494  activePose->setLocalMatrix(joint->id(), localJoint, false);
495  }
496 
497  // apply rotations to animation
498  std::vector<ACG::Vec3d>::iterator jointIt, parentIt;
499  jointIt = oldAnimJoint.begin();
500  parentIt = oldAnimParent.begin();
501  for (unsigned int a = 0; a < skeleton->animationCount(); ++a) {
502  for (unsigned int iFrame = 0; iFrame < skeleton->animation(a)->frameCount(); iFrame++) {
503  Skeleton::Pose* pose = skeleton->animation(a)->pose(iFrame);
504 
505  // only apply rotation to parent joint if it is not a branch
506  if (parentIsNotBranch) {
507 
508  // get the rotation axis and angle between the old and new parent axis
509  ACG::Vec3d translatedParent = pose->localTranslation(_jointId);
510  ACG::Vec3d parentRotAxis(0.0, 0.0, 0.0);
511  double parentRotAngle = 0.0;
512  if (!ACG::Geometry::rotationOfTwoVectors<double>(*parentIt, translatedParent, parentRotAxis,
513  parentRotAngle))
514  return;
515 
516  // parent rotation matrix
517  ACG::GLMatrixT<double> parentRotMatrix;
518  parentRotMatrix.identity();
519  parentRotMatrix.rotate(parentRotAngle, parentRotAxis);
520 
521  // apply rotation to parent joint
522  ACG::Matrix4x4d parentMat = pose->localMatrix(joint->parent()->id());
523  parentMat *= parentRotMatrix;
524  pose->setLocalMatrix(joint->parent()->id(), parentMat, false);
525 
526  ++parentIt;
527  }
528 
529  if (hasOneChild) {
530  // get rotation axis and angle between old and new joint axis
531  ACG::Vec3d translatedAxis = pose->localTranslation(joint->child(0)->id());
532  ACG::Vec3d jointRotAxis(0.0, 0.0, 0.0);
533  double jointRotAngle = 0.0;
534 
535  if (!ACG::Geometry::rotationOfTwoVectors<double>(*jointIt, translatedAxis, jointRotAxis, jointRotAngle))
536  return;
537 
538  // joint rotation matrix
539  ACG::GLMatrixT<double> jointRotMatrix;
540  jointRotMatrix.identity();
541  jointRotMatrix.rotate(jointRotAngle, jointRotAxis);
542 
543  // apply rotation to current joint
544  ACG::Matrix4x4d localMat = pose->localMatrix(joint->id());
545  localMat *= jointRotMatrix;
546  pose->setLocalMatrix(joint->id(), localMat, false);
547 
548  ++jointIt;
549  }
550  }
551  }
552  }
553  }
554  }
555 
556  emit updatedObject(_objectId, UPDATE_GEOMETRY);
557 
558  QString matString;
559  for (int i = 0; i < 4; i++)
560  for (int j = 0; j < 4; j++)
561  matString += " , " + QString::number(_matrix(i, j));
562 
563  matString = matString.right(matString.length() - 3);
564 
565  emit scriptInfo(
566  "transformJoint( ObjectId, " + QString::number(_jointId) + ", Matrix4x4("
567  + matString + " ) )");
568 
569  // Create backup if there was a change
570  // the backup is only created when the slot is called via scripting (sender == 0)
571  if (!_matrix.is_identity() && (sender() == 0))
572  emit createBackup(_objectId, "Joint Transformation", UPDATE_GEOMETRY);
573 }
574 
575 //------------------------------------------------------------------------------
576 
578 Matrix4x4 SkeletonEditingPlugin::globalMatrix(int _objectId, int _jointId) {
579 
580  BaseObjectData* obj = 0;
581 
582  PluginFunctions::getObject(_objectId, obj);
583 
584  if (obj == 0) {
585  emit log(LOGERR, tr("Unable to get object"));
586  return Matrix4x4();
587  }
588 
590 
591  if (skeletonObj == 0) {
592  emit log(LOGERR, tr("Unable to get skeletonObject"));
593  return Matrix4x4();
594  }
595 
596  Skeleton* skeleton = PluginFunctions::skeleton(obj);
597  Skeleton::Joint* joint = skeleton->joint(_jointId);
598 
599  if (joint == 0) {
600  emit log(LOGERR, tr("Unable to get joint"));
601  return Matrix4x4();
602  }
603 
604  AnimationHandle handle = skeletonObj->skeletonNode()->activePose();
605 
606  Skeleton::Pose* activePose;
607 
608  if (!handle.isValid())
609  activePose = skeleton->referencePose();
610  else
611  activePose = skeleton->animation(handle.animationIndex())->pose(
612  handle.frame());
613 
614  emit
615  scriptInfo("globalMatrix( ObjectId, " + QString::number(_jointId) + " )");
616  return activePose->globalMatrix(joint->id());
617 }
618 
619 //------------------------------------------------------------------------------
620 
622 Matrix4x4 SkeletonEditingPlugin::localMatrix(int _objectId, int _jointId) {
623 
624  BaseObjectData* obj = 0;
625 
626  PluginFunctions::getObject(_objectId, obj);
627 
628  if (obj == 0) {
629  emit log(LOGERR, tr("Unable to get object"));
630  return Matrix4x4();
631  }
632 
634 
635  if (skeletonObj == 0) {
636  emit log(LOGERR, tr("Unable to get skeletonObject"));
637  return Matrix4x4();
638  }
639 
640  Skeleton* skeleton = PluginFunctions::skeleton(obj);
641  Skeleton::Joint* joint = skeleton->joint(_jointId);
642 
643  if (joint == 0) {
644  emit log(LOGERR, tr("Unable to get joint"));
645  return Matrix4x4();
646  }
647 
648  AnimationHandle handle = skeletonObj->skeletonNode()->activePose();
649 
650  Skeleton::Pose* activePose;
651 
652  if (!handle.isValid())
653  activePose = skeleton->referencePose();
654  else
655  activePose = skeleton->animation(handle.animationIndex())->pose(
656  handle.frame());
657 
658  emit scriptInfo("localMatrix( ObjectId, " + QString::number(_jointId) + " )");
659  return activePose->localMatrix(joint->id());
660 }
661 
662 //------------------------------------------------------------------------------
663 
665 Vector SkeletonEditingPlugin::globalTranslation(int _objectId, int _jointId) {
666 
667  BaseObjectData* obj = 0;
668 
669  PluginFunctions::getObject(_objectId, obj);
670 
671  if (obj == 0) {
672  emit log(LOGERR, tr("Unable to get object"));
673  return Vector();
674  }
675 
677 
678  if (skeletonObj == 0) {
679  emit log(LOGERR, tr("Unable to get skeletonObject"));
680  return Vector();
681  }
682 
683  Skeleton* skeleton = PluginFunctions::skeleton(obj);
684  Skeleton::Joint* joint = skeleton->joint(_jointId);
685 
686  if (joint == 0) {
687  emit log(LOGERR, tr("Unable to get joint"));
688  return Vector();
689  }
690 
691  AnimationHandle handle = skeletonObj->skeletonNode()->activePose();
692 
693  Skeleton::Pose* activePose;
694 
695  if (!handle.isValid())
696  activePose = skeleton->referencePose();
697  else
698  activePose = skeleton->animation(handle.animationIndex())->pose(
699  handle.frame());
700 
701  emit scriptInfo(
702  "globalTranslation( ObjectId, " + QString::number(_jointId) + " )");
703  return activePose->globalTranslation(joint->id());
704 }
705 
706 //------------------------------------------------------------------------------
707 
709 Vector SkeletonEditingPlugin::localTranslation(int _objectId, int _jointId) {
710 
711  BaseObjectData* obj = 0;
712 
713  PluginFunctions::getObject(_objectId, obj);
714 
715  if (obj == 0) {
716  emit log(LOGERR, tr("Unable to get object"));
717  return Vector();
718  }
719 
721 
722  if (skeletonObj == 0) {
723  emit log(LOGERR, tr("Unable to get skeletonObject"));
724  return Vector();
725  }
726 
727  Skeleton* skeleton = PluginFunctions::skeleton(obj);
728  Skeleton::Joint* joint = skeleton->joint(_jointId);
729 
730  if (joint == 0) {
731  emit log(LOGERR, tr("Unable to get joint"));
732  return Vector();
733  }
734 
735  AnimationHandle handle = skeletonObj->skeletonNode()->activePose();
736 
737  Skeleton::Pose* activePose;
738 
739  if (!handle.isValid())
740  activePose = skeleton->referencePose();
741  else
742  activePose = skeleton->animation(handle.animationIndex())->pose(
743  handle.frame());
744 
745  emit scriptInfo(
746  "localTranslation( ObjectId, " + QString::number(_jointId) + " )");
747  return activePose->localTranslation(joint->id());
748 }
749 
750 //------------------------------------------------------------------------------
751 
754 
755  BaseObjectData* obj = 0;
756 
757  PluginFunctions::getObject(_objectId, obj);
758 
759  if (obj == 0) {
760  emit log(LOGERR, tr("Unable to get object"));
761  return -1;
762  }
763 
765 
766  if (skeletonObj == 0) {
767  emit log(LOGERR, tr("Unable to get skeletonObject"));
768  return -1;
769  }
770 
771  Skeleton* skeleton = PluginFunctions::skeleton(obj);
772 
773  emit scriptInfo("animationCount( ObjectId )");
774  return skeleton->animationCount();
775 }
776 
777 //------------------------------------------------------------------------------
778 
780 int SkeletonEditingPlugin::frameCount(int _objectId, int _animationIndex) {
781 
782  BaseObjectData* obj = 0;
783 
784  PluginFunctions::getObject(_objectId, obj);
785 
786  if (obj == 0) {
787  emit log(LOGERR, tr("Unable to get object"));
788  return -1;
789  }
790 
792 
793  if (skeletonObj == 0) {
794  emit log(LOGERR, tr("Unable to get skeletonObject"));
795  return -1;
796  }
797 
798  Skeleton* skeleton = PluginFunctions::skeleton(obj);
799 
800  if ((_animationIndex < 0) || (_animationIndex
801  > (int) skeleton->animationCount())) {
802  emit log(LOGERR, tr("Invalid animationIndex"));
803  return -1;
804  }
805 
806  emit scriptInfo(
807  "frameCount( ObjectId, " + QString::number(_animationIndex) + " )");
808  return skeleton->animation(_animationIndex)->frameCount();
809 }
810 
811 //------------------------------------------------------------------------------
812 
815 
816  BaseObjectData* obj = 0;
817 
818  PluginFunctions::getObject(_objectId, obj);
819 
820  if (obj == 0) {
821  emit log(LOGERR, tr("Unable to get object"));
822  return -1;
823  }
824 
826 
827  if (skeletonObj == 0) {
828  emit log(LOGERR, tr("Unable to get skeletonObject"));
829  return -1;
830  }
831 
832  AnimationHandle handle = skeletonObj->skeletonNode()->activePose();
833 
834  emit scriptInfo("activeAnimation( ObjectId )");
835  return handle.animationIndex();
836 }
837 
838 //------------------------------------------------------------------------------
839 
842  BaseObjectData* obj = 0;
843 
844  PluginFunctions::getObject(_objectId, obj);
845 
846  if (obj == 0) {
847  emit log(LOGERR, tr("Unable to get object"));
848  return -1;
849  }
850 
852 
853  if (skeletonObj == 0) {
854  emit log(LOGERR, tr("Unable to get skeletonObject"));
855  return -1;
856  }
857 
858  AnimationHandle handle = skeletonObj->skeletonNode()->activePose();
859 
860  emit scriptInfo("activeFrame( ObjectId )");
861  return handle.frame();
862 }
863 
864 //------------------------------------------------------------------------------
865 
867 void SkeletonEditingPlugin::setActivePose(int _objectId, int _animationIndex,
868  int _frame) {
869  BaseObjectData* obj = 0;
870 
871  PluginFunctions::getObject(_objectId, obj);
872 
873  if (obj == 0) {
874  emit log(LOGERR, tr("Unable to get object"));
875  return;
876  }
877 
879 
880  if (skeletonObj == 0) {
881  emit log(LOGERR, tr("Unable to get skeletonObject"));
882  return;
883  }
884 
885  Skeleton* skeleton = PluginFunctions::skeleton(obj);
886 
887  if ((_animationIndex < 0) || (_animationIndex
888  > (int) skeleton->animationCount())) {
889  emit log(LOGERR, tr("Invalid animationIndex"));
890  return;
891  }
892 
893  if ((_frame < 0) || (_frame
894  > (int) skeleton->animation(_animationIndex)->frameCount())) {
895  emit log(LOGERR, tr("Invalid frame"));
896  return;
897  }
898 
899  skeletonObj->skeletonNode()->setActivePose(
900  AnimationHandle(_animationIndex, _frame));
901  emit updatedObject(_objectId, UPDATE_GEOMETRY);
902 
903  emit scriptInfo(
904  "setActivePose( ObjectId, " + QString::number(_animationIndex) + ", "
905  + QString::number(_frame) + ")");
906 }
907 
908 //------------------------------------------------------------------------------
909 
911 void SkeletonEditingPlugin::addAnimation(int _objectId, QString _name,
912  int _frames) {
913  BaseObjectData* obj = 0;
914 
915  PluginFunctions::getObject(_objectId, obj);
916 
917  if (obj == 0) {
918  emit log(LOGERR, tr("Unable to get object"));
919  return;
920  }
921 
923 
924  if (skeletonObj == 0) {
925  emit log(LOGERR, tr("Unable to get skeletonObject"));
926  return;
927  }
928 
929  Skeleton* skeleton = PluginFunctions::skeleton(obj);
930 
931  if (_frames <= 0) {
932  emit log(LOGERR, tr("Invalid frame count"));
933  return;
934  }
935 
936  std::string stdName = _name.toStdString();
937 
938  if (skeleton->animation(stdName) != 0) {
939  emit log(LOGERR, tr("Animation with this name already exists"));
940  return;
941  }
942 
944  skeleton, _frames);
945  AnimationHandle handle = skeleton->addAnimation(stdName, animation);
946 
947  //init pose to refPose
948  for (unsigned int i = 0; i < skeleton->animation(handle)->frameCount(); i++) {
949  handle.setFrame(i);
950  Skeleton::Pose* pose = skeleton->pose(handle);
951 
952  for (unsigned int j = 0; j < skeleton->jointCount(); j++)
953  pose->setGlobalMatrix(j, skeleton->referencePose()->globalMatrix(j));
954  }
955 
956  emit updatedObject(_objectId, UPDATE_ALL);
957  emit scriptInfo(
958  "addAnimation( ObjectId, " + _name + ", " + QString::number(_frames)
959  + ")");
960 
961  // Create backup
962  emit createBackup(_objectId, "Add Animation", UPDATE_ALL);
963 }
964 
965 //------------------------------------------------------------------------------
void setDescriptions()
Set Descriptions for Scripting Slots.
void rotate(Scalar angle, Scalar x, Scalar y, Scalar z, MultiplyFrom _mult_from=MULT_FROM_RIGHT)
const UpdateType UPDATE_TOPOLOGY(UpdateTypeSet(8))
Topology updated.
unsigned int frameCount()
Returns the number of frames stored in this pose.
size_t animationIndex() const
Returns the animation index (zero based)
SkeletonObject * skeletonObject(BaseObjectData *_object)
Cast an BaseObject to a SkeletonObject if possible.
void setGlobalMatrix(unsigned int _joint, const Matrix &_global, bool _keepGlobalChildPositions=true)
Sets the global coordinate system.
Definition: PoseT_impl.hh:211
size_t id() const
returns the joint id
Definition: JointT_impl.hh:97
size_t size() const
Returns the number of children.
Definition: JointT_impl.hh:197
const UpdateType UPDATE_ALL(UpdateTypeSet(1))
Identifier for all updates.
void setGlobalTranslation(unsigned int _joint, const Vector &_position, bool _keepGlobalChildPositions=true)
Sets the global translation vector.
Definition: PoseT_impl.hh:249
void setActivePose(int _objectId, int _animationIndex, int _frame)
set active pose
QScriptValue callFunction(QString _plugin, QString _functionName, std::vector< QScriptValue > _parameters)
Call a function provided by a plugin getting multiple parameters.
Definition: RPCWrappers.cc:55
ACG::SceneGraph::SkeletonNodeT< Skeleton > * skeletonNode()
Returns the skeleton scenegraph node.
bool is_identity() const
check if the matrix is the identity ( up to an epsilon )
Definition: Matrix4x4T.hh:214
void transformJoint(int _objectId, int _jointId, Matrix4x4 _matrix)
transform joint with given matrix
void transformJoint(Skeleton::Joint *_joint, Matrix4x4 _matrix, bool _keepChildPositions=true)
apply a transformation to a joint in the refPose
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.
void removeJoint(typename SkeletonT< PointT >::Joint *_pJoint)
Remove the given joint from the tree.
Vector globalTranslation(int _objectId, int _jointId)
get global translation of a joint in the active pose
void identity()
setup an identity matrix
A general pose, used to store the frames of the animation.
Definition: PoseT.hh:58
Pose * pose(unsigned int _iFrame)
Returns a pointer to the pose stored in the given frame.
size_t frame() const
Returns the selected frame (zero based)
void addAnimation(int _objectId, QString _name, int _frames)
add animation
bool isValid() const
Returns true if the handle is valid.
const UpdateType UPDATE_GEOMETRY(UpdateTypeSet(4))
Geometry updated.
void setParent(Joint *_newParent, SkeletonT< PointT > &_skeleton)
access parent of the joint
Definition: JointT_impl.hh:122
int activeFrame(int _objectId)
get active frame
void addJoint(int _objectId, int _parent, Vector _position)
add joint to the skeleton
Skeleton transformation class.
ACG::Vec3d Vector
Standard Type for 3d Vector used for scripting.
Definition: DataTypes.hh:176
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
Matrix4x4 globalMatrix(int _objectId, int _jointId)
get global matrix of a joint in the active pose
int animationCount(int _objectId)
get the number of animations
Skeleton * skeleton(BaseObjectData *_object)
Get a skeleton from an object.
Vector localTranslation(int _objectId, int _jointId)
get local translation of a joint in the active pose
Pose * pose(const AnimationHandle &_hAni)
Returns a pointer to the pose with the given animation handle.
Joint * child(size_t _index)
Returns the child joint with the given index.
Definition: JointT_impl.hh:211
void splitBone(int _objectId, int _tailJoint)
insert a joint in the middle of a bone given by its (unique) tailJoint
Matrix4x4 localMatrix(int _objectId, int _jointId)
get local matrix of a joint in the active pose
int frameCount(int _objectId, int _animationIndex)
get the number of frames
void translateJoint(Skeleton::Joint *_joint, ACG::Vec3d _translation, bool _keepChildPositions=true)
apply a translation to a joint in the refPose
ACG::Matrix4x4d Matrix4x4
Standard Type for a 4x4 Matrix used for scripting.
Definition: DataTypes.hh:183
virtual void functionExists(QString _pluginName, QString _functionName, bool &_exists)
Definition: RPCInterface.hh:83
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 activeAnimation(int _objectId)
get active animation
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
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