1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192 |
- /*=========================================================================
- Library: CTK
- Copyright (c) Kitware Inc.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0.txt
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- =========================================================================*/
- #include <iostream>
- // CTK includes
- #include "ctkQImageView.h"
- // Qt includes
- #include <QApplication>
- #include <QLabel>
- #include <QHBoxLayout>
- #include <QDebug>
- #include <QResizeEvent>
- #include <QMouseEvent>
- #include <QKeyEvent>
- #include <QPainter>
- #include <QColor>
- #include <QTextEdit>
- #include <QDialog>
- #include <cmath>
- //--------------------------------------------------------------------------
- class ctkQImageViewPrivate
- {
- Q_DECLARE_PUBLIC( ctkQImageView );
- protected:
- ctkQImageView* const q_ptr;
- public:
- ctkQImageViewPrivate( ctkQImageView& object );
- void init();
- QLabel * Window;
- double Zoom;
- double PositionX;
- double PositionY;
- double CenterX;
- double CenterY;
- int SliceNumber;
- double IntensityLevel;
- double IntensityWindow;
- double IntensityMin;
- double IntensityMax;
- bool FlipXAxis;
- bool FlipYAxis;
- bool TransposeXY;
- QList< QImage > ImageList;
- QPixmap TmpImage;
- int TmpXMin;
- int TmpXMax;
- int TmpYMin;
- int TmpYMax;
- bool InvertImage;
- int MouseLastX;
- int MouseLastY;
- double MouseLastZoom;
- double MouseLastIntensityLevel;
- double MouseLastIntensityWindow;
- bool MouseLeftDragging;
- bool MouseMiddleDragging;
- bool MouseRightDragging;
- double clamp( double x, double xMin, double xMax );
- void fitImageRectangle( double x0, double y0, double x1, double y1 );
-
- };
- //--------------------------------------------------------------------------
- ctkQImageViewPrivate::ctkQImageViewPrivate(
- ctkQImageView& object )
- : q_ptr( &object )
- {
- this->Window = new QLabel();
- }
- //--------------------------------------------------------------------------
- void ctkQImageViewPrivate::init()
- {
- Q_Q( ctkQImageView );
- this->Window->setParent(q);
- QHBoxLayout* layout = new QHBoxLayout(q);
- layout->addWidget(this->Window);
- layout->setContentsMargins(0,0,0,0);
- q->setLayout(layout);
- q->setMouseTracking( true );
- // Set parameters for the view
- this->Zoom = 1;
- this->PositionX = 0;
- this->PositionY = 0;
- this->SliceNumber = 0;
- this->CenterX = 0;
- this->CenterY = 0;
- this->InvertImage = false;
- this->IntensityMin = 0;
- this->IntensityMax = 0;
- this->IntensityLevel = 0;
- this->IntensityWindow = 0;
- this->FlipXAxis = false;
- this->FlipYAxis = false;
- this->TransposeXY = false;
- this->ImageList.clear();
- this->TmpXMin = 0;
- this->TmpXMax = 0;
- this->TmpYMin = 0;
- this->TmpYMax = 0;
- this->MouseLastX = 0;
- this->MouseLastY = 0;
- this->MouseLastZoom = 0;
- this->MouseLeftDragging = false;
- this->MouseMiddleDragging = false;
- this->MouseRightDragging = false;
- // Don't expand for no reason
- q->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred );
- }
- //--------------------------------------------------------------------------
- double ctkQImageViewPrivate::clamp( double x, double xMin,
- double xMax )
- {
- if( x < xMin )
- {
- return xMin;
- }
- if( x > xMax )
- {
- return xMax;
- }
- return x;
- }
- //--------------------------------------------------------------------------
- void ctkQImageViewPrivate::fitImageRectangle( double x0,
- double x1, double y0, double y1 )
- {
- if( this->SliceNumber >= 0 && this->SliceNumber < this->ImageList.size() )
- {
- this->TmpXMin = this->clamp( x0, 0,
- this->ImageList[ this->SliceNumber ].width() );
- this->TmpXMax = this->clamp( x1, this->TmpXMin,
- this->ImageList[ this->SliceNumber ].width() );
- this->TmpYMin = this->clamp( y0, 0,
- this->ImageList[ this->SliceNumber ].height() );
- this->TmpYMax = this->clamp( y1, this->TmpYMin,
- this->ImageList[ this->SliceNumber ].height() );
- }
- }
- // -------------------------------------------------------------------------
- ctkQImageView::ctkQImageView( QWidget* _parent )
- : Superclass( _parent ),
- d_ptr( new ctkQImageViewPrivate( *this ) )
- {
- Q_D( ctkQImageView );
- d->init();
- d->TmpXMax = this->width();
- d->TmpYMax = this->height();
- }
- // -------------------------------------------------------------------------
- ctkQImageView::ctkQImageView(
- ctkQImageViewPrivate& pvt,
- QWidget* _parent)
- : Superclass(_parent), d_ptr(&pvt)
- {
- Q_D(ctkQImageView);
- d->init();
- }
- // -------------------------------------------------------------------------
- ctkQImageView::~ctkQImageView()
- {
- }
- // -------------------------------------------------------------------------
- void ctkQImageView::addImage( const QImage & image )
- {
- Q_D( ctkQImageView );
- d->ImageList.push_back( image );
- d->TmpXMin = 0;
- d->TmpXMax = image.width();
- d->TmpYMin = 0;
- d->TmpYMax = image.height();
- if( image.isGrayscale() )
- {
- d->IntensityMin = 0;
- d->IntensityMax = image.colorCount();
- this->setIntensityWindowLevel(
- image.colorCount(), image.colorCount()/2 );
- }
- this->update( true, false );
- this->setCenter( image.width()/2.0, image.height()/2.0 );
- }
- // -------------------------------------------------------------------------
- void ctkQImageView::clearImages( void )
- {
- Q_D( ctkQImageView );
- d->ImageList.clear();
- this->update( true, true );
- }
- // -------------------------------------------------------------------------
- double ctkQImageView::xSpacing( void )
- {
- Q_D( ctkQImageView );
- if( d->SliceNumber >= 0 && d->SliceNumber < d->ImageList.size() )
- {
- return( 1000.0 / d->ImageList[ d->SliceNumber ].dotsPerMeterX() );
- }
- else
- {
- return 1;
- }
- }
- // -------------------------------------------------------------------------
- double ctkQImageView::ySpacing( void )
- {
- Q_D( ctkQImageView );
- if( d->SliceNumber >= 0 && d->SliceNumber < d->ImageList.size() )
- {
- return( 1000.0 / d->ImageList[ d->SliceNumber ].dotsPerMeterY() );
- }
- else
- {
- return 1;
- }
- }
- // -------------------------------------------------------------------------
- double ctkQImageView::sliceSpacing( void )
- {
- return 1;
- }
- // -------------------------------------------------------------------------
- double ctkQImageView::sliceThickness( void )
- {
- return 1;
- }
- // -------------------------------------------------------------------------
- double ctkQImageView::xPosition( void )
- {
- Q_D( ctkQImageView );
- return d->PositionX;
- }
- // -------------------------------------------------------------------------
- double ctkQImageView::yPosition( void )
- {
- Q_D( ctkQImageView );
- return d->PositionY;
- }
- // -------------------------------------------------------------------------
- double ctkQImageView::slicePosition( void )
- {
- Q_D( ctkQImageView );
- return d->SliceNumber;
- }
- // -------------------------------------------------------------------------
- double ctkQImageView::positionValue( void )
- {
- Q_D( ctkQImageView );
- if( d->SliceNumber >= 0 && d->SliceNumber < d->ImageList.size() )
- {
- QColor vc( d->ImageList[ d->SliceNumber ].pixel( d->PositionX,
- d->PositionY ) );
- return vc.value();
- }
- return 0;
- }
- // -------------------------------------------------------------------------
- double ctkQImageView::xCenter( void )
- {
- Q_D( ctkQImageView );
- return d->CenterX;
- }
- // -------------------------------------------------------------------------
- double ctkQImageView::yCenter( void )
- {
- Q_D( ctkQImageView );
- return d->CenterY;
- }
- // -------------------------------------------------------------------------
- void ctkQImageView::setSliceNumber( int slicenum )
- {
- Q_D( ctkQImageView );
- if( slicenum >= 0 && slicenum < d->ImageList.size()
- && slicenum != d->SliceNumber )
- {
- d->SliceNumber = slicenum;
- emit this->sliceNumberChanged( slicenum );
- emit this->xSpacingChanged( this->xSpacing() );
- emit this->ySpacingChanged( this->ySpacing() );
- emit this->sliceThicknessChanged( this->sliceThickness() );
- emit this->slicePositionChanged( this->slicePosition() );
- this->update( false, false );
- }
- }
- //
- // -------------------------------------------------------------------------
- int ctkQImageView::sliceNumber( void ) const
- {
- Q_D( const ctkQImageView );
- if( d->SliceNumber >= 0 && d->SliceNumber < d->ImageList.size() )
- {
- return d->SliceNumber;
- }
- else
- {
- return -1;
- }
- }
- // -------------------------------------------------------------------------
- void ctkQImageView::setIntensityWindowLevel( double iwWindow,
- double iwLevel )
- {
- Q_D( ctkQImageView );
- if( iwLevel != d->IntensityLevel ||
- iwWindow != d->IntensityWindow )
- {
- d->IntensityLevel = iwLevel;
- d->IntensityWindow = iwWindow;
- emit this->intensityWindowChanged( iwWindow );
- emit this->intensityLevelChanged( iwLevel );
- this->update( false, false );
- }
- }
- // -------------------------------------------------------------------------
- double ctkQImageView::intensityLevel( void ) const
- {
- Q_D( const ctkQImageView );
- return d->IntensityLevel;
- }
- // -------------------------------------------------------------------------
- double ctkQImageView::intensityWindow( void ) const
- {
- Q_D( const ctkQImageView );
- return d->IntensityWindow;
- }
- // -------------------------------------------------------------------------
- void ctkQImageView::setInvertImage( bool invert )
- {
- Q_D( ctkQImageView );
- if( invert != d->InvertImage )
- {
- d->InvertImage = invert;
- emit this->invertImageChanged( invert );
- this->update( false, false );
- }
- }
- // -------------------------------------------------------------------------
- bool ctkQImageView::invertImage( void ) const
- {
- Q_D( const ctkQImageView );
- return d->InvertImage;
- }
- // -------------------------------------------------------------------------
- void ctkQImageView::setFlipXAxis( bool flip )
- {
- Q_D( ctkQImageView );
- if( flip != d->FlipXAxis )
- {
- d->FlipXAxis = flip;
- emit this->flipXAxisChanged( flip );
- this->update( false, false );
- }
- }
- // -------------------------------------------------------------------------
- bool ctkQImageView::flipXAxis( void ) const
- {
- Q_D( const ctkQImageView );
- return d->FlipXAxis;
- }
- // -------------------------------------------------------------------------
- void ctkQImageView::setFlipYAxis( bool flip )
- {
- Q_D( ctkQImageView );
- if( flip != d->FlipYAxis )
- {
- d->FlipYAxis = flip;
- emit this->flipYAxisChanged( flip );
- this->update( false, false );
- }
- }
- // -------------------------------------------------------------------------
- bool ctkQImageView::flipYAxis( void ) const
- {
- Q_D( const ctkQImageView );
- return d->FlipYAxis;
- }
- // -------------------------------------------------------------------------
- void ctkQImageView::setTransposeXY( bool transpose )
- {
- Q_D( ctkQImageView );
- if( transpose != d->TransposeXY )
- {
- d->TransposeXY = transpose;
- emit this->transposeXYChanged( transpose );
- this->update( false, false );
- }
- }
- // -------------------------------------------------------------------------
- bool ctkQImageView::transposeXY( void ) const
- {
- Q_D( const ctkQImageView );
- return d->TransposeXY;
- }
- // -------------------------------------------------------------------------
- void ctkQImageView::setCenter( double x, double y )
- {
- Q_D( ctkQImageView );
- if( d->SliceNumber >= 0 && d->SliceNumber < d->ImageList.size() )
- {
- int tmpXRange = d->TmpXMax - d->TmpXMin;
- if( tmpXRange > d->ImageList[ d->SliceNumber ].width() )
- {
- tmpXRange = d->ImageList[ d->SliceNumber ].width();
- }
- int tmpYRange = d->TmpYMax - d->TmpYMin;
- if( tmpYRange > d->ImageList[ d->SliceNumber ].height() )
- {
- tmpYRange = d->ImageList[ d->SliceNumber ].height();
- }
-
- int xMin2 = static_cast<int>(x) - tmpXRange/2.0;
- if( xMin2 < 0 )
- {
- xMin2 = 0;
- }
- int xMax2 = xMin2 + tmpXRange;
- if( xMax2 > d->ImageList[ d->SliceNumber ].width() )
- {
- xMax2 = d->ImageList[ d->SliceNumber ].width();
- xMin2 = xMax2 - tmpXRange;
- }
- int yMin2 = static_cast<int>(y) - tmpYRange/2.0;
- if( yMin2 < 0 )
- {
- yMin2 = 0;
- }
- int yMax2 = yMin2 + tmpYRange;
- if( yMax2 > d->ImageList[ d->SliceNumber ].height() )
- {
- yMax2 = d->ImageList[ d->SliceNumber ].height();
- yMin2 = yMax2 - tmpYRange;
- }
- d->fitImageRectangle( xMin2, xMax2, yMin2, yMax2 );
- d->CenterX = x;
- d->CenterY = y;
- emit this->xCenterChanged( x );
- emit this->yCenterChanged( y );
-
- this->update( false, false );
- }
- }
- // -------------------------------------------------------------------------
- void ctkQImageView::setPosition( double x, double y )
- {
- Q_D( ctkQImageView );
- if( d->SliceNumber >= 0 && d->SliceNumber < d->ImageList.size()
- && x >= 0 && y >= 0 && x < d->ImageList[ d->SliceNumber ].width()
- && y < d->ImageList[ d->SliceNumber ].height() )
- {
- d->PositionX = x;
- d->PositionY = y;
- emit this->xPositionChanged( x );
- emit this->yPositionChanged( y );
- emit this->positionValueChanged( this->positionValue() );
- this->update( false, false );
- }
- }
- // -------------------------------------------------------------------------
- double ctkQImageView::zoom( void )
- {
- Q_D( ctkQImageView );
- if( d->SliceNumber >= 0 && d->SliceNumber < d->ImageList.size() )
- {
- return d->Zoom;
- }
- return 1;
- }
- // -------------------------------------------------------------------------
- void ctkQImageView::setZoom( double factor )
- {
- Q_D( ctkQImageView );
- if( d->SliceNumber >= 0 && d->SliceNumber < d->ImageList.size() )
- {
- const QImage * img = & d->ImageList[ d->SliceNumber ];
- if( factor < 2.0 / img->width() )
- {
- factor = 2.0 / img->width();
- }
- if( factor > img->width()/2.0 )
- {
- factor = img->width()/2.0;
- }
- d->Zoom = factor;
- double cx = d->CenterX;
- double cy = d->CenterY;
- double x2 = img->width() / factor;
- double y2 = img->height() / factor;
-
- int xMin2 = static_cast<int>(cx) - x2 / 2.0;
- if( xMin2 < 0 )
- {
- xMin2 = 0;
- }
- int xMax2 = xMin2 + x2;
- if( xMax2 > d->ImageList[ d->SliceNumber ].width() )
- {
- xMax2 = d->ImageList[ d->SliceNumber ].width();
- xMin2 = xMax2 - x2;
- }
- int yMin2 = static_cast<int>(cy) - y2 / 2.0;
- if( yMin2 < 0 )
- {
- yMin2 = 0;
- }
- int yMax2 = yMin2 + y2;
- if( yMax2 > d->ImageList[ d->SliceNumber ].height() )
- {
- yMax2 = d->ImageList[ d->SliceNumber ].height();
- yMin2 = yMax2 - y2;
- }
- d->fitImageRectangle( xMin2, xMax2, yMin2, yMax2 );
-
- this->update( true, true );
- }
- }
- // -------------------------------------------------------------------------
- void ctkQImageView::reset( )
- {
- Q_D( ctkQImageView );
- if( d->ImageList.size() > 0 )
- {
- if( d->SliceNumber < 0 )
- {
- this->setSliceNumber( 0 );
- }
- }
- this->setZoom( 1 );
- if( d->SliceNumber >= 0 && d->SliceNumber < d->ImageList.size() )
- {
- this->setCenter( d->ImageList[ d->SliceNumber ].width()/2,
- d->ImageList[ d->SliceNumber ].height()/2 );
- }
- }
- // -------------------------------------------------------------------------
- void ctkQImageView::keyPressEvent( QKeyEvent * event )
- {
- Q_D( ctkQImageView );
- if( d->SliceNumber >= 0 && d->SliceNumber < d->ImageList.size() )
- {
- switch( event->key() )
- {
- case Qt::Key_H:
- {
- QTextEdit * help = new QTextEdit();
- help->setWindowFlags( Qt::Window );
- help->setMinimumSize( 500, 500 );
- help->setSizePolicy( QSizePolicy::Preferred,
- QSizePolicy::Preferred );
- help->setReadOnly( true );
- help->append("<h1>CTK Simple Image Viewer Widget</h1>");
- help->append("Contributed by: Kitware, Inc.<br>");
- help->append("<h3>Keyboard commands:</h3>");
- help->append(" <em>q</em> : quit");
- help->append(" <em>h</em> : display this help");
- help->append(" <em>i</em> : invert intensities");
- help->append(" <em>[ ]</em> : increase / decrease zoom");
- help->append(" <em>x y</em> : flip along the x / y axis");
- help->append(" <em>r</em> : reset to initial conditions");
- help->append(" <em>spacebar</em> : toggle continuous tracking of cursor");
- help->append(" <em>up-arrow down-arrow</em> : change to next / previous slice");
- help->append("<h3>Mouse commands:</h3>");
- help->append(" <em>left-button</em> : window and level");
- help->append(" <em>middle-button</em> : zoom");
- help->append(" <em>right-button</em> : center");
- help->show();
- break;
- }
- case Qt::Key_Space:
- {
- d->Window->setMouseTracking( ! d->Window->hasMouseTracking() );
- break;
- }
- case Qt::Key_X:
- {
- this->setFlipXAxis( ! this->flipXAxis() );
- break;
- }
- case Qt::Key_Y:
- {
- this->setFlipYAxis( ! this->flipYAxis() );
- break;
- }
- case Qt::Key_T:
- {
- this->setTransposeXY( ! this->transposeXY() );
- break;
- }
- case Qt::Key_BracketRight:
- {
- this->setZoom( this->zoom() * 1.1 );
- break;
- }
- case Qt::Key_BracketLeft:
- {
- this->setZoom( this->zoom() * 0.9 );
- break;
- }
- case Qt::Key_I:
- {
- this->setInvertImage( ! this->invertImage() );
- this->update( false, false );
- break;
- }
- case Qt::Key_Q:
- {
- exit( EXIT_SUCCESS );
- break;
- }
- case Qt::Key_R:
- {
- this->reset();
- break;
- }
- case Qt::Key_Up:
- {
- this->setSliceNumber( d->SliceNumber+1 );
- break;
- }
- case Qt::Key_Down:
- {
- this->setSliceNumber( d->SliceNumber-1 );
- break;
- }
- default:
- {
- event->ignore();
- }
- };
- }
- }
- // -------------------------------------------------------------------------
- void ctkQImageView::mousePressEvent( QMouseEvent * event )
- {
- Q_D( ctkQImageView );
- if( d->SliceNumber >= 0 && d->SliceNumber < d->ImageList.size() )
- {
- switch( event->button() )
- {
- case Qt::LeftButton:
- {
- d->MouseLeftDragging = true;
- d->MouseLastX = event->x();
- d->MouseLastY = event->y();
- d->MouseLastIntensityWindow = this->intensityWindow();
- d->MouseLastIntensityLevel = this->intensityLevel();
- break;
- }
- case Qt::MidButton:
- {
- d->MouseMiddleDragging = true;
- d->MouseLastX = event->x();
- d->MouseLastY = event->y();
- d->MouseLastZoom = this->zoom();
- break;
- }
- case Qt::RightButton:
- {
- d->MouseRightDragging = true;
- double relativeX = static_cast<double>( event->x() )
- / this->width();
- double relativeY = static_cast<double>( event->y() )
- / this->height();
- if( d->FlipXAxis )
- {
- relativeX = 1 - relativeX;
- }
- if( d->FlipYAxis )
- {
- relativeY = 1 - relativeY;
- }
- double x = (d->TmpXMax - d->TmpXMin) * relativeX + d->TmpXMin;
- double y = (d->TmpYMax - d->TmpYMin) * relativeY + d->TmpYMin;
- this->setCenter( x, y );
- break;
- }
- default:
- {
- event->ignore();
- }
- };
- }
- }
- // -------------------------------------------------------------------------
- void ctkQImageView::mouseReleaseEvent( QMouseEvent * event )
- {
- Q_D( ctkQImageView );
- d->MouseLeftDragging = false;
- d->MouseMiddleDragging = false;
- d->MouseRightDragging = false;
- event->ignore();
- }
- // -------------------------------------------------------------------------
- void ctkQImageView::mouseMoveEvent( QMouseEvent * event )
- {
- Q_D( ctkQImageView );
- if( d->SliceNumber >= 0 && d->SliceNumber < d->ImageList.size() )
- {
- if( d->MouseLeftDragging )
- {
- double distX = event->x() - d->MouseLastX;
- double distY = event->y() - d->MouseLastY;
- double deltaWin = ( distX / this->height() );
- if( deltaWin < 0 )
- {
- // Heuristic to make shrinking propotional to enlarging
- deltaWin *= -deltaWin;
- }
- double deltaLevel = ( distY / this->width() );
- if( deltaLevel < 0 )
- {
- // Heuristic to make shrinking propotional to enlarging
- deltaLevel *= -deltaLevel;
- }
- double iRange = d->IntensityMax - d->IntensityMin;
- deltaWin *= iRange;
- deltaLevel *= iRange;
- double newWin = d->MouseLastIntensityWindow + deltaWin;
- double newLevel = d->MouseLastIntensityLevel + deltaLevel;
- this->setIntensityWindowLevel( newWin, newLevel );
- }
- else if( d->MouseMiddleDragging )
- {
- double distY = d->MouseLastY - event->y();
- double deltaZ = 2 * (distY / this->height());
- if( deltaZ < 0 )
- {
- // Heuristic to make shrinking propotional to enlarging
- deltaZ *= -deltaZ;
- }
- double newZoom = d->MouseLastZoom + deltaZ;
- this->setZoom( newZoom );
- }
- else if( d->MouseRightDragging )
- {
- double relativeX = static_cast<double>( event->x() )
- / this->width();
- double relativeY = static_cast<double>( event->y() )
- / this->height();
- if( d->FlipXAxis )
- {
- relativeX = 1 - relativeX;
- }
- if( d->FlipYAxis )
- {
- relativeY = 1 - relativeY;
- }
- double x = (d->TmpXMax - d->TmpXMin) * relativeX + d->TmpXMin;
- double y = (d->TmpYMax - d->TmpYMin) * relativeY + d->TmpYMin;
- this->setCenter( x, y );
- }
- else
- {
- double relativeX = static_cast<double>( event->x() )
- / this->width();
- double relativeY = static_cast<double>( event->y() )
- / this->height();
- if( d->FlipXAxis )
- {
- relativeX = 1 - relativeX;
- }
- if( d->FlipYAxis )
- {
- relativeY = 1 - relativeY;
- }
- double x = (d->TmpXMax - d->TmpXMin) * relativeX + d->TmpXMin;
- double y = (d->TmpYMax - d->TmpYMin) * relativeY + d->TmpYMin;
- this->setPosition( x, y );
- }
- }
- }
- // -------------------------------------------------------------------------
- void ctkQImageView::enterEvent( QEvent * )
- {
- Q_D( ctkQImageView );
- QApplication::setOverrideCursor( QCursor(Qt::CrossCursor) );
- d->Window->grabKeyboard();
- }
- // -------------------------------------------------------------------------
- void ctkQImageView::leaveEvent( QEvent * )
- {
- Q_D( ctkQImageView );
- QApplication::restoreOverrideCursor();
- d->Window->releaseKeyboard();
- }
- // -------------------------------------------------------------------------
- void ctkQImageView::resizeEvent( QResizeEvent* event )
- {
- this->Superclass::resizeEvent( event );
- this->update( false, true );
- }
- // -------------------------------------------------------------------------
- void ctkQImageView::update( bool zoomChanged,
- bool sizeChanged )
- {
- Q_D( ctkQImageView );
- if( d->SliceNumber >= 0 && d->SliceNumber < d->ImageList.size() )
- {
- const QImage * img = & ( d->ImageList[ d->SliceNumber ] );
- if( zoomChanged || sizeChanged )
- {
- if( this->width() > 0 && this->height() > 0
- && d->TmpXMax > d->TmpXMin && d->TmpYMax > d->TmpYMin)
- {
- int tmpXRange = d->TmpXMax - d->TmpXMin;
- int tmpYRange = d->TmpYMax - d->TmpYMin;
- double tmpAspectRatio = static_cast<double>(tmpYRange) / tmpXRange;
- double screenAspectRatio = static_cast<double>(this->height())
- / this->width();
- if( screenAspectRatio > tmpAspectRatio )
- {
- int extraTmpYAbove = d->TmpYMin;
- int extraTmpYBelow = img->height() - d->TmpYMax;
- int extraTmpYNeeded = tmpXRange * screenAspectRatio
- - tmpYRange;
- int minExtra = extraTmpYAbove;
- if( extraTmpYBelow < minExtra )
- {
- minExtra = extraTmpYBelow;
- }
- if(2 * minExtra >= extraTmpYNeeded)
- {
- int minNeeded = extraTmpYNeeded / 2.0;
- int maxNeeded = extraTmpYNeeded - minNeeded;
- d->TmpYMin -= minNeeded;
- d->TmpYMax += maxNeeded;
- }
- else if(extraTmpYAbove + extraTmpYBelow >= extraTmpYNeeded)
- {
- if(extraTmpYAbove < extraTmpYBelow)
- {
- d->TmpYMin = 0;
- d->TmpYMax += extraTmpYNeeded - extraTmpYAbove;
- }
- else
- {
- d->TmpYMax = img->height();
- d->TmpYMin -= extraTmpYNeeded - extraTmpYBelow;
- }
- }
- else
- {
- d->TmpYMin = 0;
- d->TmpYMax = img->height();
- }
- d->TmpImage = QPixmap( this->width(),
- static_cast<unsigned int>(
- static_cast<double>(d->TmpYMax - d->TmpYMin)
- / (d->TmpXMax - d->TmpXMin)
- * this->width() + 0.5 ) );
- }
- else if(screenAspectRatio < tmpAspectRatio)
- {
- int extraTmpXLeft = d->TmpXMin;
- int extraTmpXRight = img->width() - d->TmpXMax;
- int extraTmpXNeeded = static_cast<double>(tmpYRange)
- / screenAspectRatio - tmpXRange;
- int minExtra = extraTmpXLeft;
- if( extraTmpXRight < minExtra )
- {
- minExtra = extraTmpXRight;
- }
- if(2 * minExtra >= extraTmpXNeeded)
- {
- int minNeeded = extraTmpXNeeded / 2.0;
- int maxNeeded = extraTmpXNeeded - minNeeded;
- d->TmpXMin -= minNeeded;
- d->TmpXMax += maxNeeded;
- }
- else if(extraTmpXLeft + extraTmpXRight >= extraTmpXNeeded)
- {
- if(extraTmpXLeft < extraTmpXRight)
- {
- d->TmpXMin = 0;
- d->TmpXMax += extraTmpXNeeded - extraTmpXLeft;
- }
- else
- {
- d->TmpXMax = img->width();
- d->TmpXMin -= extraTmpXNeeded - extraTmpXRight;
- }
- }
- else
- {
- d->TmpXMin = 0;
- d->TmpXMax = img->width();
- }
- d->TmpImage = QPixmap( static_cast<unsigned int>( this->height()
- / ( static_cast<double>(d->TmpYMax - d->TmpYMin)
- / (d->TmpXMax - d->TmpXMin) )
- + 0.5 ), this->height() );
- }
- else
- {
- d->TmpImage = QPixmap( this->width(), this->height() );
- }
- }
- }
- if( d->TmpImage.width() > 0 && d->TmpImage.height() > 0)
- {
- QRectF target( 0, 0, d->TmpImage.width(), d->TmpImage.height() );
- double sourceX = d->TmpXMin;
- double sourceY = d->TmpYMin;
- double sourceW = d->TmpXMax - d->TmpXMin;
- double sourceH = d->TmpYMax - d->TmpYMin;
- QPainter painter( &(d->TmpImage) );
- QImage tmpI = *img;
- if( d->InvertImage )
- {
- tmpI.invertPixels();
- }
- if( d->FlipXAxis || d->FlipYAxis )
- {
- tmpI = tmpI.mirrored( d->FlipXAxis, d->FlipYAxis );
- if( d->FlipXAxis )
- {
- sourceX = tmpI.width() - (d->TmpXMax - d->TmpXMin) - d->TmpXMin;
- }
- if( d->FlipYAxis )
- {
- sourceY = tmpI.height() - (d->TmpYMax - d->TmpYMin) - d->TmpYMin;
- }
- }
- QRectF source( sourceX, sourceY, sourceW, sourceH );
- painter.drawPixmap( target, QPixmap::fromImage( tmpI ), source );
- //if( ! sizeChanged )
- {
- int maxNumCharsPerLine = 50;
- int fontPointSize = 12;
- if( fontPointSize * maxNumCharsPerLine > this->width() )
- {
- fontPointSize = this->width() / maxNumCharsPerLine;
- }
- if( fontPointSize > 7 )
- {
- QString fontFamily( "Helvetica" );
- QFont textFont( fontFamily, fontPointSize );
- painter.setFont( textFont );
- QColor textColor;
- textColor.setNamedColor( "lime" );
- textColor.setAlpha( 128 );
- painter.setPen( textColor );
-
- int textFlags = Qt::AlignLeft | Qt::TextDontClip;
-
- QRectF pointRect( 0, 0, 1, 1 );
- QRectF spaceBound = painter.boundingRect( pointRect, textFlags,
- "X" );
-
- if( img->isGrayscale() )
- {
- QString intString = "Intensity Range = ";
- intString.append( QString::number( d->IntensityMin,
- 'f', 3 ) );
- intString.append( " - " );
- intString.append( QString::number( d->IntensityMax,
- 'f', 3 ) );
- QRectF intBound = painter.boundingRect( pointRect, textFlags,
- intString );
- QRectF intRect(
- spaceBound.width()/2,
- spaceBound.height()/8,
- intBound.width(), intBound.height() );
- painter.drawText( intRect, textFlags, intString,
- &intBound );
- QString wlString = "W / L = ";
- wlString.append( QString::number( this->intensityWindow(),
- 'f', 3 ) );
- wlString.append( " / " );
- wlString.append( QString::number( this->intensityLevel(),
- 'f', 3 ) );
- QRectF wlBound = painter.boundingRect( pointRect, textFlags,
- wlString );
- QRectF wlRect(
- spaceBound.width()/2,
- intRect.y() + intRect.height() + spaceBound.height()/8,
- wlBound.width(), wlBound.height() );
- painter.drawText( wlRect, textFlags, wlString,
- &wlBound );
- }
- QString spacingString = "Spacing = ";
- spacingString.append( QString::number( this->xSpacing(),
- 'f', 3 ) );
- spacingString.append( ", " );
- spacingString.append( QString::number( this->ySpacing(),
- 'f', 3 ) );
- spacingString.append( ", " );
- spacingString.append( QString::number( this->sliceThickness(),
- 'f', 3 ) );
- QRectF spacingBound = painter.boundingRect( pointRect, textFlags,
- spacingString );
- QRectF spacingRect(
- this->width() - spacingBound.width() - spaceBound.width()/2,
- this->height() - spacingBound.height() - spaceBound.height()/8,
- spacingBound.width(), spacingBound.height() );
- painter.drawText( spacingRect, textFlags, spacingString,
- &spacingBound );
-
- QString dimString = "Size = ";
- dimString.append(
- QString::number( d->ImageList[ d->SliceNumber ].width() ) );
- dimString.append( ", " );
- dimString.append(
- QString::number( d->ImageList[ d->SliceNumber ].height() ) );
- dimString.append( ", " );
- dimString.append(
- QString::number( d->ImageList.size() ) );
- QRectF dimBound = painter.boundingRect( pointRect, textFlags,
- dimString );
- QRectF dimRect(
- this->width() - dimBound.width() - spaceBound.width()/2,
- spacingBound.y() - dimBound.height() - spaceBound.height()/8,
- dimBound.width(), dimBound.height() );
- painter.drawText( dimRect, textFlags, dimString, &dimBound );
-
- QString rasString = "RAS = ";
- rasString.append( QString::number(
- this->xPosition() * this->xSpacing(), 'f', 3 ) );
- rasString.append( ", " );
- rasString.append( QString::number(
- this->yPosition() * this->ySpacing(), 'f', 3 ) );
- rasString.append( ", " );
- rasString.append( QString::number(
- this->slicePosition() * this->sliceSpacing(), 'f', 3 ) );
- QRectF rasBound = painter.boundingRect( pointRect, textFlags,
- rasString );
- QRectF rasRect(
- spaceBound.width()/2,
- this->height() - rasBound.height() - spaceBound.height()/8,
- rasBound.width(), rasBound.height() );
- painter.drawText( rasRect, textFlags, rasString,
- &rasBound );
-
- QString ijkString = "IJK = ";
- ijkString.append( QString::number( this->xPosition() ) );
- ijkString.append( ", " );
- ijkString.append( QString::number( this->yPosition() ) );
- ijkString.append( ", " );
- ijkString.append( QString::number( this->slicePosition() ) );
- QRectF ijkBound = painter.boundingRect( pointRect, textFlags,
- ijkString );
- QRectF ijkRect(
- spaceBound.width()/2,
- rasBound.y() - ijkBound.height() - spaceBound.height()/8,
- ijkBound.width(), ijkBound.height() );
- painter.drawText( ijkRect, textFlags, ijkString, &ijkBound );
-
- QString valString = "Value = ";
- valString.append( QString::number( this->positionValue(),
- 'f', 3 ) );
- QRectF valBound = painter.boundingRect( pointRect, textFlags,
- valString );
- QRectF valRect(
- spaceBound.width()/2,
- ijkBound.y() - valBound.height() - spaceBound.height()/8,
- valBound.width(), valBound.height() );
- painter.drawText( valRect, textFlags, valString, &valBound );
- }
-
- QColor lineColor;
- lineColor.setNamedColor( "red" );
- lineColor.setAlpha( 128 );
- painter.setPen( lineColor );
- double x = ( this->xPosition() - d->TmpXMin )
- / (d->TmpXMax - d->TmpXMin) * this->width();
- double y = ( this->yPosition() - d->TmpYMin )
- / (d->TmpYMax - d->TmpYMin) * this->height();
- if( d->FlipXAxis )
- {
- x = this->width() - x;
- }
- if( d->FlipYAxis )
- {
- y = this->height() - y;
- }
- QLine lineX( x, 0, x, this->height() );
- painter.drawLine( lineX );
- QLine lineY( 0, y, this->width(), y );
- painter.drawLine( lineY );
- }
- }
- d->Window->setPixmap( d->TmpImage );
- }
- else
- {
- d->Window->setText( "No Image Loaded." );
- }
- }
|