diff --git a/Examples/Plugins/org.mitk.example.gui.imaging/src/internal/viewinitialization/QmitkViewInitializationView.cpp b/Examples/Plugins/org.mitk.example.gui.imaging/src/internal/viewinitialization/QmitkViewInitializationView.cpp index 1064857291..f49f59f6d0 100644 --- a/Examples/Plugins/org.mitk.example.gui.imaging/src/internal/viewinitialization/QmitkViewInitializationView.cpp +++ b/Examples/Plugins/org.mitk.example.gui.imaging/src/internal/viewinitialization/QmitkViewInitializationView.cpp @@ -1,169 +1,169 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "QmitkViewInitializationView.h" #include "mitkNodePredicateDataType.h" #include "QmitkDataStorageComboBox.h" #include "mitkCameraController.h" #include #include #include "itkCommand.h" #include const std::string QmitkViewInitializationView::VIEW_ID = "org.mitk.views.viewinitialization"; QmitkViewInitializationView::QmitkViewInitializationView() : m_Controls(nullptr) { m_CommandTag = 0; } QmitkViewInitializationView::~QmitkViewInitializationView() { } void QmitkViewInitializationView::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkViewInitializationViewControls; m_Controls->setupUi(parent); this->CreateConnections(); } } void QmitkViewInitializationView::SetFocus() { m_Controls->pbApply->setFocus(); } void QmitkViewInitializationView::CreateConnections() { if (m_Controls) { connect((QObject *)(m_Controls->pbApply), SIGNAL(clicked()), (QObject *)this, SLOT(OnApply())); connect((QObject *)(m_Controls->pbReset), SIGNAL(clicked()), (QObject *)this, SLOT(OnResetAll())); } } void QmitkViewInitializationView::Activated() { // init render window selector (List Widget) this->InitRenderWindowSelector(); } void QmitkViewInitializationView::Deactivated() { } void QmitkViewInitializationView::Visible() { } void QmitkViewInitializationView::Hidden() { } void QmitkViewInitializationView::OnApply() { - mitk::SliceNavigationController::ViewDirection viewDirection(mitk::SliceNavigationController::Axial); + mitk::AnatomicalPlane anatomicalPlane(mitk::AnatomicalPlane::Axial); if (m_Controls->rbAxial->isChecked()) - viewDirection = mitk::SliceNavigationController::Axial; + anatomicalPlane = mitk::AnatomicalPlane::Axial; else if (m_Controls->rbCoronal->isChecked()) - viewDirection = mitk::SliceNavigationController::Coronal; + anatomicalPlane = mitk::AnatomicalPlane::Coronal; else if (m_Controls->rbSagittal->isChecked()) - viewDirection = mitk::SliceNavigationController::Sagittal; + anatomicalPlane = mitk::AnatomicalPlane::Sagittal; vtkRenderWindow *renderwindow = this->GetSelectedRenderWindow(); if (renderwindow != nullptr) { mitk::BaseRenderer::GetInstance(renderwindow) ->GetSliceNavigationController() - ->Update(viewDirection, + ->Update(anatomicalPlane, m_Controls->cbTop->isChecked(), m_Controls->cbFrontSide->isChecked(), m_Controls->cbRotated->isChecked()); mitk::BaseRenderer::GetInstance(renderwindow)->GetCameraController()->Fit(); } } void QmitkViewInitializationView::OnResetAll() { /* calculate bounding geometry of these nodes */ auto bounds = this->GetDataStorage()->ComputeBoundingGeometry3D(); /* initialize the views to the bounding geometry */ mitk::RenderingManager::GetInstance()->InitializeViews(bounds); } vtkRenderWindow *QmitkViewInitializationView::GetSelectedRenderWindow() { int selectedItem = m_Controls->m_lbRenderWindows->currentRow(); int itemNumber = 0; mitk::BaseRenderer::BaseRendererMapType::iterator mapit; for (mapit = mitk::BaseRenderer::baseRendererMap.begin(); mapit != mitk::BaseRenderer::baseRendererMap.end(); mapit++, itemNumber++) { if (itemNumber == selectedItem) break; } if (itemNumber == selectedItem) { return (*mapit).first; } return nullptr; } void QmitkViewInitializationView::InitRenderWindowSelector() { itk::SimpleMemberCommand::Pointer updateRendererListCommand = itk::SimpleMemberCommand::New(); updateRendererListCommand->SetCallbackFunction(this, &QmitkViewInitializationView::UpdateRendererList); this->UpdateRendererList(); } void QmitkViewInitializationView::UpdateRendererList() { vtkRenderWindow *focusedRenderWindow = mitk::RenderingManager::GetInstance()->GetFocusedRenderWindow(); int selectedItem = -1; int itemNumber = 0; m_Controls->m_lbRenderWindows->clear(); for (mitk::BaseRenderer::BaseRendererMapType::iterator mapit = mitk::BaseRenderer::baseRendererMap.begin(); mapit != mitk::BaseRenderer::baseRendererMap.end(); mapit++, itemNumber++) { if ((*mapit).second->GetName()) { m_Controls->m_lbRenderWindows->addItem(QString((*mapit).second->GetName())); if (focusedRenderWindow == (*mapit).first) selectedItem = itemNumber; } } if (selectedItem >= 0) { m_Controls->m_lbRenderWindows->setCurrentRow(selectedItem); } else { m_Controls->m_lbRenderWindows->clearSelection(); } } diff --git a/Examples/QtFreeRender/QtFreeRender.cpp b/Examples/QtFreeRender/QtFreeRender.cpp index 07e8f8e157..9c679bbb8b 100644 --- a/Examples/QtFreeRender/QtFreeRender.cpp +++ b/Examples/QtFreeRender/QtFreeRender.cpp @@ -1,319 +1,319 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkRenderWindow.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //##Documentation //## @brief Example of a NON QT DEPENDENT MITK RENDERING APPLICATION. mitk::RenderWindow::Pointer mitkWidget1; mitk::RenderWindow::Pointer mitkWidget2; mitk::RenderWindow::Pointer mitkWidget3; mitk::RenderWindow::Pointer mitkWidget4; mitk::DisplayActionEventBroadcast::Pointer m_DisplayActionEventBroadcast; vtkSmartPointer m_RectangleRendering1; vtkSmartPointer m_RectangleRendering2; vtkSmartPointer m_RectangleRendering3; vtkSmartPointer m_RectangleRendering4; mitk::SliceNavigationController *m_TimeNavigationController = nullptr; mitk::DataStorage::Pointer m_DataStorage; mitk::DataNode::Pointer m_PlaneNode1; mitk::DataNode::Pointer m_PlaneNode2; mitk::DataNode::Pointer m_PlaneNode3; mitk::DataNode::Pointer m_Node; void InitializeWindows() { // Set default view directions for SNCs - mitkWidget1->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Axial); - mitkWidget2->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Sagittal); - mitkWidget3->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Coronal); - mitkWidget4->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Original); + mitkWidget1->GetSliceNavigationController()->SetDefaultViewDirection(mitk::AnatomicalPlane::Axial); + mitkWidget2->GetSliceNavigationController()->SetDefaultViewDirection(mitk::AnatomicalPlane::Sagittal); + mitkWidget3->GetSliceNavigationController()->SetDefaultViewDirection(mitk::AnatomicalPlane::Coronal); + mitkWidget4->GetSliceNavigationController()->SetDefaultViewDirection(mitk::AnatomicalPlane::Original); // initialize m_TimeNavigationController: send time via sliceNavigationControllers m_TimeNavigationController = mitk::RenderingManager::GetInstance()->GetTimeNavigationController(); m_TimeNavigationController->ConnectGeometryTimeEvent(mitkWidget1->GetSliceNavigationController()); m_TimeNavigationController->ConnectGeometryTimeEvent(mitkWidget2->GetSliceNavigationController()); m_TimeNavigationController->ConnectGeometryTimeEvent(mitkWidget3->GetSliceNavigationController()); m_TimeNavigationController->ConnectGeometryTimeEvent(mitkWidget4->GetSliceNavigationController()); mitkWidget1->GetSliceNavigationController()->ConnectGeometrySendEvent( mitk::BaseRenderer::GetInstance(mitkWidget4->GetVtkRenderWindow())); // reverse connection between sliceNavigationControllers and m_TimeNavigationController mitkWidget1->GetSliceNavigationController()->ConnectGeometryTimeEvent(m_TimeNavigationController); mitkWidget2->GetSliceNavigationController()->ConnectGeometryTimeEvent(m_TimeNavigationController); mitkWidget3->GetSliceNavigationController()->ConnectGeometryTimeEvent(m_TimeNavigationController); mitkWidget4->GetSliceNavigationController()->ConnectGeometryTimeEvent(m_TimeNavigationController); mitkWidget4->GetRenderer()->GetVtkRenderer()->SetBackground(0.1, 0.1, 0.1); mitkWidget4->GetRenderer()->GetVtkRenderer()->SetBackground(0.5, 0.5, 0.5); mitkWidget4->GetRenderer()->GetVtkRenderer()->GradientBackgroundOn(); m_RectangleRendering1 = vtkSmartPointer::New(); m_RectangleRendering1->SetColor(1.0, 0.0, 0.0); mitkWidget1->GetRenderer()->GetVtkRenderer()->AddViewProp(m_RectangleRendering1); m_RectangleRendering2 = vtkSmartPointer::New(); m_RectangleRendering2->SetColor(0.0, 1.0, 0.0); mitkWidget2->GetRenderer()->GetVtkRenderer()->AddViewProp(m_RectangleRendering2); m_RectangleRendering3 = vtkSmartPointer::New(); m_RectangleRendering3->SetColor(0.0, 0.0, 1.0); mitkWidget3->GetRenderer()->GetVtkRenderer()->AddViewProp(m_RectangleRendering3); m_RectangleRendering4 = vtkSmartPointer::New(); m_RectangleRendering4->SetColor(1.0, 1.0, 0.0); mitkWidget4->GetRenderer()->GetVtkRenderer()->AddViewProp(m_RectangleRendering4); } void AddDisplayPlaneSubTree() { // add the displayed planes of the multiwidget to a node to which the subtree // @a planesSubTree points ... float white[3] = {1.0f, 1.0f, 1.0f}; mitk::PlaneGeometryDataMapper2D::Pointer mapper; mitk::IntProperty::Pointer layer = mitk::IntProperty::New(1000); // ... of widget 1 m_PlaneNode1 = (mitk::BaseRenderer::GetInstance(mitkWidget1->GetVtkRenderWindow()))->GetCurrentWorldPlaneGeometryNode(); m_PlaneNode1->SetColor(white, mitk::BaseRenderer::GetInstance(mitkWidget4->GetVtkRenderWindow())); m_PlaneNode1->SetProperty("visible", mitk::BoolProperty::New(true)); m_PlaneNode1->SetProperty("name", mitk::StringProperty::New("widget1Plane")); m_PlaneNode1->SetProperty("includeInBoundingBox", mitk::BoolProperty::New(false)); m_PlaneNode1->SetProperty("helper object", mitk::BoolProperty::New(true)); m_PlaneNode1->SetProperty("layer", layer); m_PlaneNode1->SetColor(1.0, 0.0, 0.0); mapper = mitk::PlaneGeometryDataMapper2D::New(); m_PlaneNode1->SetMapper(mitk::BaseRenderer::Standard2D, mapper); // ... of widget 2 m_PlaneNode2 = (mitk::BaseRenderer::GetInstance(mitkWidget2->GetVtkRenderWindow()))->GetCurrentWorldPlaneGeometryNode(); m_PlaneNode2->SetColor(white, mitk::BaseRenderer::GetInstance(mitkWidget4->GetVtkRenderWindow())); m_PlaneNode2->SetProperty("visible", mitk::BoolProperty::New(true)); m_PlaneNode2->SetProperty("name", mitk::StringProperty::New("widget2Plane")); m_PlaneNode2->SetProperty("includeInBoundingBox", mitk::BoolProperty::New(false)); m_PlaneNode2->SetProperty("helper object", mitk::BoolProperty::New(true)); m_PlaneNode2->SetProperty("layer", layer); m_PlaneNode2->SetColor(0.0, 1.0, 0.0); mapper = mitk::PlaneGeometryDataMapper2D::New(); m_PlaneNode2->SetMapper(mitk::BaseRenderer::Standard2D, mapper); // ... of widget 3 m_PlaneNode3 = (mitk::BaseRenderer::GetInstance(mitkWidget3->GetVtkRenderWindow()))->GetCurrentWorldPlaneGeometryNode(); m_PlaneNode3->SetColor(white, mitk::BaseRenderer::GetInstance(mitkWidget4->GetVtkRenderWindow())); m_PlaneNode3->SetProperty("visible", mitk::BoolProperty::New(true)); m_PlaneNode3->SetProperty("name", mitk::StringProperty::New("widget3Plane")); m_PlaneNode3->SetProperty("includeInBoundingBox", mitk::BoolProperty::New(false)); m_PlaneNode3->SetProperty("helper object", mitk::BoolProperty::New(true)); m_PlaneNode3->SetProperty("layer", layer); m_PlaneNode3->SetColor(0.0, 0.0, 1.0); mapper = mitk::PlaneGeometryDataMapper2D::New(); m_PlaneNode3->SetMapper(mitk::BaseRenderer::Standard2D, mapper); // AddPlanesToDataStorage if (m_PlaneNode1.IsNotNull() && m_PlaneNode2.IsNotNull() && m_PlaneNode3.IsNotNull() && m_Node.IsNotNull()) { if (m_DataStorage.IsNotNull()) { m_DataStorage->Add(m_PlaneNode1); m_DataStorage->Add(m_PlaneNode2); m_DataStorage->Add(m_PlaneNode3); } } } void Fit() { vtkRenderer *vtkrenderer; mitk::BaseRenderer::GetInstance(mitkWidget1->GetVtkRenderWindow())->GetCameraController()->Fit(); mitk::BaseRenderer::GetInstance(mitkWidget2->GetVtkRenderWindow())->GetCameraController()->Fit(); mitk::BaseRenderer::GetInstance(mitkWidget3->GetVtkRenderWindow())->GetCameraController()->Fit(); mitk::BaseRenderer::GetInstance(mitkWidget4->GetVtkRenderWindow())->GetCameraController()->Fit(); int w = vtkObject::GetGlobalWarningDisplay(); vtkObject::GlobalWarningDisplayOff(); vtkrenderer = mitk::BaseRenderer::GetInstance(mitkWidget1->GetVtkRenderWindow())->GetVtkRenderer(); if (vtkrenderer != nullptr) vtkrenderer->ResetCamera(); vtkrenderer = mitk::BaseRenderer::GetInstance(mitkWidget2->GetVtkRenderWindow())->GetVtkRenderer(); if (vtkrenderer != nullptr) vtkrenderer->ResetCamera(); vtkrenderer = mitk::BaseRenderer::GetInstance(mitkWidget3->GetVtkRenderWindow())->GetVtkRenderer(); if (vtkrenderer != nullptr) vtkrenderer->ResetCamera(); vtkrenderer = mitk::BaseRenderer::GetInstance(mitkWidget4->GetVtkRenderWindow())->GetVtkRenderer(); if (vtkrenderer != nullptr) vtkrenderer->ResetCamera(); vtkObject::SetGlobalWarningDisplay(w); } int main(int argc, char *argv[]) { if (argc < 2) { fprintf(stderr, "Usage: %s [filename1] [filename2] ...\n\n", ""); return 1; } // Create a DataStorage m_DataStorage = mitk::StandaloneDataStorage::New(); //************************************************************************* // Part II: Create some data by reading files //************************************************************************* int i; for (i = 1; i < argc; ++i) { // For testing if (strcmp(argv[i], "-testing") == 0) continue; std::string filename = argv[i]; try { // Read the file and add it as a data node to the data storage mitk::DataStorage::SetOfObjects::Pointer nodes = mitk::IOUtil::Load(filename, *m_DataStorage); for (mitk::DataStorage::SetOfObjects::Iterator nodeIter = nodes->Begin(), nodeIterEnd = nodes->End(); nodeIter != nodeIterEnd; ++nodeIter) { mitk::DataNode::Pointer node = nodeIter->Value(); mitk::Image::Pointer image = dynamic_cast(node->GetData()); if (image.IsNotNull()) { // Set the property "volumerendering" to the Boolean value "true" node->SetProperty("volumerendering", mitk::BoolProperty::New(false)); node->SetProperty("name", mitk::StringProperty::New("testimage")); node->SetProperty("layer", mitk::IntProperty::New(1)); } } } catch (...) { std::cerr << "Could not open file " << filename << std::endl; exit(2); } } //************************************************************************* // Part V: Create window and pass the tree to it //************************************************************************* // Create renderwindows mitkWidget1 = mitk::RenderWindow::New(); mitkWidget2 = mitk::RenderWindow::New(); mitkWidget3 = mitk::RenderWindow::New(); mitkWidget4 = mitk::RenderWindow::New(); mitkWidget1->GetRenderer()->PrepareRender(); mitkWidget2->GetRenderer()->PrepareRender(); mitkWidget3->GetRenderer()->PrepareRender(); // Tell the renderwindow which (part of) the datastorage to render mitkWidget1->GetRenderer()->SetDataStorage(m_DataStorage); mitkWidget2->GetRenderer()->SetDataStorage(m_DataStorage); mitkWidget3->GetRenderer()->SetDataStorage(m_DataStorage); mitkWidget4->GetRenderer()->SetDataStorage(m_DataStorage); // instantiate display interactor if (m_DisplayActionEventBroadcast.IsNull()) { m_DisplayActionEventBroadcast = mitk::DisplayActionEventBroadcast::New(); m_DisplayActionEventBroadcast->LoadStateMachine("DisplayInteraction.xml"); m_DisplayActionEventBroadcast->SetEventConfig("DisplayConfigMITK.xml"); } // Use it as a 2D View mitkWidget1->GetRenderer()->SetMapperID(mitk::BaseRenderer::Standard2D); mitkWidget2->GetRenderer()->SetMapperID(mitk::BaseRenderer::Standard2D); mitkWidget3->GetRenderer()->SetMapperID(mitk::BaseRenderer::Standard2D); mitkWidget4->GetRenderer()->SetMapperID(mitk::BaseRenderer::Standard3D); mitkWidget1->SetSize(400, 400); mitkWidget2->GetVtkRenderWindow()->SetPosition(mitkWidget1->GetVtkRenderWindow()->GetPosition()[0] + 420, mitkWidget1->GetVtkRenderWindow()->GetPosition()[1]); mitkWidget2->SetSize(400, 400); mitkWidget3->GetVtkRenderWindow()->SetPosition(mitkWidget1->GetVtkRenderWindow()->GetPosition()[0], mitkWidget1->GetVtkRenderWindow()->GetPosition()[1] + 450); mitkWidget3->SetSize(400, 400); mitkWidget4->GetVtkRenderWindow()->SetPosition(mitkWidget1->GetVtkRenderWindow()->GetPosition()[0] + 420, mitkWidget1->GetVtkRenderWindow()->GetPosition()[1] + 450); mitkWidget4->SetSize(400, 400); InitializeWindows(); AddDisplayPlaneSubTree(); Fit(); // Initialize the RenderWindows auto geo = m_DataStorage->ComputeBoundingGeometry3D(m_DataStorage->GetAll()); mitk::RenderingManager::GetInstance()->InitializeViews(geo); m_DataStorage->Print(std::cout); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); // reinit the mitkVTKEventProvider; // this is only necessary once after calling // ForceImmediateUpdateAll() for the first time mitkWidget1->ReinitEventProvider(); mitkWidget2->ReinitEventProvider(); mitkWidget3->ReinitEventProvider(); mitkWidget1->GetVtkRenderWindow()->Render(); mitkWidget2->GetVtkRenderWindow()->Render(); mitkWidget3->GetVtkRenderWindow()->Render(); mitkWidget4->GetVtkRenderWindow()->Render(); mitkWidget4->GetVtkRenderWindowInteractor()->Start(); return 0; } diff --git a/Examples/Tutorial/Step4/Step4.cpp b/Examples/Tutorial/Step4/Step4.cpp index 02c99351c4..3861e4d84f 100644 --- a/Examples/Tutorial/Step4/Step4.cpp +++ b/Examples/Tutorial/Step4/Step4.cpp @@ -1,164 +1,164 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "QmitkRegisterClasses.h" #include "QmitkRenderWindow.h" #include "QmitkSliceWidget.h" #include "mitkNodePredicateDataType.h" #include "mitkProperties.h" #include "mitkRenderingManager.h" #include "mitkStandaloneDataStorage.h" #include #include #include #include #include //##Documentation //## @brief Use several views to explore data //## //## As in Step2 and Step3, load one or more data sets (many image, //## surface and other formats), but create 3 views on the data. //## The QmitkRenderWindow is used for displaying a 3D view as in Step3, //## but without volume-rendering. //## Furthermore, we create two 2D views for slicing through the data. //## We use the class QmitkSliceWidget, which is based on the class //## QmitkRenderWindow, but additionally provides sliders //## to slice through the data. We create two instances of //## QmitkSliceWidget, one for axial and one for sagittal slicing. //## The two slices are also shown at their correct position in 3D as //## well as intersection-line, each in the other 2D view. 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; i < argc; ++i) { // For testing if (strcmp(argv[i], "-testing") == 0) continue; //********************************************************************* // Part III: Put the data into the datastorage //********************************************************************* // Load datanode (eg. many image formats, surface formats, etc.) mitk::IOUtil::Load(argv[i], *ds); } //************************************************************************* // Part IV: 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 IVa: 3D view //************************************************************************* // Create a renderwindow QmitkRenderWindow renderWindow(&toplevelWidget); layout.addWidget(&renderWindow); // Tell the renderwindow which (part of) the datastorage to render renderWindow.GetRenderer()->SetDataStorage(ds); // Use it as a 3D view renderWindow.GetRenderer()->SetMapperID(mitk::BaseRenderer::Standard3D); // Reposition the camera to include all visible actors renderWindow.GetRenderer()->GetVtkRenderer()->ResetCamera(); // ******************************************************* // ****************** START OF NEW PART ****************** // ******************************************************* //************************************************************************* // Part IVb: 2D view for slicing axially //************************************************************************* // Create QmitkSliceWidget, which is based on the class // QmitkRenderWindow, but additionally provides sliders QmitkSliceWidget view2(&toplevelWidget); layout.addWidget(&view2); view2.SetLevelWindowEnabled(true); // Tell the QmitkSliceWidget which (part of) the tree to render. // By default, it slices the data axially view2.SetDataStorage(ds); // Get the image from the data storage. A predicate (mitk::NodePredicateBase) // is used to get only nodes of the type mitk::Image. mitk::DataStorage::SetOfObjects::ConstPointer rs = ds->GetSubset(mitk::TNodePredicateDataType::New()); - view2.SetData(rs->Begin(), mitk::SliceNavigationController::Axial); + view2.SetData(rs->Begin(), mitk::AnatomicalPlane::Axial); // We want to see the position of the slice in 2D and the // slice itself in 3D: add it to the datastorage! ds->Add(view2.GetRenderer()->GetCurrentWorldPlaneGeometryNode()); //************************************************************************* // Part IVc: 2D view for slicing sagittally //************************************************************************* // Create QmitkSliceWidget, which is based on the class // QmitkRenderWindow, but additionally provides sliders QmitkSliceWidget view3(&toplevelWidget); layout.addWidget(&view3); view3.SetDataStorage(ds); // Tell the QmitkSliceWidget which (part of) the datastorage to render // and to slice sagittally - view3.SetData(rs->Begin(), mitk::SliceNavigationController::Sagittal); + view3.SetData(rs->Begin(), mitk::AnatomicalPlane::Sagittal); // We want to see the position of the slice in 2D and the // slice itself in 3D: add it to the datastorage! ds->Add(view3.GetRenderer()->GetCurrentWorldPlaneGeometryNode()); // ******************************************************* // ******************* END OF NEW PART ******************* // ******************************************************* //************************************************************************* // Part V: Qt-specific initialization //************************************************************************* toplevelWidget.show(); return qtapplication.exec(); } /** \example Step4.cpp */ diff --git a/Examples/Tutorial/Step5/Step5.cpp b/Examples/Tutorial/Step5/Step5.cpp index 9faeac9d64..addd3361a1 100644 --- a/Examples/Tutorial/Step5/Step5.cpp +++ b/Examples/Tutorial/Step5/Step5.cpp @@ -1,203 +1,203 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "QmitkRegisterClasses.h" #include "QmitkRenderWindow.h" #include "QmitkSliceWidget.h" #include "mitkNodePredicateDataType.h" #include "mitkProperties.h" #include "mitkRenderingManager.h" #include "mitkStandaloneDataStorage.h" #include "mitkPointSet.h" // NEW INCLUDE #include "mitkPointSetDataInteractor.h" #include #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; i < argc; ++i) { // For testing if (strcmp(argv[i], "-testing") == 0) continue; // Load datanode (eg. many image formats, surface formats, etc.) mitk::StandaloneDataStorage::SetOfObjects::Pointer dataNodes = mitk::IOUtil::Load(argv[i], *ds); //********************************************************************* // Part III: Put the data into the datastorage //********************************************************************* // Add the node to the DataStorage if (dataNodes->empty()) { fprintf(stderr, "Could not open file %s \n\n", argv[i]); 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); // Reposition the camera to include all visible actors renderWindow.GetRenderer()->GetVtkRenderer()->ResetCamera(); //************************************************************************* // 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->GetSubset(mitk::TNodePredicateDataType::New()); - view2.SetData(rs->Begin(), mitk::SliceNavigationController::Axial); + view2.SetData(rs->Begin(), mitk::AnatomicalPlane::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()->GetCurrentWorldPlaneGeometryNode()); //************************************************************************* // Part Vc: 2D view for slicing sagittally //************************************************************************* // 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 sagittally view3.SetDataStorage(ds); - view3.SetData(rs->Begin(), mitk::SliceNavigationController::Sagittal); + view3.SetData(rs->Begin(), mitk::AnatomicalPlane::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()->GetCurrentWorldPlaneGeometryNode()); // ******************************************************* // ****************** 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(); return qtapplication.exec(); } /** \example Step5.cpp */ diff --git a/Examples/Tutorial/Step6/Step6.cpp b/Examples/Tutorial/Step6/Step6.cpp index 0d60afc0f2..a6bce70bb3 100644 --- a/Examples/Tutorial/Step6/Step6.cpp +++ b/Examples/Tutorial/Step6/Step6.cpp @@ -1,233 +1,233 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "Step6.h" #include "QmitkRenderWindow.h" #include "QmitkSliceWidget.h" #include "mitkProperties.h" #include "mitkRenderingManager.h" #include "mitkPointSet.h" #include "mitkPointSetDataInteractor.h" #include "mitkImageAccessByItk.h" #include "mitkRenderingManager.h" #include #include #include #include #include #include #include //##Documentation //## @brief Start region-grower at interactively added points Step6::Step6(int argc, char *argv[], QWidget *parent) : QWidget(parent) { // load data as in the previous steps; a reference to the first loaded // image is kept in the member m_FirstImage and used as input for the // region growing Load(argc, argv); } void Step6::Initialize() { // setup the widgets as in the previous steps, but with an additional // QVBox for a button to start the segmentation this->SetupWidgets(); // Create controlsParent widget with horizontal layout QWidget *controlsParent = new QWidget(this); this->layout()->addWidget(controlsParent); QHBoxLayout *hlayout = new QHBoxLayout(controlsParent); hlayout->setSpacing(2); QLabel *labelThresholdMin = new QLabel("Lower Threshold:", controlsParent); hlayout->addWidget(labelThresholdMin); m_LineEditThresholdMin = new QLineEdit("-1000", controlsParent); hlayout->addWidget(m_LineEditThresholdMin); QLabel *labelThresholdMax = new QLabel("Upper Threshold:", controlsParent); hlayout->addWidget(labelThresholdMax); m_LineEditThresholdMax = new QLineEdit("-400", controlsParent); hlayout->addWidget(m_LineEditThresholdMax); // create button to start the segmentation and connect its clicked() // signal to method StartRegionGrowing QPushButton *startButton = new QPushButton("start region growing", controlsParent); hlayout->addWidget(startButton); connect(startButton, SIGNAL(clicked()), this, SLOT(StartRegionGrowing())); if (m_FirstImage.IsNull()) startButton->setEnabled(false); // as in Step5, create PointSet (now as a member m_Seeds) and // associate a interactor to it m_Seeds = mitk::PointSet::New(); mitk::DataNode::Pointer pointSetNode = mitk::DataNode::New(); pointSetNode->SetData(m_Seeds); pointSetNode->SetProperty("layer", mitk::IntProperty::New(2)); m_DataStorage->Add(pointSetNode); // Create PointSetDataInteractor mitk::PointSetDataInteractor::Pointer interactor = mitk::PointSetDataInteractor::New(); interactor->LoadStateMachine("PointSet.xml"); interactor->SetEventConfig("PointSetConfig.xml"); interactor->SetDataNode(pointSetNode); } int Step6::GetThresholdMin() { return m_LineEditThresholdMin->text().toInt(); } int Step6::GetThresholdMax() { return m_LineEditThresholdMax->text().toInt(); } void Step6::StartRegionGrowing() { AccessByItk_1(m_FirstImage, RegionGrowing, this); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void Step6::Load(int argc, char *argv[]) { //************************************************************************* // Part I: Basic initialization //************************************************************************* m_DataStorage = mitk::StandaloneDataStorage::New(); //************************************************************************* // Part II: Create some data by reading files //************************************************************************* int i; for (i = 1; i < argc; ++i) { // For testing if (strcmp(argv[i], "-testing") == 0) continue; // Load datanode (eg. many image formats, surface formats, etc.) mitk::StandaloneDataStorage::SetOfObjects::Pointer dataNodes = mitk::IOUtil::Load(argv[i], *m_DataStorage); if (dataNodes->empty()) { fprintf(stderr, "Could not open file %s \n\n", argv[i]); exit(2); } mitk::Image::Pointer image = dynamic_cast(dataNodes->at(0)->GetData()); if ((m_FirstImage.IsNull()) && (image.IsNotNull())) m_FirstImage = image; } } void Step6::SetupWidgets() { //************************************************************************* // Part I: Create windows and pass the datastorage to it //************************************************************************* // Create toplevel widget with vertical layout QVBoxLayout *vlayout = new QVBoxLayout(this); vlayout->setMargin(0); vlayout->setSpacing(2); // Create viewParent widget with horizontal layout QWidget *viewParent = new QWidget(this); vlayout->addWidget(viewParent); QHBoxLayout *hlayout = new QHBoxLayout(viewParent); hlayout->setMargin(0); hlayout->setSpacing(2); //************************************************************************* // Part Ia: 3D view //************************************************************************* // Create a renderwindow QmitkRenderWindow *renderWindow = new QmitkRenderWindow(viewParent); hlayout->addWidget(renderWindow); // Tell the renderwindow which (part of) the tree to render renderWindow->GetRenderer()->SetDataStorage(m_DataStorage); // Use it as a 3D view renderWindow->GetRenderer()->SetMapperID(mitk::BaseRenderer::Standard3D); // Reposition the camera to include all visible actors renderWindow->GetRenderer()->GetVtkRenderer()->ResetCamera(); //************************************************************************* // Part Ib: 2D view for slicing axially //************************************************************************* // Create QmitkSliceWidget, which is based on the class // QmitkRenderWindow, but additionally provides sliders QmitkSliceWidget *view2 = new QmitkSliceWidget(viewParent); hlayout->addWidget(view2); // Tell the QmitkSliceWidget which (part of) the tree to render. // By default, it slices the data axially view2->SetDataStorage(m_DataStorage); mitk::DataStorage::SetOfObjects::ConstPointer rs = m_DataStorage->GetAll(); - view2->SetData(rs->Begin(), mitk::SliceNavigationController::Axial); + view2->SetData(rs->Begin(), mitk::AnatomicalPlane::Axial); // We want to see the position of the slice in 2D and the // slice itself in 3D: add it to the tree! m_DataStorage->Add(view2->GetRenderer()->GetCurrentWorldPlaneGeometryNode()); //************************************************************************* // Part Ic: 2D view for slicing sagittally //************************************************************************* // Create QmitkSliceWidget, which is based on the class // QmitkRenderWindow, but additionally provides sliders QmitkSliceWidget *view3 = new QmitkSliceWidget(viewParent); hlayout->addWidget(view3); // Tell the QmitkSliceWidget which (part of) the tree to render // and to slice sagittally view3->SetDataStorage(m_DataStorage); - view3->SetData(rs->Begin(), mitk::SliceNavigationController::Sagittal); + view3->SetData(rs->Begin(), mitk::AnatomicalPlane::Sagittal); // We want to see the position of the slice in 2D and the // slice itself in 3D: add it to the tree! m_DataStorage->Add(view3->GetRenderer()->GetCurrentWorldPlaneGeometryNode()); //************************************************************************* // Part II: handle updates: To avoid unnecessary updates, we have to //************************************************************************* // define when to update. The RenderingManager serves this purpose, and // each RenderWindow has to be registered to it. /*mitk::RenderingManager *renderingManager = mitk::RenderingManager::GetInstance(); renderingManager->AddRenderWindow( renderWindow ); renderingManager->AddRenderWindow( view2->GetRenderWindow() ); renderingManager->AddRenderWindow( view3->GetRenderWindow() );*/ } /** \example Step6.cpp */ diff --git a/Modules/Annotation/test/mitkColorBarAnnotationTest.cpp b/Modules/Annotation/test/mitkColorBarAnnotationTest.cpp index 1f5bd5812c..72e5f89301 100644 --- a/Modules/Annotation/test/mitkColorBarAnnotationTest.cpp +++ b/Modules/Annotation/test/mitkColorBarAnnotationTest.cpp @@ -1,95 +1,95 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // MITK #include #include #include #include #include #include class mitkColorBarAnnotationTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkColorBarAnnotationTestSuite); MITK_TEST(RenderColorBarAnnotation); CPPUNIT_TEST_SUITE_END(); private: /** Members used inside the different test methods. All members are initialized via setUp().*/ mitk::RenderingTestHelper m_RenderingTestHelper; std::vector m_CommandlineArgs; std::string m_PathToBall; std::string m_PathToImage; std::string m_ReferenceImagePath; public: /** * @brief mitkManualPlacementAnnotationRendererTestSuite Because the RenderingTestHelper does not have an * empty default constructor, we need this constructor to initialize the helper with a * resolution. */ mitkColorBarAnnotationTestSuite() : m_RenderingTestHelper(300, 300) {} /** * @brief Setup Initialize a fresh rendering test helper and a vector of strings * to simulate commandline arguments for vtkTesting::Test. */ void setUp() { m_RenderingTestHelper = mitk::RenderingTestHelper(300, 300); m_PathToBall = GetTestDataFilePath("ball.stl"); m_PathToImage = GetTestDataFilePath("Pic3D.nrrd"); m_ReferenceImagePath = "RenderingTestData/ReferenceScreenshots/Annotation/"; // Build a command line for the vtkTesting::Test method. // See VTK documentation and RenderingTestHelper for more information. // Use the following command line option to save the difference image // and the test image in some tmp folder // m_CommandlineArgs.push_back("-T"); // m_CommandlineArgs.push_back("/path/to/save/tmp/difference/images/"); m_CommandlineArgs.push_back("-V"); } void tearDown() {} void RenderColorBarAnnotation() { mitk::DataNode::Pointer ballnode = mitk::DataNode::New(); ballnode->SetData(mitk::IOUtil::Load(m_PathToBall)[0]); m_RenderingTestHelper.AddNodeToStorage(ballnode); mitk::DataNode::Pointer imagenode = mitk::DataNode::New(); imagenode->SetData(mitk::IOUtil::Load(m_PathToImage)[0]); m_RenderingTestHelper.AddNodeToStorage(imagenode); std::string refImagePath = GetTestDataFilePath(m_ReferenceImagePath + "mitkColorBarAnnotation.png"); // reference screenshot for this test m_CommandlineArgs.push_back(refImagePath); // Convert vector of strings to argc/argv mitk::RenderingTestHelper::ArgcHelperClass arg(m_CommandlineArgs); - m_RenderingTestHelper.SetViewDirection(mitk::SliceNavigationController::Sagittal); + m_RenderingTestHelper.SetViewDirection(mitk::AnatomicalPlane::Sagittal); mitk::ColorBarAnnotation::Pointer colorbar = mitk::ColorBarAnnotation::New(); mitk::BaseRenderer *renderer = mitk::BaseRenderer::GetInstance(m_RenderingTestHelper.GetVtkRenderWindow()); mitk::ManualPlacementAnnotationRenderer::AddAnnotation(colorbar.GetPointer(), renderer); m_RenderingTestHelper.Render(); // m_RenderingTestHelper.SaveReferenceScreenShot(refImagePath); m_RenderingTestHelper.SetAutomaticallyCloseRenderWindow(true); CPPUNIT_ASSERT(m_RenderingTestHelper.CompareRenderWindowAgainstReference(arg.GetArgc(), arg.GetArgv()) == true); } }; MITK_TEST_SUITE_REGISTRATION(mitkColorBarAnnotation) diff --git a/Modules/Annotation/test/mitkLabelAnnotation3DTest.cpp b/Modules/Annotation/test/mitkLabelAnnotation3DTest.cpp index 2da4bcb428..4cacfc82ab 100644 --- a/Modules/Annotation/test/mitkLabelAnnotation3DTest.cpp +++ b/Modules/Annotation/test/mitkLabelAnnotation3DTest.cpp @@ -1,165 +1,165 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // MITK #include #include #include #include #include #include class mitkLabelAnnotation3DTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkLabelAnnotation3DTestSuite); MITK_TEST(Render2DAnnotation); MITK_TEST(Render3DAnnotation); CPPUNIT_TEST_SUITE_END(); private: /** Members used inside the different test methods. All members are initialized via setUp().*/ mitk::RenderingTestHelper m_RenderingTestHelper; std::vector m_CommandlineArgs; std::string m_PathToBall; std::string m_PathToImage; std::string m_ReferenceImagePath; public: /** * @brief mitkManualPlacementAnnotationRendererTestSuite Because the RenderingTestHelper does not have an * empty default constructor, we need this constructor to initialize the helper with a * resolution. */ mitkLabelAnnotation3DTestSuite() : m_RenderingTestHelper(300, 300) {} /** * @brief Setup Initialize a fresh rendering test helper and a vector of strings * to simulate commandline arguments for vtkTesting::Test. */ void setUp() { m_RenderingTestHelper = mitk::RenderingTestHelper(300, 300); m_PathToBall = GetTestDataFilePath("ball.stl"); m_PathToImage = GetTestDataFilePath("Pic3D.nrrd"); m_ReferenceImagePath = "RenderingTestData/ReferenceScreenshots/Annotation/"; // Build a command line for the vtkTesting::Test method. // See VTK documentation and RenderingTestHelper for more information. // Use the following command line option to save the difference image // and the test image in some tmp folder // m_CommandlineArgs.push_back("-T"); // m_CommandlineArgs.push_back("/path/to/save/tmp/difference/images/"); m_CommandlineArgs.push_back("-V"); } void tearDown() {} void Render2DAnnotation() { std::string refImagePath = GetTestDataFilePath(m_ReferenceImagePath + "mitkLabelAnnotation2D.png"); // reference screenshot for this test m_CommandlineArgs.push_back(refImagePath); // Convert vector of strings to argc/argv mitk::RenderingTestHelper::ArgcHelperClass arg(m_CommandlineArgs); - m_RenderingTestHelper.SetViewDirection(mitk::SliceNavigationController::Sagittal); + m_RenderingTestHelper.SetViewDirection(mitk::AnatomicalPlane::Sagittal); mitk::PointSet::Pointer pointset = mitk::PointSet::New(); mitk::LabelAnnotation3D::Pointer label3d = mitk::LabelAnnotation3D::New(); mitk::Point3D offset; offset[0] = .5; offset[1] = .5; offset[2] = .5; std::vector labels; unsigned long idx = 0; for (int i = -10; i < 10; i += 4) { for (int j = -10; j < 10; j += 4) { mitk::Point3D point; point[0] = i; point[1] = j; point[2] = (i * j) / 10; pointset->InsertPoint(idx++, point); labels.push_back("test"); } } label3d->SetLabelCoordinates(pointset); label3d->SetLabelVector(labels); label3d->SetOffsetVector(offset); mitk::DataNode::Pointer datanode = mitk::DataNode::New(); datanode->SetData(pointset); datanode->SetName("pointSet"); m_RenderingTestHelper.AddNodeToStorage(datanode); mitk::BaseRenderer *renderer = mitk::BaseRenderer::GetInstance(m_RenderingTestHelper.GetVtkRenderWindow()); mitk::ManualPlacementAnnotationRenderer::AddAnnotation(label3d.GetPointer(), renderer); m_RenderingTestHelper.Render(); // m_RenderingTestHelper.SaveReferenceScreenShot(refImagePath); m_RenderingTestHelper.SetAutomaticallyCloseRenderWindow(true); CPPUNIT_ASSERT(m_RenderingTestHelper.CompareRenderWindowAgainstReference(arg.GetArgc(), arg.GetArgv()) == true); } void Render3DAnnotation() { std::string refImagePath = GetTestDataFilePath(m_ReferenceImagePath + "mitkLabelAnnotation3D.png"); // reference screenshot for this test m_CommandlineArgs.push_back(refImagePath); // Convert vector of strings to argc/argv mitk::RenderingTestHelper::ArgcHelperClass arg(m_CommandlineArgs); m_RenderingTestHelper.SetMapperIDToRender3D(); mitk::PointSet::Pointer pointset = mitk::PointSet::New(); mitk::LabelAnnotation3D::Pointer label3d = mitk::LabelAnnotation3D::New(); mitk::Point3D offset; offset[0] = .5; offset[1] = .5; offset[2] = .5; std::vector labels; unsigned long idx = 0; for (int i = -10; i < 10; i += 4) { for (int j = -10; j < 10; j += 4) { mitk::Point3D point; point[0] = i; point[1] = j; point[2] = (i * j) / 10; pointset->InsertPoint(idx++, point); labels.push_back("test"); } } label3d->SetLabelCoordinates(pointset); label3d->SetLabelVector(labels); label3d->SetOffsetVector(offset); mitk::DataNode::Pointer datanode = mitk::DataNode::New(); datanode->SetData(pointset); datanode->SetName("pointSet"); m_RenderingTestHelper.AddNodeToStorage(datanode); mitk::BaseRenderer *renderer = mitk::BaseRenderer::GetInstance(m_RenderingTestHelper.GetVtkRenderWindow()); mitk::ManualPlacementAnnotationRenderer::AddAnnotation(label3d.GetPointer(), renderer); m_RenderingTestHelper.Render(); // m_RenderingTestHelper.SaveReferenceScreenShot(refImagePath); m_RenderingTestHelper.SetAutomaticallyCloseRenderWindow(true); CPPUNIT_ASSERT(m_RenderingTestHelper.CompareRenderWindowAgainstReference(arg.GetArgc(), arg.GetArgv()) == true); } }; MITK_TEST_SUITE_REGISTRATION(mitkLabelAnnotation3D) diff --git a/Modules/Annotation/test/mitkLayoutAnnotationRendererTest.cpp b/Modules/Annotation/test/mitkLayoutAnnotationRendererTest.cpp index 642eaa51a5..d5d049b039 100644 --- a/Modules/Annotation/test/mitkLayoutAnnotationRendererTest.cpp +++ b/Modules/Annotation/test/mitkLayoutAnnotationRendererTest.cpp @@ -1,158 +1,158 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // MITK #include #include #include #include #include #include void createTextAnnotationWithLayouter(std::vector &Annotation, mitk::LayoutAnnotationRenderer::Alignment align, mitk::BaseRenderer *renderer, int fontsize, float red, float green, float blue, int prio, std::string text) { // Create a textAnnotation2D mitk::TextAnnotation2D::Pointer textAnnotation = mitk::TextAnnotation2D::New(); textAnnotation->SetText(text); textAnnotation->SetFontSize(fontsize); textAnnotation->SetColor(red, green, blue); textAnnotation->SetOpacity(1); mitk::LayoutAnnotationRenderer::AddAnnotation(textAnnotation, renderer, align, 5, 5, prio); Annotation.push_back(textAnnotation); } class mitkLayoutAnnotationRendererTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkLayoutAnnotationRendererTestSuite); MITK_TEST(Render2DAnnotation); CPPUNIT_TEST_SUITE_END(); private: /** Members used inside the different test methods. All members are initialized via setUp().*/ mitk::RenderingTestHelper m_RenderingTestHelper; std::vector m_CommandlineArgs; std::string m_PathToBall; std::string m_PathToImage; std::string m_ReferenceImagePath; public: /** * @brief mitkManualPlacementAnnotationRendererTestSuite Because the RenderingTestHelper does not have an * empty default constructor, we need this constructor to initialize the helper with a * resolution. */ mitkLayoutAnnotationRendererTestSuite() : m_RenderingTestHelper(500, 500) {} /** * @brief Setup Initialize a fresh rendering test helper and a vector of strings * to simulate commandline arguments for vtkTesting::Test. */ void setUp() { m_RenderingTestHelper = mitk::RenderingTestHelper(500, 500); m_PathToBall = GetTestDataFilePath("ball.stl"); m_PathToImage = GetTestDataFilePath("Pic3D.nrrd"); m_ReferenceImagePath = "RenderingTestData/ReferenceScreenshots/Annotation/"; // Build a command line for the vtkTesting::Test method. // See VTK documentation and RenderingTestHelper for more information. // Use the following command line option to save the difference image // and the test image in some tmp folder // m_CommandlineArgs.push_back("-T"); // m_CommandlineArgs.push_back("/path/to/save/tmp/difference/images/"); m_CommandlineArgs.push_back("-V"); } void tearDown() {} void Render2DAnnotation() { mitk::DataNode::Pointer ballnode = mitk::DataNode::New(); ballnode->SetData(mitk::IOUtil::Load(m_PathToBall)[0]); m_RenderingTestHelper.AddNodeToStorage(ballnode); mitk::DataNode::Pointer imagenode = mitk::DataNode::New(); imagenode->SetData(mitk::IOUtil::Load(m_PathToImage)[0]); m_RenderingTestHelper.AddNodeToStorage(imagenode); std::string refImagePath = GetTestDataFilePath(m_ReferenceImagePath + "LayoutAnnotationRenderer.png"); // reference screenshot for this test m_CommandlineArgs.push_back(refImagePath); // Convert vector of strings to argc/argv mitk::RenderingTestHelper::ArgcHelperClass arg(m_CommandlineArgs); - m_RenderingTestHelper.SetViewDirection(mitk::SliceNavigationController::Sagittal); + m_RenderingTestHelper.SetViewDirection(mitk::AnatomicalPlane::Sagittal); std::vector Annotation; mitk::BaseRenderer *renderer = mitk::BaseRenderer::GetInstance(m_RenderingTestHelper.GetVtkRenderWindow()); createTextAnnotationWithLayouter( Annotation, mitk::LayoutAnnotationRenderer::TopLeft, renderer, 20, 1.0, 1.0, 1.0, 1, "TopLeft1"); createTextAnnotationWithLayouter( Annotation, mitk::LayoutAnnotationRenderer::TopLeft, renderer, 15, 1.0, 1.0, 1.0, 3, "TopLeft3"); createTextAnnotationWithLayouter( Annotation, mitk::LayoutAnnotationRenderer::TopLeft, renderer, 25, 1.0, 0.0, 1.0, 2, "TopLeft2"); createTextAnnotationWithLayouter(Annotation, mitk::LayoutAnnotationRenderer::Top, renderer, 15, 1.0, 1.0, 1.0, 3, "Top3"); createTextAnnotationWithLayouter(Annotation, mitk::LayoutAnnotationRenderer::Top, renderer, 20, 1.0, 1.0, 1.0, 1, "Top1"); createTextAnnotationWithLayouter(Annotation, mitk::LayoutAnnotationRenderer::Top, renderer, 25, 1.0, 0.0, 1.0, 2, "Top2"); createTextAnnotationWithLayouter( Annotation, mitk::LayoutAnnotationRenderer::TopRight, renderer, 20, 1.0, 1.0, 1.0, 1, "TopRight1"); createTextAnnotationWithLayouter( Annotation, mitk::LayoutAnnotationRenderer::TopRight, renderer, 15, 1.0, 1.0, 1.0, 3, "TopRight3"); createTextAnnotationWithLayouter( Annotation, mitk::LayoutAnnotationRenderer::TopRight, renderer, 25, 1.0, 0.0, 1.0, 2, "TopRight2"); createTextAnnotationWithLayouter(Annotation, mitk::LayoutAnnotationRenderer::Left, renderer, 20, 1.0, 1.0, 1.0, 1, "Left1"); createTextAnnotationWithLayouter(Annotation, mitk::LayoutAnnotationRenderer::Left, renderer, 15, 1.0, 1.0, 1.0, 3, "Left3"); createTextAnnotationWithLayouter(Annotation, mitk::LayoutAnnotationRenderer::Left, renderer, 25, 1.0, 0.0, 1.0, 2, "Left2"); createTextAnnotationWithLayouter(Annotation, mitk::LayoutAnnotationRenderer::Right, renderer, 25, 1.0, 0.0, 1.0, 2, "Right2"); createTextAnnotationWithLayouter(Annotation, mitk::LayoutAnnotationRenderer::Right, renderer, 20, 1.0, 1.0, 1.0, 1, "Right1"); createTextAnnotationWithLayouter(Annotation, mitk::LayoutAnnotationRenderer::Right, renderer, 15, 1.0, 1.0, 1.0, 3, "Right3"); createTextAnnotationWithLayouter( Annotation, mitk::LayoutAnnotationRenderer::BottomLeft, renderer, 25, 1.0, 0.0, 1.0, 2, "BottomLeft2"); createTextAnnotationWithLayouter( Annotation, mitk::LayoutAnnotationRenderer::BottomLeft, renderer, 20, 1.0, 1.0, 1.0, 1, "BottomLeft1"); createTextAnnotationWithLayouter( Annotation, mitk::LayoutAnnotationRenderer::BottomLeft, renderer, 15, 1.0, 1.0, 1.0, 3, "BottomLeft3"); createTextAnnotationWithLayouter(Annotation, mitk::LayoutAnnotationRenderer::Bottom, renderer, 15, 1.0, 1.0, 1.0, 3, "Bottom3"); createTextAnnotationWithLayouter(Annotation, mitk::LayoutAnnotationRenderer::Bottom, renderer, 20, 1.0, 1.0, 1.0, 1, "Bottom1"); createTextAnnotationWithLayouter(Annotation, mitk::LayoutAnnotationRenderer::Bottom, renderer, 25, 1.0, 0.0, 1.0, 2, "Bottom2"); createTextAnnotationWithLayouter( Annotation, mitk::LayoutAnnotationRenderer::BottomRight, renderer, 25, 1.0, 0.0, 1.0, 2, "BottomRight2"); createTextAnnotationWithLayouter( Annotation, mitk::LayoutAnnotationRenderer::BottomRight, renderer, 20, 1.0, 1.0, 1.0, 1, "BottomRight1"); createTextAnnotationWithLayouter( Annotation, mitk::LayoutAnnotationRenderer::BottomRight, renderer, 15, 1.0, 1.0, 1.0, 3, "BottomRight3"); m_RenderingTestHelper.Render(); // m_RenderingTestHelper.SaveReferenceScreenShot(refImagePath); m_RenderingTestHelper.SetAutomaticallyCloseRenderWindow(true); CPPUNIT_ASSERT(m_RenderingTestHelper.CompareRenderWindowAgainstReference(arg.GetArgc(), arg.GetArgv()) == true); } }; MITK_TEST_SUITE_REGISTRATION(mitkLayoutAnnotationRenderer) diff --git a/Modules/Annotation/test/mitkLogoAnnotationTest.cpp b/Modules/Annotation/test/mitkLogoAnnotationTest.cpp index a888d4f9e5..ab2cdfe98c 100644 --- a/Modules/Annotation/test/mitkLogoAnnotationTest.cpp +++ b/Modules/Annotation/test/mitkLogoAnnotationTest.cpp @@ -1,142 +1,142 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // MITK #include #include #include #include #include #include class mitkLogoAnnotationTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkLogoAnnotationTestSuite); MITK_TEST(RenderMbiLogo); MITK_TEST(RenderLogo); CPPUNIT_TEST_SUITE_END(); private: /** Members used inside the different test methods. All members are initialized via setUp().*/ mitk::RenderingTestHelper m_RenderingTestHelper; std::vector m_CommandlineArgs; std::string m_PathToBall; std::string m_PathToImage; std::string m_PathToLogo; std::string m_PathToMitkLogo; std::string m_ReferenceImagePath; public: /** * @brief mitkManualPlacementAnnotationRendererTestSuite Because the RenderingTestHelper does not have an * empty default constructor, we need this constructor to initialize the helper with a * resolution. */ mitkLogoAnnotationTestSuite() : m_RenderingTestHelper(300, 300) {} /** * @brief Setup Initialize a fresh rendering test helper and a vector of strings * to simulate commandline arguments for vtkTesting::Test. */ void setUp() { m_RenderingTestHelper = mitk::RenderingTestHelper(300, 300); m_PathToBall = GetTestDataFilePath("ball.stl"); m_PathToImage = GetTestDataFilePath("Pic3D.nrrd"); m_PathToLogo = GetTestDataFilePath("RenderingTestData/texture.jpg"); m_PathToMitkLogo = GetTestDataFilePath("RenderingTestData/defaultWatermark.png"); m_ReferenceImagePath = "RenderingTestData/ReferenceScreenshots/Annotation/"; // Build a command line for the vtkTesting::Test method. // See VTK documentation and RenderingTestHelper for more information. // Use the following command line option to save the difference image // and the test image in some tmp folder // m_CommandlineArgs.push_back("-T"); // m_CommandlineArgs.push_back("/path/to/save/tmp/difference/images/"); m_CommandlineArgs.push_back("-V"); } void tearDown() {} void RenderMbiLogo() { mitk::DataNode::Pointer ballnode = mitk::DataNode::New(); ballnode->SetData(mitk::IOUtil::Load(m_PathToBall)[0]); m_RenderingTestHelper.AddNodeToStorage(ballnode); mitk::DataNode::Pointer imagenode = mitk::DataNode::New(); imagenode->SetData(mitk::IOUtil::Load(m_PathToImage)[0]); m_RenderingTestHelper.AddNodeToStorage(imagenode); std::string refImagePath = GetTestDataFilePath(m_ReferenceImagePath + "LogoAnnotation_mitkLogo.png"); // reference screenshot for this test m_CommandlineArgs.push_back(refImagePath); // Convert vector of strings to argc/argv mitk::RenderingTestHelper::ArgcHelperClass arg(m_CommandlineArgs); - m_RenderingTestHelper.SetViewDirection(mitk::SliceNavigationController::Sagittal); + m_RenderingTestHelper.SetViewDirection(mitk::AnatomicalPlane::Sagittal); mitk::LogoAnnotation::Pointer logoAnnotation = mitk::LogoAnnotation::New(); logoAnnotation->SetLogoImagePath(m_PathToMitkLogo); logoAnnotation->LoadLogoImageFromPath(); logoAnnotation->SetOpacity(0.5); mitk::Point2D offset; offset.Fill(0.03); logoAnnotation->SetOffsetVector(offset); logoAnnotation->SetRelativeSize(0.5); logoAnnotation->SetCornerPosition(1); mitk::BaseRenderer *renderer = mitk::BaseRenderer::GetInstance(m_RenderingTestHelper.GetVtkRenderWindow()); mitk::ManualPlacementAnnotationRenderer::AddAnnotation(logoAnnotation.GetPointer(), renderer); m_RenderingTestHelper.Render(); // m_RenderingTestHelper.SaveReferenceScreenShot(refImagePath); m_RenderingTestHelper.SetAutomaticallyCloseRenderWindow(true); CPPUNIT_ASSERT(m_RenderingTestHelper.CompareRenderWindowAgainstReference(arg.GetArgc(), arg.GetArgv()) == true); } void RenderLogo() { mitk::DataNode::Pointer ballnode = mitk::DataNode::New(); ballnode->SetData(mitk::IOUtil::Load(m_PathToBall)[0]); m_RenderingTestHelper.AddNodeToStorage(ballnode); mitk::DataNode::Pointer imagenode = mitk::DataNode::New(); imagenode->SetData(mitk::IOUtil::Load(m_PathToImage)[0]); m_RenderingTestHelper.AddNodeToStorage(imagenode); std::string refImagePath = GetTestDataFilePath(m_ReferenceImagePath + "LogoAnnotation.png"); // reference screenshot for this test m_CommandlineArgs.push_back(refImagePath); // Convert vector of strings to argc/argv mitk::RenderingTestHelper::ArgcHelperClass arg(m_CommandlineArgs); - m_RenderingTestHelper.SetViewDirection(mitk::SliceNavigationController::Sagittal); + m_RenderingTestHelper.SetViewDirection(mitk::AnatomicalPlane::Sagittal); mitk::LogoAnnotation::Pointer logoAnnotation = mitk::LogoAnnotation::New(); logoAnnotation->SetLogoImagePath(m_PathToLogo); logoAnnotation->LoadLogoImageFromPath(); mitk::BaseRenderer *renderer = mitk::BaseRenderer::GetInstance(m_RenderingTestHelper.GetVtkRenderWindow()); mitk::ManualPlacementAnnotationRenderer::AddAnnotation(logoAnnotation.GetPointer(), renderer); m_RenderingTestHelper.Render(); // m_RenderingTestHelper.SaveReferenceScreenShot(refImagePath); m_RenderingTestHelper.SetAutomaticallyCloseRenderWindow(true); CPPUNIT_ASSERT(m_RenderingTestHelper.CompareRenderWindowAgainstReference(arg.GetArgc(), arg.GetArgv()) == true); } }; MITK_TEST_SUITE_REGISTRATION(mitkLogoAnnotation) diff --git a/Modules/Annotation/test/mitkManualPlacementAnnotationRendererTest.cpp b/Modules/Annotation/test/mitkManualPlacementAnnotationRendererTest.cpp index fb2c9c4084..1325cbdc8c 100644 --- a/Modules/Annotation/test/mitkManualPlacementAnnotationRendererTest.cpp +++ b/Modules/Annotation/test/mitkManualPlacementAnnotationRendererTest.cpp @@ -1,138 +1,138 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // MITK #include #include #include #include #include #include #include class mitkManualPlacementAnnotationRendererTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkManualPlacementAnnotationRendererTestSuite); MITK_TEST(Render2DAnnotation); MITK_TEST(Render3DAnnotation); CPPUNIT_TEST_SUITE_END(); private: /** Members used inside the different test methods. All members are initialized via setUp().*/ mitk::RenderingTestHelper m_RenderingTestHelper; std::vector m_CommandlineArgs; std::string m_PathToBall; std::string m_PathToImage; std::string m_ReferenceImagePath; public: /** * @brief mitkManualPlacementAnnotationRendererTestSuite Because the RenderingTestHelper does not have an * empty default constructor, we need this constructor to initialize the helper with a * resolution. */ mitkManualPlacementAnnotationRendererTestSuite() : m_RenderingTestHelper(300, 300) {} /** * @brief Setup Initialize a fresh rendering test helper and a vector of strings * to simulate commandline arguments for vtkTesting::Test. */ void setUp() { m_RenderingTestHelper = mitk::RenderingTestHelper(300, 300); m_PathToBall = GetTestDataFilePath("ball.stl"); m_PathToImage = GetTestDataFilePath("Pic3D.nrrd"); m_ReferenceImagePath = "RenderingTestData/ReferenceScreenshots/Annotation/"; // Build a command line for the vtkTesting::Test method. // See VTK documentation and RenderingTestHelper for more information. // Use the following command line option to save the difference image // and the test image in some tmp folder // m_CommandlineArgs.push_back("-T"); // m_CommandlineArgs.push_back("/path/to/save/tmp/difference/images/"); m_CommandlineArgs.push_back("-V"); } void tearDown() {} void Render2DAnnotation() { mitk::DataNode::Pointer ballnode = mitk::DataNode::New(); ballnode->SetData(mitk::IOUtil::Load(m_PathToBall)[0]); m_RenderingTestHelper.AddNodeToStorage(ballnode); mitk::DataNode::Pointer imagenode = mitk::DataNode::New(); imagenode->SetData(mitk::IOUtil::Load(m_PathToImage)[0]); m_RenderingTestHelper.AddNodeToStorage(imagenode); std::string refImagePath = GetTestDataFilePath(m_ReferenceImagePath + "ManualPlacementAnnotationRenderer2DAnnotation.png"); // reference screenshot for this test m_CommandlineArgs.push_back(refImagePath); // Convert vector of strings to argc/argv mitk::RenderingTestHelper::ArgcHelperClass arg(m_CommandlineArgs); - m_RenderingTestHelper.SetViewDirection(mitk::SliceNavigationController::Sagittal); + m_RenderingTestHelper.SetViewDirection(mitk::AnatomicalPlane::Sagittal); mitk::TextAnnotation2D::Pointer textAnnotation2D = mitk::TextAnnotation2D::New(); textAnnotation2D->SetText("TEST ManualPlacementAnnotationRenderer2DAnnotation"); mitk::Point2D pos; pos[0] = 0; pos[1] = 0; textAnnotation2D->SetPosition2D(pos); mitk::BaseRenderer *renderer = mitk::BaseRenderer::GetInstance(m_RenderingTestHelper.GetVtkRenderWindow()); mitk::ManualPlacementAnnotationRenderer::AddAnnotation(textAnnotation2D.GetPointer(), renderer); m_RenderingTestHelper.Render(); // m_RenderingTestHelper.SaveReferenceScreenShot(refImagePath); m_RenderingTestHelper.SetAutomaticallyCloseRenderWindow(true); CPPUNIT_ASSERT(m_RenderingTestHelper.CompareRenderWindowAgainstReference(arg.GetArgc(), arg.GetArgv()) == true); } void Render3DAnnotation() { mitk::DataNode::Pointer ballnode = mitk::DataNode::New(); ballnode->SetData(mitk::IOUtil::Load(m_PathToBall)[0]); m_RenderingTestHelper.AddNodeToStorage(ballnode); mitk::DataNode::Pointer imagenode = mitk::DataNode::New(); imagenode->SetData(mitk::IOUtil::Load(m_PathToImage)[0]); m_RenderingTestHelper.AddNodeToStorage(imagenode); std::string refImagePath = GetTestDataFilePath(m_ReferenceImagePath + "ManualPlacementAnnotationRenderer3DAnnotation.png"); // reference screenshot for this test m_CommandlineArgs.push_back(refImagePath); // Convert vector of strings to argc/argv mitk::RenderingTestHelper::ArgcHelperClass arg(m_CommandlineArgs); m_RenderingTestHelper.SetMapperIDToRender3D(); mitk::TextAnnotation3D::Pointer textAnnotation3D = mitk::TextAnnotation3D::New(); textAnnotation3D->SetText("TEST ManualPlacementAnnotationRenderer3DAnnotation"); mitk::Point3D pos; pos[0] = 10; pos[1] = 10; pos[2] = 10; textAnnotation3D->SetPosition3D(pos); mitk::BaseRenderer *renderer = mitk::BaseRenderer::GetInstance(m_RenderingTestHelper.GetVtkRenderWindow()); mitk::ManualPlacementAnnotationRenderer::AddAnnotation(textAnnotation3D.GetPointer(), renderer); m_RenderingTestHelper.Render(); // m_RenderingTestHelper.SaveReferenceScreenShot(refImagePath); m_RenderingTestHelper.SetAutomaticallyCloseRenderWindow(true); CPPUNIT_ASSERT(m_RenderingTestHelper.CompareRenderWindowAgainstReference(arg.GetArgc(), arg.GetArgv()) == true); } }; MITK_TEST_SUITE_REGISTRATION(mitkManualPlacementAnnotationRenderer) diff --git a/Modules/Annotation/test/mitkScaleLegendAnnotationTest.cpp b/Modules/Annotation/test/mitkScaleLegendAnnotationTest.cpp index 5b28018ee4..1cfd0fb51d 100644 --- a/Modules/Annotation/test/mitkScaleLegendAnnotationTest.cpp +++ b/Modules/Annotation/test/mitkScaleLegendAnnotationTest.cpp @@ -1,95 +1,95 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // MITK #include #include #include #include #include #include class mitkScaleLegendAnnotationTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkScaleLegendAnnotationTestSuite); MITK_TEST(RenderScaleLegendAnnotation); CPPUNIT_TEST_SUITE_END(); private: /** Members used inside the different test methods. All members are initialized via setUp().*/ mitk::RenderingTestHelper m_RenderingTestHelper; std::vector m_CommandlineArgs; std::string m_PathToBall; std::string m_PathToImage; std::string m_ReferenceImagePath; public: /** * @brief mitkManualPlacementAnnotationRendererTestSuite Because the RenderingTestHelper does not have an * empty default constructor, we need this constructor to initialize the helper with a * resolution. */ mitkScaleLegendAnnotationTestSuite() : m_RenderingTestHelper(300, 300) {} /** * @brief Setup Initialize a fresh rendering test helper and a vector of strings * to simulate commandline arguments for vtkTesting::Test. */ void setUp() { m_RenderingTestHelper = mitk::RenderingTestHelper(300, 300); m_PathToBall = GetTestDataFilePath("ball.stl"); m_PathToImage = GetTestDataFilePath("Pic3D.nrrd"); m_ReferenceImagePath = "RenderingTestData/ReferenceScreenshots/Annotation/"; // Build a command line for the vtkTesting::Test method. // See VTK documentation and RenderingTestHelper for more information. // Use the following command line option to save the difference image // and the test image in some tmp folder // m_CommandlineArgs.push_back("-T"); // m_CommandlineArgs.push_back("/path/to/save/tmp/difference/images/"); m_CommandlineArgs.push_back("-V"); } void tearDown() {} void RenderScaleLegendAnnotation() { mitk::DataNode::Pointer ballnode = mitk::DataNode::New(); ballnode->SetData(mitk::IOUtil::Load(m_PathToBall)[0]); m_RenderingTestHelper.AddNodeToStorage(ballnode); mitk::DataNode::Pointer imagenode = mitk::DataNode::New(); imagenode->SetData(mitk::IOUtil::Load(m_PathToImage)[0]); m_RenderingTestHelper.AddNodeToStorage(imagenode); std::string refImagePath = GetTestDataFilePath(m_ReferenceImagePath + "mitkScaleLegendAnnotation.png"); // reference screenshot for this test m_CommandlineArgs.push_back(refImagePath); // Convert vector of strings to argc/argv mitk::RenderingTestHelper::ArgcHelperClass arg(m_CommandlineArgs); - m_RenderingTestHelper.SetViewDirection(mitk::SliceNavigationController::Sagittal); + m_RenderingTestHelper.SetViewDirection(mitk::AnatomicalPlane::Sagittal); mitk::ScaleLegendAnnotation::Pointer colorbar = mitk::ScaleLegendAnnotation::New(); mitk::BaseRenderer *renderer = mitk::BaseRenderer::GetInstance(m_RenderingTestHelper.GetVtkRenderWindow()); mitk::ManualPlacementAnnotationRenderer::AddAnnotation(colorbar.GetPointer(), renderer); m_RenderingTestHelper.Render(); // m_RenderingTestHelper.SaveReferenceScreenShot(refImagePath); m_RenderingTestHelper.SetAutomaticallyCloseRenderWindow(true); CPPUNIT_ASSERT(m_RenderingTestHelper.CompareRenderWindowAgainstReference(arg.GetArgc(), arg.GetArgv()) == true); } }; MITK_TEST_SUITE_REGISTRATION(mitkScaleLegendAnnotation) diff --git a/Modules/Annotation/test/mitkTextAnnotation2DTest.cpp b/Modules/Annotation/test/mitkTextAnnotation2DTest.cpp index 508966b0e6..fd44c53b70 100644 --- a/Modules/Annotation/test/mitkTextAnnotation2DTest.cpp +++ b/Modules/Annotation/test/mitkTextAnnotation2DTest.cpp @@ -1,101 +1,101 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // MITK #include #include #include #include #include #include class mitkTextAnnotation2DTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkTextAnnotation2DTestSuite); MITK_TEST(Render2DAnnotation); CPPUNIT_TEST_SUITE_END(); private: /** Members used inside the different test methods. All members are initialized via setUp().*/ mitk::RenderingTestHelper m_RenderingTestHelper; std::vector m_CommandlineArgs; std::string m_PathToBall; std::string m_PathToImage; std::string m_ReferenceImagePath; public: /** * @brief mitkTextAnnotation2DTestSuite Because the RenderingTestHelper does not have an * empty default constructor, we need this constructor to initialize the helper with a * resolution. */ mitkTextAnnotation2DTestSuite() : m_RenderingTestHelper(300, 300) {} /** * @brief Setup Initialize a fresh rendering test helper and a vector of strings * to simulate commandline arguments for vtkTesting::Test. */ void setUp() { m_RenderingTestHelper = mitk::RenderingTestHelper(300, 300); m_PathToBall = GetTestDataFilePath("ball.stl"); m_PathToImage = GetTestDataFilePath("Pic3D.nrrd"); m_ReferenceImagePath = "RenderingTestData/ReferenceScreenshots/Annotation/"; // Build a command line for the vtkTesting::Test method. // See VTK documentation and RenderingTestHelper for more information. // Use the following command line option to save the difference image // and the test image in some tmp folder // m_CommandlineArgs.push_back("-T"); // m_CommandlineArgs.push_back("/path/to/save/tmp/difference/images/"); m_CommandlineArgs.push_back("-V"); } void tearDown() {} void Render2DAnnotation() { mitk::DataNode::Pointer ballnode = mitk::DataNode::New(); ballnode->SetData(mitk::IOUtil::Load(m_PathToBall)[0]); m_RenderingTestHelper.AddNodeToStorage(ballnode); mitk::DataNode::Pointer imagenode = mitk::DataNode::New(); imagenode->SetData(mitk::IOUtil::Load(m_PathToImage)[0]); m_RenderingTestHelper.AddNodeToStorage(imagenode); std::string refImagePath = GetTestDataFilePath(m_ReferenceImagePath + "TextAnnotation2D.png"); // reference screenshot for this test m_CommandlineArgs.push_back(refImagePath); // Convert vector of strings to argc/argv mitk::RenderingTestHelper::ArgcHelperClass arg(m_CommandlineArgs); - m_RenderingTestHelper.SetViewDirection(mitk::SliceNavigationController::Sagittal); + m_RenderingTestHelper.SetViewDirection(mitk::AnatomicalPlane::Sagittal); mitk::TextAnnotation2D::Pointer textAnnotation2D = mitk::TextAnnotation2D::New(); textAnnotation2D->SetText("TEST TextAnnotation2D2DAnnotation"); mitk::Point2D pos; pos[0] = 0; pos[1] = 0; textAnnotation2D->SetPosition2D(pos); mitk::BaseRenderer *renderer = mitk::BaseRenderer::GetInstance(m_RenderingTestHelper.GetVtkRenderWindow()); mitk::ManualPlacementAnnotationRenderer::AddAnnotation(textAnnotation2D.GetPointer(), renderer); m_RenderingTestHelper.Render(); // m_RenderingTestHelper.SaveReferenceScreenShot(refImagePath); m_RenderingTestHelper.SetAutomaticallyCloseRenderWindow(true); CPPUNIT_ASSERT(m_RenderingTestHelper.CompareRenderWindowAgainstReference(arg.GetArgc(), arg.GetArgv()) == true); } }; MITK_TEST_SUITE_REGISTRATION(mitkTextAnnotation2D) diff --git a/Modules/Classification/CLMiniApps/CLOverlayRoiCenterOfMass.cpp b/Modules/Classification/CLMiniApps/CLOverlayRoiCenterOfMass.cpp index be37ab6a6d..62465f1958 100644 --- a/Modules/Classification/CLMiniApps/CLOverlayRoiCenterOfMass.cpp +++ b/Modules/Classification/CLMiniApps/CLOverlayRoiCenterOfMass.cpp @@ -1,173 +1,173 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkCLPolyToNrrd_cpp #define mitkCLPolyToNrrd_cpp #include "time.h" #include #include #include #include "mitkCommandLineParser.h" #include #include #include #include #include #include "QmitkRegisterClasses.h" #include "QmitkRenderWindow.h" #include "vtkRenderLargeImage.h" #include "vtkPNGWriter.h" #include #include typedef itk::Image< double, 3 > FloatImageType; typedef itk::Image< unsigned char, 3 > MaskImageType; template static void FindMostSampleSlice(itk::Image* mask, int & selectedSlice) { int idx = VImageDimension - 1; int size = mask->GetLargestPossibleRegion().GetSize()[idx]; std::vector numberOfSamples; numberOfSamples.resize(size,0); itk::ImageRegionIteratorWithIndex > mask1Iter(mask, mask->GetLargestPossibleRegion()); while (!mask1Iter.IsAtEnd()) { if (mask1Iter.Value() > 0) { numberOfSamples[mask1Iter.GetIndex()[idx]]+=1; } ++mask1Iter; } selectedSlice = 0; for (std::size_t i = 0; i < numberOfSamples.size(); ++i) { if (numberOfSamples[selectedSlice] < numberOfSamples[i]) selectedSlice = i; } } static void SaveSliceOrImageAsPNG(mitk::Image::Pointer image, mitk::Image::Pointer mask, std::string path, int index) { // Create a Standalone Datastorage for the single purpose of saving screenshots.. mitk::StandaloneDataStorage::Pointer ds = mitk::StandaloneDataStorage::New(); QmitkRenderWindow renderWindow; renderWindow.GetRenderer()->SetDataStorage(ds); auto nodeI = mitk::DataNode::New(); nodeI->SetData(image); auto nodeM = mitk::DataNode::New(); nodeM->SetData(mask); ds->Add(nodeI); ds->Add(nodeM); auto geo = ds->ComputeBoundingGeometry3D(ds->GetAll()); mitk::RenderingManager::GetInstance()->InitializeViews(mask->GetTimeGeometry()); mitk::SliceNavigationController::Pointer sliceNaviController = renderWindow.GetSliceNavigationController(); - sliceNaviController->SetViewDirection(mitk::SliceNavigationController::Axial); + sliceNaviController->SetViewDirection(mitk::AnatomicalPlane::Axial); unsigned int numberOfSteps = 1; if (sliceNaviController) { numberOfSteps = sliceNaviController->GetSlice()->GetSteps(); sliceNaviController->GetSlice()->SetPos(numberOfSteps-index); } renderWindow.show(); renderWindow.resize(256, 256); //if (sliceNaviController) //{ // sliceNaviController->GetSlice()->SetPos(index); //} renderWindow.GetRenderer()->PrepareRender(); vtkRenderWindow* renderWindow2 = renderWindow.GetVtkRenderWindow(); mitk::BaseRenderer* baserenderer = mitk::BaseRenderer::GetInstance(renderWindow2); auto vtkRender = baserenderer->GetVtkRenderer(); vtkRender->GetRenderWindow()->WaitForCompletion(); vtkRenderLargeImage* magnifier = vtkRenderLargeImage::New(); magnifier->SetInput(vtkRender); magnifier->SetMagnification(3.0); std::stringstream ss; ss << path <<".png"; std::string tmpImageName; ss >> tmpImageName; auto fileWriter = vtkPNGWriter::New(); fileWriter->SetInputConnection(magnifier->GetOutputPort()); fileWriter->SetFileName(tmpImageName.c_str()); fileWriter->Write(); fileWriter->Delete(); } int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setArgumentPrefix("--", "-"); parser.addArgument("image", "i", mitkCommandLineParser::Image, "Input Image", "", us::Any(),false, false, false, mitkCommandLineParser::Input); parser.addArgument("mask", "m", mitkCommandLineParser::Image, "Input Image", "", us::Any(),false, false, false, mitkCommandLineParser::Input); parser.addArgument("output", "o", mitkCommandLineParser::Image, "Output Image", "", us::Any(),false, false, false, mitkCommandLineParser::Input); // Miniapp Infos parser.setCategory("Classification Tools"); parser.setTitle("Image with Overlay Plotter"); parser.setDescription("Plots "); parser.setContributor("German Cancer Research Center (DKFZ)"); std::map parsedArgs = parser.parseArguments(argc, argv); std::string imagePath = us::any_cast(parsedArgs["image"]); std::string maskPath = us::any_cast(parsedArgs["mask"]); std::string outputPath = us::any_cast(parsedArgs["output"]); if (parsedArgs.size()==0) { return EXIT_FAILURE; } if ( parsedArgs.count("help") || parsedArgs.count("h")) { return EXIT_SUCCESS; } std::string version = "Version: 1.0"; MITK_INFO << version; mitk::Image::Pointer image = mitk::IOUtil::Load(imagePath); mitk::Image::Pointer mask = mitk::IOUtil::Load(maskPath); // Create a QTApplication and a Datastorage // This is necessary in order to save screenshots of // each image / slice. QApplication qtapplication(argc, argv); QmitkRegisterClasses(); int currentSlice = 0; AccessByItk_1(mask, FindMostSampleSlice, currentSlice); SaveSliceOrImageAsPNG(image, mask, outputPath, currentSlice); return 0; } #endif diff --git a/Modules/Core/TestingHelper/include/mitkInteractionTestHelper.h b/Modules/Core/TestingHelper/include/mitkInteractionTestHelper.h index 0c44c6c66f..54898eb180 100644 --- a/Modules/Core/TestingHelper/include/mitkInteractionTestHelper.h +++ b/Modules/Core/TestingHelper/include/mitkInteractionTestHelper.h @@ -1,146 +1,146 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkInteractionTestHelper_h #define mitkInteractionTestHelper_h #include #include #include #include #include class vtkRenderWindow; class vtkRenderer; namespace mitk { /** @brief Creates everything needed to load and playback interaction events. * * The interaction is loaded from an xml file and the events are created. This file is * usually a recorded user interaction with the GUI. This can be done with InteractionEventRecorder * plugin. Also all necessary objects to handle interaction events are generated. * The user of this class is responsible to add the data object to interact with to the data storage * of InteractionTestHelper. And must also make sure that a proper data interactor is associated with the data * object. * * To test a PointSet interaction for instance make sure you have a PointSet node and a PointSetDataInteractor. * Then just add the node to the storage of the your InteractionTestHelper by calling * InteractionTestHelper::AddNodeToStorage. * Use InteractionTestHelper::PlaybackInteraction to execute. The result can afterwards be compared to a reference * object. * * Make sure to destroy the test helper instance after each test, since all render windows and its renderers have to * be unregistered. * * \sa XML2EventParser * \sa EventFactory * \sa EventRecorder */ class MITKTESTINGHELPER_EXPORT InteractionTestHelper { public: /** * @brief InteractionTestHelper set up all neseccary objects by calling Initialize. * @param interactionXmlFilePath path to xml file containing events and configuration information for the render * windows. */ InteractionTestHelper(const std::string &interactionXmlFilePath); // unregisters all render windows and its renderers. virtual ~InteractionTestHelper(); /** @brief Returns the datastorage, in order to modify the data inside a rendering test. **/ DataStorage::Pointer GetDataStorage(); /** * @brief AddNodeToStorage Add a node to the datastorage and perform a reinit which is necessary for rendering. * @param node The data you want to add. */ void AddNodeToStorage(DataNode::Pointer node); /** * @brief PlaybackInteraction playback loaded interaction by passing events to the dispatcher. */ void PlaybackInteraction(); /** * @brief SetTimeStep Sets timesteps of all SliceNavigationControllers to given timestep. * @param newTimeStep new timestep * * Does the same as using ImageNavigators Time slider. Use this if your data was modified in a timestep other than * 0. */ void SetTimeStep(int newTimeStep); typedef std::vector RenderWindowListType; const RenderWindowListType &GetRenderWindowList() { return m_RenderWindowList; } /** * @brief GetRenderWindowByName Get renderWindow by the name of its renderer. * @param name The name of the renderer of the desired renderWindow. * @return nullptr if not found. */ RenderWindow *GetRenderWindowByName(const std::string &name); /** - * @brief GetRenderWindowByDefaultViewDirection Get a renderWindow by its default viewdirection. + * @brief Get a renderWindow by its default view direction. * @param viewDirection * @return nullptr if not found. */ - RenderWindow *GetRenderWindowByDefaultViewDirection(SliceNavigationController::ViewDirection viewDirection); + RenderWindow *GetRenderWindowByDefaultViewDirection(AnatomicalPlane viewDirection); /** * @brief GetRenderWindow Get renderWindow at position 'index'. * @param index Position within the renderWindow list. * @return nullptr if index is out of bounds. */ RenderWindow *GetRenderWindow(unsigned int index); /** * @brief AddDisplayPlaneSubTree * * Creates DisplayPlanes that are shown in a 3D RenderWindow. */ void AddDisplayPlaneSubTree(); void Set3dCameraSettings(); protected: /** * @brief Initialize Internal method to initialize the renderwindow and set the datastorage. * @throws mitk::Exception if interaction xml file can not be loaded. */ void Initialize(const std::string &interactionXmlFilePath); /** * @brief Initialize the interaction event observer / event state machine and register it as a service. */ void InitializeDisplayActionEventHandling(); /** * @brief LoadInteraction loads events from xml file. */ void LoadInteraction(); mitk::XML2EventParser::EventContainerType m_Events; // List with loaded interaction events std::string m_InteractionFilePath; RenderWindowListType m_RenderWindowList; DataStorage::Pointer m_DataStorage; DisplayActionEventBroadcast::Pointer m_DisplayActionEventBroadcast; }; } #endif // namespace mitk diff --git a/Modules/Core/TestingHelper/include/mitkRenderingTestHelper.h b/Modules/Core/TestingHelper/include/mitkRenderingTestHelper.h index 89fe0f38d2..d62f1ae930 100644 --- a/Modules/Core/TestingHelper/include/mitkRenderingTestHelper.h +++ b/Modules/Core/TestingHelper/include/mitkRenderingTestHelper.h @@ -1,215 +1,215 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkRenderingTestHelper_h #define mitkRenderingTestHelper_h #include #include #include #include #include class vtkRenderWindow; class vtkRenderer; namespace mitk { class MITKTESTINGHELPER_EXPORT RenderingTestHelper { public: /** @brief Generate a rendering test helper object including a render window of the size width * height (in pixel). @param width @param height @param argc Number of parameters. (here: Images) "Usage: [filename1 filenam2 -V referenceScreenshot (optional -T /directory/to/save/differenceImage)] @param argv Given parameters. If no data is inserted via commandline, you can add data later via AddNodeToDataStorage(). @param antiAliasing The anti-aliasing mode. **/ RenderingTestHelper( int width, int height, int argc, char *argv[], AntiAliasing antiAliasing = AntiAliasing::None); /** @brief Generate a rendering test helper object including a render window of the size width * height (in * pixel).*/ RenderingTestHelper( int width, int height, AntiAliasing antiAliasing = AntiAliasing::None); /** Default destructor */ ~RenderingTestHelper(); /** @brief Getter for the vtkRenderer. **/ vtkRenderer *GetVtkRenderer(); /** @brief Getter for the vtkRenderWindow which should be used to call vtkRegressionTestImage. **/ vtkRenderWindow *GetVtkRenderWindow(); /** @brief Method can be used to save a screenshot (e.g. reference screenshot as a .png file. @param fileName The filename of the new screenshot (including path). **/ void SaveAsPNG(std::string fileName); /** * @brief SetStopRenderWindow Convenience method to make the renderwindow hold after rendering. Useful for * debugging. * @param automaticallyCloseRenderWindow Flag indicating whether the renderwindow should automatically close (false, default) or stay open * (true). Useful for debugging. */ void SetAutomaticallyCloseRenderWindow(bool automaticallyCloseRenderWindow); /** @brief This method set the property of the member datastorage @param propertyKey @param property Set a property for each image in the datastorage m_DataStorage. If you want to set the property for a single data node, use GetDataStorage() and set the property yourself for the destinct node. **/ void SetImageProperty(const char *propertyKey, mitk::BaseProperty *property); /** @brief Set the view direction of the renderwindow (e.g. sagittal, coronal, axial) **/ - void SetViewDirection(mitk::SliceNavigationController::ViewDirection viewDirection); + void SetViewDirection(mitk::AnatomicalPlane viewDirection); /** @brief Reorient the slice (e.g. rotation and translation like the swivel mode). **/ void ReorientSlices(mitk::Point3D origin, mitk::Vector3D rotation); /** @brief Render everything into an mitkRenderWindow. Call SetViewDirection() and SetProperty() before this method. **/ void Render(); /** @brief Returns the datastorage, in order to modify the data inside a rendering test. **/ mitk::DataStorage::Pointer GetDataStorage(); /** * @brief SetMapperID Change between Standard2D and 3D mappers. * @param id Enum mitk::BaseRenderer::StandardMapperSlot which defines the mapper. */ void SetMapperID(mitk::BaseRenderer::StandardMapperSlot id); /** * @brief AddNodeToStorage Add a node to the datastorage and perform a reinit which is necessary for rendering. * @param node The data you want to add. */ void AddNodeToStorage(mitk::DataNode::Pointer node); /** * @brief SetMapperIDToRender3D Convenience method to render in a 3D renderwindow. * @warning Does not add helper objects like the image planes to render images in 3D. */ void SetMapperIDToRender3D(); /** * @brief SetMapperIDToRender2D Convenience method to render in a 2D renderwindow. */ void SetMapperIDToRender2D(); /** * @brief SaveReferenceScreenShot Convenience method to save a reference screen shot. * @param fileName Path/to/save/the/png/file. */ void SaveReferenceScreenShot(std::string fileName); /** * @brief CompareRenderWindowAgainstReference Convenience method to compare the image rendered in the internal renderwindow against a reference screen shot. * Usage of vtkTesting::Test: vtkTesting::Test( argc, argv, vtkRenderWindow, threshold ) Set a vtkRenderWindow containing the desired scene. This is automatically rendered. vtkTesting::Test() automatically searches in argc and argv[] for a path a valid image with -V. If the test failed with the first image (foo.png) it checks if there are images of the form foo_N.png (where N=1,2,3...) and compare against them. This allows for multiple valid images. * @param argc Number of arguments. * @param argv Arguments must(!) contain the term "-V Path/To/Valid/Image.png" * @param threshold Allowed difference between two images. Default = 10.0 and was taken from VTK. * @return True if the images are equal regarding the threshold. False in all other cases. */ bool CompareRenderWindowAgainstReference(int argc, char *argv[], double threshold = 10.0); /** * @brief The ArgcHelperClass class is a convenience class to convert a vector * of strings to the standard c++ argv and argc arguments. This is necessary for * the vtkTesting::Test, since is requires the reference image (and other * optional parameters) via command line. */ class ArgcHelperClass { private: /** * Members for conversion. */ std::vector argv; std::vector> argvec; public: ArgcHelperClass(const std::vector &argstrings) : argv(argstrings.size() + 1), argvec(argstrings.size() + 1) { std::vector cmdArgs; cmdArgs.push_back(mitk::IOUtil::GetProgramPath()); cmdArgs.insert(cmdArgs.end(), argstrings.begin(), argstrings.end()); for (std::size_t i = 0; i < cmdArgs.size(); ++i) { argvec[i].assign(cmdArgs[i].begin(), cmdArgs[i].end()); argvec[i].push_back('\0'); argv[i] = &argvec[i][0]; } } char **GetArgv() { return &argv[0]; } int GetArgc() { return argv.size(); } }; protected: /** * @brief Initialize Internal method to initialize the renderwindow and set the datastorage. * @param width Height of renderwindow. * @param height Width of renderwindow. * @param antiAliasing The anti-aliasing mode. */ void Initialize( int width, int height, AntiAliasing antiAliasing = AntiAliasing::None); /** @brief This method tries to load the given file into a member datastorage, in order to render it. @param filename The filename of the file to be loaded (including path). **/ void AddToStorage(const std::string &filename); /** @brief This method tries to parse the given argv for files (e.g. images) and load them into a member datastorage, in order to render it. @param argc Number of parameters. @param argv Given parameters. **/ void SetInputFileNames(int argc, char *argv[]); mitk::RenderWindow::Pointer m_RenderWindow; //<< Contains the mitkRenderWindow into which the test renders the data mitk::DataStorage::Pointer m_DataStorage; //<< Contains the mitkDataStorage which contains the data to be rendered bool m_AutomaticallyCloseRenderWindow; //<< Flag indicating whether the renderwindow should automatically close (true, // default) or stay open (false). Useful for debugging. }; } // namespace mitk #endif diff --git a/Modules/Core/TestingHelper/src/mitkInteractionTestHelper.cpp b/Modules/Core/TestingHelper/src/mitkInteractionTestHelper.cpp index aedf8ae4ed..bfb05627d7 100644 --- a/Modules/Core/TestingHelper/src/mitkInteractionTestHelper.cpp +++ b/Modules/Core/TestingHelper/src/mitkInteractionTestHelper.cpp @@ -1,436 +1,435 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // MITK #include #include #include #include #include // VTK #include #include // us #include #include mitk::InteractionTestHelper::InteractionTestHelper(const std::string &interactionXmlFilePath) : m_InteractionFilePath(interactionXmlFilePath) { this->Initialize(interactionXmlFilePath); } void mitk::InteractionTestHelper::Initialize(const std::string &interactionXmlFilePath) { tinyxml2::XMLDocument document; if (tinyxml2::XML_SUCCESS == document.LoadFile(interactionXmlFilePath.c_str())) { // get RenderingManager instance auto rm = mitk::RenderingManager::GetInstance(); // create data storage m_DataStorage = mitk::StandaloneDataStorage::New(); // for each renderer found create a render window and configure for (auto *element = document.FirstChildElement(mitk::InteractionEventConst::xmlTagInteractions().c_str()) ->FirstChildElement(mitk::InteractionEventConst::xmlTagConfigRoot().c_str()) ->FirstChildElement(mitk::InteractionEventConst::xmlTagRenderer().c_str()); element != nullptr; element = element->NextSiblingElement(mitk::InteractionEventConst::xmlTagRenderer().c_str())) { // get name of renderer const char *rendererName = element->Attribute(mitk::InteractionEventConst::xmlEventPropertyRendererName().c_str()); // get view direction - mitk::SliceNavigationController::ViewDirection viewDirection = mitk::SliceNavigationController::Axial; + mitk::AnatomicalPlane viewDirection = mitk::AnatomicalPlane::Axial; if (element->Attribute(mitk::InteractionEventConst::xmlEventPropertyViewDirection().c_str()) != nullptr) { int viewDirectionNum = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlEventPropertyViewDirection().c_str())); - viewDirection = static_cast(viewDirectionNum); + viewDirection = static_cast(viewDirectionNum); } // get mapper slot id MapperSlotId mapperID = mitk::BaseRenderer::Standard2D; if (element->Attribute(mitk::InteractionEventConst::xmlEventPropertyMapperID().c_str()) != nullptr) { int mapperIDNum = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlEventPropertyMapperID().c_str())); mapperID = static_cast(mapperIDNum); } // Get Size of Render Windows int size[3]; size[0] = size[1] = size[2] = 0; if (element->Attribute(mitk::InteractionEventConst::xmlRenderSizeX().c_str()) != nullptr) { size[0] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlRenderSizeX().c_str())); } if (element->Attribute(mitk::InteractionEventConst::xmlRenderSizeY().c_str()) != nullptr) { size[1] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlRenderSizeY().c_str())); } if (element->Attribute(mitk::InteractionEventConst::xmlRenderSizeZ().c_str()) != nullptr) { size[2] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlRenderSizeZ().c_str())); } // create renderWindow, renderer and dispatcher auto rw = RenderWindow::New(nullptr, rendererName); // VtkRenderWindow is created within constructor if nullptr if (size[0] != 0 && size[1] != 0) { rw->SetSize(size[0], size[1]); rw->GetRenderer()->Resize(size[0], size[1]); } // set storage of renderer rw->GetRenderer()->SetDataStorage(m_DataStorage); // set view direction to axial rw->GetSliceNavigationController()->SetDefaultViewDirection(viewDirection); // set renderer to render 2D rw->GetRenderer()->SetMapperID(mapperID); rw->GetRenderer()->PrepareRender(); // Some more magic for the 3D render window case: // Camera view direction, position and focal point if (mapperID == mitk::BaseRenderer::Standard3D) { if (element->Attribute(mitk::InteractionEventConst::xmlCameraFocalPointX().c_str()) != nullptr) { double cameraFocalPoint[3]; cameraFocalPoint[0] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlCameraFocalPointX().c_str())); cameraFocalPoint[1] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlCameraFocalPointY().c_str())); cameraFocalPoint[2] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlCameraFocalPointZ().c_str())); rw->GetRenderer()->GetVtkRenderer()->GetActiveCamera()->SetFocalPoint(cameraFocalPoint); } if (element->Attribute(mitk::InteractionEventConst::xmlCameraPositionX().c_str()) != nullptr) { double cameraPosition[3]; cameraPosition[0] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlCameraPositionX().c_str())); cameraPosition[1] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlCameraPositionY().c_str())); cameraPosition[2] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlCameraPositionZ().c_str())); rw->GetRenderer()->GetVtkRenderer()->GetActiveCamera()->SetPosition(cameraPosition); } if (element->Attribute(mitk::InteractionEventConst::xmlViewUpX().c_str()) != nullptr) { double viewUp[3]; viewUp[0] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlViewUpX().c_str())); viewUp[1] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlViewUpY().c_str())); viewUp[2] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlViewUpZ().c_str())); rw->GetRenderer()->GetVtkRenderer()->GetActiveCamera()->SetViewUp(viewUp); } } rw->GetVtkRenderWindow()->Render(); rw->GetVtkRenderWindow()->WaitForCompletion(); // connect SliceNavigationControllers to timestep changed event of TimeNavigationController rw->GetSliceNavigationController()->ConnectGeometryTimeEvent(rm->GetTimeNavigationController()); rm->GetTimeNavigationController()->ConnectGeometryTimeEvent(rw->GetSliceNavigationController()); // add to list of known render windows m_RenderWindowList.push_back(rw); } // TODO: check the following lines taken from QmitkStdMultiWidget and adapt them to be executed in our code here. // mitkWidget1->GetSliceNavigationController() // ->ConnectGeometrySendEvent(mitk::BaseRenderer::GetInstance(mitkWidget4->GetRenderWindow())); // register interaction event obserer to handle scroll events InitializeDisplayActionEventHandling(); } else { mitkThrow() << "Can not load interaction xml file <" << m_InteractionFilePath << ">"; } // WARNING assumes a 3D window exists !!!! this->AddDisplayPlaneSubTree(); } void mitk::InteractionTestHelper::InitializeDisplayActionEventHandling() { m_DisplayActionEventBroadcast = mitk::DisplayActionEventBroadcast::New(); m_DisplayActionEventBroadcast->LoadStateMachine("DisplayInteraction.xml"); m_DisplayActionEventBroadcast->SetEventConfig("DisplayConfigMITKBase.xml"); m_DisplayActionEventBroadcast->AddEventConfig("DisplayConfigCrosshair.xml"); } mitk::InteractionTestHelper::~InteractionTestHelper() { mitk::RenderingManager *rm = mitk::RenderingManager::GetInstance(); // unregister renderers auto it = m_RenderWindowList.begin(); auto end = m_RenderWindowList.end(); for (; it != end; ++it) { rm->GetTimeNavigationController()->Disconnect((*it)->GetSliceNavigationController()); (*it)->GetSliceNavigationController()->Disconnect(rm->GetTimeNavigationController()); mitk::BaseRenderer::RemoveInstance((*it)->GetVtkRenderWindow()); } rm->RemoveAllObservers(); } mitk::DataStorage::Pointer mitk::InteractionTestHelper::GetDataStorage() { return m_DataStorage; } void mitk::InteractionTestHelper::AddNodeToStorage(mitk::DataNode::Pointer node) { this->m_DataStorage->Add(node); this->Set3dCameraSettings(); } void mitk::InteractionTestHelper::PlaybackInteraction() { mitk::RenderingManager::GetInstance()->InitializeViewsByBoundingObjects(m_DataStorage); // load events if not loaded yet if (m_Events.empty()) this->LoadInteraction(); auto it = m_RenderWindowList.begin(); auto end = m_RenderWindowList.end(); for (; it != end; ++it) { (*it)->GetRenderer()->PrepareRender(); (*it)->GetVtkRenderWindow()->Render(); (*it)->GetVtkRenderWindow()->WaitForCompletion(); } mitk::RenderingManager::GetInstance()->InitializeViewsByBoundingObjects(m_DataStorage); it = m_RenderWindowList.begin(); for (; it != end; ++it) { (*it)->GetVtkRenderWindow()->Render(); (*it)->GetVtkRenderWindow()->WaitForCompletion(); } // mitk::RenderingManager::GetInstance()->ForceImmediateUpdateAll(); // playback all events in queue for (unsigned long i = 0; i < m_Events.size(); ++i) { // let dispatcher of sending renderer process the event m_Events.at(i)->GetSender()->GetDispatcher()->ProcessEvent(m_Events.at(i)); } if (false) { it--; (*it)->GetVtkRenderWindow()->GetInteractor()->Start(); } } void mitk::InteractionTestHelper::LoadInteraction() { // load interaction pattern from xml file std::ifstream xmlStream(m_InteractionFilePath.c_str()); mitk::XML2EventParser parser(xmlStream); m_Events = parser.GetInteractions(); xmlStream.close(); // Avoid VTK warning: Trying to delete object with non-zero reference count. parser.SetReferenceCount(0); } void mitk::InteractionTestHelper::SetTimeStep(int newTimeStep) { mitk::RenderingManager::GetInstance()->InitializeViewsByBoundingObjects(m_DataStorage); bool timeStepIsvalid = mitk::RenderingManager::GetInstance()->GetTimeNavigationController()->GetCreatedWorldGeometry()->IsValidTimeStep( newTimeStep); if (timeStepIsvalid) { mitk::RenderingManager::GetInstance()->GetTimeNavigationController()->GetTime()->SetPos(newTimeStep); } } mitk::RenderWindow *mitk::InteractionTestHelper::GetRenderWindowByName(const std::string &name) { auto it = m_RenderWindowList.begin(); auto end = m_RenderWindowList.end(); for (; it != end; ++it) { if (name.compare((*it)->GetRenderer()->GetName()) == 0) return (*it).GetPointer(); } return nullptr; } -mitk::RenderWindow *mitk::InteractionTestHelper::GetRenderWindowByDefaultViewDirection( - mitk::SliceNavigationController::ViewDirection viewDirection) +mitk::RenderWindow *mitk::InteractionTestHelper::GetRenderWindowByDefaultViewDirection(AnatomicalPlane viewDirection) { auto it = m_RenderWindowList.begin(); auto end = m_RenderWindowList.end(); for (; it != end; ++it) { if (viewDirection == (*it)->GetSliceNavigationController()->GetDefaultViewDirection()) return (*it).GetPointer(); } return nullptr; } mitk::RenderWindow *mitk::InteractionTestHelper::GetRenderWindow(unsigned int index) { if (index < m_RenderWindowList.size()) { return m_RenderWindowList.at(index).GetPointer(); } else { return nullptr; } } void mitk::InteractionTestHelper::AddDisplayPlaneSubTree() { // add the displayed planes of the multiwidget to a node to which the subtree // @a planesSubTree points ... mitk::PlaneGeometryDataMapper2D::Pointer mapper; mitk::IntProperty::Pointer layer = mitk::IntProperty::New(1000); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetProperty("name", mitk::StringProperty::New("Widgets")); node->SetProperty("helper object", mitk::BoolProperty::New(true)); m_DataStorage->Add(node); for (auto it : m_RenderWindowList) { if (it->GetRenderer()->GetMapperID() == BaseRenderer::Standard3D) continue; // ... of widget 1 mitk::DataNode::Pointer planeNode1 = (mitk::BaseRenderer::GetInstance(it->GetVtkRenderWindow()))->GetCurrentWorldPlaneGeometryNode(); planeNode1->SetProperty("visible", mitk::BoolProperty::New(true)); planeNode1->SetProperty("name", mitk::StringProperty::New("widget1Plane")); planeNode1->SetProperty("includeInBoundingBox", mitk::BoolProperty::New(false)); planeNode1->SetProperty("helper object", mitk::BoolProperty::New(true)); planeNode1->SetProperty("layer", layer); planeNode1->SetColor(1.0, 0.0, 0.0); mapper = mitk::PlaneGeometryDataMapper2D::New(); planeNode1->SetMapper(mitk::BaseRenderer::Standard2D, mapper); m_DataStorage->Add(planeNode1, node); } } void mitk::InteractionTestHelper::Set3dCameraSettings() { tinyxml2::XMLDocument document; if (tinyxml2::XML_SUCCESS == document.LoadFile(m_InteractionFilePath.c_str())) { // for each renderer found create a render window and configure for (auto *element = document.FirstChildElement(mitk::InteractionEventConst::xmlTagInteractions().c_str()) ->FirstChildElement(mitk::InteractionEventConst::xmlTagConfigRoot().c_str()) ->FirstChildElement(mitk::InteractionEventConst::xmlTagRenderer().c_str()); element != nullptr; element = element->NextSiblingElement(mitk::InteractionEventConst::xmlTagRenderer().c_str())) { // get name of renderer const char *rendererName = element->Attribute(mitk::InteractionEventConst::xmlEventPropertyRendererName().c_str()); // get mapper slot id MapperSlotId mapperID = mitk::BaseRenderer::Standard2D; if (element->Attribute(mitk::InteractionEventConst::xmlEventPropertyMapperID().c_str()) != nullptr) { int mapperIDNum = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlEventPropertyMapperID().c_str())); mapperID = static_cast(mapperIDNum); } if (mapperID == mitk::BaseRenderer::Standard3D) { RenderWindow *namedRenderer = nullptr; for (const auto &it : m_RenderWindowList) { if (strcmp(it->GetRenderer()->GetName(), rendererName) == 0) { namedRenderer = it.GetPointer(); break; } } if (namedRenderer == nullptr) { MITK_ERROR << "No match for render window was found."; return; } namedRenderer->GetRenderer()->PrepareRender(); if (element->Attribute(mitk::InteractionEventConst::xmlCameraFocalPointX().c_str()) != nullptr) { double cameraFocalPoint[3]; cameraFocalPoint[0] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlCameraFocalPointX().c_str())); cameraFocalPoint[1] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlCameraFocalPointY().c_str())); cameraFocalPoint[2] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlCameraFocalPointZ().c_str())); namedRenderer->GetRenderer()->GetVtkRenderer()->GetActiveCamera()->SetFocalPoint(cameraFocalPoint); } if (element->Attribute(mitk::InteractionEventConst::xmlCameraPositionX().c_str()) != nullptr) { double cameraPosition[3]; cameraPosition[0] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlCameraPositionX().c_str())); cameraPosition[1] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlCameraPositionY().c_str())); cameraPosition[2] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlCameraPositionZ().c_str())); namedRenderer->GetRenderer()->GetVtkRenderer()->GetActiveCamera()->SetPosition(cameraPosition); } if (element->Attribute(mitk::InteractionEventConst::xmlViewUpX().c_str()) != nullptr) { double viewUp[3]; viewUp[0] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlViewUpX().c_str())); viewUp[1] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlViewUpY().c_str())); viewUp[2] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlViewUpZ().c_str())); namedRenderer->GetRenderer()->GetVtkRenderer()->GetActiveCamera()->SetViewUp(viewUp); } namedRenderer->GetVtkRenderWindow()->Render(); } } } } diff --git a/Modules/Core/TestingHelper/src/mitkRenderingTestHelper.cpp b/Modules/Core/TestingHelper/src/mitkRenderingTestHelper.cpp index 09594900e3..c3df456fad 100644 --- a/Modules/Core/TestingHelper/src/mitkRenderingTestHelper.cpp +++ b/Modules/Core/TestingHelper/src/mitkRenderingTestHelper.cpp @@ -1,239 +1,239 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // VTK #include #include #include #include #include #include // MITK #include #include #include #include #include #include #include #include // VTK Testing to compare the rendered image pixel-wise against a reference screen shot #include "vtkTesting.h" mitk::RenderingTestHelper::RenderingTestHelper(int width, int height, AntiAliasing antiAliasing) : m_AutomaticallyCloseRenderWindow(true) { this->Initialize(width, height, antiAliasing); } mitk::RenderingTestHelper::RenderingTestHelper( int width, int height, int argc, char *argv[], AntiAliasing antiAliasing) : m_AutomaticallyCloseRenderWindow(true) { this->Initialize(width, height, antiAliasing); this->SetInputFileNames(argc, argv); } void mitk::RenderingTestHelper::Initialize(int width, int height, AntiAliasing antiAliasing) { RenderingManager::GetInstance()->SetAntiAliasing(antiAliasing); mitk::UIDGenerator uidGen = mitk::UIDGenerator("UnnamedRenderer_"); m_RenderWindow = mitk::RenderWindow::New(nullptr, uidGen.GetUID().c_str()); auto renderWindow = m_RenderWindow->GetVtkRenderWindow(); if (0 == renderWindow->SupportsOpenGL()) { auto openGLRenderWindow = dynamic_cast(renderWindow); auto message = nullptr != openGLRenderWindow ? openGLRenderWindow->GetOpenGLSupportMessage() : std::string("No details available."); mitkThrowException(mitk::TestNotRunException) << "OpenGL not supported: " << message; } m_DataStorage = mitk::StandaloneDataStorage::New(); m_RenderWindow->GetRenderer()->SetDataStorage(m_DataStorage); this->SetMapperIDToRender2D(); this->GetVtkRenderWindow()->SetSize(width, height); m_RenderWindow->GetRenderer()->Resize(width, height); } mitk::RenderingTestHelper::~RenderingTestHelper() { } void mitk::RenderingTestHelper::SetMapperID(mitk::BaseRenderer::StandardMapperSlot id) { m_RenderWindow->GetRenderer()->SetMapperID(id); } void mitk::RenderingTestHelper::SetMapperIDToRender3D() { this->SetMapperID(mitk::BaseRenderer::Standard3D); mitk::RenderingManager::GetInstance()->InitializeViews( this->GetDataStorage()->ComputeBoundingGeometry3D(this->GetDataStorage()->GetAll())); } void mitk::RenderingTestHelper::SetMapperIDToRender2D() { this->SetMapperID(mitk::BaseRenderer::Standard2D); } void mitk::RenderingTestHelper::Render() { // if the datastorage is initialized and at least 1 image is loaded render it if (m_DataStorage.IsNotNull() && m_DataStorage->GetAll()->Size() >= 1) { // Prepare the VTK camera before rendering. m_RenderWindow->GetRenderer()->PrepareRender(); this->GetVtkRenderWindow()->Render(); this->GetVtkRenderWindow()->WaitForCompletion(); if (m_AutomaticallyCloseRenderWindow == false) { // Use interaction to stop the test this->GetVtkRenderWindow()->GetInteractor()->Start(); } } else { MITK_ERROR << "No images loaded in data storage!"; } } mitk::DataStorage::Pointer mitk::RenderingTestHelper::GetDataStorage() { return m_DataStorage; } void mitk::RenderingTestHelper::SetInputFileNames(int argc, char *argv[]) { // i is set 1, because 0 is the testname as string // parse parameters for (int i = 1; i < argc; ++i) { // add everything to a list but -T and -V std::string tmp = argv[i]; if ((tmp.compare("-T")) && (tmp.compare("-V"))) { this->AddToStorage(tmp); } else { break; } } } -void mitk::RenderingTestHelper::SetViewDirection(mitk::SliceNavigationController::ViewDirection viewDirection) +void mitk::RenderingTestHelper::SetViewDirection(mitk::AnatomicalPlane viewDirection) { mitk::BaseRenderer::GetInstance(m_RenderWindow->GetVtkRenderWindow()) ->GetSliceNavigationController() ->SetDefaultViewDirection(viewDirection); mitk::RenderingManager::GetInstance()->InitializeViews( m_DataStorage->ComputeBoundingGeometry3D(m_DataStorage->GetAll())); } void mitk::RenderingTestHelper::ReorientSlices(mitk::Point3D origin, mitk::Vector3D rotation) { mitk::SliceNavigationController::Pointer sliceNavigationController = mitk::BaseRenderer::GetInstance(m_RenderWindow->GetVtkRenderWindow())->GetSliceNavigationController(); sliceNavigationController->ReorientSlices(origin, rotation); } vtkRenderer *mitk::RenderingTestHelper::GetVtkRenderer() { return m_RenderWindow->GetRenderer()->GetVtkRenderer(); } void mitk::RenderingTestHelper::SetImageProperty(const char *propertyKey, mitk::BaseProperty *property) { this->m_DataStorage->GetNode(mitk::NodePredicateDataType::New("Image"))->SetProperty(propertyKey, property); } vtkRenderWindow *mitk::RenderingTestHelper::GetVtkRenderWindow() { return m_RenderWindow->GetVtkRenderWindow(); } bool mitk::RenderingTestHelper::CompareRenderWindowAgainstReference(int argc, char *argv[], double threshold) { this->Render(); // retVal meanings: (see VTK/Rendering/vtkTesting.h) // 0 = test failed // 1 = test passed // 2 = test not run // 3 = something with vtkInteraction if (vtkTesting::Test(argc, argv, this->GetVtkRenderWindow(), threshold) == 1) return true; else return false; } // method to save a screenshot of the renderwindow (e.g. create a reference screenshot) void mitk::RenderingTestHelper::SaveAsPNG(std::string fileName) { vtkSmartPointer renderer = this->GetVtkRenderer(); bool doubleBuffering(renderer->GetRenderWindow()->GetDoubleBuffer()); renderer->GetRenderWindow()->DoubleBufferOff(); vtkSmartPointer magnifier = vtkSmartPointer::New(); magnifier->SetInput(renderer); magnifier->SetMagnification(1); vtkSmartPointer fileWriter = vtkSmartPointer::New(); fileWriter->SetInputConnection(magnifier->GetOutputPort()); fileWriter->SetFileName(fileName.c_str()); fileWriter->Write(); renderer->GetRenderWindow()->SetDoubleBuffer(doubleBuffering); } void mitk::RenderingTestHelper::SetAutomaticallyCloseRenderWindow(bool automaticallyCloseRenderWindow) { m_AutomaticallyCloseRenderWindow = automaticallyCloseRenderWindow; } void mitk::RenderingTestHelper::SaveReferenceScreenShot(std::string fileName) { this->SaveAsPNG(fileName); } void mitk::RenderingTestHelper::AddToStorage(const std::string &filename) { try { mitk::IOUtil::Load(filename, *m_DataStorage.GetPointer()); mitk::RenderingManager::GetInstance()->InitializeViews( m_DataStorage->ComputeBoundingGeometry3D(m_DataStorage->GetAll())); } catch ( const itk::ExceptionObject &e ) { MITK_ERROR << "Failed loading test data '" << filename << "': " << e.what(); } } void mitk::RenderingTestHelper::AddNodeToStorage(mitk::DataNode::Pointer node) { this->m_DataStorage->Add(node); mitk::RenderingManager::GetInstance()->InitializeViews( m_DataStorage->ComputeBoundingGeometry3D(m_DataStorage->GetAll())); } diff --git a/Modules/Core/include/mitkSliceNavigationHelper.h b/Modules/Core/include/mitkSliceNavigationHelper.h index 2176f4585a..8d7ed5af5e 100644 --- a/Modules/Core/include/mitkSliceNavigationHelper.h +++ b/Modules/Core/include/mitkSliceNavigationHelper.h @@ -1,99 +1,99 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef MITKSLICENAVIGATIONHELPER_H #define MITKSLICENAVIGATIONHELPER_H #include #include #include namespace mitk { namespace SliceNavigationHelper { /** * \brief Select a specific slice from the given time geometry given a 3D point. * * The function uses the currently selected time point to retrieve the current base geometry from * the given time geometry. * If this base geometry is a SlicedGeometry3D, the best fitting slice is computed by projecting * the point onto the plane geometry of this SlicedGeometry. * The slice with the shortest distance to the point is returned as the selected slice. * * \param timeGeometry The TimeGeometry of which the slice should be selected. * \param point The Point3D which is used to select the specific slice. * * \pre The given TimeGeometry must cover the currently selected time point. If not, an exception is thrown. * If the given TimeGeomety is a nullptr, -1 is returned. * * \return The selected slice as unsigned int. If the computed slice is negative, "0" (zero) is * returned as the selected slice. */ MITKCORE_EXPORT unsigned int SelectSliceByPoint(const TimeGeometry* timeGeometry, const Point3D& point); /** * \brief Create a new time geometry, which is oriented with the given plane orientation. * * The function uses the currently selected time point to retrieve the current base geometry from * the given time geometry. * A new SlicedGeometry3D is created and initialized with the given parameters and the extracted base geometry. * This new SlicedGeometry3D is then used to replace the geometries of each time step of a cloned version * of the given TimeGeometry. This allows to only replace the contained geometries for each time step, * keeping the time steps (time point + time duration) from the original time geometry. * * \param timeGeometry The TimeGeometry which should be used for cloning. - * \param planeOrientation The PlaneOrientation that specifies the new orientation of the time geometry. + * \param orientation The AnatomicalPlane that specifies the new orientation of the time geometry. * \param top If true, create the plane at top, otherwise at bottom. * \param frontside Defines the side of the plane. * \param rotated Rotates the plane by 180 degree around its normal. * s.a. PlaneGeometry::InitializeStandardPlane * * \pre The given TimeGeometry must cover the currently selected time point. If not, an exception is thrown. * If the given TimeGeomety is a nullptr, a nullptr is returned immediately. * * \return The created geometry as TimeGeometry. */ MITKCORE_EXPORT TimeGeometry::Pointer CreateOrientedTimeGeometry(const TimeGeometry* timeGeometry, - PlaneGeometry::PlaneOrientation planeOrientation, + AnatomicalPlane orientation, bool top, bool frontside, bool rotated); /** * \brief Extracts the plane geometry for the given time step and slice position. * * The function uses the given time point to retrieve the current base geometry from * the given time geometry. * If this base geometry is a SlicedGeometry3D, the plane geometry of the given * slice position is extracted and returned. * If not, a nullptr is returned. * * \param timeGeometry The TimeGeometry of which the plane geometry should be extracted * \param timePoint The time point to extract the current base geometry. * \param slicePosition The slice position to extract the current plane geometry. * * \pre The given TimeGeometry must cover the currently selected time point. If not, an exception is thrown. * If the given TimeGeomety is a nullptr, a nullptr is returned immediately. * * \return The extracted plane geometry as PlaneGeometry. * Nullptr, if no SlicedGeometry3D was found for the given time step. */ MITKCORE_EXPORT PlaneGeometry* GetCurrentPlaneGeometry(const TimeGeometry* timeGeometry, TimePointType timePoint, unsigned int slicePosition); } // namespace SliceNavigationHelper } // namespace mitk #endif // MITKSLICENAVIGATIONHELPER_H diff --git a/Modules/Core/include/mitkSlicedGeometry3D.h b/Modules/Core/include/mitkSlicedGeometry3D.h index da2c611722..f0bc4f1389 100644 --- a/Modules/Core/include/mitkSlicedGeometry3D.h +++ b/Modules/Core/include/mitkSlicedGeometry3D.h @@ -1,328 +1,328 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef MITKSLICEDGEOMETRY3D_H_HEADER_INCLUDED_C1EBD0AD #define MITKSLICEDGEOMETRY3D_H_HEADER_INCLUDED_C1EBD0AD #include "mitkBaseGeometry.h" #include "mitkPlaneGeometry.h" namespace mitk { class SliceNavigationController; class NavigationController; /** \brief Describes the geometry of a data object consisting of slices. * * A PlaneGeometry can be requested for each slice. In the case of * \em evenly-spaced, \em plane geometries (m_EvenlySpaced==true), * only the 2D-geometry of the first slice has to be set (to an instance of * PlaneGeometry). The 2D geometries of the other slices are calculated * by shifting the first slice in the direction m_DirectionVector by * m_Spacing.z * sliceNumber. The m_Spacing member (which is only * relevant in the case m_EvenlySpaced==true) describes the size of a voxel * (in mm), i.e., m_Spacing.x is the voxel width in the x-direction of the * plane. It is derived from the reference geometry of this SlicedGeometry3D, * which usually would be the global geometry describing how datasets are to * be resliced. * * By default, slices are oriented in the direction of one of the main axes * (x, y, z). However, by means of rotation, it is possible to realign the * slices in any possible direction. In case of an inclined plane, the spacing * is derived as a product of the (regular) geometry spacing and the direction * vector of the plane. * * SlicedGeometry3D and the associated PlaneGeometries have to be initialized in * the method GenerateOutputInformation() of BaseProcess (or CopyInformation / * UpdateOutputInformation of BaseData, if possible, e.g., by analyzing pic * tags in Image) subclasses. See also * * \sa itk::ProcessObject::GenerateOutputInformation(), * \sa itk::DataObject::CopyInformation() and * \a itk::DataObject::UpdateOutputInformation(). * * Rule: everything is in mm (or ms for temporal information) if not * stated otherwise. * * \warning The hull (i.e., transform, bounding-box and * time-bounds) is only guaranteed to be up-to-date after calling * UpdateInformation(). * * \ingroup Geometry */ class MITKCORE_EXPORT SlicedGeometry3D : public mitk::BaseGeometry { public: mitkClassMacro(SlicedGeometry3D, BaseGeometry); /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self); itkCloneMacro(Self); /** * \brief Returns the PlaneGeometry of the slice (\a s). * * If (a) m_EvenlySpaced==true, (b) we don't have a PlaneGeometry stored * for the requested slice, and (c) the first slice (s=0) * is a PlaneGeometry instance, then we calculate the geometry of the * requested as the plane of the first slice shifted by m_Spacing[3]*s * in the direction of m_DirectionVector. * * \warning The PlaneGeometries are not necessarily up-to-date and not even * initialized. * * The PlaneGeometries have to be initialized in the method * GenerateOutputInformation() of BaseProcess (or CopyInformation / * UpdateOutputInformation of BaseData, if possible, e.g., by analyzing * pic tags in Image) subclasses. See also * * \sa itk::ProcessObject::GenerateOutputInformation(), * \sa itk::DataObject::CopyInformation() and * \sa itk::DataObject::UpdateOutputInformation(). */ virtual mitk::PlaneGeometry *GetPlaneGeometry(int s) const; /** * \deprecatedSince{2014_10} Please use GetPlaneGeometry */ DEPRECATED(const PlaneGeometry *GetGeometry2D(int s)) { return GetPlaneGeometry(s); } /** * \deprecatedSince{2014_10} Please use SetPlaneGeometry */ DEPRECATED(void SetGeometry2D(PlaneGeometry *geo, int s)) { SetPlaneGeometry(geo, s); } //##Documentation //## @brief When switching from an Image Geometry to a normal Geometry (and the other way around), you have to //change // the origin as well (See Geometry Documentation)! This function will change the "isImageGeometry" bool flag and // changes the origin respectively. void ChangeImageGeometryConsideringOriginOffset(const bool isAnImageGeometry) override; // virtual void SetTimeBounds( const mitk::TimeBounds& timebounds ); const mitk::BoundingBox *GetBoundingBox() const override; /** * \brief Get the number of slices */ itkGetConstMacro(Slices, unsigned int); /** * \brief Set PlaneGeometry of slice \a s. */ virtual bool SetPlaneGeometry(mitk::PlaneGeometry *geometry2D, int s); /** * \brief Check whether a slice exists */ virtual bool IsValidSlice(int s = 0) const; virtual const BaseGeometry* GetReferenceGeometry() const; virtual void SetReferenceGeometry(const BaseGeometry *referenceGeometry); bool HasReferenceGeometry() const; /** * \brief Set the SliceNavigationController corresponding to this sliced * geometry. * * The SNC needs to be informed when the number of slices in the geometry * changes, which can occur whenthe slices are re-oriented by rotation. */ virtual void SetSliceNavigationController(mitk::SliceNavigationController *snc); mitk::SliceNavigationController *GetSliceNavigationController(); /** * \brief Set/Get whether the SlicedGeometry3D is evenly-spaced * (m_EvenlySpaced) * * If (a) m_EvenlySpaced==true, (b) we don't have a PlaneGeometry stored for * the requested slice, and (c) the first slice (s=0) is a PlaneGeometry * instance, then we calculate the geometry of the requested as the plane * of the first slice shifted by m_Spacing.z * s in the direction of * m_DirectionVector. * * \sa GetPlaneGeometry */ itkGetConstMacro(EvenlySpaced, bool); virtual void SetEvenlySpaced(bool on = true); /** * \brief Set/Get the vector between slices for the evenly-spaced case * (m_EvenlySpaced==true). * * If the direction-vector is (0,0,0) (the default) and the first * 2D geometry is a PlaneGeometry, then the direction-vector will be * calculated from the plane normal. * * \sa m_DirectionVector */ virtual void SetDirectionVector(const mitk::Vector3D &directionVector); itkGetConstMacro(DirectionVector, const mitk::Vector3D &); itk::LightObject::Pointer InternalClone() const override; #ifndef SWIG static const std::string SLICES; const static std::string DIRECTION_VECTOR; const static std::string EVENLY_SPACED; #endif // !SWIG /** * \brief Tell this instance how many PlaneGeometries it shall manage. Bounding * box and the PlaneGeometries must be set additionally by calling the respective * methods! * * \warning Bounding box and the 2D-geometries must be set additionally: use * SetBounds(), SetGeometry(). */ virtual void InitializeSlicedGeometry(unsigned int slices); /** * \brief Completely initialize this instance as evenly-spaced with slices * parallel to the provided PlaneGeometry that is used as the first slice and * for spacing calculation. * * Initializes the bounding box according to the width/height of the * PlaneGeometry and \a slices. The spacing is calculated from the PlaneGeometry. */ virtual void InitializeEvenlySpaced(mitk::PlaneGeometry *geometry2D, unsigned int slices); /** * \brief Completely initialize this instance as evenly-spaced with slices * parallel to the provided PlaneGeometry that is used as the first slice and * for spacing calculation (except z-spacing). * * Initializes the bounding box according to the width/height of the * PlaneGeometry and \a slices. The x-/y-spacing is calculated from the * PlaneGeometry. */ virtual void InitializeEvenlySpaced(mitk::PlaneGeometry *geometry2D, mitk::ScalarType zSpacing, unsigned int slices); /** * \brief Completely initialize this instance as evenly-spaced plane slices * parallel to a side of the provided BaseGeometry and using its spacing * information. * * Initializes the bounding box according to the width/height of the * BaseGeometry and the number of slices according to * BaseGeometry::GetExtent(2). * * \param geometry3D - * \param planeorientation side parallel to which the slices will be oriented + * \param orientation side parallel to which the slices will be oriented * \param top if \a true, create plane at top, otherwise at bottom - * (for PlaneOrientation Axial, for other plane locations respectively) + * (for AnatomicalPlane Axial, for other plane locations respectively) * \param frontside defines the side of the plane (the definition of * front/back is somewhat arbitrary) * * \param rotated rotates the plane by 180 degree around its normal (the * definition of rotated vs not rotated is somewhat arbitrary) */ virtual void InitializePlanes(const mitk::BaseGeometry *geometry3D, - mitk::PlaneGeometry::PlaneOrientation planeorientation, + mitk::AnatomicalPlane orientation, bool top = true, bool frontside = true, bool rotated = false); void SetImageGeometry(const bool isAnImageGeometry) override; void ExecuteOperation(Operation *operation) override; static double CalculateSpacing(const mitk::Vector3D &spacing, const mitk::Vector3D &d); protected: SlicedGeometry3D(); SlicedGeometry3D(const SlicedGeometry3D &other); ~SlicedGeometry3D() override; /** * Reinitialize plane stack after rotation. More precisely, the first plane * of the stack needs to spatially aligned, in two respects: * * 1. Re-alignment with respect to the dataset center; this is necessary * since the distance from the first plane to the center could otherwise * continuously decrease or increase. * 2. Re-alignment with respect to a given reference point; the reference * point is a location which the user wants to be exactly touched by one * plane of the plane stack. The first plane is minimally shifted to * ensure this touching. Usually, the reference point would be the * point around which the geometry is rotated. */ virtual void ReinitializePlanes(const Point3D ¢er, const Point3D &referencePoint); ScalarType GetLargestExtent(const BaseGeometry *geometry); void PrintSelf(std::ostream &os, itk::Indent indent) const override; /** Calculate "directed spacing", i.e. the spacing in directions * non-orthogonal to the coordinate axes. This is done via the * ellipsoid equation. */ double CalculateSpacing(const mitk::Vector3D &direction) const; /** The extent of the slice stack, i.e. the number of slices, depends on the * plane normal. For rotated geometries, the geometry's transform needs to * be accounted in this calculation. */ mitk::Vector3D AdjustNormal(const mitk::Vector3D &normal) const; /** * Container for the 2D-geometries contained within this SliceGeometry3D. */ mutable std::vector m_PlaneGeometries; /** * If (a) m_EvenlySpaced==true, (b) we don't have a PlaneGeometry stored * for the requested slice, and (c) the first slice (s=0) * is a PlaneGeometry instance, then we calculate the geometry of the * requested as the plane of the first slice shifted by m_Spacing.z*s * in the direction of m_DirectionVector. * * \sa GetPlaneGeometry */ bool m_EvenlySpaced; /** * Vector between slices for the evenly-spaced case (m_EvenlySpaced==true). * If the direction-vector is (0,0,0) (the default) and the first * 2D geometry is a PlaneGeometry, then the direction-vector will be * calculated from the plane normal. */ mutable mitk::Vector3D m_DirectionVector; /** Number of slices this SliceGeometry3D is describing. */ unsigned int m_Slices; /** Underlying BaseGeometry for this SlicedGeometry */ const mitk::BaseGeometry *m_ReferenceGeometry; /** SNC correcsponding to this geometry; used to reflect changes in the * number of slices due to rotation. */ // mitk::NavigationController *m_NavigationController; mitk::SliceNavigationController *m_SliceNavigationController; //##Documentation //## @brief PreSetSpacing //## //## These virtual function allows a different beahiour in subclasses. //## Do implement them in every subclass of BaseGeometry. If not needed, use //## {Superclass::PreSetSpacing();}; void PreSetSpacing(const mitk::Vector3D &aSpacing) override; }; } // namespace mitk #endif /* MITKSLICEDGEOMETRY3D_H_HEADER_INCLUDED_C1EBD0AD */ diff --git a/Modules/Core/src/Controllers/mitkCrosshairManager.cpp b/Modules/Core/src/Controllers/mitkCrosshairManager.cpp index aea9b92adb..8bd39e7449 100644 --- a/Modules/Core/src/Controllers/mitkCrosshairManager.cpp +++ b/Modules/Core/src/Controllers/mitkCrosshairManager.cpp @@ -1,414 +1,414 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkCrosshairManager.h" #include #include #include #include #include #include mitk::CrosshairManager::CrosshairManager(DataStorage* dataStorage, BaseRenderer* baseRenderer) : m_DataStorage(dataStorage) , m_BaseRenderer(baseRenderer) , m_InputTimeGeometry() , m_AxialTimeGeometry() , m_CoronalTimeGeometry() , m_SagittalTimeGeometry() { m_AxialPlaneNode = mitk::DataNode::New(); m_CoronalPlaneNode = mitk::DataNode::New(); m_SagittalPlaneNode = mitk::DataNode::New(); std::string rendererName = std::string(m_BaseRenderer->GetName()); this->InitializePlaneProperties(m_AxialPlaneNode, std::string(rendererName + "axial.plane")); this->InitializePlaneProperties(m_CoronalPlaneNode, std::string(rendererName + "coronal.plane")); this->InitializePlaneProperties(m_SagittalPlaneNode, std::string(rendererName + "sagittal.plane")); m_ParentNodeForGeometryPlanes = mitk::DataNode::New(); m_ParentNodeForGeometryPlanes->SetProperty("name", mitk::StringProperty::New(rendererName)); m_ParentNodeForGeometryPlanes->SetProperty("helper object", mitk::BoolProperty::New(true)); } mitk::CrosshairManager::~CrosshairManager() { this->RemovePlanesFromDataStorage(); } void mitk::CrosshairManager::ComputeOrientedTimeGeometries(const TimeGeometry* geometry) { if (nullptr != geometry) { if (geometry->GetBoundingBoxInWorld()->GetDiagonalLength2() < eps) { itkWarningMacro("setting an empty bounding-box"); geometry = nullptr; } } if (m_InputTimeGeometry == geometry) { return; } m_InputTimeGeometry = geometry; if (m_InputTimeGeometry.IsNull()) { return; } if (0 == m_InputTimeGeometry->CountTimeSteps()) { return; } try { m_AxialTimeGeometry = SliceNavigationHelper::CreateOrientedTimeGeometry( - m_InputTimeGeometry, PlaneGeometry::Axial, false, false, true); + m_InputTimeGeometry, AnatomicalPlane::Axial, false, false, true); m_CoronalTimeGeometry = SliceNavigationHelper::CreateOrientedTimeGeometry( - m_InputTimeGeometry, PlaneGeometry::Coronal, false, true, false); + m_InputTimeGeometry, AnatomicalPlane::Coronal, false, true, false); m_SagittalTimeGeometry = SliceNavigationHelper::CreateOrientedTimeGeometry( - m_InputTimeGeometry, PlaneGeometry::Sagittal, true, true, false); + m_InputTimeGeometry, AnatomicalPlane::Sagittal, true, true, false); } catch (const mitk::Exception& e) { MITK_ERROR << "Unable to create oriented time geometries\n" << "Reason: " << e.GetDescription(); } this->InitializePlaneData(m_AxialPlaneNode, m_AxialTimeGeometry, m_AxialSlice); this->InitializePlaneData(m_CoronalPlaneNode, m_CoronalTimeGeometry, m_CoronalSlice); this->InitializePlaneData(m_SagittalPlaneNode, m_SagittalTimeGeometry, m_SagittalSlice); RenderingManager::GetInstance()->RequestUpdate(m_BaseRenderer->GetRenderWindow()); } void mitk::CrosshairManager::SetCrosshairPosition(const Point3D& selectedPoint) { if (m_AxialPlaneNode.IsNull() || m_CoronalPlaneNode.IsNull() || m_SagittalPlaneNode.IsNull()) { return; } if (m_AxialTimeGeometry.IsNull() || m_CoronalTimeGeometry.IsNull() || m_SagittalTimeGeometry.IsNull()) { return; } this->SetCrosshairPosition(selectedPoint, m_AxialPlaneNode, m_AxialTimeGeometry, m_AxialSlice); this->SetCrosshairPosition(selectedPoint, m_CoronalPlaneNode, m_CoronalTimeGeometry, m_CoronalSlice); this->SetCrosshairPosition(selectedPoint, m_SagittalPlaneNode, m_SagittalTimeGeometry, m_SagittalSlice); } mitk::Point3D mitk::CrosshairManager::GetCrosshairPosition() const { if (m_InputTimeGeometry.IsNull()) { // return null-point since we don't show the crosshair anyway return Point3D(0.0); } Point3D point = m_InputTimeGeometry->GetCenterInWorld(); PlaneGeometry* axialPlaneGeometry = nullptr; PlaneGeometry* coronalPlaneGeometry = nullptr; PlaneGeometry* sagittalPlaneGeometry = nullptr; // get the currently selected time point auto selectedTimePoint = RenderingManager::GetInstance()->GetTimeNavigationController()->GetSelectedTimePoint(); try { axialPlaneGeometry = SliceNavigationHelper::GetCurrentPlaneGeometry(m_AxialTimeGeometry, selectedTimePoint, m_AxialSlice); coronalPlaneGeometry = SliceNavigationHelper::GetCurrentPlaneGeometry(m_CoronalTimeGeometry, selectedTimePoint, m_CoronalSlice); sagittalPlaneGeometry = SliceNavigationHelper::GetCurrentPlaneGeometry(m_SagittalTimeGeometry, selectedTimePoint, m_SagittalSlice); } catch (const mitk::Exception& e) { MITK_ERROR << "Unable to get plane geometries. Using default center point.\n" << "Reason: " << e.GetDescription(); } Line3D line; if (nullptr != axialPlaneGeometry && nullptr != coronalPlaneGeometry && axialPlaneGeometry->IntersectionLine(coronalPlaneGeometry, line)) { if (nullptr != sagittalPlaneGeometry && sagittalPlaneGeometry->IntersectionPoint(line, point)) { return point; } } // return input geometry center point if no intersection point was found return point; } void mitk::CrosshairManager::UpdateSlice(const SliceNavigationController* sliceNavigationController) { auto viewDirection = sliceNavigationController->GetViewDirection(); unsigned int slicePosition = sliceNavigationController->GetSlice()->GetPos(); switch (viewDirection) { - case mitk::SliceNavigationController::Original: + case AnatomicalPlane::Original: return; - case mitk::SliceNavigationController::Axial: + case AnatomicalPlane::Axial: { m_AxialSlice = slicePosition; this->UpdatePlaneSlice(m_AxialPlaneNode, m_AxialTimeGeometry, m_AxialSlice); break; } - case mitk::SliceNavigationController::Coronal: + case AnatomicalPlane::Coronal: { m_CoronalSlice = slicePosition; this->UpdatePlaneSlice(m_CoronalPlaneNode, m_CoronalTimeGeometry, m_CoronalSlice); break; } - case mitk::SliceNavigationController::Sagittal: + case AnatomicalPlane::Sagittal: { m_SagittalSlice = slicePosition; this->UpdatePlaneSlice(m_SagittalPlaneNode, m_SagittalTimeGeometry, m_SagittalSlice); break; } } } void mitk::CrosshairManager::SetCrosshairVisibility(bool visible) { if (m_AxialPlaneNode.IsNull() || m_CoronalPlaneNode.IsNull() || m_SagittalPlaneNode.IsNull()) { return; } m_AxialPlaneNode->SetVisibility(visible, m_BaseRenderer); m_CoronalPlaneNode->SetVisibility(visible, m_BaseRenderer); m_SagittalPlaneNode->SetVisibility(visible, m_BaseRenderer); } bool mitk::CrosshairManager::GetCrosshairVisibility() const { if (m_AxialPlaneNode.IsNull() || m_CoronalPlaneNode.IsNull() || m_SagittalPlaneNode.IsNull()) { return false; } bool axialVisibility = false; if (m_AxialPlaneNode->GetVisibility(axialVisibility, m_BaseRenderer)) { bool coronalVisibility = false; if (m_CoronalPlaneNode->GetVisibility(coronalVisibility, m_BaseRenderer)) { bool sagittalVisibility = false; if (m_SagittalPlaneNode->GetVisibility(sagittalVisibility, m_BaseRenderer)) { if (axialVisibility == coronalVisibility && coronalVisibility == sagittalVisibility) { return axialVisibility; } } } } mitkThrow() << "Invalid state of plane visibility."; } void mitk::CrosshairManager::SetCrosshairGap(unsigned int gapSize) { m_AxialPlaneNode->SetIntProperty("Crosshair.Gap Size", gapSize); m_CoronalPlaneNode->SetIntProperty("Crosshair.Gap Size", gapSize); m_SagittalPlaneNode->SetIntProperty("Crosshair.Gap Size", gapSize); } void mitk::CrosshairManager::AddPlanesToDataStorage() { if (nullptr == m_DataStorage) { return; } if (m_AxialPlaneNode.IsNull() || m_CoronalPlaneNode.IsNull() || m_SagittalPlaneNode.IsNull() || m_ParentNodeForGeometryPlanes.IsNull()) { return; } this->AddPlaneToDataStorage(m_ParentNodeForGeometryPlanes, nullptr); this->AddPlaneToDataStorage(m_AxialPlaneNode, m_ParentNodeForGeometryPlanes); this->AddPlaneToDataStorage(m_CoronalPlaneNode, m_ParentNodeForGeometryPlanes); this->AddPlaneToDataStorage(m_SagittalPlaneNode, m_ParentNodeForGeometryPlanes); } void mitk::CrosshairManager::RemovePlanesFromDataStorage() { if (nullptr == m_DataStorage) { return; } if (m_AxialPlaneNode.IsNotNull() && m_CoronalPlaneNode.IsNotNull() && m_SagittalPlaneNode.IsNotNull() && m_ParentNodeForGeometryPlanes.IsNotNull()) { m_DataStorage->Remove(m_AxialPlaneNode); m_DataStorage->Remove(m_CoronalPlaneNode); m_DataStorage->Remove(m_SagittalPlaneNode); m_DataStorage->Remove(m_ParentNodeForGeometryPlanes); } } void mitk::CrosshairManager::InitializePlaneProperties(DataNode::Pointer planeNode, const std::string& planeName) { planeNode->SetProperty("reslice.thickslices", mitk::ResliceMethodProperty::New()); planeNode->SetProperty("reslice.thickslices.num", mitk::IntProperty::New(5)); planeNode->SetProperty("Crosshair.Gap Size", mitk::IntProperty::New(32)); // set the crosshair only visible for this specific renderer planeNode->SetVisibility(false); planeNode->SetVisibility(true, m_BaseRenderer); planeNode->SetProperty("name", mitk::StringProperty::New(planeName)); planeNode->SetProperty("helper object", mitk::BoolProperty::New(true)); } void mitk::CrosshairManager::InitializePlaneData(DataNode::Pointer planeNode, const TimeGeometry* timeGeometry, unsigned int& slice) { if (planeNode.IsNull()) { return; } if (nullptr == timeGeometry) { return; } // get the BaseGeometry of the selected time point auto selectedTimePoint = RenderingManager::GetInstance()->GetTimeNavigationController()->GetSelectedTimePoint(); auto currentGeometry = timeGeometry->GetGeometryForTimePoint(selectedTimePoint); if (nullptr == currentGeometry) { // time point not valid for the time geometry mitkThrow() << "Cannot extract a base geometry. A time point is selected that is not covered by" << "the given time geometry. Selected time point: " << selectedTimePoint; } const auto* slicedGeometry = dynamic_cast(currentGeometry.GetPointer()); if (nullptr == slicedGeometry) { return; } slice = slicedGeometry->GetSlices() / 2; // center slice PlaneGeometryData::Pointer planeData = PlaneGeometryData::New(); planeData->SetPlaneGeometry(slicedGeometry->GetPlaneGeometry(slice)); planeNode->SetData(planeData); planeNode->SetMapper(mitk::BaseRenderer::Standard2D, mitk::PlaneGeometryDataMapper2D::New()); } void mitk::CrosshairManager::UpdatePlaneSlice(DataNode::Pointer planeNode, const TimeGeometry* timeGeometry, unsigned int slice) { mitk::PlaneGeometry* planeGeometry = nullptr; // get the currently selected time point auto selectedTimePoint = RenderingManager::GetInstance()->GetTimeNavigationController()->GetSelectedTimePoint(); try { planeGeometry = SliceNavigationHelper::GetCurrentPlaneGeometry(timeGeometry, selectedTimePoint, slice); } catch (const mitk::Exception& e) { MITK_ERROR << "Unable to get plane geometries\n" << "Reason: " << e.GetDescription(); } if (nullptr == planeGeometry) { return; } PlaneGeometryData::Pointer planeData = dynamic_cast(planeNode->GetData()); if (nullptr == planeData) { return; } planeData->SetPlaneGeometry(planeGeometry); planeNode->SetData(planeData); } void mitk::CrosshairManager::SetCrosshairPosition(const Point3D& selectedPoint, DataNode::Pointer planeNode, const TimeGeometry* timeGeometry, unsigned int& slice) { int selectedSlice = -1; try { selectedSlice = SliceNavigationHelper::SelectSliceByPoint(timeGeometry, selectedPoint); } catch (const mitk::Exception& e) { MITK_ERROR << "Unable to select a slice by the given point " << selectedPoint << "\n" << "Reason: " << e.GetDescription(); } if (-1 == selectedSlice) { return; } slice = selectedSlice; mitk::PlaneGeometry* planeGeometry = nullptr; // get the currently selected time point auto selectedTimePoint = RenderingManager::GetInstance()->GetTimeNavigationController()->GetSelectedTimePoint(); try { planeGeometry = SliceNavigationHelper::GetCurrentPlaneGeometry(timeGeometry, selectedTimePoint, slice); } catch (const mitk::Exception& e) { MITK_ERROR << "Unable to get plane geometries\n" << "Reason: " << e.GetDescription(); } if (nullptr == planeGeometry) { return; } PlaneGeometryData::Pointer planeData = dynamic_cast(planeNode->GetData()); if (nullptr == planeData) { return; } planeData->SetPlaneGeometry(planeGeometry); planeNode->SetData(planeData); } void mitk::CrosshairManager::AddPlaneToDataStorage(DataNode::Pointer planeNode, DataNode::Pointer parent) { if (!m_DataStorage->Exists(planeNode) && (nullptr == parent || m_DataStorage->Exists(parent))) { try { m_DataStorage->Add(planeNode, parent); } catch (std::invalid_argument& /*e*/) { return; } } } diff --git a/Modules/Core/src/Controllers/mitkRenderingManager.cpp b/Modules/Core/src/Controllers/mitkRenderingManager.cpp index 992fd2ce5b..5df02a1a3e 100644 --- a/Modules/Core/src/Controllers/mitkRenderingManager.cpp +++ b/Modules/Core/src/Controllers/mitkRenderingManager.cpp @@ -1,793 +1,791 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include #include #include #include #include #include #include #include #include #include #include #include namespace mitk { itkEventMacroDefinition(RenderingManagerEvent, itk::AnyEvent); itkEventMacroDefinition(RenderingManagerViewsInitializedEvent, RenderingManagerEvent); itkEventMacroDefinition(FocusChangedEvent, itk::AnyEvent); RenderingManager::Pointer RenderingManager::s_Instance = nullptr; RenderingManagerFactory *RenderingManager::s_RenderingManagerFactory = nullptr; RenderingManager::RenderingManager() : m_UpdatePending(false), m_MaxLOD(1), m_LODIncreaseBlocked(false), m_LODAbortMechanismEnabled(false), m_ClippingPlaneEnabled(false), m_TimeNavigationController(SliceNavigationController::New()), m_DataStorage(nullptr), m_ConstrainedPanningZooming(true), m_FocusedRenderWindow(nullptr), m_AntiAliasing(AntiAliasing::FastApproximate) { m_ShadingEnabled.assign(3, false); m_ShadingValues.assign(4, 0.0); InitializePropertyList(); } RenderingManager::~RenderingManager() { // Decrease reference counts of all registered vtkRenderWindows for // proper destruction RenderWindowVector::iterator it; for (it = m_AllRenderWindows.begin(); it != m_AllRenderWindows.end(); ++it) { (*it)->UnRegister(nullptr); auto callbacks_it = this->m_RenderWindowCallbacksList.find(*it); if (callbacks_it != this->m_RenderWindowCallbacksList.end()) { (*it)->RemoveObserver(callbacks_it->second.commands[0u]); (*it)->RemoveObserver(callbacks_it->second.commands[1u]); (*it)->RemoveObserver(callbacks_it->second.commands[2u]); } } } void RenderingManager::SetFactory(RenderingManagerFactory *factory) { s_RenderingManagerFactory = factory; } const RenderingManagerFactory *RenderingManager::GetFactory() { return s_RenderingManagerFactory; } bool RenderingManager::HasFactory() { if (RenderingManager::s_RenderingManagerFactory) { return true; } else { return false; } } RenderingManager::Pointer RenderingManager::New() { const RenderingManagerFactory *factory = GetFactory(); if (factory == nullptr) return nullptr; return factory->CreateRenderingManager(); } RenderingManager *RenderingManager::GetInstance() { if (!RenderingManager::s_Instance) { if (s_RenderingManagerFactory) { s_Instance = s_RenderingManagerFactory->CreateRenderingManager(); } } return s_Instance; } bool RenderingManager::IsInstantiated() { if (RenderingManager::s_Instance) return true; else return false; } void RenderingManager::AddRenderWindow(vtkRenderWindow *renderWindow) { if (renderWindow && (m_RenderWindowList.find(renderWindow) == m_RenderWindowList.end())) { m_RenderWindowList[renderWindow] = RENDERING_INACTIVE; m_AllRenderWindows.push_back(renderWindow); if (m_DataStorage.IsNotNull()) BaseRenderer::GetInstance(renderWindow)->SetDataStorage(m_DataStorage.GetPointer()); // Register vtkRenderWindow instance renderWindow->Register(nullptr); // Add callbacks for rendering abort mechanism // BaseRenderer *renderer = BaseRenderer::GetInstance( renderWindow ); vtkCallbackCommand *startCallbackCommand = vtkCallbackCommand::New(); startCallbackCommand->SetCallback(RenderingManager::RenderingStartCallback); renderWindow->AddObserver(vtkCommand::StartEvent, startCallbackCommand); vtkCallbackCommand *progressCallbackCommand = vtkCallbackCommand::New(); progressCallbackCommand->SetCallback(RenderingManager::RenderingProgressCallback); renderWindow->AddObserver(vtkCommand::AbortCheckEvent, progressCallbackCommand); vtkCallbackCommand *endCallbackCommand = vtkCallbackCommand::New(); endCallbackCommand->SetCallback(RenderingManager::RenderingEndCallback); renderWindow->AddObserver(vtkCommand::EndEvent, endCallbackCommand); RenderWindowCallbacks callbacks; callbacks.commands[0u] = startCallbackCommand; callbacks.commands[1u] = progressCallbackCommand; callbacks.commands[2u] = endCallbackCommand; this->m_RenderWindowCallbacksList[renderWindow] = callbacks; // Delete vtk variables correctly startCallbackCommand->Delete(); progressCallbackCommand->Delete(); endCallbackCommand->Delete(); } } void RenderingManager::RemoveRenderWindow(vtkRenderWindow *renderWindow) { if (m_RenderWindowList.erase(renderWindow)) { auto callbacks_it = this->m_RenderWindowCallbacksList.find(renderWindow); if (callbacks_it != this->m_RenderWindowCallbacksList.end()) { renderWindow->RemoveObserver(callbacks_it->second.commands[0u]); renderWindow->RemoveObserver(callbacks_it->second.commands[1u]); renderWindow->RemoveObserver(callbacks_it->second.commands[2u]); this->m_RenderWindowCallbacksList.erase(callbacks_it); } auto rw_it = std::find(m_AllRenderWindows.begin(), m_AllRenderWindows.end(), renderWindow); if (rw_it != m_AllRenderWindows.cend()) { // Decrease reference count for proper destruction (*rw_it)->UnRegister(nullptr); m_AllRenderWindows.erase(rw_it); } } } const RenderingManager::RenderWindowVector &RenderingManager::GetAllRegisteredRenderWindows() { return m_AllRenderWindows; } void RenderingManager::RequestUpdate(vtkRenderWindow *renderWindow) { // If the renderWindow is not valid, we do not want to inadvertently create // an entry in the m_RenderWindowList map. It is possible if the user is // regularly calling AddRenderer and RemoveRenderer for a rendering update // to come into this method with a renderWindow pointer that is valid in the // sense that the window does exist within the application, but that // renderWindow has been temporarily removed from this RenderingManager for // performance reasons. if (m_RenderWindowList.find(renderWindow) == m_RenderWindowList.cend()) { return; } m_RenderWindowList[renderWindow] = RENDERING_REQUESTED; if (!m_UpdatePending) { m_UpdatePending = true; this->GenerateRenderingRequestEvent(); } } void RenderingManager::ForceImmediateUpdate(vtkRenderWindow *renderWindow) { // If the renderWindow is not valid, we do not want to inadvertently create // an entry in the m_RenderWindowList map. It is possible if the user is // regularly calling AddRenderer and RemoveRenderer for a rendering update // to come into this method with a renderWindow pointer that is valid in the // sense that the window does exist within the application, but that // renderWindow has been temporarily removed from this RenderingManager for // performance reasons. if (m_RenderWindowList.find(renderWindow) == m_RenderWindowList.cend()) { return; } // Erase potentially pending requests for this window m_RenderWindowList[renderWindow] = RENDERING_INACTIVE; m_UpdatePending = false; // Immediately repaint this window (implementation platform specific) // If the size is 0 it crashes int *size = renderWindow->GetSize(); if (0 != size[0] && 0 != size[1]) { // prepare the camera etc. before rendering // Note: this is a very important step which should be called before the VTK render! // If you modify the camera anywhere else or after the render call, the scene cannot be seen. auto *vPR = dynamic_cast(BaseRenderer::GetInstance(renderWindow)); if (vPR) vPR->PrepareRender(); // Execute rendering renderWindow->Render(); } } void RenderingManager::RequestUpdateAll(RequestType type) { RenderWindowList::const_iterator it; for (it = m_RenderWindowList.cbegin(); it != m_RenderWindowList.cend(); ++it) { int id = BaseRenderer::GetInstance(it->first)->GetMapperID(); if ((type == REQUEST_UPDATE_ALL) || ((type == REQUEST_UPDATE_2DWINDOWS) && (id == 1)) || ((type == REQUEST_UPDATE_3DWINDOWS) && (id == 2))) { this->RequestUpdate(it->first); } } } void RenderingManager::ForceImmediateUpdateAll(RequestType type) { RenderWindowList::const_iterator it; for (it = m_RenderWindowList.cbegin(); it != m_RenderWindowList.cend(); ++it) { int id = BaseRenderer::GetInstance(it->first)->GetMapperID(); if ((type == REQUEST_UPDATE_ALL) || ((type == REQUEST_UPDATE_2DWINDOWS) && (id == 1)) || ((type == REQUEST_UPDATE_3DWINDOWS) && (id == 2))) { // Immediately repaint this window (implementation platform specific) // If the size is 0, it crashes this->ForceImmediateUpdate(it->first); } } } void RenderingManager::InitializeViewsByBoundingObjects(const DataStorage* dataStorage) { if (nullptr == dataStorage) { return; } // get all nodes that have not set "includeInBoundingBox" to false auto pred = NodePredicateNot::New(NodePredicateProperty::New("includeInBoundingBox", BoolProperty::New(false))); DataStorage::SetOfObjects::ConstPointer filteredNodes = dataStorage->GetSubset(pred); TimeGeometry::ConstPointer boundingGeometry; if (!filteredNodes->empty()) { // calculate bounding geometry of these nodes boundingGeometry = dataStorage->ComputeBoundingGeometry3D(filteredNodes, "visible"); } // initialize the views to the bounding geometry this->InitializeViews(boundingGeometry); } void RenderingManager::InitializeViewByBoundingObjects(vtkRenderWindow* renderWindow, const DataStorage* dataStorage, bool resetCamera) { if (nullptr == dataStorage) { return; } // get all nodes that have not set "includeInBoundingBox" to false auto pred = NodePredicateNot::New(NodePredicateProperty::New("includeInBoundingBox", BoolProperty::New(false))); DataStorage::SetOfObjects::ConstPointer filteredNodes = dataStorage->GetSubset(pred); BaseRenderer* baseRenderer = BaseRenderer::GetInstance(renderWindow); TimeGeometry::ConstPointer boundingGeometry; if (!filteredNodes->empty()) { // calculate bounding geometry of these nodes boundingGeometry = dataStorage->ComputeBoundingGeometry3D(filteredNodes, "visible", baseRenderer); } // initialize the views to the bounding geometry this->InitializeView(renderWindow, boundingGeometry, resetCamera); } bool RenderingManager::InitializeViews(const BaseGeometry* geometry, RequestType type, bool resetCamera) { ProportionalTimeGeometry::Pointer propTimeGeometry = ProportionalTimeGeometry::New(); propTimeGeometry->Initialize(dynamic_cast(geometry->Clone().GetPointer()), 1); return this->InitializeViews(propTimeGeometry, type, resetCamera); } bool RenderingManager::InitializeViews(const TimeGeometry* geometry, RequestType type, bool resetCamera) { bool boundingBoxInitialized = false; TimeGeometry::Pointer modifiedGeometry = nullptr; try { boundingBoxInitialized = this->ExtendGeometryForBoundingBox(geometry, modifiedGeometry); } catch (Exception& exception) { mitkReThrow(exception); } RenderWindowVector allRenderWindows = this->GetAllRegisteredRenderWindows(); RenderWindowVector::const_iterator it; for (it = allRenderWindows.cbegin(); it != allRenderWindows.cend(); ++it) { BaseRenderer *baseRenderer = BaseRenderer::GetInstance(*it); baseRenderer->SetConstrainZoomingAndPanning(this->GetConstrainedPanningZooming()); int id = baseRenderer->GetMapperID(); if ((type == REQUEST_UPDATE_ALL) || ((type == REQUEST_UPDATE_2DWINDOWS) && (id == 1)) || ((type == REQUEST_UPDATE_3DWINDOWS) && (id == 2))) { this->InternalViewInitialization(baseRenderer, modifiedGeometry, boundingBoxInitialized, id, resetCamera); } } if (boundingBoxInitialized) { this->GetTimeNavigationController()->SetInputWorldTimeGeometry(modifiedGeometry); } this->GetTimeNavigationController()->Update(); this->RequestUpdateAll(type); // inform listeners that views have been initialized this->InvokeEvent(RenderingManagerViewsInitializedEvent()); return boundingBoxInitialized; } bool RenderingManager::InitializeViews(RequestType type) { const RenderWindowVector allRenderWindows = this->GetAllRegisteredRenderWindows(); RenderWindowVector::const_iterator it; for (it = allRenderWindows.cbegin(); it != allRenderWindows.cend(); ++it) { BaseRenderer *baseRenderer = BaseRenderer::GetInstance(*it); int id = baseRenderer->GetMapperID(); if ((type == REQUEST_UPDATE_ALL) || ((type == REQUEST_UPDATE_2DWINDOWS) && (id == 1)) || ((type == REQUEST_UPDATE_3DWINDOWS) && (id == 2))) { this->InternalViewInitialization(baseRenderer, nullptr, false, id, false); } } this->RequestUpdateAll(type); // inform listeners that views have been initialized this->InvokeEvent(RenderingManagerViewsInitializedEvent()); return true; } bool RenderingManager::InitializeView(vtkRenderWindow* renderWindow, const BaseGeometry* geometry, bool resetCamera) { ProportionalTimeGeometry::Pointer propTimeGeometry = ProportionalTimeGeometry::New(); propTimeGeometry->Initialize(dynamic_cast(geometry->Clone().GetPointer()), 1); return this->InitializeView(renderWindow, propTimeGeometry, resetCamera); } bool RenderingManager::InitializeView(vtkRenderWindow* renderWindow, const TimeGeometry* geometry, bool resetCamera) { bool boundingBoxInitialized = false; TimeGeometry::Pointer modifiedGeometry = nullptr; try { boundingBoxInitialized = this->ExtendGeometryForBoundingBox(geometry, modifiedGeometry); } catch (Exception &exception) { mitkReThrow(exception); } BaseRenderer* baseRenderer = BaseRenderer::GetInstance(renderWindow); baseRenderer->SetConstrainZoomingAndPanning(this->GetConstrainedPanningZooming()); int id = baseRenderer->GetMapperID(); this->InternalViewInitialization(baseRenderer, modifiedGeometry, boundingBoxInitialized, id, resetCamera); if (boundingBoxInitialized) { this->GetTimeNavigationController()->SetInputWorldTimeGeometry(modifiedGeometry); } this->GetTimeNavigationController()->Update(); this->RequestUpdate(renderWindow); // inform listeners that views have been initialized this->InvokeEvent(RenderingManagerViewsInitializedEvent()); return boundingBoxInitialized; } bool RenderingManager::InitializeView(vtkRenderWindow *renderWindow) { BaseRenderer *baseRenderer = BaseRenderer::GetInstance(renderWindow); int id = baseRenderer->GetMapperID(); this->InternalViewInitialization(baseRenderer, nullptr, false, id, false); this->RequestUpdate(renderWindow); // inform listeners that views have been initialized this->InvokeEvent(RenderingManagerViewsInitializedEvent()); return true; } void RenderingManager::InternalViewInitialization(BaseRenderer *baseRenderer, const TimeGeometry *geometry, bool boundingBoxInitialized, int mapperID, bool resetCamera) { SliceNavigationController *nc = baseRenderer->GetSliceNavigationController(); - - // Re-initialize view direction nc->SetViewDirectionToDefault(); if (boundingBoxInitialized) { // Set geometry for NC nc->SetInputWorldTimeGeometry(geometry); nc->Update(); if (resetCamera) { if (mapperID == BaseRenderer::Standard2D) { // For 2D SNCs, steppers are set so that the cross is centered in the image nc->GetSlice()->SetPos(nc->GetSlice()->GetSteps() / 2); baseRenderer->GetCameraController()->Fit(); } else if (mapperID == BaseRenderer::Standard3D) { baseRenderer->GetCameraController()->SetViewToAnterior(); } } } else { nc->Update(); } } bool RenderingManager::ExtendGeometryForBoundingBox(const TimeGeometry *geometry, TimeGeometry::Pointer& modifiedGeometry) { bool boundingBoxInitialized = false; if (nullptr == geometry) { return boundingBoxInitialized; } modifiedGeometry = geometry->Clone(); if (modifiedGeometry.IsNull()) { return boundingBoxInitialized; } if (modifiedGeometry->GetBoundingBoxInWorld()->GetDiagonalLength2() > eps) { boundingBoxInitialized = true; } // make sure bounding box has an extent bigger than zero in any direction for (TimeStepType step = 0; step < modifiedGeometry->CountTimeSteps(); ++step) { BaseGeometry::BoundsArrayType newBounds = modifiedGeometry->GetGeometryForTimeStep(step)->GetBounds(); for (unsigned int dimension = 0; (2 * dimension) < newBounds.Size(); dimension++) { // check for equality but for an epsilon if (Equal(newBounds[2 * dimension], newBounds[2 * dimension + 1])) { newBounds[2 * dimension + 1] += 1; if (Equal( newBounds[2 * dimension], newBounds[2 * dimension + 1])) // newBounds will still be equal if values are beyond double precision { mitkThrow() << "One dimension of object data has zero length, please make sure you're not using numbers " "beyond double precision as coordinates."; } } } modifiedGeometry->GetGeometryForTimeStep(step)->SetBounds(newBounds); } return boundingBoxInitialized; } const SliceNavigationController *RenderingManager::GetTimeNavigationController() const { return m_TimeNavigationController.GetPointer(); } SliceNavigationController *RenderingManager::GetTimeNavigationController() { return m_TimeNavigationController.GetPointer(); } void RenderingManager::ExecutePendingRequests() { m_UpdatePending = false; // Satisfy all pending update requests RenderWindowList::const_iterator it; int i = 0; for (it = m_RenderWindowList.cbegin(); it != m_RenderWindowList.cend(); ++it, ++i) { if (it->second == RENDERING_REQUESTED) { this->ForceImmediateUpdate(it->first); } } } void RenderingManager::RenderingStartCallback(vtkObject *caller, unsigned long, void *, void *) { auto renderingManager = RenderingManager::GetInstance(); auto renderWindow = dynamic_cast(caller); if (nullptr != renderWindow) renderingManager->m_RenderWindowList[renderWindow] = RENDERING_INPROGRESS; renderingManager->m_UpdatePending = false; } void RenderingManager::RenderingProgressCallback(vtkObject *caller, unsigned long, void *, void *) { auto renderingManager = RenderingManager::GetInstance(); if (renderingManager->m_LODAbortMechanismEnabled) { auto renderWindow = dynamic_cast(caller); if (nullptr != renderWindow) { auto renderer = BaseRenderer::GetInstance(renderWindow); if (nullptr != renderer && 0 < renderer->GetNumberOfVisibleLODEnabledMappers()) renderingManager->DoMonitorRendering(); } } } void RenderingManager::RenderingEndCallback(vtkObject *caller, unsigned long, void *, void *) { auto renderWindow = dynamic_cast(caller); if (nullptr == renderWindow) { return; } auto renderer = BaseRenderer::GetInstance(renderWindow); if (nullptr == renderer) { return; } auto renderingManager = RenderingManager::GetInstance(); renderingManager->m_RenderWindowList[renderer->GetRenderWindow()] = RENDERING_INACTIVE; if (0 < renderer->GetNumberOfVisibleLODEnabledMappers()) { if (0 == renderingManager->m_NextLODMap[renderer]) { renderingManager->StartOrResetTimer(); } else { renderingManager->m_NextLODMap[renderer] = 0; } } } bool RenderingManager::IsRendering() const { RenderWindowList::const_iterator it; for (it = m_RenderWindowList.cbegin(); it != m_RenderWindowList.cend(); ++it) { if (it->second == RENDERING_INPROGRESS) { return true; } } return false; } void RenderingManager::AbortRendering() { RenderWindowList::const_iterator it; for (it = m_RenderWindowList.cbegin(); it != m_RenderWindowList.cend(); ++it) { if (it->second == RENDERING_INPROGRESS) { it->first->SetAbortRender(true); m_RenderingAbortedMap[BaseRenderer::GetInstance(it->first)] = true; } } } int RenderingManager::GetNextLOD(BaseRenderer *renderer) { if (renderer != nullptr) { return m_NextLODMap[renderer]; } else { return 0; } } void RenderingManager::ExecutePendingHighResRenderingRequest() { RenderWindowList::const_iterator it; for (it = m_RenderWindowList.cbegin(); it != m_RenderWindowList.cend(); ++it) { BaseRenderer *renderer = BaseRenderer::GetInstance(it->first); if (renderer->GetNumberOfVisibleLODEnabledMappers() > 0) { if (m_NextLODMap[renderer] == 0) { m_NextLODMap[renderer] = 1; RequestUpdate(it->first); } } } } void RenderingManager::SetMaximumLOD(unsigned int max) { m_MaxLOD = max; } // enable/disable shading void RenderingManager::SetShading(bool state, unsigned int lod) { if (lod > m_MaxLOD) { itkWarningMacro(<< "LOD out of range requested: " << lod << " maxLOD: " << m_MaxLOD); return; } m_ShadingEnabled[lod] = state; } bool RenderingManager::GetShading(unsigned int lod) { if (lod > m_MaxLOD) { itkWarningMacro(<< "LOD out of range requested: " << lod << " maxLOD: " << m_MaxLOD); return false; } return m_ShadingEnabled[lod]; } // enable/disable the clipping plane void RenderingManager::SetClippingPlaneStatus(bool status) { m_ClippingPlaneEnabled = status; } bool RenderingManager::GetClippingPlaneStatus() { return m_ClippingPlaneEnabled; } void RenderingManager::SetShadingValues(float ambient, float diffuse, float specular, float specpower) { m_ShadingValues[0] = ambient; m_ShadingValues[1] = diffuse; m_ShadingValues[2] = specular; m_ShadingValues[3] = specpower; } RenderingManager::FloatVector &RenderingManager::GetShadingValues() { return m_ShadingValues; } void RenderingManager::InitializePropertyList() { if (m_PropertyList.IsNull()) { m_PropertyList = PropertyList::New(); } this->SetProperty("coupled-zoom", BoolProperty::New(false)); this->SetProperty("coupled-plane-rotation", BoolProperty::New(false)); this->SetProperty("MIP-slice-rendering", BoolProperty::New(false)); } PropertyList::Pointer RenderingManager::GetPropertyList() const { return m_PropertyList; } BaseProperty *RenderingManager::GetProperty(const char *propertyKey) const { return m_PropertyList->GetProperty(propertyKey); } void RenderingManager::SetProperty(const char *propertyKey, BaseProperty *propertyValue) { m_PropertyList->SetProperty(propertyKey, propertyValue); } void RenderingManager::SetDataStorage(DataStorage *storage) { if (storage != nullptr) { m_DataStorage = storage; RenderingManager::RenderWindowVector::const_iterator iter; for (iter = m_AllRenderWindows.cbegin(); iter < m_AllRenderWindows.cend(); ++iter) { BaseRenderer::GetInstance((*iter))->SetDataStorage(m_DataStorage.GetPointer()); } } } void RenderingManager::SetRenderWindowFocus(vtkRenderWindow *focusWindow) { if (focusWindow != m_FocusedRenderWindow) { if (!focusWindow || (m_RenderWindowList.find(focusWindow) != m_RenderWindowList.cend())) { m_FocusedRenderWindow = focusWindow; this->InvokeEvent(FocusChangedEvent()); return; } MITK_ERROR << "Tried to set a RenderWindow that does not exist."; } } void RenderingManager::SetAntiAliasing(AntiAliasing antiAliasing) { if (m_AntiAliasing != antiAliasing) { auto renderingManager = RenderingManager::GetInstance(); auto renderWindows = renderingManager->GetAllRegisteredRenderWindows(); for (auto renderWindow : renderWindows) { auto renderers = renderWindow->GetRenderers(); if (nullptr != renderers) { renderers->InitTraversal(); auto renderer = renderers->GetNextItem(); while (nullptr != renderer) { renderer->SetUseFXAA(AntiAliasing::FastApproximate == antiAliasing); renderer = renderers->GetNextItem(); } renderingManager->RequestUpdate(renderWindow); } } m_AntiAliasing = antiAliasing; } } // Create and register generic RenderingManagerFactory. TestingRenderingManagerFactory renderingManagerFactory; } // namespace diff --git a/Modules/Core/src/Controllers/mitkSliceNavigationHelper.cpp b/Modules/Core/src/Controllers/mitkSliceNavigationHelper.cpp index 9aeec5f3e6..0dc248112a 100644 --- a/Modules/Core/src/Controllers/mitkSliceNavigationHelper.cpp +++ b/Modules/Core/src/Controllers/mitkSliceNavigationHelper.cpp @@ -1,141 +1,144 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkSliceNavigationHelper.h" #include #include #include #include #include #include unsigned int mitk::SliceNavigationHelper::SelectSliceByPoint(const TimeGeometry* timeGeometry, const Point3D& point) { int selectedSlice = -1; if (nullptr == timeGeometry) { return selectedSlice; } // get the BaseGeometry of the selected time point auto selectedTimePoint = RenderingManager::GetInstance()->GetTimeNavigationController()->GetSelectedTimePoint(); auto currentGeometry = timeGeometry->GetGeometryForTimePoint(selectedTimePoint); if (nullptr == currentGeometry) { // time point not valid for the ime geometry mitkThrow() << "Cannot extract a base geometry. A time point is selected that is not covered by" << "the given time geometry. Selected time point: " << selectedTimePoint; } const auto* slicedGeometry = dynamic_cast(currentGeometry.GetPointer()); if (nullptr == slicedGeometry) { return selectedSlice; } double bestDistance = itk::NumericTraits::max(); if (slicedGeometry->GetEvenlySpaced()) { PlaneGeometry* plane = slicedGeometry->GetPlaneGeometry(0); const Vector3D& direction = slicedGeometry->GetDirectionVector(); Point3D projectedPoint; plane->Project(point, projectedPoint); // check whether the point is somewhere within the slice stack volume if (direction[0] * (point[0] - projectedPoint[0]) + direction[1] * (point[1] - projectedPoint[1]) + direction[2] * (point[2] - projectedPoint[2]) >= 0) { selectedSlice = static_cast(plane->Distance(point) / slicedGeometry->GetSpacing()[2] + 0.5); } } else { int numberOfSlices = slicedGeometry->GetSlices(); Point3D projectedPoint; for (int slice = 0; slice < numberOfSlices; ++slice) { slicedGeometry->GetPlaneGeometry(slice)->Project(point, projectedPoint); const Vector3D distance = projectedPoint - point; ScalarType currentDistance = distance.GetSquaredNorm(); if (currentDistance < bestDistance) { bestDistance = currentDistance; selectedSlice = slice; } } } if (selectedSlice < 0) { selectedSlice = 0; // do not allow negative slices } return selectedSlice; } mitk::TimeGeometry::Pointer mitk::SliceNavigationHelper::CreateOrientedTimeGeometry(const TimeGeometry* timeGeometry, - PlaneGeometry::PlaneOrientation planeOrientation, bool top, bool frontside, bool rotated) + AnatomicalPlane orientation, + bool top, + bool frontside, + bool rotated) { if (nullptr == timeGeometry) { return nullptr; } // initialize the viewplane SlicedGeometry3D::Pointer slicedGeometry; BaseGeometry::ConstPointer currentGeometry; // get the BaseGeometry of the selected time point auto selectedTimePoint = RenderingManager::GetInstance()->GetTimeNavigationController()->GetSelectedTimePoint(); currentGeometry = timeGeometry->GetGeometryForTimePoint(selectedTimePoint); if(nullptr == currentGeometry) { // time point not valid for the time geometry mitkThrow() << "Cannot extract a base geometry. A time point is selected that is not covered by" << "the given time geometry. Selected time point: " << selectedTimePoint; } slicedGeometry = SlicedGeometry3D::New(); - slicedGeometry->InitializePlanes(currentGeometry, planeOrientation, top, frontside, rotated); + slicedGeometry->InitializePlanes(currentGeometry, orientation, top, frontside, rotated); // use the existing time geometry but replace all time steps with the newly created // sliced geometry (base geometry), initialized to the desired plane orientation auto createdTimeGeometry = timeGeometry->Clone(); createdTimeGeometry->ReplaceTimeStepGeometries(slicedGeometry); return createdTimeGeometry; } mitk::PlaneGeometry* mitk::SliceNavigationHelper::GetCurrentPlaneGeometry(const TimeGeometry* timeGeometry, TimePointType timePoint, unsigned int slicePosition) { if (nullptr == timeGeometry) { return nullptr; } const auto* slicedGeometry = dynamic_cast(timeGeometry->GetGeometryForTimePoint(timePoint).GetPointer()); if (nullptr == slicedGeometry) { // time point not valid for the time geometry mitkThrow() << "Cannot extract a sliced geometry. A time point is selected that is not covered by" << "the given time geometry. Selected time point: " << timePoint; } return slicedGeometry->GetPlaneGeometry(slicePosition); } diff --git a/Modules/Core/src/DataManagement/mitkSlicedGeometry3D.cpp b/Modules/Core/src/DataManagement/mitkSlicedGeometry3D.cpp index bda3bde5bf..be03c44fd6 100644 --- a/Modules/Core/src/DataManagement/mitkSlicedGeometry3D.cpp +++ b/Modules/Core/src/DataManagement/mitkSlicedGeometry3D.cpp @@ -1,962 +1,962 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include "mitkSlicedGeometry3D.h" #include "mitkAbstractTransformGeometry.h" #include "mitkApplyTransformMatrixOperation.h" #include "mitkInteractionConst.h" #include "mitkPlaneGeometry.h" #include "mitkPlaneOperation.h" #include "mitkRestorePlanePositionOperation.h" #include "mitkRotationOperation.h" #include "mitkSliceNavigationController.h" const mitk::ScalarType PI = 3.14159265359; mitk::SlicedGeometry3D::SlicedGeometry3D() : m_EvenlySpaced(true), m_Slices(0), m_ReferenceGeometry(nullptr), m_SliceNavigationController(nullptr) { m_DirectionVector.Fill(0); this->InitializeSlicedGeometry(m_Slices); } mitk::SlicedGeometry3D::SlicedGeometry3D(const SlicedGeometry3D &other) : Superclass(other), m_EvenlySpaced(other.m_EvenlySpaced), m_Slices(other.m_Slices), m_ReferenceGeometry(other.m_ReferenceGeometry), m_SliceNavigationController(other.m_SliceNavigationController) { m_DirectionVector.Fill(0); SetSpacing(other.GetSpacing()); SetDirectionVector(other.GetDirectionVector()); if (m_EvenlySpaced) { assert(!other.m_PlaneGeometries.empty() && "This may happen when you use one of the old Initialize methods, which had a bool parameter that is implicitly casted to the number of slices now."); PlaneGeometry::Pointer geometry = other.m_PlaneGeometries[0]->Clone(); assert(geometry.IsNotNull()); SetPlaneGeometry(geometry, 0); } else { unsigned int s; for (s = 0; s < other.m_Slices; ++s) { if (other.m_PlaneGeometries[s].IsNull()) { assert(other.m_EvenlySpaced); m_PlaneGeometries[s] = nullptr; } else { PlaneGeometry *geometry2D = other.m_PlaneGeometries[s]->Clone(); assert(geometry2D != nullptr); SetPlaneGeometry(geometry2D, s); } } } } mitk::SlicedGeometry3D::~SlicedGeometry3D() { } mitk::PlaneGeometry *mitk::SlicedGeometry3D::GetPlaneGeometry(int s) const { mitk::PlaneGeometry::Pointer geometry2D = nullptr; if (this->IsValidSlice(s)) { geometry2D = m_PlaneGeometries[s]; // If (a) m_EvenlySpaced==true, (b) we don't have a PlaneGeometry stored // for the requested slice, and (c) the first slice (s=0) // is a PlaneGeometry instance, then we calculate the geometry of the // requested as the plane of the first slice shifted by m_Spacing[2]*s // in the direction of m_DirectionVector. if ((m_EvenlySpaced) && (geometry2D.IsNull())) { PlaneGeometry *firstSlice = m_PlaneGeometries[0]; if (firstSlice != nullptr && dynamic_cast(m_PlaneGeometries[0].GetPointer()) == nullptr) { if ((m_DirectionVector[0] == 0.0) && (m_DirectionVector[1] == 0.0) && (m_DirectionVector[2] == 0.0)) { m_DirectionVector = firstSlice->GetNormal(); m_DirectionVector.Normalize(); } Vector3D direction; direction = m_DirectionVector * this->GetSpacing()[2]; mitk::PlaneGeometry::Pointer requestedslice; requestedslice = static_cast(firstSlice->Clone().GetPointer()); requestedslice->SetOrigin(requestedslice->GetOrigin() + direction * s); geometry2D = requestedslice; m_PlaneGeometries[s] = geometry2D; } } return geometry2D; } else { return nullptr; } } const mitk::BoundingBox *mitk::SlicedGeometry3D::GetBoundingBox() const { assert(this->IsBoundingBoxNull() == false); return Superclass::GetBoundingBox(); } bool mitk::SlicedGeometry3D::SetPlaneGeometry(mitk::PlaneGeometry *geometry2D, int s) { if (this->IsValidSlice(s)) { m_PlaneGeometries[s] = geometry2D; m_PlaneGeometries[s]->SetReferenceGeometry(m_ReferenceGeometry); return true; } return false; } void mitk::SlicedGeometry3D::InitializeSlicedGeometry(unsigned int slices) { Superclass::Initialize(); m_Slices = slices; PlaneGeometry::Pointer gnull = nullptr; m_PlaneGeometries.assign(m_Slices, gnull); Vector3D spacing; spacing.Fill(1.0); this->SetSpacing(spacing); m_DirectionVector.Fill(0); } void mitk::SlicedGeometry3D::InitializeEvenlySpaced(mitk::PlaneGeometry *geometry2D, unsigned int slices) { assert(geometry2D != nullptr); this->InitializeEvenlySpaced(geometry2D, geometry2D->GetExtentInMM(2) / geometry2D->GetExtent(2), slices); } void mitk::SlicedGeometry3D::InitializeEvenlySpaced(mitk::PlaneGeometry *geometry2D, mitk::ScalarType zSpacing, unsigned int slices) { assert(geometry2D != nullptr); assert(geometry2D->GetExtent(0) > 0); assert(geometry2D->GetExtent(1) > 0); geometry2D->Register(); Superclass::Initialize(); m_Slices = slices; BoundingBox::BoundsArrayType bounds = geometry2D->GetBounds(); bounds[4] = 0; bounds[5] = slices; // clear and reserve PlaneGeometry::Pointer gnull = nullptr; m_PlaneGeometries.assign(m_Slices, gnull); Vector3D directionVector = geometry2D->GetAxisVector(2); directionVector.Normalize(); directionVector *= zSpacing; // Normally we should use the following four lines to create a copy of // the transform contained in geometry2D, because it may not be changed // by us. But we know that SetSpacing creates a new transform without // changing the old (coming from geometry2D), so we can use the fifth // line instead. We check this at (**). // // AffineTransform3D::Pointer transform = AffineTransform3D::New(); // transform->SetMatrix(geometry2D->GetIndexToWorldTransform()->GetMatrix()); // transform->SetOffset(geometry2D->GetIndexToWorldTransform()->GetOffset()); // SetIndexToWorldTransform(transform); this->SetIndexToWorldTransform(geometry2D->GetIndexToWorldTransform()); mitk::Vector3D spacing; FillVector3D(spacing, geometry2D->GetExtentInMM(0) / bounds[1], geometry2D->GetExtentInMM(1) / bounds[3], zSpacing); this->SetDirectionVector(directionVector); this->SetBounds(bounds); this->SetPlaneGeometry(geometry2D, 0); this->SetSpacing(spacing, true); this->SetEvenlySpaced(); // this->SetTimeBounds( geometry2D->GetTimeBounds() ); assert(this->GetIndexToWorldTransform() != geometry2D->GetIndexToWorldTransform()); // (**) see above. this->SetFrameOfReferenceID(geometry2D->GetFrameOfReferenceID()); this->SetImageGeometry(geometry2D->GetImageGeometry()); geometry2D->UnRegister(); } void mitk::SlicedGeometry3D::InitializePlanes(const mitk::BaseGeometry *geometry3D, - mitk::PlaneGeometry::PlaneOrientation planeorientation, + mitk::AnatomicalPlane orientation, bool top, bool frontside, bool rotated) { m_ReferenceGeometry = geometry3D; PlaneGeometry::Pointer planeGeometry = mitk::PlaneGeometry::New(); - planeGeometry->InitializeStandardPlane(geometry3D, top, planeorientation, frontside, rotated); + planeGeometry->InitializeStandardPlane(geometry3D, top, orientation, frontside, rotated); - int worldAxis = - planeorientation == PlaneGeometry::Sagittal ? 0 : - planeorientation == PlaneGeometry::Coronal ? 1 : 2; + int worldAxis = + orientation == AnatomicalPlane::Sagittal ? 0 : + orientation == AnatomicalPlane::Coronal ? 1 : 2; // Inspired by: // http://www.na-mic.org/Wiki/index.php/Coordinate_System_Conversion_Between_ITK_and_Slicer3 mitk::AffineTransform3D::MatrixType matrix = geometry3D->GetIndexToWorldTransform()->GetMatrix(); matrix.GetVnlMatrix().normalize_columns(); mitk::AffineTransform3D::MatrixType::InternalMatrixType inverseMatrix = matrix.GetTranspose(); int dominantAxis = planeGeometry->CalculateDominantAxes(inverseMatrix).at(worldAxis); ScalarType viewSpacing = geometry3D->GetSpacing()[dominantAxis]; /// Although the double value returned by GetExtent() holds a round number, /// you need to add 0.5 to safely convert it to unsigned it. I have seen a /// case when the result was less by one without this. auto slices = static_cast(geometry3D->GetExtent(dominantAxis) + 0.5); if ( slices == 0 && geometry3D->GetExtent(dominantAxis) > 0) { // require at least one slice if there is _some_ extent slices = 1; } #ifndef NDEBUG int upDirection = itk::Function::Sign(inverseMatrix[dominantAxis][worldAxis]); /// The normal vector of an imaginary plane that points from the world origin (bottom left back /// corner or the world, with the lowest physical coordinates) towards the inside of the volume, /// along the renderer axis. Length is the slice thickness. Vector3D worldPlaneNormal = inverseMatrix.get_row(dominantAxis) * (upDirection * viewSpacing); /// The normal of the standard plane geometry just created. Vector3D standardPlaneNormal = planeGeometry->GetNormal(); /// The standard plane must be parallel to the 'world plane'. The normal of the standard plane /// must point against the world plane if and only if 'top' is 'false'. The length of the /// standard plane normal must be equal to the slice thickness. assert((standardPlaneNormal - (top ? 1.0 : -1.0) * worldPlaneNormal).GetSquaredNorm() < 0.000001); #endif this->InitializeEvenlySpaced(planeGeometry, viewSpacing, slices); #ifndef NDEBUG /// The standard plane normal and the z axis vector of the sliced geometry must point in /// the same direction. Vector3D zAxisVector = this->GetAxisVector(2); Vector3D upscaledStandardPlaneNormal = standardPlaneNormal; upscaledStandardPlaneNormal *= slices; assert((zAxisVector - upscaledStandardPlaneNormal).GetSquaredNorm() < 0.000001); /// You can use this test is to check the handedness of the coordinate system of the current /// geometry. In principle, you can use either left- or right-handed coordinate systems, but /// you normally want it to be consistent, that is the handedness should be the same across /// the renderers of the same viewer. // ScalarType det = vnl_det(this->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix()); // MITK_DEBUG << "world axis: " << worldAxis << (det > 0 ? " ; right-handed" : " ; left-handed"); #endif } void mitk::SlicedGeometry3D::ReinitializePlanes(const Point3D ¢er, const Point3D &referencePoint) { // Need a reference frame to align the rotated planes if (!m_ReferenceGeometry) { return; } // Get first plane of plane stack PlaneGeometry *firstPlane = m_PlaneGeometries[0]; // If plane stack is empty, exit if (!firstPlane || dynamic_cast(firstPlane)) { return; } // Calculate the "directed" spacing when taking the plane (defined by its axes // vectors and normal) as the reference coordinate frame. // // This is done by calculating the radius of the ellipsoid defined by the // original volume spacing axes, in the direction of the respective axis of the // reference frame. mitk::Vector3D axis0 = firstPlane->GetAxisVector(0); mitk::Vector3D axis1 = firstPlane->GetAxisVector(1); mitk::Vector3D normal = firstPlane->GetNormal(); normal.Normalize(); Vector3D spacing; spacing[0] = this->CalculateSpacing(axis0); spacing[1] = this->CalculateSpacing(axis1); spacing[2] = this->CalculateSpacing(normal); Superclass::SetSpacing(spacing); // Now we need to calculate the number of slices in the plane's normal // direction, so that the entire volume is covered. This is done by first // calculating the dot product between the volume diagonal (the maximum // distance inside the volume) and the normal, and dividing this value by // the directed spacing calculated above. ScalarType directedExtent = std::abs(m_ReferenceGeometry->GetExtentInMM(0) * normal[0]) + std::abs(m_ReferenceGeometry->GetExtentInMM(1) * normal[1]) + std::abs(m_ReferenceGeometry->GetExtentInMM(2) * normal[2]); if (directedExtent >= spacing[2]) { m_Slices = static_cast(directedExtent / spacing[2] + 0.5); } else { m_Slices = 1; } // The origin of our "first plane" needs to be adapted to this new extent. // To achieve this, we first calculate the current distance to the volume's // center, and then shift the origin in the direction of the normal by the // difference between this distance and half of the new extent. double centerOfRotationDistance = firstPlane->SignedDistanceFromPlane(center); if (centerOfRotationDistance > 0) { firstPlane->SetOrigin(firstPlane->GetOrigin() + normal * (centerOfRotationDistance - directedExtent / 2.0)); m_DirectionVector = normal; } else { firstPlane->SetOrigin(firstPlane->GetOrigin() + normal * (directedExtent / 2.0 + centerOfRotationDistance)); m_DirectionVector = -normal; } // Now we adjust this distance according with respect to the given reference // point: we need to make sure that the point is touched by one slice of the // new slice stack. double referencePointDistance = firstPlane->SignedDistanceFromPlane(referencePoint); auto referencePointSlice = static_cast(referencePointDistance / spacing[2]); double alignmentValue = referencePointDistance / spacing[2] - referencePointSlice; firstPlane->SetOrigin(firstPlane->GetOrigin() + normal * alignmentValue * spacing[2]); // Finally, we can clear the previous geometry stack and initialize it with // our re-initialized "first plane". m_PlaneGeometries.assign(m_Slices, PlaneGeometry::Pointer(nullptr)); if (m_Slices > 0) { m_PlaneGeometries[0] = firstPlane; } // Reinitialize SNC with new number of slices m_SliceNavigationController->GetSlice()->SetSteps(m_Slices); this->Modified(); } double mitk::SlicedGeometry3D::CalculateSpacing(const mitk::Vector3D &d) const { // Need the spacing of the underlying dataset / geometry if (!m_ReferenceGeometry) { return 1.0; } const mitk::Vector3D &spacing = m_ReferenceGeometry->GetSpacing(); return SlicedGeometry3D::CalculateSpacing(spacing, d); } double mitk::SlicedGeometry3D::CalculateSpacing(const mitk::Vector3D &spacing, const mitk::Vector3D &d) { // The following can be derived from the ellipsoid equation // // 1 = x^2/a^2 + y^2/b^2 + z^2/c^2 // // where (a,b,c) = spacing of original volume (ellipsoid radii) // and (x,y,z) = scaled coordinates of vector d (according to ellipsoid) // double scaling = d[0] * d[0] / (spacing[0] * spacing[0]) + d[1] * d[1] / (spacing[1] * spacing[1]) + d[2] * d[2] / (spacing[2] * spacing[2]); scaling = sqrt(scaling); return (sqrt(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]) / scaling); } mitk::Vector3D mitk::SlicedGeometry3D::AdjustNormal(const mitk::Vector3D &normal) const { TransformType::Pointer inverse = TransformType::New(); m_ReferenceGeometry->GetIndexToWorldTransform()->GetInverse(inverse); Vector3D transformedNormal = inverse->TransformVector(normal); transformedNormal.Normalize(); return transformedNormal; } void mitk::SlicedGeometry3D::SetImageGeometry(const bool isAnImageGeometry) { Superclass::SetImageGeometry(isAnImageGeometry); unsigned int s; for (s = 0; s < m_Slices; ++s) { mitk::BaseGeometry *geometry = m_PlaneGeometries[s]; if (geometry != nullptr) { geometry->SetImageGeometry(isAnImageGeometry); } } } void mitk::SlicedGeometry3D::ChangeImageGeometryConsideringOriginOffset(const bool isAnImageGeometry) { unsigned int s; for (s = 0; s < m_Slices; ++s) { mitk::BaseGeometry *geometry = m_PlaneGeometries[s]; if (geometry != nullptr) { geometry->ChangeImageGeometryConsideringOriginOffset(isAnImageGeometry); } } Superclass::ChangeImageGeometryConsideringOriginOffset(isAnImageGeometry); } bool mitk::SlicedGeometry3D::IsValidSlice(int s) const { return ((s >= 0) && (s < (int)m_Slices)); } const mitk::BaseGeometry *mitk::SlicedGeometry3D::GetReferenceGeometry() const { return m_ReferenceGeometry; } void mitk::SlicedGeometry3D::SetReferenceGeometry(const BaseGeometry *referenceGeometry) { m_ReferenceGeometry = referenceGeometry; std::vector::iterator it; for (it = m_PlaneGeometries.begin(); it != m_PlaneGeometries.end(); ++it) { (*it)->SetReferenceGeometry(referenceGeometry); } } bool mitk::SlicedGeometry3D::HasReferenceGeometry() const { return ( m_ReferenceGeometry != nullptr ); } void mitk::SlicedGeometry3D::PreSetSpacing(const mitk::Vector3D &aSpacing) { bool hasEvenlySpacedPlaneGeometry = false; mitk::Point3D origin; mitk::Vector3D rightDV, bottomDV; BoundingBox::BoundsArrayType bounds; // Check for valid spacing if (!(aSpacing[0] > 0 && aSpacing[1] > 0 && aSpacing[2] > 0)) { mitkThrow() << "You try to set a spacing with at least one element equal or " "smaller to \"0\". This might lead to a crash during rendering. Please double" " check your data!"; } // In case of evenly-spaced data: re-initialize instances of PlaneGeometry, // since the spacing influences them if ((m_EvenlySpaced) && (m_PlaneGeometries.size() > 0)) { const PlaneGeometry *planeGeometry = m_PlaneGeometries[0]; if (planeGeometry && !dynamic_cast(planeGeometry)) { this->WorldToIndex(planeGeometry->GetOrigin(), origin); this->WorldToIndex(planeGeometry->GetAxisVector(0), rightDV); this->WorldToIndex(planeGeometry->GetAxisVector(1), bottomDV); bounds = planeGeometry->GetBounds(); hasEvenlySpacedPlaneGeometry = true; } } BaseGeometry::_SetSpacing(aSpacing); mitk::PlaneGeometry::Pointer firstGeometry; // In case of evenly-spaced data: re-initialize instances of PlaneGeometry, // since the spacing influences them if (hasEvenlySpacedPlaneGeometry) { // create planeGeometry according to new spacing this->IndexToWorld(origin, origin); this->IndexToWorld(rightDV, rightDV); this->IndexToWorld(bottomDV, bottomDV); mitk::PlaneGeometry::Pointer planeGeometry = mitk::PlaneGeometry::New(); planeGeometry->SetImageGeometry(this->GetImageGeometry()); planeGeometry->SetReferenceGeometry(m_ReferenceGeometry); // Store spacing, as Initialize... needs a pointer mitk::Vector3D lokalSpacing = this->GetSpacing(); planeGeometry->InitializeStandardPlane(rightDV.GetVnlVector(), bottomDV.GetVnlVector(), &lokalSpacing); planeGeometry->SetOrigin(origin); planeGeometry->SetBounds(bounds); firstGeometry = planeGeometry; } else if ((m_EvenlySpaced) && (m_PlaneGeometries.size() > 0)) { firstGeometry = m_PlaneGeometries[0].GetPointer(); } // clear and reserve PlaneGeometry::Pointer gnull = nullptr; m_PlaneGeometries.assign(m_Slices, gnull); if (m_Slices > 0) { m_PlaneGeometries[0] = firstGeometry; } this->Modified(); } void mitk::SlicedGeometry3D::SetSliceNavigationController(SliceNavigationController *snc) { m_SliceNavigationController = snc; } mitk::SliceNavigationController *mitk::SlicedGeometry3D::GetSliceNavigationController() { return m_SliceNavigationController; } void mitk::SlicedGeometry3D::SetEvenlySpaced(bool on) { if (m_EvenlySpaced != on) { m_EvenlySpaced = on; this->Modified(); } } void mitk::SlicedGeometry3D::SetDirectionVector(const mitk::Vector3D &directionVector) { Vector3D newDir = directionVector; newDir.Normalize(); if (newDir != m_DirectionVector) { m_DirectionVector = newDir; this->Modified(); } } // void // mitk::SlicedGeometry3D::SetTimeBounds( const mitk::TimeBounds& timebounds ) //{ // Superclass::SetTimeBounds( timebounds ); // // unsigned int s; // for ( s = 0; s < m_Slices; ++s ) // { // if(m_Geometry2Ds[s].IsNotNull()) // { // m_Geometry2Ds[s]->SetTimeBounds( timebounds ); // } // } // m_TimeBounds = timebounds; //} itk::LightObject::Pointer mitk::SlicedGeometry3D::InternalClone() const { Self::Pointer newGeometry = new SlicedGeometry3D(*this); newGeometry->UnRegister(); return newGeometry.GetPointer(); } void mitk::SlicedGeometry3D::PrintSelf(std::ostream &os, itk::Indent indent) const { Superclass::PrintSelf(os, indent); os << indent << " EvenlySpaced: " << m_EvenlySpaced << std::endl; if (m_EvenlySpaced) { os << indent << " DirectionVector: " << m_DirectionVector << std::endl; } os << indent << " Slices: " << m_Slices << std::endl; os << std::endl; os << indent << " GetPlaneGeometry(0): "; if (this->GetPlaneGeometry(0) == nullptr) { os << "nullptr" << std::endl; } else { this->GetPlaneGeometry(0)->Print(os, indent); } } void mitk::SlicedGeometry3D::ExecuteOperation(Operation *operation) { PlaneGeometry::Pointer geometry2D; ApplyTransformMatrixOperation *applyMatrixOp; Point3D center; switch (operation->GetOperationType()) { case OpNOTHING: break; case OpROTATE: if (m_EvenlySpaced) { // Need a reference frame to align the rotation if (m_ReferenceGeometry) { // Clear all generated geometries and then rotate only the first slice. // The other slices will be re-generated on demand // Save first slice PlaneGeometry::Pointer geometry2D = m_PlaneGeometries[0]; auto *rotOp = dynamic_cast(operation); // Generate a RotationOperation using the dataset center instead of // the supplied rotation center. This is necessary so that the rotated // zero-plane does not shift away. The supplied center is instead used // to adjust the slice stack afterwards. Point3D center = m_ReferenceGeometry->GetCenter(); RotationOperation centeredRotation( rotOp->GetOperationType(), center, rotOp->GetVectorOfRotation(), rotOp->GetAngleOfRotation()); // Rotate first slice geometry2D->ExecuteOperation(¢eredRotation); // Clear the slice stack and adjust it according to the center of // the dataset and the supplied rotation center (see documentation of // ReinitializePlanes) this->ReinitializePlanes(center, rotOp->GetCenterOfRotation()); geometry2D->SetSpacing(this->GetSpacing()); if (m_SliceNavigationController) { m_SliceNavigationController->SelectSliceByPoint(rotOp->GetCenterOfRotation()); m_SliceNavigationController->AdjustSliceStepperRange(); } BaseGeometry::ExecuteOperation(¢eredRotation); } else { // we also have to consider the case, that there is no reference geometry available. if (m_PlaneGeometries.size() > 0) { // Reach through to all slices in my container for (auto iter = m_PlaneGeometries.begin(); iter != m_PlaneGeometries.end(); ++iter) { // Test for empty slices, which can happen if evenly spaced geometry if ((*iter).IsNotNull()) { (*iter)->ExecuteOperation(operation); } } // rotate overall geometry auto *rotOp = dynamic_cast(operation); BaseGeometry::ExecuteOperation(rotOp); } } } else { // Reach through to all slices for (auto iter = m_PlaneGeometries.begin(); iter != m_PlaneGeometries.end(); ++iter) { (*iter)->ExecuteOperation(operation); } } break; case OpORIENT: if (m_EvenlySpaced) { // get operation data auto *planeOp = dynamic_cast(operation); // Get first slice PlaneGeometry::Pointer planeGeometry = m_PlaneGeometries[0]; // Need a PlaneGeometry, a PlaneOperation and a reference frame to // carry out the re-orientation. If not all available, stop here if (!m_ReferenceGeometry || (!planeGeometry || dynamic_cast(planeGeometry.GetPointer())) || !planeOp) { break; } // General Behavior: // Clear all generated geometries and then rotate only the first slice. // The other slices will be re-generated on demand // // 1st Step: Reorient Normal Vector of first plane // Point3D center = planeOp->GetPoint(); // m_ReferenceGeometry->GetCenter(); mitk::Vector3D currentNormal = planeGeometry->GetNormal(); mitk::Vector3D newNormal; if (planeOp->AreAxisDefined()) { // If planeOp was defined by one centerpoint and two axis vectors newNormal = CrossProduct(planeOp->GetAxisVec0(), planeOp->GetAxisVec1()); } else { // If planeOp was defined by one centerpoint and one normal vector newNormal = planeOp->GetNormal(); } // Get Rotation axis und angle currentNormal.Normalize(); newNormal.Normalize(); ScalarType rotationAngle = angle(currentNormal.GetVnlVector(), newNormal.GetVnlVector()); rotationAngle *= 180.0 / vnl_math::pi; // from rad to deg Vector3D rotationAxis = itk::CrossProduct(currentNormal, newNormal); if (std::abs(rotationAngle - 180) < mitk::eps) { // current Normal and desired normal are not linear independent!!(e.g 1,0,0 and -1,0,0). // Rotation Axis should be ANY vector that is 90� to current Normal mitk::Vector3D helpNormal; helpNormal = currentNormal; helpNormal[0] += 1; helpNormal[1] -= 1; helpNormal[2] += 1; helpNormal.Normalize(); rotationAxis = itk::CrossProduct(helpNormal, currentNormal); } RotationOperation centeredRotation(mitk::OpROTATE, center, rotationAxis, rotationAngle); // Rotate first slice planeGeometry->ExecuteOperation(¢eredRotation); // Reinitialize planes and select slice, if my rotations are all done. if (!planeOp->AreAxisDefined()) { // Clear the slice stack and adjust it according to the center of // rotation and plane position (see documentation of ReinitializePlanes) this->ReinitializePlanes(center, planeOp->GetPoint()); planeGeometry->SetSpacing(this->GetSpacing()); if (m_SliceNavigationController) { m_SliceNavigationController->SelectSliceByPoint(planeOp->GetPoint()); m_SliceNavigationController->AdjustSliceStepperRange(); } } // Also apply rotation on the slicedGeometry - Geometry3D (Bounding geometry) BaseGeometry::ExecuteOperation(¢eredRotation); // // 2nd step. If axis vectors were defined, rotate the plane around its normal to fit these // if (planeOp->AreAxisDefined()) { mitk::Vector3D vecAxixNew = planeOp->GetAxisVec0(); vecAxixNew.Normalize(); mitk::Vector3D VecAxisCurr = planeGeometry->GetAxisVector(0); VecAxisCurr.Normalize(); ScalarType rotationAngle = angle(VecAxisCurr.GetVnlVector(), vecAxixNew.GetVnlVector()); rotationAngle = rotationAngle * 180 / PI; // Rad to Deg // we rotate around the normal of the plane, but we do not know, if we need to rotate clockwise // or anti-clockwise. So we rotate around the crossproduct of old and new Axisvector. // Since both axis vectors lie in the plane, the crossproduct is the planes normal or the negative planes // normal rotationAxis = itk::CrossProduct(VecAxisCurr, vecAxixNew); if (std::abs(rotationAngle - 180) < mitk::eps) { // current axisVec and desired axisVec are not linear independent!!(e.g 1,0,0 and -1,0,0). // Rotation Axis can be just plane Normal. (have to rotate by 180�) rotationAxis = newNormal; } // Perform Rotation mitk::RotationOperation op(mitk::OpROTATE, center, rotationAxis, rotationAngle); planeGeometry->ExecuteOperation(&op); // Apply changes on first slice to whole slice stack this->ReinitializePlanes(center, planeOp->GetPoint()); planeGeometry->SetSpacing(this->GetSpacing()); if (m_SliceNavigationController) { m_SliceNavigationController->SelectSliceByPoint(planeOp->GetPoint()); m_SliceNavigationController->AdjustSliceStepperRange(); } // Also apply rotation on the slicedGeometry - Geometry3D (Bounding geometry) BaseGeometry::ExecuteOperation(&op); } } else { // Reach through to all slices for (auto iter = m_PlaneGeometries.begin(); iter != m_PlaneGeometries.end(); ++iter) { (*iter)->ExecuteOperation(operation); } } break; case OpRESTOREPLANEPOSITION: if (m_EvenlySpaced) { // Save first slice PlaneGeometry::Pointer planeGeometry = m_PlaneGeometries[0]; auto *restorePlaneOp = dynamic_cast(operation); // Need a PlaneGeometry, a PlaneOperation and a reference frame to // carry out the re-orientation if (m_ReferenceGeometry && (planeGeometry && dynamic_cast(planeGeometry.GetPointer()) == nullptr) && restorePlaneOp) { // Clear all generated geometries and then rotate only the first slice. // The other slices will be re-generated on demand // Rotate first slice planeGeometry->ExecuteOperation(restorePlaneOp); m_DirectionVector = restorePlaneOp->GetDirectionVector(); double centerOfRotationDistance = planeGeometry->SignedDistanceFromPlane(m_ReferenceGeometry->GetCenter()); if (centerOfRotationDistance <= 0) { m_DirectionVector = -m_DirectionVector; } Vector3D spacing = restorePlaneOp->GetSpacing(); Superclass::SetSpacing(spacing); // /*Now we need to calculate the number of slices in the plane's normal // direction, so that the entire volume is covered. This is done by first // calculating the dot product between the volume diagonal (the maximum // distance inside the volume) and the normal, and dividing this value by // the directed spacing calculated above.*/ ScalarType directedExtent = std::abs(m_ReferenceGeometry->GetExtentInMM(0) * m_DirectionVector[0]) + std::abs(m_ReferenceGeometry->GetExtentInMM(1) * m_DirectionVector[1]) + std::abs(m_ReferenceGeometry->GetExtentInMM(2) * m_DirectionVector[2]); if (directedExtent >= spacing[2]) { m_Slices = static_cast(directedExtent / spacing[2] + 0.5); } else { m_Slices = 1; } m_PlaneGeometries.assign(m_Slices, PlaneGeometry::Pointer(nullptr)); if (m_Slices > 0) { m_PlaneGeometries[0] = planeGeometry; } m_SliceNavigationController->GetSlice()->SetSteps(m_Slices); this->Modified(); // End Reinitialization if (m_SliceNavigationController) { m_SliceNavigationController->GetSlice()->SetPos(restorePlaneOp->GetPos()); m_SliceNavigationController->AdjustSliceStepperRange(); } BaseGeometry::ExecuteOperation(restorePlaneOp); } } else { // Reach through to all slices for (auto iter = m_PlaneGeometries.begin(); iter != m_PlaneGeometries.end(); ++iter) { (*iter)->ExecuteOperation(operation); } } break; case OpAPPLYTRANSFORMMATRIX: // Clear all generated geometries and then transform only the first slice. // The other slices will be re-generated on demand // Save first slice geometry2D = m_PlaneGeometries[0]; applyMatrixOp = dynamic_cast(operation); // Apply transformation to first plane geometry2D->ExecuteOperation(applyMatrixOp); // Generate a ApplyTransformMatrixOperation using the dataset center instead of // the supplied rotation center. The supplied center is instead used to adjust the // slice stack afterwards (see OpROTATE). center = m_ReferenceGeometry->GetCenter(); // Clear the slice stack and adjust it according to the center of // the dataset and the supplied rotation center (see documentation of // ReinitializePlanes) this->ReinitializePlanes(center, applyMatrixOp->GetReferencePoint()); BaseGeometry::ExecuteOperation(applyMatrixOp); break; default: // let handle by base class if we don't do anything BaseGeometry::ExecuteOperation(operation); } this->Modified(); } diff --git a/Modules/Core/src/Interactions/mitkDisplayActionEventBroadcast.cpp b/Modules/Core/src/Interactions/mitkDisplayActionEventBroadcast.cpp index c42172fe75..fd3cf979ef 100644 --- a/Modules/Core/src/Interactions/mitkDisplayActionEventBroadcast.cpp +++ b/Modules/Core/src/Interactions/mitkDisplayActionEventBroadcast.cpp @@ -1,807 +1,807 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkDisplayActionEventBroadcast.h" // us #include "usGetModuleContext.h" #include "usModuleContext.h" // mitk core module #include #include #include #include #include #include #include mitk::DisplayActionEventBroadcast::DisplayActionEventBroadcast() : m_AlwaysReact(false) , m_AutoRepeat(false) , m_IndexToSliceModifier(4) , m_InvertScrollDirection(false) , m_InvertZoomDirection(false) , m_ZoomFactor(2) , m_InvertMoveDirection(false) , m_InvertLevelWindowDirection(false) , m_LinkPlanes(true) { m_StartCoordinateInMM.Fill(0); m_LastDisplayCoordinate.Fill(0); m_CurrentDisplayCoordinate.Fill(0); // register the broadcast class (itself) as an interaction event observer via micro services us::ServiceProperties props; props["name"] = std::string("DisplayActionEventBroadcast"); m_ServiceRegistration = us::GetModuleContext()->RegisterService(this, props); } mitk::DisplayActionEventBroadcast::~DisplayActionEventBroadcast() { m_ServiceRegistration.Unregister(); } void mitk::DisplayActionEventBroadcast::Notify(InteractionEvent* interactionEvent, bool isHandled) { // the event is passed to the state machine interface to be handled if (!isHandled || m_AlwaysReact) { HandleEvent(interactionEvent, nullptr); } } void mitk::DisplayActionEventBroadcast::ConnectActionsAndFunctions() { CONNECT_CONDITION("check_position_event", CheckPositionEvent); CONNECT_CONDITION("check_can_rotate", CheckRotationPossible); CONNECT_CONDITION("check_can_swivel", CheckSwivelPossible); CONNECT_FUNCTION("init", Init); CONNECT_FUNCTION("move", Move); CONNECT_FUNCTION("zoom", Zoom); CONNECT_FUNCTION("scroll", Scroll); CONNECT_FUNCTION("ScrollOneUp", ScrollOneUp); CONNECT_FUNCTION("ScrollOneDown", ScrollOneDown); CONNECT_FUNCTION("levelWindow", AdjustLevelWindow); CONNECT_FUNCTION("setCrosshair", SetCrosshair); CONNECT_FUNCTION("startRotation", StartRotation); CONNECT_FUNCTION("endRotation", EndRotation); CONNECT_FUNCTION("rotate", Rotate); CONNECT_FUNCTION("swivel", Swivel); CONNECT_FUNCTION("IncreaseTimeStep", IncreaseTimeStep); CONNECT_FUNCTION("DecreaseTimeStep", DecreaseTimeStep); } void mitk::DisplayActionEventBroadcast::ConfigurationChanged() { PropertyList::Pointer properties = GetAttributes(); // alwaysReact std::string strAlwaysReact = ""; m_AlwaysReact = false; if (properties->GetStringProperty("alwaysReact", strAlwaysReact)) { if (strAlwaysReact == "true") { m_AlwaysReact = true; } } // auto repeat std::string strAutoRepeat = ""; m_AutoRepeat = false; if (properties->GetStringProperty("autoRepeat", strAutoRepeat)) { if (strAutoRepeat == "true") { m_AutoRepeat = true; } } // pixel movement for scrolling one slice std::string strPixelPerSlice = ""; m_IndexToSliceModifier = 4; if (properties->GetStringProperty("pixelPerSlice", strPixelPerSlice)) { m_IndexToSliceModifier = atoi(strPixelPerSlice.c_str()); } // scroll direction if (!properties->GetStringProperty("scrollDirection", m_ScrollDirection)) { m_ScrollDirection = "updown"; } m_InvertScrollDirection = GetBoolProperty(properties, "invertScrollDirection", false); // zoom direction if (!properties->GetStringProperty("zoomDirection", m_ZoomDirection)) { m_ZoomDirection = "updown"; } m_InvertZoomDirection = GetBoolProperty(properties, "invertZoomDirection", false); m_InvertMoveDirection = GetBoolProperty(properties, "invertMoveDirection", false); if (!properties->GetStringProperty("levelWindowDirection", m_LevelDirection)) { m_LevelDirection = "leftright"; } m_InvertLevelWindowDirection = GetBoolProperty(properties, "invertLevelWindowDirection", false); // coupled rotation std::string strCoupled = ""; m_LinkPlanes = false; if (properties->GetStringProperty("coupled", strCoupled)) { if (strCoupled == "true") { m_LinkPlanes = true; } } // zoom factor std::string strZoomFactor = ""; properties->GetStringProperty("zoomFactor", strZoomFactor); m_ZoomFactor = .05; if (atoi(strZoomFactor.c_str()) > 0) { m_ZoomFactor = 1.0 + (atoi(strZoomFactor.c_str()) / 100.0); } } bool mitk::DisplayActionEventBroadcast::FilterEvents(InteractionEvent* interactionEvent, DataNode * /*dataNode*/) { BaseRenderer* sendingRenderer = interactionEvent->GetSender(); if (nullptr == sendingRenderer) { return false; } if (BaseRenderer::Standard3D == sendingRenderer->GetMapperID()) { return false; } return true; } bool mitk::DisplayActionEventBroadcast::CheckPositionEvent(const InteractionEvent *interactionEvent) { const auto* positionEvent = dynamic_cast(interactionEvent); if (nullptr == positionEvent) { return false; } return true; } bool mitk::DisplayActionEventBroadcast::CheckRotationPossible(const InteractionEvent *interactionEvent) { // Decide between moving and rotation slices. /* Detailed logic: 1. Find the SliceNavigationController that has sent the event: this one defines our rendering plane and will NOT be rotated. Needs not even be counted or checked. 2. Inspect every other SliceNavigationController - calculate the line intersection of this SliceNavigationController's plane with our rendering plane - if there is NO intersection, ignore and continue - IF there is an intersection - check the mouse cursor's distance from that line. 0. if the line is NOT near the cursor, remember the plane as "one of the other planes" (which can be rotated in "locked" mode) 1. on first line near the cursor, just remember this intersection line as THE other plane that we want to rotate 2. on every consecutive line near the cursor, check if the line is geometrically identical to the line that we want to rotate - if yes, we just push this line to the "other" lines and rotate it along - if no, then we have a situation where the mouse is near two other lines (e.g. crossing point) and don't want to rotate */ const auto* positionEvent = dynamic_cast(interactionEvent); if (nullptr == positionEvent) { return false; } BaseRenderer* renderer = positionEvent->GetSender(); if (nullptr == renderer) { return false; } const PlaneGeometry* rendererWorldPlaneGeometry = renderer->GetCurrentWorldPlaneGeometry(); if (nullptr == rendererWorldPlaneGeometry) { return false; } Point3D position = positionEvent->GetPositionInWorld(); const auto spacing = rendererWorldPlaneGeometry->GetSpacing(); const PlaneGeometry *geometryToBeRotated = nullptr; // this one is under the mouse cursor const PlaneGeometry *anyOtherGeometry = nullptr; // this is also visible (for calculation of intersection ONLY) Line3D intersectionLineWithGeometryToBeRotated; bool hitMultipleLines(false); m_SNCsToBeRotated.clear(); const ScalarType threshholdDistancePixels = 12.0; auto allRenderWindows = RenderingManager::GetInstance()->GetAllRegisteredRenderWindows(); for (auto renderWindow : allRenderWindows) { SliceNavigationController* snc = BaseRenderer::GetInstance(renderWindow)->GetSliceNavigationController(); // If the mouse cursor is in 3D Renderwindow, do not check for intersecting planes. if (BaseRenderer::Standard3D == BaseRenderer::GetInstance(renderWindow)->GetMapperID()) { continue; } const PlaneGeometry* rendererPlaneGeometry = snc->GetCurrentPlaneGeometry(); if (nullptr == rendererPlaneGeometry) { continue; // ignore, we don't see a plane } // check if there is an intersection between rendered / clicked geometry and the one being analyzed Line3D intersectionLine; if (!rendererWorldPlaneGeometry->IntersectionLine(rendererPlaneGeometry, intersectionLine)) { continue; // we ignore this plane, it's parallel to our plane } // check distance from intersection line - const double distanceFromIntersectionLine = intersectionLine.Distance(position) / spacing[snc->GetDefaultViewDirection()]; + const double distanceFromIntersectionLine = intersectionLine.Distance(position) / spacing[static_cast(snc->GetDefaultViewDirection())]; // far away line, only remember for linked rotation if necessary if (distanceFromIntersectionLine > threshholdDistancePixels) { // we just take the last one, so overwrite each iteration (we just need some crossing point) // TODO what about multiple crossings? NOW we have undefined behavior / random crossing point is used anyOtherGeometry = rendererPlaneGeometry; if (m_LinkPlanes) { // if planes are linked, apply rotation to all planes m_SNCsToBeRotated.push_back(snc); } } else // close to cursor { if (nullptr == geometryToBeRotated) // first one close to the cursor { geometryToBeRotated = rendererPlaneGeometry; intersectionLineWithGeometryToBeRotated = intersectionLine; m_SNCsToBeRotated.push_back(snc); } else { // compare to the line defined by geometryToBeRotated: if identical, just rotate this otherRenderersRenderPlane // together with the primary one // if different, DON'T rotate if (intersectionLine.IsParallel(intersectionLineWithGeometryToBeRotated) && intersectionLine.Distance(intersectionLineWithGeometryToBeRotated.GetPoint1()) < eps) { m_SNCsToBeRotated.push_back(snc); } else { hitMultipleLines = true; } } } } bool moveSlices(true); if (geometryToBeRotated && anyOtherGeometry && rendererWorldPlaneGeometry && !hitMultipleLines) { // assure all three are valid, so calculation of center of rotation can be done moveSlices = false; } // question in state machine is: "rotate?" if (moveSlices) // i.e. NOT rotate { return false; } else { // we have enough information for rotation // remember where the last cursor position ON THE LINE has been observed m_LastCursorPosition = intersectionLineWithGeometryToBeRotated.Project(position); // find center of rotation by intersection with any of the OTHER lines if (anyOtherGeometry->IntersectionPoint(intersectionLineWithGeometryToBeRotated, m_CenterOfRotation)) { return true; } else { return false; } } return false; } bool mitk::DisplayActionEventBroadcast::CheckSwivelPossible(const InteractionEvent *interactionEvent) { // Decide between moving and rotation: if we're close to the crossing // point of the planes, moving mode is entered, otherwise // rotation/swivel mode const auto* positionEvent = dynamic_cast(interactionEvent); if (nullptr == positionEvent) { return false; } BaseRenderer* renderer = positionEvent->GetSender(); if (nullptr == renderer) { return false; } const Point3D& position = positionEvent->GetPositionInWorld(); m_SNCsToBeRotated.clear(); const PlaneGeometry* clickedGeometry(nullptr); const PlaneGeometry* otherGeometry1(nullptr); const PlaneGeometry* otherGeometry2(nullptr); const ScalarType threshholdDistancePixels = 6.0; auto allRenderWindows = RenderingManager::GetInstance()->GetAllRegisteredRenderWindows(); for (auto renderWindow : allRenderWindows) { SliceNavigationController* snc = BaseRenderer::GetInstance(renderWindow)->GetSliceNavigationController(); // If the mouse cursor is in 3D Renderwindow, do not check for intersecting planes. if (BaseRenderer::Standard3D == BaseRenderer::GetInstance(renderWindow)->GetMapperID()) { continue; } const PlaneGeometry* rendererPlaneGeometry = snc->GetCurrentPlaneGeometry(); if (nullptr == rendererPlaneGeometry) { continue; // ignore, we don't see a plane } if (snc == renderer->GetSliceNavigationController()) { clickedGeometry = rendererPlaneGeometry; m_SNCsToBeRotated.push_back(snc); } else { if (nullptr == otherGeometry1) { otherGeometry1 = rendererPlaneGeometry; } else { otherGeometry2 = rendererPlaneGeometry; } if (m_LinkPlanes) { // if planes are linked, apply rotation to all planes m_SNCsToBeRotated.push_back(snc); } } } Line3D line; Point3D point; if ((nullptr != clickedGeometry) && (nullptr != otherGeometry1) && (nullptr != otherGeometry2) && clickedGeometry->IntersectionLine(otherGeometry1, line) && otherGeometry2->IntersectionPoint(line, point)) { m_CenterOfRotation = point; if (m_CenterOfRotation.EuclideanDistanceTo(position) < threshholdDistancePixels) { return false; } else { m_ReferenceCursor = positionEvent->GetPointerPositionOnScreen(); // Get main axes of rotation plane and store it for rotation step m_RotationPlaneNormal = clickedGeometry->GetNormal(); ScalarType xVector[] = { 1.0, 0.0, 0.0 }; ScalarType yVector[] = { 0.0, 1.0, 0.0 }; clickedGeometry->BaseGeometry::IndexToWorld(Vector3D(xVector), m_RotationPlaneXVector); clickedGeometry->BaseGeometry::IndexToWorld(Vector3D(yVector), m_RotationPlaneYVector); m_RotationPlaneNormal.Normalize(); m_RotationPlaneXVector.Normalize(); m_RotationPlaneYVector.Normalize(); m_PreviousRotationAxis.Fill(0.0); m_PreviousRotationAxis[2] = 1.0; m_PreviousRotationAngle = 0.0; return true; } } else { return false; } return false; } void mitk::DisplayActionEventBroadcast::Init(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) { const auto* positionEvent = dynamic_cast(interactionEvent); if (nullptr == positionEvent) { return; } m_LastDisplayCoordinate = positionEvent->GetPointerPositionOnScreen(); m_CurrentDisplayCoordinate = m_LastDisplayCoordinate; positionEvent->GetSender()->DisplayToPlane(m_LastDisplayCoordinate, m_StartCoordinateInMM); } void mitk::DisplayActionEventBroadcast::Move(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) { const auto* positionEvent = dynamic_cast(interactionEvent); if (nullptr == positionEvent) { return; } BaseRenderer* sender = interactionEvent->GetSender(); Vector2D moveVector = m_LastDisplayCoordinate - positionEvent->GetPointerPositionOnScreen(); if (m_InvertMoveDirection) { moveVector *= -1.0; } moveVector *= sender->GetScaleFactorMMPerDisplayUnit(); // #TODO: put here? // store new display coordinate m_LastDisplayCoordinate = positionEvent->GetPointerPositionOnScreen(); // propagate move event with computed geometry values InvokeEvent(DisplayMoveEvent(interactionEvent, moveVector)); } void mitk::DisplayActionEventBroadcast::SetCrosshair(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) { const auto* positionEvent = dynamic_cast(interactionEvent); if (nullptr == positionEvent) { return; } Point3D position = positionEvent->GetPositionInWorld(); // propagate set crosshair event with computed geometry values InvokeEvent(DisplaySetCrosshairEvent(interactionEvent, position)); } void mitk::DisplayActionEventBroadcast::Zoom(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) { const auto* positionEvent = dynamic_cast(interactionEvent); if (nullptr == positionEvent) { return; } float factor = 1.0; float distance = 0; if (m_ZoomDirection == "updown") { distance = m_CurrentDisplayCoordinate[1] - m_LastDisplayCoordinate[1]; } else { distance = m_CurrentDisplayCoordinate[0] - m_LastDisplayCoordinate[0]; } if (m_InvertZoomDirection) { distance *= -1.0; } // set zooming speed if (distance < 0.0) { factor = 1.0 / m_ZoomFactor; } else if (distance > 0.0) { factor = 1.0 * m_ZoomFactor; } // store new display coordinates m_LastDisplayCoordinate = m_CurrentDisplayCoordinate; m_CurrentDisplayCoordinate = positionEvent->GetPointerPositionOnScreen(); // propagate zoom event with computed geometry values InvokeEvent(DisplayZoomEvent(interactionEvent, factor, m_StartCoordinateInMM)); } void mitk::DisplayActionEventBroadcast::Scroll(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) { const auto* positionEvent = dynamic_cast(interactionEvent); if (nullptr == positionEvent) { return; } int sliceDelta = 0; // scroll direction if (m_ScrollDirection == "updown") { sliceDelta = static_cast(m_CurrentDisplayCoordinate[1] - m_LastDisplayCoordinate[1]); } else { sliceDelta = static_cast(m_CurrentDisplayCoordinate[0] - m_LastDisplayCoordinate[0]); } if (m_InvertScrollDirection) { sliceDelta *= -1; } // set how many pixels the mouse has to be moved to scroll one slice // if the mouse has been moved less than 'm_IndexToSliceModifier', pixels slice ONE slice only if (sliceDelta > 0 && sliceDelta < m_IndexToSliceModifier) { sliceDelta = m_IndexToSliceModifier; } else if (sliceDelta < 0 && sliceDelta > -m_IndexToSliceModifier) { sliceDelta = -m_IndexToSliceModifier; } sliceDelta /= m_IndexToSliceModifier; // store new display coordinates m_LastDisplayCoordinate = m_CurrentDisplayCoordinate; m_CurrentDisplayCoordinate = positionEvent->GetPointerPositionOnScreen(); // propagate scroll event with computed geometry values InvokeEvent(DisplayScrollEvent(interactionEvent, sliceDelta, m_AutoRepeat)); } void mitk::DisplayActionEventBroadcast::ScrollOneUp(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) { int sliceDelta = 1; if (m_InvertScrollDirection) { sliceDelta = -1; } // propagate scroll event with a single slice delta (increase) InvokeEvent(DisplayScrollEvent(interactionEvent, sliceDelta, m_AutoRepeat)); } void mitk::DisplayActionEventBroadcast::ScrollOneDown(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) { int sliceDelta = -1; if (m_InvertScrollDirection) { sliceDelta = 1; } // propagate scroll event with a single slice delta (decrease) InvokeEvent(DisplayScrollEvent(interactionEvent, sliceDelta, m_AutoRepeat)); } void mitk::DisplayActionEventBroadcast::AdjustLevelWindow(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) { const auto* positionEvent = dynamic_cast(interactionEvent); if (nullptr == positionEvent) { return; } ScalarType level; ScalarType window; if (m_LevelDirection == "leftright") { level = m_CurrentDisplayCoordinate[0] - m_LastDisplayCoordinate[0]; window = m_CurrentDisplayCoordinate[1] - m_LastDisplayCoordinate[1]; } else { level = m_CurrentDisplayCoordinate[1] - m_LastDisplayCoordinate[1]; window = m_CurrentDisplayCoordinate[0] - m_LastDisplayCoordinate[0]; } if (m_InvertLevelWindowDirection) { level *= -1; window *= -1; } level *= static_cast(2); window *= static_cast(2); // store new display coordinates m_LastDisplayCoordinate = m_CurrentDisplayCoordinate; m_CurrentDisplayCoordinate = positionEvent->GetPointerPositionOnScreen(); // propagate set level window event with the level and window delta InvokeEvent(DisplaySetLevelWindowEvent(interactionEvent, level, window)); } void mitk::DisplayActionEventBroadcast::StartRotation(StateMachineAction* /*stateMachineAction*/, InteractionEvent* /*interactionEvent*/) { SetMouseCursor(rotate_cursor_xpm, 0, 0); } void mitk::DisplayActionEventBroadcast::EndRotation(StateMachineAction* /*stateMachineAction*/, InteractionEvent* /*interactionEvent*/) { ResetMouseCursor(); } void mitk::DisplayActionEventBroadcast::Rotate(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) { const auto* positionEvent = dynamic_cast(interactionEvent); if (nullptr == positionEvent) { return; } Point3D position = positionEvent->GetPositionInWorld(); Vector3D toProjected = m_LastCursorPosition - m_CenterOfRotation; Vector3D toCursor = position - m_CenterOfRotation; // cross product: | A x B | = |A| * |B| * sin(angle) Vector3D axisOfRotation; vnl_vector_fixed vnlDirection = vnl_cross_3d(toCursor.GetVnlVector(), toProjected.GetVnlVector()); axisOfRotation.SetVnlVector(vnlDirection.as_ref()); // scalar product: A * B = |A| * |B| * cos(angle) // tan = sin / cos ScalarType angle = -atan2((double)(axisOfRotation.GetNorm()), (double)(toCursor * toProjected)); angle *= 180.0 / vnl_math::pi; m_LastCursorPosition = position; // create RotationOperation and apply to all SNCs that should be rotated RotationOperation rotationOperation(OpROTATE, m_CenterOfRotation, axisOfRotation, angle); // iterate the OTHER slice navigation controllers for (auto iter = m_SNCsToBeRotated.begin(); iter != m_SNCsToBeRotated.end(); ++iter) { TimeGeometry* timeGeometry = (*iter)->GetCreatedWorldGeometry(); if (nullptr == timeGeometry) { continue; } timeGeometry->ExecuteOperation(&rotationOperation); (*iter)->SendCreatedWorldGeometryUpdate(); } RenderingManager::GetInstance()->RequestUpdateAll(); } void mitk::DisplayActionEventBroadcast::Swivel(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) { const auto* positionEvent = dynamic_cast(interactionEvent); if (nullptr == positionEvent) { return; } // Determine relative mouse movement projected onto world space Point2D position = positionEvent->GetPointerPositionOnScreen(); Vector2D relativeCursor = position - m_ReferenceCursor; Vector3D relativeCursorAxis = m_RotationPlaneXVector * relativeCursor[0] + m_RotationPlaneYVector * relativeCursor[1]; // Determine rotation axis (perpendicular to rotation plane and cursor movement) Vector3D rotationAxis = itk::CrossProduct(m_RotationPlaneNormal, relativeCursorAxis); ScalarType rotationAngle = relativeCursor.GetNorm() / 2.0; // Restore the initial plane pose by undoing the previous rotation operation RotationOperation op(OpROTATE, m_CenterOfRotation, m_PreviousRotationAxis, -m_PreviousRotationAngle); SNCVector::iterator iter; for (iter = m_SNCsToBeRotated.begin(); iter != m_SNCsToBeRotated.end(); ++iter) { if (!(*iter)->GetSliceRotationLocked()) { TimeGeometry* timeGeometry = (*iter)->GetCreatedWorldGeometry(); if (nullptr == timeGeometry) { continue; } timeGeometry->ExecuteOperation(&op); (*iter)->SendCreatedWorldGeometryUpdate(); } } // Apply new rotation operation to all relevant SNCs RotationOperation op2(OpROTATE, m_CenterOfRotation, rotationAxis, rotationAngle); for (iter = m_SNCsToBeRotated.begin(); iter != m_SNCsToBeRotated.end(); ++iter) { if (!(*iter)->GetSliceRotationLocked()) { // Retrieve the TimeGeometry of this SliceNavigationController TimeGeometry *timeGeometry = (*iter)->GetCreatedWorldGeometry(); if (nullptr == timeGeometry) { continue; } // Execute the new rotation timeGeometry->ExecuteOperation(&op2); // Notify listeners (*iter)->SendCreatedWorldGeometryUpdate(); } } m_PreviousRotationAxis = rotationAxis; m_PreviousRotationAngle = rotationAngle; RenderingManager::GetInstance()->RequestUpdateAll(); return; } void mitk::DisplayActionEventBroadcast::IncreaseTimeStep(StateMachineAction*, InteractionEvent*) { auto sliceNaviController = RenderingManager::GetInstance()->GetTimeNavigationController(); auto stepper = sliceNaviController->GetTime(); stepper->SetAutoRepeat(true); stepper->Next(); } void mitk::DisplayActionEventBroadcast::DecreaseTimeStep(StateMachineAction*, InteractionEvent*) { auto sliceNaviController = RenderingManager::GetInstance()->GetTimeNavigationController(); auto stepper = sliceNaviController->GetTime(); stepper->SetAutoRepeat(true); stepper->Previous(); } bool mitk::DisplayActionEventBroadcast::GetBoolProperty(PropertyList::Pointer propertyList, const char* propertyName, bool defaultValue) { std::string valueAsString; if (!propertyList->GetStringProperty(propertyName, valueAsString)) { return defaultValue; } else { if (valueAsString == "true") { return true; } else { return false; } } } diff --git a/Modules/Core/src/Interactions/mitkEventRecorder.cpp b/Modules/Core/src/Interactions/mitkEventRecorder.cpp index 429f00c5bd..43f7c5d130 100644 --- a/Modules/Core/src/Interactions/mitkEventRecorder.cpp +++ b/Modules/Core/src/Interactions/mitkEventRecorder.cpp @@ -1,188 +1,188 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkEventRecorder.h" #include "mitkEventFactory.h" #include "mitkInteractionEvent.h" #include "mitkInteractionEventConst.h" #include "vtkCamera.h" #include "mitkBaseRenderer.h" static void WriteEventXMLHeader(std::ofstream &stream) { stream << mitk::InteractionEventConst::xmlHead() << "\n"; } static void WriteEventXMLConfig(std::ofstream &stream) { // stream << " <" << mitk::InteractionEventConst::xmlTagConfigRoot() << ">\n"; // write renderer config // for all registered 2D renderers write name and viewdirection. auto rendererIterator = mitk::BaseRenderer::baseRendererMap.begin(); auto end = mitk::BaseRenderer::baseRendererMap.end(); for (; rendererIterator != end; ++rendererIterator) { std::string rendererName = (*rendererIterator).second->GetName(); - mitk::SliceNavigationController::ViewDirection viewDirection = + mitk::AnatomicalPlane viewDirection = (*rendererIterator).second->GetSliceNavigationController()->GetDefaultViewDirection(); MapperSlotId mapperID = (*rendererIterator).second->GetMapperID(); // stream << " <" << mitk::InteractionEventConst::xmlTagRenderer() << " " << mitk::InteractionEventConst::xmlEventPropertyRendererName() << "=\"" << rendererName << "\" " - << mitk::InteractionEventConst::xmlEventPropertyViewDirection() << "=\"" << viewDirection << "\" " + << mitk::InteractionEventConst::xmlEventPropertyViewDirection() << "=\"" << static_cast(viewDirection) << "\" " << mitk::InteractionEventConst::xmlEventPropertyMapperID() << "=\"" << mapperID << "\" " << mitk::InteractionEventConst::xmlRenderSizeX() << "=\"" << (*rendererIterator).second->GetSize()[0] << "\" " << mitk::InteractionEventConst::xmlRenderSizeY() << "=\"" << (*rendererIterator).second->GetSize()[1] << "\" " << mitk::InteractionEventConst::xmlRenderSizeZ() << "=\"" << (*rendererIterator).second->GetSize()[2] << "\" "; ; if ((*rendererIterator).second->GetMapperID() == mitk::BaseRenderer::Standard3D) { // For a 3D render window, rotation and zoom settings are determined by the vtkCamera parameters // these are recorded here: stream << mitk::InteractionEventConst::xmlViewUpX() << "=\"" << (*rendererIterator).second->GetVtkRenderer()->GetActiveCamera()->GetViewUp()[0] << "\" " << mitk::InteractionEventConst::xmlViewUpY() << "=\"" << (*rendererIterator).second->GetVtkRenderer()->GetActiveCamera()->GetViewUp()[1] << "\" " << mitk::InteractionEventConst::xmlViewUpZ() << "=\"" << (*rendererIterator).second->GetVtkRenderer()->GetActiveCamera()->GetViewUp()[2] << "\" " << mitk::InteractionEventConst::xmlCameraFocalPointX() << "=\"" << (*rendererIterator).second->GetVtkRenderer()->GetActiveCamera()->GetFocalPoint()[0] << "\" " << mitk::InteractionEventConst::xmlCameraFocalPointY() << "=\"" << (*rendererIterator).second->GetVtkRenderer()->GetActiveCamera()->GetFocalPoint()[1] << "\" " << mitk::InteractionEventConst::xmlCameraFocalPointZ() << "=\"" << (*rendererIterator).second->GetVtkRenderer()->GetActiveCamera()->GetFocalPoint()[2] << "\" " << mitk::InteractionEventConst::xmlCameraPositionX() << "=\"" << (*rendererIterator).second->GetVtkRenderer()->GetActiveCamera()->GetPosition()[0] << "\" " << mitk::InteractionEventConst::xmlCameraPositionY() << "=\"" << (*rendererIterator).second->GetVtkRenderer()->GetActiveCamera()->GetPosition()[1] << "\" " << mitk::InteractionEventConst::xmlCameraPositionZ() << "=\"" << (*rendererIterator).second->GetVtkRenderer()->GetActiveCamera()->GetPosition()[2] << "\" "; } stream << "/>\n"; } // stream << " \n"; } static void WriteEventXMLEventsOpen(std::ofstream &stream) { stream << " <" << mitk::InteractionEventConst::xmlTagEvents() << ">\n"; } static void WriteEventXMLEventsClose(std::ofstream &stream) { stream << " \n"; } static void WriteEventXMLInteractionsOpen(std::ofstream &stream) { stream << "<" << mitk::InteractionEventConst::xmlTagInteractions() << ">\n"; } static void WriteEventXMLInteractionsClose(std::ofstream &stream) { stream << ""; } static void WriteEventXMLClose(std::ofstream &stream) { WriteEventXMLEventsClose(stream); WriteEventXMLInteractionsClose(stream); } mitk::EventRecorder::EventRecorder() : m_Active(false) { } mitk::EventRecorder::~EventRecorder() { if (m_FileStream.is_open()) { m_FileStream.flush(); m_FileStream.close(); } } void mitk::EventRecorder::Notify(mitk::InteractionEvent *interactionEvent, bool /*isHandled*/) { if (m_FileStream.is_open()) m_FileStream << EventFactory::EventToXML(interactionEvent) << "\n"; } void mitk::EventRecorder::SetEventIgnoreList(std::vector list) { m_IgnoreList = list; } void mitk::EventRecorder::StartRecording() { if (m_FileName == "") { MITK_ERROR << "EventRecorder::StartRecording - Filename needs to be set first."; return; } if (m_FileStream.is_open()) { MITK_ERROR << "EventRecorder::StartRecording - Still recording. Stop recording before starting it again."; return; } m_FileStream.open(m_FileName.c_str(), std::ofstream::out); if (!m_FileStream.good()) { MITK_ERROR << "File " << m_FileName << " could not be opened!"; m_FileStream.close(); return; } m_Active = true; // write head and config // // // // // // ... // // WriteEventXMLHeader(m_FileStream); WriteEventXMLInteractionsOpen(m_FileStream); WriteEventXMLConfig(m_FileStream); WriteEventXMLEventsOpen(m_FileStream); } void mitk::EventRecorder::StopRecording() { if (m_FileStream.is_open()) { // write end tag // // WriteEventXMLClose(m_FileStream); m_FileStream.flush(); m_FileStream.close(); m_Active = false; } } diff --git a/Modules/Core/src/Rendering/mitkBaseRendererHelper.cpp b/Modules/Core/src/Rendering/mitkBaseRendererHelper.cpp index 00f7396b25..2bd9efb531 100644 --- a/Modules/Core/src/Rendering/mitkBaseRendererHelper.cpp +++ b/Modules/Core/src/Rendering/mitkBaseRendererHelper.cpp @@ -1,77 +1,77 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkBaseRendererHelper.h" #include bool mitk::BaseRendererHelper::IsRendererAlignedWithSegmentation(BaseRenderer* renderer, const TimeGeometry* timeGeometry) { const BaseGeometry* renderWindowGeometry = renderer->GetCurrentWorldGeometry(); if (nullptr == renderWindowGeometry || nullptr == timeGeometry) { return false; } auto viewDirection = renderer->GetSliceNavigationController()->GetViewDirection(); TimeGeometry::Pointer orientedTimeGeometry; try { switch (viewDirection) { - case mitk::SliceNavigationController::Original: + case mitk::AnatomicalPlane::Original: break; - case mitk::SliceNavigationController::Axial: + case mitk::AnatomicalPlane::Axial: { orientedTimeGeometry = SliceNavigationHelper::CreateOrientedTimeGeometry( - timeGeometry, PlaneGeometry::Axial, false, false, true); + timeGeometry, viewDirection, false, false, true); break; } - case mitk::SliceNavigationController::Coronal: + case mitk::AnatomicalPlane::Coronal: { orientedTimeGeometry = SliceNavigationHelper::CreateOrientedTimeGeometry( - timeGeometry, PlaneGeometry::Coronal, false, true, false); + timeGeometry, viewDirection, false, true, false); break; } - case mitk::SliceNavigationController::Sagittal: + case mitk::AnatomicalPlane::Sagittal: { orientedTimeGeometry = SliceNavigationHelper::CreateOrientedTimeGeometry( - timeGeometry, PlaneGeometry::Sagittal, true, true, false); + timeGeometry, viewDirection, true, true, false); break; } } } catch (mitk::Exception& e) { mitkReThrow(e); } if (nullptr == orientedTimeGeometry) { return false; } auto selectedTimePoint = RenderingManager::GetInstance()->GetTimeNavigationController()->GetSelectedTimePoint(); const BaseGeometry* workingImageBaseGeometry = orientedTimeGeometry->GetGeometryForTimePoint(selectedTimePoint); if (nullptr == workingImageBaseGeometry) { // time point not valid for the time geometry mitkThrow() << "Cannot extract a base geometry. A time point is selected that is not covered by" << "the given time geometry. Selected time point: " << selectedTimePoint; } bool geometryIsEqual = Equal(*workingImageBaseGeometry->GetBoundingBox(), *renderWindowGeometry->GetBoundingBox(), eps, true); return geometryIsEqual; } diff --git a/Modules/Core/test/mitkExtractSliceFilterTest.cpp b/Modules/Core/test/mitkExtractSliceFilterTest.cpp index 3dc6ef8139..96916a6240 100644 --- a/Modules/Core/test/mitkExtractSliceFilterTest.cpp +++ b/Modules/Core/test/mitkExtractSliceFilterTest.cpp @@ -1,1069 +1,1069 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // use this to create the test volume on the fly #define CREATE_VOLUME // use this to save the created volume //#define SAVE_VOLUME // use this to calculate the error from the sphere mathematical model to our pixel based one //#define CALC_TESTFAILURE_DEVIATION // use this to render an oblique slice through a specified image //#define SHOW_SLICE_IN_RENDER_WINDOW // use this to have infos printed in mbilog //#define EXTRACTOR_DEBUG /*these are the deviations calculated by the function CalcTestFailureDeviation (see for details)*/ #define Testfailure_Deviation_Mean_128 0.853842 #define Testfailure_Deviation_Volume_128 0.145184 #define Testfailure_Deviation_Diameter_128 1.5625 #define Testfailure_Deviation_Mean_256 0.397693 #define Testfailure_Deviation_Volume_256 0.0141357 #define Testfailure_Deviation_Diameter_256 0.78125 #define Testfailure_Deviation_Mean_512 0.205277 #define Testfailure_Deviation_Volume_512 0.01993 #define Testfailure_Deviation_Diameter_512 0.390625 class mitkExtractSliceFilterTestClass { public: static void TestSlice(mitk::PlaneGeometry *planeGeometry, std::string testname) { TestPlane = planeGeometry; TestName = testname; mitk::ScalarType centerCoordValue = TestvolumeSize / 2.0; mitk::ScalarType center[3] = {centerCoordValue, centerCoordValue, centerCoordValue}; mitk::Point3D centerIndex(center); double radius = TestvolumeSize / 4.0; if (TestPlane->Distance(centerIndex) >= radius) return; // outside sphere // feed ExtractSliceFilter mitk::ExtractSliceFilter::Pointer slicer = mitk::ExtractSliceFilter::New(); slicer->SetInput(TestVolume); slicer->SetWorldGeometry(TestPlane); slicer->Update(); MITK_TEST_CONDITION_REQUIRED(slicer->GetOutput() != nullptr, "Extractor returned a slice"); mitk::Image::Pointer reslicedImage = slicer->GetOutput(); AccessFixedDimensionByItk(reslicedImage, TestSphereRadiusByItk, 2); AccessFixedDimensionByItk(reslicedImage, TestSphereAreaByItk, 2); /* double devArea, devDiameter; if(TestvolumeSize == 128.0){ devArea = Testfailure_Deviation_Volume_128; devDiameter = Testfailure_Deviation_Diameter_128; } else if(TestvolumeSize == 256.0){devArea = Testfailure_Deviation_Volume_256; devDiameter = Testfailure_Deviation_Diameter_256;} else if (TestvolumeSize == 512.0){devArea = Testfailure_Deviation_Volume_512; devDiameter = Testfailure_Deviation_Diameter_512;} else{devArea = Testfailure_Deviation_Volume_128; devDiameter = Testfailure_Deviation_Diameter_128;} */ std::string areatestName = TestName.append(" area"); std::string diametertestName = TestName.append(" testing diameter"); // TODO think about the deviation, 1% makes no sense at all MITK_TEST_CONDITION(std::abs(100 - testResults.percentageAreaCalcToPixel) < 1, areatestName); MITK_TEST_CONDITION(std::abs(100 - testResults.percentageRadiusToPixel) < 1, diametertestName); #ifdef EXTRACTOR_DEBUG MITK_INFO << TestName << " >>> " << "planeDistanceToSphereCenter: " << testResults.planeDistanceToSphereCenter; MITK_INFO << "area in pixels: " << testResults.areaInPixel << " <-> area in mm: " << testResults.areaCalculated << " = " << testResults.percentageAreaCalcToPixel << "%"; MITK_INFO << "calculated diameter: " << testResults.diameterCalculated << " <-> diameter in mm: " << testResults.diameterInMM << " <-> diameter in pixel: " << testResults.diameterInPixel << " = " << testResults.percentageRadiusToPixel << "%"; #endif } /* * get the radius of the slice of a sphere based on pixel distance from edge to edge of the circle. */ template static void TestSphereRadiusByItk(itk::Image *inputImage) { typedef itk::Image InputImageType; // set the index to the middle of the image's edge at x and y axis typename InputImageType::IndexType currentIndexX; currentIndexX[0] = (int)(TestvolumeSize / 2.0); currentIndexX[1] = 0; typename InputImageType::IndexType currentIndexY; currentIndexY[0] = 0; currentIndexY[1] = (int)(TestvolumeSize / 2.0); // remember the last pixel value double lastValueX = inputImage->GetPixel(currentIndexX); double lastValueY = inputImage->GetPixel(currentIndexY); // storage for the index marks std::vector indicesX; std::vector indicesY; /*Get four indices on the edge of the circle*/ while (currentIndexX[1] < TestvolumeSize && currentIndexX[0] < TestvolumeSize) { // move x direction currentIndexX[1] += 1; // move y direction currentIndexY[0] += 1; if (inputImage->GetPixel(currentIndexX) > lastValueX) { // mark the current index typename InputImageType::IndexType markIndex; markIndex[0] = currentIndexX[0]; markIndex[1] = currentIndexX[1]; indicesX.push_back(markIndex); } else if (inputImage->GetPixel(currentIndexX) < lastValueX) { // mark the current index typename InputImageType::IndexType markIndex; markIndex[0] = currentIndexX[0]; markIndex[1] = currentIndexX[1] - 1; // value inside the sphere indicesX.push_back(markIndex); } if (inputImage->GetPixel(currentIndexY) > lastValueY) { // mark the current index typename InputImageType::IndexType markIndex; markIndex[0] = currentIndexY[0]; markIndex[1] = currentIndexY[1]; indicesY.push_back(markIndex); } else if (inputImage->GetPixel(currentIndexY) < lastValueY) { // mark the current index typename InputImageType::IndexType markIndex; markIndex[0] = currentIndexY[0]; markIndex[1] = currentIndexY[1] - 1; // value inside the sphere indicesY.push_back(markIndex); } // found both marks? if (indicesX.size() == 2 && indicesY.size() == 2) break; // the new 'last' values lastValueX = inputImage->GetPixel(currentIndexX); lastValueY = inputImage->GetPixel(currentIndexY); } /* *If we are here we found the four marks on the edge of the circle. *For the case our plane is rotated and shifted, we have to calculate the center of the circle, *else the center is the intersection of both straight lines between the marks. *When we have the center, the diameter of the circle will be checked to the reference value(math!). */ // each distance from the first mark of each direction to the center of the straight line between the marks double distanceToCenterX = std::abs(indicesX[0][1] - indicesX[1][1]) / 2.0; // double distanceToCenterY = std::abs(indicesY[0][0] - indicesY[1][0]) / 2.0; // the center of the straight lines typename InputImageType::IndexType centerX; // typename InputImageType::IndexType centerY; centerX[0] = indicesX[0][0]; centerX[1] = indicesX[0][1] + distanceToCenterX; // TODO think about implicit cast to int. this is not the real center of the image, which could be between two // pixels // centerY[0] = indicesY[0][0] + distanceToCenterY; // centerY[1] = inidcesY[0][1]; typename InputImageType::IndexType currentIndex(centerX); lastValueX = inputImage->GetPixel(currentIndex); long sumpixels = 0; std::vector diameterIndices; // move up while (currentIndex[1] < TestvolumeSize) { currentIndex[1] += 1; if (inputImage->GetPixel(currentIndex) != lastValueX) { typename InputImageType::IndexType markIndex; markIndex[0] = currentIndex[0]; markIndex[1] = currentIndex[1] - 1; diameterIndices.push_back(markIndex); break; } sumpixels++; lastValueX = inputImage->GetPixel(currentIndex); } currentIndex[1] -= sumpixels; // move back to center to go in the other direction lastValueX = inputImage->GetPixel(currentIndex); // move down while (currentIndex[1] >= 0) { currentIndex[1] -= 1; if (inputImage->GetPixel(currentIndex) != lastValueX) { typename InputImageType::IndexType markIndex; markIndex[0] = currentIndex[0]; markIndex[1] = currentIndex[1]; // outside sphere because we want to calculate the distance from edge to edge diameterIndices.push_back(markIndex); break; } sumpixels++; lastValueX = inputImage->GetPixel(currentIndex); } /* *Now sumpixels should be the apromximate diameter of the circle. This is checked with the calculated diameter from *the plane transformation(math). */ mitk::Point3D volumeCenter; volumeCenter[0] = volumeCenter[1] = volumeCenter[2] = TestvolumeSize / 2.0; double planeDistanceToSphereCenter = TestPlane->Distance(volumeCenter); double sphereRadius = TestvolumeSize / 4.0; // calculate the radius of the circle cut from the sphere by the plane double diameter = 2.0 * std::sqrt(std::pow(sphereRadius, 2) - std::pow(planeDistanceToSphereCenter, 2)); double percentageRadiusToPixel = 100 / diameter * sumpixels; /* *calculate the radius in mm by the both marks of the center line by using the world coordinates */ // get the points as 3D coordinates mitk::Vector3D diameterPointRight, diameterPointLeft; diameterPointRight[2] = diameterPointLeft[2] = 0.0; diameterPointLeft[0] = diameterIndices[0][0]; diameterPointLeft[1] = diameterIndices[0][1]; diameterPointRight[0] = diameterIndices[1][0]; diameterPointRight[1] = diameterIndices[1][1]; // transform to worldcoordinates TestVolume->GetGeometry()->IndexToWorld(diameterPointLeft, diameterPointLeft); TestVolume->GetGeometry()->IndexToWorld(diameterPointRight, diameterPointRight); // euklidian distance double diameterInMM = ((diameterPointLeft * -1.0) + diameterPointRight).GetNorm(); testResults.diameterInMM = diameterInMM; testResults.diameterCalculated = diameter; testResults.diameterInPixel = sumpixels; testResults.percentageRadiusToPixel = percentageRadiusToPixel; testResults.planeDistanceToSphereCenter = planeDistanceToSphereCenter; } /*brute force the area pixel by pixel*/ template static void TestSphereAreaByItk(itk::Image *inputImage) { typedef itk::Image InputImageType; typedef itk::ImageRegionConstIterator ImageIterator; ImageIterator imageIterator(inputImage, inputImage->GetLargestPossibleRegion()); imageIterator.GoToBegin(); int sumPixelsInArea = 0; while (!imageIterator.IsAtEnd()) { if (inputImage->GetPixel(imageIterator.GetIndex()) == pixelValueSet) sumPixelsInArea++; ++imageIterator; } mitk::Point3D volumeCenter; volumeCenter[0] = volumeCenter[1] = volumeCenter[2] = TestvolumeSize / 2.0; double planeDistanceToSphereCenter = TestPlane->Distance(volumeCenter); double sphereRadius = TestvolumeSize / 4.0; // calculate the radius of the circle cut from the sphere by the plane double radius = std::sqrt(std::pow(sphereRadius, 2) - std::pow(planeDistanceToSphereCenter, 2)); double areaInMM = 3.14159265358979 * std::pow(radius, 2); testResults.areaCalculated = areaInMM; testResults.areaInPixel = sumPixelsInArea; testResults.percentageAreaCalcToPixel = 100 / areaInMM * sumPixelsInArea; } /* * random a voxel. define plane through this voxel. reslice at the plane. compare the pixel vaues of the voxel * in the volume with the pixel value in the resliced image. * there are some indice shifting problems which causes the test to fail for oblique planes. seems like the chosen * worldcoordinate is not corresponding to the index in the 2D image. and so the pixel values are not the same as * expected. */ static void PixelvalueBasedTest() { /* setup itk image */ typedef itk::Image ImageType; typedef itk::ImageRegionConstIterator ImageIterator; ImageType::Pointer image = ImageType::New(); ImageType::IndexType start; start[0] = start[1] = start[2] = 0; ImageType::SizeType size; size[0] = size[1] = size[2] = 32; ImageType::RegionType imgRegion; imgRegion.SetSize(size); imgRegion.SetIndex(start); image->SetRegions(imgRegion); image->SetSpacing(1.0); image->Allocate(); ImageIterator imageIterator(image, image->GetLargestPossibleRegion()); imageIterator.GoToBegin(); unsigned short pixelValue = 0; // fill the image with distinct values while (!imageIterator.IsAtEnd()) { image->SetPixel(imageIterator.GetIndex(), pixelValue); ++imageIterator; ++pixelValue; } /* end setup itk image */ mitk::Image::Pointer imageInMitk; CastToMitkImage(image, imageInMitk); /*mitk::ImageWriter::Pointer writer = mitk::ImageWriter::New(); writer->SetInput(imageInMitk); std::string file = "C:\\Users\\schroedt\\Desktop\\cube.nrrd"; writer->SetFileName(file); writer->Update();*/ - PixelvalueBasedTestByPlane(imageInMitk, mitk::PlaneGeometry::Coronal); - PixelvalueBasedTestByPlane(imageInMitk, mitk::PlaneGeometry::Sagittal); - PixelvalueBasedTestByPlane(imageInMitk, mitk::PlaneGeometry::Axial); + PixelvalueBasedTestByPlane(imageInMitk, mitk::AnatomicalPlane::Coronal); + PixelvalueBasedTestByPlane(imageInMitk, mitk::AnatomicalPlane::Sagittal); + PixelvalueBasedTestByPlane(imageInMitk, mitk::AnatomicalPlane::Axial); } - static void PixelvalueBasedTestByPlane(mitk::Image *imageInMitk, mitk::PlaneGeometry::PlaneOrientation orientation) + static void PixelvalueBasedTestByPlane(mitk::Image *imageInMitk, mitk::AnatomicalPlane orientation) { typedef itk::Image ImageType; // set the seed of the rand function srand((unsigned)time(nullptr)); /* setup a random orthogonal plane */ int sliceindex = 17; // rand() % 32; bool isFrontside = true; bool isRotated = false; - if (orientation == mitk::PlaneGeometry::Axial) + if (orientation == mitk::AnatomicalPlane::Axial) { /*isFrontside = false; isRotated = true;*/ } mitk::PlaneGeometry::Pointer plane = mitk::PlaneGeometry::New(); plane->InitializeStandardPlane(imageInMitk->GetGeometry(), orientation, sliceindex, isFrontside, isRotated); mitk::Point3D origin = plane->GetOrigin(); mitk::Vector3D normal; normal = plane->GetNormal(); normal.Normalize(); origin += normal * 0.5; // pixelspacing is 1, so half the spacing is 0.5 plane->SetOrigin(origin); // we dont need this any more, because we are only testing orthogonal planes /*mitk::Vector3D rotationVector; rotationVector[0] = randFloat(); rotationVector[1] = randFloat(); rotationVector[2] = randFloat(); float degree = randFloat() * 180.0; mitk::RotationOperation* op = new mitk::RotationOperation(mitk::OpROTATE, plane->GetCenter(), rotationVector, degree); plane->ExecuteOperation(op); delete op;*/ /* end setup plane */ /* define a point in the 3D volume. * add the two axis vectors of the plane (each multiplied with a * random number) to the origin. now the two random numbers * become our index coordinates in the 2D image, because the * length of the axis vectors is 1. */ mitk::Point3D planeOrigin = plane->GetOrigin(); mitk::Vector3D axis0, axis1; axis0 = plane->GetAxisVector(0); axis1 = plane->GetAxisVector(1); axis0.Normalize(); axis1.Normalize(); unsigned char n1 = 7; // rand() % 32; unsigned char n2 = 13; // rand() % 32; mitk::Point3D testPoint3DInWorld; testPoint3DInWorld = planeOrigin + (axis0 * n1) + (axis1 * n2); // get the index of the point in the 3D volume ImageType::IndexType testPoint3DInIndex; imageInMitk->GetGeometry()->WorldToIndex(testPoint3DInWorld, testPoint3DInIndex); itk::Index<3> testPoint2DInIndex; /* end define a point in the 3D volume.*/ // do reslicing at the plane mitk::ExtractSliceFilter::Pointer slicer = mitk::ExtractSliceFilter::New(); slicer->SetInput(imageInMitk); slicer->SetWorldGeometry(plane); slicer->Update(); mitk::Image::Pointer slice = slicer->GetOutput(); // Get TestPoiont3D as Index in Slice slice->GetGeometry()->WorldToIndex(testPoint3DInWorld, testPoint2DInIndex); mitk::Point3D p, sliceIndexToWorld, imageIndexToWorld; p[0] = testPoint2DInIndex[0]; p[1] = testPoint2DInIndex[1]; p[2] = testPoint2DInIndex[2]; slice->GetGeometry()->IndexToWorld(p, sliceIndexToWorld); p[0] = testPoint3DInIndex[0]; p[1] = testPoint3DInIndex[1]; p[2] = testPoint3DInIndex[2]; imageInMitk->GetGeometry()->IndexToWorld(p, imageIndexToWorld); itk::Index<2> testPoint2DIn2DIndex; testPoint2DIn2DIndex[0] = testPoint2DInIndex[0]; testPoint2DIn2DIndex[1] = testPoint2DInIndex[1]; typedef mitk::ImagePixelReadAccessor VolumeReadAccessorType; typedef mitk::ImagePixelReadAccessor SliceReadAccessorType; VolumeReadAccessorType VolumeReadAccessor(imageInMitk); SliceReadAccessorType SliceReadAccessor(slice); // compare the pixelvalues of the defined point in the 3D volume with the value of the resliced image unsigned short valueAt3DVolume = VolumeReadAccessor.GetPixelByIndex(testPoint3DInIndex); unsigned short valueAtSlice = SliceReadAccessor.GetPixelByIndex(testPoint2DIn2DIndex); // valueAt3DVolume == valueAtSlice is not always working. because of rounding errors // indices are shifted MITK_TEST_CONDITION(valueAt3DVolume == valueAtSlice, "comparing pixelvalues for orthogonal plane"); vtkSmartPointer imageInVtk = imageInMitk->GetVtkImageData(); vtkSmartPointer sliceInVtk = slice->GetVtkImageData(); double PixelvalueByMitkOutput = sliceInVtk->GetScalarComponentAsDouble(n1, n2, 0, 0); // double valueVTKinImage = imageInVtk->GetScalarComponentAsDouble(testPoint3DInIndex[0], testPoint3DInIndex[1], // testPoint3DInIndex[2], 0); /* Test that everything is working equally if vtkoutput is used instead of the default output * from mitk ImageToImageFilter */ mitk::ExtractSliceFilter::Pointer slicerWithVtkOutput = mitk::ExtractSliceFilter::New(); slicerWithVtkOutput->SetInput(imageInMitk); slicerWithVtkOutput->SetWorldGeometry(plane); slicerWithVtkOutput->SetVtkOutputRequest(true); slicerWithVtkOutput->Update(); vtkSmartPointer vtkImageByVtkOutput = slicerWithVtkOutput->GetVtkOutput(); double PixelvalueByVtkOutput = vtkImageByVtkOutput->GetScalarComponentAsDouble(n1, n2, 0, 0); MITK_TEST_CONDITION(PixelvalueByMitkOutput == PixelvalueByVtkOutput, "testing conversion of image output vtk->mitk by reslicer"); /*================ mbilog outputs ===========================*/ #ifdef EXTRACTOR_DEBUG MITK_INFO << "\n" << "TESTINFO index: " << sliceindex << " orientation: " << orientation << " frontside: " << isFrontside << " rotated: " << isRotated; MITK_INFO << "\n" << "slice index to world: " << sliceIndexToWorld; MITK_INFO << "\n" << "image index to world: " << imageIndexToWorld; MITK_INFO << "\n" << "vtk: slice: " << PixelvalueByMitkOutput << ", image: " << valueVTKinImage; MITK_INFO << "\n" << "testPoint3D InWorld" << testPoint3DInWorld << " is " << testPoint2DInIndex << " in 2D"; MITK_INFO << "\n" << "randoms: " << ((int)n1) << ", " << ((int)n2); MITK_INFO << "\n" << "point is inside plane: " << plane->IsInside(testPoint3DInWorld) << " and volume: " << imageInMitk->GetGeometry()->IsInside(testPoint3DInWorld); MITK_INFO << "\n" << "volume idx: " << testPoint3DInIndex << " = " << valueAt3DVolume; MITK_INFO << "\n" << "volume world: " << testPoint3DInWorld << " = " << valueAt3DVolumeByWorld; MITK_INFO << "\n" << "slice idx: " << testPoint2DInIndex << " = " << valueAtSlice; itk::Index<3> curr; curr[0] = curr[1] = curr[2] = 0; for (int i = 0; i < 32; ++i) { for (int j = 0; j < 32; ++j) { ++curr[1]; if (SliceReadAccessor.GetPixelByIndex(curr) == valueAt3DVolume) { MITK_INFO << "\n" << valueAt3DVolume << " MATCHED mitk " << curr; } } curr[1] = 0; ++curr[0]; } typedef itk::Image Image2DType; Image2DType::Pointer img = Image2DType::New(); CastToItkImage(slice, img); typedef itk::ImageRegionConstIterator Iterator2D; Iterator2D iter(img, img->GetLargestPossibleRegion()); iter.GoToBegin(); while (!iter.IsAtEnd()) { if (img->GetPixel(iter.GetIndex()) == valueAt3DVolume) MITK_INFO << "\n" << valueAt3DVolume << " MATCHED itk " << iter.GetIndex(); ++iter; } #endif // EXTRACTOR_DEBUG } /* random a float value */ static float randFloat() { return (((float)rand() + 1.0) / ((float)RAND_MAX + 1.0)) + (((float)rand() + 1.0) / ((float)RAND_MAX + 1.0)) / ((float)RAND_MAX + 1.0); } /* create a sphere with the size of the given testVolumeSize*/ static void InitializeTestVolume() { #ifdef CREATE_VOLUME // do sphere creation ItkVolumeGeneration(); #ifdef SAVE_VOLUME // save in file mitk::ImageWriter::Pointer writer = mitk::ImageWriter::New(); writer->SetInput(TestVolume); std::string file; std::ostringstream filename; filename << "C:\\home\\schroedt\\MITK\\Modules\\ImageExtraction\\Testing\\Data\\sphere_"; filename << TestvolumeSize; filename << ".nrrd"; file = filename.str(); writer->SetFileName(file); writer->Update(); #endif // SAVE_VOLUME #endif #ifndef CREATE_VOLUME // read from file mitk::StandardFileLocations::Pointer locator = mitk::StandardFileLocations::GetInstance(); std::string filename = locator->FindFile("sphere_512.nrrd.mhd", "Modules/ImageExtraction/Testing/Data"); TestVolume = mitk::IOUtil::Load(filename); #endif #ifdef CALC_TESTFAILURE_DEVIATION // get the TestFailureDeviation in % AccessFixedDimensionByItk(TestVolume, CalcTestFailureDeviation, 3); #endif } // the test result of the sphere reslice struct SliceProperties { double planeDistanceToSphereCenter; double diameterInMM; double diameterInPixel; double diameterCalculated; double percentageRadiusToPixel; double areaCalculated; double areaInPixel; double percentageAreaCalcToPixel; }; static mitk::Image::Pointer TestVolume; static double TestvolumeSize; static mitk::PlaneGeometry::Pointer TestPlane; static std::string TestName; static unsigned char pixelValueSet; static SliceProperties testResults; static double TestFailureDeviation; private: /* * Generate a sphere with a radius of TestvolumeSize / 4.0 */ static void ItkVolumeGeneration() { typedef itk::Image TestVolumeType; typedef itk::ImageRegionConstIterator ImageIterator; TestVolumeType::Pointer sphereImage = TestVolumeType::New(); TestVolumeType::IndexType start; start[0] = start[1] = start[2] = 0; TestVolumeType::SizeType size; size[0] = size[1] = size[2] = TestvolumeSize; TestVolumeType::RegionType imgRegion; imgRegion.SetSize(size); imgRegion.SetIndex(start); sphereImage->SetRegions(imgRegion); sphereImage->SetSpacing(1.0); sphereImage->Allocate(); sphereImage->FillBuffer(0); mitk::Vector3D center; center[0] = center[1] = center[2] = TestvolumeSize / 2.0; double radius = TestvolumeSize / 4.0; double pixelValue = pixelValueSet; ImageIterator imageIterator(sphereImage, sphereImage->GetLargestPossibleRegion()); imageIterator.GoToBegin(); mitk::Vector3D currentVoxelInIndex; while (!imageIterator.IsAtEnd()) { currentVoxelInIndex[0] = imageIterator.GetIndex()[0]; currentVoxelInIndex[1] = imageIterator.GetIndex()[1]; currentVoxelInIndex[2] = imageIterator.GetIndex()[2]; double distanceToCenter = (center + (currentVoxelInIndex * -1.0)).GetNorm(); // if distance to center is smaller then the radius of the sphere if (distanceToCenter < radius) { sphereImage->SetPixel(imageIterator.GetIndex(), pixelValue); } ++imageIterator; } CastToMitkImage(sphereImage, TestVolume); } /* calculate the deviation of the voxel object to the mathematical sphere object. * this is use to make a statement about the accuracy of the resliced image, eg. the circle's diameter or area. */ template static void CalcTestFailureDeviation(itk::Image *inputImage) { typedef itk::Image InputImageType; typedef itk::ImageRegionConstIterator ImageIterator; ImageIterator iterator(inputImage, inputImage->GetLargestPossibleRegion()); iterator.GoToBegin(); int volumeInPixel = 0; while (!iterator.IsAtEnd()) { if (inputImage->GetPixel(iterator.GetIndex()) == pixelValueSet) volumeInPixel++; ++iterator; } double diameter = TestvolumeSize / 2.0; double volumeCalculated = (1.0 / 6.0) * 3.14159265358979 * std::pow(diameter, 3); double volumeDeviation = std::abs(100 - (100 / volumeCalculated * volumeInPixel)); typename InputImageType::IndexType index; index[0] = index[1] = TestvolumeSize / 2.0; index[2] = 0; int sumpixels = 0; while (index[2] < TestvolumeSize) { if (inputImage->GetPixel(index) == pixelValueSet) sumpixels++; index[2] += 1; } double diameterDeviation = std::abs(100 - (100 / diameter * sumpixels)); #ifdef DEBUG MITK_INFO << "volume deviation: " << volumeDeviation << " diameter deviation:" << diameterDeviation; #endif mitkExtractSliceFilterTestClass::TestFailureDeviation = (volumeDeviation + diameterDeviation) / 2.0; } }; /*================ #END class ================*/ /*================#BEGIN Instantiation of members ================*/ mitk::Image::Pointer mitkExtractSliceFilterTestClass::TestVolume = mitk::Image::New(); double mitkExtractSliceFilterTestClass::TestvolumeSize = 256.0; mitk::PlaneGeometry::Pointer mitkExtractSliceFilterTestClass::TestPlane = mitk::PlaneGeometry::New(); std::string mitkExtractSliceFilterTestClass::TestName = ""; unsigned char mitkExtractSliceFilterTestClass::pixelValueSet = 255; mitkExtractSliceFilterTestClass::SliceProperties mitkExtractSliceFilterTestClass::testResults = { -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0}; double mitkExtractSliceFilterTestClass::TestFailureDeviation = 0.0; /*================ #END Instantiation of members ================*/ /*================ #BEGIN test main ================*/ int mitkExtractSliceFilterTest(int /*argc*/, char * /*argv*/ []) { MITK_TEST_BEGIN("mitkExtractSliceFilterTest") // pixelvalue based testing mitkExtractSliceFilterTestClass::PixelvalueBasedTest(); // initialize sphere test volume mitkExtractSliceFilterTestClass::InitializeTestVolume(); mitk::Vector3D spacing = mitkExtractSliceFilterTestClass::TestVolume->GetGeometry()->GetSpacing(); // the center of the sphere = center of image double sphereCenter = mitkExtractSliceFilterTestClass::TestvolumeSize / 2.0; double planeSize = mitkExtractSliceFilterTestClass::TestvolumeSize; /* axial plane */ mitk::PlaneGeometry::Pointer geometryAxial = mitk::PlaneGeometry::New(); geometryAxial->InitializeStandardPlane( - planeSize, planeSize, spacing, mitk::PlaneGeometry::Axial, sphereCenter, false, true); + planeSize, planeSize, spacing, mitk::AnatomicalPlane::Axial, sphereCenter, false, true); geometryAxial->ChangeImageGeometryConsideringOriginOffset(true); mitk::Point3D origin = geometryAxial->GetOrigin(); mitk::Vector3D normal; normal = geometryAxial->GetNormal(); normal.Normalize(); origin += normal * 0.5; // pixelspacing is 1, so half the spacing is 0.5 // geometryAxial->SetOrigin(origin); mitkExtractSliceFilterTestClass::TestSlice(geometryAxial, "Testing axial plane"); /* end axial plane */ /* sagittal plane */ mitk::PlaneGeometry::Pointer geometrySagittal = mitk::PlaneGeometry::New(); geometrySagittal->InitializeStandardPlane( - planeSize, planeSize, spacing, mitk::PlaneGeometry::Sagittal, sphereCenter, true, false); + planeSize, planeSize, spacing, mitk::AnatomicalPlane::Sagittal, sphereCenter, true, false); geometrySagittal->ChangeImageGeometryConsideringOriginOffset(true); origin = geometrySagittal->GetOrigin(); normal = geometrySagittal->GetNormal(); normal.Normalize(); origin += normal * 0.5; // pixelspacing is 1, so half the spacing is 0.5 // geometrySagittal->SetOrigin(origin); mitkExtractSliceFilterTestClass::TestSlice(geometrySagittal, "Testing sagittal plane"); /* sagittal plane */ /* sagittal shifted plane */ mitk::PlaneGeometry::Pointer geometrySagittalShifted = mitk::PlaneGeometry::New(); geometrySagittalShifted->InitializeStandardPlane( - planeSize, planeSize, spacing, mitk::PlaneGeometry::Sagittal, (sphereCenter - 14), true, false); + planeSize, planeSize, spacing, mitk::AnatomicalPlane::Sagittal, (sphereCenter - 14), true, false); geometrySagittalShifted->ChangeImageGeometryConsideringOriginOffset(true); origin = geometrySagittalShifted->GetOrigin(); normal = geometrySagittalShifted->GetNormal(); normal.Normalize(); origin += normal * 0.5; // pixelspacing is 1, so half the spacing is 0.5 // geometrySagittalShifted->SetOrigin(origin); mitkExtractSliceFilterTestClass::TestSlice(geometrySagittalShifted, "Testing sagittal plane shifted"); /* end sagittal shifted plane */ /* coronal plane */ mitk::PlaneGeometry::Pointer geometryCoronal = mitk::PlaneGeometry::New(); geometryCoronal->InitializeStandardPlane( - planeSize, planeSize, spacing, mitk::PlaneGeometry::Coronal, sphereCenter, true, false); + planeSize, planeSize, spacing, mitk::AnatomicalPlane::Coronal, sphereCenter, true, false); geometryCoronal->ChangeImageGeometryConsideringOriginOffset(true); origin = geometryCoronal->GetOrigin(); normal = geometryCoronal->GetNormal(); normal.Normalize(); origin += normal * 0.5; // pixelspacing is 1, so half the spacing is 0.5 // geometryCoronal->SetOrigin(origin); mitkExtractSliceFilterTestClass::TestSlice(geometryCoronal, "Testing coronal plane"); /* end coronal plane */ /* oblique plane */ mitk::PlaneGeometry::Pointer obliquePlane = mitk::PlaneGeometry::New(); obliquePlane->InitializeStandardPlane( - planeSize, planeSize, spacing, mitk::PlaneGeometry::Sagittal, sphereCenter, true, false); + planeSize, planeSize, spacing, mitk::AnatomicalPlane::Sagittal, sphereCenter, true, false); obliquePlane->ChangeImageGeometryConsideringOriginOffset(true); origin = obliquePlane->GetOrigin(); normal = obliquePlane->GetNormal(); normal.Normalize(); origin += normal * 0.5; // pixelspacing is 1, so half the spacing is 0.5 // obliquePlane->SetOrigin(origin); mitk::Vector3D rotationVector; rotationVector[0] = 0.2; rotationVector[1] = 0.4; rotationVector[2] = 0.62; float degree = 37.0; mitk::RotationOperation *op = new mitk::RotationOperation(mitk::OpROTATE, obliquePlane->GetCenter(), rotationVector, degree); obliquePlane->ExecuteOperation(op); delete op; mitkExtractSliceFilterTestClass::TestSlice(obliquePlane, "Testing oblique plane"); /* end oblique plane */ #ifdef SHOW_SLICE_IN_RENDER_WINDOW /*================ #BEGIN vtk render code ================*/ // set reslicer for renderwindow mitk::Image::Pointer pic = mitk::IOUtil::Load(filename); vtkSmartPointer slicer = vtkSmartPointer::New(); slicer->SetInput(pic->GetVtkImageData()); mitk::PlaneGeometry::Pointer obliquePl = mitk::PlaneGeometry::New(); obliquePl->InitializeStandardPlane( - pic->GetGeometry(), mitk::PlaneGeometry::Sagittal, pic->GetGeometry()->GetCenter()[0], true, false); + pic->GetGeometry(), mitk::AnatomicalPlane::Sagittal, pic->GetGeometry()->GetCenter()[0], true, false); obliquePl->ChangeImageGeometryConsideringOriginOffset(true); mitk::Point3D origin2 = obliquePl->GetOrigin(); mitk::Vector3D n; n = obliquePl->GetNormal(); n.Normalize(); origin2 += n * 0.5; // pixelspacing is 1, so half the spacing is 0.5 obliquePl->SetOrigin(origin2); mitk::Vector3D rotation; rotation[0] = 0.534307; rotation[1] = 0.000439605; rotation[2] = 0.423017; MITK_INFO << rotation; mitk::RotationOperation *operation = new mitk::RotationOperation(mitk::OpROTATE, obliquePl->GetCenter(), rotationVector, degree); obliquePl->ExecuteOperation(operation); delete operation; double origin[3]; origin[0] = obliquePl->GetOrigin()[0]; origin[1] = obliquePl->GetOrigin()[1]; origin[2] = obliquePl->GetOrigin()[2]; slicer->SetResliceAxesOrigin(origin); mitk::Vector3D right, bottom, normal; right = obliquePl->GetAxisVector(0); bottom = obliquePl->GetAxisVector(1); normal = obliquePl->GetNormal(); right.Normalize(); bottom.Normalize(); normal.Normalize(); double cosines[9]; mitk::vnl2vtk(right.GetVnlVector(), cosines); // x mitk::vnl2vtk(bottom.GetVnlVector(), cosines + 3); // y mitk::vnl2vtk(normal.GetVnlVector(), cosines + 6); // n slicer->SetResliceAxesDirectionCosines(cosines); slicer->SetOutputDimensionality(2); slicer->Update(); // set vtk renderwindow vtkSmartPointer vtkPlane = vtkSmartPointer::New(); vtkPlane->SetOrigin(0.0, 0.0, 0.0); // These two points define the axes of the plane in combination with the origin. // Point 1 is the x-axis and point 2 the y-axis. // Each plane is transformed according to the view (axial, coronal and sagittal) afterwards. vtkPlane->SetPoint1(1.0, 0.0, 0.0); // P1: (xMax, yMin, depth) vtkPlane->SetPoint2(0.0, 1.0, 0.0); // P2: (xMin, yMax, depth) // these are not the correct values for all slices, only a square plane by now vtkSmartPointer imageMapper = vtkSmartPointer::New(); imageMapper->SetInputConnection(vtkPlane->GetOutputPort()); vtkSmartPointer lookupTable = vtkSmartPointer::New(); // built a default lookuptable lookupTable->SetRampToLinear(); lookupTable->SetSaturationRange(0.0, 0.0); lookupTable->SetHueRange(0.0, 0.0); lookupTable->SetValueRange(0.0, 1.0); lookupTable->Build(); // map all black values to transparent lookupTable->SetTableValue(0, 0.0, 0.0, 0.0, 0.0); lookupTable->SetRange(-255.0, 255.0); // lookupTable->SetRange(-1022.0, 1184.0);//pic3D range vtkSmartPointer texture = vtkSmartPointer::New(); texture->SetInput(slicer->GetOutput()); texture->SetLookupTable(lookupTable); texture->SetMapColorScalarsThroughLookupTable(true); vtkSmartPointer imageActor = vtkSmartPointer::New(); imageActor->SetMapper(imageMapper); imageActor->SetTexture(texture); // Setup renderers vtkSmartPointer renderer = vtkSmartPointer::New(); renderer->AddActor(imageActor); // Setup render window vtkSmartPointer renderWindow = vtkSmartPointer::New(); renderWindow->AddRenderer(renderer); // Setup render window interactor vtkSmartPointer renderWindowInteractor = vtkSmartPointer::New(); vtkSmartPointer style = vtkSmartPointer::New(); renderWindowInteractor->SetInteractorStyle(style); // Render and start interaction renderWindowInteractor->SetRenderWindow(renderWindow); // renderer->AddViewProp(imageActor); renderWindow->Render(); renderWindowInteractor->Start(); // always end with this! /*================ #END vtk render code ================*/ #endif // SHOW_SLICE_IN_RENDER_WINDOW MITK_TEST_END() } diff --git a/Modules/Core/test/mitkImageVtkMapper2DColorTest.cpp b/Modules/Core/test/mitkImageVtkMapper2DColorTest.cpp index dc33b72adf..8ef2fe1c20 100644 --- a/Modules/Core/test/mitkImageVtkMapper2DColorTest.cpp +++ b/Modules/Core/test/mitkImageVtkMapper2DColorTest.cpp @@ -1,57 +1,57 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // MITK #include "mitkRenderingTestHelper.h" #include "mitkTestingMacros.h" // VTK #include int mitkImageVtkMapper2DColorTest(int argc, char *argv[]) { try { mitk::RenderingTestHelper openGlTest(640, 480); } catch (const mitk::TestNotRunException &e) { MITK_WARN << "Test not run: " << e.GetDescription(); return 77; } // load all arguments into a datastorage, take last argument as reference rendering // setup a renderwindow of fixed size X*Y // render the datastorage // compare rendering to reference image MITK_TEST_BEGIN("mitkImageVtkMapper2DTest") mitk::RenderingTestHelper renderingHelper(640, 480, argc, argv); // Set the opacity for all images renderingHelper.SetImageProperty("color", mitk::ColorProperty::New(0.0f, 0.0f, 1.0f)); // for now this test renders in sagittal view direction - renderingHelper.SetViewDirection(mitk::SliceNavigationController::Sagittal); + renderingHelper.SetViewDirection(mitk::AnatomicalPlane::Sagittal); //### Usage of CompareRenderWindowAgainstReference: See docu of mitkRrenderingTestHelper MITK_TEST_CONDITION(renderingHelper.CompareRenderWindowAgainstReference(argc, argv) == true, "CompareRenderWindowAgainstReference test result positive?"); //#################### // Use this to generate a reference screenshot or save the file. //(Only in your local version of the test!) if (false) { renderingHelper.SaveReferenceScreenShot("/home/kilgus/Pictures/RenderingTestData/output.png"); } //#################### MITK_TEST_END(); } diff --git a/Modules/Core/test/mitkImageVtkMapper2DLevelWindowTest.cpp b/Modules/Core/test/mitkImageVtkMapper2DLevelWindowTest.cpp index 6204bdb49b..e8203d0a84 100644 --- a/Modules/Core/test/mitkImageVtkMapper2DLevelWindowTest.cpp +++ b/Modules/Core/test/mitkImageVtkMapper2DLevelWindowTest.cpp @@ -1,63 +1,63 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // MITK #include "mitkRenderingTestHelper.h" #include "mitkTestingMacros.h" #include #include // VTK #include int mitkImageVtkMapper2DLevelWindowTest(int argc, char *argv[]) { try { mitk::RenderingTestHelper openGlTest(640, 480); } catch (const mitk::TestNotRunException &e) { MITK_WARN << "Test not run: " << e.GetDescription(); return 77; } // load all arguments into a datastorage, take last argument as reference rendering // setup a renderwindow of fixed size X*Y // render the datastorage // compare rendering to reference image MITK_TEST_BEGIN("mitkImageVtkMapper2DTest") mitk::RenderingTestHelper renderingHelper(640, 480, argc, argv); // chose a level window: here we randomly chosen the blood preset. mitk::LevelWindowPreset *levelWindowPreset = mitk::LevelWindowPreset::New(); bool loadedPreset = levelWindowPreset->LoadPreset(); MITK_TEST_CONDITION_REQUIRED(loadedPreset == true, "Testing if level window preset could be loaded"); double level = levelWindowPreset->getLevel("Blood"); double window = levelWindowPreset->getWindow("Blood"); levelWindowPreset->Delete(); // apply level window to all images renderingHelper.SetImageProperty("levelwindow", mitk::LevelWindowProperty::New(mitk::LevelWindow(level, window))); // for now this test renders Sagittal - renderingHelper.SetViewDirection(mitk::SliceNavigationController::Sagittal); + renderingHelper.SetViewDirection(mitk::AnatomicalPlane::Sagittal); //### Usage of CompareRenderWindowAgainstReference: See docu of mitkRrenderingTestHelper MITK_TEST_CONDITION(renderingHelper.CompareRenderWindowAgainstReference(argc, argv) == true, "CompareRenderWindowAgainstReference test result positive?"); // use this to generate a reference screenshot or save the file: if (false) { renderingHelper.SaveReferenceScreenShot("/media/hdd/thomasHdd/Pictures/tmp/output1.png"); } MITK_TEST_END(); } diff --git a/Modules/Core/test/mitkImageVtkMapper2DOpacityTest.cpp b/Modules/Core/test/mitkImageVtkMapper2DOpacityTest.cpp index de502162ab..0e8b348398 100644 --- a/Modules/Core/test/mitkImageVtkMapper2DOpacityTest.cpp +++ b/Modules/Core/test/mitkImageVtkMapper2DOpacityTest.cpp @@ -1,54 +1,54 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // MITK #include "mitkRenderingTestHelper.h" #include "mitkTestingMacros.h" // VTK #include int mitkImageVtkMapper2DOpacityTest(int argc, char *argv[]) { try { mitk::RenderingTestHelper openGlTest(640, 480); } catch (const mitk::TestNotRunException &e) { MITK_WARN << "Test not run: " << e.GetDescription(); return 77; } // load all arguments into a datastorage, take last argument as reference rendering // setup a renderwindow of fixed size X*Y // render the datastorage // compare rendering to reference image MITK_TEST_BEGIN("mitkImageVtkMapper2DTest") mitk::RenderingTestHelper renderingHelper(640, 480, argc, argv); // Set the opacity for all images renderingHelper.SetImageProperty("opacity", mitk::FloatProperty::New(0.5f)); // for now this test renders in coronal view direction - renderingHelper.SetViewDirection(mitk::SliceNavigationController::Coronal); + renderingHelper.SetViewDirection(mitk::AnatomicalPlane::Coronal); //### Usage of CompareRenderWindowAgainstReference: See docu of mitkRrenderingTestHelper MITK_TEST_CONDITION(renderingHelper.CompareRenderWindowAgainstReference(argc, argv) == true, "CompareRenderWindowAgainstReference test result positive?"); // use this to generate a reference screenshot or save the file: if (false) { renderingHelper.SaveReferenceScreenShot("d:/tmp/renderingtest.png"); } MITK_TEST_END(); } diff --git a/Modules/Core/test/mitkPlaneGeometryDataMapper2DTest.cpp b/Modules/Core/test/mitkPlaneGeometryDataMapper2DTest.cpp index 40c94aeff0..1332fabedc 100644 --- a/Modules/Core/test/mitkPlaneGeometryDataMapper2DTest.cpp +++ b/Modules/Core/test/mitkPlaneGeometryDataMapper2DTest.cpp @@ -1,98 +1,98 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // MITK #include "mitkRenderingTestHelper.h" #include "mitkTestingMacros.h" #include #include // VTK #include mitk::DataNode::Pointer addPlaneToDataStorage(mitk::RenderingTestHelper &renderingHelper, mitk::Image *image, - mitk::PlaneGeometry::PlaneOrientation orientation, + mitk::AnatomicalPlane orientation, mitk::ScalarType zPos) { auto geometry = mitk::PlaneGeometry::New(); geometry->InitializeStandardPlane(image->GetGeometry(), orientation, zPos); auto geometryData = mitk::PlaneGeometryData::New(); geometryData->SetPlaneGeometry(geometry); auto node = mitk::DataNode::New(); node->SetData(geometryData); renderingHelper.AddNodeToStorage(node); return node; } int mitkPlaneGeometryDataMapper2DTest(int argc, char *argv[]) { try { mitk::RenderingTestHelper openGlTest(640, 480); } catch (const mitk::TestNotRunException &e) { MITK_WARN << "Test not run: " << e.GetDescription(); return 77; } // load all arguments into a datastorage, take last argument as reference rendering // setup a renderwindow of fixed size X*Y // render the datastorage // compare rendering to reference image MITK_TEST_BEGIN("mitkPlaneGeometryDataMapper2DTest") mitk::RenderingTestHelper renderingHelper(640, 480, argc, argv); auto image = static_cast( renderingHelper.GetDataStorage()->GetNode(mitk::TNodePredicateDataType::New())->GetData()); auto zCoord = image->GetGeometry()->GetBoundingBox()->GetCenter()[0]; - addPlaneToDataStorage(renderingHelper, image, mitk::PlaneGeometry::Sagittal, zCoord); - addPlaneToDataStorage(renderingHelper, image, mitk::PlaneGeometry::Coronal, zCoord); + addPlaneToDataStorage(renderingHelper, image, mitk::AnatomicalPlane::Sagittal, zCoord); + addPlaneToDataStorage(renderingHelper, image, mitk::AnatomicalPlane::Coronal, zCoord); - auto planeNode = addPlaneToDataStorage(renderingHelper, image, mitk::PlaneGeometry::Sagittal, zCoord); + auto planeNode = addPlaneToDataStorage(renderingHelper, image, mitk::AnatomicalPlane::Sagittal, zCoord); auto planeGeometry = static_cast(planeNode->GetData())->GetPlaneGeometry(); auto transform = mitk::AffineTransform3D::New(); mitk::Vector3D rotationAxis; rotationAxis.Fill(0.0); rotationAxis[2] = 1; transform->Rotate3D(rotationAxis, vnl_math::pi_over_4); planeGeometry->Compose(transform); auto bounds = planeGeometry->GetBounds(); bounds[1] /= 3; planeGeometry->SetBounds(bounds); planeGeometry->SetReferenceGeometry(nullptr); planeNode->SetIntProperty("Crosshair.Gap Size", 4); //### Usage of CompareRenderWindowAgainstReference: See docu of mitkRrenderingTestHelper MITK_TEST_CONDITION(renderingHelper.CompareRenderWindowAgainstReference(argc, argv, 1) == true, "CompareRenderWindowAgainstReference test result positive?"); // use this to generate a reference screenshot or save the file: if (false) { renderingHelper.SaveReferenceScreenShot("output.png"); } MITK_TEST_END(); } diff --git a/Modules/Core/test/mitkPlaneGeometryTest.cpp b/Modules/Core/test/mitkPlaneGeometryTest.cpp index 376771613d..e64ebc6e26 100644 --- a/Modules/Core/test/mitkPlaneGeometryTest.cpp +++ b/Modules/Core/test/mitkPlaneGeometryTest.cpp @@ -1,1093 +1,1093 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkAffineTransform3D.h" #include "mitkBaseGeometry.h" #include "mitkGeometry3D.h" #include "mitkInteractionConst.h" #include "mitkLine.h" #include "mitkPlaneGeometry.h" #include "mitkRotationOperation.h" #include "mitkSlicedGeometry3D.h" #include "mitkThinPlateSplineCurvedGeometry.h" #include #include #include #include #include #include #include #include static const mitk::ScalarType testEps = 1E-9; // the epsilon used in this test == at least float precision. class mitkPlaneGeometryTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkPlaneGeometryTestSuite); MITK_TEST(TestInitializeStandardPlane); MITK_TEST(TestProjectPointOntoPlane); MITK_TEST(TestPlaneGeometryCloning); MITK_TEST(TestInheritance); MITK_TEST(TestSetExtendInMM); MITK_TEST(TestRotate); MITK_TEST(TestClone); MITK_TEST(TestPlaneComparison); MITK_TEST(TestAxialInitialization); MITK_TEST(TestCoronalInitialization); MITK_TEST(TestSagittalInitialization); MITK_TEST(TestLefthandedCoordinateSystem); MITK_TEST(TestDominantAxesError); MITK_TEST(TestCheckRotationMatrix); // Currently commented out, see See bug 15990 // MITK_TEST(testPlaneGeometryInitializeOrder); MITK_TEST(TestIntersectionPoint); MITK_TEST(TestCase1210); CPPUNIT_TEST_SUITE_END(); private: // private test members that are initialized by setUp() mitk::PlaneGeometry::Pointer planegeometry; mitk::Point3D origin; mitk::Vector3D right, bottom, normal, spacing; mitk::ScalarType width, height; mitk::ScalarType widthInMM, heightInMM, thicknessInMM; public: void setUp() override { planegeometry = mitk::PlaneGeometry::New(); width = 100; widthInMM = width; height = 200; heightInMM = height; thicknessInMM = 1.0; mitk::FillVector3D(origin, 4.5, 7.3, 11.2); mitk::FillVector3D(right, widthInMM, 0, 0); mitk::FillVector3D(bottom, 0, heightInMM, 0); mitk::FillVector3D(normal, 0, 0, thicknessInMM); mitk::FillVector3D(spacing, 1.0, 1.0, thicknessInMM); planegeometry->InitializeStandardPlane(right, bottom); planegeometry->SetOrigin(origin); planegeometry->SetSpacing(spacing); } void tearDown() override {} // This test verifies inheritance behaviour, this test will fail if the behaviour changes in the future void TestInheritance() { mitk::PlaneGeometry::Pointer plane = mitk::PlaneGeometry::New(); mitk::Geometry3D::Pointer g3d = dynamic_cast(plane.GetPointer()); CPPUNIT_ASSERT_MESSAGE("Planegeometry should not be castable to Geometry 3D", g3d.IsNull()); mitk::BaseGeometry::Pointer base = dynamic_cast(plane.GetPointer()); CPPUNIT_ASSERT_MESSAGE("Planegeometry should be castable to BaseGeometry", base.IsNotNull()); g3d = mitk::Geometry3D::New(); base = dynamic_cast(g3d.GetPointer()); CPPUNIT_ASSERT_MESSAGE("Geometry3D should be castable to BaseGeometry", base.IsNotNull()); mitk::SlicedGeometry3D::Pointer sliced = mitk::SlicedGeometry3D::New(); g3d = dynamic_cast(sliced.GetPointer()); CPPUNIT_ASSERT_MESSAGE("SlicedGeometry3D should not be castable to Geometry3D", g3d.IsNull()); mitk::ThinPlateSplineCurvedGeometry::Pointer thin = mitk::ThinPlateSplineCurvedGeometry::New(); plane = dynamic_cast(thin.GetPointer()); CPPUNIT_ASSERT_MESSAGE("AbstractTransformGeometry should be castable to PlaneGeometry", plane.IsNotNull()); plane = mitk::PlaneGeometry::New(); mitk::AbstractTransformGeometry::Pointer atg = dynamic_cast(plane.GetPointer()); CPPUNIT_ASSERT_MESSAGE("PlaneGeometry should not be castable to AbstractTransofrmGeometry", atg.IsNull()); } void TestDominantAxesError() { auto image = mitk::IOUtil::Load(GetTestDataFilePath("NotQuiteARotationMatrix.nrrd")); auto matrix = image->GetGeometry()->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().transpose(); std::vector< int > axes = mitk::PlaneGeometry::CalculateDominantAxes(matrix); CPPUNIT_ASSERT_MESSAGE("Domiant axes cannot be determined in this dataset. Output should be default ordering.", axes.at(0)==0 && axes.at(1)==1 && axes.at(2)==2); } void TestCheckRotationMatrix() { auto image = mitk::IOUtil::Load(GetTestDataFilePath("NotQuiteARotationMatrix.nrrd")); bool is_rotation = mitk::PlaneGeometry::CheckRotationMatrix(image->GetGeometry()->GetIndexToWorldTransform(), 1e-8); CPPUNIT_ASSERT_MESSAGE("Since the test data matrix is not quite a rotation matrix, this should be detected.", !is_rotation); } void TestLefthandedCoordinateSystem() { /** * @brief This method tests InitializeStandardPlane() and IndexToWorld() * with a left-handed coordinate orientation or indexToWorldMatrix. * * Of course this test does not use standard Parameters, which are right-handed. * See also discussion of bug #11477: https://phabricator.mitk.org/T11477 */ planegeometry = mitk::PlaneGeometry::New(); width = 100; widthInMM = 5; height = 200; heightInMM = 3; thicknessInMM = 1.0; mitk::FillVector3D(right, widthInMM, 0, 0); mitk::FillVector3D(bottom, 0, heightInMM, 0); // This one negative sign results in lefthanded coordinate orientation and det(matrix) < 0. mitk::FillVector3D(normal, 0, 0, -thicknessInMM); mitk::AffineTransform3D::Pointer transform = mitk::AffineTransform3D::New(); mitk::AffineTransform3D::MatrixType matrix; mitk::AffineTransform3D::MatrixType::InternalMatrixType &vnl_matrix = matrix.GetVnlMatrix(); vnl_matrix.set_column(0, right); vnl_matrix.set_column(1, bottom); vnl_matrix.set_column(2, normal); // making sure that we didn't screw up this special test case or else fail deadly: assert(vnl_determinant(vnl_matrix) < 0.0); transform->SetIdentity(); transform->SetMatrix(matrix); planegeometry->InitializeStandardPlane(width, height, transform); // Crux of the matter. CPPUNIT_ASSERT_MESSAGE( "Testing if IndexToWorldMatrix is correct after InitializeStandardPlane( width, height, transform ) ", mitk::MatrixEqualElementWise(planegeometry->GetIndexToWorldTransform()->GetMatrix(), matrix)); mitk::Point3D p_index; p_index[0] = 10.; p_index[1] = 10.; p_index[2] = 0.; mitk::Point3D p_world; mitk::Point3D p_expectedResult; p_expectedResult[0] = 50.; p_expectedResult[1] = 30.; p_expectedResult[2] = 0.; ((mitk::BaseGeometry::Pointer)planegeometry)->IndexToWorld(p_index, p_world); // Crux of the matter. CPPUNIT_ASSERT_MESSAGE("Testing if IndexToWorld(a,b) function works correctly with lefthanded matrix ", mitk::Equal(p_world, p_expectedResult, testEps)); } // See bug 1210 // Test does not use standard Parameters void TestCase1210() { mitk::PlaneGeometry::Pointer planegeometry = mitk::PlaneGeometry::New(); mitk::Point3D origin; mitk::Vector3D right, down, spacing; mitk::FillVector3D(origin, 4.5, 7.3, 11.2); mitk::FillVector3D(right, 1.015625, 1.015625, 1.1999969482421875); mitk::FillVector3D(down, 1.4012984643248170709237295832899161312802619418765e-45, 0, 0); mitk::FillVector3D(spacing, 0, 1.4713633875410579244699160624544119378442750389703e-43, 9.2806360452222355258639080851310540729807238879469e-32); std::cout << "Testing InitializeStandardPlane(rightVector, downVector, spacing = nullptr): " << std::endl; CPPUNIT_ASSERT_NO_THROW(planegeometry->InitializeStandardPlane(right, down, &spacing)); /* std::cout << "Testing width, height and thickness (in units): "; if((mitk::Equal(planegeometry->GetExtent(0),width)==false) || (mitk::Equal(planegeometry->GetExtent(1),height)==false) || (mitk::Equal(planegeometry->GetExtent(2),1)==false) ) { std::cout<<"[FAILED]"<GetExtentInMM(0),widthInMM)==false) || (mitk::Equal(planegeometry->GetExtentInMM(1),heightInMM)==false) || (mitk::Equal(planegeometry->GetExtentInMM(2),thicknessInMM)==false) ) { std::cout<<"[FAILED]"< 0. * */ // Test does not use standard Parameters void TestIntersectionPoint() { // init plane with its parameter mitk::PlaneGeometry::Pointer myPlaneGeometry = mitk::PlaneGeometry::New(); mitk::Point3D origin; origin[0] = 0.0; origin[1] = 2.0; origin[2] = 0.0; mitk::Vector3D normal; normal[0] = 0.0; normal[1] = 1.0; normal[2] = 0.0; myPlaneGeometry->InitializePlane(origin, normal); // generate points and line for intersection testing // point distance of given line > 1 mitk::Point3D pointP1; pointP1[0] = 2.0; pointP1[1] = 1.0; pointP1[2] = 0.0; mitk::Point3D pointP2; pointP2[0] = 2.0; pointP2[1] = 4.0; pointP2[2] = 0.0; mitk::Vector3D lineDirection; lineDirection[0] = pointP2[0] - pointP1[0]; lineDirection[1] = pointP2[1] - pointP1[1]; lineDirection[2] = pointP2[2] - pointP1[2]; mitk::Line3D xingline(pointP1, lineDirection); mitk::Point3D calcXingPoint; myPlaneGeometry->IntersectionPoint(xingline, calcXingPoint); // point distance of given line < 1 mitk::Point3D pointP3; pointP3[0] = 2.0; pointP3[1] = 2.2; pointP3[2] = 0.0; mitk::Point3D pointP4; pointP4[0] = 2.0; pointP4[1] = 1.7; pointP4[2] = 0.0; mitk::Vector3D lineDirection2; lineDirection2[0] = pointP4[0] - pointP3[0]; lineDirection2[1] = pointP4[1] - pointP3[1]; lineDirection2[2] = pointP4[2] - pointP3[2]; mitk::Line3D xingline2(pointP3, lineDirection2); mitk::Point3D calcXingPoint2; myPlaneGeometry->IntersectionPoint(xingline2, calcXingPoint2); // intersection points must be the same CPPUNIT_ASSERT_MESSAGE("Failed to calculate Intersection Point", calcXingPoint == calcXingPoint2); } /** * @brief This method tests method ProjectPointOntoPlane. * * See also bug #3409. */ // Test does not use standard Parameters void TestProjectPointOntoPlane() { mitk::PlaneGeometry::Pointer myPlaneGeometry = mitk::PlaneGeometry::New(); // create normal mitk::Vector3D normal; normal[0] = 0.0; normal[1] = 0.0; normal[2] = 1.0; // create origin mitk::Point3D origin; origin[0] = -27.582859; origin[1] = 50; origin[2] = 200.27742; // initialize plane geometry myPlaneGeometry->InitializePlane(origin, normal); // output to describe the test std::cout << "Testing PlaneGeometry according to bug #3409" << std::endl; std::cout << "Our normal is: " << normal << std::endl; std::cout << "So ALL projected points should have exactly the same z-value!" << std::endl; // create a number of points mitk::Point3D myPoints[5]; myPoints[0][0] = -27.582859; myPoints[0][1] = 50.00; myPoints[0][2] = 200.27742; myPoints[1][0] = -26.58662; myPoints[1][1] = 50.00; myPoints[1][2] = 200.19026; myPoints[2][0] = -26.58662; myPoints[2][1] = 50.00; myPoints[2][2] = 200.33124; myPoints[3][0] = 104.58662; myPoints[3][1] = 452.12313; myPoints[3][2] = 866.41236; myPoints[4][0] = -207.58662; myPoints[4][1] = 312.00; myPoints[4][2] = -300.12346; // project points onto plane mitk::Point3D myProjectedPoints[5]; for (unsigned int i = 0; i < 5; ++i) { myProjectedPoints[i] = myPlaneGeometry->ProjectPointOntoPlane(myPoints[i]); } // compare z-values with z-value of plane (should be equal) bool allPointsOnPlane = true; for (auto &myProjectedPoint : myProjectedPoints) { if (fabs(myProjectedPoint[2] - origin[2]) > mitk::sqrteps) { allPointsOnPlane = false; } } CPPUNIT_ASSERT_MESSAGE("All points lie not on the same plane", allPointsOnPlane); } void TestPlaneGeometryCloning() { mitk::PlaneGeometry::Pointer geometry2D = createPlaneGeometry(); try { mitk::PlaneGeometry::Pointer clone = geometry2D->Clone(); itk::Matrix matrix = clone->GetIndexToWorldTransform()->GetMatrix(); CPPUNIT_ASSERT_MESSAGE("Test if matrix element exists...", matrix[0][0] == 31); double origin = geometry2D->GetOrigin()[0]; CPPUNIT_ASSERT_MESSAGE("First Point of origin as expected...", mitk::Equal(origin, 8)); double spacing = geometry2D->GetSpacing()[0]; CPPUNIT_ASSERT_MESSAGE("First Point of spacing as expected...", mitk::Equal(spacing, 31)); } catch (...) { CPPUNIT_FAIL("Error during access on a member of cloned geometry"); } // direction [row] [column] MITK_TEST_OUTPUT(<< "Casting a rotated 2D ITK Image to a MITK Image and check if Geometry is still same"); } void TestPlaneGeometryInitializeOrder() { mitk::Vector3D mySpacing; mySpacing[0] = 31; mySpacing[1] = 0.1; mySpacing[2] = 5.4; mitk::Point3D myOrigin; myOrigin[0] = 8; myOrigin[1] = 9; myOrigin[2] = 10; mitk::AffineTransform3D::Pointer myTransform = mitk::AffineTransform3D::New(); itk::Matrix transMatrix; transMatrix.Fill(0); transMatrix[0][0] = 1; transMatrix[1][1] = 2; transMatrix[2][2] = 4; myTransform->SetMatrix(transMatrix); mitk::PlaneGeometry::Pointer geometry2D1 = mitk::PlaneGeometry::New(); geometry2D1->SetIndexToWorldTransform(myTransform); geometry2D1->SetSpacing(mySpacing); geometry2D1->SetOrigin(myOrigin); mitk::PlaneGeometry::Pointer geometry2D2 = mitk::PlaneGeometry::New(); geometry2D2->SetSpacing(mySpacing); geometry2D2->SetOrigin(myOrigin); geometry2D2->SetIndexToWorldTransform(myTransform); mitk::PlaneGeometry::Pointer geometry2D3 = mitk::PlaneGeometry::New(); geometry2D3->SetIndexToWorldTransform(myTransform); geometry2D3->SetSpacing(mySpacing); geometry2D3->SetOrigin(myOrigin); geometry2D3->SetIndexToWorldTransform(myTransform); CPPUNIT_ASSERT_MESSAGE("Origin of Geometry 1 matches that of Geometry 2.", mitk::Equal(geometry2D1->GetOrigin(), geometry2D2->GetOrigin())); CPPUNIT_ASSERT_MESSAGE("Origin of Geometry 1 match those of Geometry 3.", mitk::Equal(geometry2D1->GetOrigin(), geometry2D3->GetOrigin())); CPPUNIT_ASSERT_MESSAGE("Origin of Geometry 2 match those of Geometry 3.", mitk::Equal(geometry2D2->GetOrigin(), geometry2D3->GetOrigin())); CPPUNIT_ASSERT_MESSAGE("Spacing of Geometry 1 match those of Geometry 2.", mitk::Equal(geometry2D1->GetSpacing(), geometry2D2->GetSpacing())); CPPUNIT_ASSERT_MESSAGE("Spacing of Geometry 1 match those of Geometry 3.", mitk::Equal(geometry2D1->GetSpacing(), geometry2D3->GetSpacing())); CPPUNIT_ASSERT_MESSAGE("Spacing of Geometry 2 match those of Geometry 3.", mitk::Equal(geometry2D2->GetSpacing(), geometry2D3->GetSpacing())); CPPUNIT_ASSERT_MESSAGE("Transformation of Geometry 1 match those of Geometry 2.", compareMatrix(geometry2D1->GetIndexToWorldTransform()->GetMatrix(), geometry2D2->GetIndexToWorldTransform()->GetMatrix())); CPPUNIT_ASSERT_MESSAGE("Transformation of Geometry 1 match those of Geometry 3.", compareMatrix(geometry2D1->GetIndexToWorldTransform()->GetMatrix(), geometry2D3->GetIndexToWorldTransform()->GetMatrix())); CPPUNIT_ASSERT_MESSAGE("Transformation of Geometry 2 match those of Geometry 3.", compareMatrix(geometry2D2->GetIndexToWorldTransform()->GetMatrix(), geometry2D3->GetIndexToWorldTransform()->GetMatrix())); } void TestInitializeStandardPlane() { CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with default Spacing: width", mitk::Equal(planegeometry->GetExtent(0), width, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with default Spacing: height", mitk::Equal(planegeometry->GetExtent(1), height, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with default Spacing: depth", mitk::Equal(planegeometry->GetExtent(2), 1, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with default Spacing: width in mm", mitk::Equal(planegeometry->GetExtentInMM(0), widthInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with default Spacing: heght in mm", mitk::Equal(planegeometry->GetExtentInMM(1), heightInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with default Spacing: depth in mm", mitk::Equal(planegeometry->GetExtentInMM(2), thicknessInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with default Spacing: AxisVectorRight", mitk::Equal(planegeometry->GetAxisVector(0), right, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with default Spacing: AxisVectorBottom", mitk::Equal(planegeometry->GetAxisVector(1), bottom, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with default Spacing: AxisVectorNormal", mitk::Equal(planegeometry->GetAxisVector(2), normal, testEps)); mitk::Vector3D spacing; thicknessInMM = 1.5; normal.Normalize(); normal *= thicknessInMM; mitk::FillVector3D(spacing, 1.0, 1.0, thicknessInMM); planegeometry->InitializeStandardPlane(right.GetVnlVector(), bottom.GetVnlVector(), &spacing); CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with custom Spacing: width", mitk::Equal(planegeometry->GetExtent(0), width, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with custom Spacing: height", mitk::Equal(planegeometry->GetExtent(1), height, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with custom Spacing: depth", mitk::Equal(planegeometry->GetExtent(2), 1, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with custom Spacing: width in mm", mitk::Equal(planegeometry->GetExtentInMM(0), widthInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with custom Spacing: height in mm", mitk::Equal(planegeometry->GetExtentInMM(1), heightInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with custom Spacing: depth in mm", mitk::Equal(planegeometry->GetExtentInMM(2), thicknessInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with custom Spacing: AxisVectorRight", mitk::Equal(planegeometry->GetAxisVector(0), right, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with custom Spacing: AxisVectorBottom", mitk::Equal(planegeometry->GetAxisVector(1), bottom, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing correct Standard Plane initialization with custom Spacing: AxisVectorNormal", mitk::Equal(planegeometry->GetAxisVector(2), normal, testEps)); ; } void TestSetExtendInMM() { normal.Normalize(); normal *= thicknessInMM; planegeometry->SetExtentInMM(2, thicknessInMM); CPPUNIT_ASSERT_MESSAGE("Testing SetExtentInMM(2, ...), querying by GetExtentInMM(2): ", mitk::Equal(planegeometry->GetExtentInMM(2), thicknessInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing SetExtentInMM(2, ...), querying by GetAxisVector(2) and comparing to normal: ", mitk::Equal(planegeometry->GetAxisVector(2), normal, testEps)); planegeometry->SetOrigin(origin); CPPUNIT_ASSERT_MESSAGE("Testing SetOrigin", mitk::Equal(planegeometry->GetOrigin(), origin, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() after SetOrigin: Right", mitk::Equal(planegeometry->GetAxisVector(0), right, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() after SetOrigin: Bottom", mitk::Equal(planegeometry->GetAxisVector(1), bottom, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() after SetOrigin: Normal", mitk::Equal(planegeometry->GetAxisVector(2), normal, testEps)); mappingTests2D(planegeometry, width, height, widthInMM, heightInMM, origin, right, bottom); } void TestRotate() { // Changing the IndexToWorldTransform to a rotated version by SetIndexToWorldTransform() (keep origin): mitk::AffineTransform3D::Pointer transform = mitk::AffineTransform3D::New(); mitk::AffineTransform3D::MatrixType::InternalMatrixType vnlmatrix; vnlmatrix = planegeometry->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix(); mitk::VnlVector axis(3); mitk::FillVector3D(axis, 1.0, 1.0, 1.0); axis.normalize(); vnl_quaternion rotation(axis, 0.223); vnlmatrix = rotation.rotation_matrix_transpose() * vnlmatrix; mitk::Matrix3D matrix; matrix = vnlmatrix; transform->SetMatrix(matrix); transform->SetOffset(planegeometry->GetIndexToWorldTransform()->GetOffset()); right.SetVnlVector(rotation.rotation_matrix_transpose() * right.GetVnlVector()); bottom.SetVnlVector(rotation.rotation_matrix_transpose() * bottom.GetVnlVector()); normal.SetVnlVector(rotation.rotation_matrix_transpose() * normal.GetVnlVector()); planegeometry->SetIndexToWorldTransform(transform); // The origin changed,because m_Origin=m_IndexToWorldTransform->GetOffset()+GetAxisVector(2)*0.5 // and the AxisVector changes due to the rotation. In other words: the rotation was done around // the corner of the box, not around the planes origin. Now change it to a rotation around // the origin, simply by re-setting the origin to the original one: planegeometry->SetOrigin(origin); CPPUNIT_ASSERT_MESSAGE("Testing whether SetIndexToWorldTransform kept origin: ", mitk::Equal(planegeometry->GetOrigin(), origin, testEps)); mitk::Point2D point; point[0] = 4; point[1] = 3; mitk::Point2D dummy; planegeometry->WorldToIndex(point, dummy); planegeometry->IndexToWorld(dummy, dummy); CPPUNIT_ASSERT_MESSAGE("Testing consistency of index and world coordinates.", dummy == point); CPPUNIT_ASSERT_MESSAGE("Testing width of rotated version: ", mitk::Equal(planegeometry->GetExtentInMM(0), widthInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing height of rotated version: ", mitk::Equal(planegeometry->GetExtentInMM(1), heightInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing thickness of rotated version: ", mitk::Equal(planegeometry->GetExtentInMM(2), thicknessInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of rotated version: right ", mitk::Equal(planegeometry->GetAxisVector(0), right, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of rotated version: bottom", mitk::Equal(planegeometry->GetAxisVector(1), bottom, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of rotated version: normal", mitk::Equal(planegeometry->GetAxisVector(2), normal, testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing GetAxisVector(direction).GetNorm() != planegeometry->GetExtentInMM(direction) of rotated version: ", mitk::Equal(planegeometry->GetAxisVector(0).GetNorm(), planegeometry->GetExtentInMM(0), testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing GetAxisVector(direction).GetNorm() != planegeometry->GetExtentInMM(direction) of rotated version: ", mitk::Equal(planegeometry->GetAxisVector(1).GetNorm(), planegeometry->GetExtentInMM(1), testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing GetAxisVector(direction).GetNorm() != planegeometry->GetExtentInMM(direction) of rotated version: ", mitk::Equal(planegeometry->GetAxisVector(2).GetNorm(), planegeometry->GetExtentInMM(2), testEps)); mappingTests2D(planegeometry, width, height, widthInMM, heightInMM, origin, right, bottom); width *= 2; height *= 3; planegeometry->SetSizeInUnits(width, height); CPPUNIT_ASSERT_MESSAGE("Testing SetSizeInUnits() of rotated version: ", mitk::Equal(planegeometry->GetExtent(0), width, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing SetSizeInUnits() of rotated version: ", mitk::Equal(planegeometry->GetExtent(1), height, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing SetSizeInUnits() of rotated version: ", mitk::Equal(planegeometry->GetExtent(2), 1, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing width (in mm) of version with changed size in units: ", mitk::Equal(planegeometry->GetExtentInMM(0), widthInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing height (in mm) of version with changed size in units: ", mitk::Equal(planegeometry->GetExtentInMM(1), heightInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing thickness (in mm) of version with changed size in units: ", mitk::Equal(planegeometry->GetExtentInMM(2), thicknessInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of version with changed size in units: right ", mitk::Equal(planegeometry->GetAxisVector(0), right, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of version with changed size in units: bottom", mitk::Equal(planegeometry->GetAxisVector(1), bottom, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of version with changed size in units: normal", mitk::Equal(planegeometry->GetAxisVector(2), normal, testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing GetAxisVector(direction).GetNorm() != planegeometry->GetExtentInMM(direction) of rotated version: ", mitk::Equal(planegeometry->GetAxisVector(0).GetNorm(), planegeometry->GetExtentInMM(0), testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing GetAxisVector(direction).GetNorm() != planegeometry->GetExtentInMM(direction) of rotated version: ", mitk::Equal(planegeometry->GetAxisVector(1).GetNorm(), planegeometry->GetExtentInMM(1), testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing GetAxisVector(direction).GetNorm() != planegeometry->GetExtentInMM(direction) of rotated version: ", mitk::Equal(planegeometry->GetAxisVector(2).GetNorm(), planegeometry->GetExtentInMM(2), testEps)); mappingTests2D(planegeometry, width, height, widthInMM, heightInMM, origin, right, bottom); } void TestClone() { mitk::PlaneGeometry::Pointer clonedplanegeometry = dynamic_cast(planegeometry->Clone().GetPointer()); // Cave: Statement below is negated! CPPUNIT_ASSERT_MESSAGE("Testing Clone(): ", !((clonedplanegeometry.IsNull()) || (clonedplanegeometry->GetReferenceCount() != 1))); CPPUNIT_ASSERT_MESSAGE("Testing origin of cloned version: ", mitk::Equal(clonedplanegeometry->GetOrigin(), origin, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing width (in units) of cloned version: ", mitk::Equal(clonedplanegeometry->GetExtent(0), width, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing height (in units) of cloned version: ", mitk::Equal(clonedplanegeometry->GetExtent(1), height, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing extent (in units) of cloned version: ", mitk::Equal(clonedplanegeometry->GetExtent(2), 1, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing width (in mm) of cloned version: ", mitk::Equal(clonedplanegeometry->GetExtentInMM(0), widthInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing height (in mm) of cloned version: ", mitk::Equal(clonedplanegeometry->GetExtentInMM(1), heightInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing thickness (in mm) of cloned version: ", mitk::Equal(clonedplanegeometry->GetExtentInMM(2), thicknessInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of cloned version: right", mitk::Equal(clonedplanegeometry->GetAxisVector(0), right, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of cloned version: bottom", mitk::Equal(clonedplanegeometry->GetAxisVector(1), bottom, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of cloned version: normal", mitk::Equal(clonedplanegeometry->GetAxisVector(2), normal, testEps)); mappingTests2D(clonedplanegeometry, width, height, widthInMM, heightInMM, origin, right, bottom); } void TestSagittalInitialization() { mitk::Point3D cornerpoint0 = planegeometry->GetCornerPoint(0); mitk::PlaneGeometry::Pointer clonedplanegeometry = planegeometry->Clone(); - // Testing InitializeStandardPlane(clonedplanegeometry, planeorientation = Sagittal, zPosition = 0, frontside=true): - planegeometry->InitializeStandardPlane(clonedplanegeometry, mitk::PlaneGeometry::Sagittal); + // Testing InitializeStandardPlane(clonedplanegeometry, anatomicalplane = Sagittal, zPosition = 0, frontside=true): + planegeometry->InitializeStandardPlane(clonedplanegeometry, mitk::AnatomicalPlane::Sagittal); mitk::Vector3D newright, newbottom, newnormal; mitk::ScalarType newthicknessInMM; newright = bottom; newthicknessInMM = widthInMM / width * 1.0; // extent in normal direction is 1; newnormal = right; newnormal.Normalize(); newnormal *= newthicknessInMM; newbottom = normal; newbottom.Normalize(); newbottom *= thicknessInMM; CPPUNIT_ASSERT_MESSAGE("Testing GetCornerPoint(0) of sagittally initialized version:", mitk::Equal(planegeometry->GetCornerPoint(0), cornerpoint0, testEps)); // ok, corner was fine, so we can dare to believe the origin is ok. origin = planegeometry->GetOrigin(); CPPUNIT_ASSERT_MESSAGE("Testing width, height and thickness (in units) of sagittally initialized version: ", mitk::Equal(planegeometry->GetExtent(0), height, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing width, height and thickness (in units) of sagittally initialized version: ", mitk::Equal(planegeometry->GetExtent(1), 1, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing width, height and thickness (in units) of sagittally initialized version: ", mitk::Equal(planegeometry->GetExtent(2), 1, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing width, height and thickness (in mm) of sagittally initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(0), heightInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing width, height and thickness (in mm) of sagittally initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(1), thicknessInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing width, height and thickness (in mm) of sagittally initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(2), newthicknessInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of sagittally initialized version: ", mitk::Equal(planegeometry->GetAxisVector(0), newright, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of sagittally initialized version: ", mitk::Equal(planegeometry->GetAxisVector(1), newbottom, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of sagittally initialized version: ", mitk::Equal(planegeometry->GetAxisVector(2), newnormal, testEps)); mappingTests2D(planegeometry, height, 1, heightInMM, thicknessInMM, origin, newright, newbottom); // set origin back to the one of the axial slice: origin = clonedplanegeometry->GetOrigin(); - // Testing backside initialization: InitializeStandardPlane(clonedplanegeometry, planeorientation = Axial, zPosition + // Testing backside initialization: InitializeStandardPlane(clonedplanegeometry, anatomicalplane = Axial, zPosition // = 0, frontside=false, rotated=true): - planegeometry->InitializeStandardPlane(clonedplanegeometry, mitk::PlaneGeometry::Axial, 0, false, true); + planegeometry->InitializeStandardPlane(clonedplanegeometry, mitk::AnatomicalPlane::Axial, 0, false, true); mitk::Point3D backsideorigin; backsideorigin = origin + clonedplanegeometry->GetAxisVector(1); //+clonedplanegeometry->GetAxisVector(2); CPPUNIT_ASSERT_MESSAGE("Testing origin of backsidedly, axially initialized version: ", mitk::Equal(planegeometry->GetOrigin(), backsideorigin, testEps)); mitk::Point3D backsidecornerpoint0; backsidecornerpoint0 = cornerpoint0 + clonedplanegeometry->GetAxisVector(1); //+clonedplanegeometry->GetAxisVector(2); CPPUNIT_ASSERT_MESSAGE("Testing GetCornerPoint(0) of sagittally initialized version: ", mitk::Equal(planegeometry->GetCornerPoint(0), backsidecornerpoint0, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing width, height and thickness (in units) of backsidedly, axially initialized version " "(should be same as in mm due to unit spacing, except for thickness, which is always 1): ", mitk::Equal(planegeometry->GetExtent(0), width, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing width, height and thickness (in units) of backsidedly, axially initialized version " "(should be same as in mm due to unit spacing, except for thickness, which is always 1): ", mitk::Equal(planegeometry->GetExtent(1), height, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing width, height and thickness (in units) of backsidedly, axially initialized version " "(should be same as in mm due to unit spacing, except for thickness, which is always 1): ", mitk::Equal(planegeometry->GetExtent(2), 1, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing width, height and thickness (in mm) of backsidedly, axially initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(0), widthInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing width, height and thickness (in mm) of backsidedly, axially initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(1), heightInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing width, height and thickness (in mm) of backsidedly, axially initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(2), thicknessInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of backsidedly, axially initialized version: ", mitk::Equal(planegeometry->GetAxisVector(0), right, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of backsidedly, axially initialized version: ", mitk::Equal(planegeometry->GetAxisVector(1), -bottom, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of backsidedly, axially initialized version: ", mitk::Equal(planegeometry->GetAxisVector(2), normal, testEps)); // T22254: Flipped sign mappingTests2D(planegeometry, width, height, widthInMM, heightInMM, backsideorigin, right, -bottom); } void TestCoronalInitialization() { mitk::Point3D cornerpoint0 = planegeometry->GetCornerPoint(0); mitk::PlaneGeometry::Pointer clonedplanegeometry = dynamic_cast(planegeometry->Clone().GetPointer()); //-------- mitk::Vector3D newright, newbottom, newnormal; mitk::ScalarType newthicknessInMM; - // Testing InitializeStandardPlane(clonedplanegeometry, planeorientation = Coronal, zPosition = 0, frontside=true) - planegeometry->InitializeStandardPlane(clonedplanegeometry, mitk::PlaneGeometry::Coronal); + // Testing InitializeStandardPlane(clonedplanegeometry, anatomicalplane = Coronal, zPosition = 0, frontside=true) + planegeometry->InitializeStandardPlane(clonedplanegeometry, mitk::AnatomicalPlane::Coronal); newright = right; newbottom = normal; newbottom.Normalize(); newbottom *= thicknessInMM; newthicknessInMM = heightInMM / height * 1.0 /*extent in normal direction is 1*/; newnormal = -bottom; newnormal.Normalize(); newnormal *= newthicknessInMM; CPPUNIT_ASSERT_MESSAGE("Testing GetCornerPoint(0) of coronally initialized version: ", mitk::Equal(planegeometry->GetCornerPoint(0), cornerpoint0, testEps)); // ok, corner was fine, so we can dare to believe the origin is ok. origin = planegeometry->GetOrigin(); CPPUNIT_ASSERT_MESSAGE("Testing width (in units) of coronally initialized version: ", mitk::Equal(planegeometry->GetExtent(0), width, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing height (in units) of coronally initialized version: ", mitk::Equal(planegeometry->GetExtent(1), 1, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing thickness (in units) of coronally initialized version: ", mitk::Equal(planegeometry->GetExtent(2), 1, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing width (in mm) of coronally initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(0), widthInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing height (in mm) of coronally initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(1), thicknessInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing thickness (in mm) of coronally initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(2), newthicknessInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of coronally initialized version: ", mitk::Equal(planegeometry->GetAxisVector(0), newright, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of coronally initialized version: ", mitk::Equal(planegeometry->GetAxisVector(1), newbottom, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of coronally initialized version: ", mitk::Equal(planegeometry->GetAxisVector(2), -newnormal, testEps)); // T22254: Flipped sign mappingTests2D(planegeometry, width, 1, widthInMM, thicknessInMM, origin, newright, newbottom); // Changing plane to in-plane unit spacing using SetSizeInUnits: planegeometry->SetSizeInUnits(planegeometry->GetExtentInMM(0), planegeometry->GetExtentInMM(1)); CPPUNIT_ASSERT_MESSAGE("Testing origin of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetOrigin(), origin, testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing width, height and thickness (in units) of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetExtent(0), widthInMM, testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing width, height and thickness (in units) of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetExtent(1), thicknessInMM, testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing width, height and thickness (in units) of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetExtent(2), 1, testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing width, height and thickness (in mm) of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(0), widthInMM, testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing width, height and thickness (in mm) of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(1), thicknessInMM, testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing width, height and thickness (in mm) of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(2), newthicknessInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetAxisVector(0), newright, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetAxisVector(1), newbottom, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetAxisVector(2), -newnormal, testEps)); // T22254: Flipped sign mappingTests2D(planegeometry, widthInMM, thicknessInMM, widthInMM, thicknessInMM, origin, newright, newbottom); // Changing plane to unit spacing also in normal direction using SetExtentInMM(2, 1.0): planegeometry->SetExtentInMM(2, 1.0); newnormal.Normalize(); CPPUNIT_ASSERT_MESSAGE("Testing origin of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetOrigin(), origin, testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing width, height and thickness (in units) of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetExtent(0), widthInMM, testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing width, height and thickness (in units) of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetExtent(1), thicknessInMM, testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing width, height and thickness (in units) of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetExtent(2), 1, testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing width, height and thickness (in mm) of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(0), widthInMM, testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing width, height and thickness (in mm) of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(1), thicknessInMM, testEps)); CPPUNIT_ASSERT_MESSAGE( "Testing width, height and thickness (in mm) of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(2), 1.0, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetAxisVector(0), newright, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetAxisVector(1), newbottom, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of unit spaced, coronally initialized version: ", mitk::Equal(planegeometry->GetAxisVector(2), -newnormal, testEps)); // T22254: Flipped sign mappingTests2D(planegeometry, widthInMM, thicknessInMM, widthInMM, thicknessInMM, origin, newright, newbottom); } void TestAxialInitialization() { mitk::Point3D cornerpoint0 = planegeometry->GetCornerPoint(0); // Clone, move, rotate and test for 'IsParallel' and 'IsOnPlane' mitk::PlaneGeometry::Pointer clonedplanegeometry = dynamic_cast(planegeometry->Clone().GetPointer()); CPPUNIT_ASSERT_MESSAGE("Testing Clone(): ", !((clonedplanegeometry.IsNull()) || (clonedplanegeometry->GetReferenceCount() != 1))); - std::cout << "Testing InitializeStandardPlane(clonedplanegeometry, planeorientation = Axial, zPosition = 0, " + std::cout << "Testing InitializeStandardPlane(clonedplanegeometry, anatomicalplane = Axial, zPosition = 0, " "frontside=true): " << std::endl; planegeometry->InitializeStandardPlane(clonedplanegeometry); CPPUNIT_ASSERT_MESSAGE("Testing origin of axially initialized version: ", mitk::Equal(planegeometry->GetOrigin(), origin)); CPPUNIT_ASSERT_MESSAGE("Testing GetCornerPoint(0) of axially initialized version: ", mitk::Equal(planegeometry->GetCornerPoint(0), cornerpoint0)); CPPUNIT_ASSERT_MESSAGE("Testing width (in units) of axially initialized version (should be same as in mm due to " "unit spacing, except for thickness, which is always 1): ", mitk::Equal(planegeometry->GetExtent(0), width, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing height (in units) of axially initialized version (should be same as in mm due to " "unit spacing, except for thickness, which is always 1): ", mitk::Equal(planegeometry->GetExtent(1), height, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing thickness (in units) of axially initialized version (should be same as in mm due " "to unit spacing, except for thickness, which is always 1): ", mitk::Equal(planegeometry->GetExtent(2), 1, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing width (in mm) of axially initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(0), widthInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing height (in mm) of axially initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(1), heightInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing thickness (in mm) of axially initialized version: ", mitk::Equal(planegeometry->GetExtentInMM(2), thicknessInMM, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of axially initialized version: ", mitk::Equal(planegeometry->GetAxisVector(0), right, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of axially initialized version: ", mitk::Equal(planegeometry->GetAxisVector(1), bottom, testEps)); CPPUNIT_ASSERT_MESSAGE("Testing GetAxisVector() of axially initialized version: ", mitk::Equal(planegeometry->GetAxisVector(2), normal, testEps)); mappingTests2D(planegeometry, width, height, widthInMM, heightInMM, origin, right, bottom); } void TestPlaneComparison() { // Clone, move, rotate and test for 'IsParallel' and 'IsOnPlane' mitk::PlaneGeometry::Pointer clonedplanegeometry2 = dynamic_cast(planegeometry->Clone().GetPointer()); CPPUNIT_ASSERT_MESSAGE("Testing Clone(): ", !((clonedplanegeometry2.IsNull()) || (clonedplanegeometry2->GetReferenceCount() != 1))); CPPUNIT_ASSERT_MESSAGE("Testing whether original and clone are at the same position", clonedplanegeometry2->IsOnPlane(planegeometry.GetPointer())); CPPUNIT_ASSERT_MESSAGE(" Asserting that origin is on the plane cloned plane:", clonedplanegeometry2->IsOnPlane(origin)); mitk::VnlVector newaxis(3); mitk::FillVector3D(newaxis, 1.0, 1.0, 1.0); newaxis.normalize(); vnl_quaternion rotation2(newaxis, 0.0); mitk::Vector3D clonednormal = clonedplanegeometry2->GetNormal(); mitk::Point3D clonedorigin = clonedplanegeometry2->GetOrigin(); auto planerot = new mitk::RotationOperation(mitk::OpROTATE, origin, clonedplanegeometry2->GetAxisVector(0), 180.0); clonedplanegeometry2->ExecuteOperation(planerot); CPPUNIT_ASSERT_MESSAGE(" Asserting that a flipped plane is still on the original plane: ", clonedplanegeometry2->IsOnPlane(planegeometry.GetPointer())); clonedorigin += clonednormal; clonedplanegeometry2->SetOrigin(clonedorigin); CPPUNIT_ASSERT_MESSAGE("Testing if the translated (cloned, flipped) plane is parallel to its origin plane: ", clonedplanegeometry2->IsParallel(planegeometry)); delete planerot; planerot = new mitk::RotationOperation(mitk::OpROTATE, origin, clonedplanegeometry2->GetAxisVector(0), 0.5); clonedplanegeometry2->ExecuteOperation(planerot); CPPUNIT_ASSERT_MESSAGE("Testing if a non-parallel plane gets recognized as not parallel [rotation +0.5 degree] : ", !clonedplanegeometry2->IsParallel(planegeometry)); delete planerot; planerot = new mitk::RotationOperation(mitk::OpROTATE, origin, clonedplanegeometry2->GetAxisVector(0), -1.0); clonedplanegeometry2->ExecuteOperation(planerot); CPPUNIT_ASSERT_MESSAGE("Testing if a non-parallel plane gets recognized as not parallel [rotation -0.5 degree] : ", !clonedplanegeometry2->IsParallel(planegeometry)); delete planerot; planerot = new mitk::RotationOperation(mitk::OpROTATE, origin, clonedplanegeometry2->GetAxisVector(0), 360.5); clonedplanegeometry2->ExecuteOperation(planerot); CPPUNIT_ASSERT_MESSAGE("Testing if a non-parallel plane gets recognized as parallel [rotation 360 degree] : ", clonedplanegeometry2->IsParallel(planegeometry)); } private: // helper Methods for the Tests mitk::PlaneGeometry::Pointer createPlaneGeometry() { mitk::Vector3D mySpacing; mySpacing[0] = 31; mySpacing[1] = 0.1; mySpacing[2] = 5.4; mitk::Point3D myOrigin; myOrigin[0] = 8; myOrigin[1] = 9; myOrigin[2] = 10; mitk::AffineTransform3D::Pointer myTransform = mitk::AffineTransform3D::New(); itk::Matrix transMatrix; transMatrix.Fill(0); transMatrix[0][0] = 1; transMatrix[1][1] = 2; transMatrix[2][2] = 4; myTransform->SetMatrix(transMatrix); mitk::PlaneGeometry::Pointer geometry2D = mitk::PlaneGeometry::New(); geometry2D->SetIndexToWorldTransform(myTransform); geometry2D->SetSpacing(mySpacing); geometry2D->SetOrigin(myOrigin); return geometry2D; } bool compareMatrix(itk::Matrix left, itk::Matrix right) { bool equal = true; for (int i = 0; i < 3; ++i) for (int j = 0; j < 3; ++j) equal &= mitk::Equal(left[i][j], right[i][j]); return equal; } /** * This function tests for correct mapping and is called several times from other tests **/ void mappingTests2D(const mitk::PlaneGeometry *planegeometry, const mitk::ScalarType &width, const mitk::ScalarType &height, const mitk::ScalarType &widthInMM, const mitk::ScalarType &heightInMM, const mitk::Point3D &origin, const mitk::Vector3D &right, const mitk::Vector3D &bottom) { std::cout << "Testing mapping Map(pt2d_mm(x=widthInMM/2.3,y=heightInMM/2.5), pt3d_mm) and compare with expected: "; mitk::Point2D pt2d_mm; mitk::Point3D pt3d_mm, expected_pt3d_mm; pt2d_mm[0] = widthInMM / 2.3; pt2d_mm[1] = heightInMM / 2.5; expected_pt3d_mm = origin + right * (pt2d_mm[0] / right.GetNorm()) + bottom * (pt2d_mm[1] / bottom.GetNorm()); planegeometry->Map(pt2d_mm, pt3d_mm); CPPUNIT_ASSERT_MESSAGE( "Testing mapping Map(pt2d_mm(x=widthInMM/2.3,y=heightInMM/2.5), pt3d_mm) and compare with expected", mitk::Equal(pt3d_mm, expected_pt3d_mm, testEps)); std::cout << "Testing mapping Map(pt3d_mm, pt2d_mm) and compare with expected: "; mitk::Point2D testpt2d_mm; planegeometry->Map(pt3d_mm, testpt2d_mm); std::cout << std::setprecision(12) << "Expected pt2d_mm " << pt2d_mm << std::endl; std::cout << std::setprecision(12) << "Result testpt2d_mm " << testpt2d_mm << std::endl; std::cout << std::setprecision(12) << "10*mitk::eps " << 10 * mitk::eps << std::endl; // This eps is temporarily set to 10*mitk::eps. See bug #15037 for details. CPPUNIT_ASSERT_MESSAGE("Testing mapping Map(pt3d_mm, pt2d_mm) and compare with expected", mitk::Equal(pt2d_mm, testpt2d_mm, 10 * mitk::eps)); std::cout << "Testing IndexToWorld(pt2d_units, pt2d_mm) and compare with expected: "; mitk::Point2D pt2d_units; pt2d_units[0] = width / 2.0; pt2d_units[1] = height / 2.0; pt2d_mm[0] = widthInMM / 2.0; pt2d_mm[1] = heightInMM / 2.0; planegeometry->IndexToWorld(pt2d_units, testpt2d_mm); std::cout << std::setprecision(12) << "Expected pt2d_mm " << pt2d_mm << std::endl; std::cout << std::setprecision(12) << "Result testpt2d_mm " << testpt2d_mm << std::endl; std::cout << std::setprecision(12) << "10*mitk::eps " << 10 * mitk::eps << std::endl; // This eps is temporarily set to 10*mitk::eps. See bug #15037 for details. CPPUNIT_ASSERT_MESSAGE("Testing IndexToWorld(pt2d_units, pt2d_mm) and compare with expected: ", mitk::Equal(pt2d_mm, testpt2d_mm, 10 * mitk::eps)); std::cout << "Testing WorldToIndex(pt2d_mm, pt2d_units) and compare with expected: "; mitk::Point2D testpt2d_units; planegeometry->WorldToIndex(pt2d_mm, testpt2d_units); std::cout << std::setprecision(12) << "Expected pt2d_units " << pt2d_units << std::endl; std::cout << std::setprecision(12) << "Result testpt2d_units " << testpt2d_units << std::endl; std::cout << std::setprecision(12) << "10*mitk::eps " << 10 * mitk::eps << std::endl; // This eps is temporarily set to 10*mitk::eps. See bug #15037 for details. CPPUNIT_ASSERT_MESSAGE("Testing WorldToIndex(pt2d_mm, pt2d_units) and compare with expected:", mitk::Equal(pt2d_units, testpt2d_units, 10 * mitk::eps)); } }; MITK_TEST_SUITE_REGISTRATION(mitkPlaneGeometry) diff --git a/Modules/Core/test/mitkPlanePositionManagerTest.cpp b/Modules/Core/test/mitkPlanePositionManagerTest.cpp index 98c49de80a..0261f58e7a 100644 --- a/Modules/Core/test/mitkPlanePositionManagerTest.cpp +++ b/Modules/Core/test/mitkPlanePositionManagerTest.cpp @@ -1,272 +1,272 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkBaseProperty.h" #include "mitkDataNode.h" #include "mitkGeometry3D.h" #include "mitkImage.h" #include "mitkInteractionConst.h" #include "mitkPlaneGeometry.h" #include "mitkPlanePositionManager.h" #include "mitkRotationOperation.h" #include "mitkSliceNavigationController.h" #include "mitkStandaloneDataStorage.h" #include "mitkStringProperty.h" #include "mitkSurface.h" #include "mitkTestingMacros.h" #include "usGetModuleContext.h" #include "usModuleContext.h" #include "usServiceReference.h" #include "vnl/vnl_vector.h" std::vector m_Geometries; std::vector m_SliceIndices; mitk::PlanePositionManagerService *m_Service; int SetUpBeforeTest() { // Getting Service us::ServiceReference serviceRef = us::GetModuleContext()->GetServiceReference(); m_Service = us::GetModuleContext()->GetService(serviceRef); if (m_Service == nullptr) return EXIT_FAILURE; // Creating different Geometries m_Geometries.reserve(100); - mitk::PlaneGeometry::PlaneOrientation views[] = { - mitk::PlaneGeometry::Axial, mitk::PlaneGeometry::Sagittal, mitk::PlaneGeometry::Coronal}; + mitk::AnatomicalPlane views[] = { + mitk::AnatomicalPlane::Axial, mitk::AnatomicalPlane::Sagittal, mitk::AnatomicalPlane::Coronal}; for (unsigned int i = 0; i < 100; ++i) { mitk::PlaneGeometry::Pointer plane = mitk::PlaneGeometry::New(); mitk::ScalarType width = 256 + (0.01 * i); mitk::ScalarType height = 256 + (0.002 * i); mitk::Vector3D right; mitk::Vector3D down; right[0] = 1; right[1] = i; right[2] = 0.5; down[0] = i * 0.02; down[1] = 1; down[2] = i * 0.03; mitk::Vector3D spacing; mitk::FillVector3D(spacing, 1.0 * 0.02 * i, 1.0 * 0.15 * i, 1.0); mitk::Vector3D rightVector; mitk::FillVector3D(rightVector, 0.02 * (i + 1), 0 + (0.05 * i), 1.0); mitk::Vector3D downVector; mitk::FillVector3D(downVector, 1, 3 - 0.01 * i, 0.0345 * i); vnl_vector normal = vnl_cross_3d(rightVector.GetVnlVector(), downVector.GetVnlVector()); normal.normalize(); normal *= 1.5; mitk::Vector3D origin; origin.Fill(1); origin[0] = 12 + 0.03 * i; mitk::AffineTransform3D::Pointer transform = mitk::AffineTransform3D::New(); mitk::Matrix3D matrix; matrix.GetVnlMatrix().set_column(0, rightVector.GetVnlVector()); matrix.GetVnlMatrix().set_column(1, downVector.GetVnlVector()); matrix.GetVnlMatrix().set_column(2, normal); transform->SetMatrix(matrix); transform->SetOffset(origin); plane->InitializeStandardPlane(width, height, transform, views[i % 3], i, true, false); m_Geometries.push_back(plane); } return EXIT_SUCCESS; } int testAddPlanePosition() { MITK_TEST_OUTPUT(<< "Starting Test: ######### A d d P l a n e P o s i t i o n #########"); MITK_TEST_CONDITION(m_Service != nullptr, "Testing getting of PlanePositionManagerService"); unsigned int currentID(m_Service->AddNewPlanePosition(m_Geometries.at(0), 0)); bool error = ((m_Service->GetNumberOfPlanePositions() != 1) || (currentID != 0)); if (error) { MITK_TEST_CONDITION(m_Service->GetNumberOfPlanePositions() == 1, "Checking for correct number of planepositions"); MITK_TEST_CONDITION(currentID == 0, "Testing for correct ID"); return EXIT_FAILURE; } // Adding new planes for (unsigned int i = 1; i < m_Geometries.size(); ++i) { unsigned int newID = m_Service->AddNewPlanePosition(m_Geometries.at(i), i); error = ((m_Service->GetNumberOfPlanePositions() != i + 1) || (newID != (currentID + 1))); if (error) { MITK_TEST_CONDITION(m_Service->GetNumberOfPlanePositions() == i + 1, "Checking for correct number of planepositions"); MITK_TEST_CONDITION(newID == (currentID + 1), "Testing for correct ID"); MITK_TEST_OUTPUT(<< "New: " << newID << " Last: " << currentID); return EXIT_FAILURE; } currentID = newID; } unsigned int numberOfPlanePos = m_Service->GetNumberOfPlanePositions(); // Adding existing planes -> nothing should change for (unsigned int i = 0; i < (m_Geometries.size() - 1) * 0.5; ++i) { unsigned int newID = m_Service->AddNewPlanePosition(m_Geometries.at(i * 2), i * 2); error = ((m_Service->GetNumberOfPlanePositions() != numberOfPlanePos) || (newID != i * 2)); if (error) { MITK_TEST_CONDITION(m_Service->GetNumberOfPlanePositions() == numberOfPlanePos, "Checking for correct number of planepositions"); MITK_TEST_CONDITION(newID == i * 2, "Testing for correct ID"); return EXIT_FAILURE; } } return EXIT_SUCCESS; } int testGetPlanePosition() { bool error(true); MITK_TEST_OUTPUT(<< "Starting Test: ######### G e t P l a n e P o s i t i o n #########"); // Testing for existing planepositions for (unsigned int i = 0; i < m_Geometries.size(); ++i) { auto plane = m_Geometries.at(i); auto op = m_Service->GetPlanePosition(i); error = (!mitk::Equal(op->GetHeight(), plane->GetExtent(1)) || !mitk::Equal(op->GetWidth(), plane->GetExtent(0)) || !mitk::Equal(op->GetSpacing(), plane->GetSpacing()) || !mitk::Equal(op->GetTransform()->GetOffset(), plane->GetIndexToWorldTransform()->GetOffset()) || !mitk::Equal(op->GetDirectionVector().GetVnlVector(), plane->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(2).normalize().as_ref()) || !mitk::MatrixEqualElementWise(op->GetTransform()->GetMatrix(), plane->GetIndexToWorldTransform()->GetMatrix())); if (error) { MITK_TEST_OUTPUT(<< "Iteration: " << i) MITK_TEST_CONDITION( mitk::Equal(op->GetHeight(), plane->GetExtent(1)) && mitk::Equal(op->GetWidth(), plane->GetExtent(0)), "Checking for correct extent"); MITK_TEST_CONDITION(mitk::Equal(op->GetSpacing(), plane->GetSpacing()), "Checking for correct spacing"); MITK_TEST_CONDITION(mitk::Equal(op->GetTransform()->GetOffset(), plane->GetIndexToWorldTransform()->GetOffset()), "Checking for correct offset"); MITK_INFO << "Op: " << op->GetDirectionVector() << " plane: " << plane->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(2) << "\n"; MITK_TEST_CONDITION(mitk::Equal(op->GetDirectionVector().GetVnlVector(), plane->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(2).as_ref()), "Checking for correct direction"); MITK_TEST_CONDITION( mitk::MatrixEqualElementWise(op->GetTransform()->GetMatrix(), plane->GetIndexToWorldTransform()->GetMatrix()), "Checking for correct matrix"); return EXIT_FAILURE; } } // Testing for not existing planepositions error = (m_Service->GetPlanePosition(100000000) != nullptr || m_Service->GetPlanePosition(-1) != nullptr); if (error) { MITK_TEST_CONDITION(m_Service->GetPlanePosition(100000000) == nullptr, "Trying to get non existing pos"); MITK_TEST_CONDITION(m_Service->GetPlanePosition(-1) == nullptr, "Trying to get non existing pos"); return EXIT_FAILURE; } return EXIT_SUCCESS; } int testRemovePlanePosition() { MITK_TEST_OUTPUT(<< "Starting Test: ######### R e m o v e P l a n e P o s i t i o n #########"); unsigned int size = m_Service->GetNumberOfPlanePositions(); // Testing for invalid IDs bool removed = m_Service->RemovePlanePosition(-1); removed = m_Service->RemovePlanePosition(1000000); unsigned int size2 = m_Service->GetNumberOfPlanePositions(); if (removed) { MITK_TEST_CONDITION(removed == false, "Testing remove not existing planepositions"); MITK_TEST_CONDITION(size == size2, "Testing remove not existing planepositions"); return EXIT_FAILURE; } // Testing for valid IDs for (unsigned int i = 0; i < m_Geometries.size() * 0.5; i++) { removed = m_Service->RemovePlanePosition(i); unsigned int size2 = m_Service->GetNumberOfPlanePositions(); removed = (size2 == (size - (i + 1))); if (!removed) { MITK_TEST_CONDITION(removed == true, "Testing remove existing planepositions"); MITK_TEST_CONDITION(size == (size - i + 1), "Testing remove existing planepositions"); return EXIT_FAILURE; } } return EXIT_SUCCESS; } int testRemoveAll() { MITK_TEST_OUTPUT(<< "Starting Test: ######### R e m o v e A l l #########"); unsigned int numPos = m_Service->GetNumberOfPlanePositions(); MITK_INFO << numPos; m_Service->RemoveAllPlanePositions(); bool error(true); error = (m_Service->GetNumberOfPlanePositions() != 0 || m_Service->GetPlanePosition(60) != nullptr); if (error) { MITK_TEST_CONDITION(m_Service->GetNumberOfPlanePositions() == 0, "Testing remove all pos"); MITK_TEST_CONDITION(m_Service->GetPlanePosition(60) == nullptr, "Testing remove all pos"); return EXIT_FAILURE; } return EXIT_SUCCESS; } int mitkPlanePositionManagerTest(int, char *[]) { MITK_TEST_BEGIN("PlanePositionManager"); SetUpBeforeTest(); int result; MITK_TEST_CONDITION_REQUIRED((result = testAddPlanePosition()) == EXIT_SUCCESS, ""); MITK_TEST_CONDITION_REQUIRED((result = testGetPlanePosition()) == EXIT_SUCCESS, ""); MITK_TEST_CONDITION_REQUIRED((result = testRemovePlanePosition()) == EXIT_SUCCESS, ""); MITK_TEST_CONDITION_REQUIRED((result = testRemoveAll()) == EXIT_SUCCESS, ""); MITK_TEST_END(); } diff --git a/Modules/Core/test/mitkPointSetVtkMapper2DGlyphTypeTest.cpp b/Modules/Core/test/mitkPointSetVtkMapper2DGlyphTypeTest.cpp index 72a37f47bd..f2bc7a5321 100644 --- a/Modules/Core/test/mitkPointSetVtkMapper2DGlyphTypeTest.cpp +++ b/Modules/Core/test/mitkPointSetVtkMapper2DGlyphTypeTest.cpp @@ -1,67 +1,66 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // MITK #include "mitkRenderingTestHelper.h" #include "mitkTestingMacros.h" #include #include #include #include // VTK #include int mitkPointSetVtkMapper2DGlyphTypeTest(int argc, char *argv[]) { try { mitk::RenderingTestHelper openGlTest(640, 480); } catch (const mitk::TestNotRunException &e) { MITK_WARN << "Test not run: " << e.GetDescription(); return 77; } // load all arguments into a datastorage, take last argument as reference rendering // setup a renderwindow of fixed size X*Y // render the datastorage // compare rendering to reference image MITK_TEST_BEGIN("mitkPointSetVtkMapper2DGlyphTypeTest") mitk::RenderingTestHelper renderingHelper(640, 480, argc, argv); - - renderingHelper.SetViewDirection(mitk::SliceNavigationController::Sagittal); + renderingHelper.SetViewDirection(mitk::AnatomicalPlane::Sagittal); mitk::EnumerationProperty *eP = dynamic_cast(renderingHelper.GetDataStorage() ->GetNode(mitk::NodePredicateDataType::New("PointSet")) ->GetProperty("Pointset.2D.shape")); // render triangles instead of crosses eP->SetValue(5); // disables anti-aliasing which is enabled on several graphics cards and // causes problems when doing a pixel-wise comparison to a reference image renderingHelper.GetVtkRenderWindow()->SetMultiSamples(0); //### Usage of CompareRenderWindowAgainstReference: See docu of mitkRrenderingTestHelper MITK_TEST_CONDITION(renderingHelper.CompareRenderWindowAgainstReference(argc, argv) == true, "CompareRenderWindowAgainstReference test result positive?"); // use this to generate a reference screenshot or save the file: if (false) { renderingHelper.SaveReferenceScreenShot("C:/development_ITK4/output.png"); } MITK_TEST_END(); } diff --git a/Modules/Core/test/mitkPointSetVtkMapper2DTest.cpp b/Modules/Core/test/mitkPointSetVtkMapper2DTest.cpp index e7fbd73671..ba2605b6b2 100644 --- a/Modules/Core/test/mitkPointSetVtkMapper2DTest.cpp +++ b/Modules/Core/test/mitkPointSetVtkMapper2DTest.cpp @@ -1,57 +1,55 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // MITK #include "mitkRenderingTestHelper.h" #include "mitkTestingMacros.h" // VTK #include int mitkPointSetVtkMapper2DTest(int argc, char *argv[]) { try { mitk::RenderingTestHelper openGlTest(640, 480); } catch (const mitk::TestNotRunException &e) { MITK_WARN << "Test not run: " << e.GetDescription(); return 77; } // load all arguments into a datastorage, take last argument as reference rendering // setup a renderwindow of fixed size X*Y // render the datastorage // compare rendering to reference image MITK_TEST_BEGIN("mitkPointSetVtkMapper2DTest") mitk::RenderingTestHelper renderingHelper(640, 480, argc, argv); - - // sagittal view direction - renderingHelper.SetViewDirection(mitk::SliceNavigationController::Sagittal); + renderingHelper.SetViewDirection(mitk::AnatomicalPlane::Sagittal); // disables anti-aliasing which is enabled on several graphics cards and // causes problems when doing a pixel-wise comparison to a reference image renderingHelper.GetVtkRenderWindow()->SetMultiSamples(0); //### Usage of CompareRenderWindowAgainstReference: See docu of mitkRrenderingTestHelper MITK_TEST_CONDITION(renderingHelper.CompareRenderWindowAgainstReference(argc, argv) == true, "CompareRenderWindowAgainstReference test result positive?"); // use this to generate a reference screenshot or save the file: if (false) { renderingHelper.SaveReferenceScreenShot("C:/development_ITK4/output.png"); } MITK_TEST_END(); } diff --git a/Modules/Core/test/mitkPointSetVtkMapper2DTransformedPointsTest.cpp b/Modules/Core/test/mitkPointSetVtkMapper2DTransformedPointsTest.cpp index 66704a596c..d232848324 100644 --- a/Modules/Core/test/mitkPointSetVtkMapper2DTransformedPointsTest.cpp +++ b/Modules/Core/test/mitkPointSetVtkMapper2DTransformedPointsTest.cpp @@ -1,76 +1,76 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // MITK #include "mitkRenderingTestHelper.h" #include "mitkTestingMacros.h" #include #include #include #include // VTK #include int mitkPointSetVtkMapper2DTransformedPointsTest(int argc, char *argv[]) { try { mitk::RenderingTestHelper openGlTest(640, 480); } catch (const mitk::TestNotRunException &e) { MITK_WARN << "Test not run: " << e.GetDescription(); return 77; } // load all arguments into a datastorage, take last argument as reference rendering // setup a renderwindow of fixed size X*Y // render the datastorage // compare rendering to reference image MITK_TEST_BEGIN("mitkPointSetVtkMapper2DTransformedPointsTest") mitk::RenderingTestHelper renderingHelper(640, 480, argc, argv); - renderingHelper.SetViewDirection(mitk::SliceNavigationController::Sagittal); + renderingHelper.SetViewDirection(mitk::AnatomicalPlane::Sagittal); mitk::DataNode *dataNode = renderingHelper.GetDataStorage()->GetNode(mitk::NodePredicateDataType::New("PointSet")); if (dataNode) { mitk::PointSet::Pointer pointSet = dynamic_cast(dataNode->GetData()); if (pointSet) { mitk::Point3D origin = pointSet->GetGeometry()->GetOrigin(); origin[1] += 10; origin[2] += 15; pointSet->GetGeometry()->SetOrigin(origin); pointSet->Modified(); dataNode->Update(); } } //### Usage of CompareRenderWindowAgainstReference: See docu of mitkRenderingTestHelper MITK_TEST_CONDITION(renderingHelper.CompareRenderWindowAgainstReference(argc, argv) == true, "CompareRenderWindowAgainstReference test result positive?"); // use this to generate a reference screenshot or save the file: if (false) { renderingHelper.SaveReferenceScreenShot("D:/test/output.png"); } MITK_TEST_END(); } diff --git a/Modules/Core/test/mitkRotatedSlice4DTest.cpp b/Modules/Core/test/mitkRotatedSlice4DTest.cpp index 22da8a8bfa..1dad8af769 100644 --- a/Modules/Core/test/mitkRotatedSlice4DTest.cpp +++ b/Modules/Core/test/mitkRotatedSlice4DTest.cpp @@ -1,84 +1,84 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkExtractSliceFilter.h" #include "mitkIOUtil.h" #include "mitkImagePixelReadAccessor.h" #include "mitkImageTimeSelector.h" #include "mitkInteractionConst.h" #include "mitkRotationOperation.h" #include "mitkTestingMacros.h" #include /* * The mitkRotatedSlice4DTest loads a 4D image and extracts a specifically rotated slice in each time step's volume. */ int mitkRotatedSlice4DTest(int, char *argv[]) { MITK_TEST_BEGIN("mitkRotatedSlice4DTest"); std::string filename = argv[1]; // load 4D image mitk::Image::Pointer image4D = mitk::IOUtil::Load(filename); // check inputs if (image4D.IsNull()) { MITK_INFO << "Could not load the file"; return false; } auto numTimeSteps = std::min(2, static_cast(image4D->GetTimeSteps())); for (int ts = 0; ts < numTimeSteps; ++ts) { mitk::ImageTimeSelector::Pointer timeSelector = mitk::ImageTimeSelector::New(); timeSelector->SetInput(image4D); timeSelector->SetTimeNr(ts); timeSelector->Update(); mitk::Image::Pointer image3D = timeSelector->GetOutput(); int sliceNumber = std::min(5, static_cast(image3D->GetSlicedGeometry()->GetSlices())); mitk::PlaneGeometry::Pointer plane = mitk::PlaneGeometry::New(); - plane->InitializeStandardPlane(image3D->GetGeometry(), mitk::PlaneGeometry::Coronal, sliceNumber, true, false); + plane->InitializeStandardPlane(image3D->GetGeometry(), mitk::AnatomicalPlane::Coronal, sliceNumber, true, false); // rotate about an arbitrary point and axis... float angle = 30; mitk::Point3D point; point.Fill(sliceNumber); mitk::Vector3D rotationAxis; rotationAxis[0] = 1; rotationAxis[1] = 2; rotationAxis[2] = 3; rotationAxis.Normalize(); // Create Rotation Operation auto *op = new mitk::RotationOperation(mitk::OpROTATE, point, rotationAxis, angle); plane->ExecuteOperation(op); delete op; // Now extract mitk::ExtractSliceFilter::Pointer extractor = mitk::ExtractSliceFilter::New(); extractor->SetInput(image3D); extractor->SetWorldGeometry(plane); extractor->Update(); mitk::Image::Pointer extractedPlane; extractedPlane = extractor->GetOutput(); std::stringstream ss; ss << " : Valid slice in timestep " << ts; MITK_TEST_CONDITION_REQUIRED(extractedPlane.IsNotNull(), ss.str().c_str()); } MITK_TEST_END(); } diff --git a/Modules/Core/test/mitkSliceNavigationControllerTest.cpp b/Modules/Core/test/mitkSliceNavigationControllerTest.cpp index 3cae978167..a546ced931 100644 --- a/Modules/Core/test/mitkSliceNavigationControllerTest.cpp +++ b/Modules/Core/test/mitkSliceNavigationControllerTest.cpp @@ -1,196 +1,196 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include #include #include #include #include #include // T22254 class mitkSliceNavigationControllerTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkSliceNavigationControllerTestSuite); CPPUNIT_TEST(validateAxialViewDirection); CPPUNIT_TEST(validateCoronalViewDirection); CPPUNIT_TEST(validateSagittalViewDirection); CPPUNIT_TEST(GetSelectedTimePoint); CPPUNIT_TEST_SUITE_END(); mitk::Geometry3D::Pointer m_Geometry3D; mitk::ArbitraryTimeGeometry::Pointer m_TimeGeometry; public: void setUp() override { mitk::Point3D origin; mitk::FillVector3D(origin, 10.0, 20.0, 30.0); mitk::Vector3D firstAxisVector; mitk::FillVector3D(firstAxisVector, 100.0, 0.0, 0.0); mitk::Vector3D secondAxisVector; mitk::FillVector3D(secondAxisVector, 0.0, 50.0, 0.0); mitk::Vector3D spacing; mitk::FillVector3D(spacing, 1.0, 1.0, 2.0); auto planeGeometry = mitk::PlaneGeometry::New(); planeGeometry->InitializeStandardPlane(firstAxisVector, secondAxisVector, &spacing); planeGeometry->SetOrigin(origin); unsigned int numberOfSlices = 100U; auto slicedGeometry3D = mitk::SlicedGeometry3D::New(); slicedGeometry3D->InitializeEvenlySpaced(planeGeometry, numberOfSlices); m_Geometry3D = mitk::Geometry3D::New(); m_Geometry3D->SetBounds(slicedGeometry3D->GetBounds()); m_Geometry3D->SetIndexToWorldTransform(slicedGeometry3D->GetIndexToWorldTransform()); m_TimeGeometry = mitk::ArbitraryTimeGeometry::New(); m_TimeGeometry->AppendNewTimeStepClone(m_Geometry3D, 0.5, 10.); m_TimeGeometry->AppendNewTimeStepClone(m_Geometry3D, 10., 30.); m_TimeGeometry->AppendNewTimeStepClone(m_Geometry3D, 30., 50.); m_TimeGeometry->AppendNewTimeStepClone(m_Geometry3D, 50., 60.); m_TimeGeometry->Update(); } void tearDown() override { } void validateAxialViewDirection() { auto sliceNavigationController = mitk::SliceNavigationController::New(); sliceNavigationController->SetInputWorldTimeGeometry(m_TimeGeometry); - sliceNavigationController->SetViewDirection(mitk::SliceNavigationController::Axial); + sliceNavigationController->SetViewDirection(mitk::AnatomicalPlane::Axial); sliceNavigationController->Update(); mitk::Point3D origin; mitk::FillVector3D(origin, 10.0, 70.0, 229.0); mitk::Vector3D firstAxisVector; mitk::FillVector3D(firstAxisVector, 100.0, 0.0, 0.0); mitk::Vector3D secondAxisVector; mitk::FillVector3D(secondAxisVector, 0.0, -50.0, 0.0); mitk::Vector3D thirdAxisVector; mitk::FillVector3D(thirdAxisVector, 0.0, 0.0, -200.0); std::cout << "Axial view direction" << std::endl; CPPUNIT_ASSERT(this->validateGeometry(sliceNavigationController->GetCurrentGeometry3D(), origin, firstAxisVector, secondAxisVector, thirdAxisVector)); } void validateCoronalViewDirection() { auto sliceNavigationController = mitk::SliceNavigationController::New(); sliceNavigationController->SetInputWorldTimeGeometry(m_TimeGeometry); - sliceNavigationController->SetViewDirection(mitk::SliceNavigationController::Coronal); + sliceNavigationController->SetViewDirection(mitk::AnatomicalPlane::Coronal); sliceNavigationController->Update(); mitk::Point3D origin; mitk::FillVector3D(origin, 10.0, 69.5, 30.0); mitk::Vector3D firstAxisVector; mitk::FillVector3D(firstAxisVector, 100.0, 0.0, 0.0); mitk::Vector3D secondAxisVector; mitk::FillVector3D(secondAxisVector, 0.0, 0.0, 200.0); mitk::Vector3D thirdAxisVector; mitk::FillVector3D(thirdAxisVector, 0.0, -50.0, 0.0); std::cout << "Coronal view direction" << std::endl; CPPUNIT_ASSERT(this->validateGeometry(sliceNavigationController->GetCurrentGeometry3D(), origin, firstAxisVector, secondAxisVector, thirdAxisVector)); } void validateSagittalViewDirection() { auto sliceNavigationController = mitk::SliceNavigationController::New(); sliceNavigationController->SetInputWorldTimeGeometry(m_TimeGeometry); - sliceNavigationController->SetViewDirection(mitk::SliceNavigationController::Sagittal); + sliceNavigationController->SetViewDirection(mitk::AnatomicalPlane::Sagittal); sliceNavigationController->Update(); mitk::Point3D origin; mitk::FillVector3D(origin, 10.5, 20.0, 30.0); mitk::Vector3D firstAxisVector; mitk::FillVector3D(firstAxisVector, 0.0, 50.0, 0.0); mitk::Vector3D secondAxisVector; mitk::FillVector3D(secondAxisVector, 0.0, 0.0, 200.0); mitk::Vector3D thirdAxisVector; mitk::FillVector3D(thirdAxisVector, 100.0, 0.0, 0.0); std::cout << "Sagittal view direction" << std::endl; CPPUNIT_ASSERT(this->validateGeometry(sliceNavigationController->GetCurrentGeometry3D(), origin, firstAxisVector, secondAxisVector, thirdAxisVector)); } void GetSelectedTimePoint() { auto sliceNavigationController = mitk::SliceNavigationController::New(); CPPUNIT_ASSERT(sliceNavigationController->GetSelectedTimePoint() == 0.); sliceNavigationController->SetInputWorldTimeGeometry(m_TimeGeometry); - sliceNavigationController->SetViewDirection(mitk::SliceNavigationController::Sagittal); + sliceNavigationController->SetViewDirection(mitk::AnatomicalPlane::Sagittal); sliceNavigationController->Update(); CPPUNIT_ASSERT(sliceNavigationController->GetSelectedTimeStep() == 0); CPPUNIT_ASSERT(sliceNavigationController->GetSelectedTimePoint() == 0.5); sliceNavigationController->GetTime()->SetPos(2); CPPUNIT_ASSERT(sliceNavigationController->GetSelectedTimeStep() == 2); CPPUNIT_ASSERT(sliceNavigationController->GetSelectedTimePoint() == 30.0); } private: bool validateGeometry(mitk::BaseGeometry::ConstPointer geometry, const mitk::Point3D &origin, const mitk::Vector3D &firstAxisVector, const mitk::Vector3D &secondAxisVector, const mitk::Vector3D &thirdAxisVector) { bool result = true; std::cout << " Origin" << std::endl; if (!mitk::Equal(geometry->GetOrigin(), origin, mitk::eps, true)) result = false; std::cout << " First axis vector" << std::endl; if (!mitk::Equal(geometry->GetAxisVector(0), firstAxisVector, mitk::eps, true)) result = false; std::cout << " Second axis vector" << std::endl; if (!mitk::Equal(geometry->GetAxisVector(1), secondAxisVector, mitk::eps, true)) result = false; std::cout << " Third axis vector" << std::endl; if (!mitk::Equal(geometry->GetAxisVector(2), thirdAxisVector, mitk::eps, true)) result = false; return result; } }; MITK_TEST_SUITE_REGISTRATION(mitkSliceNavigationController) diff --git a/Modules/Core/test/mitkSurfaceVtkMapper2D3DTest.cpp b/Modules/Core/test/mitkSurfaceVtkMapper2D3DTest.cpp index 92181e5bd0..9e0e5efa05 100644 --- a/Modules/Core/test/mitkSurfaceVtkMapper2D3DTest.cpp +++ b/Modules/Core/test/mitkSurfaceVtkMapper2D3DTest.cpp @@ -1,156 +1,156 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // MITK #include #include #include #include #include #include // VTK #include #include #include /** A couple of tests around Surface rendering with lookup tables (LUT). */ class mitkSurfaceVtkMapper2D3DTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkSurfaceVtkMapper2D3DTestSuite); MITK_TEST(RenderLUT2D); MITK_TEST(RenderLUT3D); CPPUNIT_TEST_SUITE_END(); private: /** Members used inside the different test methods. All members are initialized via setUp().*/ mitk::RenderingTestHelper m_RenderingTestHelper; std::vector m_CommandlineArgs; std::string m_PathToBall; public: /** * @brief mitkSurfaceVtkMapper2D3DTestSuite Because the RenderingTestHelper does not have an * empty default constructor, we need this constructor to initialize the helper with a * resolution. */ mitkSurfaceVtkMapper2D3DTestSuite() : m_RenderingTestHelper(300, 300) {} /** * @brief Setup Initialize a fresh rendering test helper and a vector of strings * to simulate commandline arguments for vtkTesting::Test. */ void setUp() { m_RenderingTestHelper = mitk::RenderingTestHelper(300, 300); m_PathToBall = GetTestDataFilePath("ball.stl"); // Build a command line for the vtkTesting::Test method. // See VTK documentation and RenderingTestHelper for more information. // Use the following command line option to save the difference image // and the test image in some tmp folder // m_CommandlineArgs.push_back("-T"); // m_CommandlineArgs.push_back("/path/to/save/tmp/difference/images/"); m_CommandlineArgs.push_back("-V"); } void tearDown() {} // Helper method to prepare a DataNode holding a mitk::Surface // for rendering of point scalars via a lookup table (LUT). void PrepareSurfaceRenderingWithLUT(mitk::DataNode &node) { mitk::Surface::Pointer surface = dynamic_cast(node.GetData()); CPPUNIT_ASSERT(surface); vtkPolyData *polydata = surface->GetVtkPolyData(); CPPUNIT_ASSERT(polydata); // Build lookup table entries, associate to points of vtkPolyData vtkSmartPointer data_array = vtkSmartPointer::New(); data_array->Initialize(); data_array->SetName("Funny LUT entries"); data_array->SetNumberOfComponents(1); auto num_points = polydata->GetNumberOfPoints(); // initialize all points in polydata data_array->SetNumberOfTuples(num_points); for (unsigned int index = 0; index != num_points; ++index) { // just assign values 0..4 to points // (value 0 for point idx 0..249, value 1 for idx 250..499, etc.) data_array->SetValue(index, (index / 250) % 5); // values 0 .. 4 } polydata->GetPointData()->SetScalars(data_array); mitk::LookupTable::Pointer mitk_lut = mitk::LookupTable::New(); node.SetProperty("LookupTable", mitk::LookupTableProperty::New(mitk_lut)); node.SetBoolProperty("scalar visibility", true); node.SetBoolProperty("color mode", true); node.SetFloatProperty("ScalarsRangeMinimum", 0); node.SetFloatProperty("ScalarsRangeMaximum", 3); // build the lut vtkSmartPointer vtk_lut = mitk_lut->GetVtkLookupTable(); if (vtk_lut == nullptr) { vtk_lut = vtkSmartPointer::New(); mitk_lut->SetVtkLookupTable(vtk_lut); } // Define the lookup table. vtk_lut->SetTableRange(0, 3); vtk_lut->SetNumberOfTableValues(4); vtk_lut->SetTableValue(0, 1, 0, 0); vtk_lut->SetTableValue(1, 0, 1, 0); vtk_lut->SetTableValue(2, 0, 0, 1); vtk_lut->SetTableValue(3, 1, 1, 0); vtk_lut->Build(); } void RenderLUT2D() { mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(mitk::IOUtil::Load(m_PathToBall)[0]); PrepareSurfaceRenderingWithLUT(*node); m_RenderingTestHelper.AddNodeToStorage(node); // reference screenshot for this test m_CommandlineArgs.push_back(GetTestDataFilePath("RenderingTestData/ReferenceScreenshots/ballLUT2D_300x300.png")); // Convert vector of strings to argc/argv mitk::RenderingTestHelper::ArgcHelperClass arg(m_CommandlineArgs); - m_RenderingTestHelper.SetViewDirection(mitk::SliceNavigationController::Sagittal); + m_RenderingTestHelper.SetViewDirection(mitk::AnatomicalPlane::Sagittal); CPPUNIT_ASSERT(m_RenderingTestHelper.CompareRenderWindowAgainstReference(arg.GetArgc(), arg.GetArgv()) == true); } void RenderLUT3D() { mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(mitk::IOUtil::Load(m_PathToBall)[0]); PrepareSurfaceRenderingWithLUT(*node); m_RenderingTestHelper.AddNodeToStorage(node); // reference screenshot for this test m_CommandlineArgs.push_back(GetTestDataFilePath("RenderingTestData/ReferenceScreenshots/ballLUT3D_300x300.png")); // Convert vector of strings to argc/argv mitk::RenderingTestHelper::ArgcHelperClass arg(m_CommandlineArgs); m_RenderingTestHelper.SetMapperIDToRender3D(); CPPUNIT_ASSERT(m_RenderingTestHelper.CompareRenderWindowAgainstReference(arg.GetArgc(), arg.GetArgv(), 50.0) == true); // m_RenderingTestHelper.SaveReferenceScreenShot("c:/dev/ballLUT3D_300x300.png"); } }; MITK_TEST_SUITE_REGISTRATION(mitkSurfaceVtkMapper2D3D) diff --git a/Modules/IGT/Rendering/mitkNavigationDataSliceVisualization.cpp b/Modules/IGT/Rendering/mitkNavigationDataSliceVisualization.cpp index afa4447a0b..3b9f8f745a 100644 --- a/Modules/IGT/Rendering/mitkNavigationDataSliceVisualization.cpp +++ b/Modules/IGT/Rendering/mitkNavigationDataSliceVisualization.cpp @@ -1,219 +1,219 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkNavigationDataSliceVisualization.h" #include "mitkBaseRenderer.h" mitk::NavigationDataSliceVisualization::NavigationDataSliceVisualization() : mitk::NavigationDataToNavigationDataFilter(), m_Renderer(nullptr), m_ViewDirection(Axial) { m_TipOffset[0] = 0.0f; m_TipOffset[1] = 0.0f; m_TipOffset[2] = 0.0f; m_ToolTrajectory[0] = 0; m_ToolTrajectory[1] = 0; m_ToolTrajectory[2] = -1; m_WorldVerticalVector[0] = 0.0; m_WorldVerticalVector[1] = 1.0; m_WorldVerticalVector[2] = 0.0; } void mitk::NavigationDataSliceVisualization::SetToolTrajectory(Vector3D direction) { if (Equal(direction.GetNorm(), 0.0)) { MITK_WARN << "Ignoring invalid direction of projection: " << direction; return; } if (m_ToolTrajectory != direction) { m_ToolTrajectory = direction; this->SetViewDirection(Oblique); this->Modified(); } } void mitk::NavigationDataSliceVisualization::GenerateData() { // check if renderer was set if (m_Renderer.IsNull()) { itkExceptionMacro(<< "Renderer was not properly set"); } /* update outputs with tracking data from tools */ unsigned int numberOfInputs = this->GetNumberOfInputs(); if (numberOfInputs == 0) { return; } for (unsigned int i = 0; i < numberOfInputs ; ++i) { NavigationData* output = this->GetOutput(i); assert(output); const NavigationData* input = this->GetInput(i); assert(input); if (!input->IsDataValid()) continue; output->Graft(input); // First, copy all information from input to output } // Nothing left to do if we don't have an input with valid data if (numberOfInputs == 0 || !this->GetInput()->IsDataValid()) return; // get position from NavigationData to move the slice to this position Point3D slicePosition = this->GetInput()->GetPosition(); { NavigationData::OrientationType orientation = this->GetInput()->GetOrientation(); Vector3D transformedTipOffset; transformedTipOffset.SetVnlVector(orientation.rotate(m_TipOffset.GetVnlVector()).as_ref()); slicePosition += transformedTipOffset; mitk::SliceNavigationController::Pointer snc = m_Renderer->GetSliceNavigationController(); if (Axial == m_ViewDirection) { - snc->SetViewDirection(mitk::SliceNavigationController::Axial); + snc->SetViewDirection(mitk::AnatomicalPlane::Axial); snc->SelectSliceByPoint(slicePosition); } else if (Sagittal == m_ViewDirection) { - snc->SetViewDirection(mitk::SliceNavigationController::Sagittal); + snc->SetViewDirection(mitk::AnatomicalPlane::Sagittal); snc->SelectSliceByPoint(slicePosition); } else if (Coronal == m_ViewDirection) { - snc->SetViewDirection(mitk::SliceNavigationController::Coronal); + snc->SetViewDirection(mitk::AnatomicalPlane::Coronal); snc->SelectSliceByPoint(slicePosition); } else if (AxialOblique == m_ViewDirection || SagittalOblique == m_ViewDirection) { const int slicingPlaneXAxis = AxialOblique == m_ViewDirection ? 0 : 2; // The column 0 is the slicing plane's x-axis, column 1 is the slicing plane's y-axis const mitk::PlaneGeometry::TransformType::MatrixType &m = m_Renderer->GetCurrentWorldPlaneGeometry()->GetIndexToWorldTransform()->GetMatrix(); // Rotate the tool trajectory vector into world coordinate frame (assuming // NavigationData has passed through a NavigationDataTransformFilter to // convert it into world coordinate frame) Vector3D slicingPlaneYAxisVector; slicingPlaneYAxisVector.SetVnlVector(orientation.rotate(m_ToolTrajectory.GetVnlVector()).as_ref()); // Project the tool trajectory onto the plane normal to x-axis of this // oblique slicing. This defines the y-axis ("up") of the oblique slicing // plane slicingPlaneYAxisVector[slicingPlaneXAxis] = 0.0; // Do nothing for ambigous/undefined cases: // - the R-L component of the x-axis is zero (for AxialOblique) // - the S-I component of the x-axis is zero (for SagittalOblique) // - the A-P component of the y-axis is zero if ( m(slicingPlaneXAxis,0) == 0.0 || m(1,1) == 0.0 || (slicingPlaneXAxis != 0 && slicingPlaneYAxisVector[0] == 0.0) || (slicingPlaneXAxis != 1 && slicingPlaneYAxisVector[1] == 0.0) || (slicingPlaneXAxis != 2 && slicingPlaneYAxisVector[2] == 0.0) ) { return; } // Maintain the A-P orientation of the slice's y-axis regardless of what // direction the tool trajectory points /// @todo Use std::signbit if ( (m(1,1) > 0) != (slicingPlaneYAxisVector[1] > 0) ) { slicingPlaneYAxisVector *= -1; } Vector3D slicingPlaneXAxisVector; slicingPlaneXAxisVector.Fill(0.0); // For AxialOblique: maintain the Left/Right direction of the slice's x-axis // For SagittalOblique: maintain the Superior/Inferior direction of the slice's x-axis /// @todo Use std::copysign slicingPlaneXAxisVector[slicingPlaneXAxis] = m(slicingPlaneXAxis,0) > 0 ? 1.0 : -1.0; Point3D origin; FillVector3D(origin, 0.0, 0.0, 0.0); snc->ReorientSlices(origin, slicingPlaneXAxisVector, slicingPlaneYAxisVector); snc->SelectSliceByPoint(slicePosition); } else if (Oblique == m_ViewDirection) { Vector3D slicingPlaneNormalVector; slicingPlaneNormalVector.SetVnlVector(orientation.rotate(m_ToolTrajectory.GetVnlVector()).as_ref()); // The second column of the Index-to-World matrix is the positive y-axis // of the current slicing plane in world coordinates. const mitk::PlaneGeometry::TransformType::MatrixType &m = m_Renderer->GetCurrentWorldPlaneGeometry()->GetIndexToWorldTransform()->GetMatrix(); mitk::Vector3D currentSlicingPlaneUpVector; mitk::FillVector3D(currentSlicingPlaneUpVector, m[0][1], m[1][1], m[2][1]); mitk::Vector3D worldUpVector = m_WorldVerticalVector; if (angle(worldUpVector.GetVnlVector(), currentSlicingPlaneUpVector.GetVnlVector()) > vnl_math::pi_over_2 ) { worldUpVector *= -1; } mitk::PlaneGeometry::Pointer slicingPlane = mitk::PlaneGeometry::New(); Point3D origin; FillVector3D(origin, 0.0, 0.0, 0.0); slicingPlane->InitializePlane(origin, slicingPlaneNormalVector); // Now that we have the direction of WorldVerticalVector chosen to be the // most "up" direction, project it onto the slicing plane to define the // up vector (y-axis) of the reoriented slices mitk::Vector3D slicingPlaneUpVector; if ( slicingPlane->Project(worldUpVector, slicingPlaneUpVector) ) { // slicingPlaneUpVector CROSS slicingPlaneNormalVector -> slicingPlaneRightVector // Math is done in double precision as much as possible to get more // orthogonal right and up vectors which fixes a VNL SVD error when // the WorldGeometry matrix is later inverted itk::Vector slicingPlaneUpVector_double; FillVector3D(slicingPlaneUpVector_double, slicingPlaneUpVector[0], slicingPlaneUpVector[1], slicingPlaneUpVector[2]); itk::Vector slicingPlaneNormalVector_double; FillVector3D(slicingPlaneNormalVector_double, slicingPlaneNormalVector[0], slicingPlaneNormalVector[1], slicingPlaneNormalVector[2]); itk::Vector slicingPlaneRightVector_double = itk::CrossProduct(slicingPlaneUpVector_double, slicingPlaneNormalVector_double); mitk::Vector3D slicingPlaneRightVector; mitk::FillVector3D(slicingPlaneRightVector, slicingPlaneRightVector_double[0], slicingPlaneRightVector_double[1], slicingPlaneRightVector_double[2]); mitk::FillVector3D(slicingPlaneUpVector, slicingPlaneUpVector_double[0], slicingPlaneUpVector_double[1], slicingPlaneUpVector_double[2]); snc->ReorientSlices(origin, slicingPlaneRightVector, slicingPlaneUpVector); snc->SelectSliceByPoint(slicePosition); } } else { MITK_ERROR << "Unsupported ViewDirection: " << m_ViewDirection; } m_Renderer->RequestUpdate(); } } diff --git a/Modules/ImageExtraction/mitkExtractImageFilter.cpp b/Modules/ImageExtraction/mitkExtractImageFilter.cpp index 807fc7665c..2a754f0045 100644 --- a/Modules/ImageExtraction/mitkExtractImageFilter.cpp +++ b/Modules/ImageExtraction/mitkExtractImageFilter.cpp @@ -1,259 +1,259 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkExtractImageFilter.h" #include "mitkITKImageImport.h" #include "mitkImageCast.h" #include "mitkImageTimeSelector.h" #include "mitkPlaneGeometry.h" #include #include mitk::ExtractImageFilter::ExtractImageFilter() : m_SliceIndex(0), m_SliceDimension(0), m_TimeStep(0), m_DirectionCollapseToStrategy(DIRECTIONCOLLAPSETOGUESS) { MITK_WARN << "Class ExtractImageFilter is deprecated! Use ExtractSliceFilter instead."; } mitk::ExtractImageFilter::~ExtractImageFilter() { } void mitk::ExtractImageFilter::GenerateData() { Image::ConstPointer input = ImageToImageFilter::GetInput(0); if ((input->GetDimension() > 4) || (input->GetDimension() < 2)) { MITK_ERROR << "mitk::ExtractImageFilter:GenerateData works only with 3D and 3D+t images, sorry." << std::endl; itkExceptionMacro("mitk::ExtractImageFilter works only with 3D and 3D+t images, sorry."); return; } else if (input->GetDimension() == 4) { mitk::ImageTimeSelector::Pointer timeSelector = ImageTimeSelector::New(); timeSelector->SetInput(input); timeSelector->SetTimeNr(m_TimeStep); timeSelector->UpdateLargestPossibleRegion(); input = timeSelector->GetOutput(); } else if (input->GetDimension() == 2) { Image::Pointer resultImage = ImageToImageFilter::GetOutput(); resultImage = const_cast(input.GetPointer()); ImageToImageFilter::SetNthOutput(0, resultImage); return; } if (m_SliceDimension >= input->GetDimension()) { MITK_ERROR << "mitk::ExtractImageFilter:GenerateData m_SliceDimension == " << m_SliceDimension << " makes no sense with an " << input->GetDimension() << "D image." << std::endl; itkExceptionMacro("This is not a sensible value for m_SliceDimension."); return; } AccessFixedDimensionByItk(input, ItkImageProcessing, 3); // set a nice geometry for display and point transformations BaseGeometry *inputImageGeometry = ImageToImageFilter::GetInput(0)->GetGeometry(); if (!inputImageGeometry) { MITK_ERROR << "In ExtractImageFilter::ItkImageProcessing: Input image has no geometry!" << std::endl; return; } - PlaneGeometry::PlaneOrientation orientation = PlaneGeometry::Axial; + AnatomicalPlane orientation = AnatomicalPlane::Axial; switch (m_SliceDimension) { default: case 2: - orientation = PlaneGeometry::Axial; + orientation = AnatomicalPlane::Axial; break; case 1: - orientation = PlaneGeometry::Coronal; + orientation = AnatomicalPlane::Coronal; break; case 0: - orientation = PlaneGeometry::Sagittal; + orientation = AnatomicalPlane::Sagittal; break; } PlaneGeometry::Pointer planeGeometry = PlaneGeometry::New(); planeGeometry->InitializeStandardPlane(inputImageGeometry, orientation, (ScalarType)m_SliceIndex, true, false); Image::Pointer resultImage = ImageToImageFilter::GetOutput(); planeGeometry->ChangeImageGeometryConsideringOriginOffset(true); resultImage->SetGeometry(planeGeometry); } template void mitk::ExtractImageFilter::ItkImageProcessing(const itk::Image *itkImage) { // use the itk::ExtractImageFilter to get a 2D image typedef itk::Image ImageType3D; typedef itk::Image ImageType2D; typedef itk::ExtractImageFilter ExtractImageFilterType; typename ImageType3D::RegionType inSliceRegion = itkImage->GetLargestPossibleRegion(); inSliceRegion.SetSize(m_SliceDimension, 0); typename ExtractImageFilterType::Pointer sliceExtractor = ExtractImageFilterType::New(); typename ExtractImageFilterType::DirectionCollapseStrategyEnum collapseStrategy; switch (m_DirectionCollapseToStrategy) { case DIRECTIONCOLLAPSETOUNKOWN: collapseStrategy = ExtractImageFilterType::DirectionCollapseStrategyEnum::DIRECTIONCOLLAPSETOUNKOWN; break; case DIRECTIONCOLLAPSETOIDENTITY: collapseStrategy = ExtractImageFilterType::DirectionCollapseStrategyEnum::DIRECTIONCOLLAPSETOIDENTITY; break; case DIRECTIONCOLLAPSETOSUBMATRIX: collapseStrategy = ExtractImageFilterType::DirectionCollapseStrategyEnum::DIRECTIONCOLLAPSETOSUBMATRIX; break; case DIRECTIONCOLLAPSETOGUESS: default: collapseStrategy = ExtractImageFilterType::DirectionCollapseStrategyEnum::DIRECTIONCOLLAPSETOGUESS; break; } sliceExtractor->SetDirectionCollapseToStrategy(collapseStrategy); sliceExtractor->SetInput(itkImage); inSliceRegion.SetIndex(m_SliceDimension, m_SliceIndex); sliceExtractor->SetExtractionRegion(inSliceRegion); // calculate the output sliceExtractor->UpdateLargestPossibleRegion(); typename ImageType2D::Pointer slice = sliceExtractor->GetOutput(); // re-import to MITK Image::Pointer resultImage = ImageToImageFilter::GetOutput(); GrabItkImageMemory(slice, resultImage, nullptr, false); } /* * What is the input requested region that is required to produce the output * requested region? By default, the largest possible region is always * required but this is overridden in many subclasses. For instance, for an * image processing filter where an output pixel is a simple function of an * input pixel, the input requested region will be set to the output * requested region. For an image processing filter where an output pixel is * a function of the pixels in a neighborhood of an input pixel, then the * input requested region will need to be larger than the output requested * region (to avoid introducing artificial boundary conditions). This * function should never request an input region that is outside the the * input largest possible region (i.e. implementations of this method should * crop the input requested region at the boundaries of the input largest * possible region). */ void mitk::ExtractImageFilter::GenerateInputRequestedRegion() { Superclass::GenerateInputRequestedRegion(); ImageToImageFilter::InputImagePointer input = dynamic_cast(this->GetInput()); Image::Pointer output = this->GetOutput(); if (input->GetDimension() == 2) { input->SetRequestedRegionToLargestPossibleRegion(); return; } Image::RegionType requestedRegion; requestedRegion = output->GetRequestedRegion(); requestedRegion.SetIndex(0, 0); requestedRegion.SetIndex(1, 0); requestedRegion.SetIndex(2, 0); requestedRegion.SetSize(0, input->GetDimension(0)); requestedRegion.SetSize(1, input->GetDimension(1)); requestedRegion.SetSize(2, input->GetDimension(2)); requestedRegion.SetIndex(m_SliceDimension, m_SliceIndex); // only one slice needed requestedRegion.SetSize(m_SliceDimension, 1); input->SetRequestedRegion(&requestedRegion); } /* * Generate the information decribing the output data. The default * implementation of this method will copy information from the input to the * output. A filter may override this method if its output will have different * information than its input. For instance, a filter that shrinks an image will * need to provide an implementation for this method that changes the spacing of * the pixels. Such filters should call their superclass' implementation of this * method prior to changing the information values they need (i.e. * GenerateOutputInformation() should call * Superclass::GenerateOutputInformation() prior to changing the information. */ void mitk::ExtractImageFilter::GenerateOutputInformation() { Image::Pointer output = this->GetOutput(); Image::ConstPointer input = this->GetInput(); if (input.IsNull()) return; if (m_SliceDimension >= input->GetDimension() && input->GetDimension() != 2) { MITK_ERROR << "mitk::ExtractImageFilter:GenerateOutputInformation m_SliceDimension == " << m_SliceDimension << " makes no sense with an " << input->GetDimension() << "D image." << std::endl; itkExceptionMacro("This is not a sensible value for m_SliceDimension."); return; } unsigned int sliceDimension(m_SliceDimension); if (input->GetDimension() == 2) { sliceDimension = 2; } unsigned int tmpDimensions[2]; switch (sliceDimension) { default: case 2: - // orientation = PlaneGeometry::Axial; + // orientation = AnatomicalPlane::Axial; tmpDimensions[0] = input->GetDimension(0); tmpDimensions[1] = input->GetDimension(1); break; case 1: - // orientation = PlaneGeometry::Coronal; + // orientation = AnatomicalPlane::Coronal; tmpDimensions[0] = input->GetDimension(0); tmpDimensions[1] = input->GetDimension(2); break; case 0: - // orientation = PlaneGeometry::Sagittal; + // orientation = AnatomicalPlane::Sagittal; tmpDimensions[0] = input->GetDimension(1); tmpDimensions[1] = input->GetDimension(2); break; } output->Initialize(input->GetPixelType(), 2, tmpDimensions, 1 /*input->GetNumberOfChannels()*/); // initialize the spacing of the output /* Vector3D spacing = input->GetSlicedGeometry()->GetSpacing(); if(input->GetDimension()>=2) spacing[2]=spacing[1]; else spacing[2] = 1.0; output->GetSlicedGeometry()->SetSpacing(spacing); */ output->SetPropertyList(input->GetPropertyList()->Clone()); } diff --git a/Modules/PlanarFigure/test/mitkViewportRenderingTest.cpp b/Modules/PlanarFigure/test/mitkViewportRenderingTest.cpp index 662e577507..a09b8585c2 100644 --- a/Modules/PlanarFigure/test/mitkViewportRenderingTest.cpp +++ b/Modules/PlanarFigure/test/mitkViewportRenderingTest.cpp @@ -1,156 +1,153 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // MITK #include "mitkColorProperty.h" #include "mitkImage.h" #include "mitkLevelWindowProperty.h" #include "mitkLevelWindowProperty.h" #include "mitkNodePredicateDataType.h" #include "mitkPlanarFigure.h" #include "mitkRenderingTestHelper.h" #include "mitkSurface.h" #include "mitkTestingMacros.h" #include // ITK #include // VTK #include #include // stdlib #include int mitkViewportRenderingTest(int argc, char *argv[]) { try { mitk::RenderingTestHelper openGlTest(640, 480); } catch (const mitk::TestNotRunException &e) { MITK_WARN << "Test not run: " << e.GetDescription(); return 77; } // load all arguments into a datastorage, take last argument as reference rendering // setup a renderwindow of fixed size X*Y // render the datastorage // compare rendering to reference image MITK_TEST_BEGIN("mitkViewportRenderingTest") /// \todo Fix leaks of vtkObjects. Bug 18095. vtkDebugLeaks::SetExitError(0); // enough parameters? if (argc < 2) { MITK_TEST_OUTPUT(<< "Usage: " << std::string(*argv) << " [file1 file2 ...] outputfile") MITK_TEST_OUTPUT(<< "Will render a central axial slice of all given files into outputfile") exit(EXIT_FAILURE); } double renderWindowWidth = atof(argv[1]); double renderWindowHeight = atof(argv[2]); double left = atof(argv[3]); double bottom = atof(argv[4]); double right = atof(argv[5]); double top = atof(argv[6]); std::string referenceFilename = argv[8 + 6]; argv += 6; // DO NOT attempt to read these as files, this just makes no sense argc -= 6; // DO NOT attempt to read these as files, this just makes no sense MITK_INFO << "Testing viewport " << right - left << "x" << top - bottom << " (" << left << ", " << bottom << ") to (" << right << ", " << top << ") " << "in render window of size " << renderWindowWidth << "x" << renderWindowHeight << "px"; mitk::RenderingTestHelper renderingHelper(renderWindowWidth, renderWindowHeight, argc, argv); // non-power-of-2 - - // for now this test renders Sagittal - // renderingHelper.SetViewDirection(mitk::SliceNavigationController::Axial); - renderingHelper.SetViewDirection(mitk::SliceNavigationController::Axial); + renderingHelper.SetViewDirection(mitk::AnatomicalPlane::Axial); typedef mitk::DataStorage::SetOfObjects ObjectsSet; ObjectsSet::ConstPointer figures = renderingHelper.GetDataStorage()->GetSubset(mitk::TNodePredicateDataType::New()); for (auto iterFigures = figures->begin(); iterFigures != figures->end(); ++iterFigures) { (*iterFigures)->SetProperty("planarfigure.default.line.color", mitk::ColorProperty::New(1.0, 0.0, 0.0)); // red (*iterFigures)->SetProperty("planarfigure.drawcontrolpoints", mitk::BoolProperty::New(false)); (*iterFigures)->SetProperty("planarfigure.drawname", mitk::BoolProperty::New(false)); (*iterFigures)->SetProperty("planarfigure.drawquantities", mitk::BoolProperty::New(true)); } ObjectsSet::ConstPointer surfaces = renderingHelper.GetDataStorage()->GetSubset(mitk::TNodePredicateDataType::New()); for (auto iterSurfaces = surfaces->begin(); iterSurfaces != surfaces->end(); ++iterSurfaces) { (*iterSurfaces)->SetProperty("color", mitk::ColorProperty::New(0.0, 1.0, 0.0)); // green } ObjectsSet::ConstPointer images = renderingHelper.GetDataStorage()->GetSubset(mitk::TNodePredicateDataType::New()); for (auto iterImages = images->begin(); iterImages != images->end(); ++iterImages) { (*iterImages)->SetProperty("levelwindow", mitk::LevelWindowProperty::New(mitk::LevelWindow(128.0, 256.0))); // green int imageWidth = dynamic_cast((*iterImages)->GetData())->GetDimension(0); int imageHeight = dynamic_cast((*iterImages)->GetData())->GetDimension(1); MITK_INFO << "Image dimension " << imageWidth << "x" << imageHeight; } double vLeft = left / renderWindowWidth; double vBottom = bottom / renderWindowHeight; double vRight = right / renderWindowWidth; double vTop = top / renderWindowHeight; // THIS HERE IS THE ACTUAL TEST PART, all the rest is setup and decoration mitk::RenderingManager::GetInstance()->InitializeViews( renderingHelper.GetDataStorage()->ComputeBoundingGeometry3D(images)); renderingHelper.GetVtkRenderer()->SetViewport(vLeft, vBottom, vRight, vTop); renderingHelper.SetAutomaticallyCloseRenderWindow(true); // set to false for testing the test itself renderingHelper.Render(); // use this to generate a reference screenshot or save the file: bool generateReferenceScreenshot = false; if (generateReferenceScreenshot) { std::string tmpFilename = referenceFilename; std::string::size_type slashpos = referenceFilename.find_last_of('/'); tmpFilename = referenceFilename.substr(slashpos + 1); tmpFilename = std::string("/tmp/") + tmpFilename; renderingHelper.SaveAsPNG(tmpFilename); MITK_INFO << "*********************************"; MITK_INFO << "SAVE TO " << tmpFilename; MITK_INFO << "*********************************"; } //### Usage of vtkRegressionTestImage: // vtkRegressionTestImage( vtkRenderWindow ) // Set a vtkRenderWindow containing the desired scene. // vtkRegressionTestImage automatically searches in argc and argv[] // for a path a valid image with -V. If the test failed with the // first image (foo.png) check if there are images of the form // foo_N.png (where N=1,2,3...) and compare against them. int retVal = vtkRegressionTestImageThreshold(renderingHelper.GetVtkRenderWindow(), 20.0); // retVal meanings: (see VTK/Rendering/vtkTesting.h) // 0 = test failed // 1 = test passed // 2 = test not run // 3 = something with vtkInteraction MITK_TEST_CONDITION(retVal == 1, "VTK rendering result matches expectation"); MITK_TEST_END(); } diff --git a/Modules/QtWidgets/include/mitkRenderWindowViewDirectionController.h b/Modules/QtWidgets/include/mitkRenderWindowViewDirectionController.h index 576dc1d889..c16abb479c 100644 --- a/Modules/QtWidgets/include/mitkRenderWindowViewDirectionController.h +++ b/Modules/QtWidgets/include/mitkRenderWindowViewDirectionController.h @@ -1,82 +1,81 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef MITKRENDERWINDOWVIEWDIRECTIONCONTROLLER_H #define MITKRENDERWINDOWVIEWDIRECTIONCONTROLLER_H // qt widgets module #include "MitkQtWidgetsExports.h" #include "mitkRenderWindowLayerUtilities.h" // mitk core #include #include namespace mitk { /** * The RenderWindowViewDirectionController is used to manipulate the 'sliceNavigationController' of a given base renderer. * The 'sliceNavigationController' is used to set the view direction / camera perspective of a base renderer. - * The view direction can be changed to 'mitk::SliceNavigationController::Axial', 'mitk::SliceNavigationController::Coronal' - * or 'mitk::SliceNavigationController::Sagittal'. + * The view direction can be changed to 'mitk::AnatomicalPlane::Axial', 'mitk::AnatomicalPlane::Coronal' + * or 'mitk::AnatomicalPlane::Sagittal'. * - * Functions with 'mitk::BaseRenderer* renderer' have 'nullptr' as their default argument. Using the nullptr - * these functions operate on all base renderer. Giving a specific base renderer will modify the view direction only for the given renderer. + * Functions with 'mitk::BaseRenderer* renderer' have 'nullptr' as their default argument. + * Using the nullptr these functions operate on all base renderer. + * Giving a specific base renderer will change the view direction only for the given renderer. */ class MITKQTWIDGETS_EXPORT RenderWindowViewDirectionController { public: - using ViewDirection = mitk::SliceNavigationController::ViewDirection; - RenderWindowViewDirectionController(); /** * @brief Set the data storage on which to work. */ void SetDataStorage(DataStorage::Pointer dataStorage); /** * @brief Set the controlled base renderer. */ void SetControlledRenderer(RenderWindowLayerUtilities::RendererVector controlledRenderer); - // wrapper functions to modify the view direction + // wrapper functions to change the view direction /** - * @brief Set the view direction for the given renderer (nullptr = all renderer) + * @brief Set the ciew direction for the given renderer (nullptr = all renderer) * @param viewDirection The view direction that should be used for this renderer as a string. * Currently "axial", "coronal" and "sagittal" is supported. * @param renderer Pointer to the renderer instance for which the view direction should be changed. * If it is a nullptr (default) all controlled renderer will be affected. */ void SetViewDirectionOfRenderer(const std::string& viewDirection, BaseRenderer* renderer = nullptr); /** - * @brief Set the view direction for the given renderer (nullptr = all renderer) + * @brief Set the ciew direction for the given renderer (nullptr = all renderer) * @param viewDirection The view direction that should be used for this renderer. * @param renderer Pointer to the renderer instance for which the view direction should be changed. * If it is a nullptr (default) nothing happens. */ - void SetViewDirectionOfRenderer(ViewDirection viewDirection, BaseRenderer* renderer = nullptr); + void SetViewDirectionOfRenderer(AnatomicalPlane viewDirection, BaseRenderer* renderer = nullptr); /** * @brief Reinitialize the given renderer with the currently visible nodes. - * @param renderer Pointer to the renderer instance for which the view direction should be changed. + * @param renderer Pointer to the renderer instance which should be reinitialized. * If it is a nullptr (default) all controlled renderer will be affected. */ void InitializeViewByBoundingObjects(const BaseRenderer* renderer); private: DataStorage::Pointer m_DataStorage; RenderWindowLayerUtilities::RendererVector m_ControlledRenderer; }; } // namespace mitk #endif // MITKRENDERWINDOWVIEWDIRECTIONCONTROLLER_H diff --git a/Modules/QtWidgets/src/QmitkRenderWindowContextDataStorageInspector.cpp b/Modules/QtWidgets/src/QmitkRenderWindowContextDataStorageInspector.cpp index 7cfa9f9099..664f99a2f6 100644 --- a/Modules/QtWidgets/src/QmitkRenderWindowContextDataStorageInspector.cpp +++ b/Modules/QtWidgets/src/QmitkRenderWindowContextDataStorageInspector.cpp @@ -1,146 +1,144 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // render window manager UI module #include "QmitkRenderWindowContextDataStorageInspector.h" #include #include #include #include #include // qt #include #include QmitkRenderWindowContextDataStorageInspector::QmitkRenderWindowContextDataStorageInspector( QWidget* parent /* =nullptr */, mitk::BaseRenderer* renderer /* = nullptr */) : QmitkAbstractDataStorageInspector(parent) { m_Controls.setupUi(this); mitk::RenderWindowLayerUtilities::RendererVector controlledRenderer{ renderer }; - - // initialize the render window layer controller and the render window view direction controller m_RenderWindowLayerController = std::make_unique(); m_RenderWindowLayerController->SetControlledRenderer(controlledRenderer); m_StorageModel = std::make_unique(this); m_StorageModel->SetControlledRenderer(controlledRenderer); m_Controls.renderWindowTreeView->setModel(m_StorageModel.get()); m_Controls.renderWindowTreeView->setHeaderHidden(true); m_Controls.renderWindowTreeView->setEditTriggers(QAbstractItemView::NoEditTriggers); m_Controls.renderWindowTreeView->setSelectionBehavior(QAbstractItemView::SelectRows); m_Controls.renderWindowTreeView->setSelectionMode(QAbstractItemView::ExtendedSelection); m_Controls.renderWindowTreeView->setAlternatingRowColors(true); m_Controls.renderWindowTreeView->setDragEnabled(true); m_Controls.renderWindowTreeView->setDropIndicatorShown(true); m_Controls.renderWindowTreeView->setAcceptDrops(true); m_Controls.renderWindowTreeView->setContextMenuPolicy(Qt::CustomContextMenu); connect(m_Controls.renderWindowTreeView, &QTreeView::customContextMenuRequested, this, &QmitkRenderWindowContextDataStorageInspector::OnContextMenuRequested); SetUpConnections(); if (nullptr == renderer) { return; } m_StorageModel->SetCurrentRenderer(renderer); } QAbstractItemView* QmitkRenderWindowContextDataStorageInspector::GetView() { return m_Controls.renderWindowTreeView; } const QAbstractItemView* QmitkRenderWindowContextDataStorageInspector::GetView() const { return m_Controls.renderWindowTreeView; } void QmitkRenderWindowContextDataStorageInspector::SetSelectionMode(SelectionMode mode) { m_Controls.renderWindowTreeView->setSelectionMode(mode); } QmitkRenderWindowContextDataStorageInspector::SelectionMode QmitkRenderWindowContextDataStorageInspector::GetSelectionMode() const { return m_Controls.renderWindowTreeView->selectionMode(); } QItemSelectionModel* QmitkRenderWindowContextDataStorageInspector::GetDataNodeSelectionModel() const { return m_Controls.renderWindowTreeView->selectionModel(); } void QmitkRenderWindowContextDataStorageInspector::Initialize() { auto dataStorage = m_DataStorage.Lock(); if (dataStorage.IsNull()) return; m_StorageModel->SetDataStorage(dataStorage); mitk::NodePredicateAnd::Pointer noHelperObjects = mitk::NodePredicateAnd::New(); noHelperObjects->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))); noHelperObjects->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("hidden object"))); m_StorageModel->SetNodePredicate(noHelperObjects); m_RenderWindowLayerController->SetDataStorage(dataStorage); m_Connector->SetView(m_Controls.renderWindowTreeView); } void QmitkRenderWindowContextDataStorageInspector::SetUpConnections() { connect(m_StorageModel.get(), &QAbstractItemModel::rowsInserted, this, &QmitkRenderWindowContextDataStorageInspector::ModelRowsInserted); } void QmitkRenderWindowContextDataStorageInspector::ModelRowsInserted(const QModelIndex& parent, int /*start*/, int /*end*/) { m_Controls.renderWindowTreeView->setExpanded(parent, true); } void QmitkRenderWindowContextDataStorageInspector::ResetRenderer() { m_RenderWindowLayerController->ResetRenderer(true, m_StorageModel->GetCurrentRenderer()); m_Controls.renderWindowTreeView->clearSelection(); } void QmitkRenderWindowContextDataStorageInspector::OnContextMenuRequested(const QPoint& pos) { QMenu contextMenu; contextMenu.addAction(tr("Reinit with node"), this, &QmitkRenderWindowContextDataStorageInspector::OnReinit); contextMenu.addAction(tr("Reset to node geometry"), this, &QmitkRenderWindowContextDataStorageInspector::OnReset); contextMenu.exec(this->mapToGlobal(pos)); } void QmitkRenderWindowContextDataStorageInspector::OnReinit() { auto nodes = this->GetSelectedNodes(); emit ReinitAction(nodes); } void QmitkRenderWindowContextDataStorageInspector::OnReset() { auto nodes = this->GetSelectedNodes(); emit ResetAction(nodes); } diff --git a/Modules/QtWidgets/src/QmitkRenderWindowUtilityWidget.cpp b/Modules/QtWidgets/src/QmitkRenderWindowUtilityWidget.cpp index 82b1f45bb3..8fc6d892a7 100644 --- a/Modules/QtWidgets/src/QmitkRenderWindowUtilityWidget.cpp +++ b/Modules/QtWidgets/src/QmitkRenderWindowUtilityWidget.cpp @@ -1,95 +1,95 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "QmitkRenderWindowUtilityWidget.h" #include QmitkRenderWindowUtilityWidget::QmitkRenderWindowUtilityWidget( QWidget* parent/* = nullptr */, QmitkRenderWindow* renderWindow/* = nullptr */, mitk::DataStorage* dataStorage/* = nullptr */) : m_Layout(nullptr) , m_MenuBar(nullptr) , m_RenderWindow(renderWindow) , m_DataStorage(dataStorage) , m_RenderWindowInspector(nullptr) , m_SliceNavigationWidget(nullptr) , m_StepperAdapter(nullptr) , m_ViewDirectionSelector(nullptr) { m_Layout = new QHBoxLayout(this); m_Layout->setMargin(0); auto* baseRenderer = mitk::BaseRenderer::GetInstance(m_RenderWindow->GetVtkRenderWindow()); auto* sliceNavigationController = m_RenderWindow->GetSliceNavigationController(); m_RenderWindowInspector = new QmitkRenderWindowContextDataStorageInspector(parent, baseRenderer); m_RenderWindowInspector->SetDataStorage(m_DataStorage); m_RenderWindowInspector->setObjectName(QStringLiteral("m_RenderWindowManipulatorWidget")); connect(m_RenderWindowInspector, &QmitkRenderWindowContextDataStorageInspector::ReinitAction, this, &QmitkRenderWindowUtilityWidget::ReinitAction); connect(m_RenderWindowInspector, &QmitkRenderWindowContextDataStorageInspector::ResetAction, this, &QmitkRenderWindowUtilityWidget::ResetAction); m_MenuBar = new QMenuBar(this); m_MenuBar->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred); auto menu = m_MenuBar->addMenu("Data"); QWidgetAction* newAct = new QWidgetAction(menu); newAct->setDefaultWidget(m_RenderWindowInspector); menu->addAction(newAct); m_Layout->addWidget(m_MenuBar); m_SliceNavigationWidget = new QmitkSliceNavigationWidget(this); m_StepperAdapter = new QmitkStepperAdapter(m_SliceNavigationWidget, sliceNavigationController->GetSlice()); m_Layout->addWidget(m_SliceNavigationWidget); mitk::RenderWindowLayerUtilities::RendererVector controlledRenderer{ baseRenderer }; m_RenderWindowViewDirectionController = std::make_unique(); m_RenderWindowViewDirectionController->SetControlledRenderer(controlledRenderer); m_RenderWindowViewDirectionController->SetDataStorage(dataStorage); m_ViewDirectionSelector = new QComboBox(this); QStringList viewDirections{ "axial", "coronal", "sagittal"}; m_ViewDirectionSelector->insertItems(0, viewDirections); connect(m_ViewDirectionSelector, &QComboBox::currentTextChanged, this, &QmitkRenderWindowUtilityWidget::ChangeViewDirection); auto viewDirection = sliceNavigationController->GetDefaultViewDirection(); switch (viewDirection) { - case mitk::SliceNavigationController::Axial: + case mitk::AnatomicalPlane::Axial: m_ViewDirectionSelector->setCurrentIndex(0); break; - case mitk::SliceNavigationController::Coronal: + case mitk::AnatomicalPlane::Coronal: m_ViewDirectionSelector->setCurrentIndex(1); break; - case mitk::SliceNavigationController::Sagittal: + case mitk::AnatomicalPlane::Sagittal: m_ViewDirectionSelector->setCurrentIndex(2); break; default: break; } m_Layout->addWidget(m_ViewDirectionSelector); } QmitkRenderWindowUtilityWidget::~QmitkRenderWindowUtilityWidget() { } void QmitkRenderWindowUtilityWidget::SetInvertedSliceNavigation(bool inverted) { m_SliceNavigationWidget->SetInverseDirection(inverted); } void QmitkRenderWindowUtilityWidget::ChangeViewDirection(const QString& viewDirection) { m_RenderWindowViewDirectionController->SetViewDirectionOfRenderer(viewDirection.toStdString()); } diff --git a/Modules/QtWidgets/src/QmitkRenderWindowWidget.cpp b/Modules/QtWidgets/src/QmitkRenderWindowWidget.cpp index a1c86b1c77..11585a05e9 100644 --- a/Modules/QtWidgets/src/QmitkRenderWindowWidget.cpp +++ b/Modules/QtWidgets/src/QmitkRenderWindowWidget.cpp @@ -1,424 +1,424 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "QmitkRenderWindowWidget.h" #include #include #include // itk #include // vtk #include #include QmitkRenderWindowWidget::QmitkRenderWindowWidget(QWidget* parent/* = nullptr*/, const QString& widgetName/* = ""*/, mitk::DataStorage* dataStorage/* = nullptr*/, bool windowControls/* = false */) : QFrame(parent) , m_WidgetName(widgetName) , m_DataStorage(dataStorage) , m_RenderWindow(nullptr) , m_CrosshairManager(nullptr) , m_UtilityWidget(nullptr) , m_WindowControls(windowControls) { this->InitializeGUI(); } QmitkRenderWindowWidget::~QmitkRenderWindowWidget() { auto sliceNavigationController = this->GetSliceNavigationController(); if (nullptr != sliceNavigationController) { sliceNavigationController->SetCrosshairEvent.RemoveListener( mitk::MessageDelegate1( this, &QmitkRenderWindowWidget::SetCrosshairPosition)); } } void QmitkRenderWindowWidget::SetDataStorage(mitk::DataStorage* dataStorage) { if (dataStorage == m_DataStorage) { return; } m_DataStorage = dataStorage; if (nullptr != m_RenderWindow) { mitk::BaseRenderer::GetInstance(m_RenderWindow->renderWindow())->SetDataStorage(dataStorage); } m_CrosshairManager->SetDataStorage(m_DataStorage); } mitk::SliceNavigationController* QmitkRenderWindowWidget::GetSliceNavigationController() const { return m_RenderWindow->GetSliceNavigationController(); } void QmitkRenderWindowWidget::RequestUpdate() { mitk::RenderingManager::GetInstance()->RequestUpdate(m_RenderWindow->renderWindow()); } void QmitkRenderWindowWidget::ForceImmediateUpdate() { mitk::RenderingManager::GetInstance()->ForceImmediateUpdate(m_RenderWindow->renderWindow()); } void QmitkRenderWindowWidget::SetGradientBackgroundColors(const mitk::Color& upper, const mitk::Color& lower) { vtkRenderer* vtkRenderer = m_RenderWindow->GetRenderer()->GetVtkRenderer(); if (nullptr == vtkRenderer) { return; } m_GradientBackgroundColors.first = upper; m_GradientBackgroundColors.second = lower; vtkRenderer->SetBackground(lower[0], lower[1], lower[2]); vtkRenderer->SetBackground2(upper[0], upper[1], upper[2]); ShowGradientBackground(true); } void QmitkRenderWindowWidget::ShowGradientBackground(bool show) { m_RenderWindow->GetRenderer()->GetVtkRenderer()->SetGradientBackground(show); } bool QmitkRenderWindowWidget::IsGradientBackgroundOn() const { return m_RenderWindow->GetRenderer()->GetVtkRenderer()->GetGradientBackground(); } void QmitkRenderWindowWidget::SetDecorationColor(const mitk::Color& color) { m_DecorationColor = color; m_CornerAnnotation->GetTextProperty()->SetColor(m_DecorationColor[0], m_DecorationColor[1], m_DecorationColor[2]); QColor hexColor(m_DecorationColor[0] * 255, m_DecorationColor[1] * 255, m_DecorationColor[2] * 255); setStyleSheet("QmitkRenderWindowWidget { border: 2px solid " + hexColor.name(QColor::HexRgb) + "; }"); } void QmitkRenderWindowWidget::ShowColoredRectangle(bool show) { if (show) { setFrameStyle(QFrame::Box | QFrame::Plain); } else { setFrameStyle(NoFrame); } } bool QmitkRenderWindowWidget::IsColoredRectangleVisible() const { return frameStyle() > 0; } void QmitkRenderWindowWidget::ShowCornerAnnotation(bool show) { m_CornerAnnotation->SetVisibility(show); } bool QmitkRenderWindowWidget::IsCornerAnnotationVisible() const { return m_CornerAnnotation->GetVisibility() > 0; } void QmitkRenderWindowWidget::SetCornerAnnotationText(const std::string& cornerAnnotation) { m_CornerAnnotation->SetText(0, cornerAnnotation.c_str()); } std::string QmitkRenderWindowWidget::GetCornerAnnotationText() const { return std::string(m_CornerAnnotation->GetText(0)); } bool QmitkRenderWindowWidget::IsRenderWindowMenuActivated() const { return m_RenderWindow->GetActivateMenuWidgetFlag(); } void QmitkRenderWindowWidget::SetCrosshairVisibility(bool visible) { m_CrosshairManager->SetCrosshairVisibility(visible); this->RequestUpdate(); } bool QmitkRenderWindowWidget::GetCrosshairVisibility() { return m_CrosshairManager->GetCrosshairVisibility(); } void QmitkRenderWindowWidget::SetCrosshairGap(unsigned int gapSize) { m_CrosshairManager->SetCrosshairGap(gapSize); } void QmitkRenderWindowWidget::AddPlanesToDataStorage() { m_CrosshairManager->AddPlanesToDataStorage(); } void QmitkRenderWindowWidget::RemovePlanesFromDataStorage() { m_CrosshairManager->RemovePlanesFromDataStorage(); } void QmitkRenderWindowWidget::InitializeGUI() { m_Layout = new QVBoxLayout(this); m_Layout->setMargin(0); setLayout(m_Layout); setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); setContentsMargins(0, 0, 0, 0); if (nullptr == m_DataStorage) { return; } mitk::RenderingManager::GetInstance()->SetDataStorage(m_DataStorage); // create render window for this render window widget m_RenderWindow = new QmitkRenderWindow(this, m_WidgetName, nullptr); m_RenderWindow->SetLayoutIndex(mitk::BaseRenderer::ViewDirection::SAGITTAL); auto sliceNavigationController = this->GetSliceNavigationController(); - sliceNavigationController->SetDefaultViewDirection(mitk::SliceNavigationController::Sagittal); + sliceNavigationController->SetDefaultViewDirection(mitk::AnatomicalPlane::Sagittal); if (m_WindowControls) { m_UtilityWidget = new QmitkRenderWindowUtilityWidget(this, m_RenderWindow, m_DataStorage); m_Layout->addWidget(m_UtilityWidget); connect(m_UtilityWidget, &QmitkRenderWindowUtilityWidget::ReinitAction, this, &QmitkRenderWindowWidget::OnReinitAction); connect(m_UtilityWidget, &QmitkRenderWindowUtilityWidget::ResetAction, this, &QmitkRenderWindowWidget::OnResetAction); } m_Layout->addWidget(m_RenderWindow); // set colors and corner annotation InitializeDecorations(); // use crosshair manager m_CrosshairManager = mitk::CrosshairManager::New(m_DataStorage, m_RenderWindow->GetRenderer()); sliceNavigationController->SetCrosshairEvent.AddListener( mitk::MessageDelegate1( this, &QmitkRenderWindowWidget::SetCrosshairPosition)); // finally add observer, after all relevant objects have been created / initialized sliceNavigationController->ConnectGeometrySendEvent(this); sliceNavigationController->ConnectGeometrySliceEvent(this); mitk::TimeGeometry::ConstPointer timeGeometry = m_DataStorage->ComputeBoundingGeometry3D(m_DataStorage->GetAll()); mitk::RenderingManager::GetInstance()->InitializeView(m_RenderWindow->GetVtkRenderWindow(), timeGeometry); } void QmitkRenderWindowWidget::InitializeDecorations() { vtkRenderer* vtkRenderer = m_RenderWindow->GetRenderer()->GetVtkRenderer(); if (nullptr == vtkRenderer) { return; } // initialize background color gradients float black[3] = { 0.0f, 0.0f, 0.0f }; SetGradientBackgroundColors(black, black); // initialize annotation text and decoration color setFrameStyle(QFrame::Box | QFrame::Plain); m_CornerAnnotation = vtkSmartPointer::New(); m_CornerAnnotation->SetText(0, "Sagittal"); m_CornerAnnotation->SetMaximumFontSize(12); if (0 == vtkRenderer->HasViewProp(m_CornerAnnotation)) { vtkRenderer->AddViewProp(m_CornerAnnotation); } float white[3] = { 1.0f, 1.0f, 1.0f }; SetDecorationColor(mitk::Color(white)); } void QmitkRenderWindowWidget::SetCrosshairPosition(const mitk::Point3D& newPosition) { m_CrosshairManager->SetCrosshairPosition(newPosition); this->RequestUpdate(); } mitk::Point3D QmitkRenderWindowWidget::GetCrosshairPosition() const { return m_CrosshairManager->GetCrosshairPosition(); } void QmitkRenderWindowWidget::SetGeometry(const itk::EventObject& event) { if (!mitk::SliceNavigationController::GeometrySendEvent(nullptr, 0).CheckEvent(&event)) { return; } auto sliceNavigationController = this->GetSliceNavigationController(); const auto* inputTimeGeometry = sliceNavigationController->GetInputWorldTimeGeometry(); m_CrosshairManager->ComputeOrientedTimeGeometries(inputTimeGeometry); if (m_WindowControls) { this->ComputeInvertedSliceNavigation(); } } void QmitkRenderWindowWidget::SetGeometrySlice(const itk::EventObject& event) { if (!mitk::SliceNavigationController::GeometrySliceEvent(nullptr, 0).CheckEvent(&event)) { return; } auto sliceNavigationController = this->GetSliceNavigationController(); m_CrosshairManager->UpdateSlice(sliceNavigationController); } void QmitkRenderWindowWidget::ComputeInvertedSliceNavigation() { auto sliceNavigationController = this->GetSliceNavigationController(); auto viewDirection = sliceNavigationController->GetViewDirection(); unsigned int axis = 0; switch (viewDirection) { - case mitk::SliceNavigationController::Original: + case mitk::AnatomicalPlane::Original: return; - case mitk::SliceNavigationController::Axial: + case mitk::AnatomicalPlane::Axial: { axis = 2; break; } - case mitk::SliceNavigationController::Coronal: + case mitk::AnatomicalPlane::Coronal: { axis = 1; break; } - case mitk::SliceNavigationController::Sagittal: + case mitk::AnatomicalPlane::Sagittal: { axis = 0; break; } } const auto* inputTimeGeometry = sliceNavigationController->GetInputWorldTimeGeometry(); const mitk::BaseGeometry* rendererGeometry = m_RenderWindow->GetRenderer()->GetCurrentWorldGeometry(); // todo: check timepoint / timestep mitk::TimeStepType timeStep = sliceNavigationController->GetTime()->GetPos(); mitk::BaseGeometry::ConstPointer geometry = inputTimeGeometry->GetGeometryForTimeStep(timeStep); mitk::AffineTransform3D::MatrixType matrix = geometry->GetIndexToWorldTransform()->GetMatrix(); matrix.GetVnlMatrix().normalize_columns(); mitk::AffineTransform3D::MatrixType::InternalMatrixType inverseMatrix = matrix.GetInverse(); int dominantAxis = itk::Function::Max3(inverseMatrix[0][axis], inverseMatrix[1][axis], inverseMatrix[2][axis]); bool referenceGeometryAxisInverted = inverseMatrix[dominantAxis][axis] < 0; bool rendererZAxisInverted = rendererGeometry->GetAxisVector(2)[axis] < 0; m_UtilityWidget->SetInvertedSliceNavigation(referenceGeometryAxisInverted != rendererZAxisInverted); } void QmitkRenderWindowWidget::OnReinitAction(QList selectedNodes) { if (selectedNodes.empty()) { return; } auto* baseRenderer = mitk::BaseRenderer::GetInstance(m_RenderWindow->renderWindow()); auto boundingBoxPredicate = mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("includeInBoundingBox", mitk::BoolProperty::New(false), baseRenderer)); mitk::DataStorage::SetOfObjects::Pointer nodes = mitk::DataStorage::SetOfObjects::New(); for (const auto& dataNode : selectedNodes) { if (boundingBoxPredicate->CheckNode(dataNode)) { nodes->InsertElement(nodes->Size(), dataNode); } } if (nodes->empty()) { return; } if (1 == nodes->Size()) { auto selectedImage = dynamic_cast(nodes->ElementAt(0)->GetData()); if (nullptr != selectedImage) { mitk::RenderingManager::GetInstance()->InitializeView(baseRenderer->GetRenderWindow(), selectedImage->GetTimeGeometry()); return; } } auto boundingGeometry = m_DataStorage->ComputeBoundingGeometry3D(nodes, "visible", baseRenderer); mitk::RenderingManager::GetInstance()->InitializeView(baseRenderer->GetRenderWindow(), boundingGeometry); } void QmitkRenderWindowWidget::OnResetAction(QList selectedNodes) { if (selectedNodes.empty()) { return; } auto selectedImage = dynamic_cast(selectedNodes.front()->GetData()); if (nullptr == selectedImage) { return; } const mitk::TimeGeometry* referenceGeometry = selectedImage->GetTimeGeometry(); if (nullptr == referenceGeometry) { return; } mitk::TimeStepType imageTimeStep = 0; // store the current position to set it again later, if the camera should not be reset mitk::Point3D currentPosition = this->GetCrosshairPosition(); // store the current time step to set it again later, if the camera should not be reset auto* renderingManager = mitk::RenderingManager::GetInstance(); const auto currentTimePoint = renderingManager->GetTimeNavigationController()->GetSelectedTimePoint(); if (referenceGeometry->IsValidTimePoint(currentTimePoint)) { imageTimeStep = referenceGeometry->TimePointToTimeStep(currentTimePoint); } auto* baseRenderer = mitk::BaseRenderer::GetInstance(m_RenderWindow->renderWindow()); renderingManager->InitializeView(baseRenderer->GetRenderWindow(), referenceGeometry, false); // reset position and time step this->GetSliceNavigationController()->SelectSliceByPoint(currentPosition); renderingManager->GetTimeNavigationController()->GetTime()->SetPos(imageTimeStep); } diff --git a/Modules/QtWidgets/src/QmitkStdMultiWidget.cpp b/Modules/QtWidgets/src/QmitkStdMultiWidget.cpp index d92d632082..dee10d29de 100644 --- a/Modules/QtWidgets/src/QmitkStdMultiWidget.cpp +++ b/Modules/QtWidgets/src/QmitkStdMultiWidget.cpp @@ -1,737 +1,737 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #define SMW_INFO MITK_INFO("widget.stdmulti") #include "QmitkStdMultiWidget.h" #include "QmitkRenderWindowWidget.h" // mitk core #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // qt #include #include #include // vtk #include // c++ #include QmitkStdMultiWidget::QmitkStdMultiWidget(QWidget *parent, Qt::WindowFlags f/* = 0*/, const QString &name/* = "stdmulti"*/) : QmitkAbstractMultiWidget(parent, f, name) , m_TimeNavigationController(nullptr) { m_TimeNavigationController = mitk::RenderingManager::GetInstance()->GetTimeNavigationController(); } QmitkStdMultiWidget::~QmitkStdMultiWidget() { auto allRenderWindows = this->GetRenderWindows(); for (auto& renderWindow : allRenderWindows) { m_TimeNavigationController->Disconnect(renderWindow->GetSliceNavigationController()); } } void QmitkStdMultiWidget::InitializeMultiWidget() { // yellow is default color for widget4 m_DecorationColorWidget4[0] = 1.0f; m_DecorationColorWidget4[1] = 1.0f; m_DecorationColorWidget4[2] = 0.0f; SetLayout(2, 2); // transfer colors in WorldGeometry-Nodes of the associated Renderer // of widget 1 m_PlaneNode1 = mitk::BaseRenderer::GetInstance(GetRenderWindow1()->renderWindow())->GetCurrentWorldPlaneGeometryNode(); m_PlaneNode1->SetColor(GetDecorationColor(0)); // of widget 2 m_PlaneNode2 = mitk::BaseRenderer::GetInstance(GetRenderWindow2()->renderWindow())->GetCurrentWorldPlaneGeometryNode(); m_PlaneNode2->SetColor(GetDecorationColor(1)); // of widget 3 m_PlaneNode3 = mitk::BaseRenderer::GetInstance(GetRenderWindow3()->renderWindow())->GetCurrentWorldPlaneGeometryNode(); m_PlaneNode3->SetColor(GetDecorationColor(2)); // the parent node m_ParentNodeForGeometryPlanes = mitk::BaseRenderer::GetInstance(GetRenderWindow4()->renderWindow())->GetCurrentWorldPlaneGeometryNode(); AddDisplayPlaneSubTree(); SetDisplayActionEventHandler(std::make_unique()); auto displayActionEventHandler = GetDisplayActionEventHandler(); if (nullptr != displayActionEventHandler) { displayActionEventHandler->InitActions(); } } QmitkRenderWindow* QmitkStdMultiWidget::GetRenderWindow(const QString& widgetName) const { if ("axial" == widgetName) { return GetRenderWindow1(); } if ("sagittal" == widgetName) { return GetRenderWindow2(); } if ("coronal" == widgetName) { return GetRenderWindow3(); } if ("3d" == widgetName) { return GetRenderWindow4(); } return QmitkAbstractMultiWidget::GetRenderWindow(widgetName); } QmitkRenderWindow* QmitkStdMultiWidget::GetRenderWindow(const mitk::BaseRenderer::ViewDirection& viewDirection) const { return GetRenderWindow(static_cast(viewDirection)); } void QmitkStdMultiWidget::SetReferenceGeometry(const mitk::TimeGeometry* referenceGeometry, bool resetCamera) { auto* renderingManager = mitk::RenderingManager::GetInstance(); mitk::Point3D currentPosition = mitk::Point3D(); unsigned int imageTimeStep = 0; if (!resetCamera) { // store the current position to set it again later, if the camera should not be reset currentPosition = this->GetSelectedPosition(""); // store the current time step to set it again later, if the camera should not be reset const auto currentTimePoint = renderingManager->GetTimeNavigationController()->GetSelectedTimePoint(); if (referenceGeometry->IsValidTimePoint(currentTimePoint)) { imageTimeStep = referenceGeometry->TimePointToTimeStep(currentTimePoint); } } // initialize render windows renderingManager->InitializeViews(referenceGeometry, mitk::RenderingManager::REQUEST_UPDATE_ALL, resetCamera); if (!resetCamera) { this->SetSelectedPosition(currentPosition, ""); renderingManager->GetTimeNavigationController()->GetTime()->SetPos(imageTimeStep); } } bool QmitkStdMultiWidget::HasCoupledRenderWindows() const { return true; } void QmitkStdMultiWidget::SetSelectedPosition(const mitk::Point3D& newPosition, const QString& /*widgetName*/) { GetRenderWindow1()->GetSliceNavigationController()->SelectSliceByPoint(newPosition); GetRenderWindow2()->GetSliceNavigationController()->SelectSliceByPoint(newPosition); GetRenderWindow3()->GetSliceNavigationController()->SelectSliceByPoint(newPosition); RequestUpdateAll(); } const mitk::Point3D QmitkStdMultiWidget::GetSelectedPosition(const QString& /*widgetName*/) const { const mitk::PlaneGeometry* plane1 = GetRenderWindow1()->GetSliceNavigationController()->GetCurrentPlaneGeometry(); const mitk::PlaneGeometry* plane2 = GetRenderWindow2()->GetSliceNavigationController()->GetCurrentPlaneGeometry(); const mitk::PlaneGeometry* plane3 = GetRenderWindow3()->GetSliceNavigationController()->GetCurrentPlaneGeometry(); mitk::Line3D line; if ((plane1 != nullptr) && (plane2 != nullptr) && (plane1->IntersectionLine(plane2, line))) { mitk::Point3D point; if ((plane3 != nullptr) && (plane3->IntersectionPoint(line, point))) { return point; } } return mitk::Point3D(); } void QmitkStdMultiWidget::SetCrosshairVisibility(bool visible) { if (m_PlaneNode1.IsNotNull()) { m_PlaneNode1->SetVisibility(visible); } if (m_PlaneNode2.IsNotNull()) { m_PlaneNode2->SetVisibility(visible); } if (m_PlaneNode3.IsNotNull()) { m_PlaneNode3->SetVisibility(visible); } emit NotifyCrosshairVisibilityChanged(visible); RequestUpdateAll(); } bool QmitkStdMultiWidget::GetCrosshairVisibility() const { bool crosshairVisibility = true; if (m_PlaneNode1.IsNotNull()) { bool visibilityProperty = false; m_PlaneNode1->GetVisibility(visibilityProperty, nullptr); crosshairVisibility &= visibilityProperty; } if (m_PlaneNode2.IsNotNull()) { bool visibilityProperty = false; crosshairVisibility &= m_PlaneNode2->GetVisibility(visibilityProperty, nullptr); crosshairVisibility &= visibilityProperty; } if (m_PlaneNode3.IsNotNull()) { bool visibilityProperty = false; crosshairVisibility &= m_PlaneNode3->GetVisibility(visibilityProperty, nullptr); crosshairVisibility &= visibilityProperty; } return crosshairVisibility; } void QmitkStdMultiWidget::SetCrosshairGap(unsigned int gapSize) { m_PlaneNode1->SetIntProperty("Crosshair.Gap Size", gapSize); m_PlaneNode2->SetIntProperty("Crosshair.Gap Size", gapSize); m_PlaneNode3->SetIntProperty("Crosshair.Gap Size", gapSize); } void QmitkStdMultiWidget::ResetCrosshair() { auto dataStorage = GetDataStorage(); if (nullptr == dataStorage) { return; } mitk::RenderingManager::GetInstance()->InitializeViewsByBoundingObjects(dataStorage); SetWidgetPlaneMode(mitk::InteractionSchemeSwitcher::MITKStandard); } void QmitkStdMultiWidget::SetWidgetPlaneMode(int userMode) { MITK_DEBUG << "Changing crosshair mode to " << userMode; switch (userMode) { case 0: SetInteractionScheme(mitk::InteractionSchemeSwitcher::MITKStandard); break; case 1: SetInteractionScheme(mitk::InteractionSchemeSwitcher::MITKRotationUncoupled); break; case 2: SetInteractionScheme(mitk::InteractionSchemeSwitcher::MITKRotationCoupled); break; case 3: SetInteractionScheme(mitk::InteractionSchemeSwitcher::MITKSwivel); break; } emit NotifyCrosshairRotationModeChanged(userMode); } mitk::SliceNavigationController* QmitkStdMultiWidget::GetTimeNavigationController() { return m_TimeNavigationController; } void QmitkStdMultiWidget::AddPlanesToDataStorage() { auto dataStorage = GetDataStorage(); if (nullptr == dataStorage) { return; } if (m_PlaneNode1.IsNotNull() && m_PlaneNode2.IsNotNull() && m_PlaneNode3.IsNotNull() && m_ParentNodeForGeometryPlanes.IsNotNull()) { dataStorage->Add(m_ParentNodeForGeometryPlanes); dataStorage->Add(m_PlaneNode1, m_ParentNodeForGeometryPlanes); dataStorage->Add(m_PlaneNode2, m_ParentNodeForGeometryPlanes); dataStorage->Add(m_PlaneNode3, m_ParentNodeForGeometryPlanes); } } void QmitkStdMultiWidget::RemovePlanesFromDataStorage() { auto dataStorage = GetDataStorage(); if (nullptr == dataStorage) { return; } if (m_PlaneNode1.IsNotNull() && m_PlaneNode2.IsNotNull() && m_PlaneNode3.IsNotNull() && m_ParentNodeForGeometryPlanes.IsNotNull()) { dataStorage->Remove(m_PlaneNode1); dataStorage->Remove(m_PlaneNode2); dataStorage->Remove(m_PlaneNode3); dataStorage->Remove(m_ParentNodeForGeometryPlanes); } } QmitkRenderWindow* QmitkStdMultiWidget::GetRenderWindow(unsigned int number) const { switch (number) { case 0: return GetRenderWindow1(); case 1: return GetRenderWindow2(); case 2: return GetRenderWindow3(); case 3: return GetRenderWindow4(); default: MITK_ERROR << "Requested unknown render window"; break; } return nullptr; } QmitkRenderWindow* QmitkStdMultiWidget::GetRenderWindow1() const { return QmitkAbstractMultiWidget::GetRenderWindow(GetNameFromIndex(0, 0)); } QmitkRenderWindow* QmitkStdMultiWidget::GetRenderWindow2() const { return QmitkAbstractMultiWidget::GetRenderWindow(GetNameFromIndex(0, 1)); } QmitkRenderWindow* QmitkStdMultiWidget::GetRenderWindow3() const { return QmitkAbstractMultiWidget::GetRenderWindow(GetNameFromIndex(1, 0)); } QmitkRenderWindow* QmitkStdMultiWidget::GetRenderWindow4() const { return QmitkAbstractMultiWidget::GetRenderWindow(GetNameFromIndex(1, 1)); } mitk::DataNode::Pointer QmitkStdMultiWidget::GetWidgetPlane1() const { return m_PlaneNode1; } mitk::DataNode::Pointer QmitkStdMultiWidget::GetWidgetPlane2() const { return m_PlaneNode2; } mitk::DataNode::Pointer QmitkStdMultiWidget::GetWidgetPlane3() const { return m_PlaneNode3; } mitk::DataNode::Pointer QmitkStdMultiWidget::GetWidgetPlane(unsigned number) const { switch (number) { case 1: return m_PlaneNode1; case 2: return m_PlaneNode2; case 3: return m_PlaneNode3; default: MITK_ERROR << "Requested unknown render window"; break; } return nullptr; } void QmitkStdMultiWidget::SetDecorationColor(unsigned int widgetNumber, mitk::Color color) { switch (widgetNumber) { case 0: if (m_PlaneNode1.IsNotNull()) { m_PlaneNode1->SetColor(color); } break; case 1: if (m_PlaneNode2.IsNotNull()) { m_PlaneNode2->SetColor(color); } break; case 2: if (m_PlaneNode3.IsNotNull()) { m_PlaneNode3->SetColor(color); } break; case 3: m_DecorationColorWidget4 = color; break; default: MITK_ERROR << "Decoration color for unknown widget!"; break; } } mitk::Color QmitkStdMultiWidget::GetDecorationColor(unsigned int widgetNumber) { // The implementation looks a bit messy here, but it avoids // synchronization of the color of the geometry nodes and an // internal member here. // Default colors were chosen for decent visibility. // Feel free to change your preferences in the workbench. float tmp[3] = { 0.0f, 0.0f, 0.0f }; switch (widgetNumber) { case 0: { if (m_PlaneNode1.IsNotNull()) { if (m_PlaneNode1->GetColor(tmp)) { return dynamic_cast(m_PlaneNode1->GetProperty("color"))->GetColor(); } } float red[3] = { 0.753f, 0.0f, 0.0f }; // This is #C00000 in hex return mitk::Color(red); } case 1: { if (m_PlaneNode2.IsNotNull()) { if (m_PlaneNode2->GetColor(tmp)) { return dynamic_cast(m_PlaneNode2->GetProperty("color"))->GetColor(); } } float green[3] = { 0.0f, 0.69f, 0.0f }; // This is #00B000 in hex return mitk::Color(green); } case 2: { if (m_PlaneNode3.IsNotNull()) { if (m_PlaneNode3->GetColor(tmp)) { return dynamic_cast(m_PlaneNode3->GetProperty("color"))->GetColor(); } } float blue[3] = { 0.0, 0.502f, 1.0f }; // This is #0080FF in hex return mitk::Color(blue); } case 3: { return m_DecorationColorWidget4; } default: MITK_ERROR << "Decoration color for unknown widget!"; float black[3] = { 0.0f, 0.0f, 0.0f }; return mitk::Color(black); } } void QmitkStdMultiWidget::mousePressEvent(QMouseEvent*) { // nothing here, but necessary for mouse interactions (.xml-configuration files) } void QmitkStdMultiWidget::moveEvent(QMoveEvent* e) { QWidget::moveEvent(e); // it is necessary to readjust the position of the Annotation as the StdMultiWidget has moved // unfortunately it's not done by QmitkRenderWindow::moveEvent -> must be done here emit Moved(); } void QmitkStdMultiWidget::wheelEvent(QWheelEvent* e) { emit WheelMoved(e); } void QmitkStdMultiWidget::Fit() { vtkSmartPointer vtkrenderer; vtkrenderer = mitk::BaseRenderer::GetInstance(GetRenderWindow1()->renderWindow())->GetVtkRenderer(); if (nullptr != vtkrenderer) { vtkrenderer->ResetCamera(); } vtkrenderer = mitk::BaseRenderer::GetInstance(GetRenderWindow2()->renderWindow())->GetVtkRenderer(); if (nullptr != vtkrenderer) { vtkrenderer->ResetCamera(); } vtkrenderer = mitk::BaseRenderer::GetInstance(GetRenderWindow3()->renderWindow())->GetVtkRenderer(); if (nullptr != vtkrenderer) { vtkrenderer->ResetCamera(); } vtkrenderer = mitk::BaseRenderer::GetInstance(GetRenderWindow4()->renderWindow())->GetVtkRenderer(); if (nullptr != vtkrenderer) { vtkrenderer->ResetCamera(); } mitk::BaseRenderer::GetInstance(GetRenderWindow1()->renderWindow())->GetCameraController()->Fit(); mitk::BaseRenderer::GetInstance(GetRenderWindow2()->renderWindow())->GetCameraController()->Fit(); mitk::BaseRenderer::GetInstance(GetRenderWindow3()->renderWindow())->GetCameraController()->Fit(); mitk::BaseRenderer::GetInstance(GetRenderWindow4()->renderWindow())->GetCameraController()->Fit(); int w = vtkObject::GetGlobalWarningDisplay(); vtkObject::GlobalWarningDisplayOff(); vtkObject::SetGlobalWarningDisplay(w); } void QmitkStdMultiWidget::AddDisplayPlaneSubTree() { // add the displayed planes of the multiwidget to a node to which the subtree // @a planesSubTree points ... mitk::PlaneGeometryDataMapper2D::Pointer mapper; // ... of widget 1 mitk::BaseRenderer* renderer1 = mitk::BaseRenderer::GetInstance(GetRenderWindow1()->renderWindow()); m_PlaneNode1 = renderer1->GetCurrentWorldPlaneGeometryNode(); m_PlaneNode1->SetProperty("visible", mitk::BoolProperty::New(true)); m_PlaneNode1->SetProperty("name", mitk::StringProperty::New(std::string(renderer1->GetName()) + ".plane")); m_PlaneNode1->SetProperty("includeInBoundingBox", mitk::BoolProperty::New(false)); m_PlaneNode1->SetProperty("helper object", mitk::BoolProperty::New(true)); mapper = mitk::PlaneGeometryDataMapper2D::New(); m_PlaneNode1->SetMapper(mitk::BaseRenderer::Standard2D, mapper); // ... of widget 2 mitk::BaseRenderer* renderer2 = mitk::BaseRenderer::GetInstance(GetRenderWindow2()->renderWindow()); m_PlaneNode2 = renderer2->GetCurrentWorldPlaneGeometryNode(); m_PlaneNode2->SetProperty("visible", mitk::BoolProperty::New(true)); m_PlaneNode2->SetProperty("name", mitk::StringProperty::New(std::string(renderer2->GetName()) + ".plane")); m_PlaneNode2->SetProperty("includeInBoundingBox", mitk::BoolProperty::New(false)); m_PlaneNode2->SetProperty("helper object", mitk::BoolProperty::New(true)); mapper = mitk::PlaneGeometryDataMapper2D::New(); m_PlaneNode2->SetMapper(mitk::BaseRenderer::Standard2D, mapper); // ... of widget 3 mitk::BaseRenderer *renderer3 = mitk::BaseRenderer::GetInstance(GetRenderWindow3()->renderWindow()); m_PlaneNode3 = renderer3->GetCurrentWorldPlaneGeometryNode(); m_PlaneNode3->SetProperty("visible", mitk::BoolProperty::New(true)); m_PlaneNode3->SetProperty("name", mitk::StringProperty::New(std::string(renderer3->GetName()) + ".plane")); m_PlaneNode3->SetProperty("includeInBoundingBox", mitk::BoolProperty::New(false)); m_PlaneNode3->SetProperty("helper object", mitk::BoolProperty::New(true)); mapper = mitk::PlaneGeometryDataMapper2D::New(); m_PlaneNode3->SetMapper(mitk::BaseRenderer::Standard2D, mapper); m_ParentNodeForGeometryPlanes = mitk::DataNode::New(); m_ParentNodeForGeometryPlanes->SetProperty("name", mitk::StringProperty::New("Widgets")); m_ParentNodeForGeometryPlanes->SetProperty("helper object", mitk::BoolProperty::New(true)); } void QmitkStdMultiWidget::EnsureDisplayContainsPoint(mitk::BaseRenderer *renderer, const mitk::Point3D &p) { mitk::Point2D pointOnDisplay; renderer->WorldToDisplay(p, pointOnDisplay); if (pointOnDisplay[0] < renderer->GetVtkRenderer()->GetOrigin()[0] || pointOnDisplay[1] < renderer->GetVtkRenderer()->GetOrigin()[1] || pointOnDisplay[0] > renderer->GetVtkRenderer()->GetOrigin()[0] + renderer->GetViewportSize()[0] || pointOnDisplay[1] > renderer->GetVtkRenderer()->GetOrigin()[1] + renderer->GetViewportSize()[1]) { mitk::Point2D pointOnPlane; renderer->GetCurrentWorldPlaneGeometry()->Map(p, pointOnPlane); renderer->GetCameraController()->MoveCameraToPoint(pointOnPlane); } } void QmitkStdMultiWidget::SetWidgetPlaneVisibility(const char *widgetName, bool visible, mitk::BaseRenderer *renderer) { auto dataStorage = GetDataStorage(); if (nullptr != dataStorage) { mitk::DataNode* dataNode = dataStorage->GetNamedNode(widgetName); if (dataNode != nullptr) { dataNode->SetVisibility(visible, renderer); } } } void QmitkStdMultiWidget::SetWidgetPlanesVisibility(bool visible, mitk::BaseRenderer *renderer) { if (m_PlaneNode1.IsNotNull()) { m_PlaneNode1->SetVisibility(visible, renderer); } if (m_PlaneNode2.IsNotNull()) { m_PlaneNode2->SetVisibility(visible, renderer); } if (m_PlaneNode3.IsNotNull()) { m_PlaneNode3->SetVisibility(visible, renderer); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } ////////////////////////////////////////////////////////////////////////// // PRIVATE ////////////////////////////////////////////////////////////////////////// void QmitkStdMultiWidget::SetLayoutImpl() { CreateRenderWindowWidgets(); GetMultiWidgetLayoutManager()->SetLayoutDesign(QmitkMultiWidgetLayoutManager::LayoutDesign::DEFAULT); // Initialize views as axial, sagittal, coronal to all data objects in DataStorage auto geo = GetDataStorage()->ComputeBoundingGeometry3D(GetDataStorage()->GetAll()); mitk::RenderingManager::GetInstance()->InitializeViews(geo); } void QmitkStdMultiWidget::CreateRenderWindowWidgets() { // create axial render window (widget) QString renderWindowWidgetName = GetNameFromIndex(0, 0); RenderWindowWidgetPointer renderWindowWidget1 = std::make_shared(this, renderWindowWidgetName, GetDataStorage()); auto renderWindow1 = renderWindowWidget1->GetRenderWindow(); - renderWindow1->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Axial); + renderWindow1->GetSliceNavigationController()->SetDefaultViewDirection(mitk::AnatomicalPlane::Axial); renderWindowWidget1->SetDecorationColor(GetDecorationColor(0)); renderWindowWidget1->SetCornerAnnotationText("Axial"); renderWindowWidget1->GetRenderWindow()->SetLayoutIndex(ViewDirection::AXIAL); AddRenderWindowWidget(renderWindowWidgetName, renderWindowWidget1); // create sagittal render window (widget) renderWindowWidgetName = GetNameFromIndex(0, 1); RenderWindowWidgetPointer renderWindowWidget2 = std::make_shared(this, renderWindowWidgetName, GetDataStorage()); auto renderWindow2 = renderWindowWidget2->GetRenderWindow(); - renderWindow2->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Sagittal); + renderWindow2->GetSliceNavigationController()->SetDefaultViewDirection(mitk::AnatomicalPlane::Sagittal); renderWindowWidget2->SetDecorationColor(GetDecorationColor(1)); renderWindowWidget2->setStyleSheet("border: 0px"); renderWindowWidget2->SetCornerAnnotationText("Sagittal"); renderWindowWidget2->GetRenderWindow()->SetLayoutIndex(ViewDirection::SAGITTAL); AddRenderWindowWidget(renderWindowWidgetName, renderWindowWidget2); // create coronal render window (widget) renderWindowWidgetName = GetNameFromIndex(1, 0); RenderWindowWidgetPointer renderWindowWidget3 = std::make_shared(this, renderWindowWidgetName, GetDataStorage()); auto renderWindow3 = renderWindowWidget3->GetRenderWindow(); - renderWindow3->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Coronal); + renderWindow3->GetSliceNavigationController()->SetDefaultViewDirection(mitk::AnatomicalPlane::Coronal); renderWindowWidget3->SetDecorationColor(GetDecorationColor(2)); renderWindowWidget3->SetCornerAnnotationText("Coronal"); renderWindowWidget3->GetRenderWindow()->SetLayoutIndex(ViewDirection::CORONAL); AddRenderWindowWidget(renderWindowWidgetName, renderWindowWidget3); // create 3D render window (widget) renderWindowWidgetName = GetNameFromIndex(1, 1); RenderWindowWidgetPointer renderWindowWidget4 = std::make_shared(this, renderWindowWidgetName, GetDataStorage()); auto renderWindow4 = renderWindowWidget4->GetRenderWindow(); - renderWindow4->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Original); + renderWindow4->GetSliceNavigationController()->SetDefaultViewDirection(mitk::AnatomicalPlane::Original); renderWindowWidget4->SetDecorationColor(GetDecorationColor(3)); renderWindowWidget4->SetCornerAnnotationText("3D"); renderWindowWidget4->GetRenderWindow()->SetLayoutIndex(ViewDirection::THREE_D); mitk::BaseRenderer::GetInstance(renderWindowWidget4->GetRenderWindow()->renderWindow())->SetMapperID(mitk::BaseRenderer::Standard3D); AddRenderWindowWidget(renderWindowWidgetName, renderWindowWidget4); SetActiveRenderWindowWidget(renderWindowWidget1); // connect to the "time navigation controller": send time via sliceNavigationControllers m_TimeNavigationController->ConnectGeometryTimeEvent(renderWindow1->GetSliceNavigationController()); m_TimeNavigationController->ConnectGeometryTimeEvent(renderWindow2->GetSliceNavigationController()); m_TimeNavigationController->ConnectGeometryTimeEvent(renderWindow3->GetSliceNavigationController()); m_TimeNavigationController->ConnectGeometryTimeEvent(renderWindow4->GetSliceNavigationController()); renderWindow1->GetSliceNavigationController()->ConnectGeometrySendEvent( mitk::BaseRenderer::GetInstance(renderWindow4->renderWindow())); // reverse connection between sliceNavigationControllers and timeNavigationController renderWindow1->GetSliceNavigationController()->ConnectGeometryTimeEvent(m_TimeNavigationController); renderWindow2->GetSliceNavigationController()->ConnectGeometryTimeEvent(m_TimeNavigationController); renderWindow3->GetSliceNavigationController()->ConnectGeometryTimeEvent(m_TimeNavigationController); //renderWindow4->GetSliceNavigationController()->ConnectGeometryTimeEvent(m_TimeNavigationController); auto layoutManager = GetMultiWidgetLayoutManager(); connect(renderWindow1, &QmitkRenderWindow::ResetView, this, &QmitkStdMultiWidget::ResetCrosshair); connect(renderWindow1, &QmitkRenderWindow::CrosshairVisibilityChanged, this, &QmitkStdMultiWidget::SetCrosshairVisibility); connect(renderWindow1, &QmitkRenderWindow::CrosshairRotationModeChanged, this, &QmitkStdMultiWidget::SetWidgetPlaneMode); connect(renderWindow1, &QmitkRenderWindow::LayoutDesignChanged, layoutManager, &QmitkMultiWidgetLayoutManager::SetLayoutDesign); connect(this, &QmitkStdMultiWidget::NotifyCrosshairVisibilityChanged, renderWindow1, &QmitkRenderWindow::UpdateCrosshairVisibility); connect(this, &QmitkStdMultiWidget::NotifyCrosshairRotationModeChanged, renderWindow1, &QmitkRenderWindow::UpdateCrosshairRotationMode); connect(renderWindow2, &QmitkRenderWindow::ResetView, this, &QmitkStdMultiWidget::ResetCrosshair); connect(renderWindow2, &QmitkRenderWindow::CrosshairVisibilityChanged, this, &QmitkStdMultiWidget::SetCrosshairVisibility); connect(renderWindow2, &QmitkRenderWindow::CrosshairRotationModeChanged, this, &QmitkStdMultiWidget::SetWidgetPlaneMode); connect(renderWindow2, &QmitkRenderWindow::LayoutDesignChanged, layoutManager, &QmitkMultiWidgetLayoutManager::SetLayoutDesign); connect(this, &QmitkStdMultiWidget::NotifyCrosshairVisibilityChanged, renderWindow2, &QmitkRenderWindow::UpdateCrosshairVisibility); connect(this, &QmitkStdMultiWidget::NotifyCrosshairRotationModeChanged, renderWindow2, &QmitkRenderWindow::UpdateCrosshairRotationMode); connect(renderWindow3, &QmitkRenderWindow::ResetView, this, &QmitkStdMultiWidget::ResetCrosshair); connect(renderWindow3, &QmitkRenderWindow::CrosshairVisibilityChanged, this, &QmitkStdMultiWidget::SetCrosshairVisibility); connect(renderWindow3, &QmitkRenderWindow::CrosshairRotationModeChanged, this, &QmitkStdMultiWidget::SetWidgetPlaneMode); connect(renderWindow3, &QmitkRenderWindow::LayoutDesignChanged, layoutManager, &QmitkMultiWidgetLayoutManager::SetLayoutDesign); connect(this, &QmitkStdMultiWidget::NotifyCrosshairVisibilityChanged, renderWindow3, &QmitkRenderWindow::UpdateCrosshairVisibility); connect(this, &QmitkStdMultiWidget::NotifyCrosshairRotationModeChanged, renderWindow3, &QmitkRenderWindow::UpdateCrosshairRotationMode); connect(renderWindow4, &QmitkRenderWindow::ResetView, this, &QmitkStdMultiWidget::ResetCrosshair); connect(renderWindow4, &QmitkRenderWindow::CrosshairVisibilityChanged, this, &QmitkStdMultiWidget::SetCrosshairVisibility); connect(renderWindow4, &QmitkRenderWindow::CrosshairRotationModeChanged, this, &QmitkStdMultiWidget::SetWidgetPlaneMode); connect(renderWindow4, &QmitkRenderWindow::LayoutDesignChanged, layoutManager, &QmitkMultiWidgetLayoutManager::SetLayoutDesign); connect(this, &QmitkStdMultiWidget::NotifyCrosshairVisibilityChanged, renderWindow4, &QmitkRenderWindow::UpdateCrosshairVisibility); connect(this, &QmitkStdMultiWidget::NotifyCrosshairRotationModeChanged, renderWindow4, &QmitkRenderWindow::UpdateCrosshairRotationMode); } diff --git a/Modules/QtWidgets/src/mitkRenderWindowViewDirectionController.cpp b/Modules/QtWidgets/src/mitkRenderWindowViewDirectionController.cpp index 6923c4ea9c..7410b0ec9d 100644 --- a/Modules/QtWidgets/src/mitkRenderWindowViewDirectionController.cpp +++ b/Modules/QtWidgets/src/mitkRenderWindowViewDirectionController.cpp @@ -1,137 +1,137 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkRenderWindowViewDirectionController.h" // mitk core #include #include #include mitk::RenderWindowViewDirectionController::RenderWindowViewDirectionController() : m_DataStorage(nullptr) { // nothing here } void mitk::RenderWindowViewDirectionController::SetDataStorage(DataStorage::Pointer dataStorage) { if (m_DataStorage != dataStorage) { // set the new data storage m_DataStorage = dataStorage; } } void mitk::RenderWindowViewDirectionController::SetControlledRenderer(RenderWindowLayerUtilities::RendererVector controlledRenderer) { if (m_ControlledRenderer != controlledRenderer) { // set the new set of controlled renderer m_ControlledRenderer = controlledRenderer; } } void mitk::RenderWindowViewDirectionController::SetViewDirectionOfRenderer(const std::string& viewDirection, BaseRenderer* renderer/* =nullptr*/) { if (nullptr == renderer) { // set visibility of data node in all controlled renderer for (auto& renderer : m_ControlledRenderer) { if (nullptr != renderer) { SetViewDirectionOfRenderer(viewDirection, renderer); } } } else { mitk::SliceNavigationController* sliceNavigationController = renderer->GetSliceNavigationController(); if ("axial" == viewDirection) { - sliceNavigationController->SetDefaultViewDirection(ViewDirection::Axial); + sliceNavigationController->SetDefaultViewDirection(AnatomicalPlane::Axial); } else if ("coronal" == viewDirection) { - sliceNavigationController->SetDefaultViewDirection(ViewDirection::Coronal); + sliceNavigationController->SetDefaultViewDirection(AnatomicalPlane::Coronal); } else if ("sagittal" == viewDirection) { - sliceNavigationController->SetDefaultViewDirection(ViewDirection::Sagittal); + sliceNavigationController->SetDefaultViewDirection(AnatomicalPlane::Sagittal); } if ("3D" == viewDirection) { renderer->SetMapperID(mitk::BaseRenderer::Standard3D); } else { renderer->SetMapperID(mitk::BaseRenderer::Standard2D); } // initialize the views to the bounding geometry InitializeViewByBoundingObjects(renderer); } } -void mitk::RenderWindowViewDirectionController::SetViewDirectionOfRenderer(ViewDirection viewDirection , BaseRenderer* renderer/* =nullptr*/) +void mitk::RenderWindowViewDirectionController::SetViewDirectionOfRenderer(AnatomicalPlane viewDirection , BaseRenderer* renderer/* =nullptr*/) { if (nullptr == renderer) { // set visibility of data node in all controlled renderer for (auto& renderer : m_ControlledRenderer) { if (nullptr != renderer) { SetViewDirectionOfRenderer(viewDirection, renderer); } } } else { mitk::SliceNavigationController* sliceNavigationController = renderer->GetSliceNavigationController(); sliceNavigationController->SetDefaultViewDirection(viewDirection); // initialize the views to the bounding geometry InitializeViewByBoundingObjects(renderer); } } void mitk::RenderWindowViewDirectionController::InitializeViewByBoundingObjects(const BaseRenderer* renderer) { if (nullptr == m_DataStorage || nullptr == renderer) { return; } // get all nodes that have not set "includeInBoundingBox" to false mitk::NodePredicateProperty::Pointer includeInBoundingBox = mitk::NodePredicateProperty::New("includeInBoundingBox", mitk::BoolProperty::New(false)); mitk::NodePredicateNot::Pointer notIncludeInBoundingBox = mitk::NodePredicateNot::New(includeInBoundingBox); // get all non-helper objects mitk::NodePredicateProperty::Pointer helperObject = mitk::NodePredicateProperty::New("helper object", mitk::BoolProperty::New(true)); mitk::NodePredicateNot::Pointer notAHelperObject = mitk::NodePredicateNot::New(helperObject); // get all nodes that have a fixed layer for the given renderer mitk::NodePredicateProperty::Pointer fixedLayer = mitk::NodePredicateProperty::New("fixedLayer", mitk::BoolProperty::New(true), renderer); // combine node predicates mitk::NodePredicateAnd::Pointer combinedNodePredicate = mitk::NodePredicateAnd::New(notIncludeInBoundingBox, notAHelperObject, fixedLayer); mitk::DataStorage::SetOfObjects::ConstPointer filteredDataNodes = m_DataStorage->GetSubset(combinedNodePredicate); // calculate bounding geometry of these nodes auto bounds = m_DataStorage->ComputeBoundingGeometry3D(filteredDataNodes, "visible", renderer); // initialize the views to the bounding geometry mitk::RenderingManager::GetInstance()->InitializeView(renderer->GetRenderWindow(), bounds); } diff --git a/Modules/QtWidgetsExt/include/QmitkSliceWidget.h b/Modules/QtWidgetsExt/include/QmitkSliceWidget.h index faa776fec6..04cdef4bcb 100644 --- a/Modules/QtWidgetsExt/include/QmitkSliceWidget.h +++ b/Modules/QtWidgetsExt/include/QmitkSliceWidget.h @@ -1,91 +1,91 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef QMITKSLICEWIDGET_H_ #define QMITKSLICEWIDGET_H_ #include "MitkQtWidgetsExtExports.h" #include "ui_QmitkSliceWidget.h" #include "QmitkRenderWindow.h" #include "mitkDataStorage.h" #include "mitkSliceNavigationController.h" #include "QmitkSliceNavigationWidget.h" #include "mitkSlicedGeometry3D.h" #include "mitkStandaloneDataStorage.h" #include class MITKQTWIDGETSEXT_EXPORT QmitkSliceWidget : public QWidget, public Ui::QmitkSliceWidgetUi { Q_OBJECT public: QmitkSliceWidget(QWidget *parent = nullptr, const char *name = nullptr, Qt::WindowFlags f = nullptr); mitk::VtkPropRenderer *GetRenderer(); QFrame *GetSelectionFrame(); void UpdateGL(); void mousePressEvent(QMouseEvent *e) override; void setPopUpEnabled(bool b); void SetDataStorage(mitk::StandaloneDataStorage::Pointer storage); mitk::StandaloneDataStorage *GetDataStorage(); QmitkSliceNavigationWidget* GetSliceNavigationWidget(); bool IsLevelWindowEnabled(); QmitkRenderWindow *GetRenderWindow(); mitk::SliceNavigationController *GetSliceNavigationController() const; mitk::CameraRotationController *GetCameraRotationController() const; mitk::BaseController *GetController() const; public slots: void SetData(mitk::DataStorage::SetOfObjects::ConstIterator it); - void SetData(mitk::DataStorage::SetOfObjects::ConstIterator it, mitk::SliceNavigationController::ViewDirection view); + void SetData(mitk::DataStorage::SetOfObjects::ConstIterator it, mitk::AnatomicalPlane view); void SetData(mitk::DataNode::Pointer node); - void SetData(mitk::DataNode::Pointer node, mitk::SliceNavigationController::ViewDirection view); + void SetData(mitk::DataNode::Pointer node, mitk::AnatomicalPlane view); - void InitWidget(mitk::SliceNavigationController::ViewDirection viewDirection); + void InitWidget(mitk::AnatomicalPlane viewDirection); void wheelEvent(QWheelEvent *e) override; void ChangeView(QAction *val); void SetLevelWindowEnabled(bool enable); protected: QmitkRenderWindow *m_RenderWindow; - mitk::SliceNavigationController::ViewDirection m_View; + mitk::AnatomicalPlane m_View; private: bool popUpEnabled; mitk::VtkPropRenderer::Pointer m_Renderer; mitk::SlicedGeometry3D::Pointer m_SlicedGeometry; mitk::StandaloneDataStorage::Pointer m_DataStorage; QMenu *popUp; }; #endif diff --git a/Modules/QtWidgetsExt/src/QmitkSliceWidget.cpp b/Modules/QtWidgetsExt/src/QmitkSliceWidget.cpp index a41b09e285..3a8462c70b 100644 --- a/Modules/QtWidgetsExt/src/QmitkSliceWidget.cpp +++ b/Modules/QtWidgetsExt/src/QmitkSliceWidget.cpp @@ -1,266 +1,266 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "QmitkSliceWidget.h" #include "QmitkStepperAdapter.h" #include "mitkCameraController.h" #include "mitkImage.h" #include "mitkNodePredicateDataType.h" #include #include #include #include QmitkSliceWidget::QmitkSliceWidget(QWidget *parent, const char *name, Qt::WindowFlags f) : QWidget(parent, f) { this->setupUi(this); if (name != nullptr) this->setObjectName(name); popUp = new QMenu(this); popUp->addAction("Axial"); popUp->addAction("Coronal"); popUp->addAction("Sagittal"); QObject::connect(popUp, SIGNAL(triggered(QAction *)), this, SLOT(ChangeView(QAction *))); setPopUpEnabled(false); m_SlicedGeometry = nullptr; - m_View = mitk::SliceNavigationController::Axial; + m_View = mitk::AnatomicalPlane::Axial; QHBoxLayout *hlayout = new QHBoxLayout(container); hlayout->setMargin(0); // create widget QString composedName("QmitkSliceWidget::"); if (!this->objectName().isEmpty()) composedName += this->objectName(); else composedName += "QmitkGLWidget"; m_RenderWindow = new QmitkRenderWindow(container, composedName); m_Renderer = m_RenderWindow->GetRenderer(); hlayout->addWidget(m_RenderWindow); new QmitkStepperAdapter(sliceNavigationWidget, m_RenderWindow->GetSliceNavigationController()->GetSlice()); SetLevelWindowEnabled(true); } mitk::VtkPropRenderer *QmitkSliceWidget::GetRenderer() { return m_Renderer; } QFrame *QmitkSliceWidget::GetSelectionFrame() { return SelectionFrame; } void QmitkSliceWidget::SetDataStorage(mitk::StandaloneDataStorage::Pointer storage) { m_DataStorage = storage; m_Renderer->SetDataStorage(m_DataStorage); } mitk::StandaloneDataStorage *QmitkSliceWidget::GetDataStorage() { return m_DataStorage; } void QmitkSliceWidget::SetData(mitk::DataStorage::SetOfObjects::ConstIterator it) { SetData(it->Value(), m_View); } void QmitkSliceWidget::SetData(mitk::DataStorage::SetOfObjects::ConstIterator it, - mitk::SliceNavigationController::ViewDirection view) + mitk::AnatomicalPlane view) { SetData(it->Value(), view); } void QmitkSliceWidget::SetData(mitk::DataNode::Pointer node) { try { if (m_DataStorage.IsNotNull()) { m_DataStorage->Add(node); } } catch (...) { } SetData(node, m_View); } -void QmitkSliceWidget::SetData(mitk::DataNode::Pointer node, mitk::SliceNavigationController::ViewDirection view) +void QmitkSliceWidget::SetData(mitk::DataNode::Pointer node, mitk::AnatomicalPlane view) { mitk::Image::Pointer image = dynamic_cast(node->GetData()); if (image.IsNull()) { MITK_WARN << "QmitkSliceWidget data is not an image!"; return; } m_SlicedGeometry = image->GetSlicedGeometry(); this->InitWidget(view); } -void QmitkSliceWidget::InitWidget(mitk::SliceNavigationController::ViewDirection viewDirection) +void QmitkSliceWidget::InitWidget(mitk::AnatomicalPlane view) { - m_View = viewDirection; + m_View = view; mitk::SliceNavigationController *controller = m_RenderWindow->GetSliceNavigationController(); - if (viewDirection == mitk::SliceNavigationController::Axial) + if (view == mitk::AnatomicalPlane::Axial) { - controller->SetViewDirection(mitk::SliceNavigationController::Axial); + controller->SetViewDirection(mitk::AnatomicalPlane::Axial); } - else if (viewDirection == mitk::SliceNavigationController::Coronal) + else if (view == mitk::AnatomicalPlane::Coronal) { - controller->SetViewDirection(mitk::SliceNavigationController::Coronal); + controller->SetViewDirection(mitk::AnatomicalPlane::Coronal); } - // init sagittal view + // init sagittal view for all other cases ('original' is covered here as well) else { - controller->SetViewDirection(mitk::SliceNavigationController::Sagittal); + controller->SetViewDirection(mitk::AnatomicalPlane::Sagittal); } if (m_SlicedGeometry.IsNull()) { return; } mitk::BaseGeometry::Pointer geometry = static_cast(m_SlicedGeometry->Clone().GetPointer()); const mitk::BoundingBox::Pointer boundingbox = m_DataStorage->ComputeVisibleBoundingBox(GetRenderer(), nullptr); if (boundingbox->GetPoints()->Size() > 0) { // let's see if we have data with a limited live-span ... mitk::TimeBounds timebounds = m_DataStorage->ComputeTimeBounds(GetRenderer(), nullptr); mitk::ProportionalTimeGeometry::Pointer timeGeometry = mitk::ProportionalTimeGeometry::New(); timeGeometry->Initialize(geometry, 1); { timeGeometry->SetFirstTimePoint(timebounds[0]); timeGeometry->SetStepDuration(1.0); } if (timeGeometry->GetBoundingBoxInWorld()->GetDiagonalLength2() >= mitk::eps) { controller->SetInputWorldTimeGeometry(timeGeometry); controller->Update(); } } GetRenderer()->GetCameraController()->Fit(); mitk::RenderingManager::GetInstance()->RequestUpdate(GetRenderer()->GetRenderWindow()); } void QmitkSliceWidget::UpdateGL() { GetRenderer()->GetCameraController()->Fit(); mitk::RenderingManager::GetInstance()->RequestUpdate(GetRenderer()->GetRenderWindow()); } void QmitkSliceWidget::mousePressEvent(QMouseEvent *e) { if (e->button() == Qt::RightButton && popUpEnabled) { popUp->popup(QCursor::pos()); } } void QmitkSliceWidget::wheelEvent(QWheelEvent *e) { int val = sliceNavigationWidget->GetPos(); if (e->orientation() * e->delta() > 0) { sliceNavigationWidget->SetPos(val + 1); } else { if (val > 0) sliceNavigationWidget->SetPos(val - 1); } } void QmitkSliceWidget::ChangeView(QAction *val) { if (val->text() == "Axial") { - InitWidget(mitk::SliceNavigationController::Axial); + InitWidget(mitk::AnatomicalPlane::Axial); } else if (val->text() == "Coronal") { - InitWidget(mitk::SliceNavigationController::Coronal); + InitWidget(mitk::AnatomicalPlane::Coronal); } else if (val->text() == "Sagittal") { - InitWidget(mitk::SliceNavigationController::Sagittal); + InitWidget(mitk::AnatomicalPlane::Sagittal); } } void QmitkSliceWidget::setPopUpEnabled(bool b) { popUpEnabled = b; } QmitkSliceNavigationWidget* QmitkSliceWidget::GetSliceNavigationWidget() { return sliceNavigationWidget; } void QmitkSliceWidget::SetLevelWindowEnabled(bool enable) { levelWindow->setEnabled(enable); if (!enable) { levelWindow->setMinimumWidth(0); levelWindow->setMaximumWidth(0); } else { levelWindow->setMinimumWidth(28); levelWindow->setMaximumWidth(28); } } bool QmitkSliceWidget::IsLevelWindowEnabled() { return levelWindow->isEnabled(); } QmitkRenderWindow *QmitkSliceWidget::GetRenderWindow() { return m_RenderWindow; } mitk::SliceNavigationController *QmitkSliceWidget::GetSliceNavigationController() const { return m_RenderWindow->GetSliceNavigationController(); } mitk::CameraRotationController *QmitkSliceWidget::GetCameraRotationController() const { return m_RenderWindow->GetCameraRotationController(); } mitk::BaseController *QmitkSliceWidget::GetController() const { return m_RenderWindow->GetController(); } diff --git a/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageInspector.cpp b/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageInspector.cpp index b06b5ca790..8094567bc2 100644 --- a/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageInspector.cpp +++ b/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageInspector.cpp @@ -1,167 +1,167 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // render window manager UI module #include "QmitkRenderWindowDataStorageInspector.h" #include "QmitkCustomVariants.h" // mitk core #include // qt #include QmitkRenderWindowDataStorageInspector::QmitkRenderWindowDataStorageInspector(QWidget* parent /*=nullptr*/) : QmitkAbstractDataStorageInspector(parent) { m_Controls.setupUi(this); // initialize the render window layer controller and the render window view direction controller m_RenderWindowLayerController = std::make_unique(); m_RenderWindowViewDirectionController = std::make_unique(); m_StorageModel = std::make_unique(this); m_Controls.renderWindowTreeView->setModel(m_StorageModel.get()); m_Controls.renderWindowTreeView->setHeaderHidden(true); m_Controls.renderWindowTreeView->setEditTriggers(QAbstractItemView::NoEditTriggers); m_Controls.renderWindowTreeView->setSelectionBehavior(QAbstractItemView::SelectRows); m_Controls.renderWindowTreeView->setSelectionMode(QAbstractItemView::ExtendedSelection); m_Controls.renderWindowTreeView->setAlternatingRowColors(true); m_Controls.renderWindowTreeView->setDragEnabled(true); m_Controls.renderWindowTreeView->setDropIndicatorShown(true); m_Controls.renderWindowTreeView->setAcceptDrops(true); m_Controls.renderWindowTreeView->setContextMenuPolicy(Qt::CustomContextMenu); SetUpConnections(); } QAbstractItemView* QmitkRenderWindowDataStorageInspector::GetView() { return m_Controls.renderWindowTreeView; } const QAbstractItemView* QmitkRenderWindowDataStorageInspector::GetView() const { return m_Controls.renderWindowTreeView; } void QmitkRenderWindowDataStorageInspector::SetSelectionMode(SelectionMode mode) { m_Controls.renderWindowTreeView->setSelectionMode(mode); } QmitkRenderWindowDataStorageInspector::SelectionMode QmitkRenderWindowDataStorageInspector::GetSelectionMode() const { return m_Controls.renderWindowTreeView->selectionMode(); } void QmitkRenderWindowDataStorageInspector::Initialize() { auto dataStorage = m_DataStorage.Lock(); if (dataStorage.IsNull()) return; m_StorageModel->SetDataStorage(dataStorage); m_StorageModel->SetNodePredicate(m_NodePredicate); m_RenderWindowLayerController->SetDataStorage(dataStorage); m_RenderWindowViewDirectionController->SetDataStorage(dataStorage); m_Connector->SetView(m_Controls.renderWindowTreeView); } void QmitkRenderWindowDataStorageInspector::SetUpConnections() { connect(m_StorageModel.get(), &QAbstractItemModel::rowsInserted, this, &QmitkRenderWindowDataStorageInspector::ModelRowsInserted); connect(m_Controls.pushButtonSetAsBaseLayer, &QPushButton::clicked, this, &QmitkRenderWindowDataStorageInspector::SetAsBaseLayer); connect(m_Controls.pushButtonResetRenderer, &QPushButton::clicked, this, &QmitkRenderWindowDataStorageInspector::ResetRenderer); QSignalMapper* changeViewDirectionSignalMapper = new QSignalMapper(this); changeViewDirectionSignalMapper->setMapping(m_Controls.radioButtonAxial, QString("axial")); changeViewDirectionSignalMapper->setMapping(m_Controls.radioButtonCoronal, QString("coronal")); changeViewDirectionSignalMapper->setMapping(m_Controls.radioButtonSagittal, QString("sagittal")); changeViewDirectionSignalMapper->setMapping(m_Controls.radioButton3D, QString("3D")); connect(changeViewDirectionSignalMapper, static_cast(&QSignalMapper::mapped), this, &QmitkRenderWindowDataStorageInspector::ChangeViewDirection); connect(m_Controls.radioButtonAxial, &QPushButton::clicked, changeViewDirectionSignalMapper, static_cast(&QSignalMapper::map)); connect(m_Controls.radioButtonCoronal, &QPushButton::clicked, changeViewDirectionSignalMapper, static_cast(&QSignalMapper::map)); connect(m_Controls.radioButtonSagittal, &QPushButton::clicked, changeViewDirectionSignalMapper, static_cast(&QSignalMapper::map)); connect(m_Controls.radioButton3D, &QPushButton::clicked, changeViewDirectionSignalMapper, static_cast(&QSignalMapper::map)); } void QmitkRenderWindowDataStorageInspector::SetControlledRenderer(mitk::RenderWindowLayerUtilities::RendererVector controlledRenderer) { m_StorageModel->SetControlledRenderer(controlledRenderer); m_RenderWindowLayerController->SetControlledRenderer(controlledRenderer); m_RenderWindowViewDirectionController->SetControlledRenderer(controlledRenderer); } void QmitkRenderWindowDataStorageInspector::SetActiveRenderWindow(const QString& renderWindowId) { mitk::BaseRenderer* selectedRenderer = mitk::BaseRenderer::GetByName(renderWindowId.toStdString()); if (nullptr == selectedRenderer) { return; } m_StorageModel->SetCurrentRenderer(selectedRenderer); - mitk::SliceNavigationController::ViewDirection viewDirection = selectedRenderer->GetSliceNavigationController()->GetDefaultViewDirection(); + mitk::AnatomicalPlane viewDirection = selectedRenderer->GetSliceNavigationController()->GetDefaultViewDirection(); switch (viewDirection) { - case mitk::SliceNavigationController::Axial: + case mitk::AnatomicalPlane::Axial: m_Controls.radioButtonAxial->setChecked(true); break; - case mitk::SliceNavigationController::Coronal: + case mitk::AnatomicalPlane::Coronal: m_Controls.radioButtonCoronal->setChecked(true); break; - case mitk::SliceNavigationController::Sagittal: + case mitk::AnatomicalPlane::Sagittal: m_Controls.radioButtonSagittal->setChecked(true); break; default: break; } } void QmitkRenderWindowDataStorageInspector::ModelRowsInserted(const QModelIndex& parent, int /*start*/, int /*end*/) { m_Controls.renderWindowTreeView->setExpanded(parent, true); } void QmitkRenderWindowDataStorageInspector::SetAsBaseLayer() { QModelIndex selectedIndex = m_Controls.renderWindowTreeView->currentIndex(); if (selectedIndex.isValid()) { QVariant qvariantDataNode = m_StorageModel->data(selectedIndex, Qt::UserRole); if (qvariantDataNode.canConvert()) { mitk::DataNode* dataNode = qvariantDataNode.value(); m_RenderWindowLayerController->SetBaseDataNode(dataNode, m_StorageModel->GetCurrentRenderer()); m_Controls.renderWindowTreeView->clearSelection(); } } } void QmitkRenderWindowDataStorageInspector::ResetRenderer() { m_RenderWindowLayerController->ResetRenderer(true, m_StorageModel->GetCurrentRenderer()); m_Controls.renderWindowTreeView->clearSelection(); } void QmitkRenderWindowDataStorageInspector::ChangeViewDirection(const QString& viewDirection) { m_RenderWindowViewDirectionController->SetViewDirectionOfRenderer(viewDirection.toStdString(), m_StorageModel->GetCurrentRenderer()); } diff --git a/Modules/Segmentation/Algorithms/mitkContourModelSetToImageFilter.cpp b/Modules/Segmentation/Algorithms/mitkContourModelSetToImageFilter.cpp index 5dfd573cd4..6cfcd9af94 100644 --- a/Modules/Segmentation/Algorithms/mitkContourModelSetToImageFilter.cpp +++ b/Modules/Segmentation/Algorithms/mitkContourModelSetToImageFilter.cpp @@ -1,271 +1,271 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkContourModelSetToImageFilter.h" #include #include #include #include #include #include #include mitk::ContourModelSetToImageFilter::ContourModelSetToImageFilter() : m_MakeOutputBinary(true), m_TimeStep(0), m_ReferenceImage(nullptr) { // Create the output. itk::DataObject::Pointer output = this->MakeOutput(0); Superclass::SetNumberOfRequiredInputs(1); Superclass::SetNumberOfRequiredOutputs(1); Superclass::SetNthOutput(0, output); } mitk::ContourModelSetToImageFilter::~ContourModelSetToImageFilter() { } void mitk::ContourModelSetToImageFilter::GenerateInputRequestedRegion() { mitk::Image *output = this->GetOutput(); if ((output->IsInitialized() == false)) return; GenerateTimeInInputRegion(output, const_cast(m_ReferenceImage)); } void mitk::ContourModelSetToImageFilter::GenerateOutputInformation() { mitk::Image::Pointer output = this->GetOutput(); itkDebugMacro(<< "GenerateOutputInformation()"); if ((m_ReferenceImage == nullptr) || (m_ReferenceImage->IsInitialized() == false) || (m_ReferenceImage->GetTimeGeometry() == nullptr)) return; if (m_MakeOutputBinary) { output->Initialize(mitk::MakeScalarPixelType(), *m_ReferenceImage->GetTimeGeometry(), 1); } else { output->Initialize(m_ReferenceImage->GetPixelType(), *m_ReferenceImage->GetTimeGeometry()); } output->SetPropertyList(m_ReferenceImage->GetPropertyList()->Clone()); } itk::DataObject::Pointer mitk::ContourModelSetToImageFilter::MakeOutput(DataObjectPointerArraySizeType /*idx*/) { return OutputType::New().GetPointer(); } itk::DataObject::Pointer mitk::ContourModelSetToImageFilter::MakeOutput(const DataObjectIdentifierType &name) { itkDebugMacro("MakeOutput(" << name << ")"); if (this->IsIndexedOutputName(name)) { return this->MakeOutput(this->MakeIndexFromOutputName(name)); } return OutputType::New().GetPointer(); } const mitk::ContourModelSet *mitk::ContourModelSetToImageFilter::GetInput(void) { if (this->GetNumberOfInputs() < 1) { return nullptr; } return static_cast(this->ProcessObject::GetInput(0)); } void mitk::ContourModelSetToImageFilter::SetInput(const ContourModelSet *input) { // Process object is not const-correct so the const_cast is required here this->ProcessObject::SetNthInput(0, const_cast(input)); } void mitk::ContourModelSetToImageFilter::SetImage(const mitk::Image *refImage) { m_ReferenceImage = refImage; } const mitk::Image *mitk::ContourModelSetToImageFilter::GetImage(void) { return m_ReferenceImage; } void mitk::ContourModelSetToImageFilter::GenerateData() { auto *contourSet = const_cast(this->GetInput()); // Initializing progressbar unsigned int num_contours = contourSet->GetContourModelList()->size(); mitk::ProgressBar::GetInstance()->AddStepsToDo(num_contours); // Assure that the volume data of the output is set (fill volume with zeros) this->InitializeOutputEmpty(); mitk::Image::Pointer outputImage = const_cast(this->GetOutput()); if (outputImage.IsNull() || outputImage->IsInitialized() == false || !outputImage->IsVolumeSet(m_TimeStep)) { mitkThrow() << "Error creating output for specified image!"; } if (!contourSet || contourSet->GetContourModelList()->size() == 0) { mitkThrow() << "No contours specified!"; } mitk::BaseGeometry *outputImageGeo = outputImage->GetGeometry(m_TimeStep); // Create mitkVtkImageOverwrite which is needed to write the slice back into the volume vtkSmartPointer reslice = vtkSmartPointer::New(); // Create ExtractSliceFilter for extracting the corresponding slices from the volume mitk::ExtractSliceFilter::Pointer extractor = mitk::ExtractSliceFilter::New(reslice); extractor->SetInput(outputImage); extractor->SetTimeStep(m_TimeStep); extractor->SetResliceTransformByGeometry(outputImageGeo); // Fill each contour of the contourmodelset into the image auto it = contourSet->Begin(); auto end = contourSet->End(); while (it != end) { mitk::ContourModel *contour = it->GetPointer(); // 1. Create slice geometry using the contour points mitk::PlaneGeometry::Pointer plane = mitk::PlaneGeometry::New(); mitk::Point3D point3D, tempPoint; mitk::Vector3D normal; mitk::Image::Pointer slice; int sliceIndex; bool isFrontside = true; bool isRotated = false; // Determine plane orientation point3D = contour->GetVertexAt(0)->Coordinates; tempPoint = contour->GetVertexAt(contour->GetNumberOfVertices() * 0.25)->Coordinates; mitk::Vector3D vec = point3D - tempPoint; vec.Normalize(); outputImageGeo->WorldToIndex(point3D, point3D); - mitk::PlaneGeometry::PlaneOrientation orientation; + mitk::AnatomicalPlane orientation; if (mitk::Equal(vec[0], 0)) { - orientation = mitk::PlaneGeometry::Sagittal; + orientation = mitk::AnatomicalPlane::Sagittal; sliceIndex = point3D[0]; } else if (mitk::Equal(vec[1], 0)) { - orientation = mitk::PlaneGeometry::Coronal; + orientation = mitk::AnatomicalPlane::Coronal; sliceIndex = point3D[1]; } else if (mitk::Equal(vec[2], 0)) { - orientation = mitk::PlaneGeometry::Axial; + orientation = mitk::AnatomicalPlane::Axial; sliceIndex = point3D[2]; } else { // TODO Maybe rotate geometry to extract slice? MITK_ERROR << "Cannot detect correct slice number! Only axial, sagittal and coronal oriented contours are supported!"; return; } // Initialize plane using the detected orientation plane->InitializeStandardPlane(outputImageGeo, orientation, sliceIndex, isFrontside, isRotated); point3D = plane->GetOrigin(); normal = plane->GetNormal(); normal.Normalize(); point3D += normal * 0.5; // pixelspacing is 1, so half the spacing is 0.5 plane->SetOrigin(point3D); // 2. Extract slice at the given position extractor->SetWorldGeometry(plane); extractor->SetVtkOutputRequest(false); reslice->SetOverwriteMode(false); extractor->Modified(); extractor->Update(); slice = extractor->GetOutput(); slice->DisconnectPipeline(); // 3. Fill contour into slice mitk::ContourModel::Pointer projectedContour = mitk::ContourModelUtils::ProjectContourTo2DSlice(slice, contour); mitk::ContourModelUtils::FillContourInSlice(projectedContour, slice, outputImage); // 4. Write slice back into image volume reslice->SetInputSlice(slice->GetVtkImageData()); // set overwrite mode to true to write back to the image volume reslice->SetOverwriteMode(true); reslice->Modified(); extractor->Modified(); extractor->Update(); reslice->SetInputSlice(nullptr); // Progress mitk::ProgressBar::GetInstance()->Progress(); ++it; } outputImage->Modified(); outputImage->GetVtkImageData()->Modified(); } void mitk::ContourModelSetToImageFilter::InitializeOutputEmpty() { // Initialize the output's volume with zeros mitk::Image *output = this->GetOutput(); unsigned int byteSize = output->GetPixelType().GetSize(); if (output->GetDimension() < 4) { for (unsigned int dim = 0; dim < output->GetDimension(); ++dim) { byteSize *= output->GetDimension(dim); } mitk::ImageWriteAccessor writeAccess(output, output->GetVolumeData(0)); memset(writeAccess.GetData(), 0, byteSize); } else { // if we have a time-resolved image we need to set memory to 0 for each time step for (unsigned int dim = 0; dim < 3; ++dim) { byteSize *= output->GetDimension(dim); } for (unsigned int volumeNumber = 0; volumeNumber < output->GetDimension(3); volumeNumber++) { mitk::ImageWriteAccessor writeAccess(output, output->GetVolumeData(volumeNumber)); memset(writeAccess.GetData(), 0, byteSize); } } } diff --git a/Modules/Segmentation/Testing/mitkOverwriteSliceFilterObliquePlaneTest.cpp b/Modules/Segmentation/Testing/mitkOverwriteSliceFilterObliquePlaneTest.cpp index 4ca94842ef..a6bb783040 100644 --- a/Modules/Segmentation/Testing/mitkOverwriteSliceFilterObliquePlaneTest.cpp +++ b/Modules/Segmentation/Testing/mitkOverwriteSliceFilterObliquePlaneTest.cpp @@ -1,254 +1,254 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include #include #include #include #include #include #include #include #include #include #include int ObliquePlaneTestVolumeSize = 128; static void OverwriteObliquePlaneTest(mitk::Image *workingImage, mitk::Image *refImg) { /*==============TEST WITHOUT MITK CONVERTION=============================*/ /* ============= setup plane ============*/ auto sliceindex = (int)(ObliquePlaneTestVolumeSize / 2); // rand() % 32; bool isFrontside = true; bool isRotated = false; mitk::PlaneGeometry::Pointer obliquePlane = mitk::PlaneGeometry::New(); obliquePlane->InitializeStandardPlane( - workingImage->GetGeometry(), mitk::PlaneGeometry::Axial, sliceindex, isFrontside, isRotated); + workingImage->GetGeometry(), mitk::AnatomicalPlane::Axial, sliceindex, isFrontside, isRotated); mitk::Point3D origin = obliquePlane->GetOrigin(); mitk::Vector3D normal; normal = obliquePlane->GetNormal(); normal.Normalize(); origin += normal * 0.5; // pixelspacing is 1, so half the spacing is 0.5 obliquePlane->SetOrigin(origin); mitk::Vector3D rotationVector = obliquePlane->GetAxisVector(0); rotationVector.Normalize(); float degree = 45.0; auto op = new mitk::RotationOperation(mitk::OpROTATE, obliquePlane->GetCenter(), rotationVector, degree); obliquePlane->ExecuteOperation(op); delete op; /* ============= extract slice ============*/ mitk::ExtractSliceFilter::Pointer slicer = mitk::ExtractSliceFilter::New(); slicer->SetInput(workingImage); slicer->SetWorldGeometry(obliquePlane); slicer->SetVtkOutputRequest(true); slicer->Modified(); slicer->Update(); vtkSmartPointer slice = vtkSmartPointer::New(); slice = slicer->GetVtkOutput(); /* ============= overwrite slice ============*/ vtkSmartPointer resliceIdx = vtkSmartPointer::New(); mitk::ExtractSliceFilter::Pointer overwriter = mitk::ExtractSliceFilter::New(resliceIdx); resliceIdx->SetOverwriteMode(true); resliceIdx->SetInputSlice(slice); resliceIdx->Modified(); overwriter->SetInput(workingImage); overwriter->SetWorldGeometry(obliquePlane); overwriter->SetVtkOutputRequest(true); overwriter->Modified(); overwriter->Update(); typedef mitk::ImagePixelReadAccessor ReadAccessorType; ReadAccessorType refImgReadAccessor(refImg); ReadAccessorType workingImgReadAccessor(workingImage); /* ============= check ref == working ============*/ bool areSame = true; itk::Index<3> id; id[0] = id[1] = id[2] = 0; for (int x = 0; x < ObliquePlaneTestVolumeSize; ++x) { id[0] = x; for (int y = 0; y < ObliquePlaneTestVolumeSize; ++y) { id[1] = y; for (int z = 0; z < ObliquePlaneTestVolumeSize; ++z) { id[2] = z; areSame = refImgReadAccessor.GetPixelByIndex(id) == workingImgReadAccessor.GetPixelByIndex(id); if (!areSame) goto stop; } } } stop: MITK_TEST_CONDITION(areSame, "comparing images (no mitk convertion) [oblique]"); /*==============TEST WITH MITK CONVERTION=============================*/ /* ============= extract slice ============*/ mitk::ExtractSliceFilter::Pointer slicer2 = mitk::ExtractSliceFilter::New(); slicer2->SetInput(workingImage); slicer2->SetWorldGeometry(obliquePlane); slicer2->Modified(); slicer2->Update(); mitk::Image::Pointer sliceInMitk = slicer2->GetOutput(); vtkSmartPointer slice2 = vtkSmartPointer::New(); slice2 = sliceInMitk->GetVtkImageData(); /* ============= overwrite slice ============*/ vtkSmartPointer resliceIdx2 = vtkSmartPointer::New(); mitk::ExtractSliceFilter::Pointer overwriter2 = mitk::ExtractSliceFilter::New(resliceIdx2); resliceIdx2->SetOverwriteMode(true); resliceIdx2->SetInputSlice(slice2); resliceIdx2->Modified(); overwriter2->SetInput(workingImage); overwriter2->SetWorldGeometry(obliquePlane); overwriter2->SetVtkOutputRequest(true); overwriter2->Modified(); overwriter2->Update(); /* ============= check ref == working ============*/ areSame = true; id[0] = id[1] = id[2] = 0; for (int x = 0; x < ObliquePlaneTestVolumeSize; ++x) { id[0] = x; for (int y = 0; y < ObliquePlaneTestVolumeSize; ++y) { id[1] = y; for (int z = 0; z < ObliquePlaneTestVolumeSize; ++z) { id[2] = z; areSame = refImgReadAccessor.GetPixelByIndex(id) == workingImgReadAccessor.GetPixelByIndex(id); if (!areSame) goto stop2; } } } stop2: MITK_TEST_CONDITION(areSame, "comparing images (with mitk convertion) [oblique]"); /*==============TEST EDIT WITHOUT MITK CONVERTION=============================*/ /* ============= edit slice ============*/ int idX = std::abs(ObliquePlaneTestVolumeSize - 59); int idY = std::abs(ObliquePlaneTestVolumeSize - 23); int idZ = 0; int component = 0; double val = 33.0; slice->SetScalarComponentFromDouble(idX, idY, idZ, component, val); mitk::Vector3D indx; indx[0] = idX; indx[1] = idY; indx[2] = idZ; sliceInMitk->GetGeometry()->IndexToWorld(indx, indx); /* ============= overwrite slice ============*/ vtkSmartPointer resliceIdx3 = vtkSmartPointer::New(); resliceIdx3->SetOverwriteMode(true); resliceIdx3->SetInputSlice(slice); mitk::ExtractSliceFilter::Pointer overwriter3 = mitk::ExtractSliceFilter::New(resliceIdx3); overwriter3->SetInput(workingImage); overwriter3->SetWorldGeometry(obliquePlane); overwriter3->SetVtkOutputRequest(true); overwriter3->Modified(); overwriter3->Update(); /* ============= check ============*/ areSame = true; int x = 0; int y = 0; int z = 0; for (x = 0; x < ObliquePlaneTestVolumeSize; ++x) { id[0] = x; for (y = 0; y < ObliquePlaneTestVolumeSize; ++y) { id[1] = y; for (z = 0; z < ObliquePlaneTestVolumeSize; ++z) { id[2] = z; areSame = refImgReadAccessor.GetPixelByIndex(id) == workingImgReadAccessor.GetPixelByIndex(id); if (!areSame) goto stop3; } } } stop3: MITK_TEST_CONDITION(x == idX && y == z, "overwrited the right index [oblique]"); } /*================ #BEGIN test main ================*/ int mitkOverwriteSliceFilterObliquePlaneTest(int, char *[]) { MITK_TEST_BEGIN("mitkOverwriteSliceFilterObliquePlaneTest") typedef itk::Image ImageType; typedef itk::ImageRegionConstIterator ImageIterator; ImageType::Pointer image = ImageType::New(); ImageType::IndexType start; start[0] = start[1] = start[2] = 0; ImageType::SizeType size; size[0] = size[1] = size[2] = ObliquePlaneTestVolumeSize; ImageType::RegionType imgRegion; imgRegion.SetSize(size); imgRegion.SetIndex(start); image->SetRegions(imgRegion); image->SetSpacing(1.0); image->Allocate(); ImageIterator imageIterator(image, image->GetLargestPossibleRegion()); imageIterator.GoToBegin(); unsigned short pixelValue = 0; // fill the image with distinct values while (!imageIterator.IsAtEnd()) { image->SetPixel(imageIterator.GetIndex(), pixelValue); ++imageIterator; ++pixelValue; } /* end setup itk image */ mitk::Image::Pointer refImage; CastToMitkImage(image, refImage); mitk::Image::Pointer workingImg; CastToMitkImage(image, workingImg); OverwriteObliquePlaneTest(workingImg, refImage); MITK_TEST_END() } diff --git a/Modules/Segmentation/Testing/mitkOverwriteSliceFilterTest.cpp b/Modules/Segmentation/Testing/mitkOverwriteSliceFilterTest.cpp index 12c7666fa1..6b67791740 100644 --- a/Modules/Segmentation/Testing/mitkOverwriteSliceFilterTest.cpp +++ b/Modules/Segmentation/Testing/mitkOverwriteSliceFilterTest.cpp @@ -1,181 +1,181 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include #include #include #include #include #include #include #include #include #include #include int VolumeSize = 128; /*================ #BEGIN test main ================*/ int mitkOverwriteSliceFilterTest(int, char *[]) { MITK_TEST_BEGIN("mitkOverwriteSliceFilterTest") typedef itk::Image ImageType; typedef itk::ImageRegionConstIterator ImageIterator; ImageType::Pointer image = ImageType::New(); ImageType::IndexType start; start[0] = start[1] = start[2] = 0; ImageType::SizeType size; size[0] = size[1] = size[2] = VolumeSize; ImageType::RegionType imgRegion; imgRegion.SetSize(size); imgRegion.SetIndex(start); image->SetRegions(imgRegion); image->SetSpacing(1.0); image->Allocate(); ImageIterator imageIterator(image, image->GetLargestPossibleRegion()); imageIterator.GoToBegin(); unsigned short pixelValue = 0; // fill the image with distinct values while (!imageIterator.IsAtEnd()) { image->SetPixel(imageIterator.GetIndex(), pixelValue); ++imageIterator; ++pixelValue; } /* end setup itk image */ mitk::Image::Pointer referenceImage; CastToMitkImage(image, referenceImage); mitk::Image::Pointer workingImage; CastToMitkImage(image, workingImage); typedef mitk::ImagePixelReadAccessor ReadAccessorType; ReadAccessorType refImgReadAccessor(referenceImage); ReadAccessorType workingImgReadAccessor(workingImage); /* ============= setup plane ============*/ int sliceindex = 55; // rand() % 32; bool isFrontside = true; bool isRotated = false; mitk::PlaneGeometry::Pointer plane = mitk::PlaneGeometry::New(); plane->InitializeStandardPlane( - workingImage->GetGeometry(), mitk::PlaneGeometry::Axial, sliceindex, isFrontside, isRotated); + workingImage->GetGeometry(), mitk::AnatomicalPlane::Axial, sliceindex, isFrontside, isRotated); mitk::Point3D origin = plane->GetOrigin(); mitk::Vector3D normal; normal = plane->GetNormal(); normal.Normalize(); origin += normal * 0.5; // pixelspacing is 1, so half the spacing is 0.5 plane->SetOrigin(origin); /* ============= extract slice ============*/ vtkSmartPointer resliceIdx = vtkSmartPointer::New(); mitk::ExtractSliceFilter::Pointer slicer = mitk::ExtractSliceFilter::New(resliceIdx); slicer->SetInput(workingImage); slicer->SetWorldGeometry(plane); slicer->SetVtkOutputRequest(true); slicer->Modified(); slicer->Update(); vtkSmartPointer slice = vtkSmartPointer::New(); slice = slicer->GetVtkOutput(); /* ============= overwrite slice ============*/ resliceIdx->SetOverwriteMode(true); resliceIdx->Modified(); slicer->Modified(); slicer->Update(); // implicit overwrite /* ============= check ref == working ============*/ bool areSame = true; itk::Index<3> id; id[0] = id[1] = id[2] = 0; for (int x = 0; x < VolumeSize; ++x) { id[0] = x; for (int y = 0; y < VolumeSize; ++y) { id[1] = y; for (int z = 0; z < VolumeSize; ++z) { id[2] = z; areSame = refImgReadAccessor.GetPixelByIndex(id) == workingImgReadAccessor.GetPixelByIndex(id); if (!areSame) goto stop; } } } stop: MITK_TEST_CONDITION(areSame, "test overwrite unmodified slice"); /* ============= edit slice ============*/ int idX = std::abs(VolumeSize - 59); int idY = std::abs(VolumeSize - 23); int idZ = 0; int component = 0; double val = 33.0; slice->SetScalarComponentFromDouble(idX, idY, idZ, component, val); /* ============= overwrite slice ============*/ vtkSmartPointer resliceIdx2 = vtkSmartPointer::New(); resliceIdx2->SetOverwriteMode(true); resliceIdx2->SetInputSlice(slice); mitk::ExtractSliceFilter::Pointer slicer2 = mitk::ExtractSliceFilter::New(resliceIdx2); slicer2->SetInput(workingImage); slicer2->SetWorldGeometry(plane); slicer2->SetVtkOutputRequest(true); slicer2->Modified(); slicer2->Update(); /* ============= check ============*/ areSame = true; int xx = 0; int yy = 0; int zz = 0; for (xx = 0; xx < VolumeSize; ++xx) { id[0] = xx; for (yy = 0; yy < VolumeSize; ++yy) { id[1] = yy; for (zz = 0; zz < VolumeSize; ++zz) { id[2] = zz; areSame = refImgReadAccessor.GetPixelByIndex(id) == workingImgReadAccessor.GetPixelByIndex(id); if (!areSame) goto stop2; } } } stop2: // MITK_INFO << "index: [" << x << ", " << y << ", " << z << "]"; MITK_TEST_CONDITION(xx == idX && yy == idY && zz == sliceindex, "test overwrite modified slice"); MITK_TEST_END() } diff --git a/Modules/Segmentation/Testing/mitkSegmentationInterpolationTest.cpp b/Modules/Segmentation/Testing/mitkSegmentationInterpolationTest.cpp index bf904c8303..70db37c687 100644 --- a/Modules/Segmentation/Testing/mitkSegmentationInterpolationTest.cpp +++ b/Modules/Segmentation/Testing/mitkSegmentationInterpolationTest.cpp @@ -1,204 +1,204 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // Testing #include #include // other #include #include #include #include #include #include #include #include #include class mitkSegmentationInterpolationTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkSegmentationInterpolationTestSuite); MITK_TEST(Equal_Axial_TestInterpolationAndReferenceInterpolation_ReturnsTrue); MITK_TEST(Equal_Coronal_TestInterpolationAndReferenceInterpolation_ReturnsTrue); MITK_TEST(Equal_Sagittal_TestInterpolationAndReferenceInterpolation_ReturnsTrue); CPPUNIT_TEST_SUITE_END(); private: // The tests all do the same, only in different directions - void testRoutine(mitk::SliceNavigationController::ViewDirection viewDirection) + void testRoutine(mitk::AnatomicalPlane viewDirection) { int dim; switch (viewDirection) { - case (mitk::SliceNavigationController::Axial): + case (mitk::AnatomicalPlane::Axial): dim = 2; break; - case (mitk::SliceNavigationController::Coronal): + case (mitk::AnatomicalPlane::Coronal): dim = 1; break; - case (mitk::SliceNavigationController::Sagittal): + case (mitk::AnatomicalPlane::Sagittal): dim = 0; break; - default: // mitk::SliceNavigationController::Original + default: // mitk::AnatomicalPlane::Original dim = -1; break; } /* Fill segmentation * * 1st slice: 3x3 square segmentation * 2nd slice: empty * 3rd slice: 1x1 square segmentation in corner * -> 2nd slice should become 2x2 square in corner * * put accessor in scope */ itk::Index<3> currentPoint; { mitk::ImagePixelWriteAccessor writeAccessor(m_SegmentationImage); // Fill 3x3 slice currentPoint[dim] = m_CenterPoint[dim] - 1; for (int i = -1; i <= 1; ++i) { for (int j = -1; j <= 1; ++j) { currentPoint[(dim + 1) % 3] = m_CenterPoint[(dim + 1) % 3] + i; currentPoint[(dim + 2) % 3] = m_CenterPoint[(dim + 2) % 3] + j; writeAccessor.SetPixelByIndexSafe(currentPoint, 1); } } // Now i=j=1, set point two slices up currentPoint[dim] = m_CenterPoint[dim] + 1; writeAccessor.SetPixelByIndexSafe(currentPoint, 1); } // mitk::IOUtil::Save(m_SegmentationImage, "SOME PATH"); m_InterpolationController->SetSegmentationVolume(m_SegmentationImage); m_InterpolationController->SetReferenceVolume(m_ReferenceImage); // This could be easier... mitk::SliceNavigationController::Pointer navigationController = mitk::SliceNavigationController::New(); navigationController->SetInputWorldTimeGeometry(m_SegmentationImage->GetTimeGeometry()); navigationController->Update(viewDirection); mitk::Point3D pointMM; m_SegmentationImage->GetTimeGeometry()->GetGeometryForTimeStep(0)->IndexToWorld(m_CenterPoint, pointMM); navigationController->SelectSliceByPoint(pointMM); auto plane = navigationController->GetCurrentPlaneGeometry(); mitk::Image::Pointer interpolationResult = m_InterpolationController->Interpolate(dim, m_CenterPoint[dim], plane, 0); // mitk::IOUtil::Save(interpolationResult, "SOME PATH"); // Write result into segmentation image vtkSmartPointer reslicer = vtkSmartPointer::New(); reslicer->SetInputSlice( interpolationResult->GetSliceData()->GetVtkImageAccessor(interpolationResult)->GetVtkImageData()); reslicer->SetOverwriteMode(true); reslicer->Modified(); mitk::ExtractSliceFilter::Pointer extractor = mitk::ExtractSliceFilter::New(reslicer); extractor->SetInput(m_SegmentationImage); extractor->SetTimeStep(0); extractor->SetWorldGeometry(plane); extractor->SetVtkOutputRequest(true); extractor->SetResliceTransformByGeometry(m_SegmentationImage->GetTimeGeometry()->GetGeometryForTimeStep(0)); extractor->Modified(); extractor->Update(); // mitk::IOUtil::Save(m_SegmentationImage, "SOME PATH"); // Check a 4x4 square, the center of which needs to be filled mitk::ImagePixelReadAccessor readAccess(m_SegmentationImage); currentPoint = m_CenterPoint; for (int i = -1; i <= 2; ++i) { for (int j = -1; j <= 2; ++j) { currentPoint[(dim + 1) % 3] = m_CenterPoint[(dim + 1) % 3] + i; currentPoint[(dim + 2) % 3] = m_CenterPoint[(dim + 2) % 3] + j; if (i == -1 || i == 2 || j == -1 || j == 2) { CPPUNIT_ASSERT_MESSAGE("Have false positive segmentation.", readAccess.GetPixelByIndexSafe(currentPoint) == 0); } else { CPPUNIT_ASSERT_MESSAGE("Have false negative segmentation.", readAccess.GetPixelByIndexSafe(currentPoint) == 1); } } } } mitk::Image::Pointer m_ReferenceImage; mitk::Image::Pointer m_SegmentationImage; itk::Index<3> m_CenterPoint; mitk::SegmentationInterpolationController::Pointer m_InterpolationController; public: void setUp() override { m_ReferenceImage = mitk::IOUtil::Load(GetTestDataFilePath("Pic3D.nrrd")); CPPUNIT_ASSERT_MESSAGE("Failed to load image for test: [Pic3D.nrrd]", m_ReferenceImage.IsNotNull()); m_InterpolationController = mitk::SegmentationInterpolationController::GetInstance(); // Create empty segmentation // Surely there must be a better way to get an image with all zeros? m_SegmentationImage = mitk::Image::New(); const mitk::PixelType pixelType(mitk::MakeScalarPixelType()); m_SegmentationImage->Initialize(pixelType, m_ReferenceImage->GetDimension(), m_ReferenceImage->GetDimensions()); m_SegmentationImage->SetClonedTimeGeometry(m_ReferenceImage->GetTimeGeometry()); unsigned int size = sizeof(mitk::Tool::DefaultSegmentationDataType); for (unsigned int dim = 0; dim < m_SegmentationImage->GetDimension(); ++dim) { size *= m_SegmentationImage->GetDimension(dim); } mitk::ImageWriteAccessor imageAccessor(m_SegmentationImage); memset(imageAccessor.GetData(), 0, size); // Work in the center of the image (Pic3D) m_CenterPoint = {{127, 127, 25}}; } void tearDown() override { m_ReferenceImage = nullptr; m_SegmentationImage = nullptr; m_CenterPoint = {{0, 0, 0}}; } void Equal_Axial_TestInterpolationAndReferenceInterpolation_ReturnsTrue() { - mitk::SliceNavigationController::ViewDirection viewDirection = mitk::SliceNavigationController::Axial; + mitk::AnatomicalPlane viewDirection = mitk::AnatomicalPlane::Axial; testRoutine(viewDirection); } void Equal_Coronal_TestInterpolationAndReferenceInterpolation_ReturnsTrue() // Coronal { - mitk::SliceNavigationController::ViewDirection viewDirection = mitk::SliceNavigationController::Coronal; + mitk::AnatomicalPlane viewDirection = mitk::AnatomicalPlane::Coronal; testRoutine(viewDirection); } void Equal_Sagittal_TestInterpolationAndReferenceInterpolation_ReturnsTrue() { - mitk::SliceNavigationController::ViewDirection viewDirection = mitk::SliceNavigationController::Sagittal; + mitk::AnatomicalPlane viewDirection = mitk::AnatomicalPlane::Sagittal; testRoutine(viewDirection); } }; MITK_TEST_SUITE_REGISTRATION(mitkSegmentationInterpolation) diff --git a/Modules/SemanticRelationsUI/src/QmitkSemanticRelationsUIHelper.cpp b/Modules/SemanticRelationsUI/src/QmitkSemanticRelationsUIHelper.cpp index 647de9d1ea..cce4954a44 100644 --- a/Modules/SemanticRelationsUI/src/QmitkSemanticRelationsUIHelper.cpp +++ b/Modules/SemanticRelationsUI/src/QmitkSemanticRelationsUIHelper.cpp @@ -1,91 +1,91 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // semantic relations ui module #include // mitk core #include #include #include #include // vtk #include QPixmap QmitkSemanticRelationsUIHelper::GetPixmapFromImageNode(const mitk::DataNode* dataNode) { if (nullptr == dataNode) { return QPixmap(); } const mitk::Image* image = static_cast(dataNode->GetData()); if (nullptr == image || !image->IsInitialized()) { return QPixmap(); } if (image->GetPixelType().GetNumberOfComponents() != 1) // for now only single component are allowed { return QPixmap(); } mitk::PlaneGeometry::Pointer sagittalPlaneGeometry = mitk::PlaneGeometry::New(); int sliceNumber = image->GetDimension(1) / 2; - sagittalPlaneGeometry->InitializeStandardPlane(image->GetGeometry(), mitk::PlaneGeometry::Sagittal, sliceNumber); + sagittalPlaneGeometry->InitializeStandardPlane(image->GetGeometry(), mitk::AnatomicalPlane::Sagittal, sliceNumber); mitk::ExtractSliceFilter::Pointer extractSliceFilter = mitk::ExtractSliceFilter::New(); extractSliceFilter->SetInput(image); extractSliceFilter->SetInterpolationMode(mitk::ExtractSliceFilter::RESLICE_CUBIC); extractSliceFilter->SetResliceTransformByGeometry(image->GetGeometry()); extractSliceFilter->SetWorldGeometry(sagittalPlaneGeometry); extractSliceFilter->SetOutputDimensionality(2); extractSliceFilter->SetVtkOutputRequest(true); extractSliceFilter->Update(); /* mitk::Vector3D spacing; mitk::FillVector3D(spacing,1.0,1.0,1.0); slice->GetGeometry()->SetSpacing(spacing); // save image slice mitk::IOUtil::SaveImage( slice, d->m_Path + fileName + ".png" ); */ vtkImageData* imageData = extractSliceFilter->GetVtkOutput(); mitk::LevelWindow levelWindow; dataNode->GetLevelWindow(levelWindow); vtkSmartPointer lookupTable = vtkSmartPointer::New(); lookupTable->SetRange(levelWindow.GetLowerWindowBound(), levelWindow.GetUpperWindowBound()); lookupTable->SetSaturationRange(0.0, 0.0); lookupTable->SetValueRange(0.0, 1.0); lookupTable->SetHueRange(0.0, 0.0); lookupTable->SetRampToLinear(); vtkSmartPointer levelWindowFilter = vtkSmartPointer::New(); levelWindowFilter->SetLookupTable(lookupTable); levelWindowFilter->SetInputData(imageData); levelWindowFilter->SetMinOpacity(0.0); levelWindowFilter->SetMaxOpacity(1.0); int dims[3]; imageData->GetDimensions(dims); double clippingBounds[] = { 0.0, static_cast(dims[0]), 0.0, static_cast(dims[1]) }; levelWindowFilter->SetClippingBounds(clippingBounds); levelWindowFilter->Update(); imageData = levelWindowFilter->GetOutput(); QImage thumbnailImage(reinterpret_cast(imageData->GetScalarPointer()), dims[0], dims[1], QImage::Format_ARGB32); thumbnailImage = thumbnailImage.rgbSwapped().mirrored(false, true); return QPixmap::fromImage(thumbnailImage); } diff --git a/Modules/ToFHardware/Testing/mitkPlayerLoadAndRenderDepthDataTest.cpp b/Modules/ToFHardware/Testing/mitkPlayerLoadAndRenderDepthDataTest.cpp index 00110c517c..05d03ae021 100644 --- a/Modules/ToFHardware/Testing/mitkPlayerLoadAndRenderDepthDataTest.cpp +++ b/Modules/ToFHardware/Testing/mitkPlayerLoadAndRenderDepthDataTest.cpp @@ -1,105 +1,103 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ //MITK #include "mitkTestingMacros.h" #include "mitkRenderingTestHelper.h" #include "mitkToFCameraMITKPlayerDevice.h" //VTK #include #include #include #include int mitkPlayerLoadAndRenderDepthDataTest(int argc, char* argv[]) { MITK_TEST_BEGIN("mitkPlayerLoadAndRenderDepthDataTest"); try { mitk::ToFCameraMITKPlayerDevice::Pointer playerDevice = mitk::ToFCameraMITKPlayerDevice::New(); MITK_TEST_CONDITION_REQUIRED(argc >=2, "Testing if enough input parameters are set. Usage: Testname, ImageName (must be in MITK_TOF_DATA_DIR), -V /path/to/reference/screenshot"); std::string dirname = MITK_TOF_DATA_DIR; std::string distanceFileName = dirname + "/" + argv[1]; playerDevice->SetProperty("DistanceImageFileName",mitk::StringProperty::New(distanceFileName)); for (int i = 0; i < argc; ++i) MITK_INFO << argv[i]; MITK_TEST_CONDITION_REQUIRED(playerDevice->IsCameraActive()==false,"The device (player) should not be active before starting."); MITK_TEST_CONDITION_REQUIRED(playerDevice->ConnectCamera()==true,"ConnectCamera() should return true in case of success."); MITK_TEST_OUTPUT(<< "Device connected"); playerDevice->StartCamera(); MITK_TEST_OUTPUT(<< "Device started"); MITK_TEST_CONDITION_REQUIRED(playerDevice->IsCameraActive()==true,"After starting the device, the device should be active."); //initialize an array with the correct size unsigned int captureWidth = playerDevice->GetCaptureWidth(); unsigned int captureHeight = playerDevice->GetCaptureHeight(); unsigned int numberOfPixels = captureWidth*captureHeight; float* distances = new float[numberOfPixels]; int imageSequence = 0; //fill the array with the device output playerDevice->GetDistances(distances,imageSequence); //initialize an image and fill it with the array unsigned int dimension[2]; dimension[0] = captureWidth; dimension[1] = captureHeight; mitk::Image::Pointer mitkDepthImage = mitk::Image::New(); mitkDepthImage->Initialize(mitk::PixelType(mitk::MakeScalarPixelType()), 2, dimension,1); mitkDepthImage->SetSlice(distances); //create a node to pass it to the mitkRenderingTestHelper mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(mitkDepthImage); // load all arguments into a datastorage, take last argument as reference rendering // setup a renderwindow of fixed size X*Y // render the datastorage // compare rendering to reference image mitk::RenderingTestHelper renderingHelper(640, 480, argc, argv); - //Set the opacity for all images - //for now this test renders in sagittal view direction renderingHelper.AddNodeToStorage(node); //use this to generate a reference screenshot or save the file: bool generateReferenceScreenshot = false; if(generateReferenceScreenshot) { renderingHelper.SaveReferenceScreenShot("/home/kilgus/Pictures/output.png"); } //### Usage of CompareRenderWindowAgainstReference: See docu of mitkRrenderingTestHelper MITK_TEST_CONDITION( renderingHelper.CompareRenderWindowAgainstReference(argc, argv) == true, "CompareRenderWindowAgainstReference test result positive?" ); //Wait some time to avoid threading issues. itksys::SystemTools::Delay(1000); playerDevice->StopCamera(); MITK_TEST_OUTPUT(<< "Device stopped"); MITK_TEST_CONDITION_REQUIRED(playerDevice->IsCameraActive()==false,"After stopping the device, the device should be inactive."); MITK_TEST_CONDITION_REQUIRED(playerDevice->DisconnectCamera()==true, "DisconnectCamera() should return true in case of success."); MITK_TEST_OUTPUT(<< "Device disconnected"); delete[] distances; } catch(std::exception &e) { MITK_ERROR << "Unknown exception occured: " << e.what(); } MITK_TEST_END(); } diff --git a/Modules/ToFHardware/Testing/mitkPlayerLoadAndRenderRGBDataTest.cpp b/Modules/ToFHardware/Testing/mitkPlayerLoadAndRenderRGBDataTest.cpp index a82aa040e4..4d3fd4ba88 100644 --- a/Modules/ToFHardware/Testing/mitkPlayerLoadAndRenderRGBDataTest.cpp +++ b/Modules/ToFHardware/Testing/mitkPlayerLoadAndRenderRGBDataTest.cpp @@ -1,103 +1,101 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ //MITK #include "mitkTestingMacros.h" #include "mitkRenderingTestHelper.h" #include "mitkToFCameraMITKPlayerDevice.h" //VTK #include #include #include #include int mitkPlayerLoadAndRenderRGBDataTest(int argc, char* argv[]) { MITK_TEST_BEGIN("mitkPlayerLoadAndRenderRGBDataTest"); try { mitk::ToFCameraMITKPlayerDevice::Pointer playerDevice = mitk::ToFCameraMITKPlayerDevice::New(); MITK_TEST_CONDITION_REQUIRED(argc >=2, "Testing if enough input parameters are set. Usage: Testname, ImageName (must be in MITK_TOF_DATA_DIR), -V /path/to/reference/screenshot"); std::string dirname = MITK_TOF_DATA_DIR; std::string rgbFileName = dirname + "/" + argv[1]; playerDevice->SetProperty("RGBImageFileName",mitk::StringProperty::New(rgbFileName)); MITK_TEST_CONDITION_REQUIRED(playerDevice->IsCameraActive()==false,"The device (player) should not be active before starting."); MITK_TEST_CONDITION_REQUIRED(playerDevice->ConnectCamera()==true,"ConnectCamera() should return true in case of success."); MITK_TEST_OUTPUT(<< "Device connected"); playerDevice->StartCamera(); MITK_TEST_OUTPUT(<< "Device started"); MITK_TEST_CONDITION_REQUIRED(playerDevice->IsCameraActive()==true,"After starting the device, the device should be active."); //initialize an array with the correct size unsigned int captureWidth = playerDevice->GetCaptureWidth(); unsigned int captureHeight = playerDevice->GetCaptureHeight(); unsigned int numberOfPixels = captureWidth*captureHeight; unsigned char* rgbDataArray = new unsigned char[numberOfPixels*3]; int imageSequence = 0; //fill the array with the device output playerDevice->GetRgb(rgbDataArray, imageSequence); //initialize an image and fill it with the array unsigned int dimension[2]; dimension[0] = captureWidth; dimension[1] = captureHeight; mitk::Image::Pointer rgbImage = mitk::Image::New(); rgbImage->Initialize(mitk::PixelType(mitk::MakePixelType, 3>()), 2, dimension,1); rgbImage->SetSlice(rgbDataArray); //create a node to pass it to the mitkRenderingTestHelper mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(rgbImage); // load all arguments into a datastorage, take last argument as reference rendering // setup a renderwindow of fixed size X*Y // render the datastorage // compare rendering to reference image mitk::RenderingTestHelper renderingHelper(640, 480, argc, argv); - //Set the opacity for all images - //for now this test renders in sagittal view direction renderingHelper.AddNodeToStorage(node); renderingHelper.Render(); //use this to generate a reference screenshot or save the file: bool generateReferenceScreenshot = false; if(generateReferenceScreenshot) { renderingHelper.SaveReferenceScreenShot("/home/kilgus/Pictures/output.png"); } //### Usage of CompareRenderWindowAgainstReference: See docu of mitkRrenderingTestHelper MITK_TEST_CONDITION( renderingHelper.CompareRenderWindowAgainstReference(argc, argv) == true, "CompareRenderWindowAgainstReference test result positive?" ); //Wait some time to avoid threading issues. itksys::SystemTools::Delay(1000); playerDevice->StopCamera(); MITK_TEST_OUTPUT(<< "Device stopped"); MITK_TEST_CONDITION_REQUIRED(playerDevice->IsCameraActive()==false,"After stopping the device, the device should be inactive."); MITK_TEST_CONDITION_REQUIRED(playerDevice->DisconnectCamera()==true, "DisconnectCamera() should return true in case of success."); MITK_TEST_OUTPUT(<< "Device disconnected"); delete[] rgbDataArray; } catch(std::exception &e) { MITK_ERROR << "Unknown exception occured: " << e.what(); } MITK_TEST_END(); } diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionButton.cpp b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionButton.cpp index 072b5cd082..aad227179e 100644 --- a/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionButton.cpp +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionButton.cpp @@ -1,281 +1,281 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "QmitkNodeSelectionButton.h" // mitk core #include #include #include #include #include // mitk qt widgets module #include // berry includes #include #include #include #include #include #include QPixmap GetPixmapFromImageNode(const mitk::DataNode* dataNode, int height) { if (nullptr == dataNode) { return QPixmap(); } const mitk::Image* image = dynamic_cast(dataNode->GetData()); if ((nullptr == image || !image->IsInitialized()) || // -> must be an image (image->GetPixelType().GetNumberOfComponents() != 1)) // -> for now only single component are allowed { auto descManager = QmitkNodeDescriptorManager::GetInstance(); auto desc = descManager->GetDescriptor(dataNode); auto icon = desc->GetIcon(dataNode); auto fallBackMap = icon.pixmap(height, height); return fallBackMap; } mitk::PlaneGeometry::Pointer planeGeometry = mitk::PlaneGeometry::New(); int sliceNumber = image->GetDimension(2) / 2; - planeGeometry->InitializeStandardPlane(image->GetGeometry(), mitk::PlaneGeometry::Axial, sliceNumber); + planeGeometry->InitializeStandardPlane(image->GetGeometry(), mitk::AnatomicalPlane::Axial, sliceNumber); mitk::ExtractSliceFilter::Pointer extractSliceFilter = mitk::ExtractSliceFilter::New(); extractSliceFilter->SetInput(image); extractSliceFilter->SetInterpolationMode(mitk::ExtractSliceFilter::RESLICE_CUBIC); extractSliceFilter->SetResliceTransformByGeometry(image->GetGeometry()); extractSliceFilter->SetWorldGeometry(planeGeometry); extractSliceFilter->SetOutputDimensionality(2); extractSliceFilter->SetVtkOutputRequest(true); extractSliceFilter->Update(); vtkImageData* imageData = extractSliceFilter->GetVtkOutput(); mitk::LevelWindow levelWindow; dataNode->GetLevelWindow(levelWindow); vtkSmartPointer lookupTable = vtkSmartPointer::New(); lookupTable->SetRange(levelWindow.GetLowerWindowBound(), levelWindow.GetUpperWindowBound()); lookupTable->SetSaturationRange(0.0, 0.0); lookupTable->SetValueRange(0.0, 1.0); lookupTable->SetHueRange(0.0, 0.0); lookupTable->SetRampToLinear(); vtkSmartPointer levelWindowFilter = vtkSmartPointer::New(); levelWindowFilter->SetLookupTable(lookupTable); levelWindowFilter->SetInputData(imageData); levelWindowFilter->SetMinOpacity(0.0); levelWindowFilter->SetMaxOpacity(1.0); int dims[3]; imageData->GetDimensions(dims); double clippingBounds[] = { 0.0, static_cast(dims[0]), 0.0, static_cast(dims[1]) }; levelWindowFilter->SetClippingBounds(clippingBounds); levelWindowFilter->Update(); imageData = levelWindowFilter->GetOutput(); QImage thumbnailImage(reinterpret_cast(imageData->GetScalarPointer()), dims[0], dims[1], QImage::Format_ARGB32); if (dims[0] > dims[1]) { thumbnailImage = thumbnailImage.scaledToWidth(height, Qt::SmoothTransformation).rgbSwapped(); } else { thumbnailImage = thumbnailImage.scaledToHeight(height, Qt::SmoothTransformation).rgbSwapped(); } return QPixmap::fromImage(thumbnailImage); } QmitkNodeSelectionButton::QmitkNodeSelectionButton(QWidget *parent) : QPushButton(parent) , m_OutDatedThumbNail(true) , m_DataMTime(0) , m_IsOptional(true) , m_NodeModifiedObserverTag(0) , m_NodeObserved(false) { } QmitkNodeSelectionButton::~QmitkNodeSelectionButton() { this->RemoveNodeObserver(); this->m_SelectedNode = nullptr; } void QmitkNodeSelectionButton::AddNodeObserver() { if (this->m_SelectedNode.IsNotNull()) { if (m_NodeObserved) { MITK_DEBUG << "Invalid observer state in QmitkNodeSelectionButton. There is already a registered observer. Internal logic is not correct. May be an old observer was not removed."; } auto modifiedCommand = itk::MemberCommand::New(); modifiedCommand->SetCallbackFunction(this, &QmitkNodeSelectionButton::OnNodeModified); // const cast because we need non const nodes and it seems to be the lesser of two evil. // the changes to the node are only on the observer level. The other option would be to // make the public interface require non const nodes, this we don't want to introduce. auto nonconst_node = const_cast(this->m_SelectedNode.GetPointer()); m_NodeModifiedObserverTag = nonconst_node->AddObserver(itk::ModifiedEvent(), modifiedCommand); m_NodeObserved = true; } } void QmitkNodeSelectionButton::RemoveNodeObserver() { if (this->m_SelectedNode.IsNotNull()) { // const cast because we need non const nodes and it seems to be the lesser of two evil. // the changes to the node are only on the observer level. The other option would be to // make the public interface require non const nodes, this we don't want to introduce. auto nonconst_node = const_cast(this->m_SelectedNode.GetPointer()); nonconst_node->RemoveObserver(m_NodeModifiedObserverTag); } m_NodeObserved = false; } void QmitkNodeSelectionButton::OnNodeModified(const itk::Object * /*caller*/, const itk::EventObject & event) { if (itk::ModifiedEvent().CheckEvent(&event)) { this->update(); } } const mitk::DataNode* QmitkNodeSelectionButton::GetSelectedNode() const { return m_SelectedNode; } void QmitkNodeSelectionButton::SetSelectedNode(const mitk::DataNode* node) { if (m_SelectedNode != node) { this->RemoveNodeObserver(); this->m_SelectedNode = node; this->m_OutDatedThumbNail = true; this->AddNodeObserver(); } this->update(); } void QmitkNodeSelectionButton::SetNodeInfo(QString info) { this->m_Info = info; this->update(); } void QmitkNodeSelectionButton::paintEvent(QPaintEvent *p) { QString stylesheet; ctkPluginContext* context = berry::WorkbenchPlugin::GetDefault()->GetPluginContext(); ctkServiceReference styleManagerRef = context->getServiceReference(); if (styleManagerRef) { auto styleManager = context->getService(styleManagerRef); stylesheet = styleManager->GetStylesheet(); } QPushButton::paintEvent(p); QPainter painter(this); QTextDocument td(this); td.setDefaultStyleSheet(stylesheet); auto widgetSize = this->size(); QPoint origin = QPoint(5, 5); if (this->m_SelectedNode) { auto iconLength = widgetSize.height() - 10; auto node = this->m_SelectedNode; itk::ModifiedTimeType dataMTime = 0; if (m_SelectedNode->GetData()) { dataMTime = m_SelectedNode->GetData()->GetMTime(); } if (dataMTime>m_DataMTime || this->m_OutDatedThumbNail) { this->m_ThumbNail = GetPixmapFromImageNode(node, iconLength); this->m_OutDatedThumbNail = false; m_DataMTime = dataMTime; } auto thumbNailOrigin = origin; thumbNailOrigin.setY(thumbNailOrigin.y() + ((iconLength - m_ThumbNail.height()) / 2)); painter.drawPixmap(thumbNailOrigin, m_ThumbNail); origin.setX(origin.x() + iconLength + 5); if (this->isEnabled()) { td.setHtml(QString::fromStdString("" + node->GetName() + "")); } else { td.setHtml(QString::fromStdString("" + node->GetName() + "")); } } else { if (this->isEnabled()) { if (this->m_IsOptional) { td.setHtml(QString("") + m_Info + QString("")); } else { td.setHtml(QString("") + m_Info + QString("")); } } else { td.setHtml(QString("") + m_Info + QString("")); } } auto textSize = td.size(); origin.setY( (widgetSize.height() - textSize.height()) / 2.); painter.translate(origin); td.drawContents(&painter); } void QmitkNodeSelectionButton::changeEvent(QEvent *event) { if (event->type() == QEvent::EnabledChange) { this->update(); } } bool QmitkNodeSelectionButton::GetSelectionIsOptional() const { return m_IsOptional; } void QmitkNodeSelectionButton::SetSelectionIsOptional(bool isOptional) { m_IsOptional = isOptional; this->update(); } diff --git a/Plugins/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilView.cpp b/Plugins/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilView.cpp index 0c63ce567f..6395f6f164 100644 --- a/Plugins/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilView.cpp +++ b/Plugins/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilView.cpp @@ -1,536 +1,536 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // Blueberry #include #include // Qmitk #include "QmitkToFUtilView.h" // Qt #include #include #include #include #include // MITK #include #include #include #include #include #include #include #include #include #include // VTK #include #include #include // ITK #include #include const std::string QmitkToFUtilView::VIEW_ID = "org.mitk.views.tofutil"; //Constructor QmitkToFUtilView::QmitkToFUtilView() : QmitkAbstractView() , m_Controls(nullptr) , m_Framerateoutput(false) , m_MitkDistanceImage(nullptr), m_MitkAmplitudeImage(nullptr), m_MitkIntensityImage(nullptr), m_Surface(nullptr) , m_DistanceImageNode(nullptr), m_AmplitudeImageNode(nullptr), m_IntensityImageNode(nullptr), m_RGBImageNode(nullptr), m_SurfaceNode(nullptr) , m_ToFImageRecorder(nullptr), m_ToFImageGrabber(nullptr), m_ToFDistanceImageToSurfaceFilter(nullptr), m_ToFCompositeFilter(nullptr) , m_2DDisplayCount(0) , m_RealTimeClock(nullptr) , m_StepsForFramerate(100) , m_2DTimeBefore(0.0) , m_2DTimeAfter(0.0) , m_CameraIntrinsics(nullptr) { this->m_Frametimer = new QTimer(this); this->m_ToFDistanceImageToSurfaceFilter = mitk::ToFDistanceImageToSurfaceFilter::New(); this->m_ToFCompositeFilter = mitk::ToFCompositeFilter::New(); this->m_ToFImageRecorder = mitk::ToFImageRecorder::New(); } //Destructor, specifically calling OnToFCameraStopped() and OnToFCammeraDiconnected() QmitkToFUtilView::~QmitkToFUtilView() { OnToFCameraStopped(); OnToFCameraDisconnected(); } //Createing the PartControl Signal-Slot principal void QmitkToFUtilView::CreateQtPartControl( QWidget *parent ) { // build up qt view, unless already done if ( !m_Controls ) { // create GUI widgets from the Qt Designer's .ui file m_Controls = new Ui::QmitkToFUtilViewControls; m_Controls->setupUi( parent ); //Looking for Input and Defining reaction connect(m_Frametimer, SIGNAL(timeout()), this, SLOT(OnUpdateCamera())); connect( (QObject*)(m_Controls->m_ToFConnectionWidget), SIGNAL(KinectAcquisitionModeChanged()), this, SLOT(OnKinectAcquisitionModeChanged()) ); // Todo in Widget2 connect( (QObject*)(m_Controls->m_ToFConnectionWidget), SIGNAL(ToFCameraConnected()), this, SLOT(OnToFCameraConnected()) ); connect( (QObject*)(m_Controls->m_ToFConnectionWidget), SIGNAL(ToFCameraDisconnected()), this, SLOT(OnToFCameraDisconnected()) ); connect( (QObject*)(m_Controls->m_ToFRecorderWidget), SIGNAL(ToFCameraStarted()), this, SLOT(OnToFCameraStarted()) ); connect( (QObject*)(m_Controls->m_ToFRecorderWidget), SIGNAL(ToFCameraStopped()), this, SLOT(OnToFCameraStopped()) ); connect( (QObject*)(m_Controls->m_ToFRecorderWidget), SIGNAL(RecordingStarted()), this, SLOT(OnToFCameraStopped()) ); connect( (QObject*)(m_Controls->m_ToFRecorderWidget), SIGNAL(RecordingStopped()), this, SLOT(OnToFCameraStarted()) ); } } //SetFocus-Method -> actually seting Focus to the Recorder void QmitkToFUtilView::SetFocus() { m_Controls->m_ToFRecorderWidget->setFocus(); } //Activated-Method->Generating RenderWindow void QmitkToFUtilView::Activated() { //get the current RenderWindowPart or open a new one if there is none auto* renderWindowPart = this->GetRenderWindowPart(mitk::WorkbenchUtil::OPEN); if (nullptr != renderWindowPart) { auto* linkedRenderWindowPart = dynamic_cast(renderWindowPart); if (linkedRenderWindowPart == nullptr) { MITK_ERROR << "No linked render window part avaiable!!!"; } else { linkedRenderWindowPart->EnableSlicingPlanes(false); } - renderWindowPart->GetQmitkRenderWindow("axial")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Axial); + renderWindowPart->GetQmitkRenderWindow("axial")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::AnatomicalPlane::Axial); renderWindowPart->GetQmitkRenderWindow("axial")->GetSliceNavigationController()->SliceLockedOn(); - renderWindowPart->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Axial); + renderWindowPart->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::AnatomicalPlane::Axial); renderWindowPart->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()->SliceLockedOn(); - renderWindowPart->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Axial); + renderWindowPart->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::AnatomicalPlane::Axial); renderWindowPart->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()->SliceLockedOn(); mitk::RenderingManager::GetInstance()->InitializeViews(); this->UseToFVisibilitySettings(true); if (this->m_ToFCompositeFilter) { m_Controls->m_ToFCompositeFilterWidget->SetToFCompositeFilter(this->m_ToFCompositeFilter); } if (this->GetDataStorage()) { m_Controls->m_ToFCompositeFilterWidget->SetDataStorage(this->GetDataStorage()); } if (this->m_ToFImageGrabber.IsNull()) { m_Controls->m_ToFRecorderWidget->setEnabled(false); m_Controls->m_ToFVisualisationSettingsWidget->setEnabled(false); m_Controls->m_ToFCompositeFilterWidget->setEnabled(false); m_Controls->m_ToFMeasurementWidget->setEnabled(false); m_Controls->m_ToFSurfaceGenerationWidget->setEnabled(false); } } } //ZomnnieView-Method -> Resetting GUI to default. Why not just QmitkToFUtilView()?! void QmitkToFUtilView::ActivatedZombieView(berry::IWorkbenchPartReference::Pointer /*zombieView*/) { ResetGUIToDefault(); } void QmitkToFUtilView::Deactivated() { } void QmitkToFUtilView::Visible() { } //Reset of the ToFUtilView void QmitkToFUtilView::Hidden() { ResetGUIToDefault(); } void QmitkToFUtilView::OnToFCameraConnected() { MITK_DEBUG <<"OnToFCameraConnected"; this->m_2DDisplayCount = 0; this->m_ToFImageGrabber = m_Controls->m_ToFConnectionWidget->GetToFImageGrabber(); // initialize surface generation this->m_ToFDistanceImageToSurfaceFilter = mitk::ToFDistanceImageToSurfaceFilter::New(); // initialize ToFImageRecorder and ToFRecorderWidget this->m_ToFImageRecorder = mitk::ToFImageRecorder::New(); this->m_ToFImageRecorder->SetCameraDevice(this->m_ToFImageGrabber->GetCameraDevice()); m_Controls->m_ToFRecorderWidget->SetParameter(this->m_ToFImageGrabber, this->m_ToFImageRecorder); m_Controls->m_ToFRecorderWidget->setEnabled(true); m_Controls->m_ToFRecorderWidget->ResetGUIToInitial(); m_Controls->m_ToFVisualisationSettingsWidget->setEnabled(false); // initialize ToFCompositeFilterWidget this->m_ToFCompositeFilter = mitk::ToFCompositeFilter::New(); if (this->m_ToFCompositeFilter) { m_Controls->m_ToFCompositeFilterWidget->SetToFCompositeFilter(this->m_ToFCompositeFilter); } if (this->GetDataStorage()) { m_Controls->m_ToFCompositeFilterWidget->SetDataStorage(this->GetDataStorage()); } if ( this->GetRenderWindowPart() ) // initialize measurement widget m_Controls->m_ToFMeasurementWidget->InitializeWidget(this->GetRenderWindowPart()->GetQmitkRenderWindows(),this->GetDataStorage(), this->m_ToFDistanceImageToSurfaceFilter->GetCameraIntrinsics()); else MITK_WARN << "No render window part available!!! MeasurementWidget will not work."; this->m_RealTimeClock = mitk::RealTimeClock::New(); this->m_2DTimeBefore = this->m_RealTimeClock->GetCurrentStamp(); this->RequestRenderWindowUpdate(); } void QmitkToFUtilView::ResetGUIToDefault() { auto* renderWindowPart = this->GetRenderWindowPart(); if(nullptr != renderWindowPart) { auto* linkedRenderWindowPart = dynamic_cast(renderWindowPart); if(linkedRenderWindowPart == nullptr) { MITK_ERROR << "No linked render window part avaiable!!!"; } else { linkedRenderWindowPart->EnableSlicingPlanes(true); } - renderWindowPart->GetQmitkRenderWindow("axial")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Axial); + renderWindowPart->GetQmitkRenderWindow("axial")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::AnatomicalPlane::Axial); renderWindowPart->GetQmitkRenderWindow("axial")->GetSliceNavigationController()->SliceLockedOff(); - renderWindowPart->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Sagittal); + renderWindowPart->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::AnatomicalPlane::Sagittal); renderWindowPart->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()->SliceLockedOff(); - renderWindowPart->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Coronal); + renderWindowPart->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::AnatomicalPlane::Coronal); renderWindowPart->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()->SliceLockedOff(); this->UseToFVisibilitySettings(false); //global reinit mitk::RenderingManager::GetInstance()->InitializeViews(); this->RequestRenderWindowUpdate(); } } void QmitkToFUtilView::OnToFCameraDisconnected() { this->GetDataStorage()->Remove(m_DistanceImageNode); if(m_RGBImageNode) this->GetDataStorage()->Remove(m_RGBImageNode); if(m_AmplitudeImageNode) this->GetDataStorage()->Remove(m_AmplitudeImageNode); if(m_IntensityImageNode) this->GetDataStorage()->Remove(m_IntensityImageNode); if(m_SurfaceNode) this->GetDataStorage()->Remove(m_SurfaceNode); m_Controls->m_ToFRecorderWidget->OnStop(); m_Controls->m_ToFRecorderWidget->setEnabled(false); m_Controls->m_ToFVisualisationSettingsWidget->setEnabled(false); m_Controls->m_ToFMeasurementWidget->setEnabled(false); m_Controls->m_ToFSurfaceGenerationWidget->setEnabled(false); //clean up measurement widget m_Controls->m_ToFMeasurementWidget->CleanUpWidget(); } void QmitkToFUtilView::OnKinectAcquisitionModeChanged() { if (m_ToFCompositeFilter.IsNotNull()&&m_ToFImageGrabber.IsNotNull()) { if (m_SelectedCamera.contains("Kinect")) { if (m_ToFImageGrabber->GetBoolProperty("RGB")) { this->m_RGBImageNode = ReplaceNodeData("RGB image",this->m_ToFImageGrabber->GetOutput(3)); this->m_ToFDistanceImageToSurfaceFilter->SetInput(3,this->m_ToFImageGrabber->GetOutput(3)); } else if (m_ToFImageGrabber->GetBoolProperty("IR")) { this->m_MitkAmplitudeImage = m_ToFCompositeFilter->GetOutput(1); this->m_AmplitudeImageNode = ReplaceNodeData("Amplitude image",m_MitkAmplitudeImage); } } this->UseToFVisibilitySettings(true); } } void QmitkToFUtilView::OnToFCameraStarted() { if (m_ToFImageGrabber.IsNotNull()) { // initialize camera intrinsics if (this->m_ToFImageGrabber->GetProperty("CameraIntrinsics")) { m_CameraIntrinsics = dynamic_cast(this->m_ToFImageGrabber->GetProperty("CameraIntrinsics"))->GetValue(); MITK_INFO << m_CameraIntrinsics->ToString(); } else { m_CameraIntrinsics = nullptr; MITK_ERROR << "No camera intrinsics were found!"; } // set camera intrinsics if ( m_CameraIntrinsics.IsNotNull() ) { this->m_ToFDistanceImageToSurfaceFilter->SetCameraIntrinsics(m_CameraIntrinsics); } // initial update of image grabber this->m_ToFImageGrabber->Update(); bool hasRGBImage = false; m_ToFImageGrabber->GetCameraDevice()->GetBoolProperty("HasRGBImage",hasRGBImage); bool hasIntensityImage = false; m_ToFImageGrabber->GetCameraDevice()->GetBoolProperty("HasIntensityImage",hasIntensityImage); bool hasAmplitudeImage = false; m_ToFImageGrabber->GetCameraDevice()->GetBoolProperty("HasAmplitudeImage",hasAmplitudeImage); this->m_ToFCompositeFilter->SetInput(0,this->m_ToFImageGrabber->GetOutput(0)); if(hasAmplitudeImage) this->m_ToFCompositeFilter->SetInput(1,this->m_ToFImageGrabber->GetOutput(1)); if(hasIntensityImage) this->m_ToFCompositeFilter->SetInput(2,this->m_ToFImageGrabber->GetOutput(2)); // initial update of composite filter this->m_ToFCompositeFilter->Update(); this->m_MitkDistanceImage = m_ToFCompositeFilter->GetOutput(); this->m_DistanceImageNode = ReplaceNodeData("Distance image",m_MitkDistanceImage); std::string rgbFileName; m_ToFImageGrabber->GetCameraDevice()->GetStringProperty("RGBImageFileName",rgbFileName); if(hasRGBImage || (rgbFileName!="")) { if(m_ToFImageGrabber->GetBoolProperty("IR")) { this->m_MitkAmplitudeImage = m_ToFCompositeFilter->GetOutput(1); } else { this->m_RGBImageNode = ReplaceNodeData("RGB image",this->m_ToFImageGrabber->GetOutput(3)); } } else { this->m_RGBImageNode = nullptr; } if(hasAmplitudeImage) { this->m_MitkAmplitudeImage = m_ToFCompositeFilter->GetOutput(1); this->m_AmplitudeImageNode = ReplaceNodeData("Amplitude image",m_MitkAmplitudeImage); } if(hasIntensityImage) { this->m_MitkIntensityImage = m_ToFCompositeFilter->GetOutput(2); this->m_IntensityImageNode = ReplaceNodeData("Intensity image",m_MitkIntensityImage); } this->m_ToFDistanceImageToSurfaceFilter->SetInput(0,m_MitkDistanceImage); this->m_ToFDistanceImageToSurfaceFilter->SetInput(1,m_MitkAmplitudeImage); this->m_ToFDistanceImageToSurfaceFilter->SetInput(2,m_MitkIntensityImage); this->UseToFVisibilitySettings(true); this->m_SurfaceNode = ReplaceNodeData("Surface", nullptr); m_Controls->m_ToFCompositeFilterWidget->UpdateFilterParameter(); // initialize visualization widget m_Controls->m_ToFVisualisationSettingsWidget->Initialize(this->m_DistanceImageNode, this->m_AmplitudeImageNode, this->m_IntensityImageNode, this->m_SurfaceNode); m_Controls->m_ToFSurfaceGenerationWidget->Initialize(m_ToFDistanceImageToSurfaceFilter, m_ToFImageGrabber, m_CameraIntrinsics, m_SurfaceNode, GetRenderWindowPart(mitk::WorkbenchUtil::OPEN)->GetQmitkRenderWindow("3d")->GetRenderer()->GetVtkRenderer()->GetActiveCamera()); // set distance image to measurement widget m_Controls->m_ToFMeasurementWidget->SetDistanceImage(m_MitkDistanceImage); this->m_Frametimer->start(50); m_Controls->m_ToFVisualisationSettingsWidget->setEnabled(true); m_Controls->m_ToFCompositeFilterWidget->setEnabled(true); m_Controls->m_ToFMeasurementWidget->setEnabled(true); m_Controls->m_ToFSurfaceGenerationWidget->setEnabled(true); } } void QmitkToFUtilView::OnToFCameraStopped() { m_Controls->m_ToFVisualisationSettingsWidget->setEnabled(false); m_Controls->m_ToFCompositeFilterWidget->setEnabled(false); this->m_Frametimer->stop(); } void QmitkToFUtilView::OnUpdateCamera() { if(!m_Controls->m_ToFSurfaceGenerationWidget->UpdateSurface()) { // update pipeline this->m_MitkDistanceImage->Update(); } this->RequestRenderWindowUpdate(); if (m_Framerateoutput) { this->m_2DDisplayCount++; if ((this->m_2DDisplayCount % this->m_StepsForFramerate) == 0) { this->m_2DTimeAfter = this->m_RealTimeClock->GetCurrentStamp() - this->m_2DTimeBefore; MITK_INFO << " 2D-Display-framerate (fps): " << this->m_StepsForFramerate / (this->m_2DTimeAfter / 1000); this->m_2DTimeBefore = this->m_RealTimeClock->GetCurrentStamp(); } } } void QmitkToFUtilView::OnChangeCoronalWindowOutput(int index) { this->OnToFCameraStopped(); if(index == 0) { if(this->m_IntensityImageNode.IsNotNull()) this->m_IntensityImageNode->SetVisibility(false); if(this->m_RGBImageNode.IsNotNull()) this->m_RGBImageNode->SetVisibility(true); } else if(index == 1) { if(this->m_IntensityImageNode.IsNotNull()) this->m_IntensityImageNode->SetVisibility(true); if(this->m_RGBImageNode.IsNotNull()) this->m_RGBImageNode->SetVisibility(false); } this->RequestRenderWindowUpdate(); this->OnToFCameraStarted(); } mitk::DataNode::Pointer QmitkToFUtilView::ReplaceNodeData( std::string nodeName, mitk::BaseData* data ) { mitk::DataNode::Pointer node = this->GetDataStorage()->GetNamedNode(nodeName); if (node.IsNull()) { node = mitk::DataNode::New(); node->SetName(nodeName); node->SetBoolProperty("binary",false); node->SetData(data); this->GetDataStorage()->Add(node); } else { node->SetData(data); } return node; } void QmitkToFUtilView::UseToFVisibilitySettings(bool useToF) { //We need this property for every node. auto renderingModePropertyForTransferFunction = mitk::RenderingModeProperty::New(mitk::RenderingModeProperty::COLORTRANSFERFUNCTION_COLOR); auto* renderWindowPart = this->GetRenderWindowPart(mitk::WorkbenchUtil::OPEN); auto* axialRenderer = mitk::BaseRenderer::GetInstance(renderWindowPart->GetQmitkRenderWindow("axial")->renderWindow()); auto* sagittalRenderer = mitk::BaseRenderer::GetInstance(renderWindowPart->GetQmitkRenderWindow("sagittal")->renderWindow()); auto* coronalRenderer = mitk::BaseRenderer::GetInstance(renderWindowPart->GetQmitkRenderWindow("coronal")->renderWindow()); auto* threeDimRenderer = mitk::BaseRenderer::GetInstance(renderWindowPart->GetQmitkRenderWindow("3d")->renderWindow()); // set node properties if (m_DistanceImageNode.IsNotNull()) { this->m_DistanceImageNode->SetProperty( "visible" , mitk::BoolProperty::New( true )); this->m_DistanceImageNode->SetVisibility( !useToF, sagittalRenderer ); this->m_DistanceImageNode->SetVisibility( !useToF, coronalRenderer ); this->m_DistanceImageNode->SetVisibility( !useToF, threeDimRenderer ); this->m_DistanceImageNode->SetProperty("Image Rendering.Mode", renderingModePropertyForTransferFunction); } if (m_AmplitudeImageNode.IsNotNull()) { this->m_AmplitudeImageNode->SetVisibility( !useToF, axialRenderer ); this->m_AmplitudeImageNode->SetVisibility( !useToF, coronalRenderer ); this->m_AmplitudeImageNode->SetVisibility( !useToF, threeDimRenderer ); this->m_AmplitudeImageNode->SetProperty("Image Rendering.Mode", renderingModePropertyForTransferFunction); } if (m_IntensityImageNode.IsNotNull()) { this->m_IntensityImageNode->SetProperty( "visible" , mitk::BoolProperty::New( true )); this->m_IntensityImageNode->SetVisibility( !useToF, axialRenderer ); this->m_IntensityImageNode->SetVisibility( !useToF, sagittalRenderer ); this->m_IntensityImageNode->SetVisibility( !useToF, threeDimRenderer ); this->m_IntensityImageNode->SetProperty("Image Rendering.Mode", renderingModePropertyForTransferFunction); } if ((m_RGBImageNode.IsNotNull())) { this->m_RGBImageNode->SetProperty( "visible" , mitk::BoolProperty::New( true )); this->m_RGBImageNode->SetVisibility( !useToF, axialRenderer ); this->m_RGBImageNode->SetVisibility( !useToF, sagittalRenderer ); this->m_RGBImageNode->SetVisibility( !useToF, threeDimRenderer ); } // initialize images if (m_MitkDistanceImage.IsNotNull()) { mitk::RenderingManager::GetInstance()->InitializeViews( this->m_MitkDistanceImage->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_2DWINDOWS); } if(this->m_SurfaceNode.IsNotNull()) { QHash renderWindowHashMap = renderWindowPart->GetQmitkRenderWindows(); QHashIterator i(renderWindowHashMap); while (i.hasNext()){ i.next(); this->m_SurfaceNode->SetVisibility( false, mitk::BaseRenderer::GetInstance(i.value()->renderWindow()) ); } this->m_SurfaceNode->SetVisibility( true, mitk::BaseRenderer::GetInstance(renderWindowPart->GetQmitkRenderWindow("3d")->renderWindow() ) ); } //disable/enable gradient background renderWindowPart->EnableDecorations(!useToF, QStringList(QString("background"))); if((this->m_RGBImageNode.IsNotNull())) { bool RGBImageHasDifferentResolution = false; m_ToFImageGrabber->GetCameraDevice()->GetBoolProperty("RGBImageHasDifferentResolution",RGBImageHasDifferentResolution); if(RGBImageHasDifferentResolution) { //update the display geometry by using the RBG image node. Only for renderwindow coronal mitk::RenderingManager::GetInstance()->InitializeView(renderWindowPart->GetQmitkRenderWindow("coronal")->renderWindow(), this->m_RGBImageNode->GetData()->GetGeometry()); } } }