cmtkQtTriplanarWindow.cxx

Go to the documentation of this file.
00001 /*
00002 //
00003 //  Copyright 1997-2010 Torsten Rohlfing
00004 //
00005 //  Copyright 2004-2010 SRI International
00006 //
00007 //  This file is part of the Computational Morphometry Toolkit.
00008 //
00009 //  http://www.nitrc.org/projects/cmtk/
00010 //
00011 //  The Computational Morphometry Toolkit is free software: you can
00012 //  redistribute it and/or modify it under the terms of the GNU General Public
00013 //  License as published by the Free Software Foundation, either version 3 of
00014 //  the License, or (at your option) any later version.
00015 //
00016 //  The Computational Morphometry Toolkit is distributed in the hope that it
00017 //  will be useful, but WITHOUT ANY WARRANTY; without even the implied
00018 //  warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019 //  GNU General Public License for more details.
00020 //
00021 //  You should have received a copy of the GNU General Public License along
00022 //  with the Computational Morphometry Toolkit.  If not, see
00023 //  <http://www.gnu.org/licenses/>.
00024 //
00025 //  $Revision: 2398 $
00026 //
00027 //  $LastChangedDate: 2010-10-05 14:54:37 -0700 (Tue, 05 Oct 2010) $
00028 //
00029 //  $LastChangedBy: torstenrohlfing $
00030 //
00031 */
00032 
00033 #include "cmtkQtTriplanarWindow.h"
00034 
00035 #include <Base/cmtkLandmark.h>
00036 #include <Base/cmtkLandmarkList.h>
00037 #include <IO/cmtkClassStream.h>
00038 #include <Qt/cmtkQtIcons.h>
00039 
00040 #include <qapplication.h>
00041 #include <qmessagebox.h>
00042 #include <qradiobutton.h>
00043 #include <QMenuBar>
00044 #include <QMenu>
00045 #include <qinputdialog.h>
00046 #include <qfiledialog.h>
00047 
00048 #include <QLabel>
00049 #include <QGridLayout>
00050 #include <QPixmap>
00051 #include <QPainter>
00052 
00053 #include <iostream>
00054 #include <fstream>
00055 #include <sstream>
00056 
00057 namespace
00058 cmtk
00059 {
00060 
00063 
00064 QtTriplanarWindow::QtTriplanarWindow()
00065   : QWidget( NULL ),
00066     m_Study( NULL ),
00067     m_ZoomFactor( 100 ),
00068     m_BatchMode( false )
00069 {
00070   this->setWindowIcon( QtIcons::WindowIcon() );
00071 
00072   this->m_ZoomActions = new QActionGroup( this );
00073   this->m_ZoomActions->setExclusive( true );
00074   QAction* action;
00075 
00076   MenuBar = new QMenuBar( this );
00077 
00078   this->ViewMenu = MenuBar->addMenu( "&View" );
00079   action = ViewMenu->addAction( "25%", this, SLOT( slotView25() ) );
00080   action->setCheckable( true );
00081   this->m_ZoomActions->addAction( action );
00082   action = ViewMenu->addAction( "33%", this, SLOT( slotView33() ) );
00083   action->setCheckable( true );
00084   this->m_ZoomActions->addAction( action );
00085   action = ViewMenu->addAction( "50%", this, SLOT( slotView50() ) );
00086   action->setCheckable( true );
00087   this->m_ZoomActions->addAction( action );
00088   ViewMenu->addSeparator();
00089   action = ViewMenu->addAction( "100%", this, SLOT( slotView100() ) );
00090   action->setCheckable( true );
00091   action->setChecked( true );  
00092   this->m_ZoomActions->addAction( action );
00093   ViewMenu->addSeparator();
00094   action = ViewMenu->addAction( "200%", this, SLOT( slotView200() ) );
00095   action->setCheckable( true );
00096   this->m_ZoomActions->addAction( action );
00097   action = ViewMenu->addAction( "300%", this, SLOT( slotView300() ) );
00098   action->setCheckable( true );
00099   this->m_ZoomActions->addAction( action );
00100   action = ViewMenu->addAction( "400%", this, SLOT( slotView400() ) );
00101   action->setCheckable( true );
00102   this->m_ZoomActions->addAction( action );
00103   action = ViewMenu->addAction( "500%", this, SLOT( slotView500() ) );
00104   action->setCheckable( true );
00105   this->m_ZoomActions->addAction( action );
00106   ViewMenu->addSeparator();
00107   (this->m_InterpolateAction = ViewMenu->addAction( "&Interpolation", this, SLOT( slotViewInterpolation() ) ))->setCheckable( true );
00108   this->m_InterpolateAction->setChecked( false );
00109   (this->m_CrosshairAction = ViewMenu->addAction( "&Crosshair", this, SLOT( slotViewCrosshair() ) ))->setCheckable( true );
00110   this->m_CrosshairAction->setChecked( true );
00111   (this->m_CheckerboxAction = ViewMenu->addAction( "C&heckerbox", this, SLOT( slotViewCheckerbox() ) ))->setCheckable( true );
00112   this->m_CheckerboxAction->setChecked( true );
00113   
00114   this->ExportMenu = MenuBar->addMenu( "&Export" );
00115   ExportMenu->addAction( "&Axial" )->setData( QVariant( 1 ) );
00116   ExportMenu->addAction( "&Coronal" )->setData( QVariant( 2 ) );
00117   ExportMenu->addAction( "&Sagittal" )->setData( QVariant( 3 ) );
00118   ExportMenu->addSeparator();
00119   ExportMenu->addAction( "&Panel")->setData( QVariant( 4 ) );
00120   QObject::connect( ExportMenu, SIGNAL( triggered( QAction* ) ), this, SLOT( slotExportMenuCmd( QAction* ) ) );
00121 
00122   MenuBar->show();
00123 
00124   StatusBar = new QStatusBar( this );
00125   StatusBar->show();
00126   GridIndexInfo = new QLabel( StatusBar );
00127   GridIndex[0] = GridIndex[1] = GridIndex[2] = 0;
00128   StatusBar->addWidget( GridIndexInfo, 1 );
00129 
00130   GridLayout = new QGridLayout( this );
00131   GridLayout->setMenuBar( MenuBar );
00132   GridLayout->addWidget( StatusBar, 2, 0, 1, 2 );
00133 
00134   ScrollRenderViewAx = new QtScrollRenderView( this, "Axial" );
00135   ScrollRenderViewAx->SetSliderLabelL( "I" );
00136   ScrollRenderViewAx->SetSliderLabelR( "S" );
00137   ScrollRenderViewAx->GetRenderImage()->SetFlipX( true );
00138   ScrollRenderViewAx->GetRenderImage()->SetFlipY( true );
00139   ScrollRenderViewAx->ShowSlider();
00140   ScrollRenderViewAx->GetRenderImage()->SetCrosshairMode( this->m_CrosshairAction->isChecked() );
00141   ScrollRenderViewAx->GetRenderImage()->SetCrosshairColors( QColor( 255,0,0 ), QColor( 0,255,0 ) );
00142   GridLayout->addWidget( ScrollRenderViewAx, 1, 0 );
00143 
00144   ScrollRenderViewSa = new QtScrollRenderView( this, "Sagittal" );
00145   ScrollRenderViewSa->ShowSlider();
00146   ScrollRenderViewSa->SetSliderLabelL( "L" );
00147   ScrollRenderViewSa->SetSliderLabelR( "R" );
00148   ScrollRenderViewSa->GetRenderImage()->SetCrosshairMode( this->m_CrosshairAction->isChecked() );
00149   ScrollRenderViewSa->GetRenderImage()->SetCrosshairColors( QColor( 0,255,0 ), QColor( 0,0,255 ) );
00150   GridLayout->addWidget( ScrollRenderViewSa, 0, 1 );
00151 
00152   ScrollRenderViewCo = new QtScrollRenderView( this, "Coronal" );
00153   ScrollRenderViewCo->ShowSlider();
00154   ScrollRenderViewCo->SetSliderLabelL( "P" );
00155   ScrollRenderViewCo->SetSliderLabelR( "A" );
00156   ScrollRenderViewCo->GetRenderImage()->SetFlipX( true );
00157   ScrollRenderViewCo->GetRenderImage()->SetCrosshairMode( this->m_CrosshairAction->isChecked() );
00158   ScrollRenderViewCo->GetRenderImage()->SetCrosshairColors( QColor( 255,0,0 ), QColor( 0,0,255 ) );
00159   GridLayout->addWidget( ScrollRenderViewCo, 0, 0 );
00160 
00161   this->m_ControlsTab = new QTabWidget( this );
00162   this->m_ControlsTab->setContentsMargins( 10, 10, 10, 10 );
00163   GridLayout->addWidget( this->m_ControlsTab, 1, 1 );
00164 
00165   QWidget *landmarksTab = new QWidget( this->m_ControlsTab );
00166   this->m_ControlsTab->addTab( landmarksTab, "Landmarks" );
00167 
00168   LandmarksLayout = new QGridLayout( landmarksTab );
00169 
00170   LocationEntryX = new QLineEdit( landmarksTab );
00171   LocationValidatorX = new QDoubleValidator( LocationEntryX );
00172   LocationValidatorX->setDecimals( 6 );
00173   LocationEntryX->setValidator( LocationValidatorX );
00174   LandmarksLayout->addWidget( LocationEntryX, 0, 0 );
00175 
00176   QObject::connect( LocationEntryX, SIGNAL( returnPressed() ), this, SLOT( slotGoToLocation() ) );
00177 
00178   LocationEntryY = new QLineEdit( landmarksTab );
00179   LocationValidatorY = new QDoubleValidator( LocationEntryY );
00180   LocationEntryY->setValidator( LocationValidatorY );
00181   LocationValidatorY->setDecimals( 6 );
00182   LandmarksLayout->addWidget( LocationEntryY, 0, 1 );
00183 
00184   QObject::connect( LocationEntryY, SIGNAL( returnPressed() ), this, SLOT( slotGoToLocation() ) );
00185 
00186   LocationEntryZ = new QLineEdit( landmarksTab );
00187   LocationValidatorZ = new QDoubleValidator( LocationEntryZ );
00188   LocationEntryZ->setValidator( LocationValidatorZ );
00189   LocationValidatorZ->setDecimals( 6 );
00190   LandmarksLayout->addWidget( LocationEntryZ, 0, 2 );
00191 
00192   QObject::connect( LocationEntryZ, SIGNAL( returnPressed() ), this, SLOT( slotGoToLocation() ) );
00193 
00194   CenterButton = new QPushButton( landmarksTab );
00195   CenterButton->setText( "Center" );
00196   LandmarksLayout->addWidget( CenterButton, 1, 1 );
00197   QObject::connect( CenterButton, SIGNAL( clicked() ), this, SLOT( slotCenter() ) );
00198 
00199   GoToLocationButton = new QPushButton( landmarksTab );
00200   GoToLocationButton->setText( "Go To" );
00201   LandmarksLayout->addWidget( GoToLocationButton, 1, 2 );
00202   QObject::connect( GoToLocationButton, SIGNAL( clicked() ), this, SLOT( slotGoToLocation() ) );
00203 
00204   LandmarkBox = new QComboBox( landmarksTab );
00205   LandmarksLayout->addWidget( LandmarkBox, 2, 0, 1, 2 );
00206   LandmarkBox->setEnabled( false );
00207   QObject::connect( LandmarkBox, SIGNAL( currentIndexChanged(int) ), this, SLOT( slotGoToLandmark() ) );
00208 
00209   GoToLandmarkButton = new QPushButton( landmarksTab );
00210   GoToLandmarkButton->setText( "Go To" );
00211   LandmarksLayout->addWidget( GoToLandmarkButton, 3, 0 );
00212   QObject::connect( GoToLandmarkButton, SIGNAL( clicked() ), this, SLOT( slotGoToLandmark() ) );
00213   GoToLandmarkButton->setEnabled( false );
00214 
00215   DeleteLandmarkButton = new QPushButton( landmarksTab );
00216   DeleteLandmarkButton->setText( "Delete" );
00217   LandmarksLayout->addWidget( DeleteLandmarkButton, 3, 1 );
00218   QObject::connect( DeleteLandmarkButton, SIGNAL( clicked() ), this, SLOT( slotDeleteLandmark() ) );
00219   DeleteLandmarkButton->setEnabled( false );
00220   
00221   AddLandmarkButton = new QPushButton( landmarksTab );
00222   AddLandmarkButton->setText( "Add..." );
00223   LandmarksLayout->addWidget( AddLandmarkButton, 3, 2 );
00224   QObject::connect( AddLandmarkButton, SIGNAL( clicked() ), this, SLOT( slotAddLandmark() ) );
00225   
00226   ExportLandmarksButton = new QPushButton( landmarksTab );
00227   ExportLandmarksButton->setText( "Export Landmarks..." );
00228   LandmarksLayout->addWidget( ExportLandmarksButton, 5, 0 );
00229   QObject::connect( ExportLandmarksButton, SIGNAL( clicked() ), this, SLOT( slotExportLandmarks() ) );
00230   ExportLandmarksButton->setEnabled( false );
00231 
00232   ImportLandmarksButton = new QPushButton( landmarksTab );
00233   ImportLandmarksButton->setText( "Import Landmarks..." );
00234   LandmarksLayout->addWidget( ImportLandmarksButton, 5, 2 );
00235   QObject::connect( ImportLandmarksButton, SIGNAL( clicked() ), this, SLOT( slotImportLandmarks() ) );
00236   ImportLandmarksButton->setEnabled( true );
00237 
00238   // create the window/level tab
00239   WindowLevelControls = new QtWindowLevelControls( this->m_ControlsTab );
00240   QObject::connect( WindowLevelControls, SIGNAL( colormap( Study::SmartPtr& ) ), this, SLOT( slotColormapChanged( Study::SmartPtr& ) ) );
00241   this->m_ControlsTab->addTab( WindowLevelControls, "Window/Level" );
00242 
00243   // create the visualization pipeline
00244   this->m_Colormap = Colormap::New();
00245   this->m_Colormap->SetStandardColormap( PALETTE_GRAY );
00246   this->m_Colormap->SetDataRange( 0, 2000 );
00247 
00248   // set up axial viewer
00249   PipelineImageAx = Image::New();
00250   ImageToImageRGBAx = ImageToImageRGB::New();
00251   ImageToImageRGBAx->SetAlphaMode( ImageToImageRGB::AlphaModeConst );
00252   ImageToImageRGBAx->SetInput( PipelineImageAx );
00253   ImageToImageRGBAx->SetColormap( this->m_Colormap );
00254   ScrollRenderViewAx->slotConnectImage( ImageToImageRGBAx->GetOutput() );
00255 
00256   QObject::connect( ScrollRenderViewAx, SIGNAL( indexChanged( int ) ), this, SLOT( slotSwitchImageAx( int ) ) );
00257   QObject::connect( ScrollRenderViewAx, SIGNAL( signalMouse3D( Qt::MouseButton, const Vector3D& ) ), this, SLOT( slotMouseAx( Qt::MouseButton, const Vector3D& ) ) );
00258   
00259   // set up sagittal viewer
00260   PipelineImageSa = Image::New();
00261   ImageToImageRGBSa = ImageToImageRGB::New();
00262   ImageToImageRGBSa->SetAlphaMode( ImageToImageRGB::AlphaModeConst );
00263   ImageToImageRGBSa->SetInput( PipelineImageSa );
00264   ImageToImageRGBSa->SetColormap( this->m_Colormap );
00265   ScrollRenderViewSa->slotConnectImage( ImageToImageRGBSa->GetOutput() );
00266 
00267   PipelineImageCo = Image::New();
00268   QObject::connect( ScrollRenderViewSa, SIGNAL( indexChanged( int ) ), this, SLOT( slotSwitchImageSa( int ) ) );
00269   QObject::connect( ScrollRenderViewSa, SIGNAL( signalMouse3D( Qt::MouseButton, const Vector3D& ) ), this, SLOT( slotMouseSa( Qt::MouseButton, const Vector3D& ) ) );
00270 
00271   // set up coronal viewer
00272   ImageToImageRGBCo = ImageToImageRGB::New();
00273   ImageToImageRGBCo->SetAlphaMode( ImageToImageRGB::AlphaModeConst );
00274   ImageToImageRGBCo->SetInput( PipelineImageCo );
00275   ImageToImageRGBCo->SetColormap( this->m_Colormap );
00276   ScrollRenderViewCo->slotConnectImage( ImageToImageRGBCo->GetOutput() );
00277 
00278   QObject::connect( ScrollRenderViewCo, SIGNAL( indexChanged( int ) ), this, SLOT( slotSwitchImageCo( int ) ) );
00279   QObject::connect( ScrollRenderViewCo, SIGNAL( signalMouse3D( Qt::MouseButton, const Vector3D& ) ), this, SLOT( slotMouseCo( Qt::MouseButton, const Vector3D& ) ) );
00280 
00281   this->m_ProgressReporter = new QtProgress( this );
00282 }
00283 
00284 
00285 void
00286 QtTriplanarWindow::slotSetZoom( const int zoomPercent )
00287 {
00288   this->m_ZoomFactor = zoomPercent;
00289   ScrollRenderViewAx->GetRenderImage()->SetZoomFactorPercent( zoomPercent );
00290   ScrollRenderViewCo->GetRenderImage()->SetZoomFactorPercent( zoomPercent );
00291   ScrollRenderViewSa->GetRenderImage()->SetZoomFactorPercent( zoomPercent );
00292   this->slotRenderAll();
00293 }
00294 
00295 void
00296 QtTriplanarWindow::slotSetCheckerboardMode( const bool mode )
00297 {
00298   this->m_CheckerboxAction->setChecked( mode );
00299   this->slotViewCheckerbox();
00300 }
00301       
00302 void
00303 QtTriplanarWindow::slotSetCrosshairMode( const bool mode )
00304 {
00305   this->m_CrosshairAction->setChecked( mode );
00306   this->slotViewCrosshair();
00307 }
00308       
00309 void
00310 QtTriplanarWindow::slotSetInterpolateMode( const bool mode )
00311 {
00312   this->m_InterpolateAction->setChecked( mode );
00313   this->slotViewInterpolation();
00314 }
00315       
00316 void
00317 QtTriplanarWindow::slotExportMenuCmd( QAction* action )
00318 {
00319   const int mode = action->data().toInt();
00320 
00321   QString title( "Choose filename" );
00322   switch ( mode ) 
00323     {
00324     case 1: // Axial image.
00325       title = "Axial image export";
00326       break;
00327     case 2: // Coronal image.
00328       title = "Coronal image export";
00329       break;
00330     case 3: // Sagittal.
00331       title = "Sagittal image export";
00332       break;
00333     case 4: 
00334       title = "Panel image export";
00335       break;
00336     }
00337   
00338   QString filename( "image.png" );
00339   filename = QFileDialog::getSaveFileName( this, title, filename, "Portable Network Graphic (*.png);; Tagged Image File Format (*.tif);; Portable Pixmap (*.ppm *.pgm);; JPEG (*.jpg)" );
00340   
00341   if ( !filename.isEmpty() ) 
00342     {
00343     this->slotExportImage( filename, mode );
00344     }
00345 }
00346 
00347 
00348 void
00349 QtTriplanarWindow::slotExportImage( const QString& filename, const int command )
00350 {  
00351   QPixmap pixmap;
00352   switch ( command ) 
00353     {
00354     case 1: // Axial image.
00355       pixmap = ScrollRenderViewAx->GetRenderImage()->GetPixmap();
00356       break;
00357     case 2: // Coronal image.
00358       pixmap = ScrollRenderViewCo->GetRenderImage()->GetPixmap();
00359       break;
00360     case 3: // Sagittal.
00361       pixmap = ScrollRenderViewSa->GetRenderImage()->GetPixmap();
00362       break;
00363     case 4: 
00364     { // Panel.
00365     QPixmap pixmapAx = ScrollRenderViewAx->GetRenderImage()->GetPixmap();
00366     QPixmap pixmapSa = ScrollRenderViewSa->GetRenderImage()->GetPixmap();
00367     QPixmap pixmapCo = ScrollRenderViewCo->GetRenderImage()->GetPixmap();
00368     
00369     pixmap = QPixmap( pixmapCo.width() + pixmapSa.width(), pixmapCo.height() + pixmapAx.height() );
00370     QPainter painter( &pixmap );
00371 
00372     painter.drawPixmap( 0, 0, pixmapCo.width(), pixmapCo.height(), pixmapCo );
00373     painter.drawPixmap( pixmapCo.width(), 0, pixmapSa.width(), pixmapSa.height(), pixmapSa );
00374     painter.drawPixmap( 0, pixmapCo.height(), pixmapAx.width(), pixmapAx.height(), pixmapAx );
00375     painter.fillRect( pixmapCo.width(), pixmapCo.height(), pixmapSa.width(), pixmapAx.height(), Qt::black );
00376     break;
00377     }
00378     }
00379   
00380   QString format = filename.section( ".", -1 ).toUpper();
00381   if ( format.isEmpty() )
00382     format = "PNG";
00383   if ( !pixmap.save( filename, format.toLatin1() ) )
00384     {
00385     if ( this->m_BatchMode )
00386       std::cerr << "WARNING: saving file failed." << std::endl;
00387     else
00388       QMessageBox::warning( this, "Save failed", "Error saving file" );
00389     }
00390 }
00391 
00392 void
00393 QtTriplanarWindow::slotRenderAll()
00394 {
00395   ScrollRenderViewAx->slotRender();
00396   ScrollRenderViewCo->slotRender();
00397   ScrollRenderViewSa->slotRender();
00398 }
00399 
00400 void 
00401 QtTriplanarWindow::slotSwitchToStudy( Study::SmartPtr& study )
00402 {
00403   this->m_Study = study;
00404   if ( this->m_Study ) 
00405     {
00406     qApp->setOverrideCursor( Qt::WaitCursor );
00407     this->m_Study->ReadVolume(  true /* reload */, AnatomicalOrientation::ORIENTATION_STANDARD );
00408     qApp->restoreOverrideCursor();
00409     
00410     if ( !this->m_BatchMode )
00411       {
00412       while ( ! this->m_Study->GetVolume() ) 
00413         {
00414         int button = QMessageBox::warning ( NULL, "Error", "Could not read image data for this study.", QMessageBox::Retry, QMessageBox::Abort );
00415         if ( button == QMessageBox::Abort ) break;
00416         }
00417       }
00418 
00419     if ( this->m_Study->GetVolume() ) 
00420       {
00421       this->SetStudy( this->m_Study );
00422       this->WindowLevelControls->slotSetStudy( this->m_Study );
00423       this->slotCenter();
00424       this->slotColormapChanged( this->m_Study );
00425       this->UpdateDialog();
00426       this->show();
00427       }
00428     else
00429       {
00430       if ( this->m_BatchMode )
00431         StdErr << "ERROR: could not read image " << this->m_Study->GetFileSystemPath() << "\n";
00432       }
00433     
00434     // if study has landmarks, put them into combo box.
00435     LandmarkBox->clear();
00436     const LandmarkList* ll = this->m_Study->GetLandmarkList();
00437     if ( ll ) 
00438       {
00439       LandmarkList::const_iterator ll_it = ll->begin();
00440       while ( ll_it != ll->end() ) 
00441         {
00442         LandmarkBox->addItem( (*ll_it)->GetName() );
00443         ++ll_it;
00444         }
00445       }
00446     LandmarkBox->setEnabled( LandmarkBox->count() );
00447     GoToLandmarkButton->setEnabled( LandmarkBox->count() );
00448     DeleteLandmarkButton->setEnabled( LandmarkBox->count() );
00449     ExportLandmarksButton->setEnabled( LandmarkBox->count() );
00450   }
00451 }
00452 
00453 void 
00454 QtTriplanarWindow::slotSwitchToStudyInternal( Study::SmartPtr& study )
00455 {
00456   this->m_Study = study;
00457   if ( this->m_Study ) 
00458     {
00459     this->m_Study->ReadVolume( false /* reload */, AnatomicalOrientation::ORIENTATION_STANDARD );
00460     
00461     while ( ! this->m_Study->GetVolume() ) 
00462       {
00463       int button = QMessageBox::warning ( NULL, "Error", "Could not read image data for this study.", QMessageBox::Retry, QMessageBox::Abort );
00464       if ( button == QMessageBox::Abort ) break;
00465       }
00466 
00467     if ( this->m_Study->GetVolume() ) 
00468       {
00469       this->SetStudy( this->m_Study );
00470       this->WindowLevelControls->slotSetStudy( this->m_Study );
00471 
00472       this->slotSwitchImageAx( ScrollRenderViewAx->GetSlice() );
00473       this->slotSwitchImageSa( ScrollRenderViewSa->GetSlice() );
00474       this->slotSwitchImageCo( ScrollRenderViewCo->GetSlice() );
00475       
00476       this->UpdateDialog();
00477       this->show();
00478       }
00479     }
00480 }
00481 
00482 void
00483 QtTriplanarWindow::UpdateDialog()
00484 {
00485   if ( this->m_Study ) 
00486     {
00487     const UniformVolume *volume = this->m_Study->GetVolume();
00488     if ( volume ) 
00489       {
00490       VolumeDims = volume->GetDims();
00491       
00492       ScrollRenderViewAx->slotSetNumberOfSlices( VolumeDims[AXIS_Z] );
00493       ScrollRenderViewSa->slotSetNumberOfSlices( VolumeDims[AXIS_X] );
00494       ScrollRenderViewCo->slotSetNumberOfSlices( VolumeDims[AXIS_Y] );
00495       
00496       LocationValidatorX->setBottom( 0 );
00497       LocationValidatorX->setTop( volume->Size[AXIS_X] );
00498       LocationValidatorY->setBottom( 0 );
00499       LocationValidatorY->setTop( volume->Size[AXIS_Y] );
00500       LocationValidatorZ->setBottom( 0 );
00501       LocationValidatorZ->setTop( volume->Size[AXIS_Z] );
00502       } 
00503     else
00504       {
00505       qWarning( "QtTriplanarWindow::UpdateDialog called with no image data loaded.\n" );
00506       }
00507     if ( this->m_CrosshairAction->isChecked() ) 
00508       {
00509       this->slotRenderAll();
00510       }
00511     
00512     QString caption;
00513     this->setWindowTitle( caption.sprintf( "CMTK Triplanar Viewer: %s", this->m_Study->GetName() ) );
00514     this->show();
00515     }
00516 }
00517 
00518 void
00519 QtTriplanarWindow::slotDataChanged( Study::SmartPtr& study )
00520 {
00521   if ( study != this->m_Study ) return;
00522   this->slotGoToLocation();
00523 }
00524 
00525 void
00526 QtTriplanarWindow::slotSwitchImageAx( int imageIndex )
00527 {
00528   const UniformVolume *volume = this->m_Study->GetVolume();
00529 
00530   if ( volume ) 
00531     {
00532     ScalarImage::SmartPtr sliceImage( volume->GetOrthoSlice( AXIS_Z, imageIndex ) );
00533     
00534     if ( sliceImage ) 
00535       {
00536       if ( ! this->m_CheckerboxAction->isChecked() )
00537         sliceImage->GetPixelData()->ReplacePaddingData( 0.0 );
00538       
00539       sliceImage->AdjustToIsotropic( volume->GetMinDelta(), this->m_InterpolateAction->isChecked() );
00540       PipelineImageAx->SetFromScalarImage( sliceImage );
00541       }
00542     sliceImage = ScalarImage::SmartPtr::Null;
00543 
00544     LocationEntryZ->setText( QString::number( volume->GetPlaneCoord( AXIS_Z, imageIndex ) ) );
00545     GridIndex[2] = imageIndex;
00546     this->UpdateGridInfo();
00547     
00548     if ( this->m_CrosshairAction->isChecked() ) 
00549       {
00550       this->slotGoToLocation();
00551       } 
00552     else
00553       {
00554       ScrollRenderViewAx->slotRender();
00555       }
00556     } 
00557   else
00558     {
00559     qWarning( "QtTriplanarWindow::slotSwitchImageAx called with no image data loaded.\n" );
00560     }
00561 }
00562 
00563 void
00564 QtTriplanarWindow::slotSwitchImageSa( int imageIndex )
00565 {
00566   const UniformVolume *volume = this->m_Study->GetVolume();
00567 
00568   if ( volume ) 
00569     {
00570     ScalarImage *sliceImage = volume->GetOrthoSlice( AXIS_X, imageIndex );
00571     
00572     if ( sliceImage ) 
00573       {
00574       if ( ! this->m_CheckerboxAction->isChecked() )
00575         sliceImage->GetPixelData()->ReplacePaddingData( 0.0 );
00576       
00577       sliceImage->Mirror( false /* horizontal */, true /* vertical */ );
00578       sliceImage->AdjustToIsotropic( volume->GetMinDelta(), this->m_InterpolateAction->isChecked() );
00579       PipelineImageSa->SetFromScalarImage( sliceImage );
00580       delete sliceImage;
00581       }
00582     
00583     LocationEntryX->setText( QString::number( volume->GetPlaneCoord( AXIS_X, imageIndex ) ) );
00584     GridIndex[0] = imageIndex;
00585     this->UpdateGridInfo();
00586     
00587     if ( this->m_CrosshairAction->isChecked() ) 
00588       {
00589       this->slotGoToLocation();
00590       } 
00591     else
00592       {
00593       ScrollRenderViewSa->slotRender();
00594       }
00595     } 
00596   else
00597     {
00598     qWarning( "QtTriplanarWindow::slotSwitchImageSa called with no image data loaded.\n" );
00599     }
00600 }
00601 
00602 void
00603 QtTriplanarWindow::slotSwitchImageCo( int imageIndex )
00604 {
00605   const UniformVolume *volume = this->m_Study->GetVolume();
00606 
00607   if ( volume ) 
00608     {
00609     ScalarImage *sliceImage = volume->GetOrthoSlice( AXIS_Y, imageIndex );
00610     
00611     if ( sliceImage ) 
00612       {
00613       if ( ! this->m_CheckerboxAction->isChecked() )
00614         sliceImage->GetPixelData()->ReplacePaddingData( 0.0 );
00615       
00616       sliceImage->Mirror( false /* horizontal */, true /* vertical */ );
00617       sliceImage->AdjustToIsotropic( volume->GetMinDelta(), this->m_InterpolateAction->isChecked() );
00618       PipelineImageCo->SetFromScalarImage( sliceImage );
00619       delete sliceImage;
00620       }
00621     
00622     LocationEntryY->setText( QString::number( volume->GetPlaneCoord( AXIS_Y, imageIndex ) ) );
00623     GridIndex[1] = imageIndex;
00624     this->UpdateGridInfo();
00625     
00626     if ( this->m_CrosshairAction->isChecked() ) 
00627       {
00628       this->slotGoToLocation();
00629       } 
00630     else
00631       {
00632       ScrollRenderViewCo->slotRender();
00633       }
00634     
00635     } 
00636   else
00637     {
00638     qWarning( "QtTriplanarWindow::slotSwitchImageCo called with no image data loaded.\n" );
00639     }
00640 }
00641 
00642 void
00643 QtTriplanarWindow
00644 ::slotGoToPixel( const QString& xyz )
00645 {
00646   int x, y, z;
00647   if ( 3 != sscanf( xyz.toLatin1(), "%d,%d,%d", &x, &y, &z ) )
00648     {
00649     qWarning( "QtTriplanarWindow::slotGoToPixel needs pixel index as 'x,y,z'.\n" );
00650     }
00651   else
00652     {
00653     this->slotSwitchImageSa( x );
00654     this->slotSwitchImageCo( y );
00655     this->slotSwitchImageAx( z );
00656     }
00657 }
00658 
00659 void
00660 QtTriplanarWindow::slotGoToLocation( const QString& xyz )
00661 {
00662   float v[3];
00663   if ( 3 != sscanf( xyz.toLatin1(), "%f,%f,%f", v, v+1, v+2 ) )
00664     {
00665     qWarning( "QtTriplanarWindow::slotGoToLocation needs 3D coordinate as 'x,y,z'.\n" );
00666     }
00667   else
00668     {
00669     this->slotMouse3D( Qt::LeftButton, UniformVolume::CoordinateVectorType( v ) );
00670     }
00671 }
00672 
00673 void
00674 QtTriplanarWindow
00675 ::slotSetColormap( const QString& cmap )
00676 {
00677   for ( unsigned int colormapIndex = 0; Colormap::StandardColormaps[colormapIndex]; ++colormapIndex ) 
00678     {
00679     if ( cmap == QString( Colormap::StandardColormaps[colormapIndex] ) )
00680       {
00681       this->m_Colormap->SetStandardColormap( colormapIndex );
00682       this->slotRenderAll();
00683       break;
00684       }
00685     }
00686 }
00687 
00688 void
00689 QtTriplanarWindow
00690 ::slotSetWindowLevel( const QString& wl )
00691 {
00692   float window, level;
00693   if ( 2 != sscanf( wl.toLatin1(), "%f:%f", &window, &level ) )
00694     {
00695     qWarning( "QtTriplanarWindow::slotSetWindowLevel needs 'window:level'.\n" );
00696     }
00697   else
00698     {
00699     this->m_Colormap->SetDataRange( level-0.5*window, level+0.5*window );
00700     this->slotRenderAll();
00701     }
00702 }
00703 
00704 void 
00705 QtTriplanarWindow
00706 ::slotMouse3D( Qt::MouseButton, const Vector3D& v )
00707 {
00708 // if we don't have a study yet, simply ignore.
00709   if ( ! this->m_Study )
00710     return;
00711 
00712   const UniformVolume *volume = this->m_Study->GetVolume();
00713 
00714   unsigned int i=0, j=0;
00715   PipelineImageAx->ProjectPixel( v, i, j );
00716   ScrollRenderViewAx->GetRenderImage()->SetCrosshairPosition( i, j );
00717 
00718   PipelineImageSa->ProjectPixel( v, i, j ); 
00719   ScrollRenderViewSa->GetRenderImage()->SetCrosshairPosition( i, j );
00720 
00721   PipelineImageCo->ProjectPixel( v, i, j ); 
00722   ScrollRenderViewCo->GetRenderImage()->SetCrosshairPosition( i, j );
00723 
00724   if ( volume )
00725     {
00726     const unsigned int sliceSa = volume->GetClosestCoordIndex( AXIS_X, v[AXIS_X] );
00727     ScrollRenderViewSa->slotSetSlice( sliceSa );
00728     ScrollRenderViewSa->slotRender();
00729     
00730     const unsigned int sliceCo = volume->GetClosestCoordIndex( AXIS_Y, v[AXIS_Y] );
00731     ScrollRenderViewCo->slotSetSlice( sliceCo );
00732     ScrollRenderViewCo->slotRender();
00733     
00734     const unsigned int sliceAx = volume->GetClosestCoordIndex( AXIS_Z, v[AXIS_Z] );
00735     ScrollRenderViewAx->slotSetSlice( sliceAx );
00736     ScrollRenderViewAx->slotRender();
00737     }
00738 }
00739 
00740 void 
00741 QtTriplanarWindow
00742 ::slotMouseAx( Qt::MouseButton, const Vector3D& v )
00743 {
00744 // if we don't have a study yet, simply ignore.
00745   if ( ! this->m_Study )
00746     return;
00747 
00748   const UniformVolume *volume = this->m_Study->GetVolume();
00749 
00750   unsigned int i=0, j=0;
00751   PipelineImageAx->ProjectPixel( v, i, j );
00752   ScrollRenderViewAx->GetRenderImage()->SetCrosshairPosition( i, j );
00753 
00754   if ( volume )
00755     {
00756     const unsigned int sliceSa = volume->GetClosestCoordIndex( AXIS_X, v[AXIS_X] );
00757     ScrollRenderViewSa->slotSetSlice( sliceSa );
00758     ScrollRenderViewSa->slotRender();
00759     
00760     const unsigned int sliceCo = volume->GetClosestCoordIndex( AXIS_Y, v[AXIS_Y] );
00761     ScrollRenderViewCo->slotSetSlice( sliceCo );
00762     ScrollRenderViewCo->slotRender();
00763     }
00764 }
00765 
00766 void 
00767 QtTriplanarWindow
00768 ::slotMouseSa( Qt::MouseButton, const Vector3D& v )
00769 {
00770 // if we don't have a study yet, simply ignore.
00771   if ( ! this->m_Study )
00772     return;
00773 
00774   const UniformVolume *volume = this->m_Study->GetVolume();
00775 
00776   unsigned int i=0, j=0;
00777   PipelineImageSa->ProjectPixel( v, i, j );
00778   ScrollRenderViewSa->GetRenderImage()->SetCrosshairPosition( i, j );
00779 
00780   if ( volume )
00781     {
00782     const unsigned int sliceAx = volume->GetClosestCoordIndex( AXIS_Z, v[AXIS_Z] );
00783     ScrollRenderViewAx->slotSetSlice( sliceAx );
00784     ScrollRenderViewAx->slotRender();
00785     
00786     const unsigned int sliceCo = volume->GetClosestCoordIndex( AXIS_Y, v[AXIS_Y] );
00787     ScrollRenderViewCo->slotSetSlice( sliceCo );
00788     ScrollRenderViewCo->slotRender();
00789     }
00790 }
00791 
00792 void 
00793 QtTriplanarWindow
00794 ::slotMouseCo( Qt::MouseButton, const Vector3D& v )
00795 {
00796 // if we don't have a study yet, simply ignore.
00797   if ( ! this->m_Study )
00798     return;
00799 
00800   const UniformVolume *volume = this->m_Study->GetVolume();
00801 
00802   unsigned int i=0, j=0;
00803   PipelineImageCo->ProjectPixel( v, i, j );
00804   ScrollRenderViewCo->GetRenderImage()->SetCrosshairPosition( i, j );
00805 
00806   if ( volume )
00807     {
00808     const unsigned int sliceAx = volume->GetClosestCoordIndex( AXIS_Z, v[AXIS_Z] );
00809     ScrollRenderViewAx->slotSetSlice( sliceAx );
00810     ScrollRenderViewAx->slotRender();
00811     
00812     const unsigned int sliceSa = volume->GetClosestCoordIndex( AXIS_X, v[AXIS_X] );
00813     ScrollRenderViewSa->slotSetSlice( sliceSa );
00814     ScrollRenderViewSa->slotRender();
00815     }
00816 }
00817 
00818 void
00819 QtTriplanarWindow::slotCenter()
00820 {
00821   const UniformVolume *volume = this->m_Study->GetVolume();
00822   if ( ! volume ) return;
00823 
00824   // Pretend there was a button event at the given location
00825   this->slotMouse3D( Qt::LeftButton, volume->GetCenterCropRegion() );
00826 }
00827 
00828 void
00829 QtTriplanarWindow::slotGoToLocation()
00830 {
00831   const UniformVolume *volume = this->m_Study->GetVolume();
00832   if ( ! volume ) return;
00833 
00834   // Pretend there was a button event at the given location
00835   const double location[3] = { LocationEntryX->text().toDouble(), LocationEntryY->text().toDouble(), LocationEntryZ->text().toDouble() };
00836   this->slotMouse3D( Qt::LeftButton, UniformVolume::CoordinateVectorType( location ) );
00837 }
00838 
00839 void
00840 QtTriplanarWindow::slotGoToLandmark()
00841 {
00842   if ( ! this->m_Study ) return;
00843 
00844   const LandmarkList *ll = this->m_Study->GetLandmarkList();
00845   if ( ! ll ) return;
00846 
00847   const Landmark* lm = ll->FindByName( LandmarkBox->currentText().toLatin1() );
00848   if ( lm ) 
00849     {
00850     this->slotMouse3D( Qt::LeftButton, FixedVector<3,Types::Coordinate>( lm->GetLocation() ) );
00851     }
00852 }
00853 
00854 void
00855 QtTriplanarWindow::slotDeleteLandmark()
00856 {
00857 }
00858 
00859 void
00860 QtTriplanarWindow::slotExportLandmarks()
00861 {
00862   if ( ! this->m_Study ) return;
00863 
00864   LandmarkList::SmartPtr ll = this->m_Study->GetLandmarkList();
00865   if ( ! ll ) return;
00866 
00867   QString path = QFileDialog::getSaveFileName( this, "Save Landmarks File" );
00868   
00869   if ( ! path.isEmpty() ) 
00870     {
00871     std::ofstream stream( path.toLatin1().constData() );
00872     
00873     if ( stream.good() )
00874       {
00875       for ( LandmarkList::const_iterator it = ll->begin(); it != ll->end(); ++it )
00876         {
00877         FixedVector<3,Types::Coordinate> v( (*it)->GetLocation() );
00878         QString n( (*it)->GetName() );
00879 
00880         stream << v[0] << "\t" << v[1] << "\t" << v[2] << "\t" << (const char*)(n.toLatin1()) << std::endl;
00881         }
00882       stream.close();
00883       } 
00884     else 
00885       {
00886       QMessageBox::critical( NULL, "Error", "Could not open file for writing.", QMessageBox::Ok, Qt::NoButton, Qt::NoButton );
00887       }
00888     }
00889 }
00890 
00891 void
00892 QtTriplanarWindow::slotImportLandmarks()
00893 {
00894   if ( ! this->m_Study ) return;
00895 
00896   LandmarkList::SmartPtr ll = this->m_Study->GetLandmarkList();
00897   if ( ! ll ) 
00898     {
00899     ll = LandmarkList::SmartPtr( new LandmarkList );
00900     this->m_Study->SetLandmarkList( ll );
00901     }
00902   
00903   QString path = QFileDialog::getOpenFileName( this, "Open Landmarks File", QString(), "All Files (*.*)" );
00904   
00905   if ( ! path.isEmpty() ) 
00906     {
00907     std::ifstream stream( path.toLatin1().constData() );
00908 
00909     unsigned int cnt = 0;
00910     if ( stream.good() ) 
00911       {
00912       Landmark::SmartPtr lm;
00913       while ( ! stream.eof() )
00914         {
00915         Types::Coordinate xyz[3];
00916         stream >> xyz[0] >> xyz[1] >> xyz[2];
00917 
00918         char name[128];
00919         stream.getline( name, 128, '\n' );
00920 
00921         if ( ! strlen(name) )
00922           {
00923           sprintf( name, "LM-%04d", cnt++ );
00924           }
00925 
00926         lm = Landmark::SmartPtr( new Landmark( name, xyz ) );
00927         ll->push_back( lm );
00928         LandmarkBox->addItem( name );
00929         }
00930 
00931       lm = *(ll->begin());
00932       if ( lm )
00933         {
00934         this->LandmarkBox->setCurrentIndex( this->LandmarkBox->findText( lm->GetName() ) );
00935         this->slotMouse3D( Qt::LeftButton, FixedVector<3,Types::Coordinate>( lm->GetLocation() ) );
00936         }
00937 
00938       LandmarkBox->setEnabled( true );
00939       GoToLandmarkButton->setEnabled( true );
00940       DeleteLandmarkButton->setEnabled( true );
00941       ExportLandmarksButton->setEnabled( true );
00942       
00943       stream.close();
00944       } 
00945     else 
00946       {
00947       QMessageBox::critical( NULL, "Error", "Could not open file for reading.", QMessageBox::Ok, Qt::NoButton, Qt::NoButton );
00948       }
00949     }
00950 }
00951 
00952 void
00953 QtTriplanarWindow::slotAddLandmark()
00954 {
00955   if ( ! this->m_Study ) return;
00956 
00957   LandmarkList::SmartPtr ll = this->m_Study->GetLandmarkList();
00958   if ( ! ll ) 
00959     {
00960     ll = LandmarkList::SmartPtr( new LandmarkList );
00961     this->m_Study->SetLandmarkList( ll );
00962     }
00963   
00964   bool ok;
00965   QString name = QInputDialog::getText( this, "Add New Landmark", "Enter new landmark name:", QLineEdit::Normal, QString::null, &ok );
00966   if ( ok && !name.isEmpty() ) 
00967     {
00968     Types::Coordinate location[3] = { LocationEntryX->text().toDouble(), LocationEntryY->text().toDouble(), LocationEntryZ->text().toDouble() };
00969     ll->push_back( Landmark::SmartPtr( new Landmark( name.toLatin1(), location ) ) );
00970     LandmarkBox->addItem( name );
00971     LandmarkBox->setCurrentIndex( this->LandmarkBox->findText( name ) );
00972     
00973     LandmarkBox->setEnabled( true );
00974     GoToLandmarkButton->setEnabled( true );
00975     DeleteLandmarkButton->setEnabled( true );
00976     ExportLandmarksButton->setEnabled( true );
00977     }
00978 }
00979 
00980 void
00981 QtTriplanarWindow::slotColormapChanged( Study::SmartPtr& study )
00982 {
00983   if ( this->m_Study && (this->m_Study == study) ) 
00984     {
00985     this->m_Colormap->SetFromStudy( this->m_Study.GetPtr() );
00986     this->slotRenderAll();
00987     }
00988 }
00989 
00990 void
00991 QtTriplanarWindow::UpdateGridInfo()
00992 {
00993   if ( ! (this->m_Study && this->m_Study->GetVolume()) ) return;
00994 
00995   QString str = "OUTSIDE";
00996 
00997   const UniformVolume* volume = this->m_Study->GetVolume();
00998   if ( volume->IndexIsInRange( GridIndex[0], GridIndex[1], GridIndex[2] ) )
00999     {
01000     const FixedVector<3,float> v = volume->IndexToPhysical( GridIndex );
01001 
01002     Types::DataItem value;
01003     if ( volume->GetDataAt( value, GridIndex[0], GridIndex[1], GridIndex[2] ) )
01004       str.sprintf( "Pixel Index: [%d,%d,%d] RAS: [%g,%g,%g] Value: %g", GridIndex[0], GridIndex[1], GridIndex[2], v[0], v[1], v[2], value );
01005     else
01006       str.sprintf( "Pixel Index: [%d,%d,%d] RAS: [%g,%g,%g]", GridIndex[0], GridIndex[1], GridIndex[2], v[0], v[1], v[2] );
01007     }
01008   GridIndexInfo->setText( str );
01009 }
01010 
01011 } // namespace cmtk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines