From 43371b7892b2a65c610b38807b85d80adb0a66f6 Mon Sep 17 00:00:00 2001 From: Matthew Holden Date: Wed, 22 Jan 2014 17:28:14 -0500 Subject: [PATCH] Cleaned up module structure; added automatic linear object segmentation. --- CMakeLists.txt | 6 + Logic/CMakeLists.txt | 2 + ...vtkSlicerLinearObjectRegistrationLogic.cxx | 180 ++++++------------ .../vtkSlicerLinearObjectRegistrationLogic.h | 20 +- MRML/CMakeLists.txt | 6 +- MRML/vtkMRMLLORPositionBufferNode.cxx | 44 +++++ MRML/vtkMRMLLORPositionBufferNode.h | 2 + MRML/vtkMRMLLORPositionNode.h | 6 +- MRML/vtkMRMLLORVectorMath.h | 34 ---- MRML/vtkMRMLLinearObjectRegistrationNode.cxx | 126 ++++++++++-- MRML/vtkMRMLLinearObjectRegistrationNode.h | 21 ++ .../qSlicerLinearObjectRegistrationModule.ui | 33 +++- Utilities/CMakeLists.txt | 38 ++++ Utilities/vtkMRMLLORConstants.cxx | 15 ++ Utilities/vtkMRMLLORConstants.h | 32 ++++ {MRML => Utilities}/vtkMRMLLORVectorMath.cxx | 0 Utilities/vtkMRMLLORVectorMath.h | 36 ++++ Widgets/CMakeLists.txt | 7 + .../Resources/UI/qSlicerLORAutomaticWidget.ui | 42 +--- .../Resources/UI/qSlicerLORManualDOFWidget.ui | 39 +--- .../UI/qSlicerLORManualSegmentationWidget.ui | 39 +--- Widgets/qSlicerLORAutomaticWidget.cxx | 161 ++++++++++++++++ Widgets/qSlicerLORAutomaticWidget.h | 73 +++++++ Widgets/qSlicerLORManualDOFWidget.cxx | 120 +++--------- Widgets/qSlicerLORManualDOFWidget.h | 18 +- .../qSlicerLORManualSegmentationWidget.cxx | 78 ++------ Widgets/qSlicerLORManualSegmentationWidget.h | 17 +- .../qSlicerLinearObjectCollectionWidget.cxx | 8 +- ...erLinearObjectRegistrationModuleWidget.cxx | 124 ++++++------ qSlicerLinearObjectRegistrationModuleWidget.h | 9 +- 30 files changed, 768 insertions(+), 568 deletions(-) delete mode 100644 MRML/vtkMRMLLORVectorMath.h create mode 100644 Utilities/CMakeLists.txt create mode 100644 Utilities/vtkMRMLLORConstants.cxx create mode 100644 Utilities/vtkMRMLLORConstants.h rename {MRML => Utilities}/vtkMRMLLORVectorMath.cxx (100%) create mode 100644 Utilities/vtkMRMLLORVectorMath.h create mode 100644 Widgets/qSlicerLORAutomaticWidget.cxx create mode 100644 Widgets/qSlicerLORAutomaticWidget.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 120e8d3..5164d91 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,6 +17,7 @@ endif() add_subdirectory(MRML) add_subdirectory(Logic) add_subdirectory(Widgets) +add_subdirectory(Utilities) #----------------------------------------------------------------------------- set(MODULE_EXPORT_DIRECTIVE "Q_SLICER_QTMODULES_${MODULE_NAME_UPPER}_EXPORT") @@ -27,6 +28,10 @@ set(MODULE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_BINARY_DIR}/Logic ${CMAKE_CURRENT_SOURCE_DIR}/Widgets ${CMAKE_CURRENT_BINARY_DIR}/Widgets + ${CMAKE_CURRENT_SOURCE_DIR}/MRML + ${CMAKE_CURRENT_BINARY_DIR}/MRML + ${CMAKE_CURRENT_SOURCE_DIR}/Utilities + ${CMAKE_CURRENT_BINARY_DIR}/Utilities ) set(MODULE_SRCS @@ -49,6 +54,7 @@ set(MODULE_UI_SRCS ) set(MODULE_TARGET_LIBRARIES + vtkSlicer${MODULE_NAME}ModuleUtilities vtkSlicer${MODULE_NAME}ModuleMRML vtkSlicer${MODULE_NAME}ModuleLogic qSlicer${MODULE_NAME}ModuleWidgets diff --git a/Logic/CMakeLists.txt b/Logic/CMakeLists.txt index 3ef3a18..113e7a9 100644 --- a/Logic/CMakeLists.txt +++ b/Logic/CMakeLists.txt @@ -5,6 +5,8 @@ set(KIT ${PROJECT_NAME}) set(${KIT}_EXPORT_DIRECTIVE "VTK_SLICER_${MODULE_NAME_UPPER}_MODULE_LOGIC_EXPORT") set(${KIT}_INCLUDE_DIRECTORIES + ${vtkSlicer${MODULE_NAME}ModuleUtilities_SOURCE_DIR} + ${vtkSlicer${MODULE_NAME}ModuleUtilities_BINARY_DIR} ) set(${KIT}_SRCS diff --git a/Logic/vtkSlicerLinearObjectRegistrationLogic.cxx b/Logic/vtkSlicerLinearObjectRegistrationLogic.cxx index c728aef..ae41826 100644 --- a/Logic/vtkSlicerLinearObjectRegistrationLogic.cxx +++ b/Logic/vtkSlicerLinearObjectRegistrationLogic.cxx @@ -2,13 +2,6 @@ // LinearObjectRegistration Logic includes #include "vtkSlicerLinearObjectRegistrationLogic.h" -const double FILTER_WIDTH = 5.0; -const double EXTRACTION_THRESHOLD = 0.5; -const double MATCHING_THRESHOLD = 10.0; - -const int MINIMUM_COLLECTION_FRAMES = 100; -const int DIRECTION_SCALE = 100; - void PrintToFile( std::string str ) { @@ -29,9 +22,6 @@ vtkStandardNewMacro( vtkSlicerLinearObjectRegistrationLogic ); vtkSlicerLinearObjectRegistrationLogic ::vtkSlicerLinearObjectRegistrationLogic() { - this->ObservedTransformNode = NULL; - this->ActivePositionBuffer = vtkSmartPointer< vtkMRMLLORPositionBufferNode >::New(); - this->OutputMessage = ""; } @@ -143,25 +133,6 @@ ::SetOutputMessage( std::string newOutputMessage ) } -void vtkSlicerLinearObjectRegistrationLogic -::ObserveTransformNode( vtkMRMLNode* node ) -{ - vtkMRMLLinearTransformNode* transformNode = vtkMRMLLinearTransformNode::SafeDownCast( node ); - if ( transformNode == NULL ) - { - return; - } - if ( this->ObservedTransformNode != NULL ) - { - this->ObservedTransformNode->RemoveObservers( vtkMRMLLinearTransformNode::TransformModifiedEvent, (vtkCommand*) this->GetMRMLNodesCallbackCommand() ); - } - - transformNode->AddObserver( vtkMRMLLinearTransformNode::TransformModifiedEvent, (vtkCommand*) this->GetMRMLNodesCallbackCommand() ); - - this->ObservedTransformNode = transformNode; -} - - // Let the selection node singleton keep track of this - we will just offer convenience functions void vtkSlicerLinearObjectRegistrationLogic ::SetActiveCollectionNode( vtkMRMLLORLinearObjectCollectionNode* newActiveCollectionNode ) @@ -192,72 +163,6 @@ ::GetActiveCollectionNode() } - -// This makes the module ready to record - see the ProcessMRMLNodesEvents for this class to see whether or not any recording actually happens -void vtkSlicerLinearObjectRegistrationLogic -::InitializeActivePositionBuffer( std::string collectType ) -{ - this->ActivePositionBuffer->Clear(); - this->CollectType = collectType; -} - - -void vtkSlicerLinearObjectRegistrationLogic -::FinalizeActivePositionBuffer() -{ - if ( this->ActivePositionBuffer == NULL ) - { - return; - } - - vtkSmartPointer< vtkMRMLLORLinearObjectNode > currentLinearObject; - - if ( this->CollectType.compare( "Reference" ) == 0 ) - { - currentLinearObject = this->PositionBufferToLinearObject( this->ActivePositionBuffer, REFERENCE_DOF ); - } - else if ( this->CollectType.compare( "Point" ) == 0 ) - { - currentLinearObject = this->PositionBufferToLinearObject( this->ActivePositionBuffer, POINT_DOF ); - } - else if ( this->CollectType.compare( "Line" ) == 0 ) - { - currentLinearObject = this->PositionBufferToLinearObject( this->ActivePositionBuffer, LINE_DOF ); - } - else if ( this->CollectType.compare( "Plane" ) == 0 ) - { - currentLinearObject = this->PositionBufferToLinearObject( this->ActivePositionBuffer, PLANE_DOF ); - } - else - { - currentLinearObject = this->PositionBufferToLinearObject( this->ActivePositionBuffer, UNKNOWN_DOF ); - } - - if ( currentLinearObject == NULL ) - { - this->ActivePositionBuffer->Clear(); - return; - } - - currentLinearObject->SetPositionBuffer( this->ActivePositionBuffer->DeepCopy() ); - this->InsertNewLinearObject( currentLinearObject ); - this->ActivePositionBuffer->Clear(); -} - - -void vtkSlicerLinearObjectRegistrationLogic -::InsertNewLinearObject( vtkMRMLLORLinearObjectNode* linearObject ) -{ - if ( this->GetActiveCollectionNode() == NULL ) - { - return; - } - - this->GetActiveCollectionNode()->AddLinearObject( linearObject ); - // TODO: Need to insert the current linear object into the correct slot in the collection -} - - // Return smart pointer since we created the object in this function vtkSmartPointer< vtkMRMLLORLinearObjectNode > vtkSlicerLinearObjectRegistrationLogic ::PositionBufferToLinearObject( vtkMRMLLORPositionBufferNode* positionBuffer, int dof ) @@ -293,23 +198,33 @@ ::PositionBufferToLinearObject( vtkMRMLLORPositionBufferNode* positionBuffer, in Eigenvector3.at(1) = eigenvectors.get( 1, 2 ); Eigenvector3.at(2) = eigenvectors.get( 2, 2 ); + // Get number of eigenvectors with eigenvalues larger than the threshold + double calculatedDOF = 0; + for ( int i = 0; i < vtkMRMLLORPositionNode::SIZE; i++ ) + { + if ( abs( eigenvalues.get( i ) ) > vtkMRMLLORConstants::NOISE_THRESHOLD ) + { + calculatedDOF++; + } + } + // The threshold noise is twice the extraction threshold - if ( dof == REFERENCE_DOF ) + if ( dof == vtkMRMLLORConstants::REFERENCE_DOF ) { vtkMRMLLORReferenceNode* referenceObject = vtkMRMLLORReferenceNode::New( centroid ); return vtkSmartPointer< vtkMRMLLORReferenceNode >::Take( referenceObject ); } - if ( dof == POINT_DOF ) + if ( dof == vtkMRMLLORConstants::POINT_DOF || dof == vtkMRMLLORConstants::UNKNOWN_DOF && calculatedDOF == vtkMRMLLORConstants::POINT_DOF ) { vtkMRMLLORPointNode* pointObject = vtkMRMLLORPointNode::New( centroid ); return vtkSmartPointer< vtkMRMLLORPointNode >::Take( pointObject ); } - if ( dof == LINE_DOF ) + if ( dof == vtkMRMLLORConstants::LINE_DOF || dof == vtkMRMLLORConstants::UNKNOWN_DOF && calculatedDOF == vtkMRMLLORConstants::LINE_DOF ) { vtkMRMLLORLineNode* lineObject = vtkMRMLLORLineNode::New( centroid, vtkMRMLLORVectorMath::Add( centroid, Eigenvector3 ) ); return vtkSmartPointer< vtkMRMLLORLineNode >::Take( lineObject ); } - if ( dof == PLANE_DOF ) + if ( dof == vtkMRMLLORConstants::PLANE_DOF || dof == vtkMRMLLORConstants::UNKNOWN_DOF && calculatedDOF >= vtkMRMLLORConstants::PLANE_DOF ) { vtkMRMLLORPlaneNode* planeObject = vtkMRMLLORPlaneNode::New( centroid, vtkMRMLLORVectorMath::Add( centroid, Eigenvector2 ), vtkMRMLLORVectorMath::Add( centroid, Eigenvector3 ) ); return vtkSmartPointer< vtkMRMLLORPlaneNode >::Take( planeObject ); @@ -380,7 +295,7 @@ ::MatchCollections( vtkMRMLLORLinearObjectCollectionNode* collection0, vtkMRMLLO } }// for over collection 1 - if ( bestDistance < MATCHING_THRESHOLD ) + if ( bestDistance < vtkMRMLLORConstants::MATCHING_THRESHOLD ) { matchedCollection0->AddLinearObject( currentObject0 ); matchedCollection1->AddLinearObject( nonReferenceCollection1->GetLinearObject( bestIndex ) ); @@ -725,11 +640,11 @@ ::CalculateTransform( vtkMRMLNode* node ) vtkMRMLLORLineNode* CurrentToObject = vtkMRMLLORLineNode::SafeDownCast( toLineCollection->GetLinearObject(i) ); // Add direction vector to projection of origin - testVector = vtkMRMLLORVectorMath::Add( CurrentToObject->ProjectVector( BlankVector ), vtkMRMLLORVectorMath::Multiply( DIRECTION_SCALE, CurrentToObject->GetDirection() ) ); + testVector = vtkMRMLLORVectorMath::Add( CurrentToObject->ProjectVector( BlankVector ), vtkMRMLLORVectorMath::Multiply( vtkMRMLLORConstants::DIRECTION_SCALE, CurrentToObject->GetDirection() ) ); TempToCollection->AddLinearObject( vtkMRMLLORPointNode::New( testVector ) ) ; // Subtract direction vector to projection of origin - testVector = vtkMRMLLORVectorMath::Subtract( CurrentToObject->ProjectVector( BlankVector ), vtkMRMLLORVectorMath::Multiply( DIRECTION_SCALE, CurrentToObject->GetDirection() ) ); + testVector = vtkMRMLLORVectorMath::Subtract( CurrentToObject->ProjectVector( BlankVector ), vtkMRMLLORVectorMath::Multiply( vtkMRMLLORConstants::DIRECTION_SCALE, CurrentToObject->GetDirection() ) ); TempToCollection->AddLinearObject( vtkMRMLLORPointNode::New( testVector ) ); TempToCollection->Concatenate( toReferenceCollection ); @@ -738,7 +653,7 @@ ::CalculateTransform( vtkMRMLNode* node ) vtkMRMLLORLineNode* CurrentFromObject = vtkMRMLLORLineNode::SafeDownCast( fromLineCollection->GetLinearObject(i) ); // Add direction vector to projection of origin - testVector = vtkMRMLLORVectorMath::Add( CurrentFromObject->ProjectVector( BlankVector ), vtkMRMLLORVectorMath::Multiply( DIRECTION_SCALE, CurrentFromObject->GetDirection() ) ); + testVector = vtkMRMLLORVectorMath::Add( CurrentFromObject->ProjectVector( BlankVector ), vtkMRMLLORVectorMath::Multiply( vtkMRMLLORConstants::DIRECTION_SCALE, CurrentFromObject->GetDirection() ) ); TempFromCollection->AddLinearObject( vtkMRMLLORPointNode::New( testVector ) ); TempFromCollection->Concatenate( fromReferenceCollection ); @@ -767,11 +682,11 @@ ::CalculateTransform( vtkMRMLNode* node ) vtkMRMLLORPlaneNode* CurrentToObject = vtkMRMLLORPlaneNode::SafeDownCast( toPlaneCollection->GetLinearObject(i) ); // Add direction vector to projection of origin - testVector = vtkMRMLLORVectorMath::Add( CurrentToObject->ProjectVector( BlankVector ), vtkMRMLLORVectorMath::Multiply( DIRECTION_SCALE, CurrentToObject->GetNormal() ) ); + testVector = vtkMRMLLORVectorMath::Add( CurrentToObject->ProjectVector( BlankVector ), vtkMRMLLORVectorMath::Multiply( vtkMRMLLORConstants::DIRECTION_SCALE, CurrentToObject->GetNormal() ) ); TempToCollection->AddLinearObject( vtkMRMLLORPointNode::New( testVector ) ); // Subtract direction vector to projection of origin - testVector = vtkMRMLLORVectorMath::Subtract( CurrentToObject->ProjectVector( BlankVector ), vtkMRMLLORVectorMath::Multiply( DIRECTION_SCALE, CurrentToObject->GetNormal() ) ); + testVector = vtkMRMLLORVectorMath::Subtract( CurrentToObject->ProjectVector( BlankVector ), vtkMRMLLORVectorMath::Multiply( vtkMRMLLORConstants::DIRECTION_SCALE, CurrentToObject->GetNormal() ) ); TempToCollection->AddLinearObject( vtkMRMLLORPointNode::New( testVector ) ); TempToCollection->Concatenate( toReferenceCollection ); @@ -780,7 +695,7 @@ ::CalculateTransform( vtkMRMLNode* node ) vtkMRMLLORPlaneNode* CurrentFromObject = vtkMRMLLORPlaneNode::SafeDownCast( fromPlaneCollection->GetLinearObject(i) ); // Add direction vector to projection of origin - testVector = vtkMRMLLORVectorMath::Add( CurrentFromObject->ProjectVector( BlankVector ), vtkMRMLLORVectorMath::Multiply( DIRECTION_SCALE, CurrentFromObject->GetNormal() ) ); + testVector = vtkMRMLLORVectorMath::Add( CurrentFromObject->ProjectVector( BlankVector ), vtkMRMLLORVectorMath::Multiply( vtkMRMLLORConstants::DIRECTION_SCALE, CurrentFromObject->GetNormal() ) ); TempFromCollection->AddLinearObject( vtkMRMLLORPointNode::New( testVector ) ); TempFromCollection->Concatenate( fromReferenceCollection ); @@ -1185,24 +1100,54 @@ ::ProcessMRMLNodesEvents( vtkObject* caller, unsigned long event, void* callData { // In case the module node is updated vtkMRMLLinearObjectRegistrationNode* lorNode = vtkMRMLLinearObjectRegistrationNode::SafeDownCast( caller ); + // The caller must be a vtkMRMLLinearObjectRegistrationNode - if ( lorNode != NULL ) + if ( lorNode != NULL && event == vtkCommand::ModifiedEvent ) { this->CalculateTransform( lorNode ); // Will create modified event to update widget } - // In case the observed transform node is updated - vtkMRMLLinearTransformNode* transformNode = vtkMRMLLinearTransformNode::SafeDownCast( caller ); - // Must be a transform node - if ( transformNode == NULL || this->ActivePositionBuffer == NULL ) + // The position buffer must be ready for conversion to linear object + if ( lorNode != NULL && event == vtkMRMLLinearObjectRegistrationNode::PositionBufferReady ) { - return; - } - if ( strcmp( transformNode->GetID(), this->ObservedTransformNode->GetID() ) == 0 ) - { - vtkMatrix4x4* matrix = transformNode->GetMatrixTransformToParent(); - this->ActivePositionBuffer->AddPosition( vtkMRMLLORPositionNode::New( matrix ) ); + vtkSmartPointer< vtkMRMLLORLinearObjectNode > currentLinearObject = NULL; + vtkSmartPointer< vtkMRMLLORPositionBufferNode > positionBufferCopy = lorNode->GetActivePositionBuffer()->DeepCopy(); + lorNode->GetActivePositionBuffer()->Clear(); + + if ( lorNode->GetCollectionState().compare( "Reference" ) == 0 ) + { + currentLinearObject = this->PositionBufferToLinearObject( positionBufferCopy, vtkMRMLLORConstants::REFERENCE_DOF ); + } + if ( lorNode->GetCollectionState().compare( "Point" ) == 0 ) + { + currentLinearObject = this->PositionBufferToLinearObject( positionBufferCopy, vtkMRMLLORConstants::POINT_DOF ); + } + if ( lorNode->GetCollectionState().compare( "Line" ) == 0 ) + { + currentLinearObject = this->PositionBufferToLinearObject( positionBufferCopy, vtkMRMLLORConstants::LINE_DOF ); + } + if ( lorNode->GetCollectionState().compare( "Plane" ) == 0 ) + { + currentLinearObject = this->PositionBufferToLinearObject( positionBufferCopy, vtkMRMLLORConstants::PLANE_DOF ); + } + if ( lorNode->GetCollectionState().compare( "Collect" ) == 0 ) + { + currentLinearObject = this->PositionBufferToLinearObject( positionBufferCopy, vtkMRMLLORConstants::UNKNOWN_DOF ); + } + if ( lorNode->GetCollectionState().compare( "Automatic" ) == 0 ) + { + positionBufferCopy->Trim( vtkMRMLLORConstants::TRIM_POSITIONS ); + currentLinearObject = this->PositionBufferToLinearObject( positionBufferCopy, vtkMRMLLORConstants::UNKNOWN_DOF ); + } + + if ( currentLinearObject != NULL && this->GetActiveCollectionNode() != NULL ) + { + currentLinearObject->SetPositionBuffer( positionBufferCopy ); + this->GetActiveCollectionNode()->AddLinearObject( currentLinearObject ); + } + } + } @@ -1219,6 +1164,7 @@ ::ProcessMRMLSceneEvents( vtkObject* caller, unsigned long event, void* callData { // This will get called exactly once, and we will add the observer only once (since node is never replaced) linearObjectRegistrationNode->AddObserver( vtkCommand::ModifiedEvent, ( vtkCommand* ) this->GetMRMLNodesCallbackCommand() ); + linearObjectRegistrationNode->AddObserver( vtkMRMLLinearObjectRegistrationNode::PositionBufferReady, ( vtkCommand* ) this->GetMRMLNodesCallbackCommand() ); linearObjectRegistrationNode->UpdateScene( this->GetMRMLScene() ); linearObjectRegistrationNode->ObserveAllReferenceNodes(); // This will update this->CalculateTransform( linearObjectRegistrationNode ); // Will create modified event to update widget diff --git a/Logic/vtkSlicerLinearObjectRegistrationLogic.h b/Logic/vtkSlicerLinearObjectRegistrationLogic.h index 1a93ea9..d06f8a4 100644 --- a/Logic/vtkSlicerLinearObjectRegistrationLogic.h +++ b/Logic/vtkSlicerLinearObjectRegistrationLogic.h @@ -32,6 +32,7 @@ #include "vnl/vnl_matrix.h" // Slicer includes +#include "vtkCommand.h" #include "vtkSlicerModuleLogic.h" #include "vtkMRMLLinearTransformNode.h" #include "vtkMRMLModelNode.h" @@ -94,13 +95,6 @@ vtkSlicerLinearObjectRegistrationLogic : public vtkSlicerModuleLogic public: - static const int REFERENCE_DOF = 4; // This obviously isn't true, but we need to distinguish from points - static const int POINT_DOF = 0; - static const int LINE_DOF = 1; - static const int PLANE_DOF = 2; - static const int UNKNOWN_DOF = -1; - - void CalculateTransform( vtkMRMLNode* node ); void UpdateOutputTransform( vtkMRMLLinearTransformNode* outputTransform, vtkMatrix4x4* newTransformMatrix ); @@ -125,16 +119,9 @@ vtkSlicerLinearObjectRegistrationLogic : public vtkSlicerModuleLogic vtkSmartPointer< vtkMRMLLORLinearObjectNode > PositionBufferToLinearObject( vtkMRMLLORPositionBufferNode* positionBuffer, int dof = -1 ); - void ObserveTransformNode( vtkMRMLNode* node ); - vtkMRMLLORLinearObjectCollectionNode* GetActiveCollectionNode(); void SetActiveCollectionNode( vtkMRMLLORLinearObjectCollectionNode* newActiveCollectionNode ); - void FinalizeActivePositionBuffer(); - void InitializeActivePositionBuffer( std::string collectType ); - - void InsertNewLinearObject( vtkMRMLLORLinearObjectNode* linearObject ); - void MatchCollections( vtkMRMLLORLinearObjectCollectionNode* collection0, vtkMRMLLORLinearObjectCollectionNode* collection1, bool removeUnmatched = false ); vtkSmartPointer< vtkMRMLLORLinearObjectCollectionNode > GetReferences( vtkMRMLLORLinearObjectCollectionNode* collection ); vtkSmartPointer< vtkMRMLLORLinearObjectCollectionNode > GetNonReferences( vtkMRMLLORLinearObjectCollectionNode* collection ); @@ -147,12 +134,7 @@ vtkSlicerLinearObjectRegistrationLogic : public vtkSlicerModuleLogic private: - vtkMRMLLinearTransformNode* ObservedTransformNode; - vtkSmartPointer< vtkMRMLLORPositionBufferNode > ActivePositionBuffer; - std::string CollectType; - std::string OutputMessage; - }; #endif diff --git a/MRML/CMakeLists.txt b/MRML/CMakeLists.txt index ad54828..f80562a 100644 --- a/MRML/CMakeLists.txt +++ b/MRML/CMakeLists.txt @@ -5,7 +5,8 @@ set(KIT ${PROJECT_NAME}) set(${KIT}_EXPORT_DIRECTIVE "VTK_SLICER_${MODULE_NAME_UPPER}_MODULE_MRML_EXPORT") set(${KIT}_INCLUDE_DIRECTORIES - ${Slicer_Base_INCLUDE_DIRS} + ${vtkSlicer${MODULE_NAME}ModuleUtilities_SOURCE_DIR} + ${vtkSlicer${MODULE_NAME}ModuleUtilities_BINARY_DIR} ) # -------------------------------------------------------------------------- @@ -14,8 +15,6 @@ set(${KIT}_INCLUDE_DIRECTORIES set(${KIT}_SRCS vtkMRMLLinearObjectRegistrationNode.cxx vtkMRMLLinearObjectRegistrationNode.h - vtkMRMLLORVectorMath.cxx - vtkMRMLLORVectorMath.h vtkMRMLLORReferenceNode.cxx vtkMRMLLORReferenceNode.h vtkMRMLLORPositionBufferNode.cxx @@ -42,6 +41,7 @@ SET (${KIT}_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL "" FORCE) # Build the library set(${KIT}_TARGET_LIBRARIES + vtkSlicer${MODULE_NAME}ModuleUtilities ${ITK_LIBRARIES} ${MRML_LIBRARIES} SlicerBaseLogic diff --git a/MRML/vtkMRMLLORPositionBufferNode.cxx b/MRML/vtkMRMLLORPositionBufferNode.cxx index 1a99c81..45b6137 100644 --- a/MRML/vtkMRMLLORPositionBufferNode.cxx +++ b/MRML/vtkMRMLLORPositionBufferNode.cxx @@ -62,6 +62,24 @@ ::Clear() } +void vtkMRMLLORPositionBufferNode +::Trim( int trimSize ) +{ + std::vector< vtkSmartPointer< vtkMRMLLORPositionNode > > newPositions; + + for ( int i = 0; i < this->Size(); i++ ) + { + if ( i - trimSize >= 0 && i + trimSize < this->Size() ) + { + newPositions.push_back( this->GetPosition( i ) ); + } + } + + this->Positions = newPositions; + this->Modified(); +} + + void vtkMRMLLORPositionBufferNode ::Translate( std::vector translation ) { @@ -168,4 +186,30 @@ ::CalculateCentroid() } return centroid; +} + + +int vtkMRMLLORPositionBufferNode +::GetDOF() +{ + std::vector centroid = this->CalculateCentroid(); + vnl_matrix* cov = this->CovarianceMatrix( centroid ); + + //Calculate the eigenvectors of the covariance matrix + vnl_matrix eigenvectors( vtkMRMLLORPositionNode::SIZE, vtkMRMLLORPositionNode::SIZE, 0.0 ); + vnl_vector eigenvalues( vtkMRMLLORPositionNode::SIZE, 0.0 ); + vnl_symmetric_eigensystem_compute( *cov, eigenvectors, eigenvalues ); + // Note: eigenvectors are ordered in increasing eigenvalue ( 0 = smallest, end = biggest ) + + // Get number of eigenvectors with eigenvalues larger than the threshold + int calculatedDOF = 0; + for ( int i = 0; i < vtkMRMLLORPositionNode::SIZE; i++ ) + { + if ( abs( eigenvalues.get( i ) ) > vtkMRMLLORConstants::NOISE_THRESHOLD ) + { + calculatedDOF++; + } + } + + return calculatedDOF; } \ No newline at end of file diff --git a/MRML/vtkMRMLLORPositionBufferNode.h b/MRML/vtkMRMLLORPositionBufferNode.h index cdf1d9d..12d8acb 100644 --- a/MRML/vtkMRMLLORPositionBufferNode.h +++ b/MRML/vtkMRMLLORPositionBufferNode.h @@ -47,11 +47,13 @@ vtkMRMLLORPositionBufferNode : public vtkObject vtkMRMLLORPositionNode* GetPosition( int index ); void AddPosition( vtkMRMLLORPositionNode* newPosition ); void Clear(); + void Trim( int trimSize ); void Translate( std::vector translation ); std::vector CalculateCentroid(); vnl_matrix* CovarianceMatrix( std::vector centroid ); + int GetDOF(); std::string ToXMLString(); void FromXMLElement( vtkXMLDataElement* element ); diff --git a/MRML/vtkMRMLLORPositionNode.h b/MRML/vtkMRMLLORPositionNode.h index 854d395..4ac2004 100644 --- a/MRML/vtkMRMLLORPositionNode.h +++ b/MRML/vtkMRMLLORPositionNode.h @@ -16,12 +16,12 @@ #include "vtkMatrix4x4.h" #include "vtkSmartPointer.h" -// VNL includes -#include "vnl/vnl_matrix.h" - // LinearObjectRegistration includes #include "vtkMRMLLORVectorMath.h" +// VNL includes +#include "vnl/vnl_matrix.h" + #include "vtkSlicerLinearObjectRegistrationModuleMRMLExport.h" diff --git a/MRML/vtkMRMLLORVectorMath.h b/MRML/vtkMRMLLORVectorMath.h deleted file mode 100644 index 95a10f8..0000000 --- a/MRML/vtkMRMLLORVectorMath.h +++ /dev/null @@ -1,34 +0,0 @@ - -#ifndef __vtkMRMLLORVectorMath_h -#define __vtkMRMLLORVectorMath_h - -// Standard includes -#include -#include -#include -#include - -#include "vtkSlicerLinearObjectRegistrationModuleMRMLExport.h" - -namespace vtkMRMLLORVectorMath -{ - - // Note: Do not remove any VTK_SLICER_LINEAROBJECTREGISTRATION_MODULE_MRML_EXPORT - it exports these functions so they are usable by the logic - VTK_SLICER_LINEAROBJECTREGISTRATION_MODULE_MRML_EXPORT std::vector Abs( std::vector vector ); - VTK_SLICER_LINEAROBJECTREGISTRATION_MODULE_MRML_EXPORT std::vector Normalize( std::vector vector ); - - VTK_SLICER_LINEAROBJECTREGISTRATION_MODULE_MRML_EXPORT double Distance( std::vector v1, std::vector v2 ); - VTK_SLICER_LINEAROBJECTREGISTRATION_MODULE_MRML_EXPORT double Norm( std::vector vector ); - VTK_SLICER_LINEAROBJECTREGISTRATION_MODULE_MRML_EXPORT double Dot( std::vector v1, std::vector v2 ); - VTK_SLICER_LINEAROBJECTREGISTRATION_MODULE_MRML_EXPORT std::vector Cross( std::vector v1, std::vector v2 ); - - VTK_SLICER_LINEAROBJECTREGISTRATION_MODULE_MRML_EXPORT std::vector Add( std::vector v1, std::vector v2 ); - VTK_SLICER_LINEAROBJECTREGISTRATION_MODULE_MRML_EXPORT std::vector Subtract( std::vector v1, std::vector v2 ); - VTK_SLICER_LINEAROBJECTREGISTRATION_MODULE_MRML_EXPORT std::vector Multiply( double c, std::vector vector ); - - VTK_SLICER_LINEAROBJECTREGISTRATION_MODULE_MRML_EXPORT std::string VectorToString( std::vector vector ); - VTK_SLICER_LINEAROBJECTREGISTRATION_MODULE_MRML_EXPORT std::vector StringToVector( std::string s, int size ); - -} - -#endif \ No newline at end of file diff --git a/MRML/vtkMRMLLinearObjectRegistrationNode.cxx b/MRML/vtkMRMLLinearObjectRegistrationNode.cxx index ee061b2..fe6dadc 100644 --- a/MRML/vtkMRMLLinearObjectRegistrationNode.cxx +++ b/MRML/vtkMRMLLinearObjectRegistrationNode.cxx @@ -62,9 +62,13 @@ ::vtkMRMLLinearObjectRegistrationNode() this->AddNodeReferenceRole( FROM_COLLECTION_REFERENCE_ROLE ); this->AddNodeReferenceRole( TO_COLLECTION_REFERENCE_ROLE ); this->AddNodeReferenceRole( OUTPUT_TRANSFORM_REFERENCE_ROLE ); + this->CollectionMode = "ManualDOF"; this->AutomaticMatch = "True"; + this->CollectionState = ""; + this->ActivePositionBuffer = vtkSmartPointer< vtkMRMLLORPositionBufferNode >::New(); + this->Modified(); } @@ -191,15 +195,13 @@ ::GetCollectTransformID() void vtkMRMLLinearObjectRegistrationNode ::SetCollectTransformID( std::string newCollectTransformID, int modifyType ) { - if ( newCollectTransformID.compare( "" ) == 0 ) - { - this->RemoveAllNodeReferenceIDs( COLLECT_TRANSFORM_REFERENCE_ROLE ); - } - else if ( this->GetCollectTransformID() != newCollectTransformID ) + if ( this->GetCollectTransformID().compare( newCollectTransformID ) != 0 ) { - this->SetNodeReferenceID( COLLECT_TRANSFORM_REFERENCE_ROLE, newCollectTransformID.c_str() ); + vtkNew events; + events->InsertNextValue( vtkMRMLLinearTransformNode::TransformModifiedEvent ); + this->SetAndObserveNodeReferenceID( COLLECT_TRANSFORM_REFERENCE_ROLE, newCollectTransformID.c_str(), events.GetPointer() ); } - if ( this->GetCollectTransformID() != newCollectTransformID && modifyType == DefaultModify || modifyType == AlwaysModify ) + if ( this->GetCollectTransformID().compare( newCollectTransformID ) != 0 && modifyType == DefaultModify || modifyType == AlwaysModify ) { this->Modified(); } @@ -216,11 +218,11 @@ ::GetFromCollectionID() void vtkMRMLLinearObjectRegistrationNode ::SetFromCollectionID( std::string newFromCollectionID, int modifyType ) { - if ( this->GetFromCollectionID() != newFromCollectionID ) + if ( this->GetFromCollectionID().compare( newFromCollectionID ) != 0 ) { this->SetAndObserveNodeReferenceID( FROM_COLLECTION_REFERENCE_ROLE, newFromCollectionID.c_str() ); } - if ( this->GetFromCollectionID() != newFromCollectionID && modifyType == DefaultModify || modifyType == AlwaysModify ) + if ( this->GetFromCollectionID().compare( newFromCollectionID ) != 0 && modifyType == DefaultModify || modifyType == AlwaysModify ) { this->Modified(); } @@ -237,11 +239,11 @@ ::GetToCollectionID() void vtkMRMLLinearObjectRegistrationNode ::SetToCollectionID( std::string newToCollectionID, int modifyType ) { - if ( this->GetToCollectionID() != newToCollectionID ) + if ( this->GetToCollectionID().compare( newToCollectionID ) != 0 ) { this->SetAndObserveNodeReferenceID( TO_COLLECTION_REFERENCE_ROLE, newToCollectionID.c_str() ); } - if ( this->GetToCollectionID() != newToCollectionID && modifyType == DefaultModify || modifyType == AlwaysModify ) + if ( this->GetToCollectionID().compare( newToCollectionID ) != 0 && modifyType == DefaultModify || modifyType == AlwaysModify ) { this->Modified(); } @@ -262,11 +264,11 @@ ::SetOutputTransformID( std::string newOutputTransformID, int modifyType ) { this->RemoveAllNodeReferenceIDs( OUTPUT_TRANSFORM_REFERENCE_ROLE ); } - else if ( this->GetOutputTransformID() != newOutputTransformID ) + else if ( this->GetOutputTransformID().compare( newOutputTransformID ) != 0 ) { this->SetNodeReferenceID( OUTPUT_TRANSFORM_REFERENCE_ROLE, newOutputTransformID.c_str() ); } - if ( this->GetOutputTransformID() != newOutputTransformID && modifyType == DefaultModify || modifyType == AlwaysModify ) + if ( this->GetOutputTransformID().compare( newOutputTransformID ) != 0 && modifyType == DefaultModify || modifyType == AlwaysModify ) { this->Modified(); } @@ -283,11 +285,11 @@ ::GetCollectionMode() void vtkMRMLLinearObjectRegistrationNode ::SetCollectionMode( std::string newCollectionMode, int modifyType ) { - if ( this->GetCollectionMode() != newCollectionMode ) + if ( this->GetCollectionMode().compare( newCollectionMode ) != 0 ) { this->CollectionMode = newCollectionMode; } - if ( this->GetCollectionMode() != newCollectionMode && modifyType == DefaultModify || modifyType == AlwaysModify ) + if ( this->GetCollectionMode().compare( newCollectionMode ) != 0 && modifyType == DefaultModify || modifyType == AlwaysModify ) { this->Modified(); } @@ -304,11 +306,11 @@ ::GetAutomaticMatch() void vtkMRMLLinearObjectRegistrationNode ::SetAutomaticMatch( std::string newAutomaticMatch, int modifyType ) { - if ( this->GetAutomaticMatch() != newAutomaticMatch ) + if ( this->GetAutomaticMatch().compare( newAutomaticMatch ) != 0 ) { this->AutomaticMatch = newAutomaticMatch; } - if ( this->GetAutomaticMatch() != newAutomaticMatch && modifyType == DefaultModify || modifyType == AlwaysModify ) + if ( this->GetAutomaticMatch().compare( newAutomaticMatch ) != 0 && modifyType == DefaultModify || modifyType == AlwaysModify ) { this->Modified(); } @@ -334,8 +336,94 @@ ::GetNodeReferenceIDString( std::string referenceRole ) } +// These methods are related to collecting data +// ---------------------------------------------------------------------------------------------------------- + + +vtkMRMLLORPositionBufferNode* vtkMRMLLinearObjectRegistrationNode +::GetActivePositionBuffer() +{ + return this->ActivePositionBuffer; +} + + +std::string vtkMRMLLinearObjectRegistrationNode +::GetCollectionState() +{ + return this->CollectionState; +} + + + +void vtkMRMLLinearObjectRegistrationNode +::StartCollecting( std::string newCollectionState ) +{ + this->GetActivePositionBuffer()->Clear(); + + // Don't collect if the collect transform is not specified + if ( this->GetNodeReferenceIDString( COLLECT_TRANSFORM_REFERENCE_ROLE ).compare( "" ) != 0 ) + { + this->CollectionState = newCollectionState; + } +} + + +void vtkMRMLLinearObjectRegistrationNode +::StopCollecting() +{ + // Emit an event indicating that the position buffer is ready to be converted to a linear object + if ( this->CollectionState.compare( "Automatic" ) != 0 || this->GetActivePositionBuffer()->Size() > vtkMRMLLORConstants::MINIMUM_COLLECTION_POSITIONS ) + { + this->InvokeEvent( PositionBufferReady ); + } + + this->GetActivePositionBuffer()->Clear(); // TODO: Should the clearing be done in the logic which catches the event + this->CollectionState = ""; +} + + void vtkMRMLLinearObjectRegistrationNode ::ProcessMRMLEvents( vtkObject *caller, unsigned long event, void *callData ) { - this->Modified(); // This will tell the logic to update -} \ No newline at end of file + // In case the observed transform node is updated + vtkMRMLLinearTransformNode* transformNode = vtkMRMLLinearTransformNode::SafeDownCast( caller ); + + // If it wasn't the observed transform + if ( transformNode == NULL || this->GetNodeReferenceIDString( COLLECT_TRANSFORM_REFERENCE_ROLE ).compare( transformNode->GetID() ) != 0 || event != vtkMRMLLinearTransformNode::TransformModifiedEvent ) + { + this->Modified(); // Recalculate the transform + return; + } + if ( this->CollectionState.compare( "" ) == 0 ) + { + return; + } + + vtkMRMLLORPositionNode* tempPosition = vtkMRMLLORPositionNode::New( transformNode->GetMatrixTransformToParent() ); + vtkSmartPointer< vtkMRMLLORPositionNode > newPosition = vtkSmartPointer< vtkMRMLLORPositionNode >::Take( tempPosition ); + + this->ActivePositionBuffer->AddPosition( newPosition ); + + if ( this->CollectionState.compare( "Automatic" ) != 0 ) + { + return; + } + + // Check if the position buffer is still linear + int positionBufferDOF = this->GetActivePositionBuffer()->GetDOF(); + + // If it is, then keep going + if ( positionBufferDOF <= vtkMRMLLORConstants::PLANE_DOF ) + { + return; + } + + // If it is not, then emit a ready event if we have the required number of collected frames + if ( this->GetActivePositionBuffer()->Size() > vtkMRMLLORConstants::MINIMUM_COLLECTION_POSITIONS ) + { + this->InvokeEvent( PositionBufferReady ); + this->Modified(); // TODO: For some reason, the collection node modified event is never caught when it is called from the processmrmlevents method + } + this->GetActivePositionBuffer()->Clear(); // TODO: Should the clearing be done in the logic which catches the event + +} diff --git a/MRML/vtkMRMLLinearObjectRegistrationNode.h b/MRML/vtkMRMLLinearObjectRegistrationNode.h index 82b86b4..87aeffd 100644 --- a/MRML/vtkMRMLLinearObjectRegistrationNode.h +++ b/MRML/vtkMRMLLinearObjectRegistrationNode.h @@ -22,10 +22,16 @@ #include "vtkMRMLNode.h" #include "vtkMRMLScene.h" +#include "vtkMRMLLinearTransformNode.h" +#include "vtkCommand.h" +#include "vtkNew.h" +#include "vtkIntArray.h" #include "vtkObject.h" #include "vtkObjectBase.h" #include "vtkObjectFactory.h" +#include "vtkMRMLLORPositionBufferNode.h" + // LinearObjectRegistration includes #include "vtkSlicerLinearObjectRegistrationModuleMRMLExport.h" @@ -66,6 +72,11 @@ vtkMRMLLinearObjectRegistrationNode AlwaysModify }; + enum PositionBufferEvent + { + PositionBufferReady = vtkCommand::UserEvent + 1 + }; + // Use default setters and getters - vtk set macro will cause modified event void SetCollectTransformID( std::string newCollectTransformID, int modifyType = DefaultModify ); void SetFromCollectionID( std::string newFromCollectionID, int modifyType = DefaultModify ); @@ -85,12 +96,22 @@ vtkMRMLLinearObjectRegistrationNode void ObserveAllReferenceNodes(); + std::string GetCollectionState(); + vtkMRMLLORPositionBufferNode* GetActivePositionBuffer(); + + void StartCollecting( std::string newCollectionState ); + void StopCollecting(); + void ProcessMRMLEvents( vtkObject *caller, unsigned long event, void *callData ); private: + std::string CollectionMode; std::string AutomaticMatch; + std::string CollectionState; + vtkSmartPointer< vtkMRMLLORPositionBufferNode > ActivePositionBuffer; + }; #endif diff --git a/Resources/UI/qSlicerLinearObjectRegistrationModule.ui b/Resources/UI/qSlicerLinearObjectRegistrationModule.ui index c3cd4ef..eaeae7f 100644 --- a/Resources/UI/qSlicerLinearObjectRegistrationModule.ui +++ b/Resources/UI/qSlicerLinearObjectRegistrationModule.ui @@ -90,7 +90,7 @@ Collect Linear Objects - true + false @@ -178,6 +178,21 @@ + + + + + 0 + 0 + + + + + vtkMRMLLinearTransformNode + + + + @@ -453,5 +468,21 @@ + + qSlicerLinearObjectRegistrationModule + mrmlSceneChanged(vtkMRMLScene*) + TransformNodeComboBox + setMRMLScene(vtkMRMLScene*) + + + 195 + 413 + + + 195 + 277 + + + diff --git a/Utilities/CMakeLists.txt b/Utilities/CMakeLists.txt new file mode 100644 index 0000000..499c2f4 --- /dev/null +++ b/Utilities/CMakeLists.txt @@ -0,0 +1,38 @@ +project(vtkSlicer${MODULE_NAME}ModuleUtilities) + +set(KIT ${PROJECT_NAME}) + +set(${KIT}_EXPORT_DIRECTIVE "VTK_SLICER_${MODULE_NAME_UPPER}_MODULE_UTILITIES_EXPORT") + +set(${KIT}_INCLUDE_DIRECTORIES + ${Slicer_Base_INCLUDE_DIRS} + ) + +# -------------------------------------------------------------------------- +# Sources + +set(${KIT}_SRCS + vtkMRMLLORVectorMath.cxx + vtkMRMLLORVectorMath.h + vtkMRMLLORConstants.cxx + vtkMRMLLORConstants.h + ) + +SET (${KIT}_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL "" FORCE) + +# -------------------------------------------------------------------------- +# Build the library + +set(${KIT}_TARGET_LIBRARIES + ${ITK_LIBRARIES} + ${MRML_LIBRARIES} + SlicerBaseLogic + ) + +SlicerMacroBuildModuleMRML( + NAME ${KIT} + EXPORT_DIRECTIVE ${${KIT}_EXPORT_DIRECTIVE} + INCLUDE_DIRECTORIES ${${KIT}_INCLUDE_DIRECTORIES} + SRCS ${${KIT}_SRCS} + TARGET_LIBRARIES ${${KIT}_TARGET_LIBRARIES} + ) \ No newline at end of file diff --git a/Utilities/vtkMRMLLORConstants.cxx b/Utilities/vtkMRMLLORConstants.cxx new file mode 100644 index 0000000..b543f86 --- /dev/null +++ b/Utilities/vtkMRMLLORConstants.cxx @@ -0,0 +1,15 @@ + +#include "vtkMRMLLORConstants.h" + +const int vtkMRMLLORConstants::REFERENCE_DOF = 4; // This obviously isn't true, but we need to distinguish from points +const int vtkMRMLLORConstants::POINT_DOF = 0; +const int vtkMRMLLORConstants::LINE_DOF = 1; +const int vtkMRMLLORConstants::PLANE_DOF = 2; +const int vtkMRMLLORConstants::UNKNOWN_DOF = -1; + +const int vtkMRMLLORConstants::MINIMUM_COLLECTION_POSITIONS = 100; +const int vtkMRMLLORConstants::TRIM_POSITIONS = 10; + +const double vtkMRMLLORConstants::NOISE_THRESHOLD = 0.5; +const double vtkMRMLLORConstants::MATCHING_THRESHOLD = 10.0; +const double vtkMRMLLORConstants::DIRECTION_SCALE = 100.0; \ No newline at end of file diff --git a/Utilities/vtkMRMLLORConstants.h b/Utilities/vtkMRMLLORConstants.h new file mode 100644 index 0000000..d67974d --- /dev/null +++ b/Utilities/vtkMRMLLORConstants.h @@ -0,0 +1,32 @@ + +#ifndef __vtkMRMLLORConstants_h +#define __vtkMRMLLORConstants_h + +// Standard includes +#include +#include +#include +#include + +#include "vtkSlicerLinearObjectRegistrationModuleUtilitiesExport.h" + +namespace vtkMRMLLORConstants +{ + + // Note: Do not remove any VTK_SLICER_LINEAROBJECTREGISTRATION_MODULE_MRML_EXPORT - it exports these functions so they are usable by the logic + // Also note: The "extern" qualifier is required so we can define the constants in the cxx + VTK_SLICER_LINEAROBJECTREGISTRATION_MODULE_UTILITIES_EXPORT extern const int REFERENCE_DOF; + VTK_SLICER_LINEAROBJECTREGISTRATION_MODULE_UTILITIES_EXPORT extern const int POINT_DOF; + VTK_SLICER_LINEAROBJECTREGISTRATION_MODULE_UTILITIES_EXPORT extern const int LINE_DOF; + VTK_SLICER_LINEAROBJECTREGISTRATION_MODULE_UTILITIES_EXPORT extern const int PLANE_DOF; + VTK_SLICER_LINEAROBJECTREGISTRATION_MODULE_UTILITIES_EXPORT extern const int UNKNOWN_DOF; + + VTK_SLICER_LINEAROBJECTREGISTRATION_MODULE_UTILITIES_EXPORT extern const int MINIMUM_COLLECTION_POSITIONS; + VTK_SLICER_LINEAROBJECTREGISTRATION_MODULE_UTILITIES_EXPORT extern const int TRIM_POSITIONS; + + VTK_SLICER_LINEAROBJECTREGISTRATION_MODULE_UTILITIES_EXPORT extern const double NOISE_THRESHOLD; + VTK_SLICER_LINEAROBJECTREGISTRATION_MODULE_UTILITIES_EXPORT extern const double MATCHING_THRESHOLD; + VTK_SLICER_LINEAROBJECTREGISTRATION_MODULE_UTILITIES_EXPORT extern const double DIRECTION_SCALE; +} + +#endif \ No newline at end of file diff --git a/MRML/vtkMRMLLORVectorMath.cxx b/Utilities/vtkMRMLLORVectorMath.cxx similarity index 100% rename from MRML/vtkMRMLLORVectorMath.cxx rename to Utilities/vtkMRMLLORVectorMath.cxx diff --git a/Utilities/vtkMRMLLORVectorMath.h b/Utilities/vtkMRMLLORVectorMath.h new file mode 100644 index 0000000..132bfe0 --- /dev/null +++ b/Utilities/vtkMRMLLORVectorMath.h @@ -0,0 +1,36 @@ + +#ifndef __vtkMRMLLORVectorMath_h +#define __vtkMRMLLORVectorMath_h + +// Standard includes +#include +#include +#include +#include + +#include "vtkMRMLLORConstants.h" + +#include "vtkSlicerLinearObjectRegistrationModuleUtilitiesExport.h" + +namespace vtkMRMLLORVectorMath +{ + + // Note: Do not remove any VTK_SLICER_LINEAROBJECTREGISTRATION_MODULE_MRML_EXPORT - it exports these functions so they are usable by the logic + VTK_SLICER_LINEAROBJECTREGISTRATION_MODULE_UTILITIES_EXPORT std::vector Abs( std::vector vector ); + VTK_SLICER_LINEAROBJECTREGISTRATION_MODULE_UTILITIES_EXPORT std::vector Normalize( std::vector vector ); + + VTK_SLICER_LINEAROBJECTREGISTRATION_MODULE_UTILITIES_EXPORT double Distance( std::vector v1, std::vector v2 ); + VTK_SLICER_LINEAROBJECTREGISTRATION_MODULE_UTILITIES_EXPORT double Norm( std::vector vector ); + VTK_SLICER_LINEAROBJECTREGISTRATION_MODULE_UTILITIES_EXPORT double Dot( std::vector v1, std::vector v2 ); + VTK_SLICER_LINEAROBJECTREGISTRATION_MODULE_UTILITIES_EXPORT std::vector Cross( std::vector v1, std::vector v2 ); + + VTK_SLICER_LINEAROBJECTREGISTRATION_MODULE_UTILITIES_EXPORT std::vector Add( std::vector v1, std::vector v2 ); + VTK_SLICER_LINEAROBJECTREGISTRATION_MODULE_UTILITIES_EXPORT std::vector Subtract( std::vector v1, std::vector v2 ); + VTK_SLICER_LINEAROBJECTREGISTRATION_MODULE_UTILITIES_EXPORT std::vector Multiply( double c, std::vector vector ); + + VTK_SLICER_LINEAROBJECTREGISTRATION_MODULE_UTILITIES_EXPORT std::string VectorToString( std::vector vector ); + VTK_SLICER_LINEAROBJECTREGISTRATION_MODULE_UTILITIES_EXPORT std::vector StringToVector( std::string s, int size ); + +} + +#endif \ No newline at end of file diff --git a/Widgets/CMakeLists.txt b/Widgets/CMakeLists.txt index 3eb675e..742b79d 100644 --- a/Widgets/CMakeLists.txt +++ b/Widgets/CMakeLists.txt @@ -5,6 +5,8 @@ set(KIT ${PROJECT_NAME}) set(${KIT}_EXPORT_DIRECTIVE "Q_SLICER_MODULE_${MODULE_NAME_UPPER}_WIDGETS_EXPORT") set(${KIT}_INCLUDE_DIRECTORIES + ${vtkSlicer${MODULE_NAME}ModuleUtilities_SOURCE_DIR} + ${vtkSlicer${MODULE_NAME}ModuleUtilities_BINARY_DIR} ) set(${KIT}_SRCS @@ -14,24 +16,29 @@ set(${KIT}_SRCS qSlicerLORManualDOFWidget.h qSlicerLORManualSegmentationWidget.cxx qSlicerLORManualSegmentationWidget.h + qSlicerLORAutomaticWidget.cxx + qSlicerLORAutomaticWidget.h ) set(${KIT}_MOC_SRCS qSlicerLinearObjectCollectionWidget.h qSlicerLORManualDOFWidget.h qSlicerLORManualSegmentationWidget.h + qSlicerLORAutomaticWidget.h ) set(${KIT}_UI_SRCS ./Resources/UI/qSlicerLinearObjectCollectionWidget.ui ./Resources/UI/qSlicerLORManualDOFWidget.ui ./Resources/UI/qSlicerLORManualSegmentationWidget.ui + ./Resources/UI/qSlicerLORAutomaticWidget.ui ) set(${KIT}_RESOURCES ./Resources/UI/qSlicerLinearObjectCollectionWidget.ui ./Resources/UI/qSlicerLORManualDOFWidget.ui ./Resources/UI/qSlicerLORManualSegmentationWidget.ui + ./Resources/UI/qSlicerLORAutomaticWidget.ui ) set(${KIT}_TARGET_LIBRARIES diff --git a/Widgets/Resources/UI/qSlicerLORAutomaticWidget.ui b/Widgets/Resources/UI/qSlicerLORAutomaticWidget.ui index eccb2a3..f04be9d 100644 --- a/Widgets/Resources/UI/qSlicerLORAutomaticWidget.ui +++ b/Widgets/Resources/UI/qSlicerLORAutomaticWidget.ui @@ -23,24 +23,6 @@ 0 - - - - - 0 - 0 - - - - - vtkMRMLLinearTransformNode - - - - true - - - @@ -63,11 +45,6 @@ - - qMRMLNodeComboBox - QWidget -
qMRMLNodeComboBox.h
-
qSlicerWidget QWidget @@ -76,22 +53,5 @@
- - - qSlicerLORAutomaticWidget - mrmlSceneChanged(vtkMRMLScene*) - TransformNodeComboBox - setMRMLScene(vtkMRMLScene*) - - - 199 - 122 - - - 199 - 59 - - - - + diff --git a/Widgets/Resources/UI/qSlicerLORManualDOFWidget.ui b/Widgets/Resources/UI/qSlicerLORManualDOFWidget.ui index 934ccbd..560147d 100644 --- a/Widgets/Resources/UI/qSlicerLORManualDOFWidget.ui +++ b/Widgets/Resources/UI/qSlicerLORManualDOFWidget.ui @@ -23,21 +23,6 @@ 0 - - - - - 0 - 0 - - - - - vtkMRMLLinearTransformNode - - - - @@ -109,11 +94,6 @@ - - qMRMLNodeComboBox - QWidget -
qMRMLNodeComboBox.h
-
qSlicerWidget QWidget @@ -122,22 +102,5 @@
- - - qSlicerLORManualDOFWidget - mrmlSceneChanged(vtkMRMLScene*) - TransformNodeComboBox - setMRMLScene(vtkMRMLScene*) - - - 208 - 122 - - - 208 - 59 - - - - + diff --git a/Widgets/Resources/UI/qSlicerLORManualSegmentationWidget.ui b/Widgets/Resources/UI/qSlicerLORManualSegmentationWidget.ui index def04fa..1230a95 100644 --- a/Widgets/Resources/UI/qSlicerLORManualSegmentationWidget.ui +++ b/Widgets/Resources/UI/qSlicerLORManualSegmentationWidget.ui @@ -23,21 +23,6 @@ 0 - - - - - 0 - 0 - - - - - vtkMRMLLinearTransformNode - - - - @@ -57,11 +42,6 @@ - - qMRMLNodeComboBox - QWidget -
qMRMLNodeComboBox.h
-
qSlicerWidget QWidget @@ -70,22 +50,5 @@
- - - qSlicerLORManualSegmentationWidget - mrmlSceneChanged(vtkMRMLScene*) - TransformNodeComboBox - setMRMLScene(vtkMRMLScene*) - - - 199 - 122 - - - 199 - 59 - - - - + diff --git a/Widgets/qSlicerLORAutomaticWidget.cxx b/Widgets/qSlicerLORAutomaticWidget.cxx new file mode 100644 index 0000000..6efd230 --- /dev/null +++ b/Widgets/qSlicerLORAutomaticWidget.cxx @@ -0,0 +1,161 @@ +/*============================================================================== + + Program: 3D Slicer + + Copyright (c) Kitware Inc. + + See COPYRIGHT.txt + or http://www.slicer.org/copyright/copyright.txt for details. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + This file was originally developed by Jean-Christophe Fillion-Robin, Kitware Inc. + and was partially funded by NIH grant 3P41RR013218-12S1 + +==============================================================================*/ + +// FooBar Widgets includes +#include "qSlicerLORAutomaticWidget.h" + +#include + + +//----------------------------------------------------------------------------- +/// \ingroup Slicer_QtModules_CreateModels +class qSlicerLORAutomaticWidgetPrivate + : public Ui_qSlicerLORAutomaticWidget +{ + Q_DECLARE_PUBLIC(qSlicerLORAutomaticWidget); +protected: + qSlicerLORAutomaticWidget* const q_ptr; + +public: + qSlicerLORAutomaticWidgetPrivate( qSlicerLORAutomaticWidget& object); + ~qSlicerLORAutomaticWidgetPrivate(); + virtual void setupUi(qSlicerLORAutomaticWidget*); +}; + +// -------------------------------------------------------------------------- +qSlicerLORAutomaticWidgetPrivate +::qSlicerLORAutomaticWidgetPrivate( qSlicerLORAutomaticWidget& object) : q_ptr(&object) +{ +} + +qSlicerLORAutomaticWidgetPrivate +::~qSlicerLORAutomaticWidgetPrivate() +{ +} + + +// -------------------------------------------------------------------------- +void qSlicerLORAutomaticWidgetPrivate +::setupUi(qSlicerLORAutomaticWidget* widget) +{ + this->Ui_qSlicerLORAutomaticWidget::setupUi(widget); +} + +//----------------------------------------------------------------------------- +// qSlicerLORAutomaticWidget methods + +//----------------------------------------------------------------------------- +qSlicerLORAutomaticWidget +::qSlicerLORAutomaticWidget(QWidget* parentWidget) : Superclass( parentWidget ) , d_ptr( new qSlicerLORAutomaticWidgetPrivate(*this) ) +{ +} + + +qSlicerLORAutomaticWidget +::~qSlicerLORAutomaticWidget() +{ +} + + +qSlicerLORAutomaticWidget* qSlicerLORAutomaticWidget +::New() +{ + qSlicerLORAutomaticWidget* newLORAutomaticWidget = new qSlicerLORAutomaticWidget(); + newLORAutomaticWidget->LORNode = NULL; + newLORAutomaticWidget->setup(); + return newLORAutomaticWidget; +} + + +void qSlicerLORAutomaticWidget +::setup() +{ + Q_D(qSlicerLORAutomaticWidget); + + d->setupUi(this); + + this->updateWidget(); +} + + +void qSlicerLORAutomaticWidget +::enter() +{ +} + +void qSlicerLORAutomaticWidget +::SetLORNode( vtkMRMLNode* newNode ) +{ + Q_D(qSlicerLORAutomaticWidget); + + if ( this->LORNode != NULL ) + { + this->qvtkDisconnect( this->LORNode->GetActivePositionBuffer(), vtkCommand::ModifiedEvent, this, SLOT( updateWidget() ) ); + } + + vtkMRMLLinearObjectRegistrationNode* newLORNode = vtkMRMLLinearObjectRegistrationNode::SafeDownCast( newNode ); + if ( newLORNode == NULL ) + { + return; + } + + this->LORNode = newLORNode; + + this->qvtkConnect( this->LORNode->GetActivePositionBuffer(), vtkCommand::ModifiedEvent, this, SLOT( updateWidget() ) ); +} + + + +void qSlicerLORAutomaticWidget +::show() +{ + if ( this->isHidden() ) + { + this->LORNode->StartCollecting( "Automatic" ); + } + + this->Superclass::show(); +} + + +void qSlicerLORAutomaticWidget +::hide() +{ + if ( ! this->isHidden() ) + { + this->LORNode->StopCollecting(); + } + + this->Superclass::hide(); +} + + +void qSlicerLORAutomaticWidget +::updateWidget() +{ + Q_D(qSlicerLORAutomaticWidget); + + if ( this->LORNode == NULL ) + { + return; + } + + d->CollectProgressBar->setValue( int( 100 * this->LORNode->GetActivePositionBuffer()->Size() / vtkMRMLLORConstants::MINIMUM_COLLECTION_POSITIONS ) ); +} diff --git a/Widgets/qSlicerLORAutomaticWidget.h b/Widgets/qSlicerLORAutomaticWidget.h new file mode 100644 index 0000000..80aeaf7 --- /dev/null +++ b/Widgets/qSlicerLORAutomaticWidget.h @@ -0,0 +1,73 @@ +/*============================================================================== + + Program: 3D Slicer + + Copyright (c) Kitware Inc. + + See COPYRIGHT.txt + or http://www.slicer.org/copyright/copyright.txt for details. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + This file was originally developed by Jean-Christophe Fillion-Robin, Kitware Inc. + and was partially funded by NIH grant 3P41RR013218-12S1 + +==============================================================================*/ + +#ifndef __qSlicerLORAutomaticWidget_h +#define __qSlicerLORAutomaticWidget_h + +// Qt includes +#include "qSlicerWidget.h" + +// FooBar Widgets includes +#include "qSlicerLinearObjectRegistrationModuleWidgetsExport.h" +#include "ui_qSlicerLORAutomaticWidget.h" + +#include "vtkSlicerLinearObjectRegistrationLogic.h" + + +class qSlicerLORAutomaticWidgetPrivate; + +/// \ingroup Slicer_QtModules_CreateModels +class Q_SLICER_MODULE_LINEAROBJECTREGISTRATION_WIDGETS_EXPORT +qSlicerLORAutomaticWidget : public qSlicerWidget +{ + Q_OBJECT +public: + typedef qSlicerWidget Superclass; + qSlicerLORAutomaticWidget(QWidget *parent=0); + virtual ~qSlicerLORAutomaticWidget(); + + static qSlicerLORAutomaticWidget* New(); + + // Slicer will delete logic + void SetLORNode( vtkMRMLNode* newNode ); + +public slots: + + void show(); + void hide(); + +protected slots: + + void updateWidget(); + +protected: + QScopedPointer d_ptr; + + virtual void setup(); + virtual void enter(); + +private: + Q_DECLARE_PRIVATE(qSlicerLORAutomaticWidget); + Q_DISABLE_COPY(qSlicerLORAutomaticWidget); + + vtkMRMLLinearObjectRegistrationNode* LORNode; +}; + +#endif diff --git a/Widgets/qSlicerLORManualDOFWidget.cxx b/Widgets/qSlicerLORManualDOFWidget.cxx index 32586f5..f3e7376 100644 --- a/Widgets/qSlicerLORManualDOFWidget.cxx +++ b/Widgets/qSlicerLORManualDOFWidget.cxx @@ -23,12 +23,6 @@ #include - -const int LINEAROBJECT_NAME_COLUMN = 0; -const int LINEAROBJECT_TYPE_COLUMN = 1; -const int LINEAROBJECT_COLUMNS = 2; - - //----------------------------------------------------------------------------- /// \ingroup Slicer_QtModules_CreateModels class qSlicerLORManualDOFWidgetPrivate @@ -80,10 +74,10 @@ qSlicerLORManualDOFWidget qSlicerLORManualDOFWidget* qSlicerLORManualDOFWidget -::New( vtkSlicerLinearObjectRegistrationLogic* newLORLogic ) +::New() { qSlicerLORManualDOFWidget* newLORManualDOFWidget = new qSlicerLORManualDOFWidget(); - newLORManualDOFWidget->LORLogic = newLORLogic; + newLORManualDOFWidget->LORNode = NULL; newLORManualDOFWidget->setup(); return newLORManualDOFWidget; } @@ -95,11 +89,6 @@ ::setup() Q_D(qSlicerLORManualDOFWidget); d->setupUi(this); - this->setMRMLScene( this->LORLogic->GetMRMLScene() ); - - this->CollectType = ""; - - connect( d->TransformNodeComboBox, SIGNAL( currentNodeChanged( vtkMRMLNode* ) ), this, SLOT( onTransformNodeChanged() ) ); // Use the pressed signal (otherwise we can unpress buttons without clicking them) connect( d->ReferenceButton, SIGNAL( toggled( bool ) ), this, SLOT( onReferenceButtonClicked() ) ); @@ -117,72 +106,18 @@ ::enter() } -vtkMRMLNode* qSlicerLORManualDOFWidget -::GetCurrentNode() -{ - Q_D(qSlicerLORManualDOFWidget); - - return d->TransformNodeComboBox->currentNode(); -} - - void qSlicerLORManualDOFWidget -::SetCurrentNode( vtkMRMLNode* currentNode ) +::SetLORNode( vtkMRMLNode* newNode ) { Q_D(qSlicerLORManualDOFWidget); - vtkMRMLLinearTransformNode* currentTransformNode = vtkMRMLLinearTransformNode::SafeDownCast( currentNode ); - d->TransformNodeComboBox->setCurrentNode( currentTransformNode ); -} - - -void qSlicerLORManualDOFWidget -::setCollect( std::string collectType ) -{ - Q_D(qSlicerLORManualDOFWidget); - - this->CollectType = collectType; - - if ( collectType.compare( "" ) == 0 ) + vtkMRMLLinearObjectRegistrationNode* newLORNode = vtkMRMLLinearObjectRegistrationNode::SafeDownCast( newNode ); + if ( newLORNode == NULL ) { - this->LORLogic->FinalizeActivePositionBuffer(); - // All buttons should be unchecked (since they may become unchecked by another button) - disconnect( d->ReferenceButton, SIGNAL( toggled( bool ) ), this, SLOT( onReferenceButtonClicked() ) ); - disconnect( d->PointButton, SIGNAL( toggled( bool ) ), this, SLOT( onPointButtonClicked() ) ); - disconnect( d->LineButton, SIGNAL( toggled( bool ) ), this, SLOT( onLineButtonClicked() ) ); - disconnect( d->PlaneButton, SIGNAL( toggled( bool ) ), this, SLOT( onPlaneButtonClicked() ) ); - - d->ReferenceButton->setChecked( false ); - d->PointButton->setChecked( false ); - d->LineButton->setChecked( false ); - d->PlaneButton->setChecked( false ); - - connect( d->ReferenceButton, SIGNAL( toggled( bool ) ), this, SLOT( onReferenceButtonClicked() ) ); - connect( d->PointButton, SIGNAL( toggled( bool ) ), this, SLOT( onPointButtonClicked() ) ); - connect( d->LineButton, SIGNAL( toggled( bool ) ), this, SLOT( onLineButtonClicked() ) ); - connect( d->PlaneButton, SIGNAL( toggled( bool ) ), this, SLOT( onPlaneButtonClicked() ) ); - } - else - { - this->LORLogic->InitializeActivePositionBuffer( collectType ); - // Individual buttons will be responsible for checking themselves (since they can only become checked on button press) + return; } -} - - - -void qSlicerLORManualDOFWidget -::onTransformNodeChanged() -{ - Q_D(qSlicerLORManualDOFWidget); - - emit transformNodeChanged(); - - this->LORLogic->FinalizeActivePositionBuffer(); - this->LORLogic->ObserveTransformNode( d->TransformNodeComboBox->currentNode() ); - - this->updateWidget(); + this->LORNode = newLORNode; } @@ -191,14 +126,13 @@ ::onReferenceButtonClicked() { Q_D(qSlicerLORManualDOFWidget); - if ( this->CollectType.compare( "" ) == 0 && this->GetCurrentNode() != NULL ) + if ( this->LORNode->GetCollectionState().compare( "" ) == 0 ) { - this->setCollect( "Reference" ); - d->ReferenceButton->setChecked( true ); + this->LORNode->StartCollecting( "Reference" ); } else { - this->setCollect( "" ); + this->LORNode->StopCollecting(); } } @@ -208,14 +142,13 @@ ::onPointButtonClicked() { Q_D(qSlicerLORManualDOFWidget); - if ( this->CollectType.compare( "" ) == 0 && this->GetCurrentNode() != NULL ) + if ( this->LORNode->GetCollectionState().compare( "" ) == 0 ) { - this->setCollect( "Point" ); - d->PointButton->setChecked( true ); + this->LORNode->StartCollecting( "Point" ); } else { - this->setCollect( "" ); + this->LORNode->StopCollecting(); } } @@ -225,14 +158,13 @@ ::onLineButtonClicked() { Q_D(qSlicerLORManualDOFWidget); - if ( this->CollectType.compare( "" ) == 0 && this->GetCurrentNode() != NULL ) + if ( this->LORNode->GetCollectionState().compare( "" ) == 0 ) { - this->setCollect( "Line" ); - d->LineButton->setChecked( true ); + this->LORNode->StartCollecting( "Line" ); } else { - this->setCollect( "" ); + this->LORNode->StopCollecting(); } } @@ -242,14 +174,13 @@ ::onPlaneButtonClicked() { Q_D(qSlicerLORManualDOFWidget); - if ( this->CollectType.compare( "" ) == 0 && this->GetCurrentNode() != NULL ) + if ( this->LORNode->GetCollectionState().compare( "" ) == 0 ) { - this->setCollect( "Plane" ); - d->PlaneButton->setChecked( true ); + this->LORNode->StartCollecting( "Plane" ); } else { - this->setCollect( "" ); + this->LORNode->StopCollecting(); } } @@ -260,12 +191,17 @@ ::updateWidget() { Q_D(qSlicerLORManualDOFWidget); + if ( this->LORNode == NULL ) + { + return; + } + disconnect( d->ReferenceButton, SIGNAL( toggled( bool ) ), this, SLOT( onReferenceButtonClicked() ) ); disconnect( d->PointButton, SIGNAL( toggled( bool ) ), this, SLOT( onPointButtonClicked() ) ); disconnect( d->LineButton, SIGNAL( toggled( bool ) ), this, SLOT( onLineButtonClicked() ) ); disconnect( d->PlaneButton, SIGNAL( toggled( bool ) ), this, SLOT( onPlaneButtonClicked() ) ); - if ( this->CollectType == "Reference" && this->GetCurrentNode() != NULL ) + if ( this->LORNode->GetCollectionState().compare( "Reference" ) ) { d->ReferenceButton->setChecked( true ); } @@ -274,7 +210,7 @@ ::updateWidget() d->ReferenceButton->setChecked( false ); } - if ( this->CollectType == "Point" && this->GetCurrentNode() != NULL ) + if ( this->LORNode->GetCollectionState().compare( "Point" ) ) { d->PointButton->setChecked( true ); } @@ -283,7 +219,7 @@ ::updateWidget() d->PointButton->setChecked( false ); } - if ( this->CollectType == "Line" && this->GetCurrentNode() != NULL ) + if ( this->LORNode->GetCollectionState().compare( "Line" ) ) { d->LineButton->setChecked( true ); } @@ -292,7 +228,7 @@ ::updateWidget() d->LineButton->setChecked( false ); } - if ( this->CollectType == "Plane" && this->GetCurrentNode() != NULL ) + if ( this->LORNode->GetCollectionState().compare( "Plane" ) ) { d->PlaneButton->setChecked( true ); } diff --git a/Widgets/qSlicerLORManualDOFWidget.h b/Widgets/qSlicerLORManualDOFWidget.h index 6b8fb0e..ebc59da 100644 --- a/Widgets/qSlicerLORManualDOFWidget.h +++ b/Widgets/qSlicerLORManualDOFWidget.h @@ -43,31 +43,19 @@ qSlicerLORManualDOFWidget : public qSlicerWidget qSlicerLORManualDOFWidget(QWidget *parent=0); virtual ~qSlicerLORManualDOFWidget(); - static qSlicerLORManualDOFWidget* New( vtkSlicerLinearObjectRegistrationLogic* newLORLogic ); + static qSlicerLORManualDOFWidget* New(); - // Slicer will delete logic - vtkSlicerLinearObjectRegistrationLogic* LORLogic; - - vtkMRMLNode* GetCurrentNode(); - void SetCurrentNode( vtkMRMLNode* currentNode ); + void SetLORNode( vtkMRMLNode* newNode ); protected slots: - void onTransformNodeChanged(); // User selects a different node using the combo box - void onReferenceButtonClicked(); void onPointButtonClicked(); void onLineButtonClicked(); void onPlaneButtonClicked(); - void setCollect( std::string collectType ); - void updateWidget(); -signals: - - void transformNodeChanged(); - protected: QScopedPointer d_ptr; @@ -78,7 +66,7 @@ protected slots: Q_DECLARE_PRIVATE(qSlicerLORManualDOFWidget); Q_DISABLE_COPY(qSlicerLORManualDOFWidget); - std::string CollectType; + vtkMRMLLinearObjectRegistrationNode* LORNode; }; #endif diff --git a/Widgets/qSlicerLORManualSegmentationWidget.cxx b/Widgets/qSlicerLORManualSegmentationWidget.cxx index bcb66a0..382b24d 100644 --- a/Widgets/qSlicerLORManualSegmentationWidget.cxx +++ b/Widgets/qSlicerLORManualSegmentationWidget.cxx @@ -75,10 +75,10 @@ qSlicerLORManualSegmentationWidget qSlicerLORManualSegmentationWidget* qSlicerLORManualSegmentationWidget -::New( vtkSlicerLinearObjectRegistrationLogic* newLORLogic ) +::New() { qSlicerLORManualSegmentationWidget* newLORManualSegmentationWidget = new qSlicerLORManualSegmentationWidget(); - newLORManualSegmentationWidget->LORLogic = newLORLogic; + newLORManualSegmentationWidget->LORNode = NULL; newLORManualSegmentationWidget->setup(); return newLORManualSegmentationWidget; } @@ -90,11 +90,6 @@ ::setup() Q_D(qSlicerLORManualSegmentationWidget); d->setupUi(this); - this->setMRMLScene( this->LORLogic->GetMRMLScene() ); - - this->CollectType = ""; - - connect( d->TransformNodeComboBox, SIGNAL( currentNodeChanged( vtkMRMLNode* ) ), this, SLOT( onTransformNodeChanged() ) ); // Use the pressed signal (otherwise we can unpress buttons without clicking them) connect( d->CollectButton, SIGNAL( toggled( bool ) ), this, SLOT( onCollectButtonClicked() ) ); @@ -109,63 +104,18 @@ ::enter() } -vtkMRMLNode* qSlicerLORManualSegmentationWidget -::GetCurrentNode() -{ - Q_D(qSlicerLORManualSegmentationWidget); - - return d->TransformNodeComboBox->currentNode(); -} - - -void qSlicerLORManualSegmentationWidget -::SetCurrentNode( vtkMRMLNode* currentNode ) -{ - Q_D(qSlicerLORManualSegmentationWidget); - - vtkMRMLLinearTransformNode* currentTransformNode = vtkMRMLLinearTransformNode::SafeDownCast( currentNode ); - d->TransformNodeComboBox->setCurrentNode( currentTransformNode ); -} - - void qSlicerLORManualSegmentationWidget -::setCollect( std::string collectType ) +::SetLORNode( vtkMRMLNode* newNode ) { Q_D(qSlicerLORManualSegmentationWidget); - this->CollectType = collectType; - - if ( collectType.compare( "" ) == 0 ) - { - this->LORLogic->FinalizeActivePositionBuffer(); - // All buttons should be unchecked (since they may become unchecked by another button) - connect( d->TransformNodeComboBox, SIGNAL( currentNodeChanged( vtkMRMLNode* ) ), this, SLOT( onTransformNodeChanged() ) ); - - d->CollectButton->setChecked( false ); - - connect( d->TransformNodeComboBox, SIGNAL( currentNodeChanged( vtkMRMLNode* ) ), this, SLOT( onTransformNodeChanged() ) ); - } - else + vtkMRMLLinearObjectRegistrationNode* newLORNode = vtkMRMLLinearObjectRegistrationNode::SafeDownCast( newNode ); + if ( newLORNode == NULL ) { - this->LORLogic->InitializeActivePositionBuffer( collectType ); - // Individual buttons will be responsible for checking themselves (since they can only become checked on button press) + return; } -} - - - -void qSlicerLORManualSegmentationWidget -::onTransformNodeChanged() -{ - Q_D(qSlicerLORManualSegmentationWidget); - - emit transformNodeChanged(); - - this->LORLogic->FinalizeActivePositionBuffer(); - this->LORLogic->ObserveTransformNode( d->TransformNodeComboBox->currentNode() ); - - this->updateWidget(); + this->LORNode = newLORNode; } @@ -174,14 +124,13 @@ ::onCollectButtonClicked() { Q_D(qSlicerLORManualSegmentationWidget); - if ( this->CollectType.compare( "" ) == 0 && this->GetCurrentNode() != NULL ) + if ( this->LORNode->GetCollectionState().compare( "" ) == 0 ) { - this->setCollect( "Collect" ); - d->CollectButton->setChecked( true ); + this->LORNode->StartCollecting( "Collect" ); } else { - this->setCollect( "" ); + this->LORNode->StopCollecting(); } } @@ -192,9 +141,14 @@ ::updateWidget() { Q_D(qSlicerLORManualSegmentationWidget); + if ( this->LORNode == NULL ) + { + return; + } + disconnect( d->CollectButton, SIGNAL( toggled( bool ) ), this, SLOT( onCollectButtonClicked() ) ); - if ( this->CollectType.compare( "Collect" ) == 0 && this->GetCurrentNode() != NULL ) + if ( this->LORNode->GetCollectionState().compare( "Collect" ) ) { d->CollectButton->setChecked( true ); } diff --git a/Widgets/qSlicerLORManualSegmentationWidget.h b/Widgets/qSlicerLORManualSegmentationWidget.h index bfc0524..2f814c2 100644 --- a/Widgets/qSlicerLORManualSegmentationWidget.h +++ b/Widgets/qSlicerLORManualSegmentationWidget.h @@ -43,28 +43,17 @@ qSlicerLORManualSegmentationWidget : public qSlicerWidget qSlicerLORManualSegmentationWidget(QWidget *parent=0); virtual ~qSlicerLORManualSegmentationWidget(); - static qSlicerLORManualSegmentationWidget* New( vtkSlicerLinearObjectRegistrationLogic* newLORLogic ); + static qSlicerLORManualSegmentationWidget* New(); // Slicer will delete logic - vtkSlicerLinearObjectRegistrationLogic* LORLogic; - - vtkMRMLNode* GetCurrentNode(); - void SetCurrentNode( vtkMRMLNode* currentNode ); + void SetLORNode( vtkMRMLNode* newNode ); protected slots: - void onTransformNodeChanged(); // User selects a different node using the combo box - void onCollectButtonClicked(); - void setCollect( std::string collectType ); - void updateWidget(); -signals: - - void transformNodeChanged(); - protected: QScopedPointer d_ptr; @@ -75,7 +64,7 @@ protected slots: Q_DECLARE_PRIVATE(qSlicerLORManualSegmentationWidget); Q_DISABLE_COPY(qSlicerLORManualSegmentationWidget); - std::string CollectType; + vtkMRMLLinearObjectRegistrationNode* LORNode; }; #endif diff --git a/Widgets/qSlicerLinearObjectCollectionWidget.cxx b/Widgets/qSlicerLinearObjectCollectionWidget.cxx index 33bb710..f7fe9f8 100644 --- a/Widgets/qSlicerLinearObjectCollectionWidget.cxx +++ b/Widgets/qSlicerLinearObjectCollectionWidget.cxx @@ -336,19 +336,19 @@ ::onLinearObjectEdited( int row, int column ) vtkSmartPointer< vtkMRMLLORLinearObjectNode > newLinearObject = NULL; if ( qText.toStdString().compare( "Reference" ) == 0 ) { - newLinearObject = this->LORLogic->PositionBufferToLinearObject( currentLinearObject->GetPositionBuffer(), vtkSlicerLinearObjectRegistrationLogic::REFERENCE_DOF ); + newLinearObject = this->LORLogic->PositionBufferToLinearObject( currentLinearObject->GetPositionBuffer(), vtkMRMLLORConstants::REFERENCE_DOF ); } if ( qText.toStdString().compare( "Point" ) == 0 ) { - newLinearObject = this->LORLogic->PositionBufferToLinearObject( currentLinearObject->GetPositionBuffer(), vtkSlicerLinearObjectRegistrationLogic::POINT_DOF ); + newLinearObject = this->LORLogic->PositionBufferToLinearObject( currentLinearObject->GetPositionBuffer(), vtkMRMLLORConstants::POINT_DOF ); } if ( qText.toStdString().compare( "Line" ) == 0 ) { - newLinearObject = this->LORLogic->PositionBufferToLinearObject( currentLinearObject->GetPositionBuffer(), vtkSlicerLinearObjectRegistrationLogic::LINE_DOF ); + newLinearObject = this->LORLogic->PositionBufferToLinearObject( currentLinearObject->GetPositionBuffer(), vtkMRMLLORConstants::LINE_DOF ); } if ( qText.toStdString().compare( "Plane" ) == 0 ) { - newLinearObject = this->LORLogic->PositionBufferToLinearObject( currentLinearObject->GetPositionBuffer(), vtkSlicerLinearObjectRegistrationLogic::PLANE_DOF ); + newLinearObject = this->LORLogic->PositionBufferToLinearObject( currentLinearObject->GetPositionBuffer(), vtkMRMLLORConstants::PLANE_DOF ); } if ( newLinearObject == NULL ) diff --git a/qSlicerLinearObjectRegistrationModuleWidget.cxx b/qSlicerLinearObjectRegistrationModuleWidget.cxx index cf3d6e6..038e8ee 100644 --- a/qSlicerLinearObjectRegistrationModuleWidget.cxx +++ b/qSlicerLinearObjectRegistrationModuleWidget.cxx @@ -13,6 +13,8 @@ #include "vtkSlicerLinearObjectRegistrationLogic.h" #include "qSlicerLORManualDOFWidget.h" +#include "qSlicerLORManualSegmentationWidget.h" +#include "qSlicerLORAutomaticWidget.h" #include "vtkMRMLModelNode.h" #include "vtkMRMLNode.h" @@ -35,6 +37,8 @@ class qSlicerLinearObjectRegistrationModuleWidgetPrivate: public Ui_qSlicerLinea qSlicerLinearObjectCollectionWidget* FromCollectionWidget; qSlicerLinearObjectCollectionWidget* ToCollectionWidget; qSlicerLORManualDOFWidget* ManualDOFWidget; + qSlicerLORManualSegmentationWidget* ManualSegmentationWidget; + qSlicerLORAutomaticWidget* AutomaticWidget; }; @@ -81,31 +85,6 @@ qSlicerLinearObjectRegistrationModuleWidget::~qSlicerLinearObjectRegistrationMod { } -/* -void qSlicerLinearObjectRegistrationModuleWidget -::OnRegisterButtonClicked() -{ - Q_D( qSlicerLinearObjectRegistrationModuleWidget ); - - d->logic()->CalculateTransform( d->ModuleNodeComboBox->currentNode() ); - - this->UpdateGUI(); -} - - -void qSlicerLinearObjectRegistrationModuleWidget -::OnMatchButtonClicked() -{ - Q_D( qSlicerLinearObjectRegistrationModuleWidget ); - - vtkMRMLLORLinearObjectCollectionNode* fromCollection = vtkMRMLLORLinearObjectCollectionNode::SafeDownCast( d->FromCollectionWidget->GetCurrentNode() ); - vtkMRMLLORLinearObjectCollectionNode* toCollection = vtkMRMLLORLinearObjectCollectionNode::SafeDownCast( d->ToCollectionWidget->GetCurrentNode() ); - - d->logic()->MatchCollections( fromCollection, toCollection ); - - this->UpdateGUI(); -} -*/ void qSlicerLinearObjectRegistrationModuleWidget @@ -165,9 +144,15 @@ ::setup() d->ToCollectionWidget->SetNodeBaseName( "ToLinearObjects" ); d->ToGroupBox->layout()->addWidget( d->ToCollectionWidget ); - d->ManualDOFWidget = qSlicerLORManualDOFWidget::New( d->logic() ); + d->ManualDOFWidget = qSlicerLORManualDOFWidget::New(); d->CollectionGroupBox->layout()->addWidget( d->ManualDOFWidget ); + d->ManualSegmentationWidget = qSlicerLORManualSegmentationWidget::New(); + d->CollectionGroupBox->layout()->addWidget( d->ManualSegmentationWidget ); + + d->AutomaticWidget = qSlicerLORAutomaticWidget::New(); + d->CollectionGroupBox->layout()->addWidget( d->AutomaticWidget ); + this->FromMatchState = -1; this->ToMatchState = -1; @@ -177,35 +162,47 @@ ::setup() this->qvtkConnect( d->logic(), vtkCommand::ModifiedEvent, this, SLOT( UpdateFromMRMLNode() ) ); // Make connections to update the mrml from the widget + this->ConnectWidgets(); + + // Various other connections + connect( d->FromCollectionWidget, SIGNAL( matchRequested( int ) ), this, SLOT( OnFromMatchRequested( int ) ) ); + connect( d->ToCollectionWidget, SIGNAL( matchRequested( int ) ), this, SLOT( OnToMatchRequested( int ) ) ); +} + + +void qSlicerLinearObjectRegistrationModuleWidget +::ConnectWidgets() +{ + Q_D( qSlicerLinearObjectRegistrationModuleWidget ); + connect( d->OutputNodeComboBox, SIGNAL( currentNodeChanged( vtkMRMLNode* ) ), this, SLOT( UpdateToMRMLNode() ) ); connect( d->ManualDOFRadioButton, SIGNAL( toggled( bool ) ), this, SLOT( UpdateToMRMLNode() ) ); connect( d->ManualSegmentationRadioButton, SIGNAL( toggled( bool ) ), this, SLOT( UpdateToMRMLNode() ) ); connect( d->AutomaticRadioButton, SIGNAL( toggled( bool ) ), this, SLOT( UpdateToMRMLNode() ) ); connect( d->AutomaticMatchCheckBox, SIGNAL( toggled( bool ) ), this, SLOT( UpdateToMRMLNode() ) ); + connect( d->TransformNodeComboBox, SIGNAL( currentNodeChanged( vtkMRMLNode* ) ), this, SLOT( UpdateToMRMLNode() ) ); + connect( d->FromCollectionWidget, SIGNAL( collectionNodeChanged() ), this, SLOT( UpdateToMRMLNode() ) ); connect( d->ToCollectionWidget, SIGNAL( collectionNodeChanged() ), this, SLOT( UpdateToMRMLNode() ) ); - - connect( d->ManualDOFWidget, SIGNAL( transformNodeChanged() ), this, SLOT( UpdateToMRMLNode() ) ); - - - // Various other connections - connect( d->FromCollectionWidget, SIGNAL( matchRequested( int ) ), this, SLOT( OnFromMatchRequested( int ) ) ); - connect( d->ToCollectionWidget, SIGNAL( matchRequested( int ) ), this, SLOT( OnToMatchRequested( int ) ) ); } - void qSlicerLinearObjectRegistrationModuleWidget -::UpdateGUI() +::DisconnectWidgets() { Q_D( qSlicerLinearObjectRegistrationModuleWidget ); - std::stringstream statusString; - statusString << "Status: "; - statusString << d->logic()->GetOutputMessage(); - d->StatusLabel->setText( QString::fromStdString( statusString.str() ) ); - + disconnect( d->OutputNodeComboBox, SIGNAL( currentNodeChanged( vtkMRMLNode* ) ), this, SLOT( UpdateToMRMLNode() ) ); + disconnect( d->ManualDOFRadioButton, SIGNAL( toggled( bool ) ), this, SLOT( UpdateToMRMLNode() ) ); + disconnect( d->ManualSegmentationRadioButton, SIGNAL( toggled( bool ) ), this, SLOT( UpdateToMRMLNode() ) ); + disconnect( d->AutomaticRadioButton, SIGNAL( toggled( bool ) ), this, SLOT( UpdateToMRMLNode() ) ); + disconnect( d->AutomaticMatchCheckBox, SIGNAL( toggled( bool ) ), this, SLOT( UpdateToMRMLNode() ) ); + + disconnect( d->TransformNodeComboBox, SIGNAL( currentNodeChanged( vtkMRMLNode* ) ), this, SLOT( UpdateToMRMLNode() ) ); + + disconnect( d->FromCollectionWidget, SIGNAL( collectionNodeChanged() ), this, SLOT( UpdateToMRMLNode() ) ); + disconnect( d->ToCollectionWidget, SIGNAL( collectionNodeChanged() ), this, SLOT( UpdateToMRMLNode() ) ); } @@ -224,13 +221,13 @@ ::UpdateToMRMLNode() this->qvtkBlockAll( true ); - if ( d->ManualDOFWidget->GetCurrentNode() == NULL ) + if ( d->TransformNodeComboBox->currentNode() == NULL ) { linearObjectRegistrationNode->SetCollectTransformID( "", vtkMRMLLinearObjectRegistrationNode::NeverModify ); } else { - linearObjectRegistrationNode->SetCollectTransformID( d->ManualDOFWidget->GetCurrentNode()->GetID(), vtkMRMLLinearObjectRegistrationNode::NeverModify ); + linearObjectRegistrationNode->SetCollectTransformID( d->TransformNodeComboBox->currentNode()->GetID(), vtkMRMLLinearObjectRegistrationNode::NeverModify ); } if ( d->OutputNodeComboBox->currentNode() == NULL ) @@ -306,6 +303,8 @@ ::UpdateFromMRMLNode() d->AutomaticRadioButton->setEnabled( false ); d->AutomaticMatchCheckBox->setEnabled( false ); d->ManualDOFWidget->setEnabled( false ); + d->ManualSegmentationWidget->setEnabled( false ); + d->AutomaticWidget->setEnabled( false ); d->FromCollectionWidget->setEnabled( false ); d->ToCollectionWidget->setEnabled( false ); d->StatusLabel->setText( "No Linear Object Registration module node selected." ); @@ -318,43 +317,53 @@ ::UpdateFromMRMLNode() d->AutomaticRadioButton->setEnabled( true ); d->AutomaticMatchCheckBox->setEnabled( true ); d->ManualDOFWidget->setEnabled( true ); + d->ManualSegmentationWidget->setEnabled( true ); + d->AutomaticWidget->setEnabled( true ); d->FromCollectionWidget->setEnabled( true ); d->ToCollectionWidget->setEnabled( true ); // Disconnect to prevent signals form cuing slots - disconnect( d->OutputNodeComboBox, SIGNAL( currentNodeChanged( vtkMRMLNode* ) ), this, SLOT( UpdateToMRMLNode() ) ); - disconnect( d->ManualDOFRadioButton, SIGNAL( toggled( bool ) ), this, SLOT( UpdateToMRMLNode() ) ); - disconnect( d->ManualSegmentationRadioButton, SIGNAL( toggled( bool ) ), this, SLOT( UpdateToMRMLNode() ) ); - disconnect( d->AutomaticRadioButton, SIGNAL( toggled( bool ) ), this, SLOT( UpdateToMRMLNode() ) ); - disconnect( d->FromCollectionWidget, SIGNAL( collectionNodeChanged() ), this, SLOT( UpdateToMRMLNode() ) ); - disconnect( d->ToCollectionWidget, SIGNAL( collectionNodeChanged() ), this, SLOT( UpdateToMRMLNode() ) ); - disconnect( d->ManualDOFWidget, SIGNAL( transformNodeChanged() ), this, SLOT( UpdateToMRMLNode() ) ); + this->DisconnectWidgets(); - std::string fromFid = linearObjectRegistrationNode->GetFromCollectionID(); - std::string toFid = linearObjectRegistrationNode->GetToCollectionID(); - - d->ManualDOFWidget->SetCurrentNode( this->mrmlScene()->GetNodeByID( linearObjectRegistrationNode->GetCollectTransformID() ) ); + d->TransformNodeComboBox->setCurrentNodeID( QString::fromStdString( linearObjectRegistrationNode->GetCollectTransformID() ) ); d->OutputNodeComboBox->setCurrentNodeID( QString::fromStdString( linearObjectRegistrationNode->GetOutputTransformID() ) ); + d->FromCollectionWidget->SetCurrentNode( this->mrmlScene()->GetNodeByID( linearObjectRegistrationNode->GetFromCollectionID() ) ); d->ToCollectionWidget->SetCurrentNode( this->mrmlScene()->GetNodeByID( linearObjectRegistrationNode->GetToCollectionID() ) ); + + d->ManualDOFWidget->SetLORNode( linearObjectRegistrationNode ); + d->ManualSegmentationWidget->SetLORNode( linearObjectRegistrationNode ); + d->AutomaticWidget->SetLORNode( linearObjectRegistrationNode ); if ( linearObjectRegistrationNode->GetCollectionMode().compare( "ManualDOF" ) == 0 ) { d->ManualDOFRadioButton->setChecked( Qt::Checked ); d->ManualSegmentationRadioButton->setChecked( Qt::Unchecked ); d->AutomaticRadioButton->setChecked( Qt::Unchecked ); + + d->ManualDOFWidget->show(); + d->ManualSegmentationWidget->hide(); + d->AutomaticWidget->hide(); } if ( linearObjectRegistrationNode->GetCollectionMode().compare( "ManualSegmentation" ) == 0 ) { d->ManualDOFRadioButton->setChecked( Qt::Unchecked ); d->ManualSegmentationRadioButton->setChecked( Qt::Checked ); d->AutomaticRadioButton->setChecked( Qt::Unchecked ); + + d->ManualDOFWidget->hide(); + d->ManualSegmentationWidget->show(); + d->AutomaticWidget->hide(); } if ( linearObjectRegistrationNode->GetCollectionMode().compare( "Automatic" ) == 0 ) { d->ManualDOFRadioButton->setChecked( Qt::Unchecked ); d->ManualSegmentationRadioButton->setChecked( Qt::Unchecked ); d->AutomaticRadioButton->setChecked( Qt::Checked ); + + d->ManualDOFWidget->hide(); + d->ManualSegmentationWidget->hide(); + d->AutomaticWidget->show(); } if ( linearObjectRegistrationNode->GetAutomaticMatch().compare( "True" ) == 0 ) @@ -367,14 +376,7 @@ ::UpdateFromMRMLNode() } // Unblock all singals from firing - // TODO: Is there a more efficient way to do this by blokcing slots? - connect( d->OutputNodeComboBox, SIGNAL( currentNodeChanged( vtkMRMLNode* ) ), this, SLOT( UpdateToMRMLNode() ) ); - connect( d->ManualDOFRadioButton, SIGNAL( toggled( bool ) ), this, SLOT( UpdateToMRMLNode() ) ); - connect( d->ManualSegmentationRadioButton, SIGNAL( toggled( bool ) ), this, SLOT( UpdateToMRMLNode() ) ); - connect( d->AutomaticRadioButton, SIGNAL( toggled( bool ) ), this, SLOT( UpdateToMRMLNode() ) ); - connect( d->FromCollectionWidget, SIGNAL( collectionNodeChanged() ), this, SLOT( UpdateToMRMLNode() ) ); - connect( d->ToCollectionWidget, SIGNAL( collectionNodeChanged() ), this, SLOT( UpdateToMRMLNode() ) ); - connect( d->ManualDOFWidget, SIGNAL( transformNodeChanged() ), this, SLOT( UpdateToMRMLNode() ) ); + this->ConnectWidgets(); std::stringstream statusString; statusString << "Status: "; diff --git a/qSlicerLinearObjectRegistrationModuleWidget.h b/qSlicerLinearObjectRegistrationModuleWidget.h index 6694d20..6d3efd9 100644 --- a/qSlicerLinearObjectRegistrationModuleWidget.h +++ b/qSlicerLinearObjectRegistrationModuleWidget.h @@ -24,9 +24,6 @@ class Q_SLICER_QTMODULES_LINEAROBJECTREGISTRATION_EXPORT qSlicerLinearObjectRegi public slots: - //void OnRegisterButtonClicked(); - //void OnMatchButtonClicked(); - void OnFromMatchRequested( int matchIndex ); void OnToMatchRequested( int matchIndex ); @@ -42,14 +39,12 @@ public slots: Q_DECLARE_PRIVATE(qSlicerLinearObjectRegistrationModuleWidget); Q_DISABLE_COPY(qSlicerLinearObjectRegistrationModuleWidget); - void UpdateGUI(); + void ConnectWidgets(); + void DisconnectWidgets(); int FromMatchState; int ToMatchState; - double TimerIntervalSec; - QTimer* Timer; - }; #endif