Developer Documentation
SkeletonEditingPlugin.cc
1 /*===========================================================================*\
2 * *
3 * OpenFlipper *
4  * Copyright (c) 2001-2015, RWTH-Aachen University *
5  * Department of Computer Graphics and Multimedia *
6  * All rights reserved. *
7  * www.openflipper.org *
8  * *
9  *---------------------------------------------------------------------------*
10  * This file is part of OpenFlipper. *
11  *---------------------------------------------------------------------------*
12  * *
13  * Redistribution and use in source and binary forms, with or without *
14  * modification, are permitted provided that the following conditions *
15  * are met: *
16  * *
17  * 1. Redistributions of source code must retain the above copyright notice, *
18  * this list of conditions and the following disclaimer. *
19  * *
20  * 2. Redistributions in binary form must reproduce the above copyright *
21  * notice, this list of conditions and the following disclaimer in the *
22  * documentation and/or other materials provided with the distribution. *
23  * *
24  * 3. Neither the name of the copyright holder nor the names of its *
25  * contributors may be used to endorse or promote products derived from *
26  * this software without specific prior written permission. *
27  * *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39 * *
40 \*===========================================================================*/
41 
42 /*===========================================================================*\
43 * *
44 * $Revision$ *
45 * $LastChangedBy$ *
46 * $Date$ *
47 * *
48 \*===========================================================================*/
49 
50 #include "SkeletonEditingPlugin.hh"
51 
53 #include <ObjectTypes/Skeleton/BaseSkin.hh>
54 #include <ObjectTypes/Skeleton/SkeletonObjectData.hh>
55 #include <ACG/Geometry/Algorithms.hh>
56 //--------------------------------------------------------------------------------
57 
62  toolbar_(0),
63  toolBarActions_(0),
64  skeletonEditingAction_(0),
65  pickToolbar_(0),
66  pickToolBarActions_(0),
67  selectJointAction_(0),
68  insertJointAction_(0),
69  splitJointAction_(0),
70  deleteJointAction_(0),
71  moveJointAction_(0),
72  transformChildManipAction_(0),
73  transformAllManipAction_(0),
74  rotateManipAction_(0),
75  inverseKinematicAction_(0),
76 
77  currentSkeleton_(-1),
78  currentJoint_(-1),
79  jointPreview_(false),
80  transformChildJoints_(false),
81  transformAllFrames_(true),
82  inverseKinematic_(false),
83  dblClick_(false),
84  lastRenderer_(""),
85  rendererChanged_(false),
86  manip_size_(1.0),
87  manip_size_modifier_(1.0)
88 
89 {
90 }
91 
92 //--------------------------------------------------------------------------------
93 
98 {
99 
100 }
101 
102 
103 /*******************************************************************************
104  BaseInterface implementation
105  *******************************************************************************/
106 
111 
112  emit addHiddenPickMode("MoveJoints");
113  emit addHiddenPickMode("DeleteJoints");
114  emit addHiddenPickMode("InsertJoints");
115  emit addHiddenPickMode("SplitJoints");
116  emit addHiddenPickMode("SelectJoints");
117  emit setPickModeMouseTracking ("MoveJoints", true);
118  emit setPickModeMouseTracking ("InsertJoints", true);
119 
120  //KEYS
121  emit registerKey (Qt::Key_Shift, Qt::ShiftModifier, tr("Manipulator rotation"), true);
122  emit registerKey (Qt::Key_Shift, Qt::NoModifier, tr("Manipulator rotation"), true);
123 
124  //TOOLBAR
125  toolbar_ = new QToolBar(tr("Skeleton Editing"));
126  toolbar_->setObjectName("Skeleton_Editing_Toolbar");
127 
128 
129  toolBarActions_ = new QActionGroup(toolbar_);
130 
131  WhatsThisGenerator whatsThisGen("SkeletonEditing");
132  skeletonEditingAction_ = new QAction(tr("<B>Skeleton Editing</B><br>Modify the structure of a skeleton"), toolBarActions_);
133  skeletonEditingAction_->setStatusTip(tr("Modify the structure of a skeleton."));
134  skeletonEditingAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"skeleton_editing.png") );
135  whatsThisGen.setWhatsThis(skeletonEditingAction_,tr("Skeleton Editing"));
136  skeletonEditingAction_->setCheckable(true);
137  toolbar_->addAction(skeletonEditingAction_);
138 
139  connect(toolBarActions_, SIGNAL(triggered(QAction*)), this, SLOT(slotSetEditingMode(QAction*)) );
140 
141  emit addToolbar(toolbar_);
142 
143  pickToolbar_ = new QToolBar(tr("Skeleton Editing"));
144  pickToolbar_->setAttribute(Qt::WA_AlwaysShowToolTips, true);
145  pickToolbar_->setObjectName("Skeleton_Editing_Picking_Toolbar");
146  pickToolBarActions_ = new QActionGroup(pickToolbar_);
147  pickToolBarActions_->setExclusive (false);
148 
149  selectJointAction_ = new QAction(tr("<B>Select Joint</B><br>Toggle joint selection"), pickToolBarActions_);
150  selectJointAction_->setStatusTip(tr("Toggle the selection state of a joint."));
151  selectJointAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"skeleton_selectJoint.png") );
152  selectJointAction_->setCheckable(true);
153  whatsThisGen.setWhatsThis(selectJointAction_,tr("Select single joints of the skeleton. You can select multiple joints at once."), "manipulate_joint");
154  pickToolbar_->addAction(selectJointAction_);
155 
156  insertJointAction_ = new QAction(tr("<B>Insert Joint</B><br>Add a joint to the skeleton"), pickToolBarActions_);
157  insertJointAction_->setStatusTip(tr("<DoubleClick> to start a new skeleton and end joint path. <Click> to select parent and position for new joints."));
158  insertJointAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"skeleton_insertJoint.png") );
159  whatsThisGen.setWhatsThis(insertJointAction_,tr("Insert new joints. Click on a joint first and then click somewhere else, to add a new joint at the mouseposition. Double-click to finish adding joints."));
160  insertJointAction_->setCheckable(true);
161  pickToolbar_->addAction(insertJointAction_);
162 
163  splitJointAction_ = new QAction(tr("<B>Split Joint</B><br>Add a Joint between two other Joints"), pickToolBarActions_);
164  splitJointAction_->setStatusTip(tr("Click on a joint which will be the new child Joint."));
165  splitJointAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"skeleton_splitJoint.png") );
166  whatsThisGen.setWhatsThis(splitJointAction_,tr("Click on a joint to split it in the middle."), "manipulate_joint");
167  splitJointAction_->setCheckable(true);
168  pickToolbar_->addAction(splitJointAction_);
169 
170  deleteJointAction_ = new QAction(tr("<B>Delete Joint</B><br>Remove a joint from the skeleton"), pickToolBarActions_);
171  deleteJointAction_->setStatusTip(tr("<Press> to select a joint. <Release> to delete it."));
172  deleteJointAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"skeleton_deleteJoint.png") );
173  whatsThisGen.setWhatsThis(deleteJointAction_,tr("Delete a joint by clicking on it."), "manipulate_joint");
174  deleteJointAction_->setCheckable(true);
175  pickToolbar_->addAction(deleteJointAction_);
176 
177  moveJointAction_ = new QAction(tr("<B>Transform Joint</B><br>Transform a joint from the skeleton"), pickToolBarActions_);
178  moveJointAction_->setStatusTip(tr("Transform a joint from the skeleton."));
179  moveJointAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"skeleton_moveJoint.png") );
180  whatsThisGen.setWhatsThis(moveJointAction_,tr("Transform a joint (only possible in an animation). Click on a joint and transform his position and orientation with help of the manipulator"), "manipulate_joint");
181  moveJointAction_->setCheckable(true);
182  pickToolbar_->addAction(moveJointAction_);
183 
184  pickToolbar_->addSeparator();
185 
186  rotateManipAction_ = new QAction(tr("Rotate manipulator"), pickToolBarActions_);
187  rotateManipAction_->setStatusTip(tr("Rotate manipulator. <Shift>"));
188  rotateManipAction_->setToolTip(tr("<B>Rotate manipulator</B><br> Rotates only the manipulator, not the joints. <B>Shift</B>"));
189  rotateManipAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"skeleton_maniprotate.png") );
190  whatsThisGen.setWhatsThis(rotateManipAction_,tr("Rotate a joint (possible in an animation). Click on a joint and transform his orientation with help of the manipulator."),"manipulator");
191  rotateManipAction_->setCheckable(true);
192  pickToolbar_->addAction(rotateManipAction_);
193  connect(rotateManipAction_, SIGNAL(toggled(bool)), this, SLOT(slotRotateManipulator(bool)) );
194 
195  pickToolbar_->addSeparator();
196 
197  transformAllManipAction_ = new QAction(tr(""), pickToolBarActions_);
198  transformAllManipAction_->setStatusTip(tr("Apply the relative transformation to all frames of the animation."));
199  transformAllManipAction_->setToolTip(tr("<B>Transform whole animation</B><br>Transform all frames of the animation simultaneously."));
200  transformAllManipAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"skeleton_manipAllFrames.png") );
201  whatsThisGen.setWhatsThis(transformAllManipAction_,tr("Transform whole animation. Changing will be applied to all frames of the current animation"),"transformation_modi");
202  transformAllManipAction_->setCheckable(true);
203  transformAllManipAction_->setChecked(transformAllFrames_);
204  pickToolbar_->addAction(transformAllManipAction_);
205 
206  transformChildManipAction_ = new QAction(tr("Transform Child Joints"), pickToolBarActions_);
207  transformChildManipAction_->setStatusTip(tr("Apply joint transformation to child joints as well and thereby rigidly move the whole subtree."));
208  transformChildManipAction_->setToolTip(tr("<B>Transform child joints</B><br>Apply joint transformation to all child joints as well."));
209  transformChildManipAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"skeleton_manipChildTransform.png") );
210  whatsThisGen.setWhatsThis(transformChildManipAction_,tr("Apply your transformation to all child joints."),"transformation_modi");
211  transformChildManipAction_->setCheckable(true);
212  transformChildManipAction_->setChecked(transformChildJoints_);
213  pickToolbar_->addAction(transformChildManipAction_);
214 
215  inverseKinematicAction_ = new QAction(tr("Inverse kinematic"), pickToolBarActions_);
216  inverseKinematicAction_->setStatusTip(tr("Move selected joint using inverse kinematic."));
217  inverseKinematicAction_->setToolTip(tr("<B>Inverse kinematic</B><br>Move selected joint using inverse kinematic."));
218  inverseKinematicAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"skeleton_inverseKinematic.png") );
219  whatsThisGen.setWhatsThis(inverseKinematicAction_,tr("Move a joint to the position only with rotation of the previous joints."),"transformation_modi");
220  inverseKinematicAction_->setCheckable(true);
221  inverseKinematicAction_->setChecked(inverseKinematic_);
222  pickToolbar_->addAction(inverseKinematicAction_);
223 
224  connect(pickToolBarActions_, SIGNAL(triggered(QAction*)), this, SLOT(slotPickToolbarAction(QAction*)) );
225 
226  emit setPickModeToolbar("MoveJoints", pickToolbar_);
227  emit setPickModeToolbar("DeleteJoints", pickToolbar_);
228  emit setPickModeToolbar("InsertJoints", pickToolbar_);
229  emit setPickModeToolbar("SplitJoints", pickToolbar_);
230  emit setPickModeToolbar("SelectJoints", pickToolbar_);
231 
232  setDescriptions();
233 }
234 
235 //------------------------------------------------------------------------------
236 
237 void SkeletonEditingPlugin::slotObjectUpdated( int _id, const UpdateType& _type){
238 
239  if ( !_type.contains(UPDATE_GEOMETRY) )
240  return;
241 
242  for (uint i=0; i < activeManipulators_.size(); i++){
243 
244  if ( activeManipulators_[i] != _id )
245  continue;
246 
247  BaseObjectData* obj = 0;
248 
249  PluginFunctions::getObject( activeManipulators_[i], obj );
250 
251  if (obj != 0 && obj->manipPlaced())
253  }
254 }
255 
256 /*******************************************************************************
257  ToolBoxInterface implementation
258  *******************************************************************************/
259 
260 void SkeletonEditingPlugin::initializePlugin()
261 {
262 
263 }
264 
265 
266 /*******************************************************************************
267  MouseInterface implementation
268  *******************************************************************************/
269 
270 void SkeletonEditingPlugin::slotMouseWheelEvent(QWheelEvent * _event, const std::string & /*_mode*/)
271 {
272  // Skip execution if this is not our pick mode
273  if( (PluginFunctions::pickMode() != "MoveJoints") || PluginFunctions::actionMode() != Viewer::PickingMode)
274  return;
275 
276  // compute the manipulator size modifier based on the mouse wheel change
277  manip_size_modifier_ = manip_size_modifier_ - (float)_event->delta() / 120.0 * 0.1;
278 
279  // Resize all manipulators based on the modifier on all objects
281  o_it->manipulatorNode()->set_size(manip_size_ * manip_size_modifier_);
282 
283  // Redraw scene with updated manipulators
284  emit updateView();
285 }
286 
287 //------------------------------------------------------------------------------
288 
293 bool SkeletonEditingPlugin::canModify(QMouseEvent* _event)
294 {
295  //if jointPreview_ is true, we could modify the skeleton
296  //so the skeleton is in reference pose
297  if (jointPreview_ || (PluginFunctions::pickMode() == ("InsertJoints") && _event->type() == QEvent::MouseButtonDblClick))
298  return true;
299 
300  // try to select a joint from which the insertion should be started
301  unsigned int node_idx, target_idx;
302  ACG::Vec3d hitPoint;
303  BaseObjectData* object;
304 
305  //disable picking for anything but skeletons
307  o_it->enablePicking( o_it->dataType(DATA_SKELETON) );
308 
309  //perform picking
310  bool successfullyPicked = PluginFunctions::scenegraphPick(ACG::SceneGraph::PICK_ANYTHING, _event->pos(), node_idx,
311  target_idx, &hitPoint) && PluginFunctions::getPickedObject(node_idx, object);
312 
313  //reenable picking for anything
315  o_it->enablePicking( true );
316 
317  if ( successfullyPicked )
318  {
319 
320  //check if the active pose is the reference pose
321  Skeleton* skeleton = PluginFunctions::skeleton( object );
322 
323  if ( !skeleton )
324  return false;
325 
326  if (activePose(PluginFunctions::skeletonObject(object)) == skeleton->referencePose())
327  return true;
328  else
329  return false;
330  }
331  else
332  return false;
333 }
334 
335 //------------------------------------------------------------------------------
336 
341 void SkeletonEditingPlugin::slotMouseEvent(QMouseEvent* _event) {
342 
343  if (PluginFunctions::actionMode() != Viewer::PickingMode)
344  return;
345 
346  if ( PluginFunctions::pickMode() == ("MoveJoints") )
347  moveJoint(_event);
348  else if ( PluginFunctions::pickMode() == ("SelectJoints") )
349  selectJoint(_event);
350  else if ( (( PluginFunctions::pickMode() == ("DeleteJoints")) ||
351  ( PluginFunctions::pickMode() == ("InsertJoints")) ||
352  ( PluginFunctions::pickMode() == ("SplitJoints") ) ) && canModify(_event) )
353  {
354  if ( PluginFunctions::pickMode() == ("DeleteJoints") )
355  deleteJoint(_event);
356  else if ( PluginFunctions::pickMode() == ("InsertJoints") )
357  insertJoint(_event);
358  else if (PluginFunctions::pickMode() == ("SplitJoints"))
359  splitJoint(_event);
360  }
361 
362 
363 }
364 
365 /*******************************************************************************
366  KeyInterface implementation
367  *******************************************************************************/
368 
369 void SkeletonEditingPlugin::slotKeyEvent (QKeyEvent* _event)
370 {
371  if (_event->key() == Qt::Key_Shift)
372  rotateManipAction_->setChecked(true);
373 }
374 
375 //------------------------------------------------------------------------------
376 
377 void SkeletonEditingPlugin::slotKeyReleaseEvent (QKeyEvent* _event)
378 {
379  if ( _event->key() == Qt::Key_Shift)
380  rotateManipAction_->setChecked(false);
381 }
382 
383 /*******************************************************************************
384  PickingInterface implementation
385  *******************************************************************************/
386 
391 void SkeletonEditingPlugin::slotPickModeChanged( const std::string& _mode)
392 {
393  if (_mode != "InsertJoints" )
394  if ( insertJointAction_->isChecked() )
395  cancelJointInsertion();
396 
397  moveJointAction_->setChecked( _mode == "MoveJoints" );
398  insertJointAction_->setChecked( _mode == "InsertJoints" );
399  deleteJointAction_->setChecked( _mode == "DeleteJoints" );
400  selectJointAction_->setChecked( _mode == "SelectJoints" );
401  splitJointAction_->setChecked( _mode == "SplitJoints" );
402 
403  skeletonEditingAction_->setChecked( (_mode == "MoveJoints") ||(_mode == "InsertJoints")
404  ||(_mode == "DeleteJoints")||(_mode == "SelectJoints")
405  || (_mode == "SplitJoints"));
406 
407  // We left the pickmodes, that are used for skeletonediting
408  // If the mode is "", we are in examine mode or anything else
409  // But we do not change the renderer than
410  if ( (_mode != "") &&
411  (_mode != "MoveJoints") &&
412  (_mode != "InsertJoints") &&
413  (_mode != "DeleteJoints") &&
414  (_mode != "SelectJoints") &&
415  (_mode != "SplitJoints")) {
416 
417  // Get the currently active renderer and switch to default one
418  QString currentRenderer;
419  emit getCurrentRenderer(PluginFunctions::activeExaminer(), currentRenderer);
420 
421  // If we still have the Depth peeling renderer, we switch back
422  // otherwise the user changed the active renderer and we do not override the setting
423  if ( rendererChanged_ && (currentRenderer == "Depth Peeling Renderer" ) ) {
425  rendererChanged_ = false;
426  }
427 
428 
429  }
430 
431 
433 }
434 
435 /*******************************************************************************
436  SkeletonEditingPlugin implementation
437  *******************************************************************************/
438 
439 void SkeletonEditingPlugin::slotPickToolbarAction(QAction* _action)
440 {
441  if (_action == rotateManipAction_)//in this case, enable the button and keep the rest as it is
442  return;
443 
444  if (_action != insertJointAction_)
445  if ( insertJointAction_->isChecked() )
446  cancelJointInsertion();
447 
448  if (_action == insertJointAction_){
449  PluginFunctions::actionMode(Viewer::PickingMode);
450  PluginFunctions::pickMode("InsertJoints");
451 
452  }else if (_action == splitJointAction_){
453  PluginFunctions::actionMode(Viewer::PickingMode);
454  PluginFunctions::pickMode("SplitJoints");
455 
456  }else if (_action == deleteJointAction_){
457  PluginFunctions::actionMode(Viewer::PickingMode);
458  PluginFunctions::pickMode("DeleteJoints");
459 
460  } else if (_action == moveJointAction_) {
461  PluginFunctions::actionMode(Viewer::PickingMode);
462  PluginFunctions::pickMode("MoveJoints");
463  } else if (_action == selectJointAction_) {
464  PluginFunctions::actionMode(Viewer::PickingMode);
465  PluginFunctions::pickMode("SelectJoints");
466 
467  }else if (_action == transformAllManipAction_)
468  transformAllFrames_ = transformAllManipAction_->isChecked();
469  else if (_action == transformChildManipAction_)
470  transformChildJoints_ = transformChildManipAction_->isChecked();
471  else if (_action == inverseKinematicAction_)
472  inverseKinematic_ = inverseKinematicAction_->isChecked();
473 
474  moveJointAction_->setChecked( _action == moveJointAction_ );
475  insertJointAction_->setChecked( _action == insertJointAction_ );
476  deleteJointAction_->setChecked( _action == deleteJointAction_ );
477  selectJointAction_->setChecked( _action == selectJointAction_ );
478  splitJointAction_->setChecked( _action == splitJointAction_ );
479 }
480 
481 //--------------------------------------------------------------------------------
482 
483 void SkeletonEditingPlugin::slotSetEditingMode(QAction* /*_action*/)
484 {
485 
486  if ( ! rendererChanged_ ) {
487 
488  // Get the currently active renderer and switch to default one
489  emit getCurrentRenderer(PluginFunctions::activeExaminer(), lastRenderer_);
490  emit setRenderer(PluginFunctions::activeExaminer(),"Depth Peeling Renderer");
491 
492  // remember, that we changed the active renderer in this plugin
493  // to prevent switching, if we did not do it
494  rendererChanged_ = true;
495  }
496 
497  PluginFunctions::actionMode(Viewer::PickingMode);
498  PluginFunctions::pickMode("MoveJoints");
499 }
500 
501 //--------------------------------------------------------------------------------
502 
503 void SkeletonEditingPlugin::slotRotateManipulator(bool _toggled)
504 {
506 
507  bool ourPickMode = (PluginFunctions::actionMode() == Viewer::PickingMode)
508  &&( ( PluginFunctions::pickMode() == ("DeleteJoints") )
509  ||( PluginFunctions::pickMode() == ("InsertJoints") )
510  ||( PluginFunctions::pickMode() == ("MoveJoints") )
511  ||( PluginFunctions::pickMode() == ("SelectJoints")
512  ||( PluginFunctions::pickMode() == ("SplitJoints"))));
513 
514  if (_toggled && ourPickMode){
515  mode = QtTranslationManipulatorNode::LocalRotation;
516  PluginFunctions::setViewObjectMarker (&objectMarker_);
517  } else {
518  mode = QtTranslationManipulatorNode::TranslationRotation;
520  }
521 
522  for (uint i=0; i < activeManipulators_.size(); i++){
523 
524  BaseObjectData* obj = 0;
525 
526  PluginFunctions::getObject( activeManipulators_[i], obj );
527 
528  if (obj != 0 && obj->manipPlaced())
529  obj->manipulatorNode()->setMode ( mode );
530  }
531 }
532 
533 //------------------------------------------------------------------------------
534 
539 void SkeletonEditingPlugin::placeManip(QMouseEvent * _event) {
540  unsigned int node_idx, target_idx;
541  OpenMesh::Vec3d hitPoint;
542  BaseObjectData* object;
543 
544  bool successfullyPicked = false;
545 
546  int data = -1;
547 
548  //disable picking for anything but skeletons
550  o_it->enablePicking( o_it->dataType(DATA_SKELETON) );
551 
552  //perform picking
553  successfullyPicked = PluginFunctions::scenegraphPick(ACG::SceneGraph::PICK_ANYTHING, _event->pos(), node_idx, target_idx, &hitPoint) &&
554  PluginFunctions::getPickedObject(node_idx, object);
555 
556  //reenable picking for anything
558  o_it->enablePicking( true );
559 
560  if ( successfullyPicked && object->dataType(DATA_SKELETON) ) {
561 
562  hitPoint = getNearestJoint(PluginFunctions::skeletonObject(object), hitPoint, data);
563 
565  }
566 
567  if (successfullyPicked) {
568 
569  object->manipPlaced(true);
570 
571  if (data != -1)
572  object->manipulatorNode()->setData( data );
573 
574  object->manipulatorNode()->loadIdentity();
575  object->manipulatorNode()->set_center(hitPoint);
576  object->manipulatorNode()->set_draw_cylinder(true);
577  object->manipulatorNode()->set_autosize(QtTranslationManipulatorNode::Once);
578  object->manipulatorNode()->set_size(manip_size_ * manip_size_modifier_);
579  object->manipulatorNode()->setMode( QtTranslationManipulatorNode::TranslationRotation );
580  object->manipulatorNode()->show();
581 
582  // Get the global matrix from the picked joint
583  Skeleton* skeleton = PluginFunctions::skeleton( object );
584  Skeleton::Joint* pickedJoint = skeleton->joint( data );
585  Skeleton::Pose* currentPose = activePose(PluginFunctions::skeletonObject(object));
586  const Matrix4x4 pickedGlobalMatrix = currentPose->globalMatrix(pickedJoint->id());
587 
588  // Orient the manipulator to be aligned with the joint coordinate system.
589  Vector x_axis = pickedGlobalMatrix.transform_vector(Vector(1.0, 0.0, 0.0));
590  Vector y_axis = pickedGlobalMatrix.transform_vector(Vector(0.0, 1.0, 0.0));
591 
592  object->manipulatorNode()->set_direction(x_axis,y_axis);
593  object->manipulatorNode()->enable_rotations(QtTranslationManipulatorNode::ALL_AXIS);
594 
595  object->manipulatorNode()->apply_transformation(false);
596 
597 
598  // Disconnect a previously connected Signal
599  disconnect(object->manipulatorNode() , SIGNAL(manipulatorMoved(QtTranslationManipulatorNode*,QMouseEvent*)),
600  this , SLOT( manipulatorMoved(QtTranslationManipulatorNode*,QMouseEvent*)));
601 
602  disconnect(object->manipulatorNode() , SIGNAL(positionChanged(QtTranslationManipulatorNode*)),
604 
605  // Reconnect the signals.
606  connect(object->manipulatorNode() , SIGNAL(manipulatorMoved(QtTranslationManipulatorNode*,QMouseEvent*)),
607  this , SLOT( manipulatorMoved(QtTranslationManipulatorNode*,QMouseEvent*)));
608 
609  connect(object->manipulatorNode() , SIGNAL(positionChanged(QtTranslationManipulatorNode*)),
611 
612  emit updateView();
613 
614  bool found = false;
615 
616  for (uint i=0; i < activeManipulators_.size(); i++)
617  if ( activeManipulators_[i] == object->id() ){
618  found = true;
619  break;
620  }
621 
622  if ( !found )
623  activeManipulators_.push_back( object->id() );
624 
625  }
626 }
627 //------------------------------------------------------------------------------
628 /*
629  * \brief move a joint using inverse Kinematic
630  * @param dest the new position of the joint
631  * @param currentPose the current pose in which the joint is moved
632  * @param pickedJoint your picked joint
633  * @param rotatbleJoints joints, which can be rotate. It has to be a ordered set in this order (picked,marked]. "picked" is our imaginary -1th element, his parent the 0th element and so on. "marked" is the last element. "marked"s matrix can rotate, but the "marked" will not be translated.
634  */
635 void SkeletonEditingPlugin::inverseKinematic(ACG::Vec3d dest,Skeleton::Pose* currentPose,Skeleton::Joint* pickedJoint, std::vector<Skeleton::Joint*> rotatableJoints)
636 {
637  //Now we can rotate every Joint in rotatableJoints
638  ACG::Vec3d pickedJointPos = currentPose->globalMatrix(pickedJoint->id()).transform_point(ACG::Vec3d(0.0,0.0,0.0));
639  for(std::size_t i = 5; i && pickedJointPos != dest; --i )
640  {
641 
642  //iterates through the skeleton from our picked joint to our fixed/root
643  for (std::vector<Skeleton::Joint*>::iterator iter = rotatableJoints.begin() ; iter != rotatableJoints.end(); ++iter)
644  {
645  const unsigned int currentId = (*iter)->id();
646 
647  //when we rotate to the false side
648  //we are going to compute a new angle
649  //it is more precise
650  int angleFac = -1;
651  bool rightRotation = true;
652  unsigned int tries = 0;//to be sure that we are terminate
653  do
654  {
655  //update the position of our picked Joint
656  pickedJointPos = currentPose->globalMatrix(pickedJoint->id()).transform_point(ACG::Vec3d(0.0,0.0,0.0));
657 
658  //get the position and the matrix of our current joint
659  const ACG::Matrix4x4d currentGlobalMatrix = currentPose->globalMatrix(currentId);
660  const ACG::Vec3d currentJointPos = currentGlobalMatrix.transform_point(ACG::Vec3d(0.0,0.0,0.0));
661 
662  ACG::Vec3d toDest = currentJointPos - dest; //distance from current to Destination
663  ACG::Vec3d toPickedJoint = currentJointPos - pickedJointPos;//distance from current to picked Joint
664 
665  //get angle of toDest and toPickedJoint
666  double theta = (double)angleFac*acos(dot(toPickedJoint ,toDest) / sqrt( toDest.sqrnorm() * toPickedJoint.sqrnorm()));
667 
668  if(theta != theta || theta == 0)//test nan
669  break;
670 
671  //get rotation matrix for theta and our rotation axis
672  ACG::Vec3d rotationAxis = cross(toDest,toPickedJoint);
673  ACG::Quaterniond quaternion(rotationAxis ,theta);
674 
675  ACG::Matrix4x4d changingMatrix = currentGlobalMatrix * quaternion.rotation_matrix();
676 
677  //set position and rotation of our currentJoint, so pickedJoint is moving to our destination
678  currentPose->setGlobalMatrix(currentId, changingMatrix, false);
679 
681  //test new position
682  //it is false, when the distance of pickedJoint and destination is far more away then before
683  ACG::Vec3d pickedJointPosOld = pickedJointPos;
684  pickedJointPos = currentPose->globalMatrix(pickedJoint->id()).transform_point(ACG::Vec3d(0.0,0.0,0.0));
685  //compare the distance of the old/new position
686  bool rightRotation = !( (pickedJointPos -dest).sqrnorm() > (pickedJointPosOld -dest).sqrnorm());
687 
688  if ( !rightRotation )
689  {
690  //not the right rotation? then rotate back and compute a new angle
691  ACG::Quaterniond quaternionBack(rotationAxis ,-theta);
692  ACG::Vec3d currentTranslation = currentPose->globalTranslation( currentId );
693 
694  //rotate back and compute our angle again
695  changingMatrix = currentGlobalMatrix * quaternionBack.rotation_matrix();
696 
697  currentPose->setGlobalMatrix(currentId, changingMatrix , false);
698  currentPose->setGlobalTranslation(currentId, currentTranslation, false);
699 
700  //compute angle again and this time, we try the other side for our rotation
701  ++tries;
702  angleFac *= 1;
703  }
704  }while( rightRotation && tries <= 5);
705  }
706  }
707 }
708 
709 //------------------------------------------------------------------------------
710 
717 
718  // React on event only in move mode
719  if ( PluginFunctions::pickMode() != "MoveJoints" )
720  return;
721 
722  OpenFlipper::Options::redrawDisabled( true );
723 
724  int objectId = _node->getIdentifier();
725 
726  // rotation matrix from the manipulator
727  ACG::Matrix4x4d mat;
728  mat.identity();
729  mat = _node->matrix();
730 
731  BaseObjectData* object = 0;
732  PluginFunctions::getObject(objectId, object);
733 
734  if(inverseKinematic_)
735  {
736  Skeleton* skeleton = PluginFunctions::skeleton( object );
737  SkeletonObject* skeletonObj = PluginFunctions::skeletonObject(object);
738 
739  if (!skeleton || !skeletonObj)
740  return;
741 
742  Skeleton::Joint* pickedJoint = skeleton->joint( _node->getData().toInt() );
743 
744  if (!pickedJoint)
745  return;
746 
747  Skeleton::Pose* currentPose = activePose(PluginFunctions::skeletonObject(object));
748 
749  const Matrix4x4 pickedGlobalMatrix = currentPose->globalMatrix(pickedJoint->id());
750 
751  //get our destination
752  const ACG::Vec3d dest = (mat*pickedGlobalMatrix).transform_point( ACG::Vec3d(0.0,0.0,0.0) );
753 
754  if (pickedJoint->isRoot())
755  {
756  //we have no fixed points, when we pick our root
757  currentPose->setGlobalTranslation(pickedJoint->id(), dest, false);
758  }
759  else
760  {
761  //get all Parent Joints (picked,fixed]
762  std::vector<Skeleton::Joint*> rotatableJoints;
763 
764  Skeleton::Iterator iter = pickedJoint->parent();
765 
766  //go from our picked Joint and find the first fixed/root Joint
767  for (;iter && !iter->selected() && !iter->isRoot(); iter = iter->parent())
768  rotatableJoints.push_back(*iter);
769 
770  if (iter)
771  rotatableJoints.push_back(*iter); //save the fixed/root Joint, because he can rotate
772  else
773  return;
774 
775  inverseKinematic(dest, currentPose, pickedJoint, rotatableJoints);
776 
777  if (transformAllFrames_ && _event->type() == QEvent::MouseButtonRelease)
778  for (std::vector<Skeleton::Joint*>::iterator iter = rotatableJoints.begin() ; iter != rotatableJoints.end(); ++iter)
779  {
780  ACG::Vec3d position = currentPose->globalTranslation((*iter)->id());
781  setJointPosition(skeletonObj,*iter,position);
782  }
783  }
784  //update
785  emit updatedObject(objectId, UPDATE_GEOMETRY);
786  }
787  else
788  transformJoint( objectId, _node->getData().toInt(), mat );
789 
790  // Reset Node
791  _node->loadIdentity();
792  _node->set_center(mat.transform_point(_node->center()));
793 
794 
795  if (_event->type() == QEvent::MouseButtonPress)
796  accumMatrix_.identity();
797 
798  accumMatrix_ *= mat;
799 
800  //only backup on mouseRelease
801  if ( (_event->type() == QEvent::MouseButtonRelease) && !accumMatrix_.is_identity() )
802  emit createBackup(objectId, "Joint Transformation", UPDATE_GEOMETRY);
803 
804  if ( object != 0)
805  //check if there is a skin which has to be deformed
806  if ( object->hasObjectData(OBJECTDATA_SKELETON) ){
807 
808  SkeletonObjectData* skeletonData = reinterpret_cast< SkeletonObjectData* >( object->objectData(OBJECTDATA_SKELETON) );
809 
810  AnimationHandle hAni = PluginFunctions::skeletonObject(object)->activePose();
811 
812  for (unsigned int i=0; i < skeletonData->skinCount(); i++){
813  //deform all attached skin meshes
814  int meshId = skeletonData->skin(i);
815 
816  BaseObjectData* meshObject = 0;
817  PluginFunctions::getObject(meshId, meshObject);
818 
819  if (meshObject == 0)
820  continue;
821 
822  if ( !meshObject->hasObjectData(OBJECTDATA_SKIN) )
823  continue;
824 
825  BaseSkin* skin = reinterpret_cast< BaseSkin* > ( meshObject->objectData(OBJECTDATA_SKIN) );
826  skin->deformSkin( hAni, BaseSkin::M_LBS );
827 
828  emit updatedObject(meshObject->id(), UPDATE_GEOMETRY);
829  }
830  }
831 
832  if (_event->type() == QEvent::MouseButtonRelease)
833  emit updatedObject(objectId, UPDATE_GEOMETRY);
834 
835  OpenFlipper::Options::redrawDisabled( false );
836 }
837 
838 
839 //------------------------------------------------------------------------------
840 
846 
847  // Position has been changed of the manipulator by a direct function
848  int objectId = _node->getIdentifier();
849 
850  if ( objectId > 0 ){
851 
852  BaseObjectData* object;
853  PluginFunctions::getObject(objectId,object);
854 
855  // Assume that it has a good position now
856  object->manipPlaced( true );
857  }
858 }
859 
860 //------------------------------------------------------------------------------
861 
866 
867  if ( (PluginFunctions::pickMode() == "MoveJoints") && (PluginFunctions::actionMode() == Viewer::PickingMode) ){
868 
869  for (uint i=0; i < activeManipulators_.size(); i++){
870 
871  BaseObjectData* obj = 0;
872 
873  PluginFunctions::getObject( activeManipulators_[i], obj );
874 
875  if (obj != 0 && obj->manipPlaced()) {
876  obj->manipulatorNode()->show();
877  emit nodeVisibilityChanged(obj->id());
878  }
879  }
880 
881  } else {
882 
883  for (uint i=0; i < activeManipulators_.size(); i++){
884 
885  BaseObjectData* obj = 0;
886 
887  PluginFunctions::getObject( activeManipulators_[i], obj );
888 
889  if ( obj != 0 ) {
890  obj->manipulatorNode()->hide();
891  emit nodeVisibilityChanged(obj->id());
892  }
893  }
894  }
895 
896  emit updateView();
897 }
898 
899 //--------------------------------------------------------------------------------
900 
901 void SkeletonEditingPlugin::deleteJoint(QMouseEvent* _event)
902 {
903  if ( (_event->type() == QEvent::MouseButtonPress) || (_event->type() == QEvent::MouseButtonRelease) ){
904  // only select the joint on mousePress
905  unsigned int node_idx, target_idx;
906  ACG::Vec3d hitPoint;
907  BaseObjectData* object;
908 
909  //disable picking for anything but skeletons
911  o_it->enablePicking( o_it->dataType(DATA_SKELETON) );
912 
913  //perform picking
914  bool successfullyPicked = PluginFunctions::scenegraphPick(ACG::SceneGraph::PICK_VERTEX, _event->pos(), node_idx,
915  target_idx, &hitPoint) && PluginFunctions::getPickedObject(node_idx, object);
916 
917  //reenable picking for anything
919  o_it->enablePicking( true );
920 
921  if ( successfullyPicked ){
922  Skeleton* skeleton = PluginFunctions::skeleton( object );
923 
924  if ( !skeleton )
925  return;
926 
927  currentSkeleton_ = object->id();
928 
929  Skeleton::Joint* joint = skeleton->joint( target_idx );
930 
931  if ( joint != 0 ){
932 
933  bool wasSelected = joint->selected();
934 
935  //clear selection
936  for (Skeleton::Iterator it=skeleton->begin(); it != skeleton->end(); ++it)
937  (*it)->setSelected(false);
938 
939  currentJoint_ = joint->id();
940 
941  if ( _event->type() == QEvent::MouseButtonPress ) //select on press
942  joint->setSelected(true);
943  else{
944  //delete on release
945  if ( wasSelected ){
946 
947  if (skeleton->jointCount() > 1){
948  skeleton->removeJoint(joint);
950  emit updatedObject(object->id(), UPDATE_ALL);
951  emit createBackup(object->id(), "Delete Joint", UPDATE_TOPOLOGY);
952  } else
953  emit deleteObject( object->id() );
954  }
955  }
956  }
957  }
958  }
959 
960  //make sure the joint is deselected
961  if (_event->type() == QEvent::MouseButtonRelease){
962 
963  BaseObjectData* baseObject = 0;
964  PluginFunctions::getObject(currentSkeleton_, baseObject);
965 
966  if (baseObject == 0)
967  return;
968 
969  Skeleton* skeleton = PluginFunctions::skeleton( baseObject );
970 
971  if (skeleton == 0)
972  return;
973 
974  Skeleton::Joint* joint = skeleton->joint( currentJoint_ );
975 
976  if (joint != 0)
977  joint->setSelected(false);
978 
979  currentSkeleton_ = -1;
980  currentJoint_ = -1;
981  }
982 }
983 
984 //--------------------------------------------------------------------------------
989 void SkeletonEditingPlugin::splitJoint(QMouseEvent* _event)
990 {
991  if ( _event->type() == QEvent::MouseButtonPress )
992  {
993  if ( jointPreview_ )
994  return;
995 
996  // try to select a joint from which the insertion should be started
997  unsigned int node_idx, target_idx;
998  ACG::Vec3d hitPoint;
999  BaseObjectData* object;
1000 
1001  //disable picking for anything but skeletons
1003  o_it->enablePicking( o_it->dataType(DATA_SKELETON) );
1004 
1005  //perform picking
1006  bool successfullyPicked = PluginFunctions::scenegraphPick(ACG::SceneGraph::PICK_ANYTHING, _event->pos(), node_idx,
1007  target_idx, &hitPoint) && PluginFunctions::getPickedObject(node_idx, object);
1008 
1009  //reenable picking for anything
1011  o_it->enablePicking( true );
1012 
1013  if ( successfullyPicked )
1014  {
1015  Skeleton* skeleton = PluginFunctions::skeleton( object );
1016 
1017  if ( !skeleton )
1018  return;
1019 
1020  Skeleton::Joint* joint = skeleton->joint( target_idx );
1021 
1022  splitBone(object->id(), joint->id());
1023  }
1024  }
1025 }
1026 
1027 //--------------------------------------------------------------------------------
1028 
1029 void SkeletonEditingPlugin::insertJoint(QMouseEvent* _event)
1030 {
1031 
1032  //----------------------------------------------------------------------
1033  // handle PRESS events
1034  //----------------------------------------------------------------------
1035  if ( _event->type() == QEvent::MouseButtonPress ){
1036 
1037  if ( jointPreview_ )
1038  return;
1039 
1040  // try to select a joint from which the insertion should be started
1041  //
1042  unsigned int node_idx, target_idx;
1043  ACG::Vec3d hitPoint;
1044  BaseObjectData* object;
1045 
1046  //disable picking for anything but skeletons
1048  o_it->enablePicking( o_it->dataType(DATA_SKELETON) );
1049 
1050  //perform picking
1051  bool successfullyPicked = PluginFunctions::scenegraphPick(ACG::SceneGraph::PICK_VERTEX, _event->pos(), node_idx,
1052  target_idx, &hitPoint) && PluginFunctions::getPickedObject(node_idx, object);
1053 
1054  //reenable picking for anything
1056  o_it->enablePicking( true );
1057 
1058  if ( successfullyPicked ){
1059  Skeleton* skeleton = PluginFunctions::skeleton( object );
1060 
1061  if ( !skeleton )
1062  return;
1063 
1064  currentSkeleton_ = object->id();
1065  jointPreview_ = false;
1066 
1067  Skeleton::Joint* joint = skeleton->joint( target_idx );
1068 
1069  if ( joint != 0 ){
1070  currentJoint_ = joint->id();
1071  }
1072  }
1073  }
1074 
1075  //----------------------------------------------------------------------
1076  // handle DOUBLE CLICK events
1077  //----------------------------------------------------------------------
1078  else if ( _event->type() == QEvent::MouseButtonDblClick ){
1079 
1080 
1081  dblClick_ = true;
1082  // end the path in the skeleton
1083  if (currentSkeleton_ != -1){
1084  cancelJointInsertion();
1085  return;
1086  }
1087 
1088  // add a new skeleton at this position
1089  unsigned int node_idx, target_idx;
1090  ACG::Vec3d lastHitPoint(0.0, 0.0, 0.0);
1091 
1092  // first try to pick something
1093  if( !PluginFunctions::scenegraphPick(ACG::SceneGraph::PICK_FACE, _event->pos(), node_idx, target_idx, &lastHitPoint) ){
1094  //if picking fails just unproject at position
1095  ACG::Vec3d viewCoords = ACG::Vec3d(_event->pos().x(), PluginFunctions::viewerProperties().glState().context_height() - _event->pos().y(), 0.5);
1096  lastHitPoint = PluginFunctions::viewerProperties().glState().unproject(viewCoords);
1097  }
1098 
1099 
1100  int newSkeletonID = -1;
1101  emit addEmptyObject(DATA_SKELETON, newSkeletonID);
1102 
1103  BaseObjectData* baseObject = 0;
1104  PluginFunctions::getObject(newSkeletonID, baseObject);
1105 
1106  if (baseObject == 0)
1107  return;
1108 
1109  Skeleton* skeleton = PluginFunctions::skeleton( baseObject );
1110 
1111  if (skeleton == 0)
1112  return;
1113 
1114  Skeleton::Joint* rootJoint = new Skeleton::Joint(0);
1115  skeleton->addJoint(0, rootJoint);
1116 
1117  // set joint position
1118  setJointPosition(PluginFunctions::skeletonObject(baseObject), rootJoint, lastHitPoint);
1119  emit updatedObject(baseObject->id(), UPDATE_ALL);
1120  emit createBackup(baseObject->id(), "Add Joints", UPDATE_ALL);
1121 
1122  // add an additional joint which is moved on mousemove
1123  Skeleton::Joint* tmpJoint = new Skeleton::Joint(rootJoint);
1124  skeleton->addJoint(rootJoint, tmpJoint);
1125 
1126  // set joint position
1127  setJointPosition(PluginFunctions::skeletonObject(baseObject), tmpJoint, lastHitPoint);
1128 
1129  currentSkeleton_ = baseObject->id();
1130  currentJoint_ = tmpJoint->id();
1131  jointPreview_ = true;
1132 
1133  //----------------------------------------------------------------------
1134  // handle MOVE events
1135  //----------------------------------------------------------------------
1136  } else if ( _event->type() == QEvent::MouseMove ){
1137 
1138  if ( jointPreview_ ){
1139  //only if jointPreview_ is enabled a joint is under construction
1140  BaseObjectData* baseObject = 0;
1141  PluginFunctions::getObject(currentSkeleton_, baseObject);
1142 
1143  if (baseObject == 0)
1144  return;
1145 
1146  Skeleton* skeleton = PluginFunctions::skeleton( baseObject );
1147 
1148  if (skeleton == 0)
1149  return;
1150 
1151  Skeleton::Joint* joint = skeleton->joint( currentJoint_ );
1152 
1153  if (joint != 0){
1154 
1155  ACG::Vec3d parentPosition = activePose(PluginFunctions::skeletonObject(baseObject))->globalTranslation(joint->parent()->id());
1156  ACG::Vec3d parentViewer = PluginFunctions::viewerProperties().glState().project(parentPosition);
1157 
1158  ACG::Vec3d viewCoords = ACG::Vec3d(_event->pos().x(), PluginFunctions::viewerProperties().glState().context_height() - _event->pos().y(), parentViewer[2]);
1159  ACG::Vec3d lastHitPoint = PluginFunctions::viewerProperties().glState().unproject(viewCoords);
1160 
1161  // set joint position
1162  setJointPosition(PluginFunctions::skeletonObject(baseObject), joint, lastHitPoint);
1163  }
1164  }
1165 
1166  //----------------------------------------------------------------------
1167  // handle RELEASE events
1168  //----------------------------------------------------------------------
1169  } else if ( _event->type() == QEvent::MouseButtonRelease){
1170 
1171  if (!dblClick_) {
1172 
1173  // CASE 1 : this is a release on a joint from which the insertion should be started
1174  if ( !jointPreview_ ){
1175  // in
1176  unsigned int node_idx, target_idx;
1177  ACG::Vec3d hitPoint;
1178  BaseObjectData* object;
1179 
1180  //disable picking for anything but skeletons
1182  o_it->enablePicking( o_it->dataType(DATA_SKELETON) );
1183 
1184  //perform picking
1185  bool successfullyPicked = PluginFunctions::scenegraphPick(ACG::SceneGraph::PICK_VERTEX, _event->pos(), node_idx,
1186  target_idx, &hitPoint) && PluginFunctions::getPickedObject(node_idx, object);
1187 
1188  //reenable picking for anything
1190  o_it->enablePicking( true );
1191 
1192  if ( successfullyPicked ){
1193  Skeleton* skeleton = PluginFunctions::skeleton( object );
1194 
1195  if ( !skeleton )
1196  return;
1197 
1198  currentSkeleton_ = object->id();
1199 
1200  Skeleton::Joint* joint = skeleton->joint( currentJoint_ );
1201 
1202  if ( joint != 0 ){
1203 
1204  Skeleton::Joint* tmpJoint = new Skeleton::Joint(joint);
1205  skeleton->addJoint(joint, tmpJoint);
1206 
1207  currentJoint_ = tmpJoint->id();
1208  jointPreview_ = true;
1209  }
1210  }
1211 
1212  } else {
1213  // CASE 2 : a joint is already under construction
1214  // so we insert the new joint at the current position
1215  BaseObjectData* baseObject = 0;
1216  PluginFunctions::getObject(currentSkeleton_, baseObject);
1217 
1218  if (baseObject == 0)
1219  return;
1220 
1221  Skeleton* skeleton = PluginFunctions::skeleton( baseObject );
1222 
1223  if (skeleton == 0)
1224  return;
1225 
1226  Skeleton::Joint* joint = skeleton->joint( currentJoint_ );
1227 
1228  if (joint != 0){
1229 
1230  ACG::Vec3d parentPosition = activePose(PluginFunctions::skeletonObject(baseObject))->globalTranslation(joint->parent()->id());
1231  ACG::Vec3d parentViewer = PluginFunctions::viewerProperties().glState().project(parentPosition);
1232 
1233  ACG::Vec3d viewCoords = ACG::Vec3d(_event->pos().x(), PluginFunctions::viewerProperties().glState().context_height() - _event->pos().y(), parentViewer[2]);
1234  ACG::Vec3d lastHitPoint = PluginFunctions::viewerProperties().glState().unproject(viewCoords);
1235 
1236  // set joint position
1237  setJointPosition(PluginFunctions::skeletonObject(baseObject), joint, lastHitPoint);
1238  emit updatedObject(baseObject->id(), UPDATE_ALL);
1239 
1240  Skeleton::Joint* tmpJoint = new Skeleton::Joint(joint);
1241  skeleton->addJoint(joint, tmpJoint);
1242  setJointPosition(PluginFunctions::skeletonObject(baseObject), tmpJoint, lastHitPoint);
1243 
1244  currentJoint_ = tmpJoint->id();
1245  }
1246 
1247 
1248  }
1249  } else
1250  dblClick_ = false;
1251  }
1252 
1253 
1254  // keep the joint selection correct
1255  if ( (_event->type() != QEvent::MouseButtonPress) ){
1256  BaseObjectData* baseObject = 0;
1257  PluginFunctions::getObject(currentSkeleton_, baseObject);
1258 
1259  if (baseObject == 0)
1260  return;
1261 
1262  Skeleton* skeleton = PluginFunctions::skeleton( baseObject );
1263 
1264  if (skeleton == 0)
1265  return;
1266  }
1267 }
1268 
1269 //--------------------------------------------------------------------------------
1270 
1271 Skeleton::Pose* SkeletonEditingPlugin::activePose(SkeletonObject* _skeletonObj){
1272 
1273  Skeleton* skeleton = PluginFunctions::skeleton(_skeletonObj);
1274 
1275  if(!skeleton) return NULL;
1276 
1277  AnimationHandle handle = _skeletonObj->skeletonNode()->activePose();
1278 
1279  if ( !handle.isValid() ){
1280  //no current animation found -> transform the reference Pose
1281  return skeleton->referencePose();
1282  } else {
1283 
1284  Skeleton::Animation* animation = skeleton->animation(handle);
1285  return animation->pose( handle.frame() );
1286  }
1287 }
1288 
1289 //--------------------------------------------------------------------------------
1290 
1291 void SkeletonEditingPlugin::setJointPosition(SkeletonObject* _skeletonObj, Skeleton::Joint* _joint, ACG::Vec3d& _position){
1292 
1293  Skeleton* skeleton = PluginFunctions::skeleton(_skeletonObj);
1294 
1295  if (skeleton == 0)
1296  return;
1297 
1298  //set position in refPose
1299  Skeleton::Pose* currentPose = activePose(_skeletonObj);
1300  currentPose->setGlobalTranslation(_joint->id(), _position );
1301 
1302  ACG::Matrix4x4d localMatrix = currentPose->localMatrix(_joint->id());
1303 
1304  //set position in animations
1305  for (unsigned int a=0; a < skeleton->animationCount(); a++)
1306  if ( AnimationHandle(a, 0 ).isValid() ){
1307 
1308  AnimationT<ACG::Vec3d> *animation = skeleton->animation( AnimationHandle(a, 0 ) );
1309 
1310  if ( animation != 0){
1311 
1312  //set initial joint translation
1313  for (int iFrame=0; iFrame < (int)animation->frameCount(); iFrame++) {
1314 
1315  PoseT<ACG::Vec3d>* pose = skeleton->pose( AnimationHandle(a, iFrame ) );
1316 
1317  if (pose != currentPose)
1318  pose->setLocalMatrix(_joint->id(), localMatrix );
1319  }
1320  }
1321  }
1322 
1323  if (currentPose != skeleton->referencePose())
1324  skeleton->referencePose()->setLocalMatrix(_joint->id(), localMatrix );
1325 }
1326 
1327 //--------------------------------------------------------------------------------
1328 
1329 void SkeletonEditingPlugin::cancelJointInsertion(){
1330 
1331  int cSkeleton = currentSkeleton_;
1332  int cJoint = currentJoint_;
1333 
1334  currentSkeleton_ = -1;
1335  currentJoint_ = -1;
1336  jointPreview_ = false;
1337 
1338  BaseObjectData* baseObject = 0;
1339  PluginFunctions::getObject(cSkeleton, baseObject);
1340 
1341  if (baseObject == 0)
1342  return;
1343 
1344  Skeleton* skeleton = PluginFunctions::skeleton( baseObject );
1345 
1346  if (skeleton == 0)
1347  return;
1348 
1349  Skeleton::Joint* joint = skeleton->joint( cJoint );
1350 
1351  if (joint != 0)
1352  skeleton->removeJoint(joint);
1353 
1354  emit updatedObject(baseObject->id(), UPDATE_ALL);
1355  emit createBackup(baseObject->id(), "Add Joints", UPDATE_ALL);
1356 }
1357 
1358 //--------------------------------------------------------------------------------
1359 
1360 void SkeletonEditingPlugin::moveJoint(QMouseEvent* _event)
1361 {
1362 
1363  if (_event->type() == QEvent::MouseButtonDblClick && _event->button() == Qt::LeftButton){
1364  placeManip(_event);
1365  } else {
1366 
1367  // interaction
1369  PluginFunctions::traverse(action);
1370  }
1371 }
1372 
1373 //--------------------------------------------------------------------------------
1374 
1375 void SkeletonEditingPlugin::selectJoint(QMouseEvent* _event)
1376 {
1377 
1378  if ( _event->type() == QEvent::MouseButtonRelease ){
1379 
1380  unsigned int node_idx, target_idx;
1381  ACG::Vec3d hitPoint;
1382  BaseObjectData* object;
1383 
1384  //disable picking for anything but skeletons
1386  o_it->enablePicking( o_it->dataType(DATA_SKELETON) );
1387 
1388  //perform picking
1389  bool successfullyPicked = PluginFunctions::scenegraphPick(ACG::SceneGraph::PICK_VERTEX, _event->pos(), node_idx,
1390  target_idx, &hitPoint) && PluginFunctions::getPickedObject(node_idx, object);
1391 
1392  //reenable picking for anything
1394  o_it->enablePicking( true );
1395 
1396  if ( successfullyPicked ){
1397  Skeleton* skeleton = PluginFunctions::skeleton( object );
1398 
1399  if ( !skeleton )
1400  return;
1401 
1402  Skeleton::Joint* joint = skeleton->joint( target_idx );
1403 
1404  if ( joint != 0 ){
1405  joint->setSelected( !joint->selected() );
1406  emit updatedObject(object->id(), UPDATE_SELECTION);
1407  }
1408  }
1409  }
1410 }
1411 
1412 //--------------------------------------------------------------------------------
1413 
1418 
1419  ACG::Vec3d bestJoint;
1420  double bestDistance = DBL_MAX;
1421 
1422  _bestJointID = -1;
1423 
1424  Skeleton* skeleton = PluginFunctions::skeleton(_skeletonObj);
1425 
1426  Skeleton::Pose* pose = activePose(_skeletonObj);
1427 
1428  //find the nearest joint
1429  for (unsigned int joint = 0; joint < skeleton->jointCount(); joint++){
1430 
1431  double dist = (_hitPoint - pose->globalTranslation(joint)).sqrnorm();
1432 
1433  if (dist < bestDistance){
1434  bestJoint = pose->globalTranslation(joint);
1435  _bestJointID = joint;
1436  bestDistance = dist;
1437  }
1438  }
1439 
1440  return (OpenMesh::Vec3d) bestJoint;
1441 }
1442 
1443 //--------------------------------------------------------------------------------
1444 
1449 
1450  int jointID = _skeletonObj->manipulatorNode()->getData().toInt();
1451 
1452  Skeleton* skeleton = PluginFunctions::skeleton(_skeletonObj);
1453 
1454  if (skeleton == 0)
1455  return;
1456 
1457  if (skeleton->joint(jointID) == 0)
1458  return;
1459 
1460  Skeleton::Pose* pose = activePose(PluginFunctions::skeletonObject(_skeletonObj));
1461 
1462  if(!pose) return;
1463 
1464  ACG::Vec3d newPos = pose->globalTranslation( jointID );
1465 
1466  _skeletonObj->manipulatorNode()->set_center(newPos);
1467 }
1468 
1469 //--------------------------------------------------------------------------------
1470 
1471 #if QT_VERSION < 0x050000
1472  Q_EXPORT_PLUGIN2( skeletoneditingplugin , SkeletonEditingPlugin );
1473 #endif
1474 
1475 
1476 
void traverse(ACG::SceneGraph::MouseEventAction &_action)
void slotPickModeChanged(const std::string &_mode)
slot is called when the pickMode changed
ViewObjectMarker * defaultViewObjectMarker()
Get the default ViewObjectMarker.
QString lastRenderer_
Stores the last active renderer before we switched to skeleton editing mode.
Iterator class for the skeleton.
Definition: SkeletonT.hh:88
Matrix4x4 localMatrix(int _objectId, int _jointId)
get local matrix of a joint in the active pose
bool scenegraphPick(ACG::SceneGraph::PickTarget _pickTarget, const QPoint &_mousePos, unsigned int &_nodeIdx, unsigned int &_targetIdx, ACG::Vec3d *_hitPointPtr=0)
Execute picking operation on scenegraph.
void updateManipulatorPosition(BaseObjectData *_skeletonObj)
make sure the manipulator is positioned on a joint
~SkeletonEditingPlugin()
Destructor.
void manipulatorMoved(QtTranslationManipulatorNode *_node, QMouseEvent *_event)
move the object when its manipulator moves
DrawMode SOLID_SMOOTH_SHADED
draw smooth shaded (Gouraud shaded) faces (requires halfedge normals)
Definition: DrawModes.cc:88
VectorT< T, 3 > transform_point(const VectorT< T, 3 > &_v) const
transform point (x&#39;,y&#39;,z&#39;,1) = M * (x,y,z,1)
Definition: Matrix4x4T.cc:202
void showManipulators()
Show/Hide active manipulators.
ACG::GLState & glState()
Get the glState of the Viewer.
DrawMode WIREFRAME
draw wireframe
Definition: DrawModes.cc:84
void setGlobalTranslation(unsigned int _joint, const Vector &_position, bool _keepGlobalChildPositions=true)
Sets the global translation vector.
Definition: PoseT.cc:255
Represents a single joint in the skeleton.
Definition: JointT.hh:66
int context_height() const
get gl context height
Definition: GLState.hh:833
const UpdateType UPDATE_TOPOLOGY(UpdateTypeSet(1)<< 3)
Topology updated.
int skin(unsigned int _index)
Get the skin with given index (0 <= _index < skinCount())
bool getObject(int _identifier, BSplineCurveObject *&_object)
bool dataType(DataType _type) const
Definition: BaseObject.cc:232
Vector globalTranslation(unsigned int _joint)
Returns the global translation vector.
Definition: PoseT.cc:233
unsigned int jointCount()
Returns the number of joints.
Definition: SkeletonT.cc:701
bool selected()
Returns the joint&#39;s selection state.
Definition: JointT.cc:233
bool rendererChanged_
Remembers, if we changed the renderer.
void placeManip(QMouseEvent *_event)
Place and show the Manipulator.
void transformJoint(int _objectId, int _jointId, Matrix4x4 _matrix)
transform joint with given matrix
const Matrix & globalMatrix(unsigned int _joint) const
Returns the global matrix for the given joint.
Definition: PoseT.cc:199
Iterator begin()
Iterator over joints of the skeletal tree in TOP-DOWN order (from root to leafs)
Definition: SkeletonT.cc:714
bool isValid() const
Returns true if the handle is valid.
void setSelected(bool _selected)
Set the joint&#39;s selction state.
Definition: JointT.cc:245
int getIdentifier()
Get an identifier for that manipulator.
int id() const
Definition: BaseObject.cc:201
const QStringList ALL_OBJECTS
Iterable object range.
bool getPickedObject(const unsigned int _node_idx, BaseObjectData *&_object)
Get the picked mesh.
QtTranslationManipulatorNode * manipulatorNode()
unsigned int id()
returns the joint id
Definition: JointT.cc:103
Vec3d project(const Vec3d &_point) const
project point in world coordinates to window coordinates
Definition: GLState.cc:638
Update type class.
Definition: UpdateType.hh:70
A general pose, used to store the frames of the animation.
Definition: PoseT.hh:68
const GLMatrixd & matrix() const
Returns a const reference to the current transformation matrix.
a class which provides an link generator for WhatsThisMessages linking to the user doc If you have an...
Animation * animation(std::string _name)
Returns a pointer to the animation to the given name.
Definition: SkeletonT.cc:858
const Matrix & localMatrix(unsigned int _joint) const
Returns the local matrix for the given joint.
Definition: PoseT.cc:110
A handle used to refer to an animation or to a specific frame in an animation.
bool is_identity() const
check if the matrix is the identity ( up to an epsilon )
Definition: Matrix4x4T.hh:220
Matrix rotation_matrix() const
cast to rotation matrix
Definition: QuaternionT.hh:182
void setMode(ManipulatorMode _mode)
set current operation mode
void identity()
setup an identity matrix
Definition: Matrix4x4T.cc:256
const std::string pickMode()
Get the current Picking mode.
Viewer::ViewerProperties & viewerProperties(int _id)
Get the viewer properties Use this functions to get basic viewer properties such as backgroundcolor o...
bool contains(const UpdateType &_type) const
Check if this update contains the given UpdateType.
Definition: UpdateType.cc:111
SkeletonObject * skeletonObject(BaseObjectData *_object)
Cast an BaseObject to a SkeletonObject if possible.
const UpdateType UPDATE_GEOMETRY(UpdateTypeSet(1)<< 2)
Geometry updated.
void setViewObjectMarker(ViewObjectMarker *_marker)
Vec3d unproject(const Vec3d &_winPoint) const
unproject point in window coordinates _winPoint to world coordinates
Definition: GLState.cc:649
QVariant getData()
Get additional data for the node.
ManipulatorMode
enum to define the manipulator mode
OpenMesh::Vec3d getNearestJoint(SkeletonObject *_skeletonObj, OpenMesh::Vec3d &_hitPoint, int &_bestJointID)
Get nearest joint to hitPoint (used for snapping)
const Vec3d & center() const
get center
bool hasObjectData(QString _dataName)
Checks if object data with given name is available.
Definition: BaseObject.cc:806
void slotMouseEvent(QMouseEvent *_event)
MousePress event occured.
void ManipulatorPositionChanged(QtTranslationManipulatorNode *_node)
update object when its manipulator changes position
Abstract base class for the skin template, wrapping all template versions of the skin.
Definition: BaseSkin.hh:67
void updateIndices()
Updates the joint index text node positions.
Iterator end()
Compare an iterator with the return value of this method to test if it is done.
Definition: SkeletonT.cc:725
void addJoint(typename SkeletonT< PointT >::Joint *_pParent, typename SkeletonT< PointT >::Joint *_pJoint)
Adds a joint as child of a given parent joint.
Definition: SkeletonT.cc:494
unsigned int activeExaminer()
Get the id of the examiner which got the last mouse events.
unsigned int animationCount()
Returns the number of animations stored in this skeleton.
Definition: SkeletonT.cc:971
Stores a single animation.
Definition: AnimationT.hh:67
picks verices (may not be implemented for all nodes)
Definition: BaseNode.hh:108
ACG::Vec3d Vector
Standard Type for 3d Vector used for scripting.
Definition: DataTypes.hh:187
Viewer::ActionMode actionMode()
Get the current Action mode.
virtual void enablePicking(bool _enable)
unsigned int skinCount()
Get the number of associated skins.
Joint * parent()
Returns the parent joint.
Definition: JointT.cc:162
const UpdateType UPDATE_SELECTION(UpdateTypeSet(1)<< 4)
Selection updated.
Pose * pose(const AnimationHandle &_hAni)
Returns a pointer to the pose with the given animation handle.
Definition: SkeletonT.cc:741
decltype(std::declval< S >()*std::declval< S >()) sqrnorm() const
compute squared euclidean norm
Definition: Vector11T.hh:396
ACG::SceneGraph::SkeletonNodeT< Skeleton > * skeletonNode()
Returns the skeleton scenegraph node.
void splitJoint(QMouseEvent *_event)
split selected Joint
bool canModify(QMouseEvent *_event)
checks, if the skeleton can be modified. a skeleton can be modified, if the active pose is the refere...
Skeleton * skeleton(BaseObjectData *_object)
Get a skeleton from an object.
bool manipPlaced()
Check if the manipulator has been placed.
void inverseKinematic(ACG::Vec3d dest, Skeleton::Pose *currentPose, Skeleton::Joint *pickedJoint, std::vector< Skeleton::Joint * > rotatableJoints)
function for computing the position of our joints using inverse Kinematic
#define DATA_SKELETON
Definition: Skeleton.hh:70
void setWhatsThis(QAction *_action, const QString &_msg, const QString &_ref="", const QString &_site="index.html") const
sets a whatsThis Message plus link to the doc for the given QAction
void setDescriptions()
Set Descriptions for Scripting Slots.
pick any of the prior targets (should be implemented for all nodes)
Definition: BaseNode.hh:110
const UpdateType UPDATE_ALL(UpdateTypeSet(1))
Identifier for all updates.
void pluginsInitialized()
Initialization of the plugin when it is loaded by the core.
Data object attached to the skeleton.
Joint * joint(const unsigned int &_index)
Returns the joint with the given index.
Definition: SkeletonT.cc:642
void splitBone(int _objectId, int _tailJoint)
insert a joint in the middle of a bone given by its (unique) tailJoint
void removeJoint(typename SkeletonT< PointT >::Joint *_pJoint)
Remove the given joint from the tree.
Definition: SkeletonT.cc:538
VectorT< double, 3 > Vec3d
Definition: VectorT.hh:127
SkeletonEditingPlugin()
Default Constructor.
void setGlobalMatrix(unsigned int _joint, const Matrix &_global, bool _keepGlobalChildPositions=true)
Sets the global coordinate system.
Definition: PoseT.cc:217
picks faces (should be implemented for all nodes)
Definition: BaseNode.hh:104
DLLEXPORT ObjectIterator objectsEnd()
Return Iterator to Object End.
VectorT< T, 3 > transform_vector(const VectorT< T, 3 > &_v) const
transform vector (x&#39;,y&#39;,z&#39;,0) = A * (x,y,z,0)
Definition: Matrix4x4T.cc:225
void setDrawMode(const ACG::SceneGraph::DrawModes::DrawMode &_mode, int _viewer)
Set the draw Mode of a Viewer. .
void setLocalMatrix(unsigned int _joint, const Matrix &_local, bool _keepLocalChildPositions=true)
Sets the local coordinate system.
Definition: PoseT.cc:126
Pose * referencePose()
Returns a pointer to the reference pose.
Definition: SkeletonT.cc:761
unsigned int frame() const
Returns the selected frame (zero based)
PerObjectData * objectData(QString _dataName)
Returns the object data pointer.
Definition: BaseObject.cc:814