diff --git a/Core/Code/Controllers/mitkPlanePositionManager.cpp b/Core/Code/Controllers/mitkPlanePositionManager.cpp index ef11a5fb2e..274da7a21b 100644 --- a/Core/Code/Controllers/mitkPlanePositionManager.cpp +++ b/Core/Code/Controllers/mitkPlanePositionManager.cpp @@ -1,103 +1,94 @@ #include "mitkPlanePositionManager.h" #include "mitkInteractionConst.h" +#include +#include +#include -mitk::PlanePositionManager::PlanePositionManager() + +mitk::PlanePositionManagerService::PlanePositionManagerService() { } -mitk::PlanePositionManager::~PlanePositionManager() +mitk::PlanePositionManagerService::~PlanePositionManagerService() { for (unsigned int i = 0; i < m_PositionList.size(); i++) { delete m_PositionList.at(i); } } -mitk::PlanePositionManager* mitk::PlanePositionManager::GetInstance() -{ - static mitk::PlanePositionManager* m_Instance; - - if ( m_Instance == 0) - { - m_Instance = new PlanePositionManager(); - } - - return m_Instance; -} - -unsigned int mitk::PlanePositionManager::AddNewPlanePosition ( const Geometry2D* plane, unsigned int sliceIndex ) +unsigned int mitk::PlanePositionManagerService::AddNewPlanePosition ( const Geometry2D* plane, unsigned int sliceIndex ) { for (unsigned int i = 0; i < m_PositionList.size(); i++) { if (m_PositionList.at(i) != 0) { bool isSameMatrix(true); bool isSameOffset(true); isSameOffset = mitk::Equal(m_PositionList.at(i)->GetTransform()->GetOffset(), plane->GetIndexToWorldTransform()->GetOffset()); if(!isSameOffset || sliceIndex != m_PositionList.at(i)->GetPos()) continue; isSameMatrix = mitk::MatrixEqualElementWise(m_PositionList.at(i)->GetTransform()->GetMatrix(), plane->GetIndexToWorldTransform()->GetMatrix()); if(isSameMatrix) return i; } } AffineTransform3D::Pointer transform = AffineTransform3D::New(); Matrix3D matrix; matrix.GetVnlMatrix().set_column(0, plane->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(0)); matrix.GetVnlMatrix().set_column(1, plane->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(1)); matrix.GetVnlMatrix().set_column(2, plane->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(2)); transform->SetMatrix(matrix); transform->SetOffset(plane->GetIndexToWorldTransform()->GetOffset()); mitk::Vector3D direction; direction[0] = plane->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(2)[0]; direction[1] = plane->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(2)[1]; direction[2] = plane->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(2)[2]; direction.Normalize(); mitk::RestorePlanePositionOperation* newOp = new mitk::RestorePlanePositionOperation (OpRESTOREPLANEPOSITION, plane->GetExtent(0), plane->GetExtent(1), plane->GetSpacing(), sliceIndex, direction, transform); m_PositionList.push_back( newOp ); return GetNumberOfPlanePositions()-1; } -bool mitk::PlanePositionManager::RemovePlanePosition( unsigned int ID ) +bool mitk::PlanePositionManagerService::RemovePlanePosition( unsigned int ID ) { if (m_PositionList.size() > ID && ID >= 0) { m_PositionList.erase(m_PositionList.begin()+ID); - //m_PositionList.at(ID) = 0; - return true; + return true; } else { return false; } } -mitk::RestorePlanePositionOperation* mitk::PlanePositionManager::GetPlanePosition ( unsigned int ID ) +mitk::RestorePlanePositionOperation* mitk::PlanePositionManagerService::GetPlanePosition ( unsigned int ID ) { if ( ID < m_PositionList.size() ) { return m_PositionList.at(ID); } else { MITK_WARN<<"GetPlanePosition returned NULL!"; return 0; } } -unsigned int mitk::PlanePositionManager::GetNumberOfPlanePositions() +unsigned int mitk::PlanePositionManagerService::GetNumberOfPlanePositions() { return m_PositionList.size(); } -void mitk::PlanePositionManager::RemoveAllPlanePositions() +void mitk::PlanePositionManagerService::RemoveAllPlanePositions() { m_PositionList.clear(); } diff --git a/Core/Code/Controllers/mitkPlanePositionManager.h b/Core/Code/Controllers/mitkPlanePositionManager.h index dfbcec2dd5..f74e1dbc8b 100644 --- a/Core/Code/Controllers/mitkPlanePositionManager.h +++ b/Core/Code/Controllers/mitkPlanePositionManager.h @@ -1,97 +1,104 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef mitkPlanePositionManager_h_Included #define mitkPlanePositionManager_h_Included #include "mitkCommon.h" #include "MitkExtExports.h" #include "mitkRestorePlanePositionOperation.h" #include "mitkDataStorage.h" +#include +#include +#include + +class MitkCoreActivator; namespace mitk { /** - The mitk::PlanePositionManager holds and manages a list of certain planepositions. + The mitk::PlanePositionManagerService holds and manages a list of certain planepositions. To store a new position you need to specify the first slice of your slicestack and the slicenumber you want to restore in the mitk::PlanePositionManager::AddNewPlanePosition() function. - To restore a position call mitk::PlanePositionManager::GetPlanePosition(ID) where ID is the position + To restore a position call mitk::PlanePositionManagerService::GetPlanePosition(ID) where ID is the position in the plane positionlist (returned by AddNewPlanePostion). This will give a mitk::RestorePlanePositionOperation which can be executed by the SliceNavigationController of the slicestack. \sa QmitkSegmentationView.cpp */ - class MITK_CORE_EXPORT PlanePositionManager : public itk::Object + class MITK_CORE_EXPORT PlanePositionManagerService : public itk::LightObject { public: - mitkClassMacro(PlanePositionManager, itk::Object); - itkNewMacro(Self); - - /// \brief For mitkPlanePositionManager is a singleton this static function must be called instead of a constructor - static PlanePositionManager* GetInstance(); - /** \brief Adds a new plane position to the list. If this geometry is identical to one of the list nothing will be added \a plane THE FIRST! slice of the slice stack \a sliceIndex the slice number of the selected slice \return returns the ID i.e. the position in the positionlist. If the PlaneGeometry which is to be added already exists the existing ID will be returned. */ - unsigned int AddNewPlanePosition(const Geometry2D* plane, unsigned int sliceIndex = 0); + unsigned int AddNewPlanePosition(const mitk::Geometry2D* plane, unsigned int sliceIndex = 0); /** \brief Removes the plane at the position \a ID from the list. \a ID the plane ID which should be removed, i.e. its position in the list \return true if the plane was removed successfully and false if it is an invalid ID */ bool RemovePlanePosition(unsigned int ID); /// \brief Clears the complete positionlist void RemoveAllPlanePositions(); /** \brief Getter for a specific plane position with a given ID \a ID the ID of the plane position \return Returns a RestorePlanePositionOperation which can be executed by th SliceNavigationController or NULL for an invalid ID */ - RestorePlanePositionOperation* GetPlanePosition( unsigned int ID); + mitk::RestorePlanePositionOperation* GetPlanePosition( unsigned int ID); /// \brief Getting the number of all stored planes unsigned int GetNumberOfPlanePositions(); - protected: + friend class ::MitkCoreActivator; - PlanePositionManager(); + private: - ~PlanePositionManager(); - private: + mitkClassMacro(PlanePositionManagerService, LightObject); - static PlanePositionManager* m_Instance; + itkFactorylessNewMacro(PlanePositionManagerService); + + PlanePositionManagerService(); + ~PlanePositionManagerService(); + + // Disable copy constructor and assignment operator. + PlanePositionManagerService(const PlanePositionManagerService&); + PlanePositionManagerService& operator=(const PlanePositionManagerService&); + + static PlanePositionManagerService* m_Instance; std::vector m_PositionList; }; } - +MITK_DECLARE_SERVICE_INTERFACE(mitk::PlanePositionManagerService, "org.mitk.PlanePositionManagerService") #endif diff --git a/Core/Code/Service/mitkCoreActivator.cpp b/Core/Code/Service/mitkCoreActivator.cpp index 78c6107eeb..dfeffc4e2e 100644 --- a/Core/Code/Service/mitkCoreActivator.cpp +++ b/Core/Code/Service/mitkCoreActivator.cpp @@ -1,47 +1,54 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkRenderingManager.h" +#include "mitkPlanePositionManager.h" #include /* * This is the module activator for the "Mitk" module. It registers core services * like ... */ class MitkCoreActivator : public mitk::ModuleActivator { public: void Load(mitk::ModuleContext* context) { //m_RenderingManager = mitk::RenderingManager::New(); //context->RegisterService(renderingManager.GetPointer()); + m_PlanePositionManager = mitk::PlanePositionManagerService::New(); + m_PlanePositionManagerReg = context->RegisterService(m_PlanePositionManager); } void Unload(mitk::ModuleContext* ) { + m_PlanePositionManagerReg.Unregister(); + m_PlanePositionManager = 0; } private: mitk::RenderingManager::Pointer m_RenderingManager; + mitk::PlanePositionManagerService::Pointer m_PlanePositionManager; + mitk::ServiceRegistration m_PlanePositionManagerReg; }; MITK_EXPORT_MODULE_ACTIVATOR(Mitk, MitkCoreActivator) diff --git a/Core/Code/Testing/mitkPlanePositionManagerTest.cpp b/Core/Code/Testing/mitkPlanePositionManagerTest.cpp index b467b7ab1f..a783e80e81 100644 --- a/Core/Code/Testing/mitkPlanePositionManagerTest.cpp +++ b/Core/Code/Testing/mitkPlanePositionManagerTest.cpp @@ -1,247 +1,255 @@ #include "mitkRotationOperation.h" #include "mitkTestingMacros.h" #include "mitkPlanePositionManager.h" #include "mitkSliceNavigationController.h" #include "mitkGeometry3D.h" #include "mitkPlaneGeometry.h" #include "mitkImage.h" #include "mitkSurface.h" #include "mitkStandaloneDataStorage.h" #include "mitkDataNode.h" #include "mitkStringProperty.h" #include "mitkBaseProperty.h" #include "mitkInteractionConst.h" #include "vnl/vnl_vector.h" #include - -//TODO: Test GetInstance() / GetService +#include "mitkGetModuleContext.h" std::vector m_Geometries; std::vector m_SliceIndices; +mitk::PlanePositionManagerService* m_Service; + -void SetUpBeforeTest() +int SetUpBeforeTest() { + //Getting Service + mitk::ServiceReference serviceRef = mitk::GetModuleContext()->GetServiceReference(); + m_Service = dynamic_cast(mitk::GetModuleContext()->GetService(serviceRef)); + + if (m_Service == 0) + return EXIT_FAILURE; + //Creating different Geometries m_Geometries.reserve(100); mitk::PlaneGeometry::PlaneOrientation views[] = {mitk::PlaneGeometry::Transversal, mitk::PlaneGeometry::Sagittal, mitk::PlaneGeometry::Frontal}; 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); } } 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(mitk::PlanePositionManager::GetInstance() != NULL, "Testing GetInstance() of PlanePositionManager"); + MITK_TEST_CONDITION(m_Service != NULL, "Testing getting of PlanePositionManagerService"); - unsigned int currentID(mitk::PlanePositionManager::GetInstance()->AddNewPlanePosition(m_Geometries.at(0),0)); + unsigned int currentID(m_Service->AddNewPlanePosition(m_Geometries.at(0),0)); - bool error = ((mitk::PlanePositionManager::GetInstance()->GetNumberOfPlanePositions() != 1)||(currentID != 0)); + bool error = ((m_Service->GetNumberOfPlanePositions() != 1)||(currentID != 0)); if(error) { - MITK_TEST_CONDITION(mitk::PlanePositionManager::GetInstance()->GetNumberOfPlanePositions() == 1,"Checking for correct number of planepositions"); + 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 = mitk::PlanePositionManager::GetInstance()->AddNewPlanePosition(m_Geometries.at(i),i); - error = ((mitk::PlanePositionManager::GetInstance()->GetNumberOfPlanePositions() != i+1)||(newID != (currentID+1))); + 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(mitk::PlanePositionManager::GetInstance()->GetNumberOfPlanePositions() == i+1,"Checking for correct number of planepositions"); + 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: "<GetNumberOfPlanePositions(); + 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 = mitk::PlanePositionManager::GetInstance()->AddNewPlanePosition(m_Geometries.at(i*2),i*2); - error = ((mitk::PlanePositionManager::GetInstance()->GetNumberOfPlanePositions() != numberOfPlanePos)||(newID != i*2)); + 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( mitk::PlanePositionManager::GetInstance()->GetNumberOfPlanePositions() == numberOfPlanePos, "Checking for correct number of planepositions"); + 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() { mitk::PlaneGeometry* plane; mitk::RestorePlanePositionOperation* op; 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) { plane = m_Geometries.at(i); mitk::PlaneGeometry* test = m_Geometries.at(i); - op = mitk::PlanePositionManager::GetInstance()->GetPlanePosition(i); + 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().Get_vnl_vector(),plane->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(2).normalize()) || !mitk::MatrixEqualElementWise(op->GetTransform()->GetMatrix(), plane->GetIndexToWorldTransform()->GetMatrix()) ); if( error ) { MITK_TEST_OUTPUT(<<"Iteration: "<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: "<GetDirectionVector()<<" plane: "<GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(2)<<"\n"; MITK_TEST_CONDITION( mitk::Equal(op->GetDirectionVector().Get_vnl_vector(),plane->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(2)), "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 = ( mitk::PlanePositionManager::GetInstance()->GetPlanePosition(100000000) != 0 || - mitk::PlanePositionManager::GetInstance()->GetPlanePosition(-1) != 0 ); + error = ( m_Service->GetPlanePosition(100000000) != 0 || + m_Service->GetPlanePosition(-1) != 0 ); if (error) { - MITK_TEST_CONDITION(mitk::PlanePositionManager::GetInstance()->GetPlanePosition(100000000) == 0, "Trying to get non existing pos"); - MITK_TEST_CONDITION(mitk::PlanePositionManager::GetInstance()->GetPlanePosition(-1) == 0, "Trying to get non existing pos"); + MITK_TEST_CONDITION(m_Service->GetPlanePosition(100000000) == 0, "Trying to get non existing pos"); + MITK_TEST_CONDITION(m_Service->GetPlanePosition(-1) == 0, "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 = mitk::PlanePositionManager::GetInstance()->GetNumberOfPlanePositions(); + unsigned int size = m_Service->GetNumberOfPlanePositions(); bool removed (true); //Testing for invalid IDs - removed = mitk::PlanePositionManager::GetInstance()->RemovePlanePosition( -1 ); - removed = mitk::PlanePositionManager::GetInstance()->RemovePlanePosition( 1000000 ); - unsigned int size2 = mitk::PlanePositionManager::GetInstance()->GetNumberOfPlanePositions(); + 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 = mitk::PlanePositionManager::GetInstance()->RemovePlanePosition( i ); - unsigned int size2 = mitk::PlanePositionManager::GetInstance()->GetNumberOfPlanePositions(); + 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 = mitk::PlanePositionManager::GetInstance()->GetNumberOfPlanePositions(); + unsigned int numPos = m_Service->GetNumberOfPlanePositions(); MITK_INFO<RemoveAllPlanePositions(); + m_Service->RemoveAllPlanePositions(); bool error (true); - error = (mitk::PlanePositionManager::GetInstance()->GetNumberOfPlanePositions() != 0 || - mitk::PlanePositionManager::GetInstance()->GetPlanePosition(60) != 0); + error = (m_Service->GetNumberOfPlanePositions() != 0 || + m_Service->GetPlanePosition(60) != 0); if (error) { - MITK_TEST_CONDITION(mitk::PlanePositionManager::GetInstance()->GetNumberOfPlanePositions() == 0, "Testing remove all pos"); - MITK_TEST_CONDITION(mitk::PlanePositionManager::GetInstance()->GetPlanePosition(60) == 0, "Testing remove all pos"); + MITK_TEST_CONDITION(m_Service->GetNumberOfPlanePositions() == 0, "Testing remove all pos"); + MITK_TEST_CONDITION(m_Service->GetPlanePosition(60) == 0, "Testing remove all pos"); return EXIT_FAILURE; } return EXIT_SUCCESS; } int mitkPlanePositionManagerTest(int argc, char* argv[]) { MITK_TEST_OUTPUT(<<"Starting Test 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, ""); return EXIT_SUCCESS; } diff --git a/Core/Code/Testing/mitkSliceNavigationControllerTest.cpp b/Core/Code/Testing/mitkSliceNavigationControllerTest.cpp index 3ade092104..5fe7e907e7 100644 --- a/Core/Code/Testing/mitkSliceNavigationControllerTest.cpp +++ b/Core/Code/Testing/mitkSliceNavigationControllerTest.cpp @@ -1,417 +1,420 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkSliceNavigationController.h" #include "mitkPlaneGeometry.h" #include "mitkSlicedGeometry3D.h" #include "mitkTimeSlicedGeometry.h" #include "mitkRotationOperation.h" #include "mitkInteractionConst.h" #include "mitkPlanePositionManager.h" #include "mitkTestingMacros.h" +#include "mitkGetModuleContext.h" #include #include #include bool operator==(const mitk::Geometry3D & left, const mitk::Geometry3D & right) { mitk::BoundingBox::BoundsArrayType leftbounds, rightbounds; leftbounds =left.GetBounds(); rightbounds=right.GetBounds(); unsigned int i; for(i=0;i<6;++i) if(mitk::Equal(leftbounds[i],rightbounds[i])==false) return false; const mitk::Geometry3D::TransformType::MatrixType & leftmatrix = left.GetIndexToWorldTransform()->GetMatrix(); const mitk::Geometry3D::TransformType::MatrixType & rightmatrix = right.GetIndexToWorldTransform()->GetMatrix(); unsigned int j; for(i=0;i<3;++i) { const mitk::Geometry3D::TransformType::MatrixType::ValueType* leftvector = leftmatrix[i]; const mitk::Geometry3D::TransformType::MatrixType::ValueType* rightvector = rightmatrix[i]; for(j=0;j<3;++j) if(mitk::Equal(leftvector[i],rightvector[i])==false) return false; } const mitk::Geometry3D::TransformType::OffsetType & leftoffset = left.GetIndexToWorldTransform()->GetOffset(); const mitk::Geometry3D::TransformType::OffsetType & rightoffset = right.GetIndexToWorldTransform()->GetOffset(); for(i=0;i<3;++i) if(mitk::Equal(leftoffset[i],rightoffset[i])==false) return false; return true; } int compareGeometry(const mitk::Geometry3D & geometry, const mitk::ScalarType& width, const mitk::ScalarType& height, const mitk::ScalarType& numSlices, const mitk::ScalarType& widthInMM, const mitk::ScalarType& heightInMM, const mitk::ScalarType& thicknessInMM, const mitk::Point3D& cornerpoint0, const mitk::Vector3D& right, const mitk::Vector3D& bottom, const mitk::Vector3D& normal) { std::cout << "Testing width, height and thickness (in units): "; if((mitk::Equal(geometry.GetExtent(0),width)==false) || (mitk::Equal(geometry.GetExtent(1),height)==false) || (mitk::Equal(geometry.GetExtent(2),numSlices)==false) ) { std::cout<<"[FAILED]"<GetCornerPoint(0), cornerpoint0)==false) { std::cout<<"[FAILED]"<SetInputWorldGeometry(geometry); std::cout<<"[PASSED]"<SetViewDirection(mitk::SliceNavigationController::Transversal); std::cout<<"[PASSED]"<Update(); std::cout<<"[PASSED]"<GetCreatedWorldGeometry(), width, height, numSlices, widthInMM, heightInMM, thicknessInMM*numSlices, transversalcornerpoint0, right, bottom*(-1.0), normal*(-1.0)); if(result!=EXIT_SUCCESS) { std::cout<<"[FAILED]"<SetViewDirection(mitk::SliceNavigationController::Frontal); std::cout<<"[PASSED]"<Update(); std::cout<<"[PASSED]"<GetAxisVector(1)*(+0.5/geometry->GetExtent(1)); result = compareGeometry(*sliceCtrl->GetCreatedWorldGeometry(), width, numSlices, height, widthInMM, thicknessInMM*numSlices, heightInMM, frontalcornerpoint0, right, normal, bottom); if(result!=EXIT_SUCCESS) { std::cout<<"[FAILED]"<SetViewDirection(mitk::SliceNavigationController::Sagittal); std::cout<<"[PASSED]"<Update(); std::cout<<"[PASSED]"<GetAxisVector(0)*(+0.5/geometry->GetExtent(0)); result = compareGeometry(*sliceCtrl->GetCreatedWorldGeometry(), height, numSlices, width, heightInMM, thicknessInMM*numSlices, widthInMM, sagittalcornerpoint0, bottom, normal, right); if(result!=EXIT_SUCCESS) { std::cout<<"[FAILED]"<InitializeStandardPlane(right.Get_vnl_vector(), bottom.Get_vnl_vector(), &spacing); planegeometry->SetOrigin(origin); //Create SlicedGeometry3D out of planeGeometry mitk::SlicedGeometry3D::Pointer slicedgeometry1 = mitk::SlicedGeometry3D::New(); unsigned int numSlices = 300; slicedgeometry1->InitializeEvenlySpaced(planegeometry, thicknessInMM, numSlices, false); //Create another slicedgeo which will be rotated mitk::SlicedGeometry3D::Pointer slicedgeometry2 = mitk::SlicedGeometry3D::New(); slicedgeometry2->InitializeEvenlySpaced(planegeometry, thicknessInMM, numSlices, false); //Create geo3D as reference mitk::Geometry3D::Pointer geometry = mitk::Geometry3D::New(); geometry->SetBounds(slicedgeometry1->GetBounds()); geometry->SetIndexToWorldTransform(slicedgeometry1->GetIndexToWorldTransform()); //Initialize planes for (int i=0; i < numSlices; i++) { mitk::PlaneGeometry::Pointer geo2d = mitk::PlaneGeometry::New(); geo2d->Initialize(); geo2d->SetReferenceGeometry(geometry); slicedgeometry1->SetGeometry2D(geo2d,i); } for (int i=0; i < numSlices; i++) { mitk::PlaneGeometry::Pointer geo2d = mitk::PlaneGeometry::New(); geo2d->Initialize(); geo2d->SetReferenceGeometry(geometry); slicedgeometry2->SetGeometry2D(geo2d,i); } slicedgeometry1->SetReferenceGeometry(geometry); slicedgeometry2->SetReferenceGeometry(geometry); //Create SNC mitk::SliceNavigationController::Pointer sliceCtrl1 = mitk::SliceNavigationController::New(); sliceCtrl1->SetInputWorldGeometry(slicedgeometry1); sliceCtrl1->Update(); mitk::SliceNavigationController::Pointer sliceCtrl2 = mitk::SliceNavigationController::New(); sliceCtrl2->SetInputWorldGeometry(slicedgeometry2); sliceCtrl2->Update(); slicedgeometry1->SetSliceNavigationController(sliceCtrl1); slicedgeometry2->SetSliceNavigationController(sliceCtrl2); //Rotate slicedgeo2 double angle = 63.84; mitk::Vector3D rotationVector; mitk::FillVector3D( rotationVector, 0.5, 0.95, 0.23 ); mitk::Point3D center = slicedgeometry2->GetCenter(); mitk::RotationOperation* op = new mitk::RotationOperation( mitk::OpROTATE, center, rotationVector, angle ); slicedgeometry2->ExecuteOperation(op); sliceCtrl2->Update(); - mitk::PlanePositionManager::GetInstance()->AddNewPlanePosition(slicedgeometry2->GetGeometry2D(0), 178); - sliceCtrl1->ExecuteOperation(mitk::PlanePositionManager::GetInstance()->GetPlanePosition(0)); + mitk::ServiceReference serviceRef = mitk::GetModuleContext()->GetServiceReference(); + mitk::PlanePositionManagerService* service = dynamic_cast(mitk::GetModuleContext()->GetService(serviceRef)); + service->AddNewPlanePosition(slicedgeometry2->GetGeometry2D(0), 178); + sliceCtrl1->ExecuteOperation(service->GetPlanePosition(0)); sliceCtrl1->Update(); mitk::Geometry2D* planeRotated = slicedgeometry2->GetGeometry2D(178); mitk::Geometry2D* planeRestored = dynamic_cast< const mitk::SlicedGeometry3D*>(sliceCtrl1->GetCurrentGeometry3D())->GetGeometry2D(178); bool error = ( !mitk::MatrixEqualElementWise(planeRotated->GetIndexToWorldTransform()->GetMatrix(), planeRestored->GetIndexToWorldTransform()->GetMatrix()) || !mitk::Equal(planeRotated->GetOrigin(), planeRestored->GetOrigin()) || !mitk::Equal(planeRotated->GetSpacing(), planeRestored->GetSpacing()) || !mitk::Equal(slicedgeometry2->GetDirectionVector(), dynamic_cast< const mitk::SlicedGeometry3D*>(sliceCtrl1->GetCurrentGeometry3D())->GetDirectionVector()) || !mitk::Equal(slicedgeometry2->GetSlices(), dynamic_cast< const mitk::SlicedGeometry3D*>(sliceCtrl1->GetCurrentGeometry3D())->GetSlices()) || !mitk::MatrixEqualElementWise(slicedgeometry2->GetIndexToWorldTransform()->GetMatrix(), dynamic_cast< const mitk::SlicedGeometry3D*>(sliceCtrl1->GetCurrentGeometry3D())->GetIndexToWorldTransform()->GetMatrix()) ); if (error) { MITK_TEST_CONDITION(mitk::MatrixEqualElementWise(planeRotated->GetIndexToWorldTransform()->GetMatrix(), planeRestored->GetIndexToWorldTransform()->GetMatrix()),"Testing for IndexToWorld"); MITK_INFO<<"Rotated: \n"<GetIndexToWorldTransform()->GetMatrix()<<" Restored: \n"<GetIndexToWorldTransform()->GetMatrix(); MITK_TEST_CONDITION(mitk::Equal(planeRotated->GetOrigin(), planeRestored->GetOrigin()),"Testing for origin"); MITK_INFO<<"Rotated: \n"<GetOrigin()<<" Restored: \n"<GetOrigin(); MITK_TEST_CONDITION(mitk::Equal(planeRotated->GetSpacing(), planeRestored->GetSpacing()),"Testing for spacing"); MITK_INFO<<"Rotated: \n"<GetSpacing()<<" Restored: \n"<GetSpacing(); MITK_TEST_CONDITION(mitk::Equal(slicedgeometry2->GetDirectionVector(), dynamic_cast< const mitk::SlicedGeometry3D*>(sliceCtrl1->GetCurrentGeometry3D())->GetDirectionVector()),"Testing for directionvector"); MITK_INFO<<"Rotated: \n"<GetDirectionVector()<<" Restored: \n"<(sliceCtrl1->GetCurrentGeometry3D())->GetDirectionVector(); MITK_TEST_CONDITION(mitk::Equal(slicedgeometry2->GetSlices(), dynamic_cast< const mitk::SlicedGeometry3D*>(sliceCtrl1->GetCurrentGeometry3D())->GetSlices()),"Testing for numslices"); MITK_INFO<<"Rotated: \n"<GetSlices()<<" Restored: \n"<(sliceCtrl1->GetCurrentGeometry3D())->GetSlices(); MITK_TEST_CONDITION(mitk::MatrixEqualElementWise(slicedgeometry2->GetIndexToWorldTransform()->GetMatrix(), dynamic_cast< const mitk::SlicedGeometry3D*>(sliceCtrl1->GetCurrentGeometry3D())->GetIndexToWorldTransform()->GetMatrix()),"Testing for IndexToWorld"); MITK_INFO<<"Rotated: \n"<GetIndexToWorldTransform()->GetMatrix()<<" Restored: \n"<(sliceCtrl1->GetCurrentGeometry3D())->GetIndexToWorldTransform()->GetMatrix(); return EXIT_FAILURE; } return EXIT_SUCCESS; } int mitkSliceNavigationControllerTest(int /*argc*/, char* /*argv*/[]) { int result=EXIT_FAILURE; std::cout << "Creating and initializing a PlaneGeometry: "; mitk::PlaneGeometry::Pointer planegeometry = mitk::PlaneGeometry::New(); mitk::Point3D origin; mitk::Vector3D right, bottom, normal; mitk::ScalarType width, height; mitk::ScalarType widthInMM, heightInMM, thicknessInMM; width = 100; widthInMM = width; height = 200; heightInMM = height; thicknessInMM = 1.5; // mitk::FillVector3D(origin, 0, 0, thicknessInMM*0.5); 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::Vector3D spacing; normal.Normalize(); normal *= thicknessInMM; mitk::FillVector3D(spacing, 1.0, 1.0, thicknessInMM); planegeometry->InitializeStandardPlane(right.Get_vnl_vector(), bottom.Get_vnl_vector(), &spacing); planegeometry->SetOrigin(origin); std::cout<<"[PASSED]"<InitializeEvenlySpaced(planegeometry, thicknessInMM, numSlices, false); std::cout<<"[PASSED]"<SetBounds(slicedgeometry->GetBounds()); geometry->SetIndexToWorldTransform(slicedgeometry->GetIndexToWorldTransform()); std::cout<<"[PASSED]"<GetCornerPoint(0); result=testGeometry(geometry, width, height, numSlices, widthInMM, heightInMM, thicknessInMM, cornerpoint0, right, bottom, normal); if(result!=EXIT_SUCCESS) return result; mitk::BoundingBox::BoundsArrayType bounds = geometry->GetBounds(); mitk::AffineTransform3D::Pointer transform = mitk::AffineTransform3D::New(); transform->SetMatrix(geometry->GetIndexToWorldTransform()->GetMatrix()); mitk::BoundingBox::Pointer boundingbox = geometry->CalculateBoundingBoxRelativeToTransform(transform); geometry->SetBounds(boundingbox->GetBounds()); cornerpoint0 = geometry->GetCornerPoint(0); result=testGeometry(geometry, width, height, numSlices, widthInMM, heightInMM, thicknessInMM, cornerpoint0, right, bottom, normal); if(result!=EXIT_SUCCESS) return result; std::cout << "Changing the IndexToWorldTransform of the geometry to a rotated version by SetIndexToWorldTransform() (keep cornerpoint0): "; 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(cornerpoint0.GetVectorFromOrigin()); right.Set_vnl_vector( rotation.rotation_matrix_transpose()*right.Get_vnl_vector() ); bottom.Set_vnl_vector(rotation.rotation_matrix_transpose()*bottom.Get_vnl_vector()); normal.Set_vnl_vector(rotation.rotation_matrix_transpose()*normal.Get_vnl_vector()); geometry->SetIndexToWorldTransform(transform); std::cout<<"[PASSED]"<GetCornerPoint(0); result = testGeometry(geometry, width, height, numSlices, widthInMM, heightInMM, thicknessInMM, cornerpoint0, right, bottom, normal); if(result!=EXIT_SUCCESS) return result; //Testing Execute RestorePlanePositionOperation result = testRestorePlanePostionOperation(); if(result!=EXIT_SUCCESS) return result; std::cout<<"[TEST DONE]"< #include #include "QmitkSegmentationView.h" #include "QmitkSegmentationPostProcessing.h" #include "QmitkSegmentationOrganNamesHandling.cpp" #include #include #include "mitkVtkResliceInterpolationProperty.h" +#include "mitkGetModuleContext.h" + const std::string QmitkSegmentationView::VIEW_ID = "org.mitk.views.segmentation"; // public methods QmitkSegmentationView::QmitkSegmentationView() :m_Parent(NULL) ,m_Controls(NULL) ,m_MultiWidget(NULL) ,m_RenderingManagerObserverTag(0) { } QmitkSegmentationView::~QmitkSegmentationView() { // delete m_PostProcessing; delete m_Controls; } void QmitkSegmentationView::NewNodesGenerated() { // ForceDisplayPreferencesUponAllImages(); } void QmitkSegmentationView::NewNodeObjectsGenerated(mitk::ToolManager::DataVectorType* nodes) { if (!nodes) return; mitk::ToolManager* toolManager = m_Controls->m_ManualToolSelectionBox->GetToolManager(); if (!toolManager) return; for (mitk::ToolManager::DataVectorType::iterator iter = nodes->begin(); iter != nodes->end(); ++iter) { this->FireNodeSelected( *iter ); // only last iteration meaningful, multiple generated objects are not taken into account here } } void QmitkSegmentationView::Activated() { // should be moved to ::BecomesVisible() or similar if( m_Controls ) { m_Controls->m_ManualToolSelectionBox->setEnabled( true ); m_Controls->m_OrganToolSelectionBox->setEnabled( true ); m_Controls->m_LesionToolSelectionBox->setEnabled( true ); m_Controls->m_SlicesInterpolator->EnableInterpolation( m_Controls->widgetStack->currentWidget() == m_Controls->pageManual ); itk::ReceptorMemberCommand::Pointer command1 = itk::ReceptorMemberCommand::New(); command1->SetCallbackFunction( this, &QmitkSegmentationView::RenderingManagerReinitialized ); m_RenderingManagerObserverTag = mitk::RenderingManager::GetInstance()->AddObserver( mitk::RenderingManagerViewsInitializedEvent(), command1 ); //mitk::PlanePositionManager::GetInstance()->SetDataStorage(this->GetDataStorage()); } } void QmitkSegmentationView::Deactivated() { if( m_Controls ) { mitk::RenderingManager::GetInstance()->RemoveObserver( m_RenderingManagerObserverTag ); m_Controls->m_ManualToolSelectionBox->setEnabled( false ); //deactivate all tools m_Controls->m_ManualToolSelectionBox->GetToolManager()->ActivateTool(-1); m_Controls->m_OrganToolSelectionBox->setEnabled( false ); m_Controls->m_LesionToolSelectionBox->setEnabled( false ); m_Controls->m_SlicesInterpolator->EnableInterpolation( false ); - mitk::PlanePositionManager::GetInstance()->RemoveAllPlanePositions(); + //mitk::PlanePositionManager::GetInstance()->RemoveAllPlanePositions(); + mitk::ServiceReference serviceRef = mitk::GetModuleContext()->GetServiceReference(); + mitk::PlanePositionManagerService* service = dynamic_cast(mitk::GetModuleContext()->GetService(serviceRef)); + service->RemoveAllPlanePositions(); } } void QmitkSegmentationView::StdMultiWidgetAvailable( QmitkStdMultiWidget& stdMultiWidget ) { SetMultiWidget(&stdMultiWidget); } void QmitkSegmentationView::StdMultiWidgetNotAvailable() { SetMultiWidget(NULL); } void QmitkSegmentationView::StdMultiWidgetClosed( QmitkStdMultiWidget& /*stdMultiWidget*/ ) { SetMultiWidget(NULL); } void QmitkSegmentationView::SetMultiWidget(QmitkStdMultiWidget* multiWidget) { if (m_MultiWidget) { mitk::SlicesCoordinator* coordinator = m_MultiWidget->GetSlicesRotator(); if (coordinator) { coordinator->RemoveObserver( m_SlicesRotationObserverTag1 ); } coordinator = m_MultiWidget->GetSlicesSwiveller(); if (coordinator) { coordinator->RemoveObserver( m_SlicesRotationObserverTag2 ); } } // save the current multiwidget as the working widget m_MultiWidget = multiWidget; if (m_MultiWidget) { mitk::SlicesCoordinator* coordinator = m_MultiWidget->GetSlicesRotator(); if (coordinator) { itk::ReceptorMemberCommand::Pointer command2 = itk::ReceptorMemberCommand::New(); command2->SetCallbackFunction( this, &QmitkSegmentationView::SliceRotation ); m_SlicesRotationObserverTag1 = coordinator->AddObserver( mitk::SliceRotationEvent(), command2 ); } coordinator = m_MultiWidget->GetSlicesSwiveller(); if (coordinator) { itk::ReceptorMemberCommand::Pointer command2 = itk::ReceptorMemberCommand::New(); command2->SetCallbackFunction( this, &QmitkSegmentationView::SliceRotation ); m_SlicesRotationObserverTag2 = coordinator->AddObserver( mitk::SliceRotationEvent(), command2 ); } } if (m_Parent) { m_Parent->setEnabled(m_MultiWidget); } // tell the interpolation about toolmanager and multiwidget (and data storage) if (m_Controls && m_MultiWidget) { mitk::ToolManager* toolManager = m_Controls->m_ManualToolSelectionBox->GetToolManager(); m_Controls->m_SlicesInterpolator->SetDataStorage( *(this->GetDefaultDataStorage())); m_Controls->m_SlicesInterpolator->Initialize( toolManager, m_MultiWidget ); } } void QmitkSegmentationView::OnPreferencesChanged(const berry::IBerryPreferences*) { ForceDisplayPreferencesUponAllImages(); } void QmitkSegmentationView::RenderingManagerReinitialized(const itk::EventObject&) { CheckImageAlignment(); } void QmitkSegmentationView::SliceRotation(const itk::EventObject&) { CheckImageAlignment(); } // protected slots void QmitkSegmentationView::CreateNewSegmentation() { mitk::DataNode::Pointer node = m_Controls->m_ManualToolSelectionBox->GetToolManager()->GetReferenceData(0); if (node.IsNotNull()) { mitk::Image::Pointer image = dynamic_cast( node->GetData() ); if (image.IsNotNull()) { if (image->GetDimension()>2) { // ask about the name and organ type of the new segmentation QmitkNewSegmentationDialog* dialog = new QmitkNewSegmentationDialog( m_Parent ); // needs a QWidget as parent, "this" is not QWidget QString storedList = QString::fromStdString( this->GetPreferences()->GetByteArray("Organ-Color-List","") ); QStringList organColors; if (storedList.isEmpty()) { organColors = GetDefaultOrganColorString(); } else { /* a couple of examples of how organ names are stored: a simple item is built up like 'name#AABBCC' where #AABBCC is the hexadecimal notation of a color as known from HTML items are stored separated by ';' this makes it necessary to escape occurrences of ';' in name. otherwise the string "hugo;ypsilon#AABBCC;eugen#AABBCC" could not be parsed as two organs but we would get "hugo" and "ypsilon#AABBCC" and "eugen#AABBCC" so the organ name "hugo;ypsilon" is stored as "hugo\;ypsilon" and must be unescaped after loading the following lines could be one split with Perl's negative lookbehind */ // recover string list from BlueBerry view's preferences QString storedString = QString::fromStdString( this->GetPreferences()->GetByteArray("Organ-Color-List","") ); MITK_DEBUG << "storedString: " << storedString.toStdString(); // match a string consisting of any number of repetitions of either "anything but ;" or "\;". This matches everything until the next unescaped ';' QRegExp onePart("(?:[^;]|\\\\;)*"); MITK_DEBUG << "matching " << onePart.pattern().toStdString(); int count = 0; int pos = 0; while( (pos = onePart.indexIn( storedString, pos )) != -1 ) { ++count; int length = onePart.matchedLength(); if (length == 0) break; QString matchedString = storedString.mid(pos, length); MITK_DEBUG << " Captured length " << length << ": " << matchedString.toStdString(); pos += length + 1; // skip separating ';' // unescape possible occurrences of '\;' in the string matchedString.replace("\\;", ";"); // add matched string part to output list organColors << matchedString; } MITK_DEBUG << "Captured " << count << " organ name/colors"; } dialog->SetSuggestionList( organColors ); int dialogReturnValue = dialog->exec(); if ( dialogReturnValue == QDialog::Rejected ) return; // user clicked cancel or pressed Esc or something similar // ask the user about an organ type and name, add this information to the image's (!) propertylist // create a new image of the same dimensions and smallest possible pixel type mitk::ToolManager* toolManager = m_Controls->m_ManualToolSelectionBox->GetToolManager(); mitk::Tool* firstTool = toolManager->GetToolById(0); if (firstTool) { try { mitk::DataNode::Pointer emptySegmentation = firstTool->CreateEmptySegmentationNode( image, dialog->GetSegmentationName().toStdString(), dialog->GetColor() ); //Here we change the reslice interpolation mode for a segmentation, so that contours in rotated slice can be shown correctly emptySegmentation->SetProperty( "reslice interpolation", mitk::VtkResliceInterpolationProperty::New(VTK_RESLICE_LINEAR) ); // initialize showVolume to false to prevent recalculating the volume while working on the segmentation emptySegmentation->SetProperty( "showVolume", mitk::BoolProperty::New( false ) ); if (!emptySegmentation) return; // could be aborted by user UpdateOrganList( organColors, dialog->GetSegmentationName(), dialog->GetColor() ); /* escape ';' here (replace by '\;'), see longer comment above */ std::string stringForStorage = organColors.replaceInStrings(";","\\;").join(";").toStdString(); MITK_DEBUG << "Will store: " << stringForStorage; this->GetPreferences()->PutByteArray("Organ-Color-List", stringForStorage ); this->GetPreferences()->Flush(); this->GetDefaultDataStorage()->Add( emptySegmentation, node ); // add as a child, because the segmentation "derives" from the original this->FireNodeSelected( emptySegmentation ); this->OnSelectionChanged( emptySegmentation ); } catch (std::bad_alloc) { QMessageBox::warning(NULL,"Create new segmentation","Could not allocate memory for new segmentation"); } } } else { QMessageBox::information(NULL,"Segmentation","Segmentation is currently not supported for 2D images"); } } } else { MITK_ERROR << "'Create new segmentation' button should never be clickable unless a patient image is selected..."; } } void QmitkSegmentationView::CreateSegmentationFromSurface() { mitk::DataNode::Pointer surfaceNode = m_Controls->MaskSurfaces->GetSelectedNode(); mitk::Surface::Pointer surface(0); if(surfaceNode.IsNotNull()) surface = dynamic_cast ( surfaceNode->GetData() ); if(surface.IsNull()) { this->HandleException( "No surface selected.", m_Parent, true); return; } mitk::DataNode::Pointer imageNode = m_Controls->m_ManualToolSelectionBox->GetToolManager()->GetReferenceData(0); mitk::Image::Pointer image(0); if (imageNode.IsNotNull()) image = dynamic_cast( imageNode->GetData() ); if(image.IsNull()) { this->HandleException( "No image selected.", m_Parent, true); return; } mitk::SurfaceToImageFilter::Pointer s2iFilter = mitk::SurfaceToImageFilter::New(); s2iFilter->MakeOutputBinaryOn(); s2iFilter->SetInput(surface); s2iFilter->SetImage(image); s2iFilter->Update(); mitk::DataNode::Pointer resultNode = mitk::DataNode::New(); std::string nameOfResultImage = imageNode->GetName(); nameOfResultImage.append(surfaceNode->GetName()); resultNode->SetProperty("name", mitk::StringProperty::New(nameOfResultImage) ); resultNode->SetProperty("binary", mitk::BoolProperty::New(true) ); resultNode->SetData( s2iFilter->GetOutput() ); this->GetDataStorage()->Add(resultNode, imageNode); } void QmitkSegmentationView::ManualToolSelected(int id) { // disable crosshair movement when a manual drawing tool is active (otherwise too much visual noise) if (m_MultiWidget) { if (id >= 0) { m_MultiWidget->DisableNavigationControllerEventListening(); m_MultiWidget->SetWidgetPlaneMode(0); } else { m_MultiWidget->EnableNavigationControllerEventListening(); } } } void QmitkSegmentationView::ToolboxStackPageChanged(int id) { // interpolation only with manual tools visible m_Controls->m_SlicesInterpolator->EnableInterpolation( id == 0 ); if( id == 0 ) { mitk::DataNode::Pointer workingData = m_Controls->m_ManualToolSelectionBox->GetToolManager()->GetWorkingData(0); if( workingData.IsNotNull() ) { m_Controls->lblSegmentation->setText( workingData->GetName().c_str() ); m_Controls->lblSegImage->show(); m_Controls->lblSegmentation->show(); } } else { m_Controls->lblSegImage->hide(); m_Controls->lblSegmentation->hide(); } // this is just a workaround, should be removed when all tools support 3D+t if (id==2) // lesions { mitk::DataNode::Pointer node = m_Controls->m_ManualToolSelectionBox->GetToolManager()->GetReferenceData(0); if (node.IsNotNull()) { mitk::Image::Pointer image = dynamic_cast( node->GetData() ); if (image.IsNotNull()) { if (image->GetDimension()>3) { m_Controls->widgetStack->setCurrentIndex(0); QMessageBox::information(NULL,"Segmentation","Lesion segmentation is currently not supported for 4D images"); } } } } } // protected void QmitkSegmentationView::OnComboBoxSelectionChanged( const mitk::DataNode* node ) { mitk::DataNode* selectedNode = const_cast(node); if( selectedNode != NULL ) { m_Controls->refImageSelector->show(); m_Controls->lblReferenceImageSelectionWarning->hide(); this->OnSelectionChanged( const_cast(node) ); } else { m_Controls->refImageSelector->hide(); m_Controls->lblReferenceImageSelectionWarning->show(); } } //to remember the contour positions void QmitkSegmentationView::CheckboxRememberContourPositionsStateChanged (int state) { mitk::SegTool2D::Pointer manualSegmentationTool; unsigned int numberOfExistingTools = m_Controls->m_ManualToolSelectionBox->GetToolManager()->GetTools().size(); for(unsigned int i = 0; i < numberOfExistingTools; i++) { manualSegmentationTool = dynamic_cast(m_Controls->m_ManualToolSelectionBox->GetToolManager()->GetToolById(i)); if (manualSegmentationTool) { if(state == Qt::Checked) { manualSegmentationTool->SetRememberContourPositions( true ); } else { manualSegmentationTool->SetRememberContourPositions( false ); } } } } void QmitkSegmentationView::OnSelectionChanged(mitk::DataNode* node) { std::vector nodes; nodes.push_back( node ); this->OnSelectionChanged( nodes ); } void QmitkSegmentationView::OnSurfaceSelectionChanged() { // if Image and Surface are selected, enable button if ( (m_Controls->refImageSelector->GetSelectedNode().IsNull()) || (m_Controls->MaskSurfaces->GetSelectedNode().IsNull())) m_Controls->CreateSegmentationFromSurface->setEnabled(false); else m_Controls->CreateSegmentationFromSurface->setEnabled(true); } void QmitkSegmentationView::OnSelectionChanged(std::vector nodes) { // if the selected node is a contourmarker if ( !nodes.empty() ) { std::string markerName = "Position"; unsigned int numberOfNodes = nodes.size(); std::string nodeName = nodes.at( 0 )->GetName(); if ( ( numberOfNodes == 1 ) && ( nodeName.find( markerName ) == 0) ) { this->OnContourMarkerSelected( nodes.at( 0 ) ); } } // if Image and Surface are selected, enable button if ( (m_Controls->refImageSelector->GetSelectedNode().IsNull()) || (m_Controls->MaskSurfaces->GetSelectedNode().IsNull())) m_Controls->CreateSegmentationFromSurface->setEnabled(false); else m_Controls->CreateSegmentationFromSurface->setEnabled(true); if (!m_Parent || !m_Parent->isVisible()) return; // reaction to BlueBerry selection events // this method will try to figure out if a relevant segmentation and its corresponding original image were selected // a warning is issued if the selection is invalid // appropriate reactions are triggered otherwise mitk::DataNode::Pointer referenceData = FindFirstRegularImage( nodes ); //m_Controls->refImageSelector->GetSelectedNode(); //FindFirstRegularImage( nodes ); mitk::DataNode::Pointer workingData = FindFirstSegmentation( nodes ); bool invalidSelection( !nodes.empty() && ( nodes.size() > 2 || // maximum 2 selected nodes (nodes.size() == 2 && (workingData.IsNull() || referenceData.IsNull()) ) || // with two nodes, one must be the original image, one the segmentation ( workingData.GetPointer() == referenceData.GetPointer() ) //one node is selected as reference and working image // one item is always ok (might be working or reference or nothing ) ); if (invalidSelection) { // TODO visible warning when two images are selected MITK_ERROR << "WARNING: No image, too many (>2) or two equal images were selected."; workingData = NULL; if( m_Controls->refImageSelector->GetSelectedNode().IsNull() ) referenceData = NULL; } if ( workingData.IsNotNull() && referenceData.IsNull() ) { // find the DataStorage parent of workingData // try to find a "normal image" parent, select this as reference image mitk::TNodePredicateDataType::Pointer isImage = mitk::TNodePredicateDataType::New(); mitk::NodePredicateProperty::Pointer isBinary = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); mitk::NodePredicateNot::Pointer isNotBinary = mitk::NodePredicateNot::New( isBinary ); mitk::NodePredicateAnd::Pointer isNormalImage = mitk::NodePredicateAnd::New( isImage, isNotBinary ); mitk::DataStorage::SetOfObjects::ConstPointer possibleParents = this->GetDefaultDataStorage()->GetSources( workingData, isNormalImage ); if (possibleParents->size() > 0) { if (possibleParents->size() > 1) { // TODO visible warning for this rare case MITK_ERROR << "Selected binary image has multiple parents. Using arbitrary first one for segmentation."; } referenceData = (*possibleParents)[0]; } } //set comboBox to reference image disconnect( m_Controls->refImageSelector, SIGNAL( OnSelectionChanged( const mitk::DataNode* ) ), this, SLOT( OnComboBoxSelectionChanged( const mitk::DataNode* ) ) ); m_Controls->refImageSelector->setCurrentIndex( m_Controls->refImageSelector->Find(referenceData) ); connect( m_Controls->refImageSelector, SIGNAL( OnSelectionChanged( const mitk::DataNode* ) ), this, SLOT( OnComboBoxSelectionChanged( const mitk::DataNode* ) ) ); // if Image and Surface are selected, enable button if ( (m_Controls->refImageSelector->GetSelectedNode().IsNull()) || (m_Controls->MaskSurfaces->GetSelectedNode().IsNull()) || (!referenceData)) m_Controls->CreateSegmentationFromSurface->setEnabled(false); else m_Controls->CreateSegmentationFromSurface->setEnabled(true); SetToolManagerSelection(referenceData, workingData); ForceDisplayPreferencesUponAllImages(); } //New since rotated contour drawing is allowed. Effects a reorientation of the plane of the affected widget to the marker`s position void QmitkSegmentationView::OnContourMarkerSelected(const mitk::DataNode *node) { //TODO renderWindow anders bestimmen, siehe CheckAlignment QmitkRenderWindow* selectedRenderWindow = 0; QmitkRenderWindow* RenderWindow1 = this->GetActiveStdMultiWidget()->GetRenderWindow1(); QmitkRenderWindow* RenderWindow2 = this->GetActiveStdMultiWidget()->GetRenderWindow2(); QmitkRenderWindow* RenderWindow3 = this->GetActiveStdMultiWidget()->GetRenderWindow3(); QmitkRenderWindow* RenderWindow4 = this->GetActiveStdMultiWidget()->GetRenderWindow4(); bool PlanarFigureInitializedWindow = false; // find initialized renderwindow if (node->GetBoolProperty("PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, RenderWindow1->GetRenderer())) { selectedRenderWindow = RenderWindow1; } if (!selectedRenderWindow && node->GetBoolProperty( "PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, RenderWindow2->GetRenderer())) { selectedRenderWindow = RenderWindow2; } if (!selectedRenderWindow && node->GetBoolProperty( "PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, RenderWindow3->GetRenderer())) { selectedRenderWindow = RenderWindow3; } if (!selectedRenderWindow && node->GetBoolProperty( "PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, RenderWindow4->GetRenderer())) { selectedRenderWindow = RenderWindow4; } // make node visible if (selectedRenderWindow) { std::string nodeName = node->GetName(); unsigned int t = nodeName.find_last_of(" "); unsigned int id = atof(nodeName.substr(t+1).c_str())-1; - //selectedRenderWindow->GetSliceNavigationController()->RestorePlanePosition(mitk::PlanePositionManager::GetInstance()->GetPlanePosition(id)); - selectedRenderWindow->GetSliceNavigationController()->ExecuteOperation(mitk::PlanePositionManager::GetInstance()->GetPlanePosition(id)); + mitk::ServiceReference serviceRef = mitk::GetModuleContext()->GetServiceReference(); + mitk::PlanePositionManagerService* service = dynamic_cast(mitk::GetModuleContext()->GetService(serviceRef)); + selectedRenderWindow->GetSliceNavigationController()->ExecuteOperation(service->GetPlanePosition(id)); selectedRenderWindow->GetRenderer()->GetDisplayGeometry()->Fit(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } mitk::DataNode::Pointer QmitkSegmentationView::FindFirstRegularImage( std::vector nodes ) { if (nodes.empty()) return NULL; for(unsigned int i = 0; i < nodes.size(); ++i) { //mitk::DataNode::Pointer node = i.value() bool isImage(false); if (nodes.at(i)->GetData()) { isImage = dynamic_cast(nodes.at(i)->GetData()) != NULL; } // make sure this is not a binary image bool isSegmentation(false); nodes.at(i)->GetBoolProperty("binary", isSegmentation); // return first proper mitk::Image if (isImage && !isSegmentation) return nodes.at(i); } return NULL; } mitk::DataNode::Pointer QmitkSegmentationView::FindFirstSegmentation( std::vector nodes ) { if (nodes.empty()) return NULL; for(unsigned int i = 0; i < nodes.size(); ++i) { bool isImage(false); if (nodes.at(i)->GetData()) { isImage = dynamic_cast(nodes.at(i)->GetData()) != NULL; } bool isSegmentation(false); nodes.at(i)->GetBoolProperty("binary", isSegmentation); // return first proper binary mitk::Image if (isImage && isSegmentation) { return nodes.at(i); } } return NULL; } void QmitkSegmentationView::SetToolManagerSelection(const mitk::DataNode* referenceData, const mitk::DataNode* workingData) { // called as a result of new BlueBerry selections // tells the ToolManager for manual segmentation about new selections // updates GUI information about what the user should select mitk::ToolManager* toolManager = m_Controls->m_ManualToolSelectionBox->GetToolManager(); toolManager->SetReferenceData(const_cast(referenceData)); toolManager->SetWorkingData( const_cast(workingData)); // check original image m_Controls->btnNewSegmentation->setEnabled(referenceData != NULL); if (referenceData) { m_Controls->lblReferenceImageSelectionWarning->hide(); } else { m_Controls->lblReferenceImageSelectionWarning->show(); m_Controls->lblWorkingImageSelectionWarning->hide(); m_Controls->lblSegImage->hide(); m_Controls->lblSegmentation->hide(); } // check, wheter reference image is aligned like render windows. Otherwise display a visible warning (because 2D tools will probably not work) CheckImageAlignment(); // check segmentation if (referenceData) { if (!workingData) { m_Controls->lblWorkingImageSelectionWarning->show(); if( m_Controls->widgetStack->currentIndex() == 0 ) { m_Controls->lblSegImage->hide(); m_Controls->lblSegmentation->hide(); } } else { m_Controls->lblWorkingImageSelectionWarning->hide(); if( m_Controls->widgetStack->currentIndex() == 0 ) { m_Controls->lblSegmentation->setText( workingData->GetName().c_str() ); m_Controls->lblSegmentation->show(); m_Controls->lblSegImage->show(); } } } } void QmitkSegmentationView::CheckImageAlignment() { bool wrongAlignment(true); mitk::DataNode::Pointer node = m_Controls->m_ManualToolSelectionBox->GetToolManager()->GetReferenceData(0); if (node.IsNotNull()) { mitk::Image::Pointer image = dynamic_cast( node->GetData() ); if (image.IsNotNull() && m_MultiWidget) { wrongAlignment = !( IsRenderWindowAligned(m_MultiWidget->GetRenderWindow1(), image ) && IsRenderWindowAligned(m_MultiWidget->GetRenderWindow2(), image ) && IsRenderWindowAligned(m_MultiWidget->GetRenderWindow3(), image ) ); } if (wrongAlignment) { m_Controls->lblAlignmentWarning->show(); } } } bool QmitkSegmentationView::IsRenderWindowAligned(QmitkRenderWindow* renderWindow, mitk::Image* image) { if (!renderWindow) return false; // for all 2D renderwindows of m_MultiWidget check alignment mitk::PlaneGeometry::ConstPointer displayPlane = dynamic_cast( renderWindow->GetRenderer()->GetCurrentWorldGeometry2D() ); if (displayPlane.IsNull()) return false; int affectedDimension(-1); int affectedSlice(-1); return mitk::SegTool2D::DetermineAffectedImageSlice( image, displayPlane, affectedDimension, affectedSlice ); } void QmitkSegmentationView::ForceDisplayPreferencesUponAllImages() { if (!m_Parent || !m_Parent->isVisible()) return; // check all images and segmentations in DataStorage: // (items in brackets are implicitly done by previous steps) // 1. // if a reference image is selected, // show the reference image // and hide all other images (orignal and segmentation), // (and hide all segmentations of the other original images) // and show all the reference's segmentations // if no reference image is selected, do do nothing // // 2. // if a segmentation is selected, // show it // (and hide all all its siblings (childs of the same parent, incl, NULL parent)) // if no segmentation is selected, do nothing if (!m_Controls) return; // might happen on initialization (preferences loaded) mitk::DataNode::Pointer referenceData = m_Controls->m_ManualToolSelectionBox->GetToolManager()->GetReferenceData(0); mitk::DataNode::Pointer workingData = m_Controls->m_ManualToolSelectionBox->GetToolManager()->GetWorkingData(0); // 1. if (referenceData.IsNotNull()) { // iterate all images mitk::TNodePredicateDataType::Pointer isImage = mitk::TNodePredicateDataType::New(); mitk::DataStorage::SetOfObjects::ConstPointer allImages = this->GetDefaultDataStorage()->GetSubset( isImage ); for ( mitk::DataStorage::SetOfObjects::const_iterator iter = allImages->begin(); iter != allImages->end(); ++iter) { mitk::DataNode* node = *iter; // apply display preferences ApplyDisplayOptions(node); // set visibility node->SetVisibility(node == referenceData); } } // 2. if (workingData.IsNotNull()) { workingData->SetVisibility(true); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkSegmentationView::ApplyDisplayOptions(mitk::DataNode* node) { if (!node) return; bool isBinary(false); node->GetPropertyValue("binary", isBinary); if (isBinary) { node->SetProperty( "outline binary", mitk::BoolProperty::New( this->GetPreferences()->GetBool("draw outline", true)) ); node->SetProperty( "outline width", mitk::FloatProperty::New( 2.0 ) ); node->SetProperty( "opacity", mitk::FloatProperty::New( this->GetPreferences()->GetBool("draw outline", true) ? 1.0 : 0.3 ) ); node->SetProperty( "volumerendering", mitk::BoolProperty::New( this->GetPreferences()->GetBool("volume rendering", false) ) ); } } void QmitkSegmentationView::CreateQtPartControl(QWidget* parent) { // setup the basic GUI of this view m_Parent = parent; m_Controls = new Ui::QmitkSegmentationControls; m_Controls->setupUi(parent); m_Controls->lblWorkingImageSelectionWarning->hide(); m_Controls->lblAlignmentWarning->hide(); m_Controls->lblSegImage->hide(); m_Controls->lblSegmentation->hide(); m_Controls->refImageSelector->SetDataStorage(this->GetDefaultDataStorage()); m_Controls->refImageSelector->SetPredicate(mitk::NodePredicateDataType::New("Image")); if( m_Controls->refImageSelector->GetSelectedNode().IsNotNull() ) m_Controls->lblReferenceImageSelectionWarning->hide(); else m_Controls->refImageSelector->hide(); mitk::ToolManager* toolManager = m_Controls->m_ManualToolSelectionBox->GetToolManager(); toolManager->SetDataStorage( *(this->GetDefaultDataStorage()) ); assert ( toolManager ); // all part of open source MITK m_Controls->m_ManualToolSelectionBox->SetGenerateAccelerators(true); m_Controls->m_ManualToolSelectionBox->SetToolGUIArea( m_Controls->m_ManualToolGUIContainer ); m_Controls->m_ManualToolSelectionBox->SetDisplayedToolGroups("Add Subtract Paint Wipe 'Region Growing' Correction Fill Erase"); m_Controls->m_ManualToolSelectionBox->SetEnabledMode( QmitkToolSelectionBox::EnabledWithReferenceAndWorkingData ); // available only in the 3M application if ( !m_Controls->m_OrganToolSelectionBox->children().count() ) { m_Controls->widgetStack->setItemEnabled( 1, false ); } m_Controls->m_OrganToolSelectionBox->SetToolManager( *toolManager ); m_Controls->m_OrganToolSelectionBox->SetToolGUIArea( m_Controls->m_OrganToolGUIContainer ); m_Controls->m_OrganToolSelectionBox->SetDisplayedToolGroups("'Hippocampus left' 'Hippocampus right' 'Lung left' 'Lung right' 'Liver' 'Heart LV' 'Endocard LV' 'Epicard LV' 'Prostate'"); m_Controls->m_OrganToolSelectionBox->SetEnabledMode( QmitkToolSelectionBox::EnabledWithReferenceData ); // available only in the 3M application if ( !m_Controls->m_LesionToolSelectionBox->children().count() ) { m_Controls->widgetStack->setItemEnabled( 2, false ); } m_Controls->m_LesionToolSelectionBox->SetToolManager( *toolManager ); m_Controls->m_LesionToolSelectionBox->SetToolGUIArea( m_Controls->m_LesionToolGUIContainer ); m_Controls->m_LesionToolSelectionBox->SetDisplayedToolGroups("'Lymph Node'"); m_Controls->m_LesionToolSelectionBox->SetEnabledMode( QmitkToolSelectionBox::EnabledWithReferenceData ); toolManager->NewNodesGenerated += mitk::MessageDelegate( this, &QmitkSegmentationView::NewNodesGenerated ); // update the list of segmentations toolManager->NewNodeObjectsGenerated += mitk::MessageDelegate1( this, &QmitkSegmentationView::NewNodeObjectsGenerated ); // update the list of segmentations // create signal/slot connections connect( m_Controls->refImageSelector, SIGNAL( OnSelectionChanged( const mitk::DataNode* ) ), this, SLOT( OnComboBoxSelectionChanged( const mitk::DataNode* ) ) ); connect( m_Controls->btnNewSegmentation, SIGNAL(clicked()), this, SLOT(CreateNewSegmentation()) ); connect( m_Controls->CreateSegmentationFromSurface, SIGNAL(clicked()), this, SLOT(CreateSegmentationFromSurface()) ); connect( m_Controls->m_ManualToolSelectionBox, SIGNAL(ToolSelected(int)), this, SLOT(ManualToolSelected(int)) ); connect( m_Controls->widgetStack, SIGNAL(currentChanged(int)), this, SLOT(ToolboxStackPageChanged(int)) ); //To remember the position of each contour connect( m_Controls->cbRememberContourPositions, SIGNAL(stateChanged(int)), this, SLOT(CheckboxRememberContourPositionsStateChanged(int))); connect(m_Controls->MaskSurfaces, SIGNAL( OnSelectionChanged( const mitk::DataNode* ) ), this, SLOT( OnSurfaceSelectionChanged( ) ) ); m_Controls->MaskSurfaces->SetDataStorage(this->GetDefaultDataStorage()); m_Controls->MaskSurfaces->SetPredicate(mitk::NodePredicateDataType::New("Surface")); //// create helper class to provide context menus for segmentations in data manager // m_PostProcessing = new QmitkSegmentationPostProcessing(this->GetDefaultDataStorage(), this, m_Parent); } //void QmitkSegmentationView::OnPlaneModeChanged(int i) //{ // //if plane mode changes, disable all tools // if (m_MultiWidget) // { // mitk::ToolManager* toolManager = m_Controls->m_ManualToolSelectionBox->GetToolManager(); // // if (toolManager) // { // if (toolManager->GetActiveToolID() >= 0) // { // toolManager->ActivateTool(-1); // } // else // { // m_MultiWidget->EnableNavigationControllerEventListening(); // } // } // } //} // ATTENTION some methods for handling the known list of (organ names, colors) are defined in QmitkSegmentationOrganNamesHandling.cpp diff --git a/Modules/MitkExt/Interactions/mitkSegTool2D.cpp b/Modules/MitkExt/Interactions/mitkSegTool2D.cpp index d8986df204..d4b3dfc881 100644 --- a/Modules/MitkExt/Interactions/mitkSegTool2D.cpp +++ b/Modules/MitkExt/Interactions/mitkSegTool2D.cpp @@ -1,291 +1,295 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkSegTool2D.h" #include "mitkToolManager.h" #include "mitkDataStorage.h" #include "mitkBaseRenderer.h" #include "mitkPlaneGeometry.h" #include "mitkExtractImageFilter.h" #include "mitkExtractDirectedPlaneImageFilter.h" //Include of the new ImageExtractor #include "mitkExtractDirectedPlaneImageFilterNew.h" #include "mitkPlanarCircle.h" +#include "mitkGetModuleContext.h" + #define ROUND(a) ((a)>0 ? (int)((a)+0.5) : -(int)(0.5-(a))) mitk::SegTool2D::SegTool2D(const char* type) :Tool(type), m_LastEventSender(NULL), m_LastEventSlice(0), m_Contourmarkername ("Position"), m_RememberContourPositions (false) { // great magic numbers CONNECT_ACTION( 80, OnMousePressed ); CONNECT_ACTION( 90, OnMouseMoved ); CONNECT_ACTION( 42, OnMouseReleased ); CONNECT_ACTION( 49014, OnInvertLogic ); } mitk::SegTool2D::~SegTool2D() { } bool mitk::SegTool2D::OnMousePressed (Action*, const StateEvent* stateEvent) { const PositionEvent* positionEvent = dynamic_cast(stateEvent->GetEvent()); if (!positionEvent) return false; if ( positionEvent->GetSender()->GetMapperID() != BaseRenderer::Standard2D ) return false; // we don't want anything but 2D m_LastEventSender = positionEvent->GetSender(); m_LastEventSlice = m_LastEventSender->GetSlice(); return true; } bool mitk::SegTool2D::OnMouseMoved (Action*, const StateEvent* stateEvent) { const PositionEvent* positionEvent = dynamic_cast(stateEvent->GetEvent()); if (!positionEvent) return false; if ( m_LastEventSender != positionEvent->GetSender() ) return false; if ( m_LastEventSlice != m_LastEventSender->GetSlice() ) return false; return true; } bool mitk::SegTool2D::OnMouseReleased(Action*, const StateEvent* stateEvent) { const PositionEvent* positionEvent = dynamic_cast(stateEvent->GetEvent()); if (!positionEvent) return false; if ( m_LastEventSender != positionEvent->GetSender() ) return false; if ( m_LastEventSlice != m_LastEventSender->GetSlice() ) return false; return true; } bool mitk::SegTool2D::OnInvertLogic(Action*, const StateEvent* stateEvent) { const PositionEvent* positionEvent = dynamic_cast(stateEvent->GetEvent()); if (!positionEvent) return false; if ( m_LastEventSender != positionEvent->GetSender() ) return false; if ( m_LastEventSlice != m_LastEventSender->GetSlice() ) return false; return true; } bool mitk::SegTool2D::DetermineAffectedImageSlice( const Image* image, const PlaneGeometry* plane, int& affectedDimension, int& affectedSlice ) { assert(image); assert(plane); // compare normal of plane to the three axis vectors of the image Vector3D normal = plane->GetNormal(); Vector3D imageNormal0 = image->GetSlicedGeometry()->GetAxisVector(0); Vector3D imageNormal1 = image->GetSlicedGeometry()->GetAxisVector(1); Vector3D imageNormal2 = image->GetSlicedGeometry()->GetAxisVector(2); normal.Normalize(); imageNormal0.Normalize(); imageNormal1.Normalize(); imageNormal2.Normalize(); imageNormal0.Set_vnl_vector( vnl_cross_3d(normal.Get_vnl_vector(),imageNormal0.Get_vnl_vector()) ); imageNormal1.Set_vnl_vector( vnl_cross_3d(normal.Get_vnl_vector(),imageNormal1.Get_vnl_vector()) ); imageNormal2.Set_vnl_vector( vnl_cross_3d(normal.Get_vnl_vector(),imageNormal2.Get_vnl_vector()) ); double eps( 0.00001 ); // transversal if ( imageNormal2.GetNorm() <= eps ) { affectedDimension = 2; } // sagittal else if ( imageNormal1.GetNorm() <= eps ) { affectedDimension = 1; } // frontal else if ( imageNormal0.GetNorm() <= eps ) { affectedDimension = 0; } else { affectedDimension = -1; // no idea return false; } // determine slice number in image Geometry3D* imageGeometry = image->GetGeometry(0); Point3D testPoint = imageGeometry->GetCenter(); Point3D projectedPoint; plane->Project( testPoint, projectedPoint ); Point3D indexPoint; imageGeometry->WorldToIndex( projectedPoint, indexPoint ); affectedSlice = ROUND( indexPoint[affectedDimension] ); MITK_DEBUG << "indexPoint " << indexPoint << " affectedDimension " << affectedDimension << " affectedSlice " << affectedSlice; // check if this index is still within the image if ( affectedSlice < 0 || affectedSlice >= static_cast(image->GetDimension(affectedDimension)) ) return false; return true; } mitk::Image::Pointer mitk::SegTool2D::GetAffectedImageSliceAs2DImage(const PositionEvent* positionEvent, const Image* image) { if (!positionEvent) return NULL; assert( positionEvent->GetSender() ); // sure, right? unsigned int timeStep = positionEvent->GetSender()->GetTimeStep( image ); // get the timestep of the visible part (time-wise) of the image // first, we determine, which slice is affected const PlaneGeometry* planeGeometry( dynamic_cast (positionEvent->GetSender()->GetCurrentWorldGeometry2D() ) ); if ( !image || !planeGeometry ) return NULL; int affectedDimension( -1 ); int affectedSlice( -1 ); DetermineAffectedImageSlice( image, planeGeometry, affectedDimension, affectedSlice ); if ( DetermineAffectedImageSlice( image, planeGeometry, affectedDimension, affectedSlice ) ) { try { // now we extract the correct slice from the volume, resulting in a 2D image ExtractImageFilter::Pointer extractor= ExtractImageFilter::New(); extractor->SetInput( image ); extractor->SetSliceDimension( affectedDimension ); extractor->SetSliceIndex( affectedSlice ); extractor->SetTimeStep( timeStep ); extractor->Update(); // here we have a single slice that can be modified Image::Pointer slice = extractor->GetOutput(); return slice; } catch(...) { // not working return NULL; } } else { ExtractDirectedPlaneImageFilterNew::Pointer newExtractor = ExtractDirectedPlaneImageFilterNew::New(); newExtractor->SetInput( image ); newExtractor->SetActualInputTimestep( timeStep ); newExtractor->SetCurrentWorldGeometry2D( planeGeometry ); newExtractor->Update(); Image::Pointer slice = newExtractor->GetOutput(); return slice; } } mitk::Image::Pointer mitk::SegTool2D::GetAffectedWorkingSlice(const PositionEvent* positionEvent) { DataNode* workingNode( m_ToolManager->GetWorkingData(0) ); if ( !workingNode ) return NULL; Image* workingImage = dynamic_cast(workingNode->GetData()); if ( !workingImage ) return NULL; return GetAffectedImageSliceAs2DImage( positionEvent, workingImage ); } mitk::Image::Pointer mitk::SegTool2D::GetAffectedReferenceSlice(const PositionEvent* positionEvent) { DataNode* referenceNode( m_ToolManager->GetReferenceData(0) ); if ( !referenceNode ) return NULL; Image* referenceImage = dynamic_cast(referenceNode->GetData()); if ( !referenceImage ) return NULL; return GetAffectedImageSliceAs2DImage( positionEvent, referenceImage ); } void mitk::SegTool2D::SetRememberContourPositions(bool status) { m_RememberContourPositions = status; } void mitk::SegTool2D::AddContourmarker ( const PositionEvent* positionEvent ) { const mitk::Geometry2D* plane = dynamic_cast (dynamic_cast< const mitk::SlicedGeometry3D*>( positionEvent->GetSender()->GetSliceNavigationController()->GetCurrentGeometry3D())->GetGeometry2D(0)); - unsigned int size = mitk::PlanePositionManager::GetInstance()->GetNumberOfPlanePositions(); - unsigned int id = mitk::PlanePositionManager::GetInstance()->AddNewPlanePosition(plane, positionEvent->GetSender()->GetSliceNavigationController()->GetSlice()->GetPos()); + mitk::ServiceReference serviceRef = mitk::GetModuleContext()->GetServiceReference(); + PlanePositionManagerService* service = dynamic_cast(mitk::GetModuleContext()->GetService(serviceRef)); + unsigned int size = service->GetNumberOfPlanePositions(); + unsigned int id = service->AddNewPlanePosition(plane, positionEvent->GetSender()->GetSliceNavigationController()->GetSlice()->GetPos()); if (plane) { if ( id == size ) { //Creating PlanarFigure which currently serves as marker mitk::PlanarCircle::Pointer contourMarker = mitk::PlanarCircle::New(); contourMarker->SetGeometry2D( const_cast(plane)); std::stringstream markerStream; mitk::DataNode* workingNode (m_ToolManager->GetWorkingData(0)); markerStream << m_Contourmarkername ; markerStream << " "; markerStream << id+1; DataNode::Pointer rotatedContourNode = DataNode::New(); rotatedContourNode->SetData(contourMarker); rotatedContourNode->SetProperty( "name", StringProperty::New(markerStream.str()) ); rotatedContourNode->SetProperty( "isContourMarker", BoolProperty::New(true)); rotatedContourNode->SetBoolProperty( "PlanarFigureInitializedWindow", true, positionEvent->GetSender() ); rotatedContourNode->SetProperty( "includeInBoundingBox", BoolProperty::New(false)); m_ToolManager->GetDataStorage()->Add(rotatedContourNode, workingNode); } } //return id; } void mitk::SegTool2D::InteractiveSegmentationBugMessage( const std::string& message ) { MITK_ERROR << "********************************************************************************" << std::endl << " " << message << std::endl << "********************************************************************************" << std::endl << " " << std::endl << " If your image is rotated or the 2D views don't really contain the patient image, try to press the button next to the image selection. " << std::endl << " " << std::endl << " Please file a BUG REPORT: " << std::endl << " http://bugs.mitk.org" << std::endl << " Contain the following information:" << std::endl << " - What image were you working on?" << std::endl << " - Which region of the image?" << std::endl << " - Which tool did you use?" << std::endl << " - What did you do?" << std::endl << " - What happened (not)? What did you expect?" << std::endl; }