From 6b3fd060a1476522a883d476f93d59240afcd4c5 Mon Sep 17 00:00:00 2001 From: Mike Kremer Date: Wed, 25 Mar 2009 16:59:55 +0000 Subject: [PATCH] Added tutorial #3 git-svn-id: http://www.openflipper.org/svnrepo/OpenFlipper/branches/Free@5465 383ad7c9-94d9-4d36-a494-682f7c89f535 --- .../Doxygen/example/MouseAndKeyPlugin.cc | 56 ++++++--- .../Doxygen/example/MouseAndKeyPlugin.hh | 13 +-- OpenFlipper/Doxygen/tutorial3.docu | 110 +++++++++++++++++- 3 files changed, 151 insertions(+), 28 deletions(-) diff --git a/OpenFlipper/Doxygen/example/MouseAndKeyPlugin.cc b/OpenFlipper/Doxygen/example/MouseAndKeyPlugin.cc index 44ec01ca0..95254a0d5 100644 --- a/OpenFlipper/Doxygen/example/MouseAndKeyPlugin.cc +++ b/OpenFlipper/Doxygen/example/MouseAndKeyPlugin.cc @@ -48,14 +48,14 @@ void MouseAndKeyPlugin::initializePlugin() { // Set rotation axes to x, y and z axis axis_x_ = ACG::Vec3d(1.0, 0.0, 0.0); axis_y_ = ACG::Vec3d(0.0, 1.0, 0.0); - axis_z_ = ACG::Vec3d(0.0, 0.0, 1.0); // Register keys emit registerKey(Qt::Key_W, Qt::NoModifier, "Rotate object down"); emit registerKey(Qt::Key_S, Qt::NoModifier, "Rotate object up"); emit registerKey(Qt::Key_A, Qt::NoModifier, "Rotate object left"); emit registerKey(Qt::Key_D, Qt::NoModifier, "Rotate object right"); -} + +} // End initializePlugin /* * Is called after all plugins have been initialized @@ -82,8 +82,10 @@ void MouseAndKeyPlugin::pluginsInitialized() { emit addContextMenuItem(contextMenuEntry_->menuAction() , DATA_TRIANGLE_MESH , CONTEXTOBJECTMENU ); emit addContextMenuItem(contextMenuEntry_->menuAction() , DATA_POLY_MESH , CONTEXTOBJECTMENU ); - connect( contextMenuEntry_ , SIGNAL( triggered(QAction*) ), this, SLOT(contextMenuItemSelected(QAction*)) ); -} + // Connect the created context menu entry to local function contextMenuItemSelected(QAction*) + connect(contextMenuEntry_, SIGNAL(triggered(QAction*)), this, SLOT(contextMenuItemSelected(QAction*))); + +} // End pluginsInitialized /* * Initialize toolbox @@ -97,11 +99,11 @@ bool MouseAndKeyPlugin::initializeToolbox(QWidget*& _widget) tool_->resize(size); // Create button that can be toggled - // to (de)activate plugins picking mode + // to (de)activate plugin's picking mode pickButton_ = new QPushButton(tr("Select object")); pickButton_->setCheckable(true); - // Create label the button + // Create label QLabel* label = new QLabel(); label->setText("(De)activate pick mode"); @@ -116,7 +118,8 @@ bool MouseAndKeyPlugin::initializeToolbox(QWidget*& _widget) connect( pickButton_, SIGNAL(clicked()), this, SLOT(slotButtonClicked())); return true; -} + +} // End initializeToolbox /* * Is called when button in toolbox has been clicked @@ -134,19 +137,24 @@ void MouseAndKeyPlugin::slotButtonClicked() { // Picking mode shall be deactivated PluginFunctions::actionMode( Viewer::ExamineMode ); } -} + +} // End slotButtonClicked /* * Is called when pick mode is changed in OpenFlipper */ -void MouseAndKeyPlugin::slotPickModeChanged( const std::string& _mode) { +void MouseAndKeyPlugin::slotPickModeChanged(const std::string& _mode) { // Set button checked if pick mode is our // plugin's pick mode pickButton_->setChecked(_mode == "MouseAndKeyPlugin"); -} -void MouseAndKeyPlugin::slotMouseEvent( QMouseEvent* _event ) { +} // End slotPickModeChanged + +/* + * Is called each time the mouse has moved or been clicked + */ +void MouseAndKeyPlugin::slotMouseEvent(QMouseEvent* _event) { if ( PluginFunctions::pickMode() == "MouseAndKeyPlugin" && PluginFunctions::actionMode() == Viewer::PickingMode ) { @@ -194,7 +202,8 @@ void MouseAndKeyPlugin::slotMouseEvent( QMouseEvent* _event ) { ACG::SceneGraph::MouseEventAction action(_event); PluginFunctions::traverse(action); } -} + +} // End slotMouseEvent /* * Is called when a key on the keyboard is pressed @@ -255,7 +264,8 @@ void MouseAndKeyPlugin::slotKeyEvent( QKeyEvent* _event ) { } else { emit log(LOGINFO, "No object has been selected to rotate! Select object first."); } -} + +} // End slotKeyEvent /* * Transform a mesh with the given transformation matrix @@ -265,25 +275,32 @@ void MouseAndKeyPlugin::slotKeyEvent( QKeyEvent* _event ) { */ template< typename MeshT > void MouseAndKeyPlugin::transformMesh(ACG::Matrix4x4d _mat , MeshT& _mesh ) { + typename MeshT::VertexIter v_it = _mesh.vertices_begin(); typename MeshT::VertexIter v_end = _mesh.vertices_end(); + + // Iterator over all vertices and transform them by _mat + // Update normals for (; v_it!=v_end; ++v_it) { - _mesh.set_point(v_it,(typename MeshT::Point)_mat.transform_point((OpenMesh::Vec3d)(_mesh.point(v_it)))); - _mesh.set_normal(v_it,(typename MeshT::Point)_mat.transform_vector((OpenMesh::Vec3d)(_mesh.normal(v_it)))); + _mesh.set_point(v_it,(typename MeshT::Point)_mat.transform_point((OpenMesh::Vec3d)(_mesh.point(v_it)))); + _mesh.set_normal(v_it,(typename MeshT::Point)_mat.transform_vector((OpenMesh::Vec3d)(_mesh.normal(v_it)))); } typename MeshT::FaceIter f_it = _mesh.faces_begin(); typename MeshT::FaceIter f_end = _mesh.faces_end(); + + // Iterate over all faces and update face normals for (; f_it != f_end; ++f_it) - _mesh.set_normal(f_it,(typename MeshT::Point)_mat.transform_vector((OpenMesh::Vec3d)(_mesh.normal(f_it)))); -} + _mesh.set_normal(f_it,(typename MeshT::Point)_mat.transform_vector((OpenMesh::Vec3d)(_mesh.normal(f_it)))); + +} // End transformMesh /* * Is called when context menu entry has been clicked */ void MouseAndKeyPlugin::contextMenuItemSelected(QAction* _action) { - // Get needed data from QAction object + // Get object id from QAction object QVariant contextObject = _action->data(); int objectId = contextObject.toInt(); @@ -312,7 +329,8 @@ void MouseAndKeyPlugin::contextMenuItemSelected(QAction* _action) { // Tell core that object's visibility has changed visibilityChanged(objectId); -} + +} // End contextMenuItemSelected Q_EXPORT_PLUGIN2( mouseandkeyplugin , MouseAndKeyPlugin ); diff --git a/OpenFlipper/Doxygen/example/MouseAndKeyPlugin.hh b/OpenFlipper/Doxygen/example/MouseAndKeyPlugin.hh index 40659dd1a..7e6a551eb 100644 --- a/OpenFlipper/Doxygen/example/MouseAndKeyPlugin.hh +++ b/OpenFlipper/Doxygen/example/MouseAndKeyPlugin.hh @@ -38,12 +38,12 @@ class MouseAndKeyPlugin: public QObject, void log(QString _message); //ContextMenuInterface void addContextMenuItem(QAction* _action , ContextMenuType _type); - void addContextMenuItem(QAction* _action , DataType _objectType , ContextMenuType _type ); - //PickingInterface - void addPickMode(const std::string _mode); - void addHiddenPickMode(const std::string _mode); - //KeyInterface - void registerKey(int _key, Qt::KeyboardModifiers _modifiers, QString _description, bool _multiUse = false); + void addContextMenuItem(QAction* _action , DataType _objectType , ContextMenuType _type ); + //PickingInterface + void addPickMode(const std::string _mode); + void addHiddenPickMode(const std::string _mode); + //KeyInterface + void registerKey(int _key, Qt::KeyboardModifiers _modifiers, QString _description, bool _multiUse = false); private slots: @@ -84,7 +84,6 @@ class MouseAndKeyPlugin: public QObject, // Rotation axes ACG::Vec3d axis_x_; ACG::Vec3d axis_y_; - ACG::Vec3d axis_z_; private slots: diff --git a/OpenFlipper/Doxygen/tutorial3.docu b/OpenFlipper/Doxygen/tutorial3.docu index 5cc0c3eb0..a935c1cfd 100644 --- a/OpenFlipper/Doxygen/tutorial3.docu +++ b/OpenFlipper/Doxygen/tutorial3.docu @@ -8,8 +8,10 @@ * simple keyboard shortcuts. In addition we will focus a little bit on * what is explained in \ref geometryData. The plugin will provide the following functions: * - * - Hide objects by clicking at our own context menu entry - * - Rotate an object by hitting the arrow keys on the keyboard + * - Hide object by right-clicking at it and selecting our defined action + * - Select an object by entering user defined pick mode and double-clicking + * at object in the scene + * - Rotate selected object by hitting the w,s,a,d keys on the keyboard * * For this purpose we will make use of the following \ref interfaces: * @@ -17,5 +19,109 @@ * - \ref MouseInterface * - \ref PickingInterface * - \ref KeyInterface + * - \ref ContextMenuInterface + * - \ref ToolboxInterface * - \ref LoggingInterface + * + * Since we outlined the details of overriding the BaseInterface methods + * in the previous tutorials (\ref ex1 and \ref ex2) we can directly switch + * over to what happens within these methods. When initializing our plugin + * we set the active object identifier to -1 since no object has been selected yet. + * We initialize the axis vectors that we'll need for the rotation later on. + * Then we tell OpenFlipper that we will use the w, a, s and d key on the + * keyboard (so it'll call slotKeyEvent() each time one of + * the keys has been pressed). Note: OpenFlipper will show up a warning message in the log + * widget if the desired keys are already assigned to another plugin or core function. + * + * \dontinclude MouseAndKeyPlugin.cc + * \skip void MouseAndKeyPlugin::initializePlugin() { + * \until } // End initializePlugin + * + * If all plugins have been initialized, we add our own pick mode named "MouseAndKeyPlugin" + * to OpenFlipper and create the context menu entry (which is actually a QMenu object containing + * one (or generally multiple) object(s) of type QAction) which we connect to contextMenuItemSelected(). + * + * \dontinclude MouseAndKeyPlugin.cc + * \skip void MouseAndKeyPlugin::pluginsInitialized() { + * \until } // End pluginsInitialized + * + * In intializeToolbox() we create a simple toolbox containing a label and a push-button. + * We connect the button to our method slotButtonClicked() which will then be called + * each time the button is clicked. + * + * \dontinclude MouseAndKeyPlugin.cc + * \skip bool MouseAndKeyPlugin::initializeToolbox(QWidget*& _widget) + * \until } // End initializeToolbox + * + * Now each time the button in our toolbox is clicked we want to activate + * the picking mode, such that if the button is checked pick mode "MouseAndKeyPlugin" + * that we defined at the beginning will be active and OpenFlipper switches over from + * ExamineMode to PickingMode (see \ref PluginFunctions for details). Clicking once more + * at the button will return to ExamineMode (in which the user can navigate through the scene). + * + * \dontinclude MouseAndKeyPlugin.cc + * \skip void MouseAndKeyPlugin::slotButtonClicked() { + * \until } // End slotButtonClicked + * + * If the pick mode has been changed externally, we want our button in the toolbox + * to appear pressed (or unpressed respectively). _mode holds the name of the + * currently selected pick mode. + * + * \dontinclude MouseAndKeyPlugin.cc + * \skip void MouseAndKeyPlugin::slotPickModeChanged(const std::string& _mode) { + * \until } // End slotPickModeChanged + * + * In the next method we describe how mouse actions are to be handled by the plugin. + * We want our plugin only to react to mouse events if our pick mode is active otherwise + * don't do anything. If OpenFlipper is in PickingMode and the currently active pick mode + * is "MouseAndKeyPlugin" we try to get the object on that the user has double clicked. + * If the object can be found, we'll show up a dialog window displaying the picked object's + * identifier and assign it to the member variable that holds the active object. + * Otherwise we display "Picking failed" in the log widget. Note that if object picking + * failed the mouse event has to be traversed through the rest of the scene graph. + * + * \dontinclude MouseAndKeyPlugin.cc + * \skip void MouseAndKeyPlugin::slotMouseEvent(QMouseEvent* _event) { + * \until } // End slotMouseEvent + * + * Next method is called whenever any of the keys w, s, a or d is pressed. If an object has + * been selected (accordingly the member variable activeObject_ holds a valid objects + * identifier -as described before-) we try to get its handle by calling + * PluginFunctions::getPickedObject(). We then set the rotation matrix of the selected + * object's transform node (manipulatorNode) to hold a matrix that describes + * a rotation around the x (if w or s is pressed) or y axis (if a or d is pressed) by +/- 10 degrees. + * We then call the method transformMesh and pass the recently calculated matrix and + * a handle to the mesh (triangle or polygon). As said in \ref geometryData we have to + * inform OpenFlipper's core about the changes by calling BaseInterface::updatedObject(int). + * + * \dontinclude MouseAndKeyPlugin.cc + * \skip void MouseAndKeyPlugin::slotKeyEvent( QKeyEvent* _event ) { + * \until } // End slotKeyEvent + * + * This template method transforms the given mesh: + * + * \dontinclude MouseAndKeyPlugin.cc + * \skip template< typename MeshT > + * \until } // End transformMesh + * + * Last but not least, the method that is called each time our context menu has been clicked. + * We get the object's id on which the user has performed a right click from the action data. + * Then we try to get the node and its BaseObjectData handle. If successfully passed to this + * point we hide the object by calling its hide() method. As described in \ref geometryData + * we now have to call BaseInterface::visibilityChanged() for the core to be informed about + * the changes. + * + * \dontinclude MouseAndKeyPlugin.cc + * \skip void MouseAndKeyPlugin::contextMenuItemSelected(QAction* _action) { + * \until } // End contextMenuItemSelected + * + * \section ex3_source The complete source code of this example + * + * We use the same project file as created in \ref ex1b. + * + * MouseAndKeyPlugin.hh + * \include MouseAndKeyPlugin.hh + * + * MouseAndKeyPlugin.cc + * \include MouseAndKeyPlugin.cc */ \ No newline at end of file -- GitLab