diff --git a/Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/Step05.dox b/Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/Step05.dox index be3f6d81bb..4f22b054e3 100644 --- a/Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/Step05.dox +++ b/Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/Step05.dox @@ -1,34 +1,38 @@ /** \page Step05Page MITK Tutorial - Step 5: Interactively add points In addition to Step 4 where 3 views were created on the data, we now want to interactively add points. A node containing a PointSet as data is added to the data tree and a PointSetDataInteractor is associated with the node, which handles the interaction. The @em interaction @em pattern is defined in a state-machine, stored in an external XML file. Thus, we need to load a state-machine. - The interaction patterns defines the @em events, on which the interactor reacts (e.g., which mouse buttons are used to set a point), the @em transition to the next state (e.g., the initial - may be "empty point set") and associated @a actions (e.g., add a point at the position where the mouse-click occured). + A state machine describes interaction pattern with different states (states beeing something like "a point is selected") and transitions to these states (e.g. "select a point"). + These transitions are associated with actions. In this way it is possible to model complex interaction schemes. + By what these transitions and actions are triggered is described in a configuration file. It maps user events to identifiers that are used in the state machine patterns. + In this way the user interaction can be changed by simply loading a different configuration file for a state machine, and the user may add points now with a right click instead of + left click + SHIFT, as in our case. + + Therefore after loading the state machine pattern the PointSetDataInteractor is also given a event configuration file. + More information about interaction in MITK can be found \ref InteractionPage "here". - In order to add a point the shift key has to be pressed simultaneously to highlight the point with the mouse. + In order to add a point the shift key has to be pressed while left clicking in a render window. + You can also move points or remove them (left click while pressing ALT). \li \ref Step5.cpp "Step5.cpp"\n Contains the code for this step. \image html step5_result.png - - \dontinclude Step5.cpp - A PointSet and a node for it have to be created to be able to interactively adding points: \skipline mitk::PointSet - \until "pointsetinteractor" + \until interactor->SetDataNode(pointSetNode) \ref Step04Page "[Previous step]" \ref Step06Page "[Next step]" \ref TutorialPage "[Main tutorial page]" */ diff --git a/Examples/Tutorial/Step5/Step5.cpp b/Examples/Tutorial/Step5/Step5.cpp index 2e20b587bd..9d0fd14e36 100644 --- a/Examples/Tutorial/Step5/Step5.cpp +++ b/Examples/Tutorial/Step5/Step5.cpp @@ -1,219 +1,219 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkRegisterClasses.h" #include "QmitkRenderWindow.h" #include "QmitkSliceWidget.h" #include "mitkDataNodeFactory.h" #include "mitkProperties.h" #include "mitkRenderingManager.h" #include "mitkStandaloneDataStorage.h" -//#include "mitkGlobalInteraction.h" #include "mitkPointSet.h" +// NEW INCLUDE #include "mitkPointSetDataInteractor.h" #include #include #include //##Documentation //## @brief Interactively add points //## //## As in Step4, load one or more data sets (many image, //## surface and other formats) and create 3 views on the data. //## Additionally, we want to interactively add points. A node containing //## a PointSet as data is added to the data tree and a PointSetDataInteractor //## is associated with the node, which handles the interaction. The //## @em interaction @em pattern is defined in a state-machine, stored in an //## external XML file. Thus, we need to load a state-machine //## The interaction patterns defines the @em events, //## on which the interactor reacts (e.g., which mouse buttons are used to //## set a point), the @em transition to the next state (e.g., the initial //## may be "empty point set") and associated @a actions (e.g., add a point //## at the position where the mouse-click occured). int main(int argc, char* argv[]) { QApplication qtapplication( argc, argv ); if(argc<2) { fprintf( stderr, "Usage: %s [filename1] [filename2] ...\n\n", itksys::SystemTools::GetFilenameName(argv[0]).c_str() ); return 1; } // Register Qmitk-dependent global instances QmitkRegisterClasses(); //************************************************************************* // Part I: Basic initialization //************************************************************************* // Create a DataStorage mitk::StandaloneDataStorage::Pointer ds = mitk::StandaloneDataStorage::New(); //************************************************************************* // Part II: Create some data by reading files //************************************************************************* int i; for(i=1; iSetFileName(filename); nodeReader->Update(); //********************************************************************* // Part III: Put the data into the datastorage //********************************************************************* // Since the DataNodeFactory directly creates a node, // use the iterator to add the read node to the tree mitk::DataNode::Pointer node = nodeReader->GetOutput(); ds->Add(node); } catch(...) { fprintf( stderr, "Could not open file %s \n\n", filename ); exit(2); } } //************************************************************************* // Part V: Create windows and pass the tree to it //************************************************************************* // Create toplevel widget with horizontal layout QWidget toplevelWidget; QHBoxLayout layout; layout.setSpacing(2); layout.setMargin(0); toplevelWidget.setLayout(&layout); //************************************************************************* // Part Va: 3D view //************************************************************************* // Create a renderwindow QmitkRenderWindow renderWindow(&toplevelWidget); layout.addWidget(&renderWindow); // Tell the renderwindow which (part of) the tree to render renderWindow.GetRenderer()->SetDataStorage(ds); // Use it as a 3D view renderWindow.GetRenderer()->SetMapperID(mitk::BaseRenderer::Standard3D); //************************************************************************* // Part Vb: 2D view for slicing axially //************************************************************************* // Create QmitkSliceWidget, which is based on the class // QmitkRenderWindow, but additionally provides sliders QmitkSliceWidget view2(&toplevelWidget); layout.addWidget(&view2); // Tell the QmitkSliceWidget which (part of) the tree to render. // By default, it slices the data axially view2.SetDataStorage(ds); mitk::DataStorage::SetOfObjects::ConstPointer rs = ds->GetAll(); view2.SetData(rs->Begin(), mitk::SliceNavigationController::Axial); // We want to see the position of the slice in 2D and the // slice itself in 3D: add it to the tree! ds->Add(view2.GetRenderer()->GetCurrentWorldGeometry2DNode()); //************************************************************************* // Part Vc: 2D view for slicing sagitally //************************************************************************* // Create QmitkSliceWidget, which is based on the class // QmitkRenderWindow, but additionally provides sliders QmitkSliceWidget view3(&toplevelWidget); layout.addWidget(&view3); // Tell the QmitkSliceWidget which (part of) the tree to render // and to slice sagitall view3.SetDataStorage(ds); view3.SetData(rs->Begin(), mitk::SliceNavigationController::Sagittal); // We want to see the position of the slice in 2D and the // slice itself in 3D: add it to the tree! ds->Add(view3.GetRenderer()->GetCurrentWorldGeometry2DNode()); // ******************************************************* // ****************** START OF NEW PART ****************** // ******************************************************* //************************************************************************* // Part VI: For allowing to interactively add points ... //************************************************************************* // ATTENTION: It is very important that the renderer already know their DataStorage, // because registerig DataInteractors with the render windows is done automatically // and only works if the BaseRenderer and the DataStorage know each other. // Create PointSet and a node for it mitk::PointSet::Pointer pointSet = mitk::PointSet::New(); mitk::DataNode::Pointer pointSetNode = mitk::DataNode::New(); // Store the point set in the DataNode pointSetNode->SetData(pointSet); // Add the node to the tree ds->Add(pointSetNode); // Create PointSetDataInteractor mitk::PointSetDataInteractor::Pointer interactor = mitk::PointSetDataInteractor::New(); // Set the StateMachine pattern that describes the flow of the interactions interactor->LoadStateMachine("PointSet.xml"); // Set the configuration file, which describes the user interactions that trigger actions // in this file SHIFT + LeftClick triggers add Point, but by modifying this file, // it could as well be changes to any other user interaction. interactor->SetEventConfig("PointSetConfig.xml"); // Assign the pointSetNode to the interactor, // alternatively one could also add the DataInteractor to the pointSetNode using the SetDataInteractor() method. interactor->SetDataNode(pointSetNode); // ******************************************************* // ******************* END OF NEW PART ******************* // ******************************************************* //************************************************************************* //Part VII: Qt-specific initialization //************************************************************************* toplevelWidget.show(); // For testing #include "QtTesting.h" if(strcmp(argv[argc-1], "-testing")!=0) return qtapplication.exec(); else return QtTesting(); } /** \example Step5.cpp */