arbeit
Main Page | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Namespace Members | Compound Members | File Members

SlicerWidget.cpp

Go to the documentation of this file.
00001 //------------------------------------------------------------------------
00002 //
00003 //   Joe Kniss
00004 //     6-20-03
00005 //                   ________    ____   ___ 
00006 //                  |        \  /    | /  /
00007 //                  +---+     \/     |/  /
00008 //                  +--+|  |\    /|     < 
00009 //                  |  ||  | \  / |  |\  \ 
00010 //                  |      |  \/  |  | \  \ 
00011 //                   \_____|      |__|  \__\
00012 //                       Copyright  2003 
00013 //                      Joe Michael Kniss
00014 //                   <<< jmk@cs.utah.edu >>>
00015 //               "All Your Base are Belong to Us"
00016 //-------------------------------------------------------------------------
00017 
00018 /// SlicerWidget.h
00019 ///  simianUI
00020 
00021 #include <qmainwindow.h>
00022 #include <qpopupmenu.h>
00023 #include "SlicerWidget.h"
00024 #include "SlicerBase.h"
00025 #include <qlayout.h>
00026 #include <iostream>
00027 #include <image/NrroImage.h>
00028 #include <mathGutz.h>
00029 #include <nrro/nrroUtil.h>
00030 
00031 using namespace std;
00032 using namespace gutz;
00033 
00034 //////////////////////////////////////////////////////////////////////////
00035 /// construction
00036 //////////////////////////////////////////////////////////////////////////
00037 SlicerWidget::SlicerWidget(QWidget *parent, char *name, WFlags f)
00038 :QWidget(parent,name,f), 
00039  _sliceCanvas(0), 
00040  _sliceView(0),
00041  _slider(0),
00042  _number(0),
00043  _sliceImage(0),
00044  _axisCombo(0),
00045  _curAxis(X_AXIS),
00046  _curSlice(0),
00047  _vol(0),
00048  _filter(BoxKernel)
00049 {
00050    _sliceCanvas = new QCanvas(200,200);
00051    _sliceCanvas->setDoubleBuffering(true);
00052    _sliceCanvas->setBackgroundColor(QColor(0,0,0));
00053 
00054    _sliceView = new SliceView(_sliceCanvas,this,"slice canvas");
00055    _sliceView->setVScrollBarMode(QScrollView::AlwaysOff);
00056    _sliceView->setHScrollBarMode(QScrollView::AlwaysOff);
00057 
00058    _slider = new QSlider(Qt::Horizontal,this,"slice number slider");
00059 
00060    _axisCombo = new QComboBox(FALSE, this, "axis chooser");
00061 
00062    /// slice image created on the canvas!!!
00063    _sliceImage = new NrroCanvasImg(_sliceCanvas);
00064    _sliceImage->show();
00065 
00066    conf();
00067 }
00068 
00069 //////////////////////////////////////////////////////////////////////////
00070 /// destruction
00071 //////////////////////////////////////////////////////////////////////////
00072 SlicerWidget::~SlicerWidget()
00073 {
00074    if(_sliceCanvas) delete _sliceCanvas;
00075    if(_sliceView) delete _sliceView;
00076    if(_slider) delete _slider;
00077    if(_axisCombo) delete _axisCombo;
00078    if(_sliceImage) delete _sliceImage;
00079 }
00080 
00081 //////////////////////////////////////////////////////////////////////////
00082 //////////////////////////////////////////////////////////////////////////
00083 /// Slots
00084 //////////////////////////////////////////////////////////////////////////
00085 //////////////////////////////////////////////////////////////////////////
00086 
00087 void SlicerWidget::resizeEvent(QResizeEvent *re)
00088 {
00089    _sliceCanvas->resize(re->size().width(), re->size().height());
00090    /// update the image
00091    setSlice(_curSlice);
00092    _sliceCanvas->setAllChanged();
00093    _sliceCanvas->update();
00094    update();
00095 }
00096 
00097 
00098 //////////////////////////////////////////////////////////////////////////
00099 /// Set Volume
00100 //////////////////////////////////////////////////////////////////////////
00101 void SlicerWidget::setVolume(VolumeSP vol)
00102 {
00103    if(vol.isNull()) 
00104    {
00105       cerr << typeid(*this).name() 
00106          << "::setVolume(), attempting to set a null volume" << endl;
00107       return;
00108    }
00109    _vol = vol;
00110    setAxis(_curAxis);
00111    setSlice(_curSlice);
00112 }
00113 
00114 //////////////////////////////////////////////////////////////////////////
00115 /// Set Axis
00116 //////////////////////////////////////////////////////////////////////////
00117 void SlicerWidget::setAxis(int axisId)
00118 {
00119 
00120    if((X_AXIS != axisId)&&(Y_AXIS !=axisId)&&(Z_AXIS != axisId))
00121    {
00122       cerr << typeid(*this).name()
00123          << "::setAxis(), invalid axis id" << endl;
00124       return;
00125    }
00126    _curAxis = axisId;
00127 
00128    /// check if we have any setup
00129    if(_vol.isNull()) return;
00130 
00131    /// figure out what to do with the new axis
00132    /// first update the combo box
00133    _axisCombo->setCurrentItem(_curAxis);
00134 
00135    /// some error checking
00136    if(_vol->fields.getField(0) && _vol->fields.getField(0)->getNrro().isNull())
00137       return; 
00138 
00139    /// handle various volume configs, 3D or multi-channel 4D
00140    NrroSP n = _vol->fields.getField(0)->getNrro();
00141    int l = 0;
00142    if(_curAxis == X_AXIS)
00143    {
00144       if(n->dim() == 3)
00145       {
00146          l = n->dim(0)-1;
00147       }
00148       else
00149       {
00150          l = n->dim(1)-1;
00151       }
00152    }
00153    if(_curAxis == Y_AXIS)
00154    {
00155       if(n->dim() == 3)
00156       {
00157          l = n->dim(1)-1;
00158       }
00159       else
00160       {
00161          l = n->dim(2)-1;
00162       }
00163    }
00164    if(_curAxis == Z_AXIS)
00165    {
00166       if(n->dim() == 3)
00167       {
00168          l = n->dim(2)-1;
00169       }
00170       else
00171       {
00172          l = n->dim(3)-1;
00173       }
00174    }
00175 
00176    /// set the max value of the slider to the correct axis size
00177    _slider->setMaxValue(l);
00178    /// update the slice to reflect new axis
00179    setSlice(_curSlice);
00180 }
00181 
00182 //////////////////////////////////////////////////////////////////////////
00183 /// Set Slice
00184 //////////////////////////////////////////////////////////////////////////
00185 void SlicerWidget::setSlice(int slicePos)
00186 {
00187    if(_vol.isNull())
00188    {
00189       cerr << typeid(*this).name()
00190          << "::setSlice(), null volume" << endl;
00191       return;
00192    }
00193 
00194    /// no fields
00195    if(_vol->fields.size() == 0)
00196    {
00197       return;
00198    }
00199    
00200    NrroSP field = _vol->fields.getField(0)->getNrro();
00201    if(field.isNull())
00202    {
00203       cerr << typeid(*this).name()
00204          << "::setSlice(), null nrro field" << endl;
00205       return;
00206    }
00207 
00208    _curSlice = clamp(0,slicePos,_slider->maxValue());
00209 
00210    /// respect scalar and multi-channel volumes
00211    int inc = 0;
00212    if(field->dim() == 4) inc = 1;
00213 
00214    /// slice the data
00215    NrroSP slice = field->slice(_curAxis+inc,_curSlice);
00216    slice->setKind(Nrro::IMAGE);
00217    
00218    /// size of image we need, exactly the size of the viewport
00219    vec2i vsize(_sliceView->getWidth(), 
00220                _sliceView->getHeight());
00221 
00222    /// relative dimensions, min & max (0-1) base
00223    /// these depend on the aspect ratio and 
00224    /// position of the viewport relative to the image
00225    vec2f vmin(_sliceView->getPos());
00226    vec2f vmax = vmin + _sliceView->getAspect() * _sliceView->getZoom();
00227    _sliceImage->setNrro(reshapeNrroImageA(slice,vsize,vmin,vmax,_filter),field->getMinMax());
00228 
00229    _sliceCanvas->setAllChanged();
00230    _sliceCanvas->update();
00231 
00232    _slider->setValue(_curSlice);
00233 }
00234 
00235 //////////////////////////////////////////////////////////////////////////
00236 /// Set Field ....
00237 //////////////////////////////////////////////////////////////////////////
00238 void SlicerWidget::setFieldOn(int fieldNum)
00239 {
00240 
00241 }
00242 
00243 void SlicerWidget::setFieldOff(int fieldNum)
00244 {
00245 
00246 }
00247 
00248 //////////////////////////////////////////////////////////////////////////
00249 /// Set Pick Pos
00250 //////////////////////////////////////////////////////////////////////////
00251 void SlicerWidget::setPickPos(int xp, int yp)
00252 {
00253    /// volume voxel positions
00254    int vx, vy, vz;
00255 
00256    if(_vol.isNull()) return;
00257    /// get the nrro
00258    NrroSP n = _vol->fields.getField(0)->getNrro();
00259    if(n.isNull()) return;
00260 
00261    /// handle multi-channel volumes correctly
00262    int inc = 0;
00263    if(n->dim() == 4) inc = 1;
00264 
00265    /// view space to world space
00266    float tx = _sliceView->getPos().x 
00267       + xp*(_sliceView->getAspect().x * _sliceView->getZoom())/_sliceView->getWidth();
00268    float ty = _sliceView->getPos().y 
00269       + yp*(_sliceView->getAspect().y *  _sliceView->getZoom())/_sliceView->getHeight();
00270 
00271    cerr << "pos = " << _sliceView->getPos() << endl;
00272    cerr << "aspect = " << _sliceView->getAspect() << endl;;
00273    cerr << "zoom = " << _sliceView->getZoom() << endl;
00274    cerr << "tx, ty " << tx << " " << ty << endl;
00275 
00276    if(_curAxis == X_AXIS)
00277    {
00278       vec2f aspect(vec2f_one);
00279       if(n->axisSize(1+inc) > n->axisSize(2+inc))
00280          aspect.y = n->axisSize(1+inc)/float(n->axisSize(2+inc));
00281       else
00282          aspect.x = n->axisSize(2+inc)/float(n->axisSize(1+inc));
00283 
00284       vx = _curSlice;
00285       vy =  static_cast<int>(tx * aspect.x * n->dim(1 + inc));
00286       vz =  static_cast<int>(ty * aspect.y * n->dim(2 + inc));
00287    }
00288    else if(_curAxis == Y_AXIS)
00289    {
00290       vec2f aspect(vec2f_one);
00291       if(n->axisSize(0+inc) > n->axisSize(2+inc))
00292          aspect.y = n->axisSize(0+inc)/float(n->axisSize(2+inc));
00293       else
00294          aspect.x = n->axisSize(2+inc)/float(n->axisSize(0+inc));
00295       vx =  static_cast<int>(tx * aspect.x * n->dim(0 + inc));
00296       vy = _curSlice;
00297       vz =  static_cast<int>(ty * aspect.y * n->dim(2 + inc));
00298    }
00299    else if(_curAxis == Z_AXIS)
00300    {
00301       vec2f aspect(vec2f_one);
00302       if(n->axisSize(0+inc) > n->axisSize(1+inc))
00303          aspect.y = n->axisSize(0+inc)/float(n->axisSize(1+inc));
00304       else
00305          aspect.x = n->axisSize(1+inc)/float(n->axisSize(0+inc));
00306       vx =  static_cast<int>(tx * aspect.x * n->dim(0 + inc));
00307       vy =  static_cast<int>(ty * aspect.y * n->dim(1 + inc));
00308       vz = _curSlice;
00309    }
00310       
00311    volPickPosChanged(vx,vy,vz);
00312 }
00313 
00314 //////////////////////////////////////////////////////////////////////////
00315 /// Set Volume Pos
00316 //////////////////////////////////////////////////////////////////////////
00317 void SlicerWidget::setVolPos(int xp, int yp, int zp)
00318 {
00319    if(_curAxis == X_AXIS)
00320    {
00321       setSlice(xp);
00322    }
00323    else if(_curAxis == Y_AXIS)
00324    {
00325       setSlice(yp);
00326    }
00327    else if(_curAxis == Z_AXIS)
00328    {
00329       setSlice(zp);
00330    }
00331 }
00332 
00333 //////////////////////////////////////////////////////////////////////////
00334 /// Set Filter
00335 //////////////////////////////////////////////////////////////////////////
00336 void SlicerWidget::setFilter(int f)
00337 {
00338    switch(f){
00339       case SlicerBase::NEAREST:
00340          _filter = BoxKernel;
00341          break;
00342       case SlicerBase::BILIN:
00343          _filter = TentKernel;
00344          break;
00345       case SlicerBase::BICUBE:
00346          _filter = CatmulRomKernel;
00347          break;
00348       case SlicerBase::BSPLINE:
00349          _filter = BSplineKernel;
00350          break;
00351       default:
00352          cerr << "SlicerWidget::setFilter(), unknown filter" << endl;
00353    };
00354 
00355    setSlice(_curSlice);
00356 }
00357 
00358 //////////////////////////////////////////////////////////////////////////
00359 //////////////////////////////////////////////////////////////////////////
00360 /// Protected Members
00361 //////////////////////////////////////////////////////////////////////////
00362 //////////////////////////////////////////////////////////////////////////
00363 
00364 //////////////////////////////////////////////////////////////////////////
00365 /// configure
00366 //////////////////////////////////////////////////////////////////////////
00367 void SlicerWidget::conf()
00368 {
00369    // Create a layout to position the widgets
00370    QHBoxLayout *topLayout = new QHBoxLayout( this, 5 );
00371 
00372    // Create a grid layout the slice view with relation
00373    // to the slider...
00374    // 2 rows, 1 column
00375    QGridLayout *grid = new QGridLayout(topLayout, 2,1);
00376 
00377    /// top widget
00378    grid->addWidget(_sliceView,0,0);
00379    /// connect the slice view to us
00380    connect(_sliceView,SIGNAL(pickPosChanged(int,int)), SLOT(setPickPos(int,int)));
00381 
00382    /// bottom widget
00383    // Create a grid layout for the slider and slice number
00384    // 2 rows, 2 columns
00385    QGridLayout *sliderGrid = new QGridLayout(grid,2,2);
00386 
00387    /// slice slider
00388    sliderGrid->addWidget(_slider,0,0);
00389    _slider->setValue(_curSlice);
00390    connect(_slider,SIGNAL(valueChanged(int)),SLOT(setSlice(int)));
00391 
00392    /// slice number
00393    QLCDNumber *num = new QLCDNumber(3,this,"slice number");
00394    num->setSegmentStyle(QLCDNumber::Flat);
00395    num->connect(_slider, SIGNAL(valueChanged(int)),SLOT(display(int)));
00396    sliderGrid->addWidget(num,0,1);
00397 
00398    /// axis combo box
00399    sliderGrid->addWidget(_axisCombo,1,0);
00400    _axisCombo->insertItem("X axis", X_AXIS);
00401    _axisCombo->insertItem("Y axis", Y_AXIS);
00402    _axisCombo->insertItem("Z axis", Z_AXIS);
00403    _axisCombo->setCurrentItem(_curAxis);
00404    connect(_axisCombo,SIGNAL(activated(int)),SLOT(setAxis(int)));
00405 
00406 }
00407 
00408 

Send questions, comments, and bug reports to:
jmk