diff --git a/Modules/IGT/Documentation/doxygen/IGTTutorialStep3.dox b/Modules/IGT/Documentation/doxygen/IGTTutorialStep3.dox index 7e0d8c95eb..2b63a1eb1e 100644 --- a/Modules/IGT/Documentation/doxygen/IGTTutorialStep3.dox +++ b/Modules/IGT/Documentation/doxygen/IGTTutorialStep3.dox @@ -1,13 +1,17 @@ /** -\page IGTTutorialStepSimplePlugin Qt Gui Tutorial +\page IGTTutorialStepSimplePlugin IGT QT Tutorial -This tutorial shows how to integrate IGT in your plugin. You can enable this example in CMake with the -option: MITK_BUILD_org.mitk.gui.qt.igtexamples. The code of the plugin/view is located in: +This tutorial shows how to integrate IGT in your plugin. You can enable this example in cmake with the +option: MITK_BUILD_org.mitk.gui.qt.igtexamples. + +\imageMacro{IGTTutorialStep3_cmake.png,"",15.90} + +The code of the plugin/view is located in: MITK-Source/Plugins/org.mitk.gui.qt.igtexamples/src/internal/QmitkIGTTutorialView The plugin will automatically be lodaed in the mitkWorkbench. -More information can be found in the user manual: \ref org_imageguidedtherapytutorial "User manual" +Please read the manual page on how to use this example: \ref org_imageguidedtherapytutorial \ref Return to the \ref IGTTutorialOverview "[IGT Tutorial Overview]" */ \ No newline at end of file diff --git a/Modules/IGT/Documentation/doxygen/IGTTutorialStep3_cmake.png b/Modules/IGT/Documentation/doxygen/IGTTutorialStep3_cmake.png new file mode 100644 index 0000000000..b1395c1f9a Binary files /dev/null and b/Modules/IGT/Documentation/doxygen/IGTTutorialStep3_cmake.png differ diff --git a/Plugins/org.mitk.gui.qt.igtexamples/documentation/UserManual/QmitkIGTTutorial.dox b/Plugins/org.mitk.gui.qt.igtexamples/documentation/UserManual/QmitkIGTTutorial.dox index 60a919c5fb..c9a72db643 100644 --- a/Plugins/org.mitk.gui.qt.igtexamples/documentation/UserManual/QmitkIGTTutorial.dox +++ b/Plugins/org.mitk.gui.qt.igtexamples/documentation/UserManual/QmitkIGTTutorial.dox @@ -1,14 +1,93 @@ /** -\page org_imageguidedtherapytutorial The MITK-IGT Tutorial Module +\page org_imageguidedtherapytutorial The MITK-IGT Tutorial View -\imageMacro{QmitkIGTExamples_ImageGuidedTherapy.png,"Icon of the MITK-IGT Tutorial Module",2.00} - -\section QmitkIGTTutorialUserManualSummary Summary - -This module is not meant as a end-user module. It contains tutorial program code that explains how to use the MITK-IGT component. +This view is not meant as an end-user module. It contains tutorial program code that explains how to use the MITK-IGT component. It contains only two buttons. The "Start image guided therapy" button will create a virtual tracking device and a virtual tool. It will move the tool around on random paths in a tracking volume of 200x200x200 mm. The tool is visualized with a cone. If you do not see a cone moving around, you will need to initialize the rendering views correctly. Use the DataManager view to perform a global reinit. + +The symbol of this view is the following: + +\imageMacro{../../resources/IGTTutorial.png,"",2} + + +In this tutorial we connect to the NDI Polaris tracking system (or alternatively use a virtual tracking device) and we will show the movement of a tool as cone in the StdMultiWidget editor. + +First of all, you will have to add an IGT dependency to your cmake list. FOr this example, MitkIGTUI would be sufficient, but as the plugin contains several views, we have additional OpenIGTLink and US dependencies: + +\code{.cpp} + + project(org_mitk_gui_qt_igtexamples) + + mitk_create_plugin( + EXPORT_DIRECTIVE IGTEXAMPLES_EXPORT + EXPORTED_INCLUDE_SUFFIXES src + MODULE_DEPENDS MitkQtWidgetsExt MitkIGT MitkIGTUI MitkOpenIGTLink MitkOpenIGTLinkUI MitkUS + ) +\endcode + +More information on how to create your own plugin can be found here: \ref NewPluginPage + +The view looks like this: +\imageMacro{IGTExampleIGT_QT_Tutorial_PluginView.png,"",15.90} +When clicking the start button, a cone should move in the 3D view and stop after clicking the stop button. + +The view has several fuctions. Most of them deal with the basic functionality with the plugin (e.g. CreateQTPartControl or CreateConnections). For a deeper understanding, you might have a look at the files QmitkIGTTutorialView.cpp and QmitkIGTTutorialView.h +For our IGT functionality, the following functions are important: +\li OnStartIGT: Starts the navigation pipeline +\li OnStopIGT: Disconnect the pipeline +\li OnTimer: Updates the view + +Let's now have a deeper look at these functions. + +\section OnStartIGT OnStartIGT + +\snippet ../../src/internal/QmitkIGTTutorialView.cpp OnStart 1 + +We first check in a try environment, if we should use an NDI tracking device or a virtual device. Let's start with NDI, we hardcode the parameters here and give out a warning. In your propper application, the parameters should be set via the gui aswell (see \ref org_mitk_views_igttrackingtoolbox ), but for simplicity, we just set hardcoded parameters here. If you want to try it with your own NDI device, you need to adapt these parameters here in the code: + +\snippet ../../src/internal/QmitkIGTTutorialView.cpp OnStart 2 + +The tracking device has to be set to a source. For more information on the tracking pipeline, please have a look at the \ref IGTTutorialStepFilterPipeline. + +\snippet QmitkIGTTutorialView.cpp OnStart 3 + +Alternatively, we can setup a virtual tracking device. We create this device, set the bounds, add a tool and connect it to the source: + +\snippet QmitkIGTTutorialView.cpp OnStart 4 + +Now we need to connect the tracking system + +\snippet QmitkIGTTutorialView.cpp OnStart 5 + +For the visualisation, we need an object. Here, we create a red cone + +\snippet QmitkIGTTutorialView.cpp OnStart 6 + +The visualization filter will actually render the cone +\snippet QmitkIGTTutorialView.cpp OnStart 7 + +For a continuous display, we need to call update, here we decide to do it every 100 ms using a timer. +\snippet QmitkIGTTutorialView.cpp OnStart 8 + +Disable the selection of tracking devices during tracking: +\snippet QmitkIGTTutorialView.cpp OnStart 8a + +For propper coding, you should always catch the exceptions: +\snippet QmitkIGTTutorialView.cpp OnStart 9 + +\section OnTimer OnTimer + +Each time, the timer is updated, the following code is executed: +\snippet QmitkIGTTutorialView.cpp OnTimer + +\section OnStopIGT OnStopIGT +This function will stop the pipeline and clean up everything: +\snippet QmitkIGTTutorialView.cpp OnStop + +You now have a very simple plugin, which creates an own tracking device and starts or stops tracking. Of course, for your more advanced project, you could implement a new tracking device to be available in every plugin (see \ref IGTHowToImplementATrackingDevice) or use already implemented tracking devices via the tracking toolbox and/or microservices. This small example should just show you the most simple way to start tracking. + +\ref Return to the \ref IGTTutorialOverview "[IGT Tutorial Overview]" */ diff --git a/Plugins/org.mitk.gui.qt.igtexamples/documentation/doxygen/IGTExampleIGT_QT_Tutorial_PluginView.png b/Plugins/org.mitk.gui.qt.igtexamples/documentation/doxygen/IGTExampleIGT_QT_Tutorial_PluginView.png new file mode 100644 index 0000000000..b72414b411 Binary files /dev/null and b/Plugins/org.mitk.gui.qt.igtexamples/documentation/doxygen/IGTExampleIGT_QT_Tutorial_PluginView.png differ diff --git a/Plugins/org.mitk.gui.qt.igtexamples/plugin.xml b/Plugins/org.mitk.gui.qt.igtexamples/plugin.xml index 78eac90d20..09b9748524 100644 --- a/Plugins/org.mitk.gui.qt.igtexamples/plugin.xml +++ b/Plugins/org.mitk.gui.qt.igtexamples/plugin.xml @@ -1,38 +1,38 @@ diff --git a/Plugins/org.mitk.gui.qt.igtexamples/src/internal/QmitkIGTTutorialView.cpp b/Plugins/org.mitk.gui.qt.igtexamples/src/internal/QmitkIGTTutorialView.cpp index 6fdedc8efa..0d7c0cc7af 100644 --- a/Plugins/org.mitk.gui.qt.igtexamples/src/internal/QmitkIGTTutorialView.cpp +++ b/Plugins/org.mitk.gui.qt.igtexamples/src/internal/QmitkIGTTutorialView.cpp @@ -1,230 +1,263 @@ /*=================================================================== 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 "QmitkIGTTutorialView.h" #include "QmitkStdMultiWidget.h" #include "mitkNDIPassiveTool.h" #include "mitkNDITrackingDevice.h" #include "mitkVirtualTrackingDevice.h" #include "mitkStandardFileLocations.h" #include "mitkSerialCommunication.h" #include "mitkCone.h" #include #include #include "mitkNDIPolarisTypeInformation.h" const std::string QmitkIGTTutorialView::VIEW_ID = "org.mitk.views.igttutorial"; QmitkIGTTutorialView::QmitkIGTTutorialView() : QmitkAbstractView(), m_Controls(NULL), m_Source(NULL), m_Visualizer(NULL), m_Timer(NULL) { } QmitkIGTTutorialView::~QmitkIGTTutorialView() { } void QmitkIGTTutorialView::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widget m_Controls = new Ui::QmitkIGTTutorialViewControls; m_Controls->setupUi(parent); this->CreateConnections(); } } void QmitkIGTTutorialView::CreateConnections() { if ( m_Controls ) { connect( (QObject*)(m_Controls->m_StartButton), SIGNAL(clicked()),(QObject*) this, SLOT(OnStartIGT())); connect( (QObject*)(m_Controls->m_StopButton), SIGNAL(clicked()),(QObject*) this, SLOT(OnStopIGT())); } } void QmitkIGTTutorialView::SetFocus() { m_Controls->m_virtualTrackingRadioButton->setFocus(); } - +//The next line starts a snippet to display this code in the documentation. If you don't revise the documentation, don't remove it! + //! [OnStart 1] void QmitkIGTTutorialView::OnStartIGT() { - //This method is called when the Do IGT button is pressed. Any kind of navigation application will + //This method is called when the "Start Image Guided Therapy" button is pressed. Any kind of navigation application will //start with the connection to a tracking system and as we do image guided procedures we want to show - //something on the screen. In this tutorial we connect to the NDI Polaris tracking system and we will + //something on the screen. In this tutorial we connect to the NDI Polaris tracking system pr a virtual tracking device and we will //show the movement of a tool as cone in MITK. + + //! [OnStart 1] + + //! [OnStart 2] try { if(m_Controls->m_NDITrackingRadioButton->isChecked()) { /**************** Variant 1: Use a NDI Polaris Tracking Device ****************/ //Here we want to use the NDI Polaris tracking device. Therefore we instantiate a object of the class //NDITrackingDevice and make some settings which are necessary for a proper connection to the device. MITK_INFO << "NDI tracking"; QMessageBox::warning ( NULL, "Warning", "You have to set the parameters for the NDITracking device inside the code (QmitkIGTTutorialView::OnStartIGT()) before you can use it."); mitk::NDITrackingDevice::Pointer tracker = mitk::NDITrackingDevice::New(); //instantiate tracker->SetPortNumber(mitk::SerialCommunication::COM4); //set the comport tracker->SetBaudRate(mitk::SerialCommunication::BaudRate115200); //set the baud rate tracker->SetType(mitk::NDIPolarisTypeInformation::GetTrackingDeviceName()); //set the type there you can choose between Polaris and Aurora //The tools represent the sensors of the tracking device. In this case we have one pointer tool. //The TrackingDevice object it self fills the tool with data. So we have to add the tool to the //TrackingDevice object. // The Polaris system needs a ".rom" file which describes the geometry of the markers related to the tool tip. //NDI provides an own software (NDI architect) to generate those files. tracker->AddTool("MyInstrument", "c:\\myinstrument.rom"); + //! [OnStart 2] /**************** End of Variant 1 ****************/ - + //! [OnStart 3] //The tracking device object is used for the physical connection to the device. To use the //data inside of our tracking pipeline we need a source. This source encapsulate the tracking device //and provides objects of the type mitk::NavigationData as output. The NavigationData objects stores //position, orientation, if the data is valid or not and special error informations in a covariance //matrix. // //Typically the start of a pipeline is a TrackingDeviceSource. To work correct we have to set a //TrackingDevice object. Attention you have to set the tools before you set the whole TrackingDevice //object to the TrackingDeviceSource because the source need to know how many outputs should be //generated. m_Source = mitk::TrackingDeviceSource::New(); //We need the filter objects to stay alive, //therefore they must be members. m_Source->SetTrackingDevice(tracker); //Here we set the tracking device to the source of the pipeline. + //! [OnStart 3] + } + //! [OnStart 4] else { /**************** Variant 2: Emulate a Tracking Device with mitk::VirtualTrackingDevice ****************/ // For tests, it is useful to simulate a tracking device in software. This is what mitk::VirtualTrackingDevice does. // It will produce random position, orientation and error values for each tool that is added. MITK_INFO << "virtual tracking"<SetBounds(bounds); tracker->AddTool("MyInstrument"); // add a tool to tracker //The tracking device object is used for the physical connection to the device. To use the //data inside of our tracking pipeline we need a source. This source encapsulate the tracking device //and provides objects of the type mitk::NavigationData as output. The NavigationData objects stores //position, orientation, if the data is valid or not and special error informations in a covariance //matrix. // //Typically the start of a pipeline is a TrackingDeviceSource. To work correct we have to set a //TrackingDevice object. Attention you have to set the tools before you set the whole TrackingDevice //object to the TrackingDeviceSource because the source need to know how many outputs should be //generated. m_Source = mitk::TrackingDeviceSource::New(); //We need the filter objects to stay alive, //therefore they must be members. m_Source->SetTrackingDevice(tracker); //Here we set the tracking device to the source of the pipeline. /**************** End of Variant 2 ****************/ } + //! [OnStart 4] + + //! [OnStart 5] m_Source->Connect(); //Now we connect to the tracking system. //Note we do not call this on the TrackingDevice object + //! [OnStart 5] - + //! [OnStart 6] //As we wish to visualize our tool we need to have a PolyData which shows us the movement of our tool. //Here we take a cone shaped PolyData. In MITK you have to add the PolyData as a node into the DataStorage //to show it inside of the rendering windows. After that you can change the properties of the cone //to manipulate rendering, e.g. the position and orientation as in our case. mitk::Cone::Pointer cone = mitk::Cone::New(); //instantiate a new cone double scale[] = {10.0, 10.0, 10.0}; cone->GetGeometry()->SetSpacing(scale); //scale it a little that so we can see something mitk::DataNode::Pointer node = mitk::DataNode::New(); //generate a new node to store the cone into //the DataStorage. node->SetData(cone); //The data of that node is our cone. node->SetName("My tracked object"); //The node has additional properties like a name node->SetColor(1.0, 0.0, 0.0); //or the color. Here we make it red. this->GetDataStorage()->Add(node); //After adding the Node with the cone in it to the //DataStorage, MITK will show the cone in the //render windows. + //! [OnStart 6] + + //! [OnStart 7] //For updating the render windows we use another filter of the MITK-IGT pipeline concept. The //NavigationDataObjectVisualizationFilter needs as input a NavigationData and a //PolyData. In our case the input is the source and the PolyData our cone. //First we create a new filter for the visualization update. m_Visualizer = mitk::NavigationDataObjectVisualizationFilter::New(); m_Visualizer->SetInput(0, m_Source->GetOutput()); //Then we connect to the pipeline. m_Visualizer->SetRepresentationObject(0, cone); //After that we have to assign the cone to the input //Now this simple pipeline is ready, so we can start the tracking. Here again: We do not call the //StartTracking method from the tracker object itself. Instead we call this method from our source. m_Source->StartTracking(); + //! [OnStart 7] + //! [OnStart 8] //Now every call of m_Visualizer->Update() will show us the cone at the position and orientation //given from the tracking device. //We use a QTimer object to call this Update() method in a fixed interval. if (m_Timer == NULL) { m_Timer = new QTimer(this); //create a new timer } connect(m_Timer, SIGNAL(timeout()), this, SLOT(OnTimer())); //connect the timer to the method OnTimer() m_Timer->start(100); //Every 100ms the method OnTimer() is called. -> 10fps - //Now have look at the OnTimer() method. + //! [OnStart 8] + + //! [OnStart 8a] + //disable the tracking device selection + this->m_Controls->m_NDITrackingRadioButton->setDisabled(true); + this->m_Controls->m_virtualTrackingRadioButton->setDisabled(true); + //! [OnStart 8a] + } + //! [OnStart 9] catch (std::exception& e) { // add cleanup - MITK_INFO << "Error in QmitkIGTTutorial::OnDoIGT():" << e.what(); + MITK_INFO << "Error in QmitkIGTTutorial::OnStartIGT():" << e.what(); } + //! [OnStart 9] } - + //![OnTimer] void QmitkIGTTutorialView::OnTimer() { //Here we call the Update() method from the Visualization Filter. Internally the filter checks if //new NavigationData is available. If we have a new NavigationData the cone position and orientation //will be adapted. m_Visualizer->Update(); mitk::TimeGeometry::Pointer geo = this->GetDataStorage()->ComputeBoundingGeometry3D(this->GetDataStorage()->GetAll()); mitk::RenderingManager::GetInstance()->InitializeViews( geo ); this->RequestRenderWindowUpdate(); } + //![OnTimer] - + //![OnStop] void QmitkIGTTutorialView::OnStopIGT() { //This method is called when the Stop button is pressed. Here we disconnect the pipeline. if (m_Timer == NULL) { MITK_INFO << "No Timer was set yet!"; return; } //To disconnect the pipeline in a save way we first stop the timer than we disconnect the tracking device. //After that we destroy all filters with changing them to NULL. m_Timer->stop(); disconnect(m_Timer, SIGNAL(timeout()), this, SLOT(OnTimer())); m_Timer = NULL; m_Source->StopTracking(); m_Source->Disconnect(); m_Source = NULL; m_Visualizer = NULL; m_Source = NULL; this->GetDataStorage()->Remove(this->GetDataStorage()->GetNamedNode("My tracked object")); + + //enable the tracking device selection + this->m_Controls->m_NDITrackingRadioButton->setEnabled(true); + this->m_Controls->m_virtualTrackingRadioButton->setEnabled(true); } + //![OnStop] diff --git a/Plugins/org.mitk.gui.qt.igtexamples/src/internal/QmitkIGTTutorialView.h b/Plugins/org.mitk.gui.qt.igtexamples/src/internal/QmitkIGTTutorialView.h index f49287015b..afca84667c 100644 --- a/Plugins/org.mitk.gui.qt.igtexamples/src/internal/QmitkIGTTutorialView.h +++ b/Plugins/org.mitk.gui.qt.igtexamples/src/internal/QmitkIGTTutorialView.h @@ -1,90 +1,89 @@ /*=================================================================== 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. ===================================================================*/ #ifndef _QMITKIGTTUTORIALVIEW_H_INCLUDED #define _QMITKIGTTUTORIALVIEW_H_INCLUDED #include #include #include "ui_QmitkIGTTutorialViewControls.h" -//#include "../IgttutorialDll.h" #include "mitkTrackingDeviceSource.h" #include "mitkNavigationDataObjectVisualizationFilter.h" /** * \brief QmitkIGTTutorial shows a small typically navigation MITK view * * Any kind of navigation application will start with the connection to a tracking system * and as we do image guided procedures we want to show something on the screen. In this * tutorial we connect to the NDI Polaris tracking system (or alternatively use a virtual tracking device) * and we will show the movement of a tool as cone in the StdMultiWidget editor. * * \sa also take a look at the CMakeLists.txt of this view to see how to * link to the mitkIGT library. */ class QmitkIGTTutorialView : public QmitkAbstractView { // this is needed for all Qt objects that should have a MOC object (everything that derives from QObject) Q_OBJECT public: static const std::string VIEW_ID; QmitkIGTTutorialView(); virtual ~QmitkIGTTutorialView(); virtual void CreateQtPartControl(QWidget *parent) override; /// \brief Creation of the connections of main and control widget virtual void CreateConnections(); virtual void SetFocus() override; protected slots: /** * \brief Execute MITK-IGT Tutorial */ void OnStartIGT(); /** * \brief stop IGT scene and clean up */ void OnStopIGT(); /** * \brief timer based update of IGT scene */ void OnTimer(); protected: Ui::QmitkIGTTutorialViewControls* m_Controls; mitk::TrackingDeviceSource::Pointer m_Source; ///< source filer that connects to the tracking device mitk::NavigationDataObjectVisualizationFilter::Pointer m_Visualizer; ///< visualization filter uses output from m_Source QTimer* m_Timer; ///< timer for continuous tracking update }; #endif // _QMITKIGTTUTORIALVIEW_H_INCLUDED