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