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#include <QAction>
54#include <QActionGroup>
55
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
233}
234
235//------------------------------------------------------------------------------
236
237void 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
260void SkeletonEditingPlugin::initializePlugin()
261{
262
263}
264
265
266/*******************************************************************************
267 MouseInterface implementation
268 *******************************************************************************/
269
270void 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->angleDelta().y() / 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
293bool 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 size_t 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
341void 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
369void SkeletonEditingPlugin::slotKeyEvent (QKeyEvent* _event)
370{
371 if (_event->key() == Qt::Key_Shift)
372 rotateManipAction_->setChecked(true);
373}
374
375//------------------------------------------------------------------------------
376
377void SkeletonEditingPlugin::slotKeyReleaseEvent (QKeyEvent* _event)
378{
379 if ( _event->key() == Qt::Key_Shift)
380 rotateManipAction_->setChecked(false);
381}
382
383/*******************************************************************************
384 PickingInterface implementation
385 *******************************************************************************/
386
391void 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
439void 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
483void 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
503void 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;
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
539void SkeletonEditingPlugin::placeManip(QMouseEvent * _event) {
540 size_t 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 */
635void 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
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, Blending::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
901void SkeletonEditingPlugin::deleteJoint(QMouseEvent* _event)
902{
903 if ( (_event->type() == QEvent::MouseButtonPress) || (_event->type() == QEvent::MouseButtonRelease) ){
904 // only select the joint on mousePress
905 size_t 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
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//--------------------------------------------------------------------------------
989void 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 size_t 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
1029void 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 size_t 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 size_t 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
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
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 size_t 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 ){
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
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
1263
1264 if (skeleton == 0)
1265 return;
1266 }
1267}
1268
1269//--------------------------------------------------------------------------------
1270
1271Skeleton::Pose* SkeletonEditingPlugin::activePose(SkeletonObject* _skeletonObj){
1272
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
1291void SkeletonEditingPlugin::setJointPosition(SkeletonObject* _skeletonObj, Skeleton::Joint* _joint, ACG::Vec3d& _position){
1292
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
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())
1325}
1326
1327//--------------------------------------------------------------------------------
1328
1329void 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
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
1360void SkeletonEditingPlugin::moveJoint(QMouseEvent* _event)
1361{
1362
1363 if (_event->type() == QEvent::MouseButtonDblClick && _event->button() == Qt::LeftButton){
1364 placeManip(_event);
1365 } else {
1366
1367 // interaction
1370 }
1371}
1372
1373//--------------------------------------------------------------------------------
1374
1375void SkeletonEditingPlugin::selectJoint(QMouseEvent* _event)
1376{
1377
1378 if ( _event->type() == QEvent::MouseButtonRelease ){
1379
1380 size_t 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 ){
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
1472
1473
ACG::Vec3d Vector
Standard Type for 3d Vector used for scripting.
Definition: DataTypes.hh:176
#define DATA_SKELETON
Definition: Skeleton.hh:64
@ PickingMode
Picking Mode.
int context_height() const
get gl context height
Definition: GLState.hh:855
Vec3d unproject(const Vec3d &_winPoint) const
unproject point in window coordinates _winPoint to world coordinates
Definition: GLState.cc:651
Vec3d project(const Vec3d &_point) const
project point in world coordinates to window coordinates
Definition: GLState.cc:640
VectorT< T, 3 > transform_vector(const VectorT< T, 3 > &_v) const
transform vector (x',y',z',0) = A * (x,y,z,0)
void identity()
setup an identity matrix
bool is_identity() const
check if the matrix is the identity ( up to an epsilon )
Definition: Matrix4x4T.hh:215
VectorT< T, 3 > transform_point(const VectorT< T, 3 > &_v) const
transform point (x',y',z',1) = M * (x,y,z,1)
Matrix rotation_matrix() const
cast to rotation matrix
Definition: QuaternionT.hh:176
int getIdentifier()
Get an identifier for that manipulator.
QVariant getData()
Get additional data for the node.
const Vec3d & center() const
get center
const GLMatrixd & matrix() const
Returns a const reference to the current transformation matrix.
void setMode(ManipulatorMode _mode)
set current operation mode
ManipulatorMode
enum to define the manipulator mode
A handle used to refer to an animation or to a specific frame in an animation.
bool isValid() const
Returns true if the handle is valid.
size_t frame() const
Returns the selected frame (zero based)
Stores a single animation.
Definition: AnimationT.hh:59
virtual void enablePicking(bool _enable)
QtTranslationManipulatorNode * manipulatorNode()
bool manipPlaced()
Check if the manipulator has been placed.
PerObjectData * objectData(QString _dataName)
Returns the object data pointer.
Definition: BaseObject.cc:801
bool dataType(DataType _type) const
Definition: BaseObject.cc:219
bool hasObjectData(QString _dataName)
Checks if object data with given name is available.
Definition: BaseObject.cc:793
int id() const
Definition: BaseObject.cc:188
Abstract base class for the skin template, wrapping all template versions of the skin.
Definition: BaseSkin.hh:63
Represents a single joint in the skeleton.
Definition: JointT.hh:61
size_t id() const
returns the joint id
Definition: JointT_impl.hh:97
bool selected() const
Returns the joint's selection state.
Definition: JointT_impl.hh:227
Joint * parent()
Returns the parent joint.
Definition: JointT_impl.hh:156
void setSelected(bool _selected)
Set the joint's selction state.
Definition: JointT_impl.hh:239
decltype(std::declval< S >() *std::declval< S >()) sqrnorm() const
compute squared euclidean norm
Definition: Vector11T.hh:422
A general pose, used to store the frames of the animation.
Definition: PoseT.hh:59
void setLocalMatrix(unsigned int _joint, const Matrix &_local, bool _keepLocalChildPositions=true)
Sets the local coordinate system.
Definition: PoseT_impl.hh:120
const Matrix & localMatrix(unsigned int _joint) const
Returns the local matrix for the given joint.
Definition: PoseT_impl.hh:104
void setGlobalTranslation(unsigned int _joint, const Vector &_position, bool _keepGlobalChildPositions=true)
Sets the global translation vector.
Definition: PoseT_impl.hh:249
const Matrix & globalMatrix(unsigned int _joint) const
Returns the global matrix for the given joint.
Definition: PoseT_impl.hh:193
void setGlobalMatrix(unsigned int _joint, const Matrix &_global, bool _keepGlobalChildPositions=true)
Sets the global coordinate system.
Definition: PoseT_impl.hh:211
Vector globalTranslation(unsigned int _joint)
Returns the global translation vector.
Definition: PoseT_impl.hh:227
void manipulatorMoved(QtTranslationManipulatorNode *_node, QMouseEvent *_event)
move the object when its manipulator moves
void placeManip(QMouseEvent *_event)
Place and show the Manipulator.
void transformJoint(int _objectId, int _jointId, Matrix4x4 _matrix)
transform joint with given matrix
void slotMouseEvent(QMouseEvent *_event)
MousePress event occured.
void ManipulatorPositionChanged(QtTranslationManipulatorNode *_node)
update object when its manipulator changes position
void pluginsInitialized()
Initialization of the plugin when it is loaded by the core.
void showManipulators()
Show/Hide active manipulators.
bool canModify(QMouseEvent *_event)
checks, if the skeleton can be modified. a skeleton can be modified, if the active pose is the refere...
void slotPickModeChanged(const std::string &_mode)
slot is called when the pickMode changed
void splitBone(int _objectId, int _tailJoint)
insert a joint in the middle of a bone given by its (unique) tailJoint
void splitJoint(QMouseEvent *_event)
split selected Joint
Matrix4x4 localMatrix(int _objectId, int _jointId)
get local matrix of a joint in the active pose
void updateManipulatorPosition(BaseObjectData *_skeletonObj)
make sure the manipulator is positioned on a joint
bool rendererChanged_
Remembers, if we changed the renderer.
QString lastRenderer_
Stores the last active renderer before we switched to skeleton editing mode.
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
void setDescriptions()
Set Descriptions for Scripting Slots.
OpenMesh::Vec3d getNearestJoint(SkeletonObject *_skeletonObj, OpenMesh::Vec3d &_hitPoint, int &_bestJointID)
Get nearest joint to hitPoint (used for snapping)
SkeletonEditingPlugin()
Default Constructor.
Data object attached to the skeleton.
unsigned int skinCount()
Get the number of associated skins.
int skin(unsigned int _index)
Get the skin with given index (0 <= _index < skinCount())
AnimationHandle activePose()
Returns true if the picked node given by _node_idx is this objects scenegraph node.
ACG::SceneGraph::SkeletonNodeT< Skeleton > * skeletonNode()
Returns the skeleton scenegraph node.
void updateIndices()
Updates the joint index text node positions.
Iterator class for the skeleton.
Definition: SkeletonT.hh:83
Pose * referencePose()
Returns a pointer to the reference pose.
Iterator begin()
Iterator over joints of the skeletal tree in TOP-DOWN order (from root to leafs)
size_t jointCount()
Returns the number of joints.
void addJoint(typename SkeletonT< PointT >::Joint *_pParent, typename SkeletonT< PointT >::Joint *_pJoint)
Adds a joint as child of a given parent joint.
size_t animationCount()
Returns the number of animations stored in this skeleton.
Animation * animation(std::string _name)
Returns a pointer to the animation to the given name.
Pose * pose(const AnimationHandle &_hAni)
Returns a pointer to the pose with the given animation handle.
Joint * joint(const size_t &_index)
Returns the joint with the given index.
Iterator end()
Compare an iterator with the return value of this method to test if it is done.
void removeJoint(typename SkeletonT< PointT >::Joint *_pJoint)
Remove the given joint from the tree.
Update type class.
Definition: UpdateType.hh:59
bool contains(const UpdateType &_type) const
Check if this update contains the given UpdateType.
Definition: UpdateType.cc:99
ACG::GLState & glState()
Get the glState of the Viewer.
a class which provides an link generator for WhatsThisMessages linking to the user doc If you have an...
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 UpdateType UPDATE_TOPOLOGY(UpdateTypeSet(8))
Topology updated.
const UpdateType UPDATE_ALL(UpdateTypeSet(1))
Identifier for all updates.
const UpdateType UPDATE_GEOMETRY(UpdateTypeSet(4))
Geometry updated.
const UpdateType UPDATE_SELECTION(UpdateTypeSet(16))
Selection updated.
DrawMode SOLID_SMOOTH_SHADED
draw smooth shaded (Gouraud shaded) faces (requires halfedge normals)
Definition: DrawModes.cc:82
DrawMode WIREFRAME
draw wireframe
Definition: DrawModes.cc:78
@ PICK_ANYTHING
pick any of the prior targets (should be implemented for all nodes)
Definition: PickTarget.hh:84
@ PICK_FACE
picks faces (should be implemented for all nodes)
Definition: PickTarget.hh:78
@ PICK_VERTEX
picks verices (may not be implemented for all nodes)
Definition: PickTarget.hh:82
VectorT< double, 3 > Vec3d
Definition: VectorT.hh:121
SkeletonObject * skeletonObject(BaseObjectData *_object)
Cast an BaseObject to a SkeletonObject if possible.
DLLEXPORT ObjectIterator objectsEnd()
Return Iterator to Object End.
Viewer::ViewerProperties & viewerProperties(int _id)
Get the viewer properties Use this functions to get basic viewer properties such as backgroundcolor o...
bool getObject(const int _identifier, BaseObject *&_object)
Get the object which has the given identifier.
const std::string pickMode()
Get the current Picking mode.
Skeleton * skeleton(BaseObjectData *_object)
Get a skeleton from an object.
bool getPickedObject(const size_t _node_idx, BaseObjectData *&_object)
Get the picked mesh.
ViewObjectMarker * defaultViewObjectMarker()
Get the default ViewObjectMarker.
void traverse(ACG::SceneGraph::MouseEventAction &_action)
bool scenegraphPick(ACG::SceneGraph::PickTarget _pickTarget, const QPoint &_mousePos, size_t &_nodeIdx, size_t &_targetIdx, ACG::Vec3d *_hitPointPtr=0)
Execute picking operation on scenegraph.
Viewer::ActionMode actionMode()
Get the current Action mode.
void setDrawMode(const ACG::SceneGraph::DrawModes::DrawMode &_mode, int _viewer)
Set the draw Mode of a Viewer. .
unsigned int activeExaminer()
Get the id of the examiner which got the last mouse events.
void setViewObjectMarker(ViewObjectMarker *_marker)
const QStringList ALL_OBJECTS
Iterable object range.