diff --git a/Core/Code/Interactions/mitkPointSetInteractor.cpp b/Core/Code/Interactions/mitkPointSetInteractor.cpp index 0442048a4e..a350342d58 100644 --- a/Core/Code/Interactions/mitkPointSetInteractor.cpp +++ b/Core/Code/Interactions/mitkPointSetInteractor.cpp @@ -1,1169 +1,1182 @@ /*========================================================================= 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 "mitkPointSetInteractor.h" #include "mitkPointOperation.h" #include "mitkPositionEvent.h" #include "mitkPointSet.h" //#include "mitkStatusBar.h" #include "mitkDataNode.h" #include "mitkInteractionConst.h" #include "mitkAction.h" #include "mitkStateEvent.h" #include "mitkOperationEvent.h" #include "mitkUndoController.h" #include "mitkStateMachineFactory.h" #include "mitkStateTransitionOperation.h" #include "mitkBaseRenderer.h" #include "mitkRenderingManager.h" //how precise must the user pick the point //default value const int PRECISION = 5; mitk::PointSetInteractor ::PointSetInteractor(const char * type, DataNode* dataNode, int n) :Interactor(type, dataNode), m_Precision(PRECISION), m_N(n) { if (m_N==0) { STATEMACHINE_WARN<<"Instanciation of PointSetInteractor which takes care of 0 points does't make sense!\n"; STATEMACHINE_WARN<<"Setting number of points to 1!\n"; m_N = 1; } m_LastPoint.Fill(0); m_SumVec.Fill(0); this->InitAccordingToNumberOfPoints(); } mitk::PointSetInteractor::~PointSetInteractor() { } //##Documentation //## overwritten cause this class can handle it better! float mitk::PointSetInteractor::CanHandleEvent(StateEvent const* stateEvent) const { float returnValue = 0.0; //if it is a key event that can be handled in the current state, then return 0.5 mitk::DisplayPositionEvent const *disPosEvent = dynamic_cast (stateEvent->GetEvent()); //Key event handling: if (disPosEvent == NULL) { //check, if the current state has a transition waiting for that key event. if (this->GetCurrentState()->GetTransition(stateEvent->GetId())!=NULL) { return 0.5; } else { return 0; } } //on MouseMove do nothing! if (stateEvent->GetEvent()->GetType() == mitk::Type_MouseMove) { return 0; } //get the time of the sender to look for the right transition. mitk::BaseRenderer* sender = stateEvent->GetEvent()->GetSender(); if (sender != NULL) { unsigned int timeStep = sender->GetTimeStep(m_DataNode->GetData()); //if the event can be understood and if there is a transition waiting for that event mitk::State const* state = this->GetCurrentState(timeStep); if (state!= NULL) if (state->GetTransition(stateEvent->GetId())!=NULL) returnValue = 0.5;//it can be understood mitk::PointSet *pointSet = dynamic_cast(m_DataNode->GetData()); if ( pointSet != NULL ) { //if we have one point or more, then check if the have been picked if ( (pointSet->GetSize( timeStep ) > 0) && (pointSet->SearchPoint( disPosEvent->GetWorldPosition(), m_Precision, timeStep) > -1) ) { returnValue = 1.0; } } } return returnValue; } //TODO: add a new calculation of precision here! Input: StateEvent and Precision //the method does a 2D picking with display coordinates and display geometry. //Here the distance between the mouse position and the point is not as relative anymore! //float mitk::PointSetInteractor::CalculatePrecision(float precision, mitk::StateEvent stateEvent) //{ // mitk::BaseRenderer *renderer = stateEvent->GetEvent()->GetSender(); // if (renderer != NULL) // { // const mitk::DisplayGeometry* displayGeometry = renderer->GetDisplayGeometry(); // if (displayGeometry != NULL) // displayGeometry->WorldToDisplay(, lineFrom); // precision = // } // // return precision; // //} void mitk::PointSetInteractor::UnselectAll( unsigned int timeStep, ScalarType timeInMS ) { mitk::PointSet *pointSet = dynamic_cast( m_DataNode->GetData() ); if ( pointSet == NULL ) { return; } mitk::PointSet::DataType *itkPointSet = pointSet->GetPointSet( timeStep ); if ( itkPointSet == NULL ) { return; } mitk::PointSet::PointsContainer::Iterator it, end; end = itkPointSet->GetPoints()->End(); for (it = itkPointSet->GetPoints()->Begin(); it != end; it++) { int position = it->Index(); PointSet::PointDataType pointData = {0, false, PTUNDEFINED}; itkPointSet->GetPointData( position, &pointData ); //then declare an operation which unselects this point; //UndoOperation as well! if ( pointData.selected ) { mitk::Point3D noPoint; noPoint.Fill( 0 ); mitk::PointOperation *doOp = new mitk::PointOperation( OpDESELECTPOINT, timeInMS, noPoint, position); if ( m_UndoEnabled ) { mitk::PointOperation *undoOp = new mitk::PointOperation(OpSELECTPOINT, timeInMS, noPoint, position); OperationEvent *operationEvent = new OperationEvent( pointSet, doOp, undoOp ); m_UndoController->SetOperationEvent( operationEvent ); } pointSet->ExecuteOperation( doOp ); if ( !m_UndoEnabled ) delete doOp; } } } void mitk::PointSetInteractor::SelectPoint( int position, unsigned int timeStep, ScalarType timeInMS ) { mitk::PointSet *pointSet = dynamic_cast< mitk::PointSet * >( m_DataNode->GetData() ); //if List is empty, then no select of a point can be done! if ( (pointSet == NULL) || (pointSet->GetSize( timeStep ) <= 0) ) { return; } //dummyPoint... not needed anyway mitk::Point3D noPoint; noPoint.Fill(0); mitk::PointOperation *doOp = new mitk::PointOperation( OpSELECTPOINT, timeInMS, noPoint, position); if ( m_UndoEnabled ) { mitk::PointOperation* undoOp = new mitk::PointOperation( OpDESELECTPOINT, timeInMS, noPoint, position); OperationEvent *operationEvent = new OperationEvent(pointSet, doOp, undoOp); m_UndoController->SetOperationEvent(operationEvent); } pointSet->ExecuteOperation( doOp ); if ( !m_UndoEnabled ) delete doOp; } bool mitk::PointSetInteractor::ExecuteAction( Action* action, mitk::StateEvent const* stateEvent ) { bool ok = false;//for return type bool //checking corresponding Data; has to be a PointSet or a subclass mitk::PointSet* pointSet = dynamic_cast(m_DataNode->GetData()); if ( pointSet == NULL ) { return false; } //get the timestep to support 3D+T const mitk::Event *theEvent = stateEvent->GetEvent(); mitk::ScalarType timeInMS = 0.0; //check if the current timestep has to be changed if ( theEvent ) { if (theEvent->GetSender() != NULL) { //additionaly to m_TimeStep we need timeInMS to satisfy the execution of the operations timeInMS = theEvent->GetSender()->GetTime(); } } //for reading on the points, Id's etc mitk::PointSet::DataType *itkPointSet = pointSet->GetPointSet( m_TimeStep ); if ( itkPointSet == NULL ) { return false; } mitk::PointSet::PointsContainer *points = itkPointSet->GetPoints(); /*Each case must watch the type of the event!*/ switch (action->GetActionId()) { case AcDONOTHING: ok = true; break; case AcCHECKOPERATION: //to check if the given Event is a DisplayPositionEvent. { mitk::DisplayPositionEvent const *dispPosEvent = dynamic_cast ( stateEvent->GetEvent()); if (dispPosEvent != NULL) { mitk::StateEvent* newStateEvent = new mitk::StateEvent(EIDYES, stateEvent->GetEvent()); this->HandleEvent( newStateEvent ); delete newStateEvent; } else { mitk::StateEvent* newStateEvent = new mitk::StateEvent(EIDNO, stateEvent->GetEvent()); this->HandleEvent( newStateEvent ); delete newStateEvent; } ok = true; break; } case AcADDPOINT: // Declare two operations: one for the selected state: deselect the last // one selected and select the new one the other operation is the add // operation: There the first empty place have to be found and the new // point inserted into that space { mitk::DisplayPositionEvent const *posEvent = dynamic_cast < const mitk::DisplayPositionEvent * > (stateEvent->GetEvent()); // Check if it is a DisplayEvent thrown in a 3D window. Then the // z-information is missing. Returning false might end in the state // full, but the last point couldn't be added, so the set wouldn't be // full. So a extra Action that checks the operationtype has been added. if ( posEvent == NULL ) { return false; } mitk::Point3D itkPoint; itkPoint = posEvent->GetWorldPosition(); // undo-supported deselect of all points in the DataList; if List is // empty, then nothing will be unselected this->UnselectAll( m_TimeStep, timeInMS ); // find the position, the point is to be added to: first entry with // empty index. If the Set is empty, then start with 0. if not empty, // then take the first index not occupied int lastPosition = 0; if (!points->empty()) { mitk::PointSet::PointsIterator it, end; it = points->Begin(); end = points->End(); while( it != end ) { if (!points->IndexExists(lastPosition)) break; ++it; ++lastPosition; } } PointOperation* doOp = new mitk::PointOperation( OpINSERT, timeInMS, itkPoint, lastPosition); if (m_UndoEnabled) { // difference between OpDELETE and OpREMOVE is, that OpDELETE deletes // a point at the end, and OpREMOVE deletes it from the given position // remove is better, cause we need the position to add or remove the // point anyway. We can get the last position from size() PointOperation *undoOp = new mitk::PointOperation( OpREMOVE, timeInMS, itkPoint, lastPosition); OperationEvent *operationEvent = new OperationEvent(pointSet, doOp, undoOp, "Add point"); m_UndoController->SetOperationEvent(operationEvent); } //execute the Operation pointSet->ExecuteOperation(doOp); if ( !m_UndoEnabled ) delete doOp; //the point is added and directly selected in PintSet. So no need to call OpSELECTPOINT ok = true; // Update the display mitk::RenderingManager::GetInstance()->RequestUpdateAll(); break; } case AcINITMOVEMENT: { mitk::PositionEvent const *posEvent = dynamic_cast (stateEvent->GetEvent()); if (posEvent == NULL) return false; // start of the Movement is stored to calculate the undoKoordinate // in FinishMovement m_LastPoint = posEvent->GetWorldPosition(); // initialize a value to calculate the movement through all // MouseMoveEvents from MouseClick to MouseRelease m_SumVec.Fill(0); ok = true; break; } case AcMOVESELECTED://moves all selected Elements { mitk::PositionEvent const *posEvent = dynamic_cast (stateEvent->GetEvent()); if (posEvent == NULL) return false; mitk::Point3D newPoint, resultPoint; newPoint = posEvent->GetWorldPosition(); // search the elements in the list that are selected then calculate the // vector, because only with the vector we can move several elements in // the same direction // newPoint - lastPoint = vector // then move all selected and set the lastPoint = newPoint. // then add all vectors to a summeryVector (to be able to calculate the // startpoint for undoOperation) mitk::Vector3D dirVector = newPoint - m_LastPoint; //sum up all Movement for Undo in FinishMovement m_SumVec = m_SumVec + dirVector; mitk::PointSet::PointsIterator it, end; it = points->Begin(); end = points->End(); while( it != end ) { int position = it->Index(); if ( pointSet->GetSelectInfo(position, m_TimeStep) )//if selected { PointSet::PointType pt = pointSet->GetPoint(position, m_TimeStep); mitk::Point3D sumVec; sumVec[0] = pt[0]; sumVec[1] = pt[1]; sumVec[2] = pt[2]; resultPoint = sumVec + dirVector; PointOperation* doOp = new mitk::PointOperation(OpMOVE, timeInMS, resultPoint, position); //execute the Operation //here no undo is stored, because the movement-steps aren't interesting. // only the start and the end is interisting to store for undo. pointSet->ExecuteOperation(doOp); delete doOp; } ++it; } m_LastPoint = newPoint;//for calculation of the direction vector ok = true; // Update the display mitk::RenderingManager::GetInstance()->RequestUpdateAll(); break; } case AcREMOVEPOINT://remove the given Point from the list { //if the point to be removed is given by the positionEvent: mitk::PositionEvent const *posEvent = dynamic_cast (stateEvent->GetEvent()); if (posEvent != NULL) { mitk::Point3D itkPoint; itkPoint = posEvent->GetWorldPosition(); //search the point in the list int position = pointSet->SearchPoint(itkPoint, 0.0, m_TimeStep); //distance set to 0, cause we already got the exact point from last //State checkpointbut we also need the position in the list to remove it if (position>=0)//found a point { PointSet::PointType pt = pointSet->GetPoint(position, m_TimeStep); itkPoint[0] = pt[0]; itkPoint[1] = pt[1]; itkPoint[2] = pt[2]; //Undo PointOperation* doOp = new mitk::PointOperation(OpREMOVE, timeInMS, itkPoint, position); if (m_UndoEnabled) //write to UndoMechanism { PointOperation* undoOp = new mitk::PointOperation(OpINSERT, timeInMS, itkPoint, position); OperationEvent *operationEvent = new OperationEvent(pointSet, doOp, undoOp, "Remove point"); m_UndoController->SetOperationEvent(operationEvent); } //execute the Operation pointSet->ExecuteOperation(doOp); if ( !m_UndoEnabled ) delete doOp; /*now select the point "position-1", and if it is the first in list, then contine at the last in list*/ //only then a select of a point is possible! if (pointSet->GetSize( m_TimeStep ) > 0) { if (position>0)//not the first in list { this->SelectPoint( position-1, m_TimeStep, timeInMS ); } //it was the first point in list, that was removed, so select //the last in list else { position = pointSet->GetSize( m_TimeStep ) - 1; //last in list this->SelectPoint( position, m_TimeStep, timeInMS ); }//else }//if ok = true; } } else //no position is given so remove all selected elements { //delete all selected points //search for the selected one and then declare the operations! mitk::PointSet::PointsContainer::Iterator it, end; it = points->Begin(); end = points->End(); int position = 0; int previousExistingPosition = -1;//to recognize the last existing position; needed because the iterator gets invalid if the point is deleted! int lastDelPrevExistPosition = -1; //the previous position of the last deleted point while (it != end) { if (points->IndexExists(it->Index())) { //if point is selected if ( pointSet->GetSelectInfo(it->Index(), m_TimeStep) ) { //get the coordinates of that point to be undoable PointSet::PointType selectedPoint = it->Value(); mitk::Point3D itkPoint; itkPoint[0] = selectedPoint[0]; itkPoint[1] = selectedPoint[1]; itkPoint[2] = selectedPoint[2]; position = it->Index(); PointOperation* doOp = new mitk::PointOperation(OpREMOVE, timeInMS, itkPoint, position); //Undo if (m_UndoEnabled) //write to UndoMechanism { PointOperation* undoOp = new mitk::PointOperation(OpINSERT, timeInMS, itkPoint, position); OperationEvent *operationEvent = new OperationEvent(pointSet, doOp, undoOp, "Remove point"); m_UndoController->SetOperationEvent(operationEvent); } pointSet->ExecuteOperation(doOp); if ( !m_UndoEnabled ) delete doOp; //after delete the iterator is undefined, so start again //count to the last existing entry if (points->Size()>1 && points->IndexExists(previousExistingPosition)) { for (it = points->Begin(); it != points->End(); it++) { if (it->Index() == (unsigned int) previousExistingPosition) { lastDelPrevExistPosition = previousExistingPosition; break; //return if the iterator on the last existing position is found } } } else // size <= 1 or no previous existing position set { //search for the first existing position for (it = points->Begin(); it != points->End(); it++) if (points->IndexExists(it->Index())) { previousExistingPosition = it->Index(); break; } } //now that we have set the iterator, lets get sure, that the next it++ will not crash! if (it == end) { break; } }//if else { previousExistingPosition = it->Index(); } }//if index exists it++; }//while if (lastDelPrevExistPosition < 0)//the var has not been set because the first element was deleted and there was no prev position lastDelPrevExistPosition = previousExistingPosition; //go to the end /* * now select the point before the point/points that was/were deleted */ if (pointSet->GetSize( m_TimeStep ) > 0) //only then a select of a point is possible! { if (points->IndexExists(lastDelPrevExistPosition)) { this->SelectPoint( lastDelPrevExistPosition, m_TimeStep, timeInMS ); } else { //select the first existing element for (mitk::PointSet::PointsContainer::Iterator it = points->Begin(); it != points->End(); it++) if (points->IndexExists(it->Index())) { this->SelectPoint( it->Index(), m_TimeStep, timeInMS ); break; } } }//if ok = true; }//else }//case // Update the display mitk::RenderingManager::GetInstance()->RequestUpdateAll(); break; // Remove all Points that have been set at once. // TODO: Undo function not supported yet. case AcREMOVEALL: { if ( !points->empty() ) { PointSet::PointType pt; mitk::PointSet::PointsContainer::Iterator it, end; it = points->Begin(); end = points->End(); int position = 0; while ( it != end ) { position = it->Index(); if ( points->IndexExists( position ) ) { pt = pointSet->GetPoint( position, m_TimeStep ); PointOperation* doOp = new mitk::PointOperation( OpREMOVE, timeInMS, pt, position ); ++it; pointSet->ExecuteOperation( doOp ); delete doOp; } else it++; } } ok = true; // Update the display mitk::RenderingManager::GetInstance()->RequestUpdateAll(); break; } //Checking if the Point transmitted is close enough to one point. Then //generate a new event with the point and let this statemaschine //handle the event. case AcCHECKELEMENT: { mitk::PositionEvent const *posEvent = dynamic_cast (stateEvent->GetEvent()); if (posEvent != NULL) { mitk::Point3D worldPoint = posEvent->GetWorldPosition(); int position = pointSet->SearchPoint( worldPoint, m_Precision, m_TimeStep ); if (position>=0)//found a point near enough to the given point { //get that point, the one meant by the user! PointSet::PointType pt = pointSet->GetPoint(position, m_TimeStep); mitk::Point2D displPoint; displPoint[0] = worldPoint[0]; displPoint[1] = worldPoint[1]; //new Event with information YES and with the correct point mitk::PositionEvent const* newPosEvent = new mitk::PositionEvent(posEvent->GetSender(), Type_None, BS_NoButton, BS_NoButton, Key_none, displPoint, pt); mitk::StateEvent* newStateEvent = new mitk::StateEvent(EIDYES, newPosEvent); //call HandleEvent to leave the guard-state this->HandleEvent( newStateEvent ); delete newStateEvent; delete newPosEvent; ok = true; } else { //new Event with information NO mitk::StateEvent* newStateEvent = new mitk::StateEvent(EIDNO, posEvent); this->HandleEvent(newStateEvent ); delete newStateEvent; ok = true; } } else { STATEMACHINE_DEBUG("OperationError")<GetType()<<" AcCHECKELEMENT expected PointOperation."; mitk::DisplayPositionEvent const *disPosEvent = dynamic_cast ( stateEvent->GetEvent()); if (disPosEvent != NULL) { //2d Koordinates for 3D Interaction; return false to redo //the last statechange mitk::StateEvent* newStateEvent = new mitk::StateEvent(EIDNO, disPosEvent); this->HandleEvent(newStateEvent ); delete newStateEvent; ok = true; } } break; } case AcCHECKONESELECTED: //check if there is a point that is selected { if (pointSet->GetNumberOfSelected(m_TimeStep)>0) { mitk::StateEvent* newStateEvent = new mitk::StateEvent( EIDYES, theEvent); this->HandleEvent( newStateEvent ); delete newStateEvent; } else //not selected then call event EIDNO { //new Event with information NO mitk::StateEvent* newStateEvent = new mitk::StateEvent( EIDNO, theEvent); this->HandleEvent( newStateEvent ); delete newStateEvent; } ok = true; break; } case AcCHECKSELECTED: /*check, if the given point is selected: if no, then send EIDNO if yes, then send EIDYES*/ // check, if: because of the need to look up the point again, it is // possible, that we grab the wrong point in case there are two same points // so maybe we do have to set a global index for further computation, // as long, as the mouse is moved... { int position = -1; mitk::PositionEvent const *posEvent = dynamic_cast (stateEvent->GetEvent()); if (posEvent == NULL) return false; mitk::Point3D worldPoint = posEvent->GetWorldPosition(); position = pointSet->SearchPoint(worldPoint, m_Precision, m_TimeStep); if (position>=0) { mitk::PositionEvent const *newPosEvent = new mitk::PositionEvent(posEvent->GetSender(), posEvent->GetType(), posEvent->GetButton(), posEvent->GetButtonState(), posEvent->GetKey(), posEvent->GetDisplayPosition(), posEvent->GetWorldPosition()); //if selected on true, then call Event EIDYES if (pointSet->GetSelectInfo(position, m_TimeStep)) { mitk::StateEvent* newStateEvent = new mitk::StateEvent( EIDYES, newPosEvent ); this->HandleEvent( newStateEvent ); delete newStateEvent; ok = true; //saving the spot for calculating the direction vector in moving m_LastPoint = posEvent->GetWorldPosition(); } else //not selected then call event EIDNO { //new Event with information NO mitk::StateEvent* newStateEvent = new mitk::StateEvent( EIDNO, newPosEvent ); this->HandleEvent( newStateEvent ); delete newStateEvent; ok = true; } delete newPosEvent; } //the position wasn't set properly. If necessary: search the given //point in list and set var position else { /* mitk::StatusBar::GetInstance()->DisplayText( "Message from mitkPointSetInteractor: Error in Actions! Check Config XML-file", 10000); */ ok = false; } break; } //generate Events if the set will be full after the addition of the // point or not. case AcCHECKNMINUS1: { // number of points not limited->pass on // "Amount of points in Set is smaller then N-1" if (m_N<0) { mitk::StateEvent* newStateEvent = new mitk::StateEvent(EIDSTSMALERNMINUS1, stateEvent->GetEvent()); this->HandleEvent( newStateEvent ); delete newStateEvent; ok = true; } else { if (pointSet->GetSize( m_TimeStep ) < m_N-1 ) //pointset after addition won't be full { mitk::StateEvent* newStateEvent = new mitk::StateEvent(EIDSTSMALERNMINUS1, stateEvent->GetEvent()); this->HandleEvent( newStateEvent ); delete newStateEvent; ok = true; } else //after the addition of a point, the container will be full { mitk::StateEvent* newStateEvent = new mitk::StateEvent(EIDSTLARGERNMINUS1, stateEvent->GetEvent()); this->HandleEvent(newStateEvent ); delete newStateEvent; ok = true; }//else }//else } break; case AcCHECKEQUALS1: { //the number of points in the list is 1 (or smaler) if (pointSet->GetSize( m_TimeStep ) <= 1) { mitk::StateEvent* newStateEvent = new mitk::StateEvent(EIDYES, stateEvent->GetEvent()); this->HandleEvent( newStateEvent ); delete newStateEvent; ok = true; } else //more than 1 points in list, so stay in the state! { mitk::StateEvent* newStateEvent = new mitk::StateEvent(EIDNO, stateEvent->GetEvent()); this->HandleEvent(newStateEvent ); delete newStateEvent; ok = true; } } break; case AcCHECKNUMBEROFPOINTS: { //the number of points in the list is 1 (or smaler), so will be empty after delete if (pointSet->GetSize( m_TimeStep ) <= 1) { mitk::StateEvent* newStateEvent = new mitk::StateEvent(EIDEMPTY, stateEvent->GetEvent()); this->HandleEvent( newStateEvent ); delete newStateEvent; ok = true; } else if (pointSet->GetSize( m_TimeStep ) <= m_N || m_N <= -1) - //m_N is set to unlimited points allowed or more than 1 points in list, but not full, so stay in the state! - { - mitk::StateEvent* newStateEvent = - new mitk::StateEvent(EIDSMALLERN, stateEvent->GetEvent()); - this->HandleEvent(newStateEvent ); - delete newStateEvent; - ok = true; - } + //m_N is set to unlimited points allowed or more than 1 points in list, but not full, so stay in the state! + { + // if the number of points equals m_N and no point of the point set is selected switch to state EIDEQUALSN + if ((pointSet->GetSize( m_TimeStep ) == m_N)&&(pointSet->GetNumberOfSelected()==0)) + { + mitk::StateEvent* newStateEvent = + new mitk::StateEvent(EIDEQUALSN, stateEvent->GetEvent()); + this->HandleEvent(newStateEvent ); + delete newStateEvent; + ok = true; + } + // if the number of points is small than or equal m_N and point(s) are selected stay in state + else + { + mitk::StateEvent* newStateEvent = + new mitk::StateEvent(EIDSMALLERN, stateEvent->GetEvent()); + this->HandleEvent(newStateEvent ); + delete newStateEvent; + ok = true; + } + } else //pointSet->GetSize( m_TimeStep ) >=m_N. // This can happen if the points were not added // by interaction but by loading a .mps file { mitk::StateEvent* newStateEvent = new mitk::StateEvent(EIDEQUALSN, stateEvent->GetEvent()); this->HandleEvent(newStateEvent ); delete newStateEvent; ok = true; } } break; case AcSELECTPICKEDOBJECT://and deselect others { mitk::PositionEvent const *posEvent = dynamic_cast (stateEvent->GetEvent()); if (posEvent == NULL) return false; mitk::Point3D itkPoint; itkPoint = posEvent->GetWorldPosition(); //search the point in the list int position = pointSet->SearchPoint(itkPoint, 0.0, m_TimeStep); //distance set to 0, cause we already got the exact point from last //State checkpoint but we also need the position in the list to move it if (position>=0)//found a point { //first deselect the other points //undoable deselect of all points in the DataList this->UnselectAll( m_TimeStep, timeInMS); PointOperation* doOp = new mitk::PointOperation(OpSELECTPOINT, timeInMS, itkPoint, position); //Undo if (m_UndoEnabled) //write to UndoMechanism { PointOperation* undoOp = new mitk::PointOperation(OpDESELECTPOINT, timeInMS, itkPoint, position); OperationEvent *operationEvent = new OperationEvent(pointSet, doOp, undoOp); m_UndoController->SetOperationEvent(operationEvent); } //execute the Operation pointSet->ExecuteOperation(doOp); if ( !m_UndoEnabled ) delete doOp; ok = true; } // Update the display mitk::RenderingManager::GetInstance()->RequestUpdateAll(); break; } case AcDESELECTOBJECT: { mitk::PositionEvent const *posEvent = dynamic_cast (stateEvent->GetEvent()); if (posEvent == NULL) return false; mitk::Point3D itkPoint; itkPoint = posEvent->GetWorldPosition(); //search the point in the list int position = pointSet->SearchPoint(itkPoint, 0.0, m_TimeStep); //distance set to 0, cause we already got the exact point from last // State checkpoint but we also need the position in the list to move it if (position>=0)//found a point { //Undo PointOperation* doOp = new mitk::PointOperation(OpDESELECTPOINT, timeInMS, itkPoint, position); if (m_UndoEnabled) //write to UndoMechanism { PointOperation* undoOp = new mitk::PointOperation(OpSELECTPOINT, timeInMS, itkPoint, position); OperationEvent *operationEvent = new OperationEvent(pointSet, doOp, undoOp); m_UndoController->SetOperationEvent(operationEvent); } //execute the Operation pointSet->ExecuteOperation(doOp); if ( !m_UndoEnabled ) delete doOp; ok = true; } // Update the display mitk::RenderingManager::GetInstance()->RequestUpdateAll(); break; } case AcDESELECTALL: { //undo-supported able deselect of all points in the DataList this->UnselectAll( m_TimeStep, timeInMS ); ok = true; // Update the display mitk::RenderingManager::GetInstance()->RequestUpdateAll(); break; } case AcFINISHMOVEMENT: { mitk::PositionEvent const *posEvent = dynamic_cast (stateEvent->GetEvent()); if (posEvent == NULL) return false; //finish the movement: //the final point is m_LastPoint //m_SumVec stores the movement in a vector //the operation would not be necessary, but we need it for the undo Operation. //m_LastPoint is for the Operation //the point for undoOperation calculates from all selected //elements (point) - m_SumVec //search all selected elements and move them with undo-functionality. mitk::PointSet::PointsIterator it, end; it = points->Begin(); end = points->End(); while( it != end ) { int position = it->Index(); if ( pointSet->GetSelectInfo(position, m_TimeStep) )//if selected { PointSet::PointType pt = pointSet->GetPoint(position, m_TimeStep); Point3D itkPoint; itkPoint[0] = pt[0]; itkPoint[1] = pt[1]; itkPoint[2] = pt[2]; PointOperation* doOp = new mitk::PointOperation(OpMOVE, timeInMS, itkPoint, position); if ( m_UndoEnabled )//&& (posEvent->GetType() == mitk::Type_MouseButtonRelease) { //set the undo-operation, so the final position is undo-able //calculate the old Position from the already moved position - m_SumVec mitk::Point3D undoPoint = ( itkPoint - m_SumVec ); PointOperation* undoOp = new mitk::PointOperation(OpMOVE, timeInMS, undoPoint, position); OperationEvent *operationEvent = new OperationEvent(pointSet, doOp, undoOp, "Move point"); m_UndoController->SetOperationEvent(operationEvent); } //execute the Operation pointSet->ExecuteOperation(doOp); if ( !m_UndoEnabled ) delete doOp; } ++it; } //set every variable for movement calculation to zero // commented out: increases usebility in derived classes. /*m_LastPoint.Fill(0); m_SumVec.Fill(0);*/ //increase the GroupEventId, so that the Undo goes to here this->IncCurrGroupEventId(); ok = true; // Update the display mitk::RenderingManager::GetInstance()->RequestUpdateAll(); break; } case AcCLEAR: { this->Clear( m_TimeStep, timeInMS ); // Update the display mitk::RenderingManager::GetInstance()->RequestUpdateAll(); break; } default: return Superclass::ExecuteAction( action, stateEvent ); } // indicate modification of data tree node m_DataNode->Modified(); return ok; } void mitk::PointSetInteractor::Clear( unsigned int timeStep, ScalarType timeInMS ) { mitk::Point3D point; point.Fill(0); mitk::PointSet *pointSet = dynamic_cast(m_DataNode->GetData()); if ( pointSet == NULL ) { return; } mitk::PointSet::DataType *itkPointSet = pointSet->GetPointSet( timeStep ); if ( itkPointSet == NULL ) { return; } //for reading on the points, Id's etc mitk::PointSet::PointsContainer *points = itkPointSet->GetPoints(); mitk::PointSet::PointsIterator it, end; it = points->Begin(); end = points->End(); while( (it != end) && (pointSet->GetSize( timeStep ) > 0) ) { point = pointSet->GetPoint( it->Index(), timeStep ); PointOperation *doOp = new mitk::PointOperation( OpREMOVE, timeInMS, point, it->Index()); //write to UndoMechanism if ( m_UndoEnabled ) { PointOperation *undoOp = new mitk::PointOperation( OpINSERT, timeInMS, point, it->Index()); OperationEvent *operationEvent = new OperationEvent( pointSet, doOp, undoOp ); m_UndoController->SetOperationEvent( operationEvent ); } //execute the Operation ++it; pointSet->ExecuteOperation( doOp ); if ( !m_UndoEnabled ) delete doOp; } //reset the statemachine this->ResetStatemachineToStartState(timeStep); } void mitk::PointSetInteractor::InitAccordingToNumberOfPoints() { if (m_DataNode == NULL) return; mitk::PointSet *pointSet = dynamic_cast(m_DataNode->GetData()); if ( pointSet != NULL ) { //resize the CurrentStateVector this->ExpandStartStateVector(pointSet->GetPointSetSeriesSize()); for (unsigned int timestep = 0; timestep < pointSet->GetPointSetSeriesSize(); timestep++) { //go to new timestep this->UpdateTimeStep(timestep); int numberOfPoints = pointSet->GetSize( timestep ); if (numberOfPoints == 0) continue; //pointset is empty else { //we have a set of loaded points. Deselect all points, because they are all set to selected when added! this->UnselectAll(timestep); if (numberOfPointsHandleEvent( newStateEvent ); delete newStateEvent; delete nullEvent; } else if (numberOfPoints>=m_N) { if (numberOfPoints>m_N) { STATEMACHINE_WARN<<"Point Set contains more points than needed!\n";//display a warning that there are too many points } //get the currentState to state "Set full" const mitk::Event* nullEvent = new mitk::Event(NULL, Type_User, BS_NoButton, BS_NoButton, Key_none); mitk::StateEvent* newStateEvent = new mitk::StateEvent(EIDEQUALSN, nullEvent); this->HandleEvent( newStateEvent ); delete newStateEvent; delete nullEvent; } } } } return; } void mitk::PointSetInteractor::DataChanged() { this->InitAccordingToNumberOfPoints(); return; } diff --git a/Core/Code/Testing/mitkPointSetInteractorTest.cpp b/Core/Code/Testing/mitkPointSetInteractorTest.cpp index eb93e62e29..3192bfbc00 100644 --- a/Core/Code/Testing/mitkPointSetInteractorTest.cpp +++ b/Core/Code/Testing/mitkPointSetInteractorTest.cpp @@ -1,571 +1,591 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date: 2010-05-03 12:55:29 +0200 (Mo, 03 Mai 2010) $ Version: $Revision: 22655 $ 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 "mitkPointSetInteractor.h" #include "mitkPointSet.h" #include "mitkPositionEvent.h" #include "mitkVtkPropRenderer.h" #include "mitkStateEvent.h" #include "mitkInteractionConst.h" #include "mitkGlobalInteraction.h" #include "mitkPointOperation.h" #include "mitkTestingMacros.h" #include const char* POINTSETINTERACTORNAME = "pointsetinteractor"; const char* ONLYMOVEPOINTSETINTERACTORNAME = "onlymovepointsetinteractor"; const char* SEEDPOINTSETINTERACTORNAME = "seedpointsetinteractor"; const char* SINGLEPOINTWITHOUTSHIFTCLICKNAME = "singlepointinteractorwithoutshiftclick"; /** *@brief method to send specified events to EventMapper **/ class mitkPointSetInteractorTestClass { public: void TestPointSetInteractor(const char* name, mitk::DataNode* node, mitk::BaseRenderer* sender, int numberOfPointsAllowed) { mitk::PointSetInteractor::Pointer interactor = mitk::PointSetInteractor::New(name, node, numberOfPointsAllowed); MITK_TEST_CONDITION_REQUIRED(interactor.IsNotNull(),"Testing to initialize PointSetInteractor") std::cout<<"The pattern of the interactor is called: "<GetType()<GetType() == name,"testing pattern name of interactor"); //should not be null MITK_TEST_CONDITION_REQUIRED(node != NULL, "error in test! Node == NULL"); mitk::PointSet::Pointer pointSet = dynamic_cast(node->GetData()); MITK_TEST_CONDITION_REQUIRED(pointSet.IsNotNull(), "error in test! PointSet not set"); //sending an event now shouln't lead to an addition of a point because interactor is not yet connected to globalinteraction mitk::Point3D pos3D; mitk::Point2D pos2D; pos3D[0]= 10.0; pos3D[1]= 20.0; pos3D[2]= 30.0; pos2D[0]= 100; pos2D[0]= 200; this->SendPositionEvent(sender, mitk::Type_MouseButtonPress, mitk::BS_LeftButton, mitk::BS_ShiftButton, mitk::Key_none, pos2D, pos3D); MITK_TEST_CONDITION_REQUIRED(pointSet->GetPointSet()->GetNumberOfPoints()==0,"Checking unconnected interactor."); //activate interaction mitk::GlobalInteraction::GetInstance()->AddInteractor(interactor); //now one point should be added going from state 1 over state 3 and 40 to state 2 (space left) this->SendPositionEvent(sender, mitk::Type_MouseButtonPress, mitk::BS_LeftButton, mitk::BS_ShiftButton, mitk::Key_none, pos2D, pos3D); MITK_TEST_CONDITION_REQUIRED(pointSet->GetPointSet()->GetNumberOfPoints()==1,"Checking connected interactor by adding a point."); MITK_TEST_CONDITION_REQUIRED(pointSet->GetPoint(0) == pos3D,"Testing right addition of point."); MITK_TEST_CONDITION_REQUIRED(pointSet->GetSelectInfo(0) ,"Testing if point is selected."); //delesecting point; going from state 2 over state 10 to state 2 pos3D.Fill(-100.0); pos2D.Fill(200.0); this->SendPositionEvent(sender, mitk::Type_MouseButtonPress, mitk::BS_LeftButton, mitk::BS_NoButton, mitk::Key_none, pos2D, pos3D); MITK_TEST_CONDITION_REQUIRED(pointSet->GetSelectInfo(0) == false,"Testing deselection of a point."); MITK_TEST_CONDITION_REQUIRED(pointSet->GetNumberOfSelected() == 0,"No selected points."); //trying to delete a deselected point so going from state 2 over 30 to 1 mitk::Event* delEvent = new mitk::Event(sender, mitk::Type_KeyPress, mitk::BS_NoButton, mitk::BS_NoButton, mitk::Key_Delete); mitk::GlobalInteraction::GetInstance()->GetEventMapper()->MapEvent(delEvent); MITK_TEST_CONDITION_REQUIRED(pointSet->GetPointSet()->GetNumberOfPoints()==1,"Checking that no unselected point can be deleted."); //not deleting delEvent, because if will be used later on //picking point pos3D[0]= 10.0; pos3D[1]= 20.0; pos3D[2]= 30.0; pos2D[0]= 100; pos2D[0]= 200; this->SendPositionEvent(sender, mitk::Type_MouseButtonPress, mitk::BS_LeftButton, mitk::BS_NoButton, mitk::Key_none, pos2D, pos3D); MITK_TEST_CONDITION_REQUIRED(pointSet->GetSelectInfo(0) ,"Testing if point is picked."); //deleting selected point mitk::GlobalInteraction::GetInstance()->GetEventMapper()->MapEvent(delEvent); MITK_TEST_CONDITION_REQUIRED(pointSet->GetPointSet()->GetNumberOfPoints()==0,"Checking if the selected point could be delected."); //adding two points and checking selection pos3D[0]= 11.0; pos3D[1]= 22.0; pos3D[2]= 33.0; pos2D[0]= 11; pos2D[0]= 22; this->SendPositionEvent(sender, mitk::Type_MouseButtonPress, mitk::BS_LeftButton, mitk::BS_ShiftButton, mitk::Key_none, pos2D, pos3D); MITK_TEST_CONDITION_REQUIRED(pointSet->GetPointSet()->GetNumberOfPoints()==1,"Checking adding point."); MITK_TEST_CONDITION_REQUIRED(pointSet->GetSelectInfo(0) ,"Testing if point1 is selected."); MITK_TEST_CONDITION_REQUIRED(pointSet->GetPoint(0) == pos3D,"Testing addition of point."); pos3D[0]= 111.0; pos3D[1]= 222.0; pos3D[2]= 333.0; pos2D[0]= 111; pos2D[0]= 222; this->SendPositionEvent(sender, mitk::Type_MouseButtonPress, mitk::BS_LeftButton, mitk::BS_ShiftButton, mitk::Key_none, pos2D, pos3D); MITK_TEST_CONDITION_REQUIRED(pointSet->GetPointSet()->GetNumberOfPoints()==2,"Checking adding second point."); MITK_TEST_CONDITION_REQUIRED(pointSet->GetSelectInfo(0) ==false,"Testing if point1 is deselected."); MITK_TEST_CONDITION_REQUIRED(pointSet->GetPoint(1) == pos3D,"Testing addition of point."); MITK_TEST_CONDITION_REQUIRED(pointSet->GetSelectInfo(1) ,"Testing if point2 is selected."); //selecting the first point and deleting it pos3D[0]= 11.0; pos3D[1]= 22.0; pos3D[2]= 33.0; pos2D[0]= 11; pos2D[0]= 22; this->SendPositionEvent(sender, mitk::Type_MouseButtonPress, mitk::BS_LeftButton, mitk::BS_NoButton, mitk::Key_none, pos2D, pos3D); MITK_TEST_CONDITION_REQUIRED(pointSet->GetSelectInfo(0) ,"Testing if point1 is picked."); //sending delete-event mitk::GlobalInteraction::GetInstance()->GetEventMapper()->MapEvent(delEvent); MITK_TEST_CONDITION_REQUIRED(pointSet->GetPointSet()->GetNumberOfPoints()==1,"Checking if the picked point1 could be delected."); MITK_TEST_CONDITION_REQUIRED(pointSet->GetSelectInfo(1) ,"Testing if point2 is now selected."); //sending delete-event again mitk::GlobalInteraction::GetInstance()->GetEventMapper()->MapEvent(delEvent); MITK_TEST_CONDITION_REQUIRED(pointSet->GetPointSet()->GetNumberOfPoints()==0,"Checking if point2 could be delected."); //adding more than three points and see if only three can be added pos3D[0]= 1.0; pos3D[1]= 2.0; pos3D[2]= 3.0; pos2D[0]= 1; pos2D[0]= 2; this->SendPositionEvent(sender, mitk::Type_MouseButtonPress, mitk::BS_LeftButton, mitk::BS_ShiftButton, mitk::Key_none, pos2D, pos3D); pos3D[0]= 11.0; pos3D[1]= 22.0; pos3D[2]= 33.0; pos2D[0]= 11; pos2D[0]= 22; this->SendPositionEvent(sender, mitk::Type_MouseButtonPress, mitk::BS_LeftButton, mitk::BS_ShiftButton, mitk::Key_none, pos2D, pos3D); pos3D[0]= 111.0; pos3D[1]= 222.0; pos3D[2]= 333.0; pos2D[0]= 111; pos2D[0]= 222; this->SendPositionEvent(sender, mitk::Type_MouseButtonPress, mitk::BS_LeftButton, mitk::BS_ShiftButton, mitk::Key_none, pos2D, pos3D); pos3D[0]= 1111.0; pos3D[1]= 2222.0; pos3D[2]= 3333.0; pos2D[0]= 12; pos2D[0]= 21; this->SendPositionEvent(sender, mitk::Type_MouseButtonPress, mitk::BS_LeftButton, mitk::BS_ShiftButton, mitk::Key_none, pos2D, pos3D); if (numberOfPointsAllowed>=0) //not number of points set to unlimited { MITK_TEST_CONDITION_REQUIRED(pointSet->GetPointSet()->GetNumberOfPoints()==(unsigned long)numberOfPointsAllowed,"Checking if only the amount of defined points could be added."); MITK_TEST_CONDITION_REQUIRED(pointSet->GetSelectInfo(2) ,"Testing if the last point added is selected."); MITK_TEST_CONDITION_REQUIRED(pointSet->GetPoint(2) != pos3D,"Testing that the last addition didn't work."); } + //testing whether a point can be added to an already filled point set after deleting an unselected point + if (numberOfPointsAllowed>=0) //not number of points set to unlimited + { + //delesecting point; going from state 2 over state 10 to state 2 + pos3D.Fill(-100.0); + pos2D.Fill(200.0); + this->SendPositionEvent(sender, mitk::Type_MouseButtonPress, mitk::BS_LeftButton, mitk::BS_NoButton, mitk::Key_none, pos2D, pos3D); + MITK_TEST_CONDITION_REQUIRED(pointSet->GetSelectInfo(0) == false,"Testing deselection of a point."); + MITK_TEST_CONDITION_REQUIRED(pointSet->GetNumberOfSelected() == 0,"No selected points."); + //trying to delete a deselected point so going from state 2 over 30 to 1 + mitk::GlobalInteraction::GetInstance()->GetEventMapper()->MapEvent(delEvent); + unsigned long nPts = pointSet->GetPointSet()->GetNumberOfPoints(); + MITK_TEST_CONDITION_REQUIRED(pointSet->GetPointSet()->GetNumberOfPoints()==(unsigned long)numberOfPointsAllowed,"Checking that no unselected point can be deleted."); + //trying to add point to already filled point set + this->SendPositionEvent(sender, mitk::Type_MouseButtonPress, mitk::BS_LeftButton, mitk::BS_ShiftButton, mitk::Key_none, pos2D, pos3D); + MITK_TEST_CONDITION_REQUIRED(pointSet->GetPointSet()->GetNumberOfPoints()==(unsigned long)numberOfPointsAllowed,"Checking that no point can be added after hitting DEL on no selection."); + MITK_TEST_CONDITION_REQUIRED(pointSet->GetSelectInfo(2) ,"Testing if the last point added is selected."); + MITK_TEST_CONDITION_REQUIRED(pointSet->GetPoint(2) != pos3D,"Testing that the last addition didn't work."); + } + //selecting the first point and moving it to 0,0,0 pos3D[0]= 1.0; pos3D[1]= 2.0; pos3D[2]= 3.0; pos2D[0]= 1; pos2D[0]= 2; this->SendPositionEvent(sender, mitk::Type_MouseButtonPress, mitk::BS_LeftButton, mitk::BS_NoButton, mitk::Key_none, pos2D, pos3D); MITK_TEST_CONDITION_REQUIRED(pointSet->GetSelectInfo(0) ,"Testing if point1 is selected."); //sending the same event to hold the point for movement this->SendPositionEvent(sender, mitk::Type_MouseButtonPress, mitk::BS_LeftButton, mitk::BS_NoButton, mitk::Key_none, pos2D, pos3D); //slowly move to 0,0,0 pos3D[0]= 0.5; pos3D[1]= 1.0; pos3D[2]= 1.5; pos2D[0]= 0; pos2D[0]= 1; this->SendPositionEvent(sender, mitk::Type_MouseMove, mitk::BS_NoButton, mitk::BS_LeftButton, mitk::Key_none, pos2D, pos3D); pos3D[0]= 0.0; pos3D[1]= 0.0; pos3D[2]= 0.0; pos2D[0]= 0; pos2D[0]= 0; this->SendPositionEvent(sender, mitk::Type_MouseMove, mitk::BS_NoButton, mitk::BS_LeftButton, mitk::Key_none, pos2D, pos3D); //release event this->SendPositionEvent(sender, mitk::Type_MouseButtonRelease, mitk::BS_LeftButton, mitk::BS_LeftButton, mitk::Key_none, pos2D, pos3D); MITK_TEST_CONDITION_REQUIRED(pointSet->GetPoint(0) == pos3D,"Testing movement of point."); if (numberOfPointsAllowed>=0) //not number of points set to unlimited { //deleting all three points now mitk::GlobalInteraction::GetInstance()->GetEventMapper()->MapEvent(delEvent); MITK_TEST_CONDITION_REQUIRED(pointSet->GetPointSet()->GetNumberOfPoints()==2,"Checking if point3 could be delected."); mitk::GlobalInteraction::GetInstance()->GetEventMapper()->MapEvent(delEvent); MITK_TEST_CONDITION_REQUIRED(pointSet->GetPointSet()->GetNumberOfPoints()==1,"Checking if point2 could be delected."); mitk::GlobalInteraction::GetInstance()->GetEventMapper()->MapEvent(delEvent); MITK_TEST_CONDITION_REQUIRED(pointSet->GetPointSet()->GetNumberOfPoints()==0,"Checking if point1 could be delected."); } else { //deleting all four points now mitk::GlobalInteraction::GetInstance()->GetEventMapper()->MapEvent(delEvent); MITK_TEST_CONDITION_REQUIRED(pointSet->GetPointSet()->GetNumberOfPoints()==3,"Checking if point4 could be delected."); mitk::GlobalInteraction::GetInstance()->GetEventMapper()->MapEvent(delEvent); MITK_TEST_CONDITION_REQUIRED(pointSet->GetPointSet()->GetNumberOfPoints()==2,"Checking if point3 could be delected."); mitk::GlobalInteraction::GetInstance()->GetEventMapper()->MapEvent(delEvent); MITK_TEST_CONDITION_REQUIRED(pointSet->GetPointSet()->GetNumberOfPoints()==1,"Checking if point2 could be delected."); mitk::GlobalInteraction::GetInstance()->GetEventMapper()->MapEvent(delEvent); MITK_TEST_CONDITION_REQUIRED(pointSet->GetPointSet()->GetNumberOfPoints()==0,"Checking if point1 could be delected."); } mitk::GlobalInteraction::GetInstance()->RemoveInteractor(interactor); delete delEvent; } void TestOnlyMovePointSetInteractor(const char* name, mitk::DataNode* node, mitk::BaseRenderer* sender, int numberOfPointsAllowed) { mitk::PointSetInteractor::Pointer interactor = mitk::PointSetInteractor::New(name, node, numberOfPointsAllowed); MITK_TEST_CONDITION_REQUIRED(interactor.IsNotNull(),"Testing to initialize PointSetInteractor") std::cout<<"The pattern of the interactor is called: "<GetType()<GetType() == name,"testing pattern name of interactor"); MITK_TEST_CONDITION_REQUIRED(node != NULL, "error in test! Node == NULL"); mitk::PointSet::Pointer pointSet = dynamic_cast(node->GetData()); MITK_TEST_CONDITION_REQUIRED(pointSet.IsNotNull(), "error in test! PointSet not set"); //sending an event now shouln't lead to an addition of a point because interactor is not connected to globalinteraction mitk::Point3D pos3D; mitk::Point2D pos2D; pos3D[0]= 10.0; pos3D[1]= 20.0; pos3D[2]= 30.0; pos2D[0]= 10; pos2D[0]= 20; this->SendPositionEvent(sender, mitk::Type_MouseButtonPress, mitk::BS_LeftButton, mitk::BS_ShiftButton, mitk::Key_none, pos2D, pos3D); MITK_TEST_CONDITION_REQUIRED(pointSet->GetPointSet()->GetNumberOfPoints()==0,"Checking unconnected interactor."); //activate interaction mitk::GlobalInteraction::GetInstance()->AddInteractor(interactor); //sending event shouldn't lead to an addition of a point, because statemachine cannot handle this! this->SendPositionEvent(sender, mitk::Type_MouseButtonPress, mitk::BS_LeftButton, mitk::BS_ShiftButton, mitk::Key_none, pos2D, pos3D); MITK_TEST_CONDITION_REQUIRED(pointSet->GetPointSet()->GetNumberOfPoints()==0,"Check to add a point."); //manually adding two points to a new pointset and setting it to node mitk::PointSet::Pointer newPointSet = mitk::PointSet::New(); //pos3D[0]= 10.0; pos3D[1]= 20.0; pos3D[2]= 30.0; //pos2D[0]= 10; pos2D[0]= 20; int timestep = 0; int index = 0; mitk::PointOperation* doOp = new mitk::PointOperation( mitk::OpINSERT, timestep, pos3D, index); newPointSet->ExecuteOperation(doOp); //undo is enabled on default, so no need to delete doOp pos3D[0]= 100.0; pos3D[1]= 200.0; pos3D[2]= 300.0; pos2D[0]= 100; pos2D[0]= 200; index = 1; mitk::PointOperation* secondDoOp = new mitk::PointOperation( mitk::OpINSERT, timestep, pos3D, index); newPointSet->ExecuteOperation(secondDoOp); //setting it to node node->SetData(newPointSet); pointSet = dynamic_cast(node->GetData()); MITK_TEST_CONDITION_REQUIRED(pointSet.IsNotNull(), "error in test! new PointSet not set"); //checking if data has two points now MITK_TEST_CONDITION_REQUIRED(pointSet->GetPointSet()->GetNumberOfPoints() == 2,"Testing new data."); //all points should be deselected but standard addition of a point is selected by default so all are selected. To be solved later //MITK_TEST_CONDITION_REQUIRED(pointSet->GetNumberOfSelected() == 2,"No selected points."); //trying to delete a selected point mitk::Event* delEvent = new mitk::Event(sender, mitk::Type_KeyPress, mitk::BS_NoButton, mitk::BS_NoButton, mitk::Key_Delete); mitk::GlobalInteraction::GetInstance()->GetEventMapper()->MapEvent(delEvent); MITK_TEST_CONDITION_REQUIRED(pointSet->GetPointSet()->GetNumberOfPoints()==2,"Checking that no point can be deleted."); delete delEvent; //delesecting point pos3D.Fill(-100.0); pos2D.Fill(200.0); this->SendPositionEvent(sender, mitk::Type_MouseButtonPress, mitk::BS_LeftButton, mitk::BS_NoButton, mitk::Key_none, pos2D, pos3D); MITK_TEST_CONDITION_REQUIRED(pointSet->GetSelectInfo(1) == false,"Testing deselection of a point."); MITK_TEST_CONDITION_REQUIRED(pointSet->GetNumberOfSelected() == 0,"No selected points."); //picking point pos3D[0]= 10.0; pos3D[1]= 20.0; pos3D[2]= 30.0; pos2D[0]= 10; pos2D[0]= 20; this->SendPositionEvent(sender, mitk::Type_MouseButtonPress, mitk::BS_LeftButton, mitk::BS_NoButton, mitk::Key_none, pos2D, pos3D); MITK_TEST_CONDITION_REQUIRED(pointSet->GetSelectInfo(0) ,"Testing if point is picked."); //sending the same event to hold the point for movement this->SendPositionEvent(sender, mitk::Type_MouseButtonPress, mitk::BS_LeftButton, mitk::BS_NoButton, mitk::Key_none, pos2D, pos3D); //slowly move to 0,0,0 pos3D[0]= 0.5; pos3D[1]= 1.0; pos3D[2]= 1.5; pos2D[0]= 0; pos2D[0]= 1; this->SendPositionEvent(sender, mitk::Type_MouseMove, mitk::BS_NoButton, mitk::BS_LeftButton, mitk::Key_none, pos2D, pos3D); pos3D[0]= 0.0; pos3D[1]= 0.0; pos3D[2]= 0.0; pos2D[0]= 0; pos2D[0]= 0; this->SendPositionEvent(sender, mitk::Type_MouseMove, mitk::BS_NoButton, mitk::BS_LeftButton, mitk::Key_none, pos2D, pos3D); //release event this->SendPositionEvent(sender, mitk::Type_MouseButtonRelease, mitk::BS_LeftButton, mitk::BS_LeftButton, mitk::Key_none, pos2D, pos3D); MITK_TEST_CONDITION_REQUIRED(pointSet->GetPoint(0) == pos3D,"Testing movement of point."); mitk::GlobalInteraction::GetInstance()->RemoveInteractor(interactor); } void TestSeedPointSetInteractor(const char* name, mitk::DataNode* node, mitk::BaseRenderer* sender) { mitk::PointSetInteractor::Pointer interactor = mitk::PointSetInteractor::New(name, node); MITK_TEST_CONDITION_REQUIRED(interactor.IsNotNull(),"Testing to initialize PointSetInteractor") std::cout<<"The pattern of the interactor is called: "<GetType()<GetType() == name,"testing pattern name of interactor"); //should not be null MITK_TEST_CONDITION_REQUIRED(node != NULL, "error in test! Node == NULL"); mitk::PointSet::Pointer pointSet = dynamic_cast(node->GetData()); MITK_TEST_CONDITION_REQUIRED(pointSet.IsNotNull(), "error in test! PointSet not set"); //sending an event now shouln't lead to an addition of a point because interactor is not yet connected to globalinteraction mitk::Point3D pos3D; mitk::Point2D pos2D; pos3D[0]= 10.0; pos3D[1]= 20.0; pos3D[2]= 30.0; pos2D[0]= 10; pos2D[0]= 20; this->SendPositionEvent(sender, mitk::Type_MouseButtonPress, mitk::BS_LeftButton, mitk::BS_ShiftButton, mitk::Key_none, pos2D, pos3D); MITK_TEST_CONDITION_REQUIRED(pointSet->GetPointSet()->GetNumberOfPoints()==0,"Checking unconnected interactor."); //activate interaction mitk::GlobalInteraction::GetInstance()->AddInteractor(interactor); //now one point should be added going from state 1 over state 2 to state 10 this->SendPositionEvent(sender, mitk::Type_MouseButtonPress, mitk::BS_LeftButton, mitk::BS_ShiftButton, mitk::Key_none, pos2D, pos3D); MITK_TEST_CONDITION_REQUIRED(pointSet->GetPointSet()->GetNumberOfPoints()==1,"Checking connected interactor by adding a point."); MITK_TEST_CONDITION_REQUIRED(pointSet->GetPoint(0) == pos3D,"Testing right addition of point."); MITK_TEST_CONDITION_REQUIRED(pointSet->GetSelectInfo(0) ,"Testing if point is selected."); //delesecting point; going from state 10 over state 12 to state 10 pos3D.Fill(-100.0); pos2D.Fill(200.0); this->SendPositionEvent(sender, mitk::Type_MouseButtonPress, mitk::BS_LeftButton, mitk::BS_NoButton, mitk::Key_none, pos2D, pos3D); MITK_TEST_CONDITION_REQUIRED(pointSet->GetSelectInfo(0) == false,"Testing deselection of a point."); MITK_TEST_CONDITION_REQUIRED(pointSet->GetNumberOfSelected() == 0,"No selected points."); //trying to delete a deselected point so going from state 10 over 15 to 10 mitk::Event* delEvent = new mitk::Event(sender, mitk::Type_KeyPress, mitk::BS_NoButton, mitk::BS_NoButton, mitk::Key_Delete); mitk::GlobalInteraction::GetInstance()->GetEventMapper()->MapEvent(delEvent); MITK_TEST_CONDITION_REQUIRED(pointSet->GetPointSet()->GetNumberOfPoints()==1,"Checking that no unselected point can be deleted."); //not deleting delEvent, because if will be used later on //picking point pos3D[0]= 10.0; pos3D[1]= 20.0; pos3D[2]= 30.0; pos2D[0]= 10; pos2D[0]= 20; this->SendPositionEvent(sender, mitk::Type_MouseButtonPress, mitk::BS_LeftButton, mitk::BS_NoButton, mitk::Key_none, pos2D, pos3D); MITK_TEST_CONDITION_REQUIRED(pointSet->GetSelectInfo(0) ,"Testing picking point."); //deleting selected point mitk::GlobalInteraction::GetInstance()->GetEventMapper()->MapEvent(delEvent); MITK_TEST_CONDITION_REQUIRED(pointSet->GetPointSet()->GetNumberOfPoints()==0,"Checking if the selected point could be delected."); //adding two points and checking that only the last one remains in point set pos3D[0]= 11.0; pos3D[1]= 22.0; pos3D[2]= 33.0; pos2D[0]= 11; pos2D[0]= 22; this->SendPositionEvent(sender, mitk::Type_MouseButtonPress, mitk::BS_LeftButton, mitk::BS_ShiftButton, mitk::Key_none, pos2D, pos3D); MITK_TEST_CONDITION_REQUIRED(pointSet->GetPointSet()->GetNumberOfPoints()==1,"Checking adding point."); MITK_TEST_CONDITION_REQUIRED(pointSet->GetSelectInfo(0) ,"Testing if point1 is selected."); MITK_TEST_CONDITION_REQUIRED(pointSet->GetPoint(0) == pos3D,"Testing addition of point."); pos3D[0]= 111.0; pos3D[1]= 222.0; pos3D[2]= 333.0; pos2D[0]= 111; pos2D[0]= 222; this->SendPositionEvent(sender, mitk::Type_MouseButtonPress, mitk::BS_LeftButton, mitk::BS_ShiftButton, mitk::Key_none, pos2D, pos3D); MITK_TEST_CONDITION_REQUIRED(pointSet->GetPointSet()->GetNumberOfPoints()==1,"Checking that only one point remains in pointset."); MITK_TEST_CONDITION_REQUIRED(pointSet->GetPoint(0) == pos3D,"Testing addition of point."); MITK_TEST_CONDITION_REQUIRED(pointSet->GetSelectInfo(0) ==true,"Testing if point is selected."); //sending delete-event mitk::GlobalInteraction::GetInstance()->GetEventMapper()->MapEvent(delEvent); MITK_TEST_CONDITION_REQUIRED(pointSet->GetPointSet()->GetNumberOfPoints()==0,"Checking if the point could be delected."); //sending delete-event again mitk::GlobalInteraction::GetInstance()->GetEventMapper()->MapEvent(delEvent); MITK_TEST_CONDITION_REQUIRED(pointSet->GetPointSet()->GetNumberOfPoints()==0,"Checking Sending Delete again."); //adding three points and see if only the third remains pos3D[0]= 1.0; pos3D[1]= 2.0; pos3D[2]= 3.0; pos2D[0]= 1; pos2D[0]= 2; this->SendPositionEvent(sender, mitk::Type_MouseButtonPress, mitk::BS_LeftButton, mitk::BS_ShiftButton, mitk::Key_none, pos2D, pos3D); pos3D[0]= 11.0; pos3D[1]= 22.0; pos3D[2]= 33.0; pos2D[0]= 11; pos2D[0]= 22; this->SendPositionEvent(sender, mitk::Type_MouseButtonPress, mitk::BS_LeftButton, mitk::BS_ShiftButton, mitk::Key_none, pos2D, pos3D); pos3D[0]= 111.0; pos3D[1]= 222.0; pos3D[2]= 333.0; pos2D[0]= 111; pos2D[0]= 222; this->SendPositionEvent(sender, mitk::Type_MouseButtonPress, mitk::BS_LeftButton, mitk::BS_ShiftButton, mitk::Key_none, pos2D, pos3D); MITK_TEST_CONDITION_REQUIRED(pointSet->GetPointSet()->GetNumberOfPoints()==1,"Checking if only one point could be added."); MITK_TEST_CONDITION_REQUIRED(pointSet->GetPoint(0) == pos3D,"Testing if the last point was inserted."); MITK_TEST_CONDITION_REQUIRED(pointSet->GetSelectInfo(0) ,"Testing if the last point added is selected."); //sending the picking event to hold the point for movement this->SendPositionEvent(sender, mitk::Type_MouseButtonPress, mitk::BS_LeftButton, mitk::BS_NoButton, mitk::Key_none, pos2D, pos3D); //slowly move to 0,0,0 pos3D[0]= 0.5; pos3D[1]= 1.0; pos3D[2]= 1.5; pos2D[0]= 0; pos2D[0]= 1; this->SendPositionEvent(sender, mitk::Type_MouseMove, mitk::BS_NoButton, mitk::BS_LeftButton, mitk::Key_none, pos2D, pos3D); pos3D[0]= 0.0; pos3D[1]= 0.0; pos3D[2]= 0.0; pos2D[0]= 0; pos2D[0]= 0; this->SendPositionEvent(sender, mitk::Type_MouseMove, mitk::BS_NoButton, mitk::BS_LeftButton, mitk::Key_none, pos2D, pos3D); //release event this->SendPositionEvent(sender, mitk::Type_MouseButtonRelease, mitk::BS_LeftButton, mitk::BS_LeftButton, mitk::Key_none, pos2D, pos3D); MITK_TEST_CONDITION_REQUIRED(pointSet->GetPoint(0) == pos3D,"Testing movement of point."); //not deleting the points and end of test //removing interactor from GlobalInteraction mitk::GlobalInteraction::GetInstance()->RemoveInteractor(interactor); delete delEvent; } void TestSinglePointSetInteractorWithoutShiftClick(const char* name, mitk::DataNode* node, mitk::BaseRenderer* sender) { mitk::PointSetInteractor::Pointer interactor = mitk::PointSetInteractor::New(name, node); MITK_TEST_CONDITION_REQUIRED(interactor.IsNotNull(),"Testing to initialize PointSetInteractor") std::cout<<"The pattern of the interactor is called: "<GetType()<GetType() == name,"testing pattern name of interactor"); //should not be null MITK_TEST_CONDITION_REQUIRED(node != NULL, "error in test! Node == NULL"); mitk::PointSet::Pointer pointSet = dynamic_cast(node->GetData()); MITK_TEST_CONDITION_REQUIRED(pointSet.IsNotNull(), "error in test! PointSet not set"); //sending an event now shouln't lead to an addition of a point because interactor is not yet connected to globalinteraction mitk::Point3D pos3D; mitk::Point2D pos2D; pos3D[0]= 10.0; pos3D[1]= 20.0; pos3D[2]= 30.0; pos2D[0]= 10; pos2D[0]= 20; this->SendPositionEvent(sender, mitk::Type_MouseButtonPress, mitk::BS_LeftButton, mitk::BS_NoButton, mitk::Key_none, pos2D, pos3D); MITK_TEST_CONDITION_REQUIRED(pointSet->GetPointSet()->GetNumberOfPoints()==0,"Checking unconnected interactor."); //activate interaction mitk::GlobalInteraction::GetInstance()->AddInteractor(interactor); //now one point should be added going from state 1 to state 2 this->SendPositionEvent(sender, mitk::Type_MouseButtonPress, mitk::BS_LeftButton, mitk::BS_NoButton, mitk::Key_none, pos2D, pos3D); MITK_TEST_CONDITION_REQUIRED(pointSet->GetPointSet()->GetNumberOfPoints()==1,"Checking connected interactor by adding a point."); MITK_TEST_CONDITION_REQUIRED(pointSet->GetPoint(0) == pos3D,"Testing right addition of point."); MITK_TEST_CONDITION_REQUIRED(pointSet->GetSelectInfo(0) ,"Testing if point is selected."); //trying to delete point mitk::Event* delEvent = new mitk::Event(sender, mitk::Type_KeyPress, mitk::BS_NoButton, mitk::BS_NoButton, mitk::Key_Delete); mitk::GlobalInteraction::GetInstance()->GetEventMapper()->MapEvent(delEvent); MITK_TEST_CONDITION_REQUIRED(pointSet->GetPointSet()->GetNumberOfPoints()==0,"Checking deleting point."); //adding two points and checking that only the last one remains in point set pos3D[0]= 11.0; pos3D[1]= 22.0; pos3D[2]= 33.0; pos2D[0]= 11; pos2D[0]= 22; this->SendPositionEvent(sender, mitk::Type_MouseButtonPress, mitk::BS_LeftButton, mitk::BS_NoButton, mitk::Key_none, pos2D, pos3D); MITK_TEST_CONDITION_REQUIRED(pointSet->GetPointSet()->GetNumberOfPoints()==1,"Checking adding point."); MITK_TEST_CONDITION_REQUIRED(pointSet->GetSelectInfo(0) ,"Testing if point1 is selected."); MITK_TEST_CONDITION_REQUIRED(pointSet->GetPoint(0) == pos3D,"Testing addition of point."); pos3D[0]= 111.0; pos3D[1]= 222.0; pos3D[2]= 333.0; pos2D[0]= 111; pos2D[0]= 222; this->SendPositionEvent(sender, mitk::Type_MouseButtonPress, mitk::BS_LeftButton, mitk::BS_NoButton, mitk::Key_none, pos2D, pos3D); MITK_TEST_CONDITION_REQUIRED(pointSet->GetPointSet()->GetNumberOfPoints()==1,"Checking that only one point remains in pointset."); MITK_TEST_CONDITION_REQUIRED(pointSet->GetPoint(0) == pos3D,"Testing addition of point."); MITK_TEST_CONDITION_REQUIRED(pointSet->GetSelectInfo(0) ==true,"Testing if point is selected."); //sending delete-event mitk::GlobalInteraction::GetInstance()->GetEventMapper()->MapEvent(delEvent); MITK_TEST_CONDITION_REQUIRED(pointSet->GetPointSet()->GetNumberOfPoints()==0,"Checking if the point could be delected."); //sending delete-event again mitk::GlobalInteraction::GetInstance()->GetEventMapper()->MapEvent(delEvent); MITK_TEST_CONDITION_REQUIRED(pointSet->GetPointSet()->GetNumberOfPoints()==0,"Checking Sending Delete again."); //adding three points and see if only the third remains pos3D[0]= 1.0; pos3D[1]= 2.0; pos3D[2]= 3.0; pos2D[0]= 1; pos2D[0]= 2; this->SendPositionEvent(sender, mitk::Type_MouseButtonPress, mitk::BS_LeftButton, mitk::BS_NoButton, mitk::Key_none, pos2D, pos3D); pos3D[0]= 11.0; pos3D[1]= 22.0; pos3D[2]= 33.0; pos2D[0]= 11; pos2D[0]= 22; this->SendPositionEvent(sender, mitk::Type_MouseButtonPress, mitk::BS_LeftButton, mitk::BS_NoButton, mitk::Key_none, pos2D, pos3D); pos3D[0]= 111.0; pos3D[1]= 222.0; pos3D[2]= 333.0; pos2D[0]= 111; pos2D[0]= 222; this->SendPositionEvent(sender, mitk::Type_MouseButtonPress, mitk::BS_LeftButton, mitk::BS_NoButton, mitk::Key_none, pos2D, pos3D); MITK_TEST_CONDITION_REQUIRED(pointSet->GetPointSet()->GetNumberOfPoints()==1,"Checking if only one point could be added."); MITK_TEST_CONDITION_REQUIRED(pointSet->GetPoint(0) == pos3D,"Testing if the last point was inserted."); MITK_TEST_CONDITION_REQUIRED(pointSet->GetSelectInfo(0) ,"Testing if the last point added is selected."); //removing interactor from GlobalInteraction mitk::GlobalInteraction::GetInstance()->RemoveInteractor(interactor); delete delEvent; } private: void SendPositionEvent(mitk::BaseRenderer* sender, int type, int button, int buttonState, int key, const mitk::Point2D& displPosition, const mitk::Point3D& worldPosition) { mitk::Event *posEvent = new mitk::PositionEvent(sender, type, button, buttonState, key, displPosition, worldPosition); mitk::GlobalInteraction::GetInstance()->GetEventMapper()->MapEvent(posEvent); delete posEvent; } }; //mitkPointSetInteractorTestClass int mitkPointSetInteractorTest(int /*argc*/, char* /*argv*/[]) { MITK_TEST_BEGIN("PointSetInteractor") // Global interaction must(!) be initialized if used mitk::GlobalInteraction::GetInstance()->Initialize("global"); //create the corresponding data mitk::PointSet::Pointer pointSet = mitk::PointSet::New(); mitk::DataNode::Pointer node = mitk::DataNode::New(); //we need a baserenderer (VtkPropRenderer) to be able to let PointSetInteractor::CanHandleEvent() proccess //and for this we need a RenderWindow and a RenderingManager mitk::RenderingManager::Pointer myRenderingManager = mitk::RenderingManager::New(); myRenderingManager->SetGlobalInteraction(mitk::GlobalInteraction::GetInstance()); vtkRenderWindow* vtkRenWin = vtkRenderWindow::New(); mitk::VtkPropRenderer::Pointer sender = mitk::VtkPropRenderer::New("testingBR", vtkRenWin, myRenderingManager); vtkRenWin->Delete(); //hook everything up into a dataNode. (node doesn't here have to be in DataStorage) node->SetData(pointSet); //pointset should be empty MITK_TEST_CONDITION_REQUIRED(pointSet->GetPointSet()->GetNumberOfPoints()==0,"Checking if pointset is empty."); //instance of testclass mitkPointSetInteractorTestClass* test = new mitkPointSetInteractorTestClass(); //test setup regular pointsetinteractor MITK_TEST_OUTPUT(<<"--------Testing "<TestPointSetInteractor(POINTSETINTERACTORNAME, node, sender, 3); pointSet = mitk::PointSet::New(); node = mitk::DataNode::New(); node->SetData(pointSet); //test setup with unlimited numbers of points supported MITK_TEST_OUTPUT(<<"--------Testing "<TestPointSetInteractor(POINTSETINTERACTORNAME, node, sender, -1); pointSet = mitk::PointSet::New(); node = mitk::DataNode::New(); node->SetData(pointSet); //test setup only move pointsetinteractor MITK_TEST_OUTPUT(<<"--------Testing "<TestOnlyMovePointSetInteractor(ONLYMOVEPOINTSETINTERACTORNAME, node, sender, -1); pointSet = mitk::PointSet::New(); node = mitk::DataNode::New(); node->SetData(pointSet); MITK_TEST_OUTPUT(<<"--------Testing "<TestSeedPointSetInteractor(SEEDPOINTSETINTERACTORNAME, node, sender); pointSet = mitk::PointSet::New(); node = mitk::DataNode::New(); node->SetData(pointSet); MITK_TEST_OUTPUT(<<"--------Testing "<TestSinglePointSetInteractorWithoutShiftClick(SINGLEPOINTWITHOUTSHIFTCLICKNAME, node, sender); MITK_TEST_END() }