]> Creatis software - cpPlugins.git/blob - appli/ImageMPR/ImageMPR.cxx
undo redo for images in viewer
[cpPlugins.git] / appli / ImageMPR / ImageMPR.cxx
1 #include "ImageMPR.h"
2 #include "MementoState.h"
3 #include "ui_ImageMPR.h"
4
5 #include <vtkProperty.h>
6 #include <vtkRenderWindow.h>
7 #include <vtkMetaImageReader.h>
8
9 #include <QFileDialog>
10 #include <QMessageBox>
11
12 #ifdef _WIN32
13 #  define PLUGIN_PREFIX ""
14 #  define PLUGIN_EXT "dll"
15 #  define PLUGIN_REGEX "Plugins file (*.dll);;All files (*)"
16 #else
17 #  define PLUGIN_PREFIX "lib"
18 #  define PLUGIN_EXT "so"
19 #  define PLUGIN_REGEX "Plugins file (*.so);;All files (*)"
20 #endif // _WIN32
21
22 // -------------------------------------------------------------------------
23 ImageMPR::ImageMPR( QWidget* parent )
24   : QMainWindow( parent ),
25     m_UI( new Ui::ImageMPR ),
26     m_ImageReaderClass( "" ),
27     m_ImageWriterClass( "" ),
28     m_MeshReaderClass( "" ),
29     m_MeshWriterClass( "" ),
30     m_MeshCutterClass( "" ),
31     m_Image( NULL ),
32         m_state(1)
33 {
34   this->m_UI->setupUi( this );
35
36   // Create and associate renderers
37   this->m_MPRObjects = vtkSmartPointer< TMPRObjects >::New( );
38   this->m_MPRObjects->SetRenderWindows(
39     this->m_UI->m_XPlaneVTK->GetRenderWindow( ),
40     this->m_UI->m_YPlaneVTK->GetRenderWindow( ),
41     this->m_UI->m_ZPlaneVTK->GetRenderWindow( ),
42     this->m_UI->m_3DVTK->GetRenderWindow( )
43     );
44
45   // signals <-> slots
46   QObject::connect(
47     this->m_UI->actionOpenPlugins, SIGNAL( triggered( ) ),
48     this, SLOT( _triggered_actionOpenPlugins( ) )
49     );
50   QObject::connect(
51     this->m_UI->actionOpenInputImage, SIGNAL( triggered( ) ),
52     this, SLOT( _triggered_actionOpenInputImage( ) )
53     );
54   QObject::connect(
55     this->m_UI->actionOpenSegmentation, SIGNAL( triggered( ) ),
56     this, SLOT( _triggered_actionOpenSegmentation( ) )
57     );
58   QObject::connect(
59     this->m_UI->actionOpenInputPolyData, SIGNAL( triggered( ) ),
60     this, SLOT( _triggered_actionOpenInputPolyData( ) )
61     );
62   QObject::connect(
63         this->m_UI->actionUndo, SIGNAL(triggered()),
64         this, SLOT(_triggered_actionUndo())
65         );
66   QObject::connect(
67         this->m_UI->actionRedo, SIGNAL(triggered()),
68         this, SLOT(_triggered_actionRedo())
69         );
70
71   // Start: load all disponible plugins
72   this->_LoadPlugins(
73     std::string( PLUGIN_PREFIX ) +
74     std::string( "cpPluginsIO." ) +
75     std::string( PLUGIN_EXT )
76     );
77   this->_LoadPlugins(
78     std::string( PLUGIN_PREFIX ) +
79     std::string( "cpPluginsBasicFilters." ) +
80     std::string( PLUGIN_EXT )
81     );
82 }
83
84 // -------------------------------------------------------------------------
85 ImageMPR::
86 ~ImageMPR( )
87 {
88   // Close all connections
89   this->m_Plugins.UnloadAll( );
90
91   // Delete objects
92   delete this->m_UI;
93 }
94
95 // -------------------------------------------------------------------------
96 bool ImageMPR::
97 _LoadPlugins( const std::string& filename )
98 {
99   QApplication::setOverrideCursor( Qt::WaitCursor );
100   this->setEnabled( false );
101
102   this->m_ImageReaderClass = "";
103   this->m_ImageWriterClass = "";
104   this->m_MeshReaderClass = "";
105   this->m_MeshWriterClass = "";
106   this->m_MeshCutterClass = "";
107   this->m_UI->MenuImageToImage->clear( );
108   this->m_UI->MenuImageToMesh->clear( );
109
110   if( !( this->m_Plugins.Load( filename ) ) )
111     return( false );
112
113   typedef TPluginsInterface::TClasses _TClasses;
114   _TClasses::const_iterator cIt = this->m_Plugins.GetClasses( ).begin( );
115   for( ; cIt != this->m_Plugins.GetClasses( ).end( ); ++cIt )
116   {
117     TPluginFilter::Pointer o =
118       this->m_Plugins.CreateProcessObject( cIt->first );
119     std::string name = o->GetClassName( );
120     std::string category = o->GetClassCategory( );
121     if( category == "ImageReader" )
122       this->m_ImageReaderClass = name;
123     else if( category == "ImageWriter" )
124       this->m_ImageWriterClass = name;
125     else if( category == "MeshReader" )
126       this->m_MeshReaderClass = name;
127     else if( category == "MeshWriter" )
128       this->m_MeshWriterClass = name;
129     else if( category == "MeshToMeshFilter" )
130     {
131       if( name.find_last_of( "Cutter" ) != std::string::npos )
132         this->m_MeshCutterClass = name;
133     }
134     else if( category == "ImageToImageFilter" )
135     {
136       QAction* action =
137         this->m_UI->MenuImageToImage->addAction( QString( name.c_str( ) ) );
138       QObject::connect(
139         action, SIGNAL( triggered( ) ),
140         this, SLOT( _triggered_actionImageToImage( ) )
141         );
142     }
143     else if( category == "ImageToMeshFilter" )
144     {
145       QAction* action =
146         this->m_UI->MenuImageToMesh->addAction( QString( name.c_str( ) ) );
147       QObject::connect(
148         action, SIGNAL( triggered( ) ),
149         this, SLOT( _triggered_actionImageToMesh( ) )
150         );
151
152     } // fi
153
154   } // rof
155   QApplication::restoreOverrideCursor( );
156   this->setEnabled( true );
157
158   return( true );
159 }
160
161 // -------------------------------------------------------------------------
162 std::string ImageMPR::
163 _LoadImage( TPluginImage::Pointer& image )
164 {
165   std::string ret = "";
166   image = NULL;
167
168   // Get a reader from loaded plugins
169   TPluginFilter::Pointer reader =
170     this->m_Plugins.CreateProcessObject( this->m_ImageReaderClass );
171   if( reader.IsNotNull( ) )
172   {
173     if( reader->ExecConfigurationDialog( this ) )
174     {
175       // Block application
176       QApplication::setOverrideCursor( Qt::WaitCursor );
177       this->setEnabled( false );
178
179       // Execute and get error message, if any
180       ret = reader->Update( );
181
182       // Assign fresh image, if any
183       if( ret == "" )
184       {
185         image = reader->GetOutput< TPluginImage >( 0 );
186         reader->DisconnectOutputs( );
187
188       } // fi
189
190       // Unblock application
191       QApplication::restoreOverrideCursor( );
192       this->setEnabled( true );
193
194     } // fi
195   }
196   else
197     ret = "No suitable reader object found in loaded plugins.";
198   
199   return( ret );
200 }
201
202 // -------------------------------------------------------------------------
203 std::string ImageMPR::
204 _ConfigureMeshActors( )
205 {
206   if( this->m_Mesh.IsNull( ) )
207     return( "Valid mesh not found." );
208
209   this->m_Mesh->CreateVTKActor( );
210   vtkActor* vtk_actor = this->m_Mesh->GetVTKActor( );
211   if( vtk_actor != NULL )
212   {
213     this->m_MPRObjects->Get3DRenderer( )->AddActor( vtk_actor );
214     this->m_MPRObjects->Render( 4 );
215
216   } // fi
217
218   TMPRObjects::TMPRActors* mprActors = this->m_MPRObjects->GetMPRActors( );
219
220   std::string err = "";
221   for( unsigned int i = 0; i < 3; ++i )
222   {
223     this->m_Cutters[ i ] = this->m_Plugins.CreateProcessObject( this->m_MeshCutterClass );
224     this->m_Planes[ i ] = TPluginImplicitFunction::New( );
225     this->m_Planes[ i ]->SetFunction( mprActors->GetSliceActors( i )->GetPlaneFunction( ) );
226     this->m_Cutters[ i ]->SetInput( 0, this->m_Mesh );
227     this->m_Cutters[ i ]->SetInput( 1, this->m_Planes[ i ] );
228     std::string lerr = this->m_Cutters[ i ]->Update( );
229     if( lerr == "" )
230     {
231       this->m_Cutters[ i ]->GetOutput< TPluginMesh >( 0 )->CreateVTKActor( );
232       vtkActor* actor = this->m_Cutters[ i ]->GetOutput< TPluginMesh >( 0 )->GetVTKActor( );
233       mprActors->GetSliceActors( i )->AddActor( this->m_Cutters[ i ]->GetVTK< vtkAlgorithm >( ), actor );
234       if( i == 0 )
235         this->m_MPRObjects->GetXRenderer( )->AddActor( actor );
236       else if( i == 1 )
237         this->m_MPRObjects->GetYRenderer( )->AddActor( actor );
238       else if( i == 2 )
239         this->m_MPRObjects->GetZRenderer( )->AddActor( actor );
240
241     } // fi
242     err += lerr;
243
244   } // rof
245   this->m_MPRObjects->RenderAll( );
246   return( err );
247 }
248
249 // -------------------------------------------------------------------------
250 void ImageMPR::
251 _triggered_actionOpenPlugins( )
252 {
253   // Show dialog and check if it was accepted
254   QFileDialog dialog( this );
255   dialog.setFileMode( QFileDialog::ExistingFile );
256   dialog.setDirectory( "." );
257   dialog.setNameFilter( tr( PLUGIN_REGEX ) );
258   dialog.setDefaultSuffix( tr( PLUGIN_EXT ) );
259   if( !( dialog.exec( ) ) )
260     return;
261   
262   std::string fname = dialog.selectedFiles( ).at( 0 ).toStdString( );
263   if( !( _LoadPlugins( fname ) ) )
264     QMessageBox::critical(
265       this,
266       tr( "Ignoring plugin" ),
267       tr( fname.c_str( ) )
268       );
269 }
270
271 // -------------------------------------------------------------------------
272 void ImageMPR::
273 _triggered_actionOpenInputImage( )
274 {
275   // Read image
276   std::string err = this->_LoadImage( this->m_Image );
277   if( err == "" )
278   {
279     vtkImageData* vtk_id = this->m_Image->GetVTK< vtkImageData >( );
280     if( vtk_id != NULL )
281     {
282       this->m_MPRObjects->SetImage( vtk_id );
283       this->m_MPRObjects->ActivateInteractors( );
284       this->m_MPRObjects->ResetCameras( );
285       this->m_MPRObjects->RenderAll( );
286
287           MementoState(m_state, this->m_Image);   
288     }
289     else
290       QMessageBox::critical(
291         this,
292         tr( "Error message" ),
293         tr( "Read image does not have a valid VTK converter." )
294         );
295   }
296   else
297     QMessageBox::critical(
298       this,
299       tr( "Error reading single image" ),
300       tr( err.c_str( ) )
301       );
302 }
303
304 // -------------------------------------------------------------------------
305 void ImageMPR::
306 _triggered_actionOpenSegmentation( )
307 {
308   if( this->m_Image.IsNull( ) )
309   {
310     QMessageBox::critical(
311       this,
312       tr( "Error message" ),
313       tr( "Before reading a segmentation, first load a raw image." )
314       );
315     return;
316
317   } // fi
318
319   // Read image
320   std::string err = this->_LoadImage( this->m_Segmentation );
321   if( err == "" )
322   {
323     vtkImageData* vtk_id = this->m_Segmentation->GetVTK< vtkImageData >( );
324     if( vtk_id != NULL )
325     {
326       this->m_MPRObjects->AddAuxiliaryImage( vtk_id );
327       this->m_MPRObjects->RenderAll( );
328     }
329     else
330       QMessageBox::critical(
331         this,
332         tr( "Error message" ),
333         tr( "Read image does not have a valid VTK converter." )
334         );
335   }
336   else
337     QMessageBox::critical(
338       this,
339       tr( "Error reading single image" ),
340       tr( err.c_str( ) )
341       );
342 }
343
344 // -------------------------------------------------------------------------
345 void ImageMPR::
346 _triggered_actionOpenInputPolyData( )
347 {
348   this->m_Mesh = NULL;
349
350   // Get a reader from plugins
351   TPluginFilter::Pointer reader =
352     this->m_Plugins.CreateProcessObject( this->m_MeshReaderClass );
353
354   if( reader.IsNotNull( ) )
355   {
356     // Configure reader
357     if( reader->ExecConfigurationDialog( this ) )
358     {
359       // Execute and get error message, if any
360       QApplication::setOverrideCursor( Qt::WaitCursor );
361       this->setEnabled( false );
362       std::string err = reader->Update( );
363       QApplication::restoreOverrideCursor( );
364       this->setEnabled( true );
365
366       // Assign fresh mesh, if any
367       if( err == "" )
368       {
369         this->m_Mesh = reader->GetOutput< TPluginMesh >( 0 );
370         reader->DisconnectOutputs( );
371         err = this->_ConfigureMeshActors( );
372         if( err != "" )
373           QMessageBox::critical(
374             this,
375             tr( "Error message" ),
376             tr( err.c_str( ) )
377             );
378       }
379       else
380         QMessageBox::critical(
381           this,
382           tr( "Error reading mesh" ),
383           tr( err.c_str( ) )
384           );
385
386     } // fi
387   }
388   else
389     QMessageBox::critical(
390       this,
391       tr( "Error reading single mesh" ),
392       tr( "No suitable mesh reader found in loaded plugins." )
393       );
394 }
395
396 // -------------------------------------------------------------------------
397 void ImageMPR::
398 _triggered_actionImageToImage( )
399 {
400   if( this->m_Image.IsNull( ) )
401     return;
402
403   // Get filter name
404   QAction* action = dynamic_cast< QAction* >( this->sender( ) );
405   if( action == NULL )
406     return;
407   std::string name = action->text( ).toStdString( );
408
409   // Configure filter
410   TPluginFilter::Pointer filter =
411     this->m_Plugins.CreateProcessObject( name );
412   bool dlg_ok = filter->ExecConfigurationDialog( NULL );
413   if( !dlg_ok )
414     return;
415
416   // Execute filter
417   QApplication::setOverrideCursor( Qt::WaitCursor );
418   this->setEnabled( false );
419   filter->SetInput( 0, this->m_Image );
420   std::string err = filter->Update( );
421   QApplication::restoreOverrideCursor( );
422   this->setEnabled( true );
423
424   // Update image
425   if( err == "" )
426   {
427     TPluginImage* result = filter->GetOutput< TPluginImage >( 0 );
428     result->DisconnectPipeline( );
429     this->m_Image = result;
430     if( this->m_Image.IsNotNull( ) )
431       this->m_MPRObjects->SetImage(
432         this->m_Image->GetVTK< vtkImageData >( )
433
434                 );
435         m_state++;
436         MementoState(m_state, this->m_Image);
437   }
438   else
439     QMessageBox::critical(
440       this,
441       tr( "Error executing filter" ),
442       tr( err.c_str( ) )
443       );
444 }
445
446 // -------------------------------------------------------------------------
447 void ImageMPR::
448 _triggered_actionImageToMesh( )
449 {
450   if( this->m_Image.IsNull( ) )
451     return;
452
453   // Get filter name
454   QAction* action = dynamic_cast< QAction* >( this->sender( ) );
455   if( action == NULL )
456     return;
457   std::string name = action->text( ).toStdString( );
458
459   // Configure filter
460   TPluginFilter::Pointer filter =
461     this->m_Plugins.CreateProcessObject( name );
462   bool dlg_ok = filter->ExecConfigurationDialog( NULL );
463   if( !dlg_ok )
464     return;
465
466   // Execute filter
467   QApplication::setOverrideCursor( Qt::WaitCursor );
468   this->setEnabled( false );
469   filter->SetInput( 0, this->m_Image );
470   std::string err = filter->Update( );
471   QApplication::restoreOverrideCursor( );
472   this->setEnabled( true );
473
474   // Update image
475   if( err == "" )
476   {
477     TPluginMesh* result = filter->GetOutput< TPluginMesh >( 0 );
478     result->DisconnectPipeline( );
479     this->m_Mesh = result;
480     err = this->_ConfigureMeshActors( );
481     if( err != "" )
482       QMessageBox::critical(
483         this,
484         tr( "Error message" ),
485         tr( err.c_str( ) )
486         );
487   }
488   else
489     QMessageBox::critical(
490       this,
491       tr( "Error executing filter" ),
492       tr( err.c_str( ) )
493       );
494 }
495
496 // -------------------------------------------------------------------------
497 void ImageMPR::
498 _triggered_actionUndo()
499 {
500         MementoState memento = MementoState();
501     
502         if (this->m_state>1)
503         {
504                 this->m_state--;
505                 this->m_MPRObjects->SetImage(
506                         memento.getMemento(this->m_state)->GetOutput()
507                         );
508         } else
509         {
510                 QMessageBox::critical(
511                         this,
512                         tr("Error message"),
513                         tr("No history to undo")
514                         );
515         }
516
517 }
518
519 // -------------------------------------------------------------------------
520 void ImageMPR::
521 _triggered_actionRedo()
522 {
523         MementoState memento = MementoState();
524         try
525         {
526                 this->m_state++;
527                 this->m_MPRObjects->SetImage(
528                         memento.getMemento(this->m_state)->GetOutput()
529                         );
530         }
531         catch (int err)
532         {
533                 QMessageBox::critical(
534                         this,
535                         tr("Error message"),
536                         tr("No history to redo")
537                         );
538         }
539 }
540         
541
542 // eof - $RCSfile$