diff --git a/Core/Code/Controllers/mitkPlanePositionManager.cpp b/Core/Code/Controllers/mitkPlanePositionManager.cpp new file mode 100644 index 0000000000..bf36f4023b --- /dev/null +++ b/Core/Code/Controllers/mitkPlanePositionManager.cpp @@ -0,0 +1,136 @@ +#include "mitkPlanePositionManager.h" +#include "mitkInteractionConst.h" + + +mitk::PlanePositionManager::PlanePositionManager() +: m_ID (0) +{ +} + +mitk::PlanePositionManager::~PlanePositionManager() +{ + 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 ) +{ + 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(); + + for (unsigned int i = 0; i < m_PositionList.size(); i++) + { + if (m_PositionList.at(i) != 0) + { + itk::Matrix diffM = plane->GetIndexToWorldTransform()->GetMatrix()-m_PositionList.at(i)->GetTransform()->GetMatrix(); + bool isSameMatrix(true); + for (unsigned int j = 0; j < 3; j++) + { + if (fabs(diffM[j][0]) > 0.0001 && fabs(diffM[j][1]) > 0.0001 && fabs(diffM[j][2]) > 0.0001) + { + isSameMatrix = false; + break; + } + } + itk::Vector diffV = m_PositionList.at(i)->GetTransform()->GetOffset()-transform->GetOffset(); + if ( isSameMatrix && m_PositionList.at(i)->GetPos() == sliceIndex && (fabs(diffV[0]) < 0.0001 && fabs(diffV[1]) < 0.0001 && fabs(diffV[2]) < 0.0001) ) + return i; + } + + } + + 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::DeletePlanePosition( unsigned int ID ) +{ + if (m_PositionList.size() > ID) + { + m_PositionList.at(ID) = 0; + return true; + } + else + { + return false; + } +} + +mitk::RestorePlanePositionOperation* mitk::PlanePositionManager::GetPlanePosition ( unsigned int ID ) +{ + if ( m_PositionList.at(ID) != 0 ) + { + return m_PositionList.at(ID); + } + else + { + MITK_INFO<<"GetPlanePosition returned NULL"; + return 0; + } +} + +unsigned int mitk::PlanePositionManager::GetNumberOfPlanePositions() +{ + return m_PositionList.size(); +} + +void mitk::PlanePositionManager::DeleteAllMarkers() +{ + m_PositionList.clear(); +} + +void mitk::PlanePositionManager::SetDataStorage( mitk::DataStorage* ds ) +{ + if (ds == NULL) + return; + + /* remove listeners of old DataStorage */ + if (m_DataStorage.IsNotNull()) + { + m_DataStorage->RemoveNodeEvent.RemoveListener(MessageDelegate1( this, &PlanePositionManager::DataStorageRemovedNode )); + } + /* register listener for new DataStorage */ + m_DataStorage = ds; // register + m_DataStorage->RemoveNodeEvent.AddListener(MessageDelegate1( this, &PlanePositionManager::DataStorageRemovedNode )); +} + +void mitk::PlanePositionManager::DataStorageRemovedNode(const mitk::DataNode* removedNode) +{ + bool isContourMarker (false); + if (removedNode->GetBoolProperty("isContourMarker", isContourMarker)) + { + unsigned int t = removedNode->GetName().find_last_of(" "); + unsigned int id = atof(removedNode->GetName().substr(t+1).c_str()); + this->DeletePlanePosition(id-1); + } +} + + \ No newline at end of file diff --git a/Core/Code/Controllers/mitkPlanePositionManager.h b/Core/Code/Controllers/mitkPlanePositionManager.h new file mode 100644 index 0000000000..4bda45350d --- /dev/null +++ b/Core/Code/Controllers/mitkPlanePositionManager.h @@ -0,0 +1,70 @@ +/*========================================================================= + +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" + +namespace mitk +{ + + class MITK_CORE_EXPORT PlanePositionManager : public itk::Object + { + + public: + + mitkClassMacro(PlanePositionManager, itk::Object); + itkNewMacro(Self); + + static PlanePositionManager* GetInstance(); + + unsigned int AddNewPlanePosition(const Geometry2D* plane, unsigned int sliceIndex = 0); + + bool DeletePlanePosition(unsigned int ID); + + void DeleteAllMarkers(); + + RestorePlanePositionOperation* GetPlanePosition( unsigned int ID); + + unsigned int GetNumberOfPlanePositions(); + + void DataStorageRemovedNode(const mitk::DataNode* removedNode = NULL); + + void SetDataStorage(mitk::DataStorage* ds); + + protected: + + PlanePositionManager(); + + ~PlanePositionManager(); + + private: + + static PlanePositionManager* m_Instance; + std::vector m_PositionList; + unsigned int m_ID; + DataStorage::Pointer m_DataStorage; + + }; +} + + +#endif \ No newline at end of file diff --git a/Core/Code/Controllers/mitkSliceNavigationController.cpp b/Core/Code/Controllers/mitkSliceNavigationController.cpp index 2be5807b77..544e6ac62a 100644 --- a/Core/Code/Controllers/mitkSliceNavigationController.cpp +++ b/Core/Code/Controllers/mitkSliceNavigationController.cpp @@ -1,728 +1,736 @@ /*========================================================================= 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 "mitkBaseRenderer.h" #include "mitkSlicedGeometry3D.h" #include "mitkPlaneGeometry.h" #include "mitkOperation.h" #include "mitkOperationActor.h" #include "mitkStateEvent.h" #include "mitkCrosshairPositionEvent.h" #include "mitkPositionEvent.h" #include "mitkInteractionConst.h" #include "mitkAction.h" #include "mitkGlobalInteraction.h" #include "mitkEventMapper.h" #include "mitkFocusManager.h" #include "mitkVtkPropRenderer.h" #include "mitkRenderingManager.h" #include "mitkInteractionConst.h" #include "mitkPointOperation.h" #include "mitkPlaneOperation.h" #include "mitkUndoController.h" #include "mitkOperationEvent.h" #include "mitkNodePredicateDataType.h" #include "mitkStatusBar.h" #include #include "mitkMemoryUtilities.h" #include namespace mitk { SliceNavigationController::SliceNavigationController( const char *type ) : BaseController( type ), m_InputWorldGeometry( NULL ), m_CreatedWorldGeometry( NULL ), m_ViewDirection( Transversal ), m_DefaultViewDirection( Transversal ), m_RenderingManager( NULL ), m_Renderer( NULL ), m_Top( false ), m_FrontSide( false ), m_Rotated( false ), m_BlockUpdate( false ), m_SliceLocked( false ), m_SliceRotationLocked( false ), m_OldPos(0) { typedef itk::SimpleMemberCommand< SliceNavigationController > SNCCommandType; SNCCommandType::Pointer sliceStepperChangedCommand, timeStepperChangedCommand; sliceStepperChangedCommand = SNCCommandType::New(); timeStepperChangedCommand = SNCCommandType::New(); sliceStepperChangedCommand->SetCallbackFunction( this, &SliceNavigationController::SendSlice ); timeStepperChangedCommand->SetCallbackFunction( this, &SliceNavigationController::SendTime ); m_Slice->AddObserver( itk::ModifiedEvent(), sliceStepperChangedCommand ); m_Time->AddObserver( itk::ModifiedEvent(), timeStepperChangedCommand ); m_Slice->SetUnitName( "mm" ); m_Time->SetUnitName( "ms" ); m_Top = false; m_FrontSide = false; m_Rotated = false; } SliceNavigationController::~SliceNavigationController() { } void SliceNavigationController::SetInputWorldGeometry( const Geometry3D *geometry ) { if ( geometry != NULL ) { if ( const_cast< BoundingBox * >( geometry->GetBoundingBox()) ->GetDiagonalLength2() < eps ) { itkWarningMacro( "setting an empty bounding-box" ); geometry = NULL; } } if ( m_InputWorldGeometry != geometry ) { m_InputWorldGeometry = geometry; this->Modified(); } } RenderingManager * SliceNavigationController::GetRenderingManager() const { mitk::RenderingManager* renderingManager = m_RenderingManager.GetPointer(); if (renderingManager != NULL) return renderingManager; if ( m_Renderer != NULL ) { renderingManager = m_Renderer->GetRenderingManager(); if (renderingManager != NULL) return renderingManager; } return mitk::RenderingManager::GetInstance(); } void SliceNavigationController::SetViewDirectionToDefault() { m_ViewDirection = m_DefaultViewDirection; } void SliceNavigationController::Update() { if ( !m_BlockUpdate ) { if ( m_ViewDirection == Transversal ) { this->Update( Transversal, false, false, true ); } else { this->Update( m_ViewDirection ); } } } void SliceNavigationController::Update( SliceNavigationController::ViewDirection viewDirection, bool top, bool frontside, bool rotated ) { const TimeSlicedGeometry* worldTimeSlicedGeometry = dynamic_cast< const TimeSlicedGeometry * >( m_InputWorldGeometry.GetPointer() ); if( m_BlockUpdate || m_InputWorldGeometry.IsNull() || ( (worldTimeSlicedGeometry != NULL) && (worldTimeSlicedGeometry->GetTimeSteps() == 0) ) ) { return; } m_BlockUpdate = true; if ( m_LastUpdateTime < m_InputWorldGeometry->GetMTime() ) { Modified(); } this->SetViewDirection( viewDirection ); this->SetTop( top ); this->SetFrontSide( frontside ); this->SetRotated( rotated ); if ( m_LastUpdateTime < GetMTime() ) { m_LastUpdateTime = GetMTime(); // initialize the viewplane SlicedGeometry3D::Pointer slicedWorldGeometry = NULL; m_CreatedWorldGeometry = NULL; switch ( viewDirection ) { case Original: if ( worldTimeSlicedGeometry != NULL ) { m_CreatedWorldGeometry = static_cast< TimeSlicedGeometry * >( m_InputWorldGeometry->Clone().GetPointer() ); worldTimeSlicedGeometry = m_CreatedWorldGeometry.GetPointer(); slicedWorldGeometry = dynamic_cast< SlicedGeometry3D * >( m_CreatedWorldGeometry->GetGeometry3D( this->GetTime()->GetPos() ) ); if ( slicedWorldGeometry.IsNotNull() ) { break; } } else { const SlicedGeometry3D *worldSlicedGeometry = dynamic_cast< const SlicedGeometry3D * >( m_InputWorldGeometry.GetPointer()); if ( worldSlicedGeometry != NULL ) { slicedWorldGeometry = static_cast< SlicedGeometry3D * >( m_InputWorldGeometry->Clone().GetPointer()); break; } } //else: use Transversal: no "break" here!! case Transversal: slicedWorldGeometry = SlicedGeometry3D::New(); slicedWorldGeometry->InitializePlanes( m_InputWorldGeometry, PlaneGeometry::Transversal, top, frontside, rotated ); slicedWorldGeometry->SetSliceNavigationController( this ); break; case Frontal: slicedWorldGeometry = SlicedGeometry3D::New(); slicedWorldGeometry->InitializePlanes( m_InputWorldGeometry, PlaneGeometry::Frontal, top, frontside, rotated ); slicedWorldGeometry->SetSliceNavigationController( this ); break; case Sagittal: slicedWorldGeometry = SlicedGeometry3D::New(); slicedWorldGeometry->InitializePlanes( m_InputWorldGeometry, PlaneGeometry::Sagittal, top, frontside, rotated ); slicedWorldGeometry->SetSliceNavigationController( this ); break; default: itkExceptionMacro("unknown ViewDirection"); } m_Slice->SetPos( 0 ); m_Slice->SetSteps( (int)slicedWorldGeometry->GetSlices() ); if ( m_CreatedWorldGeometry.IsNull() ) { // initialize TimeSlicedGeometry m_CreatedWorldGeometry = TimeSlicedGeometry::New(); } if ( worldTimeSlicedGeometry == NULL ) { m_CreatedWorldGeometry->InitializeEvenlyTimed( slicedWorldGeometry, 1 ); m_Time->SetSteps( 0 ); m_Time->SetPos( 0 ); m_Time->InvalidateRange(); } else { m_BlockUpdate = true; m_Time->SetSteps( worldTimeSlicedGeometry->GetTimeSteps() ); m_Time->SetPos( 0 ); const TimeBounds &timeBounds = worldTimeSlicedGeometry->GetTimeBounds(); m_Time->SetRange( timeBounds[0], timeBounds[1] ); m_BlockUpdate = false; assert( worldTimeSlicedGeometry->GetGeometry3D( this->GetTime()->GetPos() ) != NULL ); slicedWorldGeometry->SetTimeBounds( worldTimeSlicedGeometry->GetGeometry3D( this->GetTime()->GetPos() )->GetTimeBounds() ); //@todo implement for non-evenly-timed geometry! m_CreatedWorldGeometry->InitializeEvenlyTimed( slicedWorldGeometry, worldTimeSlicedGeometry->GetTimeSteps() ); } } // unblock update; we may do this now, because if m_BlockUpdate was already // true before this method was entered, then we will never come here. m_BlockUpdate = false; // Send the geometry. Do this even if nothing was changed, because maybe // Update() was only called to re-send the old geometry and time/slice data. this->SendCreatedWorldGeometry(); this->SendSlice(); this->SendTime(); // Adjust the stepper range of slice stepper according to geometry this->AdjustSliceStepperRange(); } void SliceNavigationController::SendCreatedWorldGeometry() { // Send the geometry. Do this even if nothing was changed, because maybe // Update() was only called to re-send the old geometry. if ( !m_BlockUpdate ) { this->InvokeEvent( GeometrySendEvent(m_CreatedWorldGeometry, 0) ); } } void SliceNavigationController::SendCreatedWorldGeometryUpdate() { if ( !m_BlockUpdate ) { this->InvokeEvent( GeometryUpdateEvent(m_CreatedWorldGeometry, m_Slice->GetPos()) ); } } void SliceNavigationController::SendSlice() { if ( !m_BlockUpdate ) { if ( m_CreatedWorldGeometry.IsNotNull() ) { this->InvokeEvent( GeometrySliceEvent(m_CreatedWorldGeometry, m_Slice->GetPos()) ); // send crosshair event crosshairPositionEvent.Send(); // Request rendering update for all views this->GetRenderingManager()->RequestUpdateAll(); } } } void SliceNavigationController::SendTime() { if ( !m_BlockUpdate ) { if ( m_CreatedWorldGeometry.IsNotNull() ) { this->InvokeEvent( GeometryTimeEvent(m_CreatedWorldGeometry, m_Time->GetPos()) ); // Request rendering update for all views this->GetRenderingManager()->RequestUpdateAll(); } } } void SliceNavigationController::SetGeometry( const itk::EventObject & ) { } void SliceNavigationController ::SetGeometryTime( const itk::EventObject &geometryTimeEvent ) { const SliceNavigationController::GeometryTimeEvent *timeEvent = dynamic_cast< const SliceNavigationController::GeometryTimeEvent * >( &geometryTimeEvent); assert( timeEvent != NULL ); TimeSlicedGeometry *timeSlicedGeometry = timeEvent->GetTimeSlicedGeometry(); assert( timeSlicedGeometry != NULL ); if ( m_CreatedWorldGeometry.IsNotNull() ) { int timeStep = (int) timeEvent->GetPos(); ScalarType timeInMS; timeInMS = timeSlicedGeometry->TimeStepToMS( timeStep ); timeStep = m_CreatedWorldGeometry->MSToTimeStep( timeInMS ); this->GetTime()->SetPos( timeStep ); } } void SliceNavigationController ::SetGeometrySlice(const itk::EventObject & geometrySliceEvent) { const SliceNavigationController::GeometrySliceEvent* sliceEvent = dynamic_cast( &geometrySliceEvent); assert(sliceEvent!=NULL); this->GetSlice()->SetPos(sliceEvent->GetPos()); } void SliceNavigationController::SelectSliceByPoint( const Point3D &point ) { //@todo add time to PositionEvent and use here!! SlicedGeometry3D* slicedWorldGeometry = dynamic_cast< SlicedGeometry3D * >( m_CreatedWorldGeometry->GetGeometry3D( this->GetTime()->GetPos() ) ); if ( slicedWorldGeometry ) { int bestSlice = -1; double bestDistance = itk::NumericTraits::max(); int s, slices; slices = slicedWorldGeometry->GetSlices(); if ( slicedWorldGeometry->GetEvenlySpaced() ) { mitk::Geometry2D *plane = slicedWorldGeometry->GetGeometry2D( 0 ); const Vector3D &direction = slicedWorldGeometry->GetDirectionVector(); Point3D projectedPoint; plane->Project( point, projectedPoint ); // Check whether the point is somewhere within the slice stack volume; // otherwise, the defualt slice (0) will be selected if ( direction[0] * (point[0] - projectedPoint[0]) + direction[1] * (point[1] - projectedPoint[1]) + direction[2] * (point[2] - projectedPoint[2]) >= 0 ) { bestSlice = (int)(plane->Distance( point ) / slicedWorldGeometry->GetSpacing()[2] + 0.5); } } else { Point3D projectedPoint; for ( s = 0; s < slices; ++s ) { slicedWorldGeometry->GetGeometry2D( s )->Project( point, projectedPoint ); Vector3D distance = projectedPoint - point; ScalarType currentDistance = distance.GetSquaredNorm(); if ( currentDistance < bestDistance ) { bestDistance = currentDistance; bestSlice = s; } } } if ( bestSlice >= 0 ) { this->GetSlice()->SetPos( bestSlice ); } else { this->GetSlice()->SetPos( 0 ); } this->SendCreatedWorldGeometryUpdate(); } } void SliceNavigationController::ReorientSlices( const Point3D &point, const Vector3D &normal ) { PlaneOperation op( OpORIENT, point, normal ); m_CreatedWorldGeometry->ExecuteOperation( &op ); this->SendCreatedWorldGeometryUpdate(); } const mitk::TimeSlicedGeometry * SliceNavigationController::GetCreatedWorldGeometry() { return m_CreatedWorldGeometry; } const mitk::Geometry3D * SliceNavigationController::GetCurrentGeometry3D() { if ( m_CreatedWorldGeometry.IsNotNull() ) { return m_CreatedWorldGeometry->GetGeometry3D( this->GetTime()->GetPos() ); } else { return NULL; } } const mitk::PlaneGeometry * SliceNavigationController::GetCurrentPlaneGeometry() { const mitk::SlicedGeometry3D *slicedGeometry = dynamic_cast< const mitk::SlicedGeometry3D * > ( this->GetCurrentGeometry3D() ); if ( slicedGeometry ) { const mitk::PlaneGeometry *planeGeometry = dynamic_cast< mitk::PlaneGeometry * > ( slicedGeometry->GetGeometry2D(this->GetSlice()->GetPos()) ); return planeGeometry; } else { return NULL; } } void SliceNavigationController::SetRenderer( BaseRenderer *renderer ) { m_Renderer = renderer; } BaseRenderer * SliceNavigationController::GetRenderer() const { return m_Renderer; } void SliceNavigationController::AdjustSliceStepperRange() { const mitk::SlicedGeometry3D *slicedGeometry = dynamic_cast< const mitk::SlicedGeometry3D * > ( this->GetCurrentGeometry3D() ); const Vector3D &direction = slicedGeometry->GetDirectionVector(); int c = 0; int i, k = 0; for ( i = 0; i < 3; ++i ) { if ( fabs( (float) direction[i] ) < 0.000000001 ) { ++c; } else { k = i; } } if ( c == 2 ) { ScalarType min = m_InputWorldGeometry->GetOrigin()[k]; ScalarType max = min + m_InputWorldGeometry->GetExtentInMM( k ); m_Slice->SetRange( min, max ); } else { m_Slice->InvalidateRange(); } } void SliceNavigationController::ExecuteOperation( Operation *operation ) { // switch on type // - select best slice for a given point // - rotate created world geometry according to Operation->SomeInfo() if ( !operation ) { return; } switch ( operation->GetOperationType() ) { case OpMOVE: // should be a point operation { if ( !m_SliceLocked ) //do not move the cross position { // select a slice PointOperation *po = dynamic_cast< PointOperation * >( operation ); if ( po && po->GetIndex() == -1 ) { this->SelectSliceByPoint( po->GetPoint() ); } else if ( po && po->GetIndex() != -1 ) // undo case because index != -1, index holds the old position of this slice { this->GetSlice()->SetPos( po->GetIndex() ); } } break; } + case OpRESTOREPLANEPOSITION: + { + m_CreatedWorldGeometry->ExecuteOperation( operation ); + + this->SendCreatedWorldGeometryUpdate(); + + break; + } default: { // do nothing break; } } } // Relict from the old times, when automous decisions were accepted // behavior. Remains in here, because some RenderWindows do exist outside // of StdMultiWidgets. bool SliceNavigationController ::ExecuteAction( Action* action, StateEvent const* stateEvent ) { bool ok = false; const PositionEvent* posEvent = dynamic_cast< const PositionEvent * >( stateEvent->GetEvent() ); if ( posEvent != NULL ) { if ( m_CreatedWorldGeometry.IsNull() ) { return true; } switch (action->GetActionId()) { case AcMOVE: { BaseRenderer *baseRenderer = posEvent->GetSender(); if ( !baseRenderer ) { baseRenderer = const_cast( GlobalInteraction::GetInstance()->GetFocus() ); } if ( baseRenderer ) if ( baseRenderer->GetMapperID() == 1 ) { PointOperation* doOp = new mitk::PointOperation(OpMOVE, posEvent->GetWorldPosition()); if (m_UndoEnabled) { m_OldPos = this->GetSlice()->GetPos(); // m_OldPos holds the old slice position. For the undo controller this old position will be stored as index in mitk::PointOperation PointOperation* undoOp = new mitk::PointOperation(OpMOVE, posEvent->GetWorldPosition(), m_OldPos); OperationEvent *operationEvent = new mitk::OperationEvent(this, doOp, undoOp, "Move slices"); m_UndoController->SetOperationEvent(operationEvent); } this->ExecuteOperation( doOp ); // If click was performed in this render window than we have to update the status bar information about position and pixel value. if(baseRenderer == m_Renderer) { { std::string statusText; TNodePredicateDataType::Pointer isImageData = TNodePredicateDataType::New(); mitk::DataStorage::SetOfObjects::ConstPointer nodes = baseRenderer->GetDataStorage()->GetSubset(isImageData).GetPointer(); mitk::Point3D worldposition = posEvent->GetWorldPosition(); int maxlayer = -32768; mitk::Image::Pointer image3D; // find image with largest layer, that is the image shown on top in the render window for (unsigned int x = 0; x < nodes->size(); x++) { //Just consider image data that is no helper object. E.g. do not consider nodes created for the slice interpolation bool isHelper (false); nodes->at(x)->GetBoolProperty("helper object", isHelper); if(nodes->at(x)->GetData()->GetGeometry()->IsInside(worldposition) && isHelper == false) { int layer = 0; if(!(nodes->at(x)->GetIntProperty("layer", layer))) continue; if(layer > maxlayer) { if(static_cast(nodes->at(x))->IsVisible(m_Renderer)) { image3D = dynamic_cast(nodes->at(x)->GetData()); maxlayer = layer; } } } } std::stringstream stream; stream.imbue(std::locale::classic()); // get the position and gray value from the image and build up status bar text if(image3D.IsNotNull()) { Index3D p; image3D->GetGeometry()->WorldToIndex(worldposition, p); stream.precision(2); stream<<"Position: <" << std::fixed < mm"; stream<<"; Index: <"< "; mitk::ScalarType pixelValue = image3D->GetPixelValueByIndex(p, baseRenderer->GetTimeStep()); if (fabs(pixelValue)>1000000) { stream<<"; Time: " << baseRenderer->GetTime() << " ms; Pixelvalue: "<GetPixelValueByIndex(p, baseRenderer->GetTimeStep())<<" "; } else { stream<<"; Time: " << baseRenderer->GetTime() << " ms; Pixelvalue: "<GetPixelValueByIndex(p, baseRenderer->GetTimeStep())<<" "; } } else { stream << "No image information at this position!"; } statusText = stream.str(); mitk::StatusBar::GetInstance()->DisplayGreyValueText(statusText.c_str()); } } ok = true; break; } } default: ok = true; break; } return ok; } const DisplayPositionEvent *displPosEvent = dynamic_cast< const DisplayPositionEvent * >( stateEvent->GetEvent() ); if ( displPosEvent != NULL ) { return true; } return false; } } // namespace diff --git a/Core/Code/Controllers/mitkSliceNavigationController.h b/Core/Code/Controllers/mitkSliceNavigationController.h index 74bf7bc9c4..4573793b71 100644 --- a/Core/Code/Controllers/mitkSliceNavigationController.h +++ b/Core/Code/Controllers/mitkSliceNavigationController.h @@ -1,512 +1,512 @@ /*========================================================================= 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 SLICENAVIGATIONCONTROLLER_H_HEADER_INCLUDED_C1C55A2F #define SLICENAVIGATIONCONTROLLER_H_HEADER_INCLUDED_C1C55A2F #include #include "mitkBaseController.h" #include "mitkRenderingManager.h" #include "mitkTimeSlicedGeometry.h" #include "mitkMessage.h" #pragma GCC visibility push(default) #include #pragma GCC visibility pop #include #include #include +#include "mitkRestorePlanePositionOperation.h" namespace mitk { #define mitkTimeSlicedGeometryEventMacro( classname , super ) \ class MITK_CORE_EXPORT classname : public super { \ public: \ typedef classname Self; \ typedef super Superclass; \ classname(TimeSlicedGeometry* aTimeSlicedGeometry, unsigned int aPos) \ : Superclass(aTimeSlicedGeometry, aPos) {} \ virtual ~classname() {} \ virtual const char * GetEventName() const { return #classname; } \ virtual bool CheckEvent(const ::itk::EventObject* e) const \ { return dynamic_cast(e); } \ virtual ::itk::EventObject* MakeObject() const \ { return new Self(GetTimeSlicedGeometry(), GetPos()); } \ private: \ void operator=(const Self&); \ } class PlaneGeometry; class Geometry3D; class BaseRenderer; /** * \brief Controls the selection of the slice the associated BaseRenderer * will display * * A SliceNavigationController takes a Geometry3D as input world geometry * (TODO what are the exact requirements?) and generates a TimeSlicedGeometry * as output. The TimeSlicedGeometry holds a number of SlicedGeometry3Ds and * these in turn hold a series of Geometry2Ds. One of these Geometry2Ds is * selected as world geometry for the BaseRenderers associated to 2D views. * * The SliceNavigationController holds has Steppers (one for the slice, a * second for the time step), which control the selection of a single * Geometry2D from the TimeSlicedGeometry. SliceNavigationController generates * ITK events to tell observers, like a BaseRenderer, when the selected slice * or timestep changes. * * SliceNavigationControllers are registered as listeners to GlobalInteraction * by the QmitkStdMultiWidget. In ExecuteAction, the controllers react to * PositionEvents by setting the steppers to the slice which is nearest to the * point of the PositionEvent. * * Example: * \code * // Initialization * sliceCtrl = mitk::SliceNavigationController::New(); * * // Tell the navigator the geometry to be sliced (with geometry a * // Geometry3D::ConstPointer) * sliceCtrl->SetInputWorldGeometry(geometry.GetPointer()); * * // Tell the navigator in which direction it shall slice the data * sliceCtrl->SetViewDirection(mitk::SliceNavigationController::Transversal); * * // Connect one or more BaseRenderer to this navigator, i.e.: events sent * // by the navigator when stepping through the slices (e.g. by * // sliceCtrl->GetSlice()->Next()) will be received by the BaseRenderer * // (in this example only slice-changes, see also ConnectGeometryTimeEvent * // and ConnectGeometryEvents.) * sliceCtrl->ConnectGeometrySliceEvent(renderer.GetPointer()); * * //create a world geometry and send the information to the connected renderer(s) * sliceCtrl->Update(); * \endcode * * * You can connect visible navigators to a SliceNavigationController, e.g., a * QmitkSliderNavigator (for Qt): * * \code * // Create the visible navigator (a slider with a spin-box) * QmitkSliderNavigator* navigator = * new QmitkSliderNavigator(parent, "slidernavigator"); * * // Connect the navigator to the slice-stepper of the * // SliceNavigationController. For initialization (position, mininal and * // maximal values) the values of the SliceNavigationController are used. * // Thus, accessing methods of a navigator is normally not necessary, since * // everything can be set via the (Qt-independent) SliceNavigationController. * // The QmitkStepperAdapter converts the Qt-signals to Qt-independent * // itk-events. * new QmitkStepperAdapter(navigator, sliceCtrl->GetSlice(), "navigatoradaptor"); * \endcode * * If you do not want that all renderwindows are updated when a new slice is * selected, you can use a specific RenderingManager, which updates only those * renderwindows that should be updated. This is sometimes useful when a 3D view * does not need to be updated when the slices in some 2D views are changed. * QmitkSliderNavigator (for Qt): * * \code * // create a specific RenderingManager * mitk::RenderingManager::Pointer myManager = mitk::RenderingManager::New(); * * // tell the RenderingManager to update only renderwindow1 and renderwindow2 * myManager->AddRenderWindow(renderwindow1); * myManager->AddRenderWindow(renderwindow2); * * // tell the SliceNavigationController of renderwindow1 and renderwindow2 * // to use the specific RenderingManager instead of the global one * renderwindow1->GetSliceNavigationController()->SetRenderingManager(myManager); * renderwindow2->GetSliceNavigationController()->SetRenderingManager(myManager); * \endcode * * \todo implement for non-evenly-timed geometry! * \ingroup NavigationControl */ class MITK_CORE_EXPORT SliceNavigationController : public BaseController { public: mitkClassMacro(SliceNavigationController,BaseController); itkNewMacro(Self); mitkNewMacro1Param(Self, const char *); /** * \brief Possible view directions, \a Original will uses * the Geometry2D instances in a SlicedGeometry3D provided * as input world geometry (by SetInputWorldGeometry). */ enum ViewDirection{Transversal, Sagittal, Frontal, Original}; /** * \brief Set the input world geometry out of which the * geometries for slicing will be created. */ void SetInputWorldGeometry(const mitk::Geometry3D* geometry); itkGetConstObjectMacro(InputWorldGeometry, mitk::Geometry3D); /** * \brief Access the created geometry */ itkGetConstObjectMacro(CreatedWorldGeometry, mitk::Geometry3D); /** * \brief Set the desired view directions * * \sa ViewDirection * \sa Update(ViewDirection viewDirection, bool top = true, * bool frontside = true, bool rotated = false) */ itkSetEnumMacro(ViewDirection, ViewDirection); itkGetEnumMacro(ViewDirection, ViewDirection); /** * \brief Set the default view direction * * This is used to re-initialize the view direction of the SNC to the * default value with SetViewDirectionToDefault() * * \sa ViewDirection * \sa Update(ViewDirection viewDirection, bool top = true, * bool frontside = true, bool rotated = false) */ itkSetEnumMacro(DefaultViewDirection, ViewDirection); itkGetEnumMacro(DefaultViewDirection, ViewDirection); virtual void SetViewDirectionToDefault(); /** * \brief Do the actual creation and send it to the connected * observers (renderers) * */ virtual void Update(); /** * \brief Extended version of Update, additionally allowing to * specify the direction/orientation of the created geometry. * */ virtual void Update(ViewDirection viewDirection, bool top = true, bool frontside = true, bool rotated = false); /** * \brief Send the created geometry to the connected * observers (renderers) * * Called by Update(). */ virtual void SendCreatedWorldGeometry(); /** * \brief Tell observers to re-read the currently selected 2D geometry * * Called by mitk::SlicesRotator during rotation. */ virtual void SendCreatedWorldGeometryUpdate(); /** * \brief Send the currently selected slice to the connected * observers (renderers) * * Called by Update(). */ virtual void SendSlice(); /** * \brief Send the currently selected time to the connected * observers (renderers) * * Called by Update(). */ virtual void SendTime(); /** * \brief Set the RenderingManager to be used * * If \a NULL, the default RenderingManager will be used. */ itkSetObjectMacro(RenderingManager, RenderingManager); mitk::RenderingManager* GetRenderingManager() const; #pragma GCC visibility push(default) itkEventMacro( UpdateEvent, itk::AnyEvent ); #pragma GCC visibility pop class MITK_CORE_EXPORT TimeSlicedGeometryEvent : public itk::AnyEvent { public: typedef TimeSlicedGeometryEvent Self; typedef itk::AnyEvent Superclass; TimeSlicedGeometryEvent( TimeSlicedGeometry* aTimeSlicedGeometry, unsigned int aPos) : m_TimeSlicedGeometry(aTimeSlicedGeometry), m_Pos(aPos) {} virtual ~TimeSlicedGeometryEvent() {} virtual const char * GetEventName() const { return "TimeSlicedGeometryEvent"; } virtual bool CheckEvent(const ::itk::EventObject* e) const { return dynamic_cast(e); } virtual ::itk::EventObject* MakeObject() const { return new Self(m_TimeSlicedGeometry, m_Pos); } TimeSlicedGeometry* GetTimeSlicedGeometry() const { return m_TimeSlicedGeometry; } unsigned int GetPos() const { return m_Pos; } private: TimeSlicedGeometry::Pointer m_TimeSlicedGeometry; unsigned int m_Pos; // TimeSlicedGeometryEvent(const Self&); void operator=(const Self&); //just hide }; mitkTimeSlicedGeometryEventMacro( GeometrySendEvent,TimeSlicedGeometryEvent ); mitkTimeSlicedGeometryEventMacro( GeometryUpdateEvent, TimeSlicedGeometryEvent ); mitkTimeSlicedGeometryEventMacro( GeometryTimeEvent, TimeSlicedGeometryEvent ); mitkTimeSlicedGeometryEventMacro( GeometrySliceEvent, TimeSlicedGeometryEvent ); template void ConnectGeometrySendEvent(T* receiver) { typedef typename itk::ReceptorMemberCommand::Pointer ReceptorMemberCommandPointer; ReceptorMemberCommandPointer eventReceptorCommand = itk::ReceptorMemberCommand::New(); eventReceptorCommand->SetCallbackFunction(receiver, &T::SetGeometry); AddObserver(GeometrySendEvent(NULL,0), eventReceptorCommand); } template void ConnectGeometryUpdateEvent(T* receiver) { typedef typename itk::ReceptorMemberCommand::Pointer ReceptorMemberCommandPointer; ReceptorMemberCommandPointer eventReceptorCommand = itk::ReceptorMemberCommand::New(); eventReceptorCommand->SetCallbackFunction(receiver, &T::UpdateGeometry); AddObserver(GeometryUpdateEvent(NULL,0), eventReceptorCommand); } template void ConnectGeometrySliceEvent(T* receiver, bool connectSendEvent=true) { typedef typename itk::ReceptorMemberCommand::Pointer ReceptorMemberCommandPointer; ReceptorMemberCommandPointer eventReceptorCommand = itk::ReceptorMemberCommand::New(); eventReceptorCommand->SetCallbackFunction(receiver, &T::SetGeometrySlice); AddObserver(GeometrySliceEvent(NULL,0), eventReceptorCommand); if(connectSendEvent) ConnectGeometrySendEvent(receiver); } template void ConnectGeometryTimeEvent(T* receiver, bool connectSendEvent=true) { typedef typename itk::ReceptorMemberCommand::Pointer ReceptorMemberCommandPointer; ReceptorMemberCommandPointer eventReceptorCommand = itk::ReceptorMemberCommand::New(); eventReceptorCommand->SetCallbackFunction(receiver, &T::SetGeometryTime); AddObserver(GeometryTimeEvent(NULL,0), eventReceptorCommand); if(connectSendEvent) ConnectGeometrySendEvent(receiver); } template void ConnectGeometryEvents(T* receiver) { //connect sendEvent only once ConnectGeometrySliceEvent(receiver, false); ConnectGeometryTimeEvent(receiver); } Message<> crosshairPositionEvent; /** * \brief To connect multiple SliceNavigationController, we can * act as an observer ourselves: implemented interface * \warning not implemented */ virtual void SetGeometry(const itk::EventObject & geometrySliceEvent); /** * \brief To connect multiple SliceNavigationController, we can * act as an observer ourselves: implemented interface */ virtual void SetGeometrySlice(const itk::EventObject & geometrySliceEvent); /** * \brief To connect multiple SliceNavigationController, we can * act as an observer ourselves: implemented interface */ virtual void SetGeometryTime(const itk::EventObject & geometryTimeEvent); /** \brief Positions the SNC according to the specified point */ void SelectSliceByPoint( const mitk::Point3D &point ); /** \brief Returns the TimeSlicedGeometry created by the SNC. */ const mitk::TimeSlicedGeometry *GetCreatedWorldGeometry(); /** \brief Returns the Geometry3D of the currently selected time step. */ const mitk::Geometry3D *GetCurrentGeometry3D(); /** \brief Returns the currently selected Plane in the current * Geometry3D (if existent). */ const mitk::PlaneGeometry *GetCurrentPlaneGeometry(); /** \brief Sets the BaseRenderer associated with this SNC (if any). While * the BaseRenderer is not directly used by SNC, this is a convenience * method to enable BaseRenderer access via the SNC. */ void SetRenderer( BaseRenderer *renderer ); /** \brief Gets the BaseRenderer associated with this SNC (if any). While * the BaseRenderer is not directly used by SNC, this is a convenience * method to enable BaseRenderer access via the SNC. Returns NULL if no * BaseRenderer has been specified*/ BaseRenderer *GetRenderer() const; /** \brief Re-orients the slice stack to include the plane specified by * the given point an normal vector. */ void ReorientSlices( const mitk::Point3D &point, const mitk::Vector3D &normal ); - virtual bool ExecuteAction( Action* action, mitk::StateEvent const* stateEvent); void ExecuteOperation(Operation* operation); /** * \brief Feature option to lock planes during mouse interaction. * This option flag disables the mouse event which causes the center * cross to move near by. */ itkSetMacro(SliceLocked, bool); itkGetMacro(SliceLocked, bool); itkBooleanMacro(SliceLocked); /** * \brief Feature option to lock slice rotation. * * This option flag disables separately the rotation of a slice which is * implemented in mitkSliceRotator. */ itkSetMacro(SliceRotationLocked, bool); itkGetMacro(SliceRotationLocked, bool); itkBooleanMacro(SliceRotationLocked); /** * \brief Adjusts the numerical range of the slice stepper according to * the current geometry orientation of this SNC's SlicedGeometry. */ void AdjustSliceStepperRange(); protected: SliceNavigationController(const char * type = NULL); virtual ~SliceNavigationController(); template static void buildstring( mitkIpPicDescriptor *pic, itk::Point p, std::string &s, T = 0) { std::string value; std::stringstream stream; stream.imbue(std::locale::classic()); stream<=0 && p[1] >=0 && p[2]>=0) && (unsigned int)p[0] < pic->n[0] && (unsigned int)p[1] < pic->n[1] && (unsigned int)p[2] < pic->n[2] ) { if(pic->bpe!=24) { stream<<(((T*) pic->data)[ p[0] + p[1]*pic->n[0] + p[2]*pic->n[0]*pic->n[1] ]); } else { stream<<(((T*) pic->data)[p[0]*3 + 0 + p[1]*pic->n[0]*3 + p[2]*pic->n[0]*pic->n[1]*3 ]); stream<<(((T*) pic->data)[p[0]*3 + 1 + p[1]*pic->n[0]*3 + p[2]*pic->n[0]*pic->n[1]*3 ]); stream<<(((T*) pic->data)[p[0]*3 + 2 + p[1]*pic->n[0]*3 + p[2]*pic->n[0]*pic->n[1]*3 ]); } s = stream.str(); } else { s+= "point out of data"; } }; mitk::Geometry3D::ConstPointer m_InputWorldGeometry; mitk::Geometry3D::Pointer m_ExtendedInputWorldGeometry; mitk::TimeSlicedGeometry::Pointer m_CreatedWorldGeometry; ViewDirection m_ViewDirection; ViewDirection m_DefaultViewDirection; mitk::RenderingManager::Pointer m_RenderingManager; mitk::BaseRenderer *m_Renderer; itkSetMacro(Top, bool); itkGetMacro(Top, bool); itkBooleanMacro(Top); itkSetMacro(FrontSide, bool); itkGetMacro(FrontSide, bool); itkBooleanMacro(FrontSide); itkSetMacro(Rotated, bool); itkGetMacro(Rotated, bool); itkBooleanMacro(Rotated); bool m_Top; bool m_FrontSide; bool m_Rotated; bool m_BlockUpdate; bool m_SliceLocked; bool m_SliceRotationLocked; unsigned int m_OldPos; }; } // namespace mitk #endif /* SLICENAVIGATIONCONTROLLER_H_HEADER_INCLUDED_C1C55A2F */ diff --git a/Core/Code/DataManagement/mitkPlaneGeometry.cpp b/Core/Code/DataManagement/mitkPlaneGeometry.cpp index c6241f734f..ad0d1184c3 100644 --- a/Core/Code/DataManagement/mitkPlaneGeometry.cpp +++ b/Core/Code/DataManagement/mitkPlaneGeometry.cpp @@ -1,755 +1,778 @@ /*========================================================================= 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 "mitkPlaneGeometry.h" #include "mitkPlaneOperation.h" #include "mitkInteractionConst.h" #include "mitkLine.h" #include #include namespace mitk { mitk::PlaneGeometry::PlaneGeometry() { Initialize(); } mitk::PlaneGeometry::~PlaneGeometry() { } void PlaneGeometry::Initialize() { Superclass::Initialize(); } void PlaneGeometry::EnsurePerpendicularNormal(mitk::AffineTransform3D *transform) { //ensure row(2) of transform to be perpendicular to plane, keep length. VnlVector normal = vnl_cross_3d( transform->GetMatrix().GetVnlMatrix().get_column(0), transform->GetMatrix().GetVnlMatrix().get_column(1) ); normal.normalize(); ScalarType len = transform->GetMatrix() .GetVnlMatrix().get_column(2).two_norm(); if (len==0) len = 1; normal*=len; Matrix3D matrix = transform->GetMatrix(); matrix.GetVnlMatrix().set_column(2, normal); transform->SetMatrix(matrix); } void PlaneGeometry::SetIndexToWorldTransform(mitk::AffineTransform3D *transform) { EnsurePerpendicularNormal(transform); Superclass::SetIndexToWorldTransform(transform); } void PlaneGeometry::SetBounds(const BoundingBox::BoundsArrayType &bounds) { //currently the unit rectangle must be starting at the origin [0,0] assert(bounds[0]==0); assert(bounds[2]==0); //the unit rectangle must be two-dimensional assert(bounds[1]>0); assert(bounds[3]>0); Superclass::SetBounds(bounds); } void PlaneGeometry::IndexToWorld( const Point2D &pt_units, Point2D &pt_mm ) const { pt_mm[0]=m_ScaleFactorMMPerUnitX*pt_units[0]; pt_mm[1]=m_ScaleFactorMMPerUnitY*pt_units[1]; } void PlaneGeometry::WorldToIndex( const Point2D &pt_mm, Point2D &pt_units ) const { pt_units[0]=pt_mm[0]*(1.0/m_ScaleFactorMMPerUnitX); pt_units[1]=pt_mm[1]*(1.0/m_ScaleFactorMMPerUnitY); } void PlaneGeometry::IndexToWorld( const Point2D &atPt2d_units, const Vector2D &vec_units, Vector2D &vec_mm) const { MITK_WARN<<"Warning! Call of the deprecated function PlaneGeometry::IndexToWorld(point, vec, vec). Use PlaneGeometry::IndexToWorld(vec, vec) instead!"; this->IndexToWorld(vec_units, vec_mm); } void PlaneGeometry::IndexToWorld(const Vector2D &vec_units, Vector2D &vec_mm) const { vec_mm[0] = m_ScaleFactorMMPerUnitX * vec_units[0]; vec_mm[1] = m_ScaleFactorMMPerUnitY * vec_units[1]; } void PlaneGeometry::WorldToIndex( const Point2D &atPt2d_mm, const Vector2D &vec_mm, Vector2D &vec_units) const { MITK_WARN<<"Warning! Call of the deprecated function PlaneGeometry::WorldToIndex(point, vec, vec). Use PlaneGeometry::WorldToIndex(vec, vec) instead!"; this->WorldToIndex(vec_mm, vec_units); } void PlaneGeometry::WorldToIndex( const Vector2D &vec_mm, Vector2D &vec_units) const { vec_units[0] = vec_mm[0] * ( 1.0 / m_ScaleFactorMMPerUnitX ); vec_units[1] = vec_mm[1] * ( 1.0 / m_ScaleFactorMMPerUnitY ); } void PlaneGeometry::InitializeStandardPlane( mitk::ScalarType width, ScalarType height, const Vector3D & spacing, PlaneGeometry::PlaneOrientation planeorientation, ScalarType zPosition, bool frontside, bool rotated ) { AffineTransform3D::Pointer transform; transform = AffineTransform3D::New(); AffineTransform3D::MatrixType matrix; AffineTransform3D::MatrixType::InternalMatrixType &vnlmatrix = matrix.GetVnlMatrix(); vnlmatrix.set_identity(); vnlmatrix(0,0) = spacing[0]; vnlmatrix(1,1) = spacing[1]; vnlmatrix(2,2) = spacing[2]; transform->SetIdentity(); transform->SetMatrix(matrix); InitializeStandardPlane(width, height, transform.GetPointer(), planeorientation, zPosition, frontside, rotated); } void PlaneGeometry::InitializeStandardPlane( mitk::ScalarType width, ScalarType height, const AffineTransform3D* transform, PlaneGeometry::PlaneOrientation planeorientation, ScalarType zPosition, bool frontside, bool rotated ) { Superclass::Initialize(); //construct standard view Point3D origin; VnlVector rightDV(3), bottomDV(3); origin.Fill(0); int normalDirection; switch(planeorientation) { case Transversal: if(frontside) { if(rotated==false) { FillVector3D(origin, 0, 0, zPosition); FillVector3D(rightDV, 1, 0, 0); FillVector3D(bottomDV, 0, 1, 0); } else { FillVector3D(origin, width, height, zPosition); FillVector3D(rightDV, -1, 0, 0); FillVector3D(bottomDV, 0, -1, 0); } } else { if(rotated==false) { FillVector3D(origin, width, 0, zPosition); FillVector3D(rightDV, -1, 0, 0); FillVector3D(bottomDV, 0, 1, 0); } else { FillVector3D(origin, 0, height, zPosition); FillVector3D(rightDV, 1, 0, 0); FillVector3D(bottomDV, 0, -1, 0); } } normalDirection = 2; break; case Frontal: if(frontside) { if(rotated==false) { FillVector3D(origin, 0, zPosition, 0); FillVector3D(rightDV, 1, 0, 0); FillVector3D(bottomDV, 0, 0, 1); } else { FillVector3D(origin, width, zPosition, height); FillVector3D(rightDV, -1, 0, 0); FillVector3D(bottomDV, 0, 0, -1); } } else { if(rotated==false) { FillVector3D(origin, width, zPosition, 0); FillVector3D(rightDV, -1, 0, 0); FillVector3D(bottomDV, 0, 0, 1); } else { FillVector3D(origin, 0, zPosition, height); FillVector3D(rightDV, 1, 0, 0); FillVector3D(bottomDV, 0, 0, -1); } } normalDirection = 1; break; case Sagittal: if(frontside) { if(rotated==false) { FillVector3D(origin, zPosition, 0, 0); FillVector3D(rightDV, 0, 1, 0); FillVector3D(bottomDV, 0, 0, 1); } else { FillVector3D(origin, zPosition, width, height); FillVector3D(rightDV, 0, -1, 0); FillVector3D(bottomDV, 0, 0, -1); } } else { if(rotated==false) { FillVector3D(origin, zPosition, width, 0); FillVector3D(rightDV, 0, -1, 0); FillVector3D(bottomDV, 0, 0, 1); } else { FillVector3D(origin, zPosition, 0, height); FillVector3D(rightDV, 0, 1, 0); FillVector3D(bottomDV, 0, 0, -1); } } normalDirection = 0; break; default: itkExceptionMacro("unknown PlaneOrientation"); } if ( transform != NULL ) { origin = transform->TransformPoint( origin ); rightDV = transform->TransformVector( rightDV ); bottomDV = transform->TransformVector( bottomDV ); } ScalarType bounds[6]= { 0, width, 0, height, 0, 1 }; this->SetBounds( bounds ); if ( transform == NULL ) { this->SetMatrixByVectors( rightDV, bottomDV ); } else { this->SetMatrixByVectors( rightDV, bottomDV, transform->GetMatrix().GetVnlMatrix() .get_column(normalDirection).magnitude() ); } this->SetOrigin(origin); } void PlaneGeometry::InitializeStandardPlane( const Geometry3D *geometry3D, PlaneOrientation planeorientation, ScalarType zPosition, bool frontside, bool rotated ) { this->SetReferenceGeometry( const_cast< Geometry3D * >( geometry3D ) ); ScalarType width, height; const BoundingBox::BoundsArrayType& boundsarray = geometry3D->GetBoundingBox()->GetBounds(); Vector3D originVector; FillVector3D(originVector, boundsarray[0], boundsarray[2], boundsarray[4]); - MITK_DEBUG << originVector; if(geometry3D->GetImageGeometry()) { FillVector3D( originVector, originVector[0] - 0.5, originVector[1] - 0.5, originVector[2] - 0.5 ); } switch(planeorientation) { case Transversal: width = geometry3D->GetExtent(0); height = geometry3D->GetExtent(1); break; case Frontal: width = geometry3D->GetExtent(0); height = geometry3D->GetExtent(2); break; case Sagittal: width = geometry3D->GetExtent(1); height = geometry3D->GetExtent(2); break; default: itkExceptionMacro("unknown PlaneOrientation"); } InitializeStandardPlane( width, height, geometry3D->GetIndexToWorldTransform(), planeorientation, zPosition, frontside, rotated ); ScalarType bounds[6]= { 0, width, 0, height, 0, 1 }; this->SetBounds( bounds ); Point3D origin; originVector = geometry3D->GetIndexToWorldTransform() ->TransformVector( originVector ); origin = GetOrigin() + originVector; SetOrigin(origin); } void PlaneGeometry::InitializeStandardPlane( const Geometry3D *geometry3D, bool top, PlaneOrientation planeorientation, bool frontside, bool rotated ) { ScalarType zPosition; switch(planeorientation) { case Transversal: zPosition = (top ? 0.5 : geometry3D->GetExtent(2)-1+0.5); break; case Frontal: zPosition = (top ? 0.5 : geometry3D->GetExtent(1)-1+0.5); break; case Sagittal: zPosition = (top ? 0.5 : geometry3D->GetExtent(0)-1+0.5); break; default: itkExceptionMacro("unknown PlaneOrientation"); } InitializeStandardPlane( geometry3D, planeorientation, zPosition, frontside, rotated ); } void PlaneGeometry::InitializeStandardPlane( const Vector3D &rightVector, const Vector3D &downVector, const Vector3D *spacing ) { InitializeStandardPlane( rightVector.Get_vnl_vector(), downVector.Get_vnl_vector(), spacing ); } void PlaneGeometry::InitializeStandardPlane( const VnlVector& rightVector, const VnlVector &downVector, const Vector3D *spacing ) { ScalarType width = rightVector.magnitude(); ScalarType height = downVector.magnitude(); InitializeStandardPlane( width, height, rightVector, downVector, spacing ); } void PlaneGeometry::InitializeStandardPlane( mitk::ScalarType width, ScalarType height, const Vector3D &rightVector, const Vector3D &downVector, const Vector3D *spacing ) { InitializeStandardPlane( width, height, rightVector.Get_vnl_vector(), downVector.Get_vnl_vector(), spacing ); } void PlaneGeometry::InitializeStandardPlane( mitk::ScalarType width, ScalarType height, const VnlVector &rightVector, const VnlVector &downVector, const Vector3D *spacing ) { assert(width > 0); assert(height > 0); VnlVector rightDV = rightVector; rightDV.normalize(); VnlVector downDV = downVector; downDV.normalize(); VnlVector normal = vnl_cross_3d(rightVector, downVector); normal.normalize(); if(spacing!=NULL) { rightDV *= (*spacing)[0]; downDV *= (*spacing)[1]; normal *= (*spacing)[2]; } AffineTransform3D::Pointer transform = AffineTransform3D::New(); Matrix3D matrix; matrix.GetVnlMatrix().set_column(0, rightDV); matrix.GetVnlMatrix().set_column(1, downDV); matrix.GetVnlMatrix().set_column(2, normal); transform->SetMatrix(matrix); transform->SetOffset(m_IndexToWorldTransform->GetOffset()); ScalarType bounds[6] = { 0, width, 0, height, 0, 1 }; this->SetBounds( bounds ); this->SetIndexToWorldTransform( transform ); } void PlaneGeometry::InitializePlane( const Point3D &origin, const Vector3D &normal ) { VnlVector rightVectorVnl(3), downVectorVnl; if( Equal( normal[1], 0.0f ) == false ) { FillVector3D( rightVectorVnl, 1.0f, -normal[0]/normal[1], 0.0f ); rightVectorVnl.normalize(); } else { FillVector3D( rightVectorVnl, 0.0f, 1.0f, 0.0f ); } downVectorVnl = vnl_cross_3d( normal.Get_vnl_vector(), rightVectorVnl ); downVectorVnl.normalize(); InitializeStandardPlane( rightVectorVnl, downVectorVnl ); SetOrigin(origin); } void PlaneGeometry::SetMatrixByVectors( const VnlVector &rightVector, const VnlVector &downVector, ScalarType thickness ) { VnlVector normal = vnl_cross_3d(rightVector, downVector); normal.normalize(); normal *= thickness; AffineTransform3D::Pointer transform = AffineTransform3D::New(); Matrix3D matrix; matrix.GetVnlMatrix().set_column(0, rightVector); matrix.GetVnlMatrix().set_column(1, downVector); matrix.GetVnlMatrix().set_column(2, normal); transform->SetMatrix(matrix); transform->SetOffset(m_IndexToWorldTransform->GetOffset()); SetIndexToWorldTransform(transform); } Vector3D PlaneGeometry::GetNormal() const { Vector3D frontToBack; frontToBack.Set_vnl_vector( m_IndexToWorldTransform ->GetMatrix().GetVnlMatrix().get_column(2) ); return frontToBack; } VnlVector PlaneGeometry::GetNormalVnl() const { return m_IndexToWorldTransform ->GetMatrix().GetVnlMatrix().get_column(2); } ScalarType PlaneGeometry::DistanceFromPlane( const Point3D &pt3d_mm ) const { return fabs(SignedDistance( pt3d_mm )); } ScalarType PlaneGeometry::SignedDistance( const Point3D &pt3d_mm ) const { return SignedDistanceFromPlane(pt3d_mm); } bool PlaneGeometry::IsAbove( const Point3D &pt3d_mm ) const { return SignedDistanceFromPlane(pt3d_mm) > 0; } bool PlaneGeometry::IntersectionLine( const PlaneGeometry* plane, Line3D& crossline ) const { Vector3D normal = this->GetNormal(); normal.Normalize(); Vector3D planeNormal = plane->GetNormal(); planeNormal.Normalize(); Vector3D direction = itk::CrossProduct( normal, planeNormal ); if ( direction.GetSquaredNorm() < eps ) return false; crossline.SetDirection( direction ); double N1dN2 = normal * planeNormal; double determinant = 1.0 - N1dN2 * N1dN2; Vector3D origin = this->GetOrigin().GetVectorFromOrigin(); Vector3D planeOrigin = plane->GetOrigin().GetVectorFromOrigin(); double d1 = normal * origin; double d2 = planeNormal * planeOrigin; double c1 = ( d1 - d2 * N1dN2 ) / determinant; double c2 = ( d2 - d1 * N1dN2 ) / determinant; Vector3D p = normal * c1 + planeNormal * c2; crossline.GetPoint().Get_vnl_vector() = p.Get_vnl_vector(); return true; } unsigned int PlaneGeometry::IntersectWithPlane2D( const PlaneGeometry* plane, Point2D& lineFrom, Point2D &lineTo ) const { Line3D crossline; if ( this->IntersectionLine( plane, crossline ) == false ) return 0; Point2D point2; Vector2D direction2; this->Map( crossline.GetPoint(), point2 ); this->Map( crossline.GetPoint(), crossline.GetDirection(), direction2 ); return Line3D::RectangleLineIntersection( 0, 0, GetExtentInMM(0), GetExtentInMM(1), point2, direction2, lineFrom, lineTo ); } double PlaneGeometry::Angle( const PlaneGeometry *plane ) const { return angle(plane->GetMatrixColumn(2), GetMatrixColumn(2)); } double PlaneGeometry::Angle( const Line3D &line ) const { return vnl_math::pi_over_2 - angle( line.GetDirection().Get_vnl_vector(), GetMatrixColumn(2) ); } bool PlaneGeometry::IntersectionPoint( const Line3D &line, Point3D &intersectionPoint ) const { Vector3D planeNormal = this->GetNormal(); planeNormal.Normalize(); Vector3D lineDirection = line.GetDirection(); lineDirection.Normalize(); double t = planeNormal * lineDirection; if ( fabs( t ) < eps ) { return false; } Vector3D diff; diff = this->GetOrigin() - line.GetPoint(); t = ( planeNormal * diff ) / t; intersectionPoint = line.GetPoint() + lineDirection * t; return true; } bool PlaneGeometry::IntersectionPointParam( const Line3D &line, double &t ) const { Vector3D planeNormal = this->GetNormal(); Vector3D lineDirection = line.GetDirection(); t = planeNormal * lineDirection; if ( fabs( t ) < eps ) { return false; } Vector3D diff; diff = this->GetOrigin() - line.GetPoint(); t = ( planeNormal * diff ) / t; return true; } bool PlaneGeometry::IsParallel( const PlaneGeometry *plane ) const { return ( (Angle(plane) < 10.0 * mitk::sqrteps ) || ( Angle(plane) > ( vnl_math::pi - 10.0 * sqrteps ) ) ) ; } bool PlaneGeometry::IsOnPlane( const Point3D &point ) const { return Distance(point) < eps; } bool PlaneGeometry::IsOnPlane( const Line3D &line ) const { return ( (Distance( line.GetPoint() ) < eps) && (Distance( line.GetPoint2() ) < eps) ); } bool PlaneGeometry::IsOnPlane( const PlaneGeometry *plane ) const { return ( IsParallel( plane ) && (Distance( plane->GetOrigin() ) < eps) ); } Point3D PlaneGeometry::ProjectPointOntoPlane( const Point3D& pt ) const { ScalarType len = this->GetNormalVnl().two_norm(); return pt - this->GetNormal() * this->SignedDistanceFromPlane( pt ) / len; } AffineGeometryFrame3D::Pointer PlaneGeometry::Clone() const { Self::Pointer newGeometry = new PlaneGeometry(*this); newGeometry->UnRegister(); return newGeometry.GetPointer(); } void PlaneGeometry::ExecuteOperation( Operation *operation ) { vtkTransform *transform = vtkTransform::New(); transform->SetMatrix( m_VtkMatrix ); switch ( operation->GetOperationType() ) { case OpORIENT: { mitk::PlaneOperation *planeOp = dynamic_cast< mitk::PlaneOperation * >( operation ); if ( planeOp == NULL ) { return; } Point3D center = planeOp->GetPoint(); Vector3D orientationVector = planeOp->GetNormal(); Vector3D defaultVector; FillVector3D( defaultVector, 0.0, 0.0, 1.0 ); Vector3D rotationAxis = itk::CrossProduct( orientationVector, defaultVector ); //vtkFloatingPointType rotationAngle = acos( orientationVector[2] / orientationVector.GetNorm() ); vtkFloatingPointType rotationAngle = atan2( (double) rotationAxis.GetNorm(), (double) (orientationVector * defaultVector) ); rotationAngle *= 180.0 / vnl_math::pi; transform->PostMultiply(); transform->Identity(); transform->Translate( center[0], center[1], center[2] ); transform->RotateWXYZ( rotationAngle, rotationAxis[0], rotationAxis[1], rotationAxis[2] ); transform->Translate( -center[0], -center[1], -center[2] ); break; } + case OpRESTOREPLANEPOSITION: + { + RestorePlanePositionOperation *op = dynamic_cast< mitk::RestorePlanePositionOperation* >(operation); + if(op == NULL) + { + return; + } + AffineTransform3D::Pointer transform2 = AffineTransform3D::New(); + Matrix3D matrix; + matrix.GetVnlMatrix().set_column(0, op->GetTransform()->GetMatrix().GetVnlMatrix().get_column(0)); + matrix.GetVnlMatrix().set_column(1, op->GetTransform()->GetMatrix().GetVnlMatrix().get_column(1)); + matrix.GetVnlMatrix().set_column(2, op->GetTransform()->GetMatrix().GetVnlMatrix().get_column(2)); + transform2->SetMatrix(matrix); + Vector3D offset = op->GetTransform()->GetOffset(); + transform2->SetOffset(offset); + + this->SetIndexToWorldTransform(transform2); + ScalarType bounds[6] = {0, op->GetWidth(), 0, op->GetHeight(), 0 ,1 }; + this->SetBounds(bounds); + TransferItkToVtkTransform(); + this->Modified(); + transform->Delete(); + return; + } default: Superclass::ExecuteOperation( operation ); transform->Delete(); return; } m_VtkMatrix->DeepCopy(transform->GetMatrix()); this->TransferVtkToItkTransform(); this->Modified(); transform->Delete(); } void PlaneGeometry::PrintSelf( std::ostream& os, itk::Indent indent ) const { Superclass::PrintSelf(os,indent); os << indent << " Normal: " << GetNormal() << std::endl; } } // namespace diff --git a/Core/Code/DataManagement/mitkPlaneGeometry.h b/Core/Code/DataManagement/mitkPlaneGeometry.h index 7b2c6a0477..a36b1b1119 100644 --- a/Core/Code/DataManagement/mitkPlaneGeometry.h +++ b/Core/Code/DataManagement/mitkPlaneGeometry.h @@ -1,422 +1,423 @@ /*========================================================================= 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 PLANEGEOMETRY_H_HEADER_INCLUDED_C1C68A2C #define PLANEGEOMETRY_H_HEADER_INCLUDED_C1C68A2C #include #include "mitkGeometry2D.h" +#include "mitkRestorePlanePositionOperation.h" #include namespace mitk { template < class TCoordRep, unsigned int NPointDimension > class Line; typedef Line Line3D; /** * \brief Describes a two-dimensional, rectangular plane * * \ingroup Geometry */ class MITK_CORE_EXPORT PlaneGeometry : public Geometry2D { public: mitkClassMacro(PlaneGeometry,Geometry2D); /** Method for creation through the object factory. */ itkNewMacro(Self); enum PlaneOrientation { Transversal, Sagittal, Frontal }; virtual void IndexToWorld(const Point2D &pt_units, Point2D &pt_mm) const; virtual void WorldToIndex(const Point2D &pt_mm, Point2D &pt_units) const; //##Documentation //## @brief Convert (continuous or discrete) index coordinates of a \em vector //## \a vec_units to world coordinates (in mm) //## @deprecated First parameter (Point2D) is not used. If possible, please use void IndexToWorld(const mitk::Vector2D& vec_units, mitk::Vector2D& vec_mm) const. //## For further information about coordinates types, please see the Geometry documentation virtual void IndexToWorld(const mitk::Point2D &atPt2d_untis, const mitk::Vector2D &vec_units, mitk::Vector2D &vec_mm) const; //##Documentation //## @brief Convert (continuous or discrete) index coordinates of a \em vector //## \a vec_units to world coordinates (in mm) //## For further information about coordinates types, please see the Geometry documentation virtual void IndexToWorld(const mitk::Vector2D &vec_units, mitk::Vector2D &vec_mm) const; //##Documentation //## @brief Convert world coordinates (in mm) of a \em vector //## \a vec_mm to (continuous!) index coordinates. //## @deprecated First parameter (Point2D) is not used. If possible, please use void WorldToIndex(const mitk::Vector2D& vec_mm, mitk::Vector2D& vec_units) const. //## For further information about coordinates types, please see the Geometry documentation virtual void WorldToIndex(const mitk::Point2D &atPt2d_mm, const mitk::Vector2D &vec_mm, mitk::Vector2D &vec_units) const; //##Documentation //## @brief Convert world coordinates (in mm) of a \em vector //## \a vec_mm to (continuous!) index coordinates. //## For further information about coordinates types, please see the Geometry documentation virtual void WorldToIndex(const mitk::Vector2D &vec_mm, mitk::Vector2D &vec_units) const; virtual void Initialize(); /** * \brief Initialize a plane with orientation \a planeorientation * (default: transversal) with respect to \a geometry3D (default: identity). * Spacing also taken from \a geometry3D. * * \warning A former version of this method created a geometry with unit * spacing. For unit spacing use * * \code * // for in-plane unit spacing: * thisgeometry->SetSizeInUnits(thisgeometry->GetExtentInMM(0), * thisgeometry->GetExtentInMM(1)); * // additionally, for unit spacing in normal direction (former version * // did not do this): * thisgeometry->SetExtentInMM(2, 1.0); * \endcode */ virtual void InitializeStandardPlane( const Geometry3D* geometry3D, PlaneOrientation planeorientation = Transversal, ScalarType zPosition = 0, bool frontside=true, bool rotated=false ); /** * \brief Initialize a plane with orientation \a planeorientation * (default: transversal) with respect to \a geometry3D (default: identity). * Spacing also taken from \a geometry3D. * * \param top if \a true, create plane at top, otherwise at bottom * (for PlaneOrientation Transversal, for other plane locations respectively) */ virtual void InitializeStandardPlane( const Geometry3D* geometry3D, bool top, PlaneOrientation planeorientation = Transversal, bool frontside=true, bool rotated=false ); /** * \brief Initialize a plane with orientation \a planeorientation * (default: transversal) with respect to \a transform (default: identity) * given width and height in units. * */ virtual void InitializeStandardPlane( ScalarType width, ScalarType height, const AffineTransform3D* transform = NULL, PlaneOrientation planeorientation = Transversal, ScalarType zPosition = 0, bool frontside=true, bool rotated=false ); /** * \brief Initialize plane with orientation \a planeorientation * (default: transversal) given width, height and spacing. * */ virtual void InitializeStandardPlane( ScalarType width, ScalarType height, const Vector3D & spacing, PlaneOrientation planeorientation = Transversal, ScalarType zPosition = 0, bool frontside = true, bool rotated = false ); /** * \brief Initialize plane by width and height in pixels, right-/down-vector * (itk) to describe orientation in world-space (vectors will be normalized) * and spacing (default: 1.0 mm in all directions). * * The vectors are normalized and multiplied by the respective spacing before * they are set in the matrix. */ virtual void InitializeStandardPlane( ScalarType width, ScalarType height, const Vector3D& rightVector, const Vector3D& downVector, const Vector3D *spacing = NULL ); /** * \brief Initialize plane by width and height in pixels, * right-/down-vector (vnl) to describe orientation in world-space (vectors * will be normalized) and spacing (default: 1.0 mm in all directions). * * The vectors are normalized and multiplied by the respective spacing * before they are set in the matrix. */ virtual void InitializeStandardPlane( ScalarType width, ScalarType height, const VnlVector& rightVector, const VnlVector& downVector, const Vector3D * spacing = NULL ); /** * \brief Initialize plane by right-/down-vector (itk) and spacing * (default: 1.0 mm in all directions). * * The length of the right-/-down-vector is used as width/height in units, * respectively. Then, the vectors are normalized and multiplied by the * respective spacing before they are set in the matrix. */ virtual void InitializeStandardPlane( const Vector3D& rightVector, const Vector3D& downVector, const Vector3D * spacing = NULL ); /** * \brief Initialize plane by right-/down-vector (vnl) and spacing * (default: 1.0 mm in all directions). * * The length of the right-/-down-vector is used as width/height in units, * respectively. Then, the vectors are normalized and multiplied by the * respective spacing before they are set in the matrix. */ virtual void InitializeStandardPlane( const VnlVector& rightVector, const VnlVector& downVector, const Vector3D * spacing = NULL ); /** * \brief Initialize plane by origin and normal (size is 1.0 mm in * all directions, direction of right-/down-vector valid but * undefined). * */ virtual void InitializePlane( const Point3D& origin, const Vector3D& normal); /** * \brief Initialize plane by right-/down-vector. * * \warning The vectors are set into the matrix as they are, * \em without normalization! */ void SetMatrixByVectors( const VnlVector& rightVector, const VnlVector& downVector, ScalarType thickness=1.0 ); /** * \brief Change \a transform so that the third column of the * transform-martix is perpendicular to the first two columns * */ static void EnsurePerpendicularNormal( AffineTransform3D* transform ); /** * \brief Normal of the plane * */ Vector3D GetNormal() const; /** * \brief Normal of the plane as VnlVector * */ VnlVector GetNormalVnl() const; virtual ScalarType SignedDistance( const Point3D& pt3d_mm ) const; virtual bool IsAbove( const Point3D& pt3d_mm ) const; /** * \brief Distance of the point from the plane * (bounding-box \em not considered) * */ ScalarType DistanceFromPlane( const Point3D& pt3d_mm ) const ; /** * \brief Signed distance of the point from the plane * (bounding-box \em not considered) * * > 0 : point is in the direction of the direction vector. */ inline ScalarType SignedDistanceFromPlane( const Point3D& pt3d_mm ) const { ScalarType len = GetNormalVnl().two_norm(); if( len == 0 ) return 0; return (pt3d_mm-GetOrigin())*GetNormal() / len; } /** * \brief Distance of the plane from another plane * (bounding-box \em not considered) * * Result is 0 if planes are not parallel. */ ScalarType DistanceFromPlane(const PlaneGeometry* plane) const { return fabs(SignedDistanceFromPlane(plane)); } /** * \brief Signed distance of the plane from another plane * (bounding-box \em not considered) * * Result is 0 if planes are not parallel. */ inline ScalarType SignedDistanceFromPlane( const PlaneGeometry *plane ) const { if(IsParallel(plane)) { return SignedDistance(plane->GetOrigin()); } return 0; } /** * \brief Calculate the intersecting line of two planes * * \return \a true planes are intersecting * \return \a false planes do not intersect */ bool IntersectionLine( const PlaneGeometry *plane, Line3D &crossline ) const; /** * \brief Calculate two points where another plane intersects the border of this plane * * \return number of intersection points (0..2). First interection point (if existing) * is returned in \a lineFrom, second in \a lineTo. */ unsigned int IntersectWithPlane2D(const PlaneGeometry *plane, Point2D &lineFrom, Point2D &lineTo ) const ; /** * \brief Calculate the angle between two planes * * \return angle in radiants */ double Angle( const PlaneGeometry *plane ) const; /** * \brief Calculate the angle between the plane and a line * * \return angle in radiants */ double Angle( const Line3D &line ) const; /** * \brief Calculate intersection point between the plane and a line * * \param intersectionPoint intersection point * \return \a true if \em unique intersection exists, i.e., if line * is \em not on or parallel to the plane */ bool IntersectionPoint( const Line3D &line, Point3D &intersectionPoint ) const; /** * \brief Calculate line parameter of intersection point between the * plane and a line * * \param t parameter of line: intersection point is * line.GetPoint()+t*line.GetDirection() * \return \a true if \em unique intersection exists, i.e., if line * is \em not on or parallel to the plane */ bool IntersectionPointParam( const Line3D &line, double &t ) const; /** * \brief Returns whether the plane is parallel to another plane * * @return true iff the normal vectors both point to the same or exactly oposit direction */ bool IsParallel( const PlaneGeometry *plane ) const; /** * \brief Returns whether the point is on the plane * (bounding-box \em not considered) */ bool IsOnPlane( const Point3D &point ) const; /** * \brief Returns whether the line is on the plane * (bounding-box \em not considered) */ bool IsOnPlane( const Line3D &line ) const; /** * \brief Returns whether the plane is on the plane * (bounding-box \em not considered) * * @return true iff the normal vector of the planes point to the same or the exactly oposit direction and * the distance of the planes is < eps * */ bool IsOnPlane( const PlaneGeometry *plane ) const; /** * \brief Returns the lot from the point to the plane */ Point3D ProjectPointOntoPlane( const Point3D &pt ) const; virtual void SetIndexToWorldTransform( AffineTransform3D *transform); virtual void SetBounds( const BoundingBox::BoundsArrayType &bounds ); AffineGeometryFrame3D::Pointer Clone() const; /** Implements operation to re-orient the plane */ virtual void ExecuteOperation( Operation *operation ); protected: PlaneGeometry(); virtual ~PlaneGeometry(); virtual void PrintSelf( std::ostream &os, itk::Indent indent ) const; private: /** * \brief Compares plane with another plane: \a true if IsOnPlane * (bounding-box \em not considered) */ virtual bool operator==( const PlaneGeometry * ) const { return false; }; /** * \brief Compares plane with another plane: \a false if IsOnPlane * (bounding-box \em not considered) */ virtual bool operator!=( const PlaneGeometry * ) const { return false; }; }; } // namespace mitk #endif /* PLANEGEOMETRY_H_HEADER_INCLUDED_C1C68A2C */ diff --git a/Core/Code/DataManagement/mitkRestorePlanePositionOperation.cpp b/Core/Code/DataManagement/mitkRestorePlanePositionOperation.cpp new file mode 100644 index 0000000000..b15f11010d --- /dev/null +++ b/Core/Code/DataManagement/mitkRestorePlanePositionOperation.cpp @@ -0,0 +1,67 @@ +/*========================================================================= + +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 "mitkRestorePlanePositionOperation.h" + +namespace mitk +{ + +RestorePlanePositionOperation +::RestorePlanePositionOperation( OperationType operationType, float width, float height, Vector3D spacing , unsigned int pos, Vector3D direction, AffineTransform3D::Pointer transform/*, PlaneOrientation orientation*/) +: Operation(operationType), m_Width( width ), m_Height( height ), m_Spacing( spacing ), m_Pos(pos), m_DirectionVector(direction), m_Transform(transform)/*, m_Orientation(orientation)*/ +{ + //MITK_INFO<<"Width: "<InitializeSlicedGeometry( m_Slices ); + this->InitializeSlicedGeometry( m_Slices ); } mitk::SlicedGeometry3D::SlicedGeometry3D(const SlicedGeometry3D& other) : Superclass(other), -m_EvenlySpaced( other.m_EvenlySpaced ), -m_Slices( other.m_Slices ), -m_ReferenceGeometry( other.m_ReferenceGeometry ), -m_SliceNavigationController( other.m_SliceNavigationController ) + m_EvenlySpaced( other.m_EvenlySpaced ), + m_Slices( other.m_Slices ), + m_ReferenceGeometry( other.m_ReferenceGeometry ), + m_SliceNavigationController( other.m_SliceNavigationController ) { m_DirectionVector.Fill(0); - SetSpacing( other.GetSpacing() ); - SetDirectionVector( other.GetDirectionVector() ); - - if ( m_EvenlySpaced ) - { - AffineGeometryFrame3D::Pointer geometry = other.m_Geometry2Ds[0]->Clone(); - Geometry2D* geometry2D = dynamic_cast(geometry.GetPointer()); - assert(geometry2D!=NULL); - SetGeometry2D(geometry2D, 0); - } - else - { - unsigned int s; - for ( s = 0; s < other.m_Slices; ++s ) + SetSpacing( other.GetSpacing() ); + SetDirectionVector( other.GetDirectionVector() ); + + if ( m_EvenlySpaced ) + { + AffineGeometryFrame3D::Pointer geometry = other.m_Geometry2Ds[0]->Clone(); + Geometry2D* geometry2D = dynamic_cast(geometry.GetPointer()); + assert(geometry2D!=NULL); + SetGeometry2D(geometry2D, 0); + } + else + { + unsigned int s; + for ( s = 0; s < other.m_Slices; ++s ) + { + if ( other.m_Geometry2Ds[s].IsNull() ) { - if ( other.m_Geometry2Ds[s].IsNull() ) - { - assert(other.m_EvenlySpaced); - m_Geometry2Ds[s] = NULL; - } - else - { - AffineGeometryFrame3D::Pointer geometry = other.m_Geometry2Ds[s]->Clone(); - Geometry2D* geometry2D = dynamic_cast(geometry.GetPointer()); - assert(geometry2D!=NULL); - SetGeometry2D(geometry2D, s); - } + assert(other.m_EvenlySpaced); + m_Geometry2Ds[s] = NULL; } - } + else + { + AffineGeometryFrame3D::Pointer geometry = other.m_Geometry2Ds[s]->Clone(); + Geometry2D* geometry2D = dynamic_cast(geometry.GetPointer()); + assert(geometry2D!=NULL); + SetGeometry2D(geometry2D, s); + } + } + } } mitk::SlicedGeometry3D::~SlicedGeometry3D() { } mitk::Geometry2D * mitk::SlicedGeometry3D::GetGeometry2D( int s ) const { - mitk::Geometry2D::Pointer geometry2D = NULL; - - if ( this->IsValidSlice(s) ) - { - geometry2D = m_Geometry2Ds[s]; - - // If (a) m_EvenlySpaced==true, (b) we don't have a Geometry2D stored - // for the requested slice, and (c) the first slice (s=0) - // is a PlaneGeometry instance, then we calculate the geometry of the - // requested as the plane of the first slice shifted by m_Spacing[2]*s - // in the direction of m_DirectionVector. - if ( (m_EvenlySpaced) && (geometry2D.IsNull()) ) + mitk::Geometry2D::Pointer geometry2D = NULL; + + if ( this->IsValidSlice(s) ) + { + geometry2D = m_Geometry2Ds[s]; + + // If (a) m_EvenlySpaced==true, (b) we don't have a Geometry2D stored + // for the requested slice, and (c) the first slice (s=0) + // is a PlaneGeometry instance, then we calculate the geometry of the + // requested as the plane of the first slice shifted by m_Spacing[2]*s + // in the direction of m_DirectionVector. + if ( (m_EvenlySpaced) && (geometry2D.IsNull()) ) + { + PlaneGeometry *firstSlice = dynamic_cast< PlaneGeometry * > ( + m_Geometry2Ds[0].GetPointer() ); + + if ( firstSlice != NULL ) { - PlaneGeometry *firstSlice = dynamic_cast< PlaneGeometry * > ( - m_Geometry2Ds[0].GetPointer() ); - - if ( firstSlice != NULL ) - { - if ( (m_DirectionVector[0] == 0.0) - && (m_DirectionVector[1] == 0.0) - && (m_DirectionVector[2] == 0.0) ) - { - - m_DirectionVector = firstSlice->GetNormal(); - m_DirectionVector.Normalize(); - } - - Vector3D direction; - direction = m_DirectionVector * m_Spacing[2]; - - mitk::PlaneGeometry::Pointer requestedslice; - requestedslice = static_cast< mitk::PlaneGeometry * >( - firstSlice->Clone().GetPointer() ); - - - requestedslice->SetOrigin( - requestedslice->GetOrigin() + direction * s ); - - geometry2D = requestedslice; - m_Geometry2Ds[s] = geometry2D; - } + if ( (m_DirectionVector[0] == 0.0) + && (m_DirectionVector[1] == 0.0) + && (m_DirectionVector[2] == 0.0) ) + { + m_DirectionVector = firstSlice->GetNormal(); + m_DirectionVector.Normalize(); + } + + Vector3D direction; + direction = m_DirectionVector * m_Spacing[2]; + + mitk::PlaneGeometry::Pointer requestedslice; + requestedslice = static_cast< mitk::PlaneGeometry * >( + firstSlice->Clone().GetPointer() ); + + requestedslice->SetOrigin( + requestedslice->GetOrigin() + direction * s ); + + geometry2D = requestedslice; + m_Geometry2Ds[s] = geometry2D; } - return geometry2D; - } - else - { - return NULL; - } + } + return geometry2D; + } + else + { + return NULL; + } } const mitk::BoundingBox * mitk::SlicedGeometry3D::GetBoundingBox() const { - assert(m_BoundingBox.IsNotNull()); - return m_BoundingBox.GetPointer(); + assert(m_BoundingBox.IsNotNull()); + return m_BoundingBox.GetPointer(); } bool mitk::SlicedGeometry3D::SetGeometry2D( mitk::Geometry2D *geometry2D, int s ) { - if ( this->IsValidSlice(s) ) - { - m_Geometry2Ds[s] = geometry2D; - m_Geometry2Ds[s]->SetReferenceGeometry( m_ReferenceGeometry ); - return true; - } - return false; + if ( this->IsValidSlice(s) ) + { + m_Geometry2Ds[s] = geometry2D; + m_Geometry2Ds[s]->SetReferenceGeometry( m_ReferenceGeometry ); + return true; + } + return false; } void mitk::SlicedGeometry3D::InitializeSlicedGeometry( unsigned int slices ) { - Superclass::Initialize(); - m_Slices = slices; - - Geometry2D::Pointer gnull = NULL; - m_Geometry2Ds.assign( m_Slices, gnull ); + Superclass::Initialize(); + m_Slices = slices; - Vector3D spacing; - spacing.Fill( 1.0 ); - this->SetSpacing( spacing ); + Geometry2D::Pointer gnull = NULL; + m_Geometry2Ds.assign( m_Slices, gnull ); + + Vector3D spacing; + spacing.Fill( 1.0 ); + this->SetSpacing( spacing ); - m_DirectionVector.Fill( 0 ); + m_DirectionVector.Fill( 0 ); } void mitk::SlicedGeometry3D::InitializeEvenlySpaced( - mitk::Geometry2D* geometry2D, unsigned int slices, bool flipped ) + mitk::Geometry2D* geometry2D, unsigned int slices, bool flipped ) { - assert( geometry2D != NULL ); - this->InitializeEvenlySpaced( - geometry2D, geometry2D->GetExtentInMM(2)/geometry2D->GetExtent(2), - slices, flipped ); + assert( geometry2D != NULL ); + this->InitializeEvenlySpaced( + geometry2D, geometry2D->GetExtentInMM(2)/geometry2D->GetExtent(2), + slices, flipped ); } void mitk::SlicedGeometry3D::InitializeEvenlySpaced( - mitk::Geometry2D* geometry2D, mitk::ScalarType zSpacing, - unsigned int slices, bool flipped ) + mitk::Geometry2D* geometry2D, mitk::ScalarType zSpacing, + unsigned int slices, bool flipped ) { - assert( geometry2D != NULL ); - assert( geometry2D->GetExtent(0) > 0 ); - assert( geometry2D->GetExtent(1) > 0 ); - - geometry2D->Register(); - - Superclass::Initialize(); - m_Slices = slices; - - BoundingBox::BoundsArrayType bounds = geometry2D->GetBounds(); - bounds[4] = 0; - bounds[5] = slices; - - // clear and reserve - Geometry2D::Pointer gnull = NULL; - m_Geometry2Ds.assign( m_Slices, gnull ); - - Vector3D directionVector = geometry2D->GetAxisVector(2); - directionVector.Normalize(); - directionVector *= zSpacing; - - if ( flipped == false ) - { - // Normally we should use the following four lines to create a copy of - // the transform contrained in geometry2D, because it may not be changed - // by us. But we know that SetSpacing creates a new transform without - // changing the old (coming from geometry2D), so we can use the fifth - // line instead. We check this at (**). - // - // AffineTransform3D::Pointer transform = AffineTransform3D::New(); - // transform->SetMatrix(geometry2D->GetIndexToWorldTransform()->GetMatrix()); - // transform->SetOffset(geometry2D->GetIndexToWorldTransform()->GetOffset()); - // SetIndexToWorldTransform(transform); - - m_IndexToWorldTransform = const_cast< AffineTransform3D * >( - geometry2D->GetIndexToWorldTransform() ); - } - else - { - directionVector *= -1.0; - m_IndexToWorldTransform = AffineTransform3D::New(); - m_IndexToWorldTransform->SetMatrix( - geometry2D->GetIndexToWorldTransform()->GetMatrix() ); - - AffineTransform3D::OutputVectorType scaleVector; - FillVector3D(scaleVector, 1.0, 1.0, -1.0); - m_IndexToWorldTransform->Scale(scaleVector, true); - m_IndexToWorldTransform->SetOffset( - geometry2D->GetIndexToWorldTransform()->GetOffset() ); - } - - mitk::Vector3D spacing; - FillVector3D( spacing, - geometry2D->GetExtentInMM(0) / bounds[1], - geometry2D->GetExtentInMM(1) / bounds[3], - zSpacing ); - - // Ensure that spacing differs from m_Spacing to make SetSpacing change the - // matrix. - m_Spacing[2] = zSpacing - 1; - - this->SetDirectionVector( directionVector ); - this->SetBounds( bounds ); - this->SetGeometry2D( geometry2D, 0 ); - this->SetSpacing( spacing ); - this->SetEvenlySpaced(); - this->SetTimeBounds( geometry2D->GetTimeBounds() ); - - assert(m_IndexToWorldTransform.GetPointer() - != geometry2D->GetIndexToWorldTransform()); // (**) see above. - - this->SetFrameOfReferenceID( geometry2D->GetFrameOfReferenceID() ); - this->SetImageGeometry( geometry2D->GetImageGeometry() ); - - geometry2D->UnRegister(); + assert( geometry2D != NULL ); + assert( geometry2D->GetExtent(0) > 0 ); + assert( geometry2D->GetExtent(1) > 0 ); + + geometry2D->Register(); + + Superclass::Initialize(); + m_Slices = slices; + + BoundingBox::BoundsArrayType bounds = geometry2D->GetBounds(); + bounds[4] = 0; + bounds[5] = slices; + + // clear and reserve + Geometry2D::Pointer gnull = NULL; + m_Geometry2Ds.assign( m_Slices, gnull ); + + Vector3D directionVector = geometry2D->GetAxisVector(2); + directionVector.Normalize(); + directionVector *= zSpacing; + + if ( flipped == false ) + { + // Normally we should use the following four lines to create a copy of + // the transform contrained in geometry2D, because it may not be changed + // by us. But we know that SetSpacing creates a new transform without + // changing the old (coming from geometry2D), so we can use the fifth + // line instead. We check this at (**). + // + // AffineTransform3D::Pointer transform = AffineTransform3D::New(); + // transform->SetMatrix(geometry2D->GetIndexToWorldTransform()->GetMatrix()); + // transform->SetOffset(geometry2D->GetIndexToWorldTransform()->GetOffset()); + // SetIndexToWorldTransform(transform); + + m_IndexToWorldTransform = const_cast< AffineTransform3D * >( + geometry2D->GetIndexToWorldTransform() ); + } + else + { + directionVector *= -1.0; + m_IndexToWorldTransform = AffineTransform3D::New(); + m_IndexToWorldTransform->SetMatrix( + geometry2D->GetIndexToWorldTransform()->GetMatrix() ); + + AffineTransform3D::OutputVectorType scaleVector; + FillVector3D(scaleVector, 1.0, 1.0, -1.0); + m_IndexToWorldTransform->Scale(scaleVector, true); + m_IndexToWorldTransform->SetOffset( + geometry2D->GetIndexToWorldTransform()->GetOffset() ); + } + + mitk::Vector3D spacing; + FillVector3D( spacing, + geometry2D->GetExtentInMM(0) / bounds[1], + geometry2D->GetExtentInMM(1) / bounds[3], + zSpacing ); + + // Ensure that spacing differs from m_Spacing to make SetSpacing change the + // matrix. + m_Spacing[2] = zSpacing - 1; + + this->SetDirectionVector( directionVector ); + this->SetBounds( bounds ); + this->SetGeometry2D( geometry2D, 0 ); + this->SetSpacing( spacing ); + this->SetEvenlySpaced(); + this->SetTimeBounds( geometry2D->GetTimeBounds() ); + + assert(m_IndexToWorldTransform.GetPointer() + != geometry2D->GetIndexToWorldTransform()); // (**) see above. + + this->SetFrameOfReferenceID( geometry2D->GetFrameOfReferenceID() ); + this->SetImageGeometry( geometry2D->GetImageGeometry() ); + + geometry2D->UnRegister(); } void mitk::SlicedGeometry3D::InitializePlanes( - const mitk::Geometry3D *geometry3D, - mitk::PlaneGeometry::PlaneOrientation planeorientation, - bool top, bool frontside, bool rotated ) + const mitk::Geometry3D *geometry3D, + mitk::PlaneGeometry::PlaneOrientation planeorientation, + bool top, bool frontside, bool rotated ) { - m_ReferenceGeometry = const_cast< Geometry3D * >( geometry3D ); - - PlaneGeometry::Pointer planeGeometry = mitk::PlaneGeometry::New(); - planeGeometry->InitializeStandardPlane( - geometry3D, top, planeorientation, frontside, rotated ); - - ScalarType viewSpacing = 1; - unsigned int slices = 1; - - switch ( planeorientation ) - { - case PlaneGeometry::Transversal: + m_ReferenceGeometry = const_cast< Geometry3D * >( geometry3D ); + + PlaneGeometry::Pointer planeGeometry = mitk::PlaneGeometry::New(); + planeGeometry->InitializeStandardPlane( + geometry3D, top, planeorientation, frontside, rotated ); + + ScalarType viewSpacing = 1; + unsigned int slices = 1; + + switch ( planeorientation ) + { + case PlaneGeometry::Transversal: viewSpacing = geometry3D->GetSpacing()[2]; slices = (unsigned int) geometry3D->GetExtent( 2 ); break; - case PlaneGeometry::Frontal: + case PlaneGeometry::Frontal: viewSpacing = geometry3D->GetSpacing()[1]; slices = (unsigned int) geometry3D->GetExtent( 1 ); break; - case PlaneGeometry::Sagittal: + case PlaneGeometry::Sagittal: viewSpacing = geometry3D->GetSpacing()[0]; slices = (unsigned int) geometry3D->GetExtent( 0 ); break; - default: + default: itkExceptionMacro("unknown PlaneOrientation"); - } + } - mitk::Vector3D normal = this->AdjustNormal( planeGeometry->GetNormal() ); + mitk::Vector3D normal = this->AdjustNormal( planeGeometry->GetNormal() ); - ScalarType directedExtent = + ScalarType directedExtent = fabs( m_ReferenceGeometry->GetExtentInMM( 0 ) * normal[0] ) - + fabs( m_ReferenceGeometry->GetExtentInMM( 1 ) * normal[1] ) - + fabs( m_ReferenceGeometry->GetExtentInMM( 2 ) * normal[2] ); - - if ( directedExtent >= viewSpacing ) - { - slices = static_cast< int >(directedExtent / viewSpacing + 0.5); - } - else - { - slices = 1; - } - - bool flipped = (top == false); - - if ( frontside == false ) - { - flipped = !flipped; - } - if ( planeorientation == PlaneGeometry::Frontal ) - { - flipped = !flipped; - } - - this->InitializeEvenlySpaced( planeGeometry, viewSpacing, slices, flipped ); + + fabs( m_ReferenceGeometry->GetExtentInMM( 1 ) * normal[1] ) + + fabs( m_ReferenceGeometry->GetExtentInMM( 2 ) * normal[2] ); + + if ( directedExtent >= viewSpacing ) + { + slices = static_cast< int >(directedExtent / viewSpacing + 0.5); + } + else + { + slices = 1; + } + + bool flipped = (top == false); + + if ( frontside == false ) + { + flipped = !flipped; + } + if ( planeorientation == PlaneGeometry::Frontal ) + { + flipped = !flipped; + } + + this->InitializeEvenlySpaced( planeGeometry, viewSpacing, slices, flipped ); } void mitk::SlicedGeometry3D ::ReinitializePlanes( const Point3D ¢er, const Point3D &referencePoint ) { - // Need a reference frame to align the rotated planes - if ( !m_ReferenceGeometry ) - { - return; - } - - // Get first plane of plane stack - PlaneGeometry *firstPlane = - dynamic_cast< PlaneGeometry * >( m_Geometry2Ds[0].GetPointer() ); - - // If plane stack is empty, exit - if ( firstPlane == NULL ) - { - return; - } - - // Calculate the "directed" spacing when taking the plane (defined by its axes - // vectors and normal) as the reference coordinate frame. - // - // This is done by calculating the radius of the ellipsoid defined by the - // original volume spacing axes, in the direction of the respective axis of the - // reference frame. - mitk::Vector3D axis0 = firstPlane->GetAxisVector(0); - mitk::Vector3D axis1 = firstPlane->GetAxisVector(1); - mitk::Vector3D normal = firstPlane->GetNormal(); - normal.Normalize(); - - Vector3D spacing; - spacing[0] = this->CalculateSpacing( axis0 ); - spacing[1] = this->CalculateSpacing( axis1 ); - spacing[2] = this->CalculateSpacing( normal ); - - Superclass::SetSpacing( spacing ); - - - // Now we need to calculate the number of slices in the plane's normal - // direction, so that the entire volume is covered. This is done by first - // calculating the dot product between the volume diagonal (the maximum - // distance inside the volume) and the normal, and dividing this value by - // the directed spacing calculated above. - ScalarType directedExtent = + // Need a reference frame to align the rotated planes + if ( !m_ReferenceGeometry ) + { + return; + } + + // Get first plane of plane stack + PlaneGeometry *firstPlane = + dynamic_cast< PlaneGeometry * >( m_Geometry2Ds[0].GetPointer() ); + + // If plane stack is empty, exit + if ( firstPlane == NULL ) + { + return; + } + + // Calculate the "directed" spacing when taking the plane (defined by its axes + // vectors and normal) as the reference coordinate frame. + // + // This is done by calculating the radius of the ellipsoid defined by the + // original volume spacing axes, in the direction of the respective axis of the + // reference frame. + mitk::Vector3D axis0 = firstPlane->GetAxisVector(0); + mitk::Vector3D axis1 = firstPlane->GetAxisVector(1); + mitk::Vector3D normal = firstPlane->GetNormal(); + normal.Normalize(); + + Vector3D spacing; + spacing[0] = this->CalculateSpacing( axis0 ); + spacing[1] = this->CalculateSpacing( axis1 ); + spacing[2] = this->CalculateSpacing( normal ); + + Superclass::SetSpacing( spacing ); + + + // Now we need to calculate the number of slices in the plane's normal + // direction, so that the entire volume is covered. This is done by first + // calculating the dot product between the volume diagonal (the maximum + // distance inside the volume) and the normal, and dividing this value by + // the directed spacing calculated above. + ScalarType directedExtent = fabs( m_ReferenceGeometry->GetExtentInMM( 0 ) * normal[0] ) - + fabs( m_ReferenceGeometry->GetExtentInMM( 1 ) * normal[1] ) - + fabs( m_ReferenceGeometry->GetExtentInMM( 2 ) * normal[2] ); - - if ( directedExtent >= spacing[2] ) - { - m_Slices = static_cast< unsigned int >(directedExtent / spacing[2] + 0.5); - } - else - { - m_Slices = 1; - } - - // The origin of our "first plane" needs to be adapted to this new extent. - // To achieve this, we first calculate the current distance to the volume's - // center, and then shift the origin in the direction of the normal by the - // difference between this distance and half of the new extent. - double centerOfRotationDistance = - firstPlane->SignedDistanceFromPlane( center ); - - if ( centerOfRotationDistance > 0 ) - { - firstPlane->SetOrigin( firstPlane->GetOrigin() - + normal * (centerOfRotationDistance - directedExtent / 2.0) - ); - m_DirectionVector = normal; - } - else - { - firstPlane->SetOrigin( firstPlane->GetOrigin() - + normal * (directedExtent / 2.0 + centerOfRotationDistance) - ); - m_DirectionVector = -normal; - } - - // Now we adjust this distance according with respect to the given reference - // point: we need to make sure that the point is touched by one slice of the - // new slice stack. - double referencePointDistance = - firstPlane->SignedDistanceFromPlane( referencePoint ); - - int referencePointSlice = static_cast< int >( - referencePointDistance / spacing[2]); - - double alignmentValue = - referencePointDistance / spacing[2] - referencePointSlice; - - firstPlane->SetOrigin( - firstPlane->GetOrigin() + normal * alignmentValue * spacing[2] ); - - - // Finally, we can clear the previous geometry stack and initialize it with - // our re-initialized "first plane". - m_Geometry2Ds.assign( m_Slices, Geometry2D::Pointer( NULL ) ); - - if ( m_Slices > 0 ) - { - m_Geometry2Ds[0] = firstPlane; - } - - // Reinitialize SNC with new number of slices - m_SliceNavigationController->GetSlice()->SetSteps( m_Slices ); - - this->Modified(); + + fabs( m_ReferenceGeometry->GetExtentInMM( 1 ) * normal[1] ) + + fabs( m_ReferenceGeometry->GetExtentInMM( 2 ) * normal[2] ); + + if ( directedExtent >= spacing[2] ) + { + m_Slices = static_cast< unsigned int >(directedExtent / spacing[2] + 0.5); + } + else + { + m_Slices = 1; + } + + // The origin of our "first plane" needs to be adapted to this new extent. + // To achieve this, we first calculate the current distance to the volume's + // center, and then shift the origin in the direction of the normal by the + // difference between this distance and half of the new extent. + double centerOfRotationDistance = + firstPlane->SignedDistanceFromPlane( center ); + + if ( centerOfRotationDistance > 0 ) + { + firstPlane->SetOrigin( firstPlane->GetOrigin() + + normal * (centerOfRotationDistance - directedExtent / 2.0) + ); + m_DirectionVector = normal; + } + else + { + firstPlane->SetOrigin( firstPlane->GetOrigin() + + normal * (directedExtent / 2.0 + centerOfRotationDistance) + ); + m_DirectionVector = -normal; + } + + // Now we adjust this distance according with respect to the given reference + // point: we need to make sure that the point is touched by one slice of the + // new slice stack. + double referencePointDistance = + firstPlane->SignedDistanceFromPlane( referencePoint ); + + int referencePointSlice = static_cast< int >( + referencePointDistance / spacing[2]); + + double alignmentValue = + referencePointDistance / spacing[2] - referencePointSlice; + + firstPlane->SetOrigin( + firstPlane->GetOrigin() + normal * alignmentValue * spacing[2] ); + + + // Finally, we can clear the previous geometry stack and initialize it with + // our re-initialized "first plane". + m_Geometry2Ds.assign( m_Slices, Geometry2D::Pointer( NULL ) ); + + if ( m_Slices > 0 ) + { + m_Geometry2Ds[0] = firstPlane; + } + + // Reinitialize SNC with new number of slices + m_SliceNavigationController->GetSlice()->SetSteps( m_Slices ); + + this->Modified(); } double mitk::SlicedGeometry3D::CalculateSpacing( const mitk::Vector3D &d ) const { - // Need the spacing of the underlying dataset / geometry - if ( !m_ReferenceGeometry ) - { - return 1.0; - } - - // The following can be derived from the ellipsoid equation - // - // 1 = x^2/a^2 + y^2/b^2 + z^2/c^2 - // - // where (a,b,c) = spacing of original volume (ellipsoid radii) - // and (x,y,z) = scaled coordinates of vector d (according to ellipsoid) - // - const mitk::Vector3D &spacing = m_ReferenceGeometry->GetSpacing(); - - double scaling = d[0]*d[0] / (spacing[0] * spacing[0]) - + d[1]*d[1] / (spacing[1] * spacing[1]) - + d[2]*d[2] / (spacing[2] * spacing[2]); - - scaling = sqrt( scaling ); - - return ( sqrt( d[0]*d[0] + d[1]*d[1] + d[2]*d[2] ) / scaling ); + // Need the spacing of the underlying dataset / geometry + if ( !m_ReferenceGeometry ) + { + return 1.0; + } + + // The following can be derived from the ellipsoid equation + // + // 1 = x^2/a^2 + y^2/b^2 + z^2/c^2 + // + // where (a,b,c) = spacing of original volume (ellipsoid radii) + // and (x,y,z) = scaled coordinates of vector d (according to ellipsoid) + // + const mitk::Vector3D &spacing = m_ReferenceGeometry->GetSpacing(); + + double scaling = d[0]*d[0] / (spacing[0] * spacing[0]) + + d[1]*d[1] / (spacing[1] * spacing[1]) + + d[2]*d[2] / (spacing[2] * spacing[2]); + + scaling = sqrt( scaling ); + + return ( sqrt( d[0]*d[0] + d[1]*d[1] + d[2]*d[2] ) / scaling ); } mitk::Vector3D mitk::SlicedGeometry3D::AdjustNormal( const mitk::Vector3D &normal ) const { - Geometry3D::TransformType::Pointer inverse = Geometry3D::TransformType::New(); - m_ReferenceGeometry->GetIndexToWorldTransform()->GetInverse( inverse ); - - Vector3D transformedNormal = inverse->TransformVector( normal ); + Geometry3D::TransformType::Pointer inverse = Geometry3D::TransformType::New(); + m_ReferenceGeometry->GetIndexToWorldTransform()->GetInverse( inverse ); + + Vector3D transformedNormal = inverse->TransformVector( normal ); - transformedNormal.Normalize(); - return transformedNormal; + transformedNormal.Normalize(); + return transformedNormal; } void mitk::SlicedGeometry3D::SetImageGeometry( const bool isAnImageGeometry ) { - Superclass::SetImageGeometry( isAnImageGeometry ); - - mitk::Geometry3D* geometry; - - unsigned int s; - for ( s = 0; s < m_Slices; ++s ) - { - geometry = m_Geometry2Ds[s]; - if ( geometry!=NULL ) - { - geometry->SetImageGeometry( isAnImageGeometry ); - } - } + Superclass::SetImageGeometry( isAnImageGeometry ); + + mitk::Geometry3D* geometry; + + unsigned int s; + for ( s = 0; s < m_Slices; ++s ) + { + geometry = m_Geometry2Ds[s]; + if ( geometry!=NULL ) + { + geometry->SetImageGeometry( isAnImageGeometry ); + } + } } void mitk::SlicedGeometry3D::ChangeImageGeometryConsideringOriginOffset( const bool isAnImageGeometry ) { - mitk::Geometry3D* geometry; - - unsigned int s; - for ( s = 0; s < m_Slices; ++s ) - { - geometry = m_Geometry2Ds[s]; - if ( geometry!=NULL ) - { - geometry->ChangeImageGeometryConsideringOriginOffset( isAnImageGeometry ); - } - } - - Superclass::ChangeImageGeometryConsideringOriginOffset( isAnImageGeometry ); + mitk::Geometry3D* geometry; + + unsigned int s; + for ( s = 0; s < m_Slices; ++s ) + { + geometry = m_Geometry2Ds[s]; + if ( geometry!=NULL ) + { + geometry->ChangeImageGeometryConsideringOriginOffset( isAnImageGeometry ); + } + } + + Superclass::ChangeImageGeometryConsideringOriginOffset( isAnImageGeometry ); } bool mitk::SlicedGeometry3D::IsValidSlice( int s ) const { - return ((s >= 0) && (s < (int)m_Slices)); + return ((s >= 0) && (s < (int)m_Slices)); } void mitk::SlicedGeometry3D::SetReferenceGeometry( Geometry3D *referenceGeometry ) { - m_ReferenceGeometry = referenceGeometry; + m_ReferenceGeometry = referenceGeometry; - std::vector::iterator it; + std::vector::iterator it; - for ( it = m_Geometry2Ds.begin(); it != m_Geometry2Ds.end(); ++it ) - { - (*it)->SetReferenceGeometry( referenceGeometry ); - } + for ( it = m_Geometry2Ds.begin(); it != m_Geometry2Ds.end(); ++it ) + { + (*it)->SetReferenceGeometry( referenceGeometry ); + } } void mitk::SlicedGeometry3D::SetSpacing( const mitk::Vector3D &aSpacing ) { - bool hasEvenlySpacedPlaneGeometry = false; - mitk::Point3D origin; - mitk::Vector3D rightDV, bottomDV; - BoundingBox::BoundsArrayType bounds; - - assert(aSpacing[0]>0 && aSpacing[1]>0 && aSpacing[2]>0); - - // In case of evenly-spaced data: re-initialize instances of Geometry2D, - // since the spacing influences them - if ((m_EvenlySpaced) && (m_Geometry2Ds.size() > 0)) - { - mitk::Geometry2D::ConstPointer firstGeometry = - m_Geometry2Ds[0].GetPointer(); - - const PlaneGeometry *planeGeometry = - dynamic_cast< const PlaneGeometry * >( firstGeometry.GetPointer() ); - - if (planeGeometry != NULL ) - { - this->WorldToIndex( planeGeometry->GetOrigin(), origin ); - this->WorldToIndex( planeGeometry->GetAxisVector(0), rightDV ); - this->WorldToIndex( planeGeometry->GetAxisVector(1), bottomDV ); - - bounds = planeGeometry->GetBounds(); - hasEvenlySpacedPlaneGeometry = true; - } - } - - Superclass::SetSpacing(aSpacing); - - mitk::Geometry2D::Pointer firstGeometry; - - // In case of evenly-spaced data: re-initialize instances of Geometry2D, - // since the spacing influences them - if ( hasEvenlySpacedPlaneGeometry ) - { - //create planeGeometry according to new spacing - this->IndexToWorld( origin, origin ); - this->IndexToWorld( rightDV, rightDV ); - this->IndexToWorld( bottomDV, bottomDV ); - - mitk::PlaneGeometry::Pointer planeGeometry = mitk::PlaneGeometry::New(); - planeGeometry->SetImageGeometry( this->GetImageGeometry() ); - - planeGeometry->SetReferenceGeometry( m_ReferenceGeometry ); - planeGeometry->InitializeStandardPlane( - rightDV.Get_vnl_vector(), bottomDV.Get_vnl_vector(), &m_Spacing ); - planeGeometry->SetOrigin(origin); - planeGeometry->SetBounds(bounds); - - firstGeometry = planeGeometry; - } - else if ( (m_EvenlySpaced) && (m_Geometry2Ds.size() > 0) ) - { - firstGeometry = m_Geometry2Ds[0].GetPointer(); - } - - //clear and reserve - Geometry2D::Pointer gnull=NULL; - m_Geometry2Ds.assign(m_Slices, gnull); - - if ( m_Slices > 0 ) - { - m_Geometry2Ds[0] = firstGeometry; - } - - this->Modified(); + bool hasEvenlySpacedPlaneGeometry = false; + mitk::Point3D origin; + mitk::Vector3D rightDV, bottomDV; + BoundingBox::BoundsArrayType bounds; + + assert(aSpacing[0]>0 && aSpacing[1]>0 && aSpacing[2]>0); + + // In case of evenly-spaced data: re-initialize instances of Geometry2D, + // since the spacing influences them + if ((m_EvenlySpaced) && (m_Geometry2Ds.size() > 0)) + { + mitk::Geometry2D::ConstPointer firstGeometry = + m_Geometry2Ds[0].GetPointer(); + + const PlaneGeometry *planeGeometry = + dynamic_cast< const PlaneGeometry * >( firstGeometry.GetPointer() ); + + if (planeGeometry != NULL ) + { + this->WorldToIndex( planeGeometry->GetOrigin(), origin ); + this->WorldToIndex( planeGeometry->GetAxisVector(0), rightDV ); + this->WorldToIndex( planeGeometry->GetAxisVector(1), bottomDV ); + + bounds = planeGeometry->GetBounds(); + hasEvenlySpacedPlaneGeometry = true; + } + } + + Superclass::SetSpacing(aSpacing); + + mitk::Geometry2D::Pointer firstGeometry; + + // In case of evenly-spaced data: re-initialize instances of Geometry2D, + // since the spacing influences them + if ( hasEvenlySpacedPlaneGeometry ) + { + //create planeGeometry according to new spacing + this->IndexToWorld( origin, origin ); + this->IndexToWorld( rightDV, rightDV ); + this->IndexToWorld( bottomDV, bottomDV ); + + mitk::PlaneGeometry::Pointer planeGeometry = mitk::PlaneGeometry::New(); + planeGeometry->SetImageGeometry( this->GetImageGeometry() ); + + planeGeometry->SetReferenceGeometry( m_ReferenceGeometry ); + planeGeometry->InitializeStandardPlane( + rightDV.Get_vnl_vector(), bottomDV.Get_vnl_vector(), &m_Spacing ); + planeGeometry->SetOrigin(origin); + planeGeometry->SetBounds(bounds); + + firstGeometry = planeGeometry; + } + else if ( (m_EvenlySpaced) && (m_Geometry2Ds.size() > 0) ) + { + firstGeometry = m_Geometry2Ds[0].GetPointer(); + } + + //clear and reserve + Geometry2D::Pointer gnull=NULL; + m_Geometry2Ds.assign(m_Slices, gnull); + + if ( m_Slices > 0 ) + { + m_Geometry2Ds[0] = firstGeometry; + } + + this->Modified(); } void mitk::SlicedGeometry3D ::SetSliceNavigationController( SliceNavigationController *snc ) { - m_SliceNavigationController = snc; + m_SliceNavigationController = snc; } mitk::SliceNavigationController * mitk::SlicedGeometry3D::GetSliceNavigationController() { - return m_SliceNavigationController; + return m_SliceNavigationController; } void mitk::SlicedGeometry3D::SetEvenlySpaced(bool on) { - if(m_EvenlySpaced!=on) - { - m_EvenlySpaced=on; - this->Modified(); - } + if(m_EvenlySpaced!=on) + { + m_EvenlySpaced=on; + this->Modified(); + } } void mitk::SlicedGeometry3D ::SetDirectionVector( const mitk::Vector3D& directionVector ) { Vector3D newDir = directionVector; newDir.Normalize(); if ( newDir != m_DirectionVector ) - { + { m_DirectionVector = newDir; - this->Modified(); - } + this->Modified(); + } } void mitk::SlicedGeometry3D::SetTimeBounds( const mitk::TimeBounds& timebounds ) { - Superclass::SetTimeBounds( timebounds ); - - unsigned int s; - for ( s = 0; s < m_Slices; ++s ) - { - if(m_Geometry2Ds[s].IsNotNull()) - { - m_Geometry2Ds[s]->SetTimeBounds( timebounds ); - } - } - m_TimeBounds = timebounds; + Superclass::SetTimeBounds( timebounds ); + + unsigned int s; + for ( s = 0; s < m_Slices; ++s ) + { + if(m_Geometry2Ds[s].IsNotNull()) + { + m_Geometry2Ds[s]->SetTimeBounds( timebounds ); + } + } + m_TimeBounds = timebounds; } mitk::AffineGeometryFrame3D::Pointer mitk::SlicedGeometry3D::Clone() const { - Self::Pointer newGeometry = new SlicedGeometry3D(*this); - newGeometry->UnRegister(); - return newGeometry.GetPointer(); + Self::Pointer newGeometry = new SlicedGeometry3D(*this); + newGeometry->UnRegister(); + return newGeometry.GetPointer(); } void mitk::SlicedGeometry3D::PrintSelf( std::ostream& os, itk::Indent indent ) const { - Superclass::PrintSelf(os,indent); - os << indent << " EvenlySpaced: " << m_EvenlySpaced << std::endl; - if ( m_EvenlySpaced ) - { - os << indent << " DirectionVector: " << m_DirectionVector << std::endl; - } - os << indent << " Slices: " << m_Slices << std::endl; - - os << std::endl; - os << indent << " GetGeometry2D(0): "; - if ( this->GetGeometry2D(0) == NULL ) - { - os << "NULL" << std::endl; - } - else - { - this->GetGeometry2D(0)->Print(os, indent); - } + Superclass::PrintSelf(os,indent); + os << indent << " EvenlySpaced: " << m_EvenlySpaced << std::endl; + if ( m_EvenlySpaced ) + { + os << indent << " DirectionVector: " << m_DirectionVector << std::endl; + } + os << indent << " Slices: " << m_Slices << std::endl; + + os << std::endl; + os << indent << " GetGeometry2D(0): "; + if ( this->GetGeometry2D(0) == NULL ) + { + os << "NULL" << std::endl; + } + else + { + this->GetGeometry2D(0)->Print(os, indent); + } } void mitk::SlicedGeometry3D::ExecuteOperation(Operation* operation) { - switch ( operation->GetOperationType() ) - { - case OpNOTHING: - break; - - case OpROTATE: - if ( m_EvenlySpaced ) + switch ( operation->GetOperationType() ) + { + case OpNOTHING: + break; + + case OpROTATE: + if ( m_EvenlySpaced ) + { + // Need a reference frame to align the rotation + if ( m_ReferenceGeometry ) { - // Need a reference frame to align the rotation - if ( m_ReferenceGeometry ) - { - // Clear all generated geometries and then rotate only the first slice. - // The other slices will be re-generated on demand - - // Save first slice - Geometry2D::Pointer geometry2D = m_Geometry2Ds[0]; - - RotationOperation *rotOp = dynamic_cast< RotationOperation * >( operation ); - - // Generate a RotationOperation using the dataset center instead of - // the supplied rotation center. This is necessary so that the rotated - // zero-plane does not shift away. The supplied center is instead used - // to adjust the slice stack afterwards. - Point3D center = m_ReferenceGeometry->GetCenter(); - - RotationOperation centeredRotation( - rotOp->GetOperationType(), - center, - rotOp->GetVectorOfRotation(), - rotOp->GetAngleOfRotation() - ); - - // Rotate first slice - geometry2D->ExecuteOperation( ¢eredRotation ); - - // Clear the slice stack and adjust it according to the center of - // the dataset and the supplied rotation center (see documentation of - // ReinitializePlanes) - this->ReinitializePlanes( center, rotOp->GetCenterOfRotation() ); - - if ( m_SliceNavigationController ) - { - m_SliceNavigationController->SelectSliceByPoint( - rotOp->GetCenterOfRotation() ); - m_SliceNavigationController->AdjustSliceStepperRange(); - } - - Geometry3D::ExecuteOperation( ¢eredRotation ); - } + // Clear all generated geometries and then rotate only the first slice. + // The other slices will be re-generated on demand + + // Save first slice + Geometry2D::Pointer geometry2D = m_Geometry2Ds[0]; + + RotationOperation *rotOp = dynamic_cast< RotationOperation * >( operation ); + + // Generate a RotationOperation using the dataset center instead of + // the supplied rotation center. This is necessary so that the rotated + // zero-plane does not shift away. The supplied center is instead used + // to adjust the slice stack afterwards. + Point3D center = m_ReferenceGeometry->GetCenter(); + + RotationOperation centeredRotation( + rotOp->GetOperationType(), + center, + rotOp->GetVectorOfRotation(), + rotOp->GetAngleOfRotation() + ); + + // Rotate first slice + geometry2D->ExecuteOperation( ¢eredRotation ); + + // Clear the slice stack and adjust it according to the center of + // the dataset and the supplied rotation center (see documentation of + // ReinitializePlanes) + this->ReinitializePlanes( center, rotOp->GetCenterOfRotation() ); + + geometry2D->SetSpacing(this->GetSpacing()); + + if ( m_SliceNavigationController ) + { + m_SliceNavigationController->SelectSliceByPoint( + rotOp->GetCenterOfRotation() ); + m_SliceNavigationController->AdjustSliceStepperRange(); + } + + Geometry3D::ExecuteOperation( ¢eredRotation ); } - else + } + else + { + // Reach through to all slices + for (std::vector::iterator iter = m_Geometry2Ds.begin(); + iter != m_Geometry2Ds.end(); + ++iter) { - // Reach through to all slices - for (std::vector::iterator iter = m_Geometry2Ds.begin(); - iter != m_Geometry2Ds.end(); - ++iter) - { - (*iter)->ExecuteOperation(operation); - } + (*iter)->ExecuteOperation(operation); } - break; + } + break; - case OpORIENT: - if ( m_EvenlySpaced ) - { - // Save first slice - Geometry2D::Pointer geometry2D = m_Geometry2Ds[0]; + case OpORIENT: + if ( m_EvenlySpaced ) + { + // Save first slice + Geometry2D::Pointer geometry2D = m_Geometry2Ds[0]; - PlaneGeometry *planeGeometry = dynamic_cast< PlaneGeometry * >( - geometry2D.GetPointer() ); + PlaneGeometry *planeGeometry = dynamic_cast< PlaneGeometry * >( + geometry2D.GetPointer() ); - PlaneOperation *planeOp = dynamic_cast< PlaneOperation * >( operation ); + PlaneOperation *planeOp = dynamic_cast< PlaneOperation * >( operation ); - // Need a PlaneGeometry, a PlaneOperation and a reference frame to - // carry out the re-orientation - if ( m_ReferenceGeometry && planeGeometry && planeOp ) - { - // Clear all generated geometries and then rotate only the first slice. - // The other slices will be re-generated on demand + // Need a PlaneGeometry, a PlaneOperation and a reference frame to + // carry out the re-orientation + if ( m_ReferenceGeometry && planeGeometry && planeOp ) + { + // Clear all generated geometries and then rotate only the first slice. + // The other slices will be re-generated on demand - // Generate a RotationOperation by calculating the angle between - // the current and the requested slice orientation - Point3D center = m_ReferenceGeometry->GetCenter(); + // Generate a RotationOperation by calculating the angle between + // the current and the requested slice orientation + Point3D center = m_ReferenceGeometry->GetCenter(); - const mitk::Vector3D ¤tNormal = planeGeometry->GetNormal(); - const mitk::Vector3D &newNormal = planeOp->GetNormal(); + const mitk::Vector3D ¤tNormal = planeGeometry->GetNormal(); + const mitk::Vector3D &newNormal = planeOp->GetNormal(); - Vector3D rotationAxis = itk::CrossProduct( newNormal, currentNormal ); + Vector3D rotationAxis = itk::CrossProduct( newNormal, currentNormal ); - vtkFloatingPointType rotationAngle = - atan2( - (double) rotationAxis.GetNorm(), - (double) (newNormal * currentNormal) ); + vtkFloatingPointType rotationAngle = - atan2( + (double) rotationAxis.GetNorm(), + (double) (newNormal * currentNormal) ); - rotationAngle *= 180.0 / vnl_math::pi; + rotationAngle *= 180.0 / vnl_math::pi; - RotationOperation centeredRotation( - mitk::OpROTATE, - center, - rotationAxis, - rotationAngle - ); + RotationOperation centeredRotation( + mitk::OpROTATE, + center, + rotationAxis, + rotationAngle + ); - // Rotate first slice - geometry2D->ExecuteOperation( ¢eredRotation ); + // Rotate first slice + geometry2D->ExecuteOperation( ¢eredRotation ); - // Clear the slice stack and adjust it according to the center of - // rotation and plane position (see documentation of ReinitializePlanes) - this->ReinitializePlanes( center, planeOp->GetPoint() ); + // Clear the slice stack and adjust it according to the center of + // rotation and plane position (see documentation of ReinitializePlanes) + this->ReinitializePlanes( center, planeOp->GetPoint() ); - if ( m_SliceNavigationController ) - { - m_SliceNavigationController->SelectSliceByPoint( planeOp->GetPoint() ); - m_SliceNavigationController->AdjustSliceStepperRange(); - } + if ( m_SliceNavigationController ) + { + m_SliceNavigationController->SelectSliceByPoint( planeOp->GetPoint() ); + m_SliceNavigationController->AdjustSliceStepperRange(); + } - Geometry3D::ExecuteOperation( ¢eredRotation ); - } + Geometry3D::ExecuteOperation( ¢eredRotation ); } - else + } + else + { + // Reach through to all slices + for (std::vector::iterator iter = m_Geometry2Ds.begin(); + iter != m_Geometry2Ds.end(); + ++iter) + { + (*iter)->ExecuteOperation(operation); + } + } + break; + + case OpRESTOREPLANEPOSITION: + if ( m_EvenlySpaced ) + { + // Save first slice + Geometry2D::Pointer geometry2D = m_Geometry2Ds[0]; + + PlaneGeometry* planeGeometry = dynamic_cast< PlaneGeometry * >( + geometry2D.GetPointer() ); + + RestorePlanePositionOperation *restorePlaneOp = dynamic_cast< RestorePlanePositionOperation* >( operation ); + + // Need a PlaneGeometry, a PlaneOperation and a reference frame to + // carry out the re-orientation + if ( m_ReferenceGeometry && planeGeometry && restorePlaneOp ) { - // Reach through to all slices - for (std::vector::iterator iter = m_Geometry2Ds.begin(); - iter != m_Geometry2Ds.end(); - ++iter) + // Clear all generated geometries and then rotate only the first slice. + // The other slices will be re-generated on demand + + // Rotate first slice + geometry2D->ExecuteOperation( restorePlaneOp ); + + m_DirectionVector = restorePlaneOp->GetDirectionVector(); + + double centerOfRotationDistance = + planeGeometry->SignedDistanceFromPlane( m_ReferenceGeometry->GetCenter() ); + + if ( centerOfRotationDistance > 0 ) + { + m_DirectionVector = m_DirectionVector; + } + else + { + m_DirectionVector = -m_DirectionVector; + } + + Vector3D spacing = restorePlaneOp->GetSpacing(); + + Superclass::SetSpacing( spacing ); + + // /*Now we need to calculate the number of slices in the plane's normal + // direction, so that the entire volume is covered. This is done by first + // calculating the dot product between the volume diagonal (the maximum + // distance inside the volume) and the normal, and dividing this value by + // the directed spacing calculated above.*/ + ScalarType directedExtent = + fabs( m_ReferenceGeometry->GetExtentInMM( 0 ) * m_DirectionVector[0] ) + + fabs( m_ReferenceGeometry->GetExtentInMM( 1 ) * m_DirectionVector[1] ) + + fabs( m_ReferenceGeometry->GetExtentInMM( 2 ) * m_DirectionVector[2] ); + + if ( directedExtent >= spacing[2] ) + { + m_Slices = static_cast< unsigned int >(directedExtent / spacing[2] + 0.5); + } + else + { + m_Slices = 1; + } + + m_Geometry2Ds.assign( m_Slices, Geometry2D::Pointer( NULL ) ); + + if ( m_Slices > 0 ) { - (*iter)->ExecuteOperation(operation); + m_Geometry2Ds[0] = geometry2D; } + + m_SliceNavigationController->GetSlice()->SetSteps( m_Slices ); + + this->Modified(); + + //End Reinitialization + + if ( m_SliceNavigationController ) + { + m_SliceNavigationController->GetSlice()->SetPos( restorePlaneOp->GetPos() ); + m_SliceNavigationController->AdjustSliceStepperRange(); + } } - break; - } + } + else + { + // Reach through to all slices + for (std::vector::iterator iter = m_Geometry2Ds.begin(); + iter != m_Geometry2Ds.end(); + ++iter) + { + (*iter)->ExecuteOperation(operation); + } + } + break; + + } - this->Modified(); + this->Modified(); } diff --git a/Core/Code/DataManagement/mitkSlicedGeometry3D.h b/Core/Code/DataManagement/mitkSlicedGeometry3D.h index d3c5ae5580..a6246df353 100644 --- a/Core/Code/DataManagement/mitkSlicedGeometry3D.h +++ b/Core/Code/DataManagement/mitkSlicedGeometry3D.h @@ -1,323 +1,323 @@ /*========================================================================= 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 MITKSLICEDGEOMETRY3D_H_HEADER_INCLUDED_C1EBD0AD #define MITKSLICEDGEOMETRY3D_H_HEADER_INCLUDED_C1EBD0AD #include "mitkGeometry3D.h" #include "mitkPlaneGeometry.h" namespace mitk { class SliceNavigationController; class NavigationController; /** \brief Describes the geometry of a data object consisting of slices. * * A Geometry2D can be requested for each slice. In the case of * \em evenly-spaced, \em plane geometries (m_EvenlySpaced==true), * only the 2D-geometry of the first slice has to be set (to an instance of * PlaneGeometry). The 2D geometries of the other slices are calculated * by shifting the first slice in the direction m_DirectionVector by * m_Spacing.z * sliceNumber. The m_Spacing member (which is only * relevant in the case m_EvenlySpaced==true) descibes the size of a voxel * (in mm), i.e., m_Spacing.x is the voxel width in the x-direction of the * plane. It is derived from the reference geometry of this SlicedGeometry3D, * which usually would be the global geometry describing how datasets are to * be resliced. * * By default, slices are oriented in the direction of one of the main axes * (x, y, z). However, by means of rotation, it is possible to realign the * slices in any possible direction. In case of an inclined plane, the spacing * is derived as a product of the (regular) geometry spacing and the direction * vector of the plane. * * SlicedGeometry3D and the associated Geometry2Ds have to be initialized in * the method GenerateOutputInformation() of BaseProcess (or CopyInformation / * UpdateOutputInformation of BaseData, if possible, e.g., by analyzing pic * tags in Image) subclasses. See also * * \sa itk::ProcessObject::GenerateOutputInformation(), * \sa itk::DataObject::CopyInformation() and * \a itk::DataObject::UpdateOutputInformation(). * * Rule: everything is in mm (or ms for temporal information) if not * stated otherwise. * * \warning The hull (i.e., transform, bounding-box and * time-bounds) is only guaranteed to be up-to-date after calling * UpdateInformation(). * * \ingroup Geometry */ class MITK_CORE_EXPORT SlicedGeometry3D : public mitk::Geometry3D { public: mitkClassMacro(SlicedGeometry3D, Geometry3D); /** Method for creation through the object factory. */ itkNewMacro(Self); /** * \brief Returns the Geometry2D of the slice (\a s). * * If (a) m_EvenlySpaced==true, (b) we don't have a Geometry2D stored * for the requested slice, and (c) the first slice (s=0) * is a PlaneGeometry instance, then we calculate the geometry of the * requested as the plane of the first slice shifted by m_Spacing[3]*s * in the direction of m_DirectionVector. * * \warning The Geometry2Ds are not necessarily up-to-date and not even * initialized. * * The Geometry2Ds have to be initialized in the method * GenerateOutputInformation() of BaseProcess (or CopyInformation / * UpdateOutputInformation of BaseData, if possible, e.g., by analyzing * pic tags in Image) subclasses. See also * * \sa itk::ProcessObject::GenerateOutputInformation(), * \sa itk::DataObject::CopyInformation() and * \sa itk::DataObject::UpdateOutputInformation(). */ virtual mitk::Geometry2D* GetGeometry2D( int s ) const; /** * \brief Set Geometry2D of slice \a s. */ virtual bool SetGeometry2D( mitk::Geometry2D *geometry2D, int s ); //##Documentation //## @brief When switching from an Image Geometry to a normal Geometry (and the other way around), you have to change the origin as well (See Geometry Documentation)! This function will change the "isImageGeometry" bool flag and changes the origin respectively. virtual void ChangeImageGeometryConsideringOriginOffset( const bool isAnImageGeometry ); virtual void SetTimeBounds( const mitk::TimeBounds& timebounds ); virtual const mitk::BoundingBox* GetBoundingBox() const; /** * \brief Get the number of slices */ itkGetConstMacro( Slices, unsigned int ); /** * \brief Check whether a slice exists */ virtual bool IsValidSlice( int s = 0 ) const; virtual void SetReferenceGeometry( Geometry3D *referenceGeometry ); /** * \brief Set the spacing (m_Spacing), in direction of the plane normal. * * INTERNAL METHOD. */ virtual void SetSpacing( const mitk::Vector3D &aSpacing ); /** * \brief Set the SliceNavigationController corresponding to this sliced * geometry. * * The SNC needs to be informed when the number of slices in the geometry * changes, which can occur whenthe slices are re-oriented by rotation. */ virtual void SetSliceNavigationController( mitk::SliceNavigationController *snc ); mitk::SliceNavigationController *GetSliceNavigationController(); /** * \brief Set/Get whether the SlicedGeometry3D is evenly-spaced * (m_EvenlySpaced) * * If (a) m_EvenlySpaced==true, (b) we don't have a Geometry2D stored for * the requested slice, and (c) the first slice (s=0) is a PlaneGeometry * instance, then we calculate the geometry of the requested as the plane * of the first slice shifted by m_Spacing.z * s in the direction of * m_DirectionVector. * * \sa GetGeometry2D */ itkGetConstMacro(EvenlySpaced, bool); virtual void SetEvenlySpaced(bool on = true); /** * \brief Set/Get the vector between slices for the evenly-spaced case * (m_EvenlySpaced==true). * * If the direction-vector is (0,0,0) (the default) and the first * 2D geometry is a PlaneGeometry, then the direction-vector will be * calculated from the plane normal. * * \sa m_DirectionVector */ virtual void SetDirectionVector(const mitk::Vector3D& directionVector); itkGetConstMacro(DirectionVector, const mitk::Vector3D&); virtual AffineGeometryFrame3D::Pointer Clone() const; static const std::string SLICES; const static std::string DIRECTION_VECTOR; const static std::string EVENLY_SPACED; /** * \brief Tell this instance how many Geometry2Ds it shall manage. Bounding * box and the Geometry2Ds must be set additionally by calling the respective * methods! * * \warning Bounding box and the 2D-geometries must be set additionally: use * SetBounds(), SetGeometry(). */ virtual void InitializeSlicedGeometry( unsigned int slices ); /** * \brief Completely initialize this instance as evenly-spaced with slices * parallel to the provided Geometry2D that is used as the first slice and * for spacing calculation. * * Initializes the bounding box according to the width/height of the * Geometry2D and \a slices. The spacing is calculated from the Geometry2D. */ virtual void InitializeEvenlySpaced( mitk::Geometry2D *geometry2D, unsigned int slices, bool flipped=false ); /** * \brief Completely initialize this instance as evenly-spaced with slices * parallel to the provided Geometry2D that is used as the first slice and * for spacing calculation (except z-spacing). * * Initializes the bounding box according to the width/height of the * Geometry2D and \a slices. The x-/y-spacing is calculated from the * Geometry2D. */ virtual void InitializeEvenlySpaced( mitk::Geometry2D *geometry2D, mitk::ScalarType zSpacing, unsigned int slices, bool flipped=false ); /** * \brief Completely initialize this instance as evenly-spaced plane slices * parallel to a side of the provided Geometry3D and using its spacing * information. * * Initializes the bounding box according to the width/height of the * Geometry3D and the number of slices according to * Geometry3D::GetExtent(2). * * \param planeorientation side parallel to which the slices will be oriented * \param top if \a true, create plane at top, otherwise at bottom * (for PlaneOrientation Transversal, for other plane locations respectively) * \param frontside defines the side of the plane (the definition of * front/back is somewhat arbitrary) * * \param rotate rotates the plane by 180 degree around its normal (the * definition of rotated vs not rotated is somewhat arbitrary) */ virtual void InitializePlanes( const mitk::Geometry3D *geometry3D, mitk::PlaneGeometry::PlaneOrientation planeorientation, bool top=true, bool frontside=true, bool rotated=false ); virtual void SetImageGeometry(const bool isAnImageGeometry); virtual void ExecuteOperation(Operation* operation); protected: SlicedGeometry3D(); SlicedGeometry3D(const SlicedGeometry3D& other); virtual ~SlicedGeometry3D(); /** * Reinitialize plane stack after rotation. More precisely, the first plane * of the stack needs to spatially aligned, in two respects: * * 1. Re-alignment with respect to the dataset center; this is necessary - * since the distance from the first palne to the center could otherwise + * since the distance from the first plane to the center could otherwise * continuously decrease or increase. * 2. Re-alignment with respect to a given reference point; the reference * point is a location which the user wants to be exactly touched by one * plane of the plane stack. The first plane is minimally shifted to * ensure this touching. Usually, the reference point would be the * point around which the geometry is rotated. */ virtual void ReinitializePlanes( const Point3D ¢er, const Point3D &referencePoint ); ScalarType GetLargestExtent( const Geometry3D *geometry ); void PrintSelf(std::ostream& os, itk::Indent indent) const; /** Calculate "directed spacing", i.e. the spacing in directions * non-orthogonal to the coordinate axes. This is done via the * ellipsoid equation. */ double CalculateSpacing( const mitk::Vector3D &direction ) const; /** The extent of the slice stack, i.e. the number of slices, depends on the * plane normal. For rotated geometries, the geometry's transform needs to * be accounted in this calculation. */ mitk::Vector3D AdjustNormal( const mitk::Vector3D &normal ) const; /** * Container for the 2D-geometries contained within this SliceGeometry3D. */ mutable std::vector m_Geometry2Ds; /** * If (a) m_EvenlySpaced==true, (b) we don't have a Geometry2D stored * for the requested slice, and (c) the first slice (s=0) * is a PlaneGeometry instance, then we calculate the geometry of the * requested as the plane of the first slice shifted by m_Spacing.z*s * in the direction of m_DirectionVector. * * \sa GetGeometry2D */ bool m_EvenlySpaced; /** * Vector between slices for the evenly-spaced case (m_EvenlySpaced==true). * If the direction-vector is (0,0,0) (the default) and the first * 2D geometry is a PlaneGeometry, then the direction-vector will be * calculated from the plane normal. */ mutable mitk::Vector3D m_DirectionVector; /** Number of slices this SliceGeometry3D is descibing. */ unsigned int m_Slices; /** Underlying Geometry3D for this SlicedGeometry */ mitk::Geometry3D *m_ReferenceGeometry; /** SNC correcsponding to this geometry; used to reflect changes in the * number of slices due to rotation. */ //mitk::NavigationController *m_NavigationController; mitk::SliceNavigationController *m_SliceNavigationController; }; } // namespace mitk #endif /* MITKSLICEDGEOMETRY3D_H_HEADER_INCLUDED_C1EBD0AD */ diff --git a/Core/Code/Interactions/mitkInteractionConst.h b/Core/Code/Interactions/mitkInteractionConst.h index 43be353356..2d7e31abda 100644 --- a/Core/Code/Interactions/mitkInteractionConst.h +++ b/Core/Code/Interactions/mitkInteractionConst.h @@ -1,753 +1,754 @@ /*========================================================================= 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 MITKINTERACTCONST_H #define MITKINTERACTCONST_H //##Documentation //## @file mitkInteractionConst.h //## @brief Constants for most interaction classes, due to the generic StateMachines. //## //## Changes in Type, ButtonState or Key has to be don in mitkEventMapper.cpp, too. //## @ingroup Interaction /*Prefixes for Constants: E = Enumeration EID = EventId's Op = Operations Ac = Action Type_ = Type of Event BS_ = ButtonStates and Buttons Key_ = Keys like in QT */ namespace mitk{ //Constants for EventIds; use the according constant to through an event in the code enum EEventIds { EIDNULLEVENT = 0, EIDLEFTMOUSEBTN = 1, EIDRIGHTMOUSEBTN = 2, EIDLEFTMOUSEBTNANDSHIFT = 3, EIDMIDDLEMOUSEBTN = 4, EIDLEFTMOUSEBTNANDCTRL = 5, EIDMIDDLEMOUSEBTNANDCTRL = 6, EIDRIGHTMOUSEBTNANDCTRL = 7, EIDLEFTMOUSEBTNDOUBLECLICK = 8, EIDMOUSEWHEEL = 9, EIDLEFTMOUSERELEASE = 505, EIDMIDDLEMOUSERELEASE = 506, EIDRIGHTMOUSERELEASE = 507, EIDLEFTMOUSERELEASEANDSHIFT = 508, EIDMOUSEMOVE = 520, EIDLEFTMOUSEBTNANDMOUSEWHEEL = 521, EIDRIGHTMOUSEBTNANDMOUSEWHEEL = 522, EIDMIDDLEMOUSEBTNANDMOUSEWHEEL = 523, EIDLEFTMOUSEBTNANDMOUSEMOVE = 530, EIDRIGHTMOUSEBTNANDMOUSEMOVE = 531, EIDMIDDLEMOUSEBTNANDMOUSEMOVE = 533, EIDCTRLANDLEFTMOUSEBTNANDMOUSEMOVE = 534, EIDCTRLANDRIGHTMOUSEBTNANDMOUSEMOVE = 535, EIDCTRLANDMIDDLEMOUSEBTNANDMOUSEMOVE = 536, EIDCTRLANDLEFTMOUSEBTNRELEASE = 537, EIDCTRLANDRIGHTMOUSEBTNRELEASE = 538, EIDCTRLANDMIDDLEMOUSEBTNRELEASE = 539, EIDSHIFTANDCTRLANDMIDDLEMOUSEBTN = 540, EIDSHIFTANDLEFTMOUSEBTNANDMOUSEMOVE = 541, EIDSHIFTANDCTRLANDMOUSEMOVE = 542, EIDSHIFTANDCTRLANDMOUSERELEASE = 543, EIDALTANDLEFTMOUSEBTN = 600, EIDALTANDLEFTMOUSEBTNANDMOUSEMOVE = 610, EIDALTANDLEFTMOUSERELEASE = 620, EIDCTRLANDLEFTMOUSEWHEEL = 630, EIDALTANDMOUSEWHEEL = 640, EIDALTANDMIDDLEMOUSEBTN = 641, EIDALTANDMIDDLEMOUSEBTNANDMOVE = 642, EIDALTANDMIDDLEMOUSEBTNRELEASE = 643, EIDALTANDSHIFTANDRIGHTMOUSEBTN = 644, EIDALTANDSHIFTANDRIGHTMOUSEBTNANDMOUSEMOVE = 645, EIDALTANDSHIFTANDRIGHTMOUSEBTNRELEASE = 646, EIDSHIFTANDRIGHTMOUSEPRESS = 2000, EIDSHIFTANDRIGHTMOUSEMOVE = 2001, EIDSHIFTANDRIGHTMOUSERELEASE = 2002, EIDSHIFTANDMIDDLEMOUSEPRESS = 2003, EIDSHIFTANDMIDDLEMOUSEMOVE = 2004, EIDSHIFTANDMIDDLEMOUSERELEASE = 2005, EIDSPACENAVIGATORINPUT = 4001, // 3d Mouse, SpaceNavigator input EIDSPACENAVIGATORKEYDOWN = 4002, // 3d Mouse, KeyDown EIDWIIMOTEINPUT = 4003, // WiiMote input EIDWIIMOTEBUTTON = 4004, // WiiMote home button EIDWIIMOTEBUTTONB = 4005, // WiiMote b button EIDSTRGANDN = 10, EIDSTRGANDE = 11, EIDDELETE = 12, EIDN = 13, EIDESCAPE = 14, EIDP = 15, EIDR = 16, EIDT = 17, EIDS = 18, EIDE = 19, EIDSTRGANDALTANDA = 20, EIDSTRGANDALTANDB = 21, EIDH = 22, EIDRETURN = 23, EIDENTER = 24, EIDSPACE = 25, EIDPLUS = 26, EIDMINUS = 27, EIDSTRGANDALTANDH = 30, EIDSTRGANDALTANDI = 31, EIDSTRGANDALTANDS = 40, EIDALT = 90, EIDSTRGANDB = 91, EIDNEW = 1000, EIDOLD = 1001, EIDFINISHED = 1002, EIDNO = 1003, EIDYES = 1004, EIDSAME = 1005, EIDNOANDLASTOBJECT = 1006, EIDNOANDNOTLASTOBJECT = 1007, EIDLAST = 1008, EIDNOTLAST = 1009, EIDSTSMALERNMINUS1 = 1010, EIDSTLARGERNMINUS1 = 1011, EIDPOSITIONEVENT = 1012, EIDEDIT = 1013, EIDSMALLERN = 1014, EIDEQUALSN = 1015, EIDLARGERN = 1016, EIDEMPTY = 1017, EIDSUBDESELECT = 1020, EIDSMTOSELECTED = 1030, EIDSMTODESELECTED = 1031, EIDTIP = 1050, EIDHEAD = 1051, EIDBODY = 1052, EIDCLEAR = 1100, EIDACTIVATETOOL = 1300, EIDPRINT = 3001, EV_INIT = 5551001, EV_PREVIOUS = 5551002, EV_PATH_COLLECTION_SELECTED = 5551003, EV_NAVIGATION_SELECTED = 5551004, EV_LESS_THEN_MIN_COUNT = 5551005, EV_READY = 5551006, EV_NEXT = 5551007, EV_DONE = 5551008, EV_NEW_LANDMARK = 5551009, EV_REMOVE_LANDMARK = 5551010, EIDINSIDE = 2500, EIDFIGUREHOVER = 12340, EIDNOFIGUREHOVER = 12341 }; //##Constants for Operations //## xomments are always examples of the usage enum EOperations { OpNOTHING = 0, OpTEST = 1, OpNEWCELL = 10, //add a new cell OpADD = 100, //add a point or a vessel OpUNDOADD = 101, OpADDLINE = 1001, //add a line OpINSERT = 200, //insert a point at position OpINSERTLINE = 201, //insert a line at position OpINSERTPOINT = 202, OpCLOSECELL = 250, //close a cell (to a polygon) OpOPENCELL = 251, //close a cell (to a polygon) OpMOVE = 300, //move a point OpMOVELINE = 301, //move a line OpMOVECELL = 302, //move a line OpUNDOMOVE = 303, OpMOVEPOINTUP = 304, OpMOVEPOINTDOWN = 305, OpREMOVE = 400, //remove a point at position OpREMOVELINE = 401, //remove a line at position OpREMOVECELL = 402, //remove a cell OpREMOVEPOINT = 403, OpDELETE = 500, //delete OpDELETELINE = 501, //delete the last line in a cell OpUNDELETE = 502, OpDELETECELL = 505, OpSTATECHANGE = 600, //change a state OpTIMECHANGE = 601, //change a state OpTERMINATE = 666, //change a state OpSELECTPOINT = 700, OpSELECTLINE = 701, OpSELECTCELL = 702, OpSELECTSUBOBJECT = 703, //for VesselGraphInteractor //OpSELECTNEWSUBOBJECT = 704, //for VesselGraphInteractor OpSELECT = 705, OpDESELECTPOINT = 800, OpDESELECTLINE = 801, OpDESELECTCELL = 802, OpDESELECTSUBOBJECT = 803, //for VesselGraphInteractor OpDESELECTALL = 804, //for VesselGraphInteractor OpDESELECT = 805, OpNAVIGATE = 900, OpZOOM = 1000, OpSCALE = 1100, OpROTATE = 1200, OpORIENT = 1201, + OpRESTOREPLANEPOSITION = 1202, OpSETPOINTTYPE = 1210, OpMODECHANGE = 1500, OpSENDCOORDINATES = 1600, OpPERIPHERYSEARCH = 2000, //used in VesselGraphInteractor OpROOTSEARCH = 2001, //used in VesselGraphInteractor OpTHICKSTVESSELSEARCH = 2002, //used in VesselGraphInteractor OpSHORTESTPATHSEARCH = 2003, //used in VesselGraphInteractor OpATTRIBUTATION = 2004, //used in VesselGraphInteractor OpDEFAULT = 2006, //used in VesselGraphInteractor OpSURFACECHANGED = 3000, // used for changing polydata in surfaces }; //##Constants for EventMapping... //##connects the statemachine.xml-File with the implemented conditions. //##within one statemachine the choice of the actionconstants is freely //## //## ActionId enum EActions { AcDONOTHING = 0, AcINITNEWOBJECT = 5, AcINITEDITOBJECT = 6, AcINITEDITGROUP = 7, AcINITMOVEMENT = 8, AcINITMOVE = 9, AcINITFOREGROUND = 45, // used in SeedsInteractor for setting the foreground seeds AcINITBACKGROUND = 46, // used in SeedsInteractor for setting the background seeds AcINITNEUTRAL = 47, // used in SeedsInteractor for setting the neutral seeds (rubber) AcINITUPDATE = 1235, // For shape model deformation AcADDPOINT = 10, AcADD = 11, AcADDLINE = 12, AcADDANDFINISH = 13, AcADDSELECTEDTOGROUP = 64, AcCHECKPOINT = 21, AcCHECKLINE = 22, AcCHECKCELL = 23, AcCHECKELEMENT = 30, // check if there is a element close enough (picking) AcCHECKOBJECT = 31, // check if an object is hit AcCHECKNMINUS1 = 32, // check if the number of elements is equal to N-1 AcCHECKEQUALS1 = 33, // check if the number of elements in the data is equal to 1 AcCHECKNUMBEROFPOINTS = 330, //check the number of elements in the data AcCHECKSELECTED = 34, // check if the given element is selected or not AcCHECKONESELECTED = 340, //check if there is an element that is selected AcCHECKHOVERING = 341, //check if there is an element that is selected AcCHECKGREATERZERO = 35, // check if the current number of elements is greater than 0 AcCHECKGREATERTWO = 36, // check if the current number of elements is greater than two AcCHECKOPERATION = 37, // check if the operation is of one spectial type AcCHECKONESUBINTERACTOR = 38, AcCHECKSUBINTERACTORS = 39, AcFINISHOBJECT = 40, AcFINISHGROUP = 41, AcFINISHMOVEMENT = 42, AcFINISHMOVE = 43, AcFINISH = 44, AcSEARCHOBJECT = 50, AcSEARCHGROUP = 51, AcSEARCHANOTHEROBJECT = 52, // one object is selected and another object is to be added to selection AcSELECTPICKEDOBJECT = 60, // select the picked object and deselect others AcSELECTANOTHEROBJECT = 61, AcSELECTGROUP = 62, AcSELECTALL = 63, AcSELECT = 65, AcSELECTPOINT = 66, AcSELECTLINE = 68, AcSELECTCELL = 67, AcSELECTSUBOBJECT = 69, // used in VesselGraphInteractor AcDESELECTOBJECT = 70, // deselect picked from group AcDESELECTALL = 72, AcDESELECT = 75, AcDESELECTPOINT = 76, AcDESELECTLINE = 78, AcDESELECTCELL = 77, AcNEWPOINT = 80, AcNEWSUBOBJECT = 81, AcMOVEPOINT = 90, AcMOVESELECTED = 91, AcMOVE = 92, AcMOVEPOINTUP = 93, AcMOVEPOINTDOWN = 94, AcREMOVEPOINT = 100, AcREMOVE = 101, AcREMOVELINE = 102, AcREMOVEALL = 103, AcREMOVESELECTEDSUBOBJECT = 104, // used in VesselGraphInteractor AcWHEEL = 105, AcPLUS = 106, AcMINUS = 107, AcDELETEPOINT = 120, AcCLEAR = 130, // clear all elements from a list AcINSERTPOINT = 110, AcINSERTLINE = 111, AC_SET_NEXT_BUTTON_VISIBLE = 5550001, AC_SET_NEXT_BUTTON_INVISIBLE = 5550002, AC_SET_PREVIOUS_BUTTON_VISIBLE = 5550003, AC_SET_PREVIOUS_BUTTON_INVISIBLE = 5550004, AC_SET_ASSISTAND_WIDGET_STECK = 5550005, AC_SETMAX_COUNT_REF_POINTS = 5550006, AC_SET_NEXT_BUTTON_TEXT = 5550007, AC_CHECK_LANDMARK_COUNT = 5550008, AC_SET_DONE_FALSE = 5550009, AC_INIT = 55500010, AC_SET_APPLICATION_SELECTED_FALSE = 55500011, AC_SENSOR_ATTACHED = 55500012, AC_CLOSE_ASSISTENT = 55500013, AC_START_APPLICATION_TEXT = 55500014, AC_START_NAVIGATION = 55500015, AC_START_PATHCOLLECTION = 55500016, AC_LOAD_LANDMARKS = 55500017, AC_CALCULATE_LANDMARK_TRANSFORM = 55500018, AcTERMINATE_INTERACTION = 666, AcTRANSLATESTART = 1000, AcTRANSLATE = 1001, AcSCALESTART = 1002, AcSCALE = 1003, AcROTATESTART = 1004, AcROTATE = 1005, AcINITAFFINEINTERACTIONS = 1006, AcFINISHAFFINEINTERACTIONS = 1007, AcTRANSLATEEND = 1008, AcSCALEEND = 1009, AcROTATEEND = 1010, AcINITZOOM = 1011, AcZOOM = 1012, AcSCROLL = 1013, AcLEVELWINDOW = 1014, AcSCROLLMOUSEWHEEL = 1015, AcSETSTARTPOINT = 1050, AcMODEDESELECT = 1100, // set interactor in not selected mode AcMODESELECT = 1101, // set interactor in selected mode AcMODESUBSELECT = 1102, // set interacor in sub selected mode AcINFORMLISTENERS = 1200, // GlobalInteraction AcASKINTERACTORS = 1201, // GlobalInteraction AcCHECKGREATERONE = 1500, AcCHECKBOUNDINGBOX = 1510, AcFORCESUBINTERACTORS = 1550, AcSENDCOORDINATES = 1600, AcTRANSMITEVENT = 2000, // to transmit an event to a lower Interactor/Statemachine AcPERIPHERYSEARCH = 3000, // used in VesselGraphInteractor AcROOTSEARCH = 3001, // used in VesselGraphInteractor AcTHICKSTVESSELSEARCH = 3002, // used in VesselGraphInteractor AcSHORTESTPATHSEARCH = 3003, // used in VesselGraphInteractor AcSINGLE = 3004, // used in VesselGraphInteractor AcATTRIBUTATION = 3005, // used in VesselGraphInteractor AcDEFAULT = 3007, // used in VesselGraphInteractor AcSETVESSELELEMENT = 3008, // used in VesselGraphInteractor AcCHECKBARRIERSTATUS = 3010, // used in VesselGraphInteractor AcUPDATEMESH = 1234, // For Shape Model Interaction AcINCREASE = 49012, AcDECREASE = 49013, AcMODIFY = 49014, AcUNDOUPDATE = 1236, // For restoring a mesh after an update AcENTEROBJECT = 48000, AcLEAVEOBJECT = 48001, AcSWITCHOBJECT = 48002, AcUPDATELINE = 48003, AcINITLINE = 48004, AcTERMINATELINE = 48005, AcCREATEBOX = 48006, AcCREATEOBJECTFROMLINE = 48007, AcCANCEL = 48008, AcACTIVATETOOL = 48009, AcROTATEAROUNDPOINT1 = 49002, AcROTATEAROUNDPOINT2 = 49003, AcMOVEPOINT1 = 49004, AcMOVEPOINT2 = 49005, AcUPDATEPOINT = 49006, AcUPDATERADIUSMOUSEWHEEL = 49007, AcDISPLAYOPTIONS = 49009, AcCYCLE = 49010, AcACCEPT = 49011, AcONSPACENAVIGATORMOUSEINPUT = 4001, // On input of 3D Mouse AcONPACENAVIGATORKEYDOWN = 4002, // On input of 3D Mouse AcONWIIMOTEINPUT = 4003, // used for wiimote to signal IR input AcRESETVIEW = 4004, // used for wiimote to reset view AcONWIIMOTEBUTTONRELEASED = 4005, // stops the surface interaction AcCHECKPOSITION = 5000, AcINITIALIZECONTOUR = 5001, AcCALCULATENEWSEGMENTATION_SP= 5002, AcINTERACTOR = 5003, AcCALCULATENEWSEGMENTATION_BB= 5004 }; /* //!!!!!!!!!!!!!!!!!!!!!!!! //!!!!!!!!!!!!!!!!!!!!!!!! //EventMechanism: //If you change anything from here on, then change in mitkEventMapper.cpp (Array of constants) as well. //!!!!!!!!!!!!!!!!!!!!!!!! //!!!!!!!!!!!!!!!!!!!!!!!! */ //Type of an Event; enum EEventType { Type_None = 0, // invalid event Type_Timer = 1, // timer event Type_MouseButtonPress = 2, // mouse button pressed Type_MouseButtonRelease = 3, // mouse button released Type_MouseButtonDblClick = 4, // mouse button double click Type_MouseMove = 5, // mouse move Type_KeyPress = 6, // key pressed Type_KeyRelease = 7, // key released Type_FocusIn = 8, // keyboard focus received Type_FocusOut = 9, // keyboard focus lost Type_Enter = 10, // mouse enters widget Type_Leave = 11, // mouse leaves widget Type_Paint = 12, // paint widget Type_Move = 13, // move widget Type_Resize = 14, // resize widget Type_Create = 15, // after object creation Type_Destroy = 16, // during object destruction Type_Show = 17, // widget is shown Type_Hide = 18, // widget is hidden Type_Close = 19, // request to close widget Type_Quit = 20, // request to quit application Type_Reparent = 21, // widget has been reparented Type_ShowMinimized = 22, // widget is shown minimized Type_ShowNormal = 23, // widget is shown normal Type_WindowActivate = 24, // window was activated Type_WindowDeactivate = 25, // window was deactivated Type_ShowToParent = 26, // widget is shown to parent Type_HideToParent = 27, // widget is hidden to parent Type_ShowMaximized = 28, // widget is shown maximized Type_ShowFullScreen = 29, // widget is shown full-screen Type_Accel = 30, // accelerator event Type_Wheel = 31, // wheel event Type_AccelAvailable = 32, // accelerator available event Type_CaptionChange = 33, // caption changed Type_IconChange = 34, // icon changed Type_ParentFontChange = 35, // parent font changed Type_ApplicationFontChange = 36, // application font changed Type_ParentPaletteChange = 37, // parent palette changed Type_ApplicationPaletteChange = 38, // application palette changed Type_PaletteChange = 39, // widget palette changed Type_Clipboard = 40, // internal clipboard event Type_Speech = 42, // reserved for speech input Type_SockAct = 50, // socket activation Type_AccelOverride = 51, // accelerator override event Type_DeferredDelete = 52, // deferred delete event Type_DragEnter = 60, // drag moves into widget Type_DragMove = 61, // drag moves in widget Type_DragLeave = 62, // drag leaves or is cancelled Type_Drop = 63, // actual drop Type_DragResponse = 64, // drag accepted/rejected Type_ChildInserted = 70, // new child widget Type_ChildRemoved = 71, // deleted child widget Type_LayoutHint = 72, // child min/max size changed Type_ShowWindowRequest = 73, // widget's window should be mapped Type_ActivateControl = 80, // ActiveX activation Type_DeactivateControl = 81, // ActiveX deactivation Type_ContextMenu = 82, // context popup menu Type_IMStart = 83, // input method composition start Type_IMCompose = 84, // input method composition Type_IMEnd = 85, // input method composition end Type_Accessibility = 86, // accessibility information is requested Type_TabletMove = 87, // Wacom tablet event Type_LocaleChange = 88, // the system locale changed Type_LanguageChange = 89, // the application language changed Type_LayoutDirectionChange = 90, // the layout direction changed Type_Style = 91, // internal style event Type_TabletPress = 92, // tablet press Type_TabletRelease = 93, // tablet release Type_User = 1000, // first user event id Type_SpaceNavigatorInput = 1094, // 3D mouse input occured Type_SpaceNavigatorKeyDown = 1095, // 3D mouse input occured Type_WiiMoteInput = 1096, // WiiMote input occured Type_WiiMoteButton= 1097, // WiiMote button pressed Type_MaxUser = 65535 }; //##ButtonState // mouse/keyboard state values //QT combinations if MOUSEBUTTONRelease: left MouseButton + ControlButton: 0x201 enum EButtonStates { BS_NoButton = 0x0000, BS_LeftButton = 0x0001, BS_RightButton = 0x0002, BS_MidButton = 0x0004, BS_MouseButtonMask = 0x0007, BS_ShiftButton = 0x0100, BS_ControlButton = 0x0200, BS_AltButton = 0x0400, BS_MetaButton = 0x0800, BS_KeyButtonMask = 0x0f00, BS_Keypad = 0x4000 }; //##Key enum EKeys { Key_Escape = 0x1000, // misc keys Key_Tab = 0x1001, Key_Backtab = 0x1002, Key_BackTab = 0x1002, //= Key_Backtab Key_Backspace = 0x1003, Key_BackSpace = 0x1003, //= Key_Backspace Key_Return = 0x1004, Key_Enter = 0x1005, Key_Insert = 0x1006, Key_Delete = 0x1007, Key_Pause = 0x1008, Key_Print = 0x1009, Key_SysReq = 0x100a, Key_Home = 0x1010, // cursor movement Key_End = 0x1011, Key_Left = 0x1012, Key_Up = 0x1013, Key_Right = 0x1014, Key_Down = 0x1015, Key_Prior = 0x1016, Key_PageUp = 0x1016, //=Key_Prior Key_Next = 0x1017, Key_PageDown = 0x1017, //=Key_Next Key_Shift = 0x1020, // modifiers Key_Control = 0x1021, Key_Meta = 0x1022, Key_Alt = 0x1023, Key_CapsLock = 0x1024, Key_NumLock = 0x1025, Key_ScrollLock = 0x1026, Key_F1 = 0x1030, // function keys Key_F2 = 0x1031, Key_F3 = 0x1032, Key_F4 = 0x1033, Key_F5 = 0x1034, Key_F6 = 0x1035, Key_F7 = 0x1036, Key_F8 = 0x1037, Key_F9 = 0x1038, Key_F10 = 0x1039, Key_F11 = 0x103a, Key_F12 = 0x103b, Key_F13 = 0x103c, Key_F14 = 0x103d, Key_F15 = 0x103e, Key_F16 = 0x103f, Key_F17 = 0x1040, Key_F18 = 0x1041, Key_F19 = 0x1042, Key_F20 = 0x1043, Key_F21 = 0x1044, Key_F22 = 0x1045, Key_F23 = 0x1046, Key_F24 = 0x1047, Key_F25 = 0x1048, // F25 .. F35 only on X11 Key_F26 = 0x1049, Key_F27 = 0x104a, Key_F28 = 0x104b, Key_F29 = 0x104c, Key_F30 = 0x104d, Key_F31 = 0x104e, Key_F32 = 0x104f, Key_F33 = 0x1050, Key_F34 = 0x1051, Key_F35 = 0x1052, Key_Super_L = 0x1053, // extra keys Key_Super_R = 0x1054, Key_Menu = 0x1055, Key_Hyper_L = 0x1056, Key_Hyper_R = 0x1057, Key_Help = 0x1058, // International input method support (X keycode - = 0xEE00) // Only interesting if you are writing your own input method Key_Muhenkan = 0x1122, // Cancel Conversion Key_Henkan = 0x1123, // Start/Stop Conversion Key_Hiragana_Katakana = 0x1127, // Hiragana/Katakana toggle Key_Zenkaku_Hankaku = 0x112A, // Zenkaku/Hankaku toggle Key_Space = 0x20, // 7 bit printable ASCII Key_Any = 0x20, //= Key_Space Key_Exclam = 0x21, Key_QuoteDbl = 0x22, Key_NumberSign = 0x23, Key_Dollar = 0x24, Key_Percent = 0x25, Key_Ampersand = 0x26, Key_Apostrophe = 0x27, Key_ParenLeft = 0x28, Key_ParenRight = 0x29, Key_Asterisk = 0x2a, Key_Plus = 0x2b, Key_Comma = 0x2c, Key_Minus = 0x2d, Key_Period = 0x2e, Key_Slash = 0x2f, Key_0 = 0x30, Key_1 = 0x31, Key_2 = 0x32, Key_3 = 0x33, Key_4 = 0x34, Key_5 = 0x35, Key_6 = 0x36, Key_7 = 0x37, Key_8 = 0x38, Key_9 = 0x39, Key_Colon = 0x3a, Key_Semicolon = 0x3b, Key_Less = 0x3c, Key_Equal = 0x3d, Key_Greater = 0x3e, Key_Question = 0x3f, Key_At = 0x40, Key_A = 0x41, Key_B = 0x42, Key_C = 0x43, Key_D = 0x44, Key_E = 0x45, Key_F = 0x46, Key_G = 0x47, Key_H = 0x48, Key_I = 0x49, Key_J = 0x4a, Key_K = 0x4b, Key_L = 0x4c, Key_M = 0x4d, Key_N = 0x4e, Key_O = 0x4f, Key_P = 0x50, Key_Q = 0x51, Key_R = 0x52, Key_S = 0x53, Key_T = 0x54, Key_U = 0x55, Key_V = 0x56, Key_W = 0x57, Key_X = 0x58, Key_Y = 0x59, Key_Z = 0x5a, Key_BracketLeft = 0x5b, Key_Backslash = 0x5c, Key_BracketRight = 0x5d, Key_AsciiCircum = 0x5e, Key_Underscore = 0x5f, Key_QuoteLeft = 0x60, Key_BraceLeft = 0x7b, Key_Bar = 0x7c, Key_BraceRight = 0x7d, Key_AsciiTilde = 0x7e, Key_nobreakspace = 0x0a0, Key_exclamdown = 0x0a1, Key_cent = 0x0a2, Key_sterling = 0x0a3, Key_currency = 0x0a4, Key_yen = 0x0a5, Key_brokenbar = 0x0a6, Key_section = 0x0a7, Key_diaeresis = 0x0a8, Key_copyright = 0x0a9, Key_ordfeminine = 0x0aa, Key_guillemotleft = 0x0ab, // left angle quotation mark Key_notsign = 0x0ac, Key_hyphen = 0x0ad, Key_registered = 0x0ae, Key_macron = 0x0af, Key_degree = 0x0b0, Key_plusminus = 0x0b1, Key_twosuperior = 0x0b2, Key_threesuperior = 0x0b3, Key_acute = 0x0b4, Key_mu = 0x0b5, Key_paragraph = 0x0b6, Key_periodcentered = 0x0b7, Key_cedilla = 0x0b8, Key_onesuperior = 0x0b9, Key_masculine = 0x0ba, Key_guillemotright = 0x0bb, // right angle quotation mark Key_onequarter = 0x0bc, Key_onehalf = 0x0bd, Key_threequarters = 0x0be, Key_questiondown = 0x0bf, Key_Agrave = 0x0c0, Key_Aacute = 0x0c1, Key_Acircumflex = 0x0c2, Key_Atilde = 0x0c3, Key_Adiaeresis = 0x0c4, Key_Aring = 0x0c5, Key_AE = 0x0c6, Key_Ccedilla = 0x0c7, Key_Egrave = 0x0c8, Key_Eacute = 0x0c9, Key_Ecircumflex = 0x0ca, Key_Ediaeresis = 0x0cb, Key_Igrave = 0x0cc, Key_Iacute = 0x0cd, Key_Icircumflex = 0x0ce, Key_Idiaeresis = 0x0cf, Key_ETH = 0x0d0, Key_Ntilde = 0x0d1, Key_Ograve = 0x0d2, Key_Oacute = 0x0d3, Key_Ocircumflex = 0x0d4, Key_Otilde = 0x0d5, Key_Odiaeresis = 0x0d6, Key_multiply = 0x0d7, Key_Ooblique = 0x0d8, Key_Ugrave = 0x0d9, Key_Uacute = 0x0da, Key_Ucircumflex = 0x0db, Key_Udiaeresis = 0x0dc, Key_Yacute = 0x0dd, Key_THORN = 0x0de, Key_ssharp = 0x0df, Key_agrave = 0x0e0, Key_aacute = 0x0e1, Key_acircumflex = 0x0e2, Key_atilde = 0x0e3, Key_adiaeresis = 0x0e4, Key_aring = 0x0e5, Key_ae = 0x0e6, Key_ccedilla = 0x0e7, Key_egrave = 0x0e8, Key_eacute = 0x0e9, Key_ecircumflex = 0x0ea, Key_ediaeresis = 0x0eb, Key_igrave = 0x0ec, Key_iacute = 0x0ed, Key_icircumflex = 0x0ee, Key_idiaeresis = 0x0ef, Key_eth = 0x0f0, Key_ntilde = 0x0f1, Key_ograve = 0x0f2, Key_oacute = 0x0f3, Key_ocircumflex = 0x0f4, Key_otilde = 0x0f5, Key_odiaeresis = 0x0f6, Key_division = 0x0f7, Key_oslash = 0x0f8, Key_ugrave = 0x0f9, Key_uacute = 0x0fa, Key_ucircumflex = 0x0fb, Key_udiaeresis = 0x0fc, Key_yacute = 0x0fd, Key_thorn = 0x0fe, Key_ydiaeresis = 0x0ff, Key_unknown = 0xffff, Key_none = 0xffff//= Key_unknown }; }//namespace mitk #endif //ifndef MITKINTERACTCONST_H diff --git a/Core/Code/files.cmake b/Core/Code/files.cmake index 8efff5eebe..9468a54f2f 100644 --- a/Core/Code/files.cmake +++ b/Core/Code/files.cmake @@ -1,326 +1,328 @@ SET(H_FILES Algorithms/itkImportMitkImageContainer.h Algorithms/itkImportMitkImageContainer.txx Algorithms/itkLocalVariationImageFilter.h Algorithms/itkLocalVariationImageFilter.txx Algorithms/itkMITKScalarImageToHistogramGenerator.h Algorithms/itkMITKScalarImageToHistogramGenerator.txx Algorithms/itkTotalVariationDenoisingImageFilter.h Algorithms/itkTotalVariationDenoisingImageFilter.txx Algorithms/itkTotalVariationSingleIterationImageFilter.h Algorithms/itkTotalVariationSingleIterationImageFilter.txx Algorithms/mitkBilateralFilter.h Algorithms/mitkBilateralFilter.cpp Algorithms/mitkImageAccessByItk.h Algorithms/mitkImageCast.h Algorithms/mitkImageToItk.h Algorithms/mitkImageToItk.txx Algorithms/mitkInstantiateAccessFunctions.h Algorithms/mitkITKImageImport.h Algorithms/mitkITKImageImport.txx Algorithms/mitkPixelTypeList.h # Preprocessor macros taken from Boost Algorithms/mitkPPArithmeticDec.h Algorithms/mitkPPArgCount.h Algorithms/mitkPPCat.h Algorithms/mitkPPConfig.h Algorithms/mitkPPControlExprIIf.h Algorithms/mitkPPControlIf.h Algorithms/mitkPPControlIIf.h Algorithms/mitkPPDebugError.h Algorithms/mitkPPDetailAutoRec.h Algorithms/mitkPPDetailDMCAutoRec.h Algorithms/mitkPPExpand.h Algorithms/mitkPPFacilitiesEmpty.h Algorithms/mitkPPFacilitiesExpand.h Algorithms/mitkPPLogicalBool.h Algorithms/mitkPPRepetitionDetailDMCFor.h Algorithms/mitkPPRepetitionDetailEDGFor.h Algorithms/mitkPPRepetitionDetailFor.h Algorithms/mitkPPRepetitionDetailMSVCFor.h Algorithms/mitkPPRepetitionFor.h Algorithms/mitkPPSeqElem.h Algorithms/mitkPPSeqForEach.h Algorithms/mitkPPSeqForEachProduct.h Algorithms/mitkPPSeq.h Algorithms/mitkPPSeqEnum.h Algorithms/mitkPPSeqSize.h Algorithms/mitkPPSeqToTuple.h Algorithms/mitkPPStringize.h Algorithms/mitkPPTupleEat.h Algorithms/mitkPPTupleElem.h Algorithms/mitkPPTupleRem.h Algorithms/mitkClippedSurfaceBoundsCalculator.h DataManagement/mitkCommon.h Interactions/mitkEventMapperAddOn.h Service/mitkAny.h Service/mitkGetModuleContext.h Service/mitkItkHashMap.h Service/mitkItkHashSet.h Service/mitkItkHashTable.h Service/mitkModuleAbstractTracked.h Service/mitkModuleAbstractTracked.tpp Service/mitkModuleActivator.h Service/mitkServiceFactory.h Service/mitkServiceTracker.h Service/mitkServiceTracker.tpp Service/mitkServiceTrackerCustomizer.h Service/mitkServiceTrackerPrivate.h Service/mitkServiceTrackerPrivate.tpp Service/mitkServiceUtils.h Service/mitkSharedData.h Service/mitkStaticInit.h Service/mitkTrackedService.h Service/mitkTrackedService.tpp Service/mitkTrackedServiceListener.h ) SET(CPP_FILES Algorithms/mitkBaseDataSource.cpp Algorithms/mitkBaseProcess.cpp Algorithms/mitkCoreObjectFactoryBase.cpp Algorithms/mitkCoreObjectFactory.cpp Algorithms/mitkDataNodeFactory.cpp Algorithms/mitkDataNodeSource.cpp Algorithms/mitkGeometry2DDataToSurfaceFilter.cpp Algorithms/mitkHistogramGenerator.cpp Algorithms/mitkImageCaster.cpp Algorithms/mitkImageCastPart1.cpp Algorithms/mitkImageCastPart2.cpp Algorithms/mitkImageCastPart3.cpp Algorithms/mitkImageCastPart4.cpp Algorithms/mitkImageChannelSelector.cpp Algorithms/mitkImageSliceSelector.cpp Algorithms/mitkImageSource.cpp Algorithms/mitkImageTimeSelector.cpp Algorithms/mitkImageToImageFilter.cpp Algorithms/mitkPointSetSource.cpp Algorithms/mitkPointSetToPointSetFilter.cpp Algorithms/mitkRGBToRGBACastImageFilter.cpp Algorithms/mitkSubImageSelector.cpp Algorithms/mitkSurfaceSource.cpp Algorithms/mitkSurfaceToSurfaceFilter.cpp Algorithms/mitkUIDGenerator.cpp Algorithms/mitkVolumeCalculator.cpp Algorithms/mitkClippedSurfaceBoundsCalculator.cpp Controllers/mitkBaseController.cpp Controllers/mitkCallbackFromGUIThread.cpp Controllers/mitkCameraController.cpp Controllers/mitkCameraRotationController.cpp Controllers/mitkFocusManager.cpp Controllers/mitkLimitedLinearUndo.cpp Controllers/mitkOperationEvent.cpp + Controllers/mitkPlanePositionManager.cpp Controllers/mitkProgressBar.cpp Controllers/mitkRenderingManager.cpp Controllers/mitkSliceNavigationController.cpp Controllers/mitkSlicesCoordinator.cpp Controllers/mitkSlicesRotator.cpp Controllers/mitkSlicesSwiveller.cpp Controllers/mitkStatusBar.cpp Controllers/mitkStepper.cpp Controllers/mitkTestManager.cpp Controllers/mitkUndoController.cpp Controllers/mitkVerboseLimitedLinearUndo.cpp Controllers/mitkVtkInteractorCameraController.cpp Controllers/mitkVtkLayerController.cpp DataManagement/mitkAbstractTransformGeometry.cpp DataManagement/mitkAnnotationProperty.cpp DataManagement/mitkApplicationCursor.cpp DataManagement/mitkBaseData.cpp DataManagement/mitkBaseProperty.cpp DataManagement/mitkClippingProperty.cpp DataManagement/mitkColorProperty.cpp DataManagement/mitkDataStorage.cpp #DataManagement/mitkDataTree.cpp DataManagement/mitkDataNode.cpp #DataManagement/mitkDataTreeStorage.cpp DataManagement/mitkDisplayGeometry.cpp DataManagement/mitkEnumerationProperty.cpp DataManagement/mitkGeometry2D.cpp DataManagement/mitkGeometry2DData.cpp DataManagement/mitkGeometry3D.cpp DataManagement/mitkGeometryData.cpp DataManagement/mitkGroupTagProperty.cpp DataManagement/mitkImage.cpp DataManagement/mitkImageDataItem.cpp DataManagement/mitkLandmarkBasedCurvedGeometry.cpp DataManagement/mitkLandmarkProjectorBasedCurvedGeometry.cpp DataManagement/mitkLandmarkProjector.cpp DataManagement/mitkLevelWindow.cpp DataManagement/mitkLevelWindowManager.cpp DataManagement/mitkLevelWindowPreset.cpp DataManagement/mitkLevelWindowProperty.cpp DataManagement/mitkLookupTable.cpp DataManagement/mitkLookupTables.cpp # specializations of GenericLookupTable DataManagement/mitkMemoryUtilities.cpp DataManagement/mitkModalityProperty.cpp DataManagement/mitkModeOperation.cpp DataManagement/mitkNodePredicateAnd.cpp DataManagement/mitkNodePredicateBase.cpp DataManagement/mitkNodePredicateCompositeBase.cpp DataManagement/mitkNodePredicateData.cpp DataManagement/mitkNodePredicateDataType.cpp DataManagement/mitkNodePredicateDimension.cpp DataManagement/mitkNodePredicateFirstLevel.cpp DataManagement/mitkNodePredicateNot.cpp DataManagement/mitkNodePredicateOr.cpp DataManagement/mitkNodePredicateProperty.cpp DataManagement/mitkNodePredicateSource.cpp DataManagement/mitkPlaneOrientationProperty.cpp DataManagement/mitkPlaneGeometry.cpp DataManagement/mitkPlaneOperation.cpp DataManagement/mitkPointOperation.cpp DataManagement/mitkPointSet.cpp DataManagement/mitkProperties.cpp DataManagement/mitkPropertyList.cpp + DataManagement/mitkRestorePlanePositionOperation.cpp DataManagement/mitkRotationOperation.cpp DataManagement/mitkSlicedData.cpp DataManagement/mitkSlicedGeometry3D.cpp DataManagement/mitkSmartPointerProperty.cpp DataManagement/mitkStandaloneDataStorage.cpp DataManagement/mitkStateTransitionOperation.cpp DataManagement/mitkStringProperty.cpp DataManagement/mitkSurface.cpp DataManagement/mitkSurfaceOperation.cpp DataManagement/mitkThinPlateSplineCurvedGeometry.cpp DataManagement/mitkTimeSlicedGeometry.cpp DataManagement/mitkTransferFunction.cpp DataManagement/mitkTransferFunctionInitializer.cpp DataManagement/mitkVector.cpp DataManagement/mitkVtkInterpolationProperty.cpp DataManagement/mitkVtkRepresentationProperty.cpp DataManagement/mitkVtkResliceInterpolationProperty.cpp DataManagement/mitkVtkScalarModeProperty.cpp DataManagement/mitkVtkVolumeRenderingProperty.cpp DataManagement/mitkWeakPointerProperty.cpp DataManagement/mitkShaderProperty.cpp DataManagement/mitkResliceMethodProperty.cpp DataManagement/mitkMaterial.cpp Interactions/mitkAction.cpp Interactions/mitkAffineInteractor.cpp Interactions/mitkCoordinateSupplier.cpp Interactions/mitkDisplayCoordinateOperation.cpp Interactions/mitkDisplayInteractor.cpp Interactions/mitkDisplayPositionEvent.cpp Interactions/mitkDisplayVectorInteractor.cpp Interactions/mitkDisplayVectorInteractorLevelWindow.cpp Interactions/mitkDisplayVectorInteractorScroll.cpp Interactions/mitkEvent.cpp Interactions/mitkEventDescription.cpp Interactions/mitkEventMapper.cpp Interactions/mitkGlobalInteraction.cpp Interactions/mitkInteractor.cpp Interactions/mitkMouseMovePointSetInteractor.cpp Interactions/mitkMoveSurfaceInteractor.cpp Interactions/mitkNodeDepententPointSetInteractor.cpp Interactions/mitkPointSetInteractor.cpp Interactions/mitkPositionEvent.cpp Interactions/mitkPositionTracker.cpp Interactions/mitkState.cpp Interactions/mitkStateEvent.cpp Interactions/mitkStateMachine.cpp Interactions/mitkStateMachineFactory.cpp Interactions/mitkTransition.cpp Interactions/mitkWheelEvent.cpp Interactions/mitkKeyEvent.cpp Interactions/mitkVtkEventAdapter.cpp Interactions/mitkCrosshairPositionEvent.cpp IO/mitkBaseDataIOFactory.cpp IO/mitkDicomSeriesReader.cpp IO/mitkFileReader.cpp IO/mitkFileSeriesReader.cpp IO/mitkFileWriter.cpp IO/mitkIpPicGet.c IO/mitkImageGenerator.cpp IO/mitkImageWriter.cpp IO/mitkImageWriterFactory.cpp IO/mitkItkImageFileIOFactory.cpp IO/mitkItkImageFileReader.cpp IO/mitkItkPictureWrite.cpp IO/mitkLookupTableProperty.cpp IO/mitkOperation.cpp IO/mitkPicFileIOFactory.cpp IO/mitkPicFileReader.cpp IO/mitkPicFileWriter.cpp IO/mitkPicHelper.cpp IO/mitkPicVolumeTimeSeriesIOFactory.cpp IO/mitkPicVolumeTimeSeriesReader.cpp IO/mitkPixelType.cpp IO/mitkPointSetIOFactory.cpp IO/mitkPointSetReader.cpp IO/mitkPointSetWriter.cpp IO/mitkPointSetWriterFactory.cpp IO/mitkRawImageFileReader.cpp IO/mitkStandardFileLocations.cpp IO/mitkSTLFileIOFactory.cpp IO/mitkSTLFileReader.cpp IO/mitkSurfaceVtkWriter.cpp IO/mitkSurfaceVtkWriterFactory.cpp IO/mitkVtiFileIOFactory.cpp IO/mitkVtiFileReader.cpp IO/mitkVtkImageIOFactory.cpp IO/mitkVtkImageReader.cpp IO/mitkVtkSurfaceIOFactory.cpp IO/mitkVtkSurfaceReader.cpp IO/vtkPointSetXMLParser.cpp IO/mitkLog.cpp Rendering/mitkBaseRenderer.cpp Rendering/mitkVtkMapper2D.cpp Rendering/mitkVtkMapper3D.cpp Rendering/mitkRenderWindowFrame.cpp Rendering/mitkGeometry2DDataMapper2D.cpp Rendering/mitkGeometry2DDataVtkMapper3D.cpp Rendering/mitkGLMapper2D.cpp Rendering/mitkGradientBackground.cpp Rendering/mitkManufacturerLogo.cpp Rendering/mitkMapper2D.cpp Rendering/mitkMapper3D.cpp Rendering/mitkMapper.cpp Rendering/mitkPointSetGLMapper2D.cpp Rendering/mitkPointSetVtkMapper3D.cpp Rendering/mitkPolyDataGLMapper2D.cpp Rendering/mitkSurfaceGLMapper2D.cpp Rendering/mitkSurfaceVtkMapper3D.cpp Rendering/mitkVolumeDataVtkMapper3D.cpp Rendering/mitkVtkPropRenderer.cpp Rendering/mitkVtkWidgetRendering.cpp Rendering/vtkMitkRectangleProp.cpp Rendering/vtkMitkRenderProp.cpp Rendering/mitkVtkEventProvider.cpp Rendering/mitkRenderWindow.cpp Rendering/mitkRenderWindowBase.cpp Rendering/mitkShaderRepository.cpp Rendering/mitkImageVtkMapper2D.cpp Rendering/vtkMitkThickSlicesFilter.cpp Rendering/vtkMitkApplyLevelWindowToRGBFilter.cpp Service/mitkAny.cpp Service/mitkAtomicInt.cpp Service/mitkCoreActivator.cpp Service/mitkCoreModuleContext.cpp Service/mitkModule.cpp Service/mitkModuleContext.cpp Service/mitkModuleEvent.cpp Service/mitkModuleInfo.cpp Service/mitkModulePrivate.cpp Service/mitkModuleRegistry.cpp Service/mitkModuleUtils.cpp Service/mitkModuleVersion.cpp Service/mitkLDAPExpr.cpp Service/mitkLDAPFilter.cpp Service/mitkServiceEvent.cpp Service/mitkServiceException.cpp Service/mitkServiceListenerEntry.cpp Service/mitkServiceListeners.cpp Service/mitkServiceProperties.cpp Service/mitkServiceReference.cpp Service/mitkServiceReferencePrivate.cpp Service/mitkServiceRegistration.cpp Service/mitkServiceRegistrationPrivate.cpp Service/mitkServiceRegistry.cpp ) diff --git a/Modules/Bundles/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.cpp b/Modules/Bundles/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.cpp index 7e42df757f..1ede256e63 100644 --- a/Modules/Bundles/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.cpp +++ b/Modules/Bundles/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.cpp @@ -1,940 +1,938 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision: 1.12 $ 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 "mitkDataNodeObject.h" #include "mitkProperties.h" #include "mitkSegTool2D.h" #include "mitkGlobalInteraction.h" #include "QmitkStdMultiWidget.h" #include "QmitkNewSegmentationDialog.h" #include #include #include "QmitkSegmentationView.h" #include "QmitkSegmentationPostProcessing.h" #include "QmitkSegmentationOrganNamesHandling.cpp" #include #include #include "mitkVtkResliceInterpolationProperty.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()->DeleteAllMarkers(); } } 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 ); - } + 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 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 + 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" + 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 + 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 + 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 + 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(); + 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); + = 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(); + = 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 ) + 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->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() ) + // 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) ) { - std::string markerName = "Contourmarker"; - unsigned int numberOfNodes = nodes.size(); - std::string nodeName = nodes.at( 0 )->GetName(); - if ( ( numberOfNodes == 1 ) && ( nodeName.find( markerName ) == 0) ) - { - this->OnContourMarkerSelected( nodes.at( 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->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 - ) - ); + ( + 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* ) ) ); + //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) ); + m_Controls->refImageSelector->setCurrentIndex( m_Controls->refImageSelector->Find(referenceData) ); - connect( m_Controls->refImageSelector, SIGNAL( OnSelectionChanged( const mitk::DataNode* ) ), - this, SLOT( OnComboBoxSelectionChanged( const mitk::DataNode* ) ) ); + 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); + // 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); + 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; - const mitk::PlaneGeometry* markerGeometry = - dynamic_cast ( node->GetData()->GetGeometry() ); - - 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; - } + // 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) - { - mitk::Point3D centerP = markerGeometry->GetOrigin(); - selectedRenderWindow->GetSliceNavigationController()->SelectSliceByPoint( - centerP); - selectedRenderWindow->GetSliceNavigationController()->ReorientSlices( - centerP, markerGeometry->GetNormal()); + // 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)); + 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; - } + //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); + // 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 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 isImage(false); + if (nodes.at(i)->GetData()) + { + isImage = dynamic_cast(nodes.at(i)->GetData()) != NULL; + } - bool isSegmentation(false); - nodes.at(i)->GetBoolProperty("binary", isSegmentation); + bool isSegmentation(false); + nodes.at(i)->GetBoolProperty("binary", isSegmentation); - // return first proper binary mitk::Image - if (isImage && isSegmentation) - { - return nodes.at(i); - } + // 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 ) - ); + && 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) + 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->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( ) ) ); + 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/Bundles/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.h b/Modules/Bundles/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.h index 75720f7d5d..31c6d31d13 100644 --- a/Modules/Bundles/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.h +++ b/Modules/Bundles/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.h @@ -1,161 +1,161 @@ /*====================================================================== Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision: 1.12 $ - + 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 QmitkSegmentationView_h #define QmitkSegmentationView_h #include "QmitkFunctionality.h" #include #include "ui_QmitkSegmentationControls.h" class QmitkRenderWindow; // class QmitkSegmentationPostProcessing; /** * \ingroup ToolManagerEtAl * \ingroup org_mitk_gui_qt_segmentation_internal * \warning Implementation of this class is split up into two .cpp files to make things more compact. Check both this file and QmitkSegmentationOrganNamesHandling.cpp */ class QmitkSegmentationView : public QmitkFunctionality { Q_OBJECT - + public: - + QmitkSegmentationView(); QmitkSegmentationView(const QmitkSegmentationView& other) { Q_UNUSED(other) throw std::runtime_error("Copy constructor not implemented"); } virtual ~QmitkSegmentationView(); /*! \brief Invoked when the DataManager selection changed */ virtual void OnSelectionChanged(mitk::DataNode* node); virtual void OnSelectionChanged(std::vector nodes); - + // reaction to new segmentations being created by segmentation tools void NewNodesGenerated(); void NewNodeObjectsGenerated(mitk::ToolManager::DataVectorType*); - + // QmitkFunctionality's activate/deactivate virtual void Activated(); - virtual void Deactivated(); - + virtual void Deactivated(); + // QmitkFunctionality's changes regarding THE QmitkStdMultiWidget virtual void StdMultiWidgetAvailable(QmitkStdMultiWidget& stdMultiWidget); virtual void StdMultiWidgetNotAvailable(); virtual void StdMultiWidgetClosed(QmitkStdMultiWidget& stdMultiWidget); - + // BlueBerry's notification about preference changes (e.g. from a dialog) virtual void OnPreferencesChanged(const berry::IBerryPreferences*); - + // observer to mitk::RenderingManager's RenderingManagerViewsInitializedEvent event void RenderingManagerReinitialized(const itk::EventObject&); - + // observer to mitk::SliceController's SliceRotation event void SliceRotation(const itk::EventObject&); - + static const std::string VIEW_ID; protected slots: - + void OnComboBoxSelectionChanged(const mitk::DataNode* node); - + // reaction to the button "New segmentation" void CreateNewSegmentation(); - + // reaction to the button "New segmentation" void CreateSegmentationFromSurface(); - + // called when a segmentation tool is activated void ManualToolSelected(int id); - + // called when one of "Manual", "Organ", "Lesion" pages of the QToolbox is selected void ToolboxStackPageChanged(int id); - + void OnSurfaceSelectionChanged(); - + //called when the checkbox Remember Contour Positions is selected/deselected void CheckboxRememberContourPositionsStateChanged(int state); protected: - + // a type for handling lists of DataNodes typedef std::vector NodeList; - + // set available multiwidget void SetMultiWidget(QmitkStdMultiWidget* multiWidget); - + // actively query the current selection of data manager //void PullCurrentDataManagerSelection(); - + // reactions to selection events from data manager (and potential other senders) //void BlueBerrySelectionChanged(berry::IWorkbenchPart::Pointer sourcepart, berry::ISelection::ConstPointer selection); mitk::DataNode::Pointer FindFirstRegularImage( std::vector nodes ); mitk::DataNode::Pointer FindFirstSegmentation( std::vector nodes ); - + // propagate BlueBerry selection to ToolManager for manual segmentation void SetToolManagerSelection(const mitk::DataNode* referenceData, const mitk::DataNode* workingData); - + // checks if selected reference image is aligned with the slices stack orientation of the StdMultiWidget void CheckImageAlignment(); - + // checks if given render window aligns with the slices of given image bool IsRenderWindowAligned(QmitkRenderWindow* renderWindow, mitk::Image* image); - + // make sure all images/segmentations look as selected by the users in this view's preferences void ForceDisplayPreferencesUponAllImages(); - + // decorates a DataNode according to the user preference settings void ApplyDisplayOptions(mitk::DataNode* node); - + // GUI setup void CreateQtPartControl(QWidget* parent); - + // handling of a list of known (organ name, organ color) combination // ATTENTION these methods are defined in QmitkSegmentationOrganNamesHandling.cpp QStringList GetDefaultOrganColorString(); void UpdateOrganList(QStringList& organColors, const QString& organname, mitk::Color colorname); void AppendToOrganList(QStringList& organColors, const QString& organname, int r, int g, int b); - + // If a contourmarker is selected, the plane in the related widget will be reoriented according to the marker`s geometry void OnContourMarkerSelected (const mitk::DataNode* node); // the Qt parent of our GUI (NOT of this object) QWidget* m_Parent; - + // our GUI Ui::QmitkSegmentationControls * m_Controls; - + // THE currently existing QmitkStdMultiWidget QmitkStdMultiWidget * m_MultiWidget; - + // QmitkSegmentationPostProcessing* m_PostProcessing; - + unsigned long m_RenderingManagerObserverTag; unsigned long m_SlicesRotationObserverTag1; unsigned long m_SlicesRotationObserverTag2; - + }; #endif /*QMITKsegmentationVIEW_H_*/ diff --git a/Modules/MitkExt/Interactions/mitkSegTool2D.cpp b/Modules/MitkExt/Interactions/mitkSegTool2D.cpp index 86270978c4..d8986df204 100644 --- a/Modules/MitkExt/Interactions/mitkSegTool2D.cpp +++ b/Modules/MitkExt/Interactions/mitkSegTool2D.cpp @@ -1,330 +1,291 @@ /*========================================================================= - + 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" #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 ("Contourmarker"), + 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; + 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 ) { - mitk::PlaneGeometry* currentGeometry2D = dynamic_cast( const_cast(positionEvent->GetSender()->GetCurrentWorldGeometry2D())); - if ( ( currentGeometry2D != NULL ) && ( !ContourmarkerAlreadyExists( currentGeometry2D )) ) - { - //Creating PlanarFigure which serves as marker - mitk::PlanarCircle::Pointer contourMarker = mitk::PlanarCircle::New(); - contourMarker->SetGeometry2D( currentGeometry2D ); - - //Here we check which consecutive number must be the suffix to the markers name - std::stringstream markerStream; - markerStream << m_Contourmarkername; - int markerCount = 0; - mitk::DataNode* workingNode (m_ToolManager->GetWorkingData(0)); - while (m_ToolManager->GetDataStorage()->GetNamedDerivedNode(markerStream.str().c_str(), workingNode)) - { - m_ToolManager->GetDataStorage()->GetNamedDerivedNode(markerStream.str().c_str(),workingNode)->SetProperty( "visible", mitk::BoolProperty::New(false) ); - markerCount++; - markerStream.str(""); - markerStream.clear(); - markerStream << m_Contourmarkername ; - markerStream << " "; - markerStream << markerCount; - } - - //Now we place the figure in the image and the DataManager as a new Node - Point2D controlPoint2D; - Point3D controlPoint3D = positionEvent->GetWorldPosition(); - currentGeometry2D->Map(controlPoint3D ,controlPoint2D); - DataNode::Pointer rotatedContourNode = DataNode::New(); - rotatedContourNode->SetData(contourMarker); - rotatedContourNode->SetProperty( "name", StringProperty::New(markerStream.str()) ); - rotatedContourNode->SetBoolProperty( "PlanarFigureInitializedWindow", true, positionEvent->GetSender() ); - rotatedContourNode->SetProperty( "includeInBoundingBox", BoolProperty::New(false)); - m_ToolManager->GetDataStorage()->Add(rotatedContourNode, workingNode); - } -} + const mitk::Geometry2D* plane = dynamic_cast (dynamic_cast< const mitk::SlicedGeometry3D*>( + positionEvent->GetSender()->GetSliceNavigationController()->GetCurrentGeometry3D())->GetGeometry2D(0)); -bool mitk::SegTool2D::ContourmarkerAlreadyExists ( const mitk::PlaneGeometry* currentGeometry2D ) -{ - itk::VectorContainer::ConstPointer allNodes = m_ToolManager->GetDataStorage()->GetDerivations( m_ToolManager->GetWorkingData(0) ); - mitk::DataNode* currentNode; - for( unsigned int i = 0; i < allNodes->Size(); i++ ) + unsigned int size = mitk::PlanePositionManager::GetInstance()->GetNumberOfPlanePositions(); + unsigned int id = mitk::PlanePositionManager::GetInstance()->AddNewPlanePosition(plane, positionEvent->GetSender()->GetSliceNavigationController()->GetSlice()->GetPos()); + + if (plane) + { + + if ( id == size ) { - currentNode = allNodes->GetElement(i); - std::string nodeName = currentNode->GetName(); - const mitk::PlaneGeometry* nodeGeometry = dynamic_cast( currentNode->GetData()->GetGeometry() ); - if ( !nodeGeometry ) continue; - Point3D nodeCenter = nodeGeometry->GetCenter(); - Point3D currentCenter = currentGeometry2D->GetCenter(); - /*mitk::ScalarType distance1 = currentGeometry2D->DistanceFromPlane(nodeCenter); - mitk::ScalarType distance2 = nodeGeometry->DistanceFromPlane(currentCenter);*/ - Vector3D nodeNormal = nodeGeometry->GetNormal(); - Vector3D currentNormal = currentGeometry2D->GetNormal(); - //Timestep... - - bool isSameGeometry = ( (nodeCenter == currentCenter) && (nodeNormal == currentNormal)); - - - /*bool isSameGeometry = ( ( nodeGeometry->GetOrigin() == currentGeometry2D->GetOrigin() ) && - ( nodeGeometry->GetBounds() == currentGeometry2D->GetBounds() ) && - ( nodeGeometry->GetIndexToWorldTransform()->GetMatrix() == currentGeometry2D->GetIndexToWorldTransform()->GetMatrix() ) && - ( nodeGeometry->GetIndexToWorldTransform()->GetOffset() == currentGeometry2D->GetIndexToWorldTransform()->GetOffset() ) && - ( nodeGeometry->GetSpacing() == currentGeometry2D->GetSpacing() ) && - ( nodeGeometry->GetTimeBounds() ) == currentGeometry2D->GetTimeBounds() ) && - ( nodeGeometry->GetImageGeometry() == currentGeometry2D->GetImageGeometry() );*/ - - int stringPosition = nodeName.find( m_Contourmarkername ); - if ( ( stringPosition == 0 ) && ( isSameGeometry ) ) - return true; - } + //Creating PlanarFigure which currently serves as marker + mitk::PlanarCircle::Pointer contourMarker = mitk::PlanarCircle::New(); + contourMarker->SetGeometry2D( const_cast(plane)); - return false; -} + 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; + << " " << 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; } diff --git a/Modules/MitkExt/Interactions/mitkSegTool2D.h b/Modules/MitkExt/Interactions/mitkSegTool2D.h index 3fe0e170ac..75a5876067 100644 --- a/Modules/MitkExt/Interactions/mitkSegTool2D.h +++ b/Modules/MitkExt/Interactions/mitkSegTool2D.h @@ -1,134 +1,130 @@ /*========================================================================= 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 mitkSegTool2D_h_Included #define mitkSegTool2D_h_Included #include "mitkCommon.h" #include "MitkExtExports.h" #include "mitkTool.h" #include "mitkImage.h" #include "mitkStateEvent.h" #include "mitkPositionEvent.h" -//ContourSet - Test -#include "mitkContourSet.h" +#include "mitkPlanePositionManager.h" +#include "mitkRestorePlanePositionOperation.h" +#include "mitkInteractionConst.h" namespace mitk { class BaseRenderer; /** \brief Abstract base class for segmentation tools. \sa Tool \ingroup Interaction \ingroup ToolManagerEtAl Implements 2D segmentation specific helper methods, that might be of use to all kind of 2D segmentation tools. At the moment these are: - Determination of the slice where the user paints upon (DetermineAffectedImageSlice) - Projection of a 3D contour onto a 2D plane/slice SegTool2D tries to structure the interaction a bit. If you pass "PressMoveRelease" as the interaction type of your derived tool, you might implement the methods OnMousePressed, OnMouseMoved, and OnMouseReleased. Yes, your guess about when they are called is correct. \warning Only to be instantiated by mitk::ToolManager. $Author$ */ class MitkExt_EXPORT SegTool2D : public Tool { public: mitkClassMacro(SegTool2D, Tool); /** \brief Calculates for a given Image and PlaneGeometry, which slice of the image (in index corrdinates) is meant by the plane. \return false, if no slice direction seems right (e.g. rotated planes) \param affectedDimension The image dimension, which is constant for all points in the plane, e.g. Transversal --> 2 \param affectedSlice The index of the image slice */ static bool DetermineAffectedImageSlice( const Image* image, const PlaneGeometry* plane, int& affectedDimension, int& affectedSlice ); void SetRememberContourPositions(bool); protected: SegTool2D(); // purposely hidden SegTool2D(const char*); // purposely hidden virtual ~SegTool2D(); virtual bool OnMousePressed (Action*, const StateEvent*); virtual bool OnMouseMoved (Action*, const StateEvent*); virtual bool OnMouseReleased(Action*, const StateEvent*); virtual bool OnInvertLogic (Action*, const StateEvent*); /** \brief Extract the slice of an image that the user just scribbles on. \return NULL if SegTool2D is either unable to determine which slice was affected, or if there was some problem getting the image data at that position. */ Image::Pointer GetAffectedImageSliceAs2DImage(const PositionEvent*, const Image* image); /** \brief Extract the slice of the currently selected working image that the user just scribbles on. \return NULL if SegTool2D is either unable to determine which slice was affected, or if there was some problem getting the image data at that position, or just no working image is selected. */ Image::Pointer GetAffectedWorkingSlice(const PositionEvent*); /** \brief Extract the slice of the currently selected reference image that the user just scribbles on. \return NULL if SegTool2D is either unable to determine which slice was affected, or if there was some problem getting the image data at that position, or just no reference image is selected. */ Image::Pointer GetAffectedReferenceSlice(const PositionEvent*); /** - \brief Adds a new node called @a contourmarker which holds a mitk::PlanarFigure. By selecting this node the slices will be oriented according to the planarGeometry + \brief Adds a new node called Contourmarker to the datastorage which holds a mitk::PlanarFigure. + By selecting this node the slicestack will be reoriented according to the PlanarFigure's Geometry */ void AddContourmarker ( const PositionEvent* ); - void AddContour ( const mitk::Contour::Pointer ); void InteractiveSegmentationBugMessage( const std::string& message ); bool m_RememberContourPositions; private: BaseRenderer* m_LastEventSender; unsigned int m_LastEventSlice; - //The prefix of the contourmarkernames. Suffix is a consecutive number + //The prefix of the contourmarkername. Suffix is a consecutive number const std::string m_Contourmarkername; - - /** - \brief Checks whether a marker for the currentGeometry already exists - */ - bool ContourmarkerAlreadyExists ( const mitk::PlaneGeometry* currentGeometry2D ); }; } // namespace #endif