00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "mitkPlanarFigureInteractor.h"
00020 #include "mitkPointOperation.h"
00021 #include "mitkPositionEvent.h"
00022 #include "mitkPlanarFigure.h"
00023 #include "mitkStatusBar.h"
00024 #include "mitkDataNode.h"
00025 #include "mitkInteractionConst.h"
00026 #include "mitkAction.h"
00027 #include "mitkStateEvent.h"
00028 #include "mitkOperationEvent.h"
00029 #include "mitkUndoController.h"
00030 #include "mitkStateMachineFactory.h"
00031 #include "mitkStateTransitionOperation.h"
00032 #include "mitkBaseRenderer.h"
00033 #include "mitkRenderingManager.h"
00034 #include "mitkNodePredicateDataType.h"
00035 #include "mitkNodePredicateOr.h"
00036
00037
00038
00039
00040 mitk::PlanarFigureInteractor
00041 ::PlanarFigureInteractor(const char * type, DataNode* dataNode, int )
00042 : Interactor( type, dataNode ),
00043 m_Precision( 6.5 ),
00044 m_IsHovering( false )
00045 {
00046 }
00047
00048 mitk::PlanarFigureInteractor::~PlanarFigureInteractor()
00049 {
00050 }
00051
00052 void mitk::PlanarFigureInteractor::SetPrecision( mitk::ScalarType precision )
00053 {
00054 m_Precision = precision;
00055 }
00056
00057
00058 float mitk::PlanarFigureInteractor
00059 ::CanHandleEvent(StateEvent const* stateEvent) const
00060 {
00061 float returnValue = 0.5;
00062
00063
00064
00065
00066 mitk::DisplayPositionEvent const *disPosEvent =
00067 dynamic_cast <const mitk::DisplayPositionEvent *> (stateEvent->GetEvent());
00068
00069
00070 if (disPosEvent == NULL)
00071 {
00072
00073 if (this->GetCurrentState()->GetTransition(stateEvent->GetId())!=NULL)
00074 {
00075 return 0.5;
00076 }
00077 else
00078 {
00079 return 0.0;
00080 }
00081 }
00082
00083 mitk::PlanarFigure *planarFigure = dynamic_cast<mitk::PlanarFigure *>(
00084 m_DataNode->GetData() );
00085
00086 if ( planarFigure != NULL )
00087 {
00088
00089 if ( planarFigure->GetSelectedControlPoint() >= 0 )
00090 {
00091 return 1.0;
00092 }
00093
00094 }
00095 return returnValue;
00096 }
00097
00098
00099 bool mitk::PlanarFigureInteractor
00100 ::ExecuteAction( Action *action, mitk::StateEvent const *stateEvent )
00101 {
00102 bool ok = false;
00103
00104
00105 mitk::PlanarFigure *planarFigure =
00106 dynamic_cast< mitk::PlanarFigure * >( m_DataNode->GetData() );
00107
00108 if ( planarFigure == NULL )
00109 {
00110 return false;
00111 }
00112
00113
00114 const mitk::Event *theEvent = stateEvent->GetEvent();
00115 int timeStep = 0;
00116 mitk::ScalarType timeInMS = 0.0;
00117
00118 if ( theEvent )
00119 {
00120 if (theEvent->GetSender() != NULL)
00121 {
00122 timeStep = theEvent->GetSender()->GetTimeStep( planarFigure );
00123 timeInMS = theEvent->GetSender()->GetTime();
00124 }
00125 }
00126
00127
00128 mitk::Geometry2D *planarFigureGeometry =
00129 dynamic_cast< mitk::Geometry2D * >( planarFigure->GetGeometry( timeStep ) );
00130
00131
00132
00133 mitk::BaseRenderer *renderer = NULL;
00134 const Geometry2D *projectionPlane = NULL;
00135 if ( theEvent )
00136 {
00137 renderer = theEvent->GetSender();
00138 projectionPlane = renderer->GetCurrentWorldGeometry2D();
00139 }
00140
00141
00142
00143
00144 switch (action->GetActionId())
00145 {
00146 case AcDONOTHING:
00147 ok = true;
00148 break;
00149
00150 case AcCHECKOBJECT:
00151 {
00152 if ( planarFigure->IsPlaced() )
00153 {
00154 this->HandleEvent( new mitk::StateEvent( EIDYES, NULL ) );
00155 }
00156 else
00157 {
00158 this->HandleEvent( new mitk::StateEvent( EIDNO, NULL ) );
00159 }
00160 ok = false;
00161 break;
00162 }
00163
00164 case AcADD:
00165 {
00166
00167 planarFigure->InvokeEvent( StartPlacementPlanarFigureEvent() );
00168
00169
00170 mitk::PlaneGeometry *planeGeometry = const_cast< mitk::PlaneGeometry * >(
00171 dynamic_cast< const mitk::PlaneGeometry * >(
00172 renderer->GetSliceNavigationController()->GetCurrentPlaneGeometry() ) );
00173 if ( planeGeometry != NULL )
00174 {
00175 planarFigureGeometry = planeGeometry;
00176 planarFigure->SetGeometry2D( planeGeometry );
00177 }
00178 else
00179 {
00180 ok = false;
00181 break;
00182 }
00183
00184
00185
00186 Point2D point2D;
00187 if ( !this->TransformPositionEventToPoint2D( stateEvent, point2D,
00188 planarFigureGeometry ) )
00189 {
00190 ok = false;
00191 break;
00192 }
00193
00194
00195 planarFigure->PlaceFigure( point2D );
00196
00197
00198 planarFigure->EvaluateFeatures();
00199
00200
00201
00202
00203
00204
00205 m_DataNode->SetBoolProperty( "PlanarFigureInitializedWindow", true, renderer );
00206
00207
00208 renderer->GetRenderingManager()->RequestUpdateAll();
00209
00210 ok = true;
00211 break;
00212 }
00213
00214 case AcMOVEPOINT:
00215 {
00216
00217
00218 Point2D point2D;
00219 if ( !this->TransformPositionEventToPoint2D( stateEvent, point2D,
00220 planarFigureGeometry ) )
00221 {
00222 ok = false;
00223 break;
00224 }
00225
00226
00227 planarFigure->SetCurrentControlPoint( point2D );
00228
00229
00230 planarFigure->EvaluateFeatures();
00231
00232
00233
00234 renderer->GetRenderingManager()->RequestUpdateAll();
00235
00236 ok = true;
00237 break;
00238 }
00239
00240
00241 case AcCHECKNMINUS1:
00242 {
00243 if ( planarFigure->GetNumberOfControlPoints() >=
00244 planarFigure->GetMaximumNumberOfControlPoints() )
00245 {
00246
00247
00248 planarFigure->Modified();
00249 planarFigure->DeselectControlPoint();
00250 planarFigure->InvokeEvent( EndPlacementPlanarFigureEvent() );
00251 planarFigure->InvokeEvent( EndInteractionPlanarFigureEvent() );
00252 m_DataNode->Modified();
00253 this->HandleEvent( new mitk::StateEvent( EIDYES, stateEvent->GetEvent() ) );
00254 }
00255 else
00256 {
00257 this->HandleEvent( new mitk::StateEvent( EIDNO, stateEvent->GetEvent() ) );
00258 }
00259
00260
00261 renderer->GetRenderingManager()->RequestUpdateAll();
00262
00263 ok = true;
00264 break;
00265 }
00266
00267
00268 case AcCHECKEQUALS1:
00269 {
00270
00271
00272
00273
00274 if ( planarFigure->GetNumberOfControlPoints() >=
00275 planarFigure->GetMinimumNumberOfControlPoints() )
00276 {
00277
00278
00279 planarFigure->Modified();
00280 planarFigure->DeselectControlPoint();
00281 if ( planarFigure->GetNumberOfControlPoints()-1 >= planarFigure->GetMinimumNumberOfControlPoints() )
00282 {
00283 planarFigure->RemoveLastControlPoint();
00284 }
00285 planarFigure->InvokeEvent( EndPlacementPlanarFigureEvent() );
00286 planarFigure->InvokeEvent( EndInteractionPlanarFigureEvent() );
00287 m_DataNode->Modified();
00288 this->HandleEvent( new mitk::StateEvent( EIDYES, NULL ) );
00289 }
00290 else
00291 {
00292 this->HandleEvent( new mitk::StateEvent( EIDNO, NULL ) );
00293 }
00294
00295
00296 renderer->GetRenderingManager()->RequestUpdateAll();
00297
00298 ok = true;
00299 break;
00300 }
00301
00302
00303 case AcCHECKPOINT:
00304 {
00305
00306
00307
00308
00309 const mitk::PositionEvent *positionEvent =
00310 dynamic_cast< const mitk::PositionEvent * > ( stateEvent->GetEvent() );
00311 if ( positionEvent == NULL )
00312 {
00313 ok = false;
00314 break;
00315 }
00316
00317
00318 mitk::Point2D currentDisplayPosition = positionEvent->GetDisplayPosition();
00319
00320
00321 int previousIndex = planarFigure->GetNumberOfControlPoints() - 2;
00322 if ( previousIndex >= 0 )
00323 {
00324
00325
00326 mitk::Point3D previousPoint3D;
00327 planarFigureGeometry->Map( planarFigure->GetControlPoint( previousIndex ), previousPoint3D );
00328 if ( renderer->GetDisplayGeometry()->Distance( previousPoint3D ) < 0.1 )
00329 {
00330 mitk::Point2D previousDisplayPosition;
00331 renderer->GetCurrentWorldGeometry2D()->Map( previousPoint3D, previousDisplayPosition );
00332 renderer->GetDisplayGeometry()->WorldToDisplay( previousDisplayPosition, previousDisplayPosition );
00333
00334 double a = currentDisplayPosition[0] - previousDisplayPosition[0];
00335 double b = currentDisplayPosition[1] - previousDisplayPosition[1];
00336
00337
00338 if ( a * a + b * b < 25.0 )
00339 {
00340 this->HandleEvent( new mitk::StateEvent( EIDNO, stateEvent->GetEvent() ) );
00341
00342 ok = true;
00343 break;
00344 }
00345 }
00346 }
00347
00348 this->HandleEvent( new mitk::StateEvent( EIDYES, stateEvent->GetEvent() ) );
00349 ok = true;
00350 break;
00351 }
00352
00353
00354 case AcADDPOINT:
00355 {
00356
00357
00358 Point2D point2D;
00359 if ( !this->TransformPositionEventToPoint2D( stateEvent, point2D,
00360 planarFigureGeometry ) )
00361 {
00362 ok = false;
00363 break;
00364 }
00365
00366
00367 planarFigure->AddControlPoint( point2D );
00368
00369
00370 planarFigure->EvaluateFeatures();
00371
00372
00373
00374 renderer->GetRenderingManager()->RequestUpdateAll();
00375
00376 ok = true;
00377 break;
00378 }
00379
00380
00381 case AcDESELECTPOINT:
00382 {
00383 planarFigure->DeselectControlPoint();
00384
00385
00386 planarFigure->Modified();
00387 planarFigure->InvokeEvent( EndInteractionPlanarFigureEvent() );
00388
00389 m_DataNode->Modified();
00390
00391
00392 }
00393
00394 case AcCHECKSELECTED:
00395 {
00396 bool isHovering = mitk::PlanarFigureInteractor::IsPositionOverFigure(
00397 stateEvent, planarFigure,
00398 planarFigureGeometry,
00399 renderer->GetCurrentWorldGeometry2D(),
00400 renderer->GetDisplayGeometry() );
00401
00402 int pointIndex = mitk::PlanarFigureInteractor::IsPositionInsideMarker(
00403 stateEvent, planarFigure,
00404 planarFigureGeometry,
00405 renderer->GetCurrentWorldGeometry2D(),
00406 renderer->GetDisplayGeometry() );
00407
00408 if ( pointIndex >= 0 )
00409 {
00410
00411 planarFigure->SelectControlPoint( pointIndex );
00412
00413
00414 isHovering = true;
00415 }
00416 else
00417 {
00418
00419 planarFigure->DeselectControlPoint();
00420 }
00421
00422 if ( isHovering )
00423 {
00424 if ( !m_IsHovering )
00425 {
00426
00427 m_IsHovering = true;
00428 planarFigure->InvokeEvent( StartHoverPlanarFigureEvent() );
00429
00430
00431 m_DataNode->SetBoolProperty( "planarfigure.ishovering", true );
00432 }
00433
00434 this->HandleEvent( new mitk::StateEvent( EIDYES, NULL ) );
00435
00436
00437 ok = true;
00438 }
00439 else
00440 {
00441 if ( m_IsHovering )
00442 {
00443
00444 m_IsHovering = false;
00445 planarFigure->InvokeEvent( EndHoverPlanarFigureEvent() );
00446
00447
00448 m_DataNode->SetBoolProperty( "planarfigure.ishovering", false );
00449 }
00450
00451 this->HandleEvent( new mitk::StateEvent( EIDNO, NULL ) );
00452
00453
00454
00455 ok = false;
00456 }
00457
00458
00459 renderer->GetRenderingManager()->RequestUpdateAll();
00460 break;
00461 }
00462
00463 case AcSELECTPICKEDOBJECT:
00464 {
00465
00466 planarFigure->InvokeEvent( SelectPlanarFigureEvent() );
00467
00468
00469 bool isEditable = true;
00470 m_DataNode->GetBoolProperty( "planarfigure.iseditable", isEditable );
00471
00472 int pointIndex = -1;
00473
00474 if ( isEditable )
00475 {
00476
00477 pointIndex = mitk::PlanarFigureInteractor::IsPositionInsideMarker(
00478 stateEvent, planarFigure,
00479 planarFigureGeometry,
00480 renderer->GetCurrentWorldGeometry2D(),
00481 renderer->GetDisplayGeometry() );
00482 }
00483
00484
00485 if ( pointIndex >= 0 )
00486 {
00487 this->HandleEvent( new mitk::StateEvent( EIDYES, NULL ) );
00488
00489
00490 ok = true;
00491 }
00492 else
00493 {
00494 this->HandleEvent( new mitk::StateEvent( EIDNO, NULL ) );
00495
00496
00497
00498 ok = false;
00499 }
00500
00501 ok = true;
00502 break;
00503 }
00504
00505
00506 case AcSELECTPOINT:
00507 {
00508
00509 planarFigure->InvokeEvent( StartInteractionPlanarFigureEvent() );
00510
00511
00512 if ( planarFigure->ResetOnPointSelect() )
00513 {
00514 this->HandleEvent( new mitk::StateEvent( EIDYES, stateEvent->GetEvent() ) );
00515 }
00516 else
00517 {
00518 this->HandleEvent( new mitk::StateEvent( EIDNO, stateEvent->GetEvent() ) );
00519 }
00520
00521 ok = true;
00522 break;
00523 }
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544 default:
00545 return Superclass::ExecuteAction( action, stateEvent );
00546 }
00547
00548 return ok;
00549 }
00550
00551 bool mitk::PlanarFigureInteractor::TransformPositionEventToPoint2D(
00552 const StateEvent *stateEvent, Point2D &point2D,
00553 const Geometry2D *planarFigureGeometry )
00554 {
00555
00556
00557 const mitk::PositionEvent *positionEvent =
00558 dynamic_cast< const mitk::PositionEvent * > ( stateEvent->GetEvent() );
00559 if ( positionEvent == NULL )
00560 {
00561 return false;
00562 }
00563
00564 mitk::Point3D worldPoint3D = positionEvent->GetWorldPosition();
00565
00566
00567 if ( planarFigureGeometry->Distance( worldPoint3D ) > 0.1 )
00568 {
00569 return false;
00570 }
00571
00572
00573 planarFigureGeometry->Map( worldPoint3D, point2D );
00574 return true;
00575 }
00576
00577
00578 bool mitk::PlanarFigureInteractor::TransformObjectToDisplay(
00579 const mitk::Point2D &point2D,
00580 mitk::Point2D &displayPoint,
00581 const mitk::Geometry2D *objectGeometry,
00582 const mitk::Geometry2D *rendererGeometry,
00583 const mitk::DisplayGeometry *displayGeometry ) const
00584 {
00585 mitk::Point3D point3D;
00586
00587
00588 objectGeometry->Map( point2D, point3D );
00589
00590
00591 if ( displayGeometry->Distance( point3D ) < 0.1 )
00592 {
00593
00594 rendererGeometry->Map( point3D, displayPoint );
00595 displayGeometry->WorldToDisplay( displayPoint, displayPoint );
00596 return true;
00597 }
00598
00599 return false;
00600 }
00601
00602
00603 bool mitk::PlanarFigureInteractor::IsPointNearLine(
00604 const mitk::Point2D& point,
00605 const mitk::Point2D& startPoint, const mitk::Point2D& endPoint ) const
00606 {
00607 mitk::Vector2D n1 = endPoint - startPoint;
00608 n1.Normalize();
00609
00610
00611 double l1 = n1 * (point - startPoint);
00612 double l2 = -n1 * (point - endPoint);
00613
00614
00615 mitk::Point2D crossPoint = startPoint + n1 * l1;
00616
00617
00618
00619
00620 if ( (crossPoint.SquaredEuclideanDistanceTo( point ) < 20.0 )
00621 && ( l1 > -5.0 ) && ( l2 > -5.0 ) )
00622 {
00623 return true;
00624 }
00625
00626 return false;
00627 }
00628
00629
00630 bool mitk::PlanarFigureInteractor::IsPositionOverFigure(
00631 const StateEvent *stateEvent, PlanarFigure *planarFigure,
00632 const Geometry2D *planarFigureGeometry,
00633 const Geometry2D *rendererGeometry,
00634 const DisplayGeometry *displayGeometry ) const
00635 {
00636
00637 const mitk::PositionEvent *positionEvent =
00638 dynamic_cast< const mitk::PositionEvent * > ( stateEvent->GetEvent() );
00639 if ( positionEvent == NULL )
00640 {
00641 return -1;
00642 }
00643
00644 mitk::Point2D displayPosition = positionEvent->GetDisplayPosition();
00645
00646
00647
00648
00649 typedef mitk::PlanarFigure::VertexContainerType VertexContainerType;
00650
00651 mitk::Point2D worldPoint2D, displayControlPoint;
00652 mitk::Point3D worldPoint3D;
00653
00654 for ( unsigned short loop = 0; loop < planarFigure->GetPolyLinesSize(); ++loop )
00655 {
00656 const VertexContainerType* polyLine = planarFigure->GetPolyLine( loop );
00657
00658 Point2D polyLinePoint;
00659 Point2D firstPolyLinePoint;
00660 Point2D previousPolyLinePoint;
00661
00662 bool firstPoint = true;
00663 for ( VertexContainerType::ConstIterator it = polyLine->Begin(); it != polyLine->End(); ++it )
00664 {
00665
00666 if ( !this->TransformObjectToDisplay( it->Value(), polyLinePoint,
00667 planarFigureGeometry, rendererGeometry, displayGeometry ) )
00668 {
00669 break;
00670 }
00671
00672 if ( firstPoint )
00673 {
00674 firstPolyLinePoint = polyLinePoint;
00675 firstPoint = false;
00676 }
00677 else if ( this->IsPointNearLine( displayPosition, previousPolyLinePoint, polyLinePoint ) )
00678 {
00679
00680 return true;
00681 }
00682 previousPolyLinePoint = polyLinePoint;
00683 }
00684
00685
00686 if ( planarFigure->IsClosed()
00687 && this->IsPointNearLine( displayPosition, polyLinePoint, firstPolyLinePoint ) )
00688 {
00689 return true;
00690 }
00691 }
00692
00693 return false;
00694 }
00695
00696
00697 int mitk::PlanarFigureInteractor::IsPositionInsideMarker(
00698 const StateEvent *stateEvent, const PlanarFigure *planarFigure,
00699 const Geometry2D *planarFigureGeometry,
00700 const Geometry2D *rendererGeometry,
00701 const DisplayGeometry *displayGeometry ) const
00702 {
00703
00704 const mitk::PositionEvent *positionEvent =
00705 dynamic_cast< const mitk::PositionEvent * > ( stateEvent->GetEvent() );
00706 if ( positionEvent == NULL )
00707 {
00708 return -1;
00709 }
00710
00711 mitk::Point2D displayPosition = positionEvent->GetDisplayPosition();
00712
00713
00714
00715
00716 typedef mitk::PlanarFigure::VertexContainerType VertexContainerType;
00717 const VertexContainerType *controlPoints = planarFigure->GetControlPoints();
00718
00719 mitk::Point2D worldPoint2D, displayControlPoint;
00720 mitk::Point3D worldPoint3D;
00721
00722 VertexContainerType::ConstIterator it;
00723 for ( it = controlPoints->Begin(); it != controlPoints->End(); ++it )
00724 {
00725 Point2D displayControlPoint;
00726 if ( this->TransformObjectToDisplay( it->Value(), displayControlPoint,
00727 planarFigureGeometry, rendererGeometry, displayGeometry ) )
00728 {
00729
00730 if ( (abs(displayPosition[0] - displayControlPoint[0]) < 4 )
00731 && (abs(displayPosition[1] - displayControlPoint[1]) < 4 ) )
00732 {
00733 return it->Index();
00734 }
00735 }
00736 }
00737
00738 return -1;
00739 }
00740
00741
00742 void mitk::PlanarFigureInteractor::LogPrintPlanarFigureQuantities(
00743 const PlanarFigure *planarFigure )
00744 {
00745 MITK_INFO << "PlanarFigure: " << planarFigure->GetNameOfClass();
00746 for ( unsigned int i = 0; i < planarFigure->GetNumberOfFeatures(); ++i )
00747 {
00748 MITK_INFO << "* " << planarFigure->GetFeatureName( i ) << ": "
00749 << planarFigure->GetQuantity( i ) << " " << planarFigure->GetFeatureUnit( i );
00750 }
00751 }
00752