00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
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
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
00244 this->m_Colormap = Colormap::New();
00245 this->m_Colormap->SetStandardColormap( PALETTE_GRAY );
00246 this->m_Colormap->SetDataRange( 0, 2000 );
00247
00248
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
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
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:
00325 title = "Axial image export";
00326 break;
00327 case 2:
00328 title = "Coronal image export";
00329 break;
00330 case 3:
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:
00355 pixmap = ScrollRenderViewAx->GetRenderImage()->GetPixmap();
00356 break;
00357 case 2:
00358 pixmap = ScrollRenderViewCo->GetRenderImage()->GetPixmap();
00359 break;
00360 case 3:
00361 pixmap = ScrollRenderViewSa->GetRenderImage()->GetPixmap();
00362 break;
00363 case 4:
00364 {
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 , 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
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 , 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 , true );
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 , true );
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
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
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
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
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
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
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 }