Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

vuCellProjector.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002                           vuCellProjector.cpp  -  description
00003                              -------------------
00004     begin                : Thu May 1 2003
00005     copyright            : (C) 2003 by tmeng
00006     email                : tmeng@sfu.ca
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU General Public License as published by  *
00013  *   the Free Software Foundation; either version 2 of the License, or     *
00014  *   (at your option) any later version.                                   *
00015  *                                                                         *
00016  ***************************************************************************/
00017 
00018 #include "vuCellProjector.h"
00019 #include "../../wxUIElements/vuGLCanvas.h"
00020 #include "../../wxUIElements/vuTFDialogSpec.h"
00021 #include "vuColourRGBa.h"
00022 
00023 //----------------------------------------------------------------------------
00024 
00025 enum IDEnum //for the event table and wx controls initilization.
00026 {
00027   idCheckBoxIsSort,
00028   idListBoxSubdivScheme,
00029   idButtonRender
00030 };
00031 
00032 //----------------------------------------------------------------------------
00033 //----------------- The vuCellProjector event table --------------------------
00034 //----------------------------------------------------------------------------
00035 
00036 //Message map, very similar to MFC.
00037 BEGIN_EVENT_TABLE(vuCellProjector, vuBasicUtility)
00038   EVT_CHECKBOX(idCheckBoxIsSort, vuCellProjector::onCheckBoxIsSort)
00039   EVT_LISTBOX(idListBoxSubdivScheme, vuCellProjector::onListBoxSubdivScheme)
00040   EVT_BUTTON(idButtonRender, vuCellProjector::onButtonRender)
00041 END_EVENT_TABLE();
00042 
00043 //----------------------------------------------------------------------------
00044 //------------------------- The constructor ----------------------------------
00045 //----------------------------------------------------------------------------
00046 
00047 vuCellProjector::vuCellProjector() 
00048   : vuBasicUtility(), 
00049     m_Data(new vu111211a), //default cell projector.
00050     m_ViewScale(1.0f), //Default zooming is 100%
00051     m_TFunc(4), //4 means RGBA (4 channels)
00052     m_TFDialog(this, m_TFunc), //construct transfer function dialog.
00053     m_x(0), m_y(0) //sensible values before actual mouse clicks.
00054 {
00055 }
00056 
00057 //----------------------------------------------------------------------------
00058 //------------------------- The destructor -----------------------------------
00059 //----------------------------------------------------------------------------
00060 
00061 /*virtual*/ vuCellProjector::~vuCellProjector()
00062 {
00063   if (m_Data != 0) delete m_Data;
00064 }
00065 
00066 //----------------------------------------------------------------------------
00067 //------------------------- public: getFileType() ----------------------------
00068 //----------------------------------------------------------------------------
00069 
00070 /*static*/ const char* vuCellProjector::getFileType()
00071 {
00072   return "11121";
00073 }
00074 
00075 //----------------------------------------------------------------------------
00076 //------------------------- public: addRight() -------------------------------
00077 //----------------------------------------------------------------------------
00078 
00079 
00080 /*virtual*/ void vuCellProjector::addRight(wxSizer* sizer)
00081 {
00082   //top alignment by default.
00083   addCheckBoxIsSort(sizer);
00084   addListBoxSubdivScheme(sizer);
00085   addButtonRender(sizer);
00086 }
00087 
00088 //----------------------------------------------------------------------------
00089 //------------------------- public: init() -----------------------------------
00090 //----------------------------------------------------------------------------
00091 
00092 /*virtual*/ bool vuCellProjector::init(const char* DataFile)
00093   //Initializes the cellProjector utility.
00094   //Initializes the utility window.  A cellProjector object is created and
00095   //the volume data is read.  The window appears when finished.
00096 {
00097   //Set up the window for the cellProjectorter.
00098   SetTitle("vuCellProjector");
00099   CreateStatusBar(); //shows render time.
00100     
00101   //Create a volume data instance.
00102   //  m_Data = new vu111211a; //allocate space for a cell projector.
00103   m_Data->setFileName(DataFile); //will project the volume data in the specified file.
00104 
00105   //see readme.txt within vuVolume/TFunc for more info
00106   m_TFunc.loadTF("TFunc/default.tf");
00107   m_TFunc.setOpacitySmoothing(0);
00108   m_TFunc.setColourSmoothing(1);
00109   m_TFunc.generateFunction();
00110   m_Data->setTransferFunc(m_TFunc); 
00111   //the CellProjector (not the utility window) now has a transfer function.
00112 
00113   //Read in the data.
00114   bool success = m_Data->read();
00115   if (success)
00116     {
00117       m_glCanvas->SetSize(512,512); //default utility size.
00118       Fit(); //likely a wxWindows command.
00119     }
00120   else
00121     {
00122       //Show the error message.
00123       wxMessageDialog dlg(this, m_Data->getErrorMessage(), "vuCellProjector",wxOK);
00124       dlg.ShowModal();
00125     }
00126   
00127   //Not sure if false should be returned anywhere, since as I recall in MFC
00128   //false is never returned in init() either. So may have to look back to this later.
00129   return success; //initialization successful.
00130 };
00131 
00132 //----------------------------------------------------------------------------
00133 //------------------------- public: notifyDataChanged() ----------------------
00134 //----------------------------------------------------------------------------
00135 
00136 /*virtual*/ void vuCellProjector::notifyDataChanged()
00137   //Acts kind of like Invalidate() in MFC, which does a redraw.
00138 {
00139   m_glCanvas->redraw();
00140 }
00141 
00142 //----------------------------------------------------------------------------
00143 //------------------------- public: DrawAgain() ------------------------------
00144 //----------------------------------------------------------------------------
00145 
00146 /*virtual*/ void vuCellProjector::DrawAgain()
00147   //Rerenders the screen from the current camera position.
00148 {
00149   m_glCanvas->redraw();
00150 }
00151 
00152 //----------------------------------------------------------------------------
00153 //------------------------- public: DrawFromImage() --------------------------
00154 //----------------------------------------------------------------------------
00155 
00156 /*virtual*/ void vuCellProjector::DrawFromImage()
00157   //Draws on the screen the image contained in the image buffer.
00158   //Basically, it's a flush() function.
00159 {
00160   m_Data->drawPic();
00161 }
00162 
00163 //----------------------------------------------------------------------------
00164 //------------------------- public: getCurrentImage() ------------------------
00165 //----------------------------------------------------------------------------
00166 
00167 /*virtual*/ vuImage* vuCellProjector::getCurrentImage()
00168   //This will return a pointer to the image buffer.
00169 {
00170   return m_Data->getBuffer ();
00171 }
00172 
00173 //----------------------------------------------------------------------------
00174 //------------------------- public: getCamera() ------------------------------
00175 //----------------------------------------------------------------------------
00176 
00177 /*virtual*/ vuCamera* vuCellProjector::getCamera()
00178   //This will return a pointer to the camera that this class is using
00179   //(note that this may be derived from vuCamera...) 
00180 {
00181   return &m_Camera;
00182 }
00183 
00184 //----------------------------------------------------------------------------
00185 //------------------------- public: IsReRendering() --------------------------
00186 //----------------------------------------------------------------------------
00187 
00188 /*virtual*/ bool vuCellProjector::IsReRendering()
00189   //This will return whether or not the cellProjector is rerendering to the screen.
00190 {
00191   return m_Data->IsReRendering ();
00192 }
00193 
00194 //----------------------------------------------------------------------------
00195 //------------------------- public: setIsReRendering() -----------------------
00196 //----------------------------------------------------------------------------
00197 
00198 /*virtual*/ void vuCellProjector::setIsReRendering (bool isit)
00199   //This will set the state of rerendering to be the same as "isit". 
00200 {
00201   m_Data->setIsReRendering(isit);
00202 }
00203 
00204 //----------------------------------------------------------------------------
00205 //------------------------- protected: glInit() ------------------------------
00206 //----------------------------------------------------------------------------
00207 
00208 /*virtual*/ bool vuCellProjector::glInit()   
00209   //Initializes openGL for the cellProjector utility.
00210   //The method calls the CellProjector initGL() method so it can do the
00211   //proper initialization.
00212 {
00213   if (m_Data == 0) return false;
00214     
00215   //Paint a black background to the utility window.
00216   const GLfloat RED = 0.0f;
00217   const GLfloat GREEN = 0.0f;
00218   const GLfloat BLUE = 0.0f;
00219   const GLfloat ALPHA = 1.0f;
00220   glClearColor(RED, GREEN, BLUE, ALPHA);
00221     
00222   //Enable one light for now.
00223   glEnable(GL_LIGHTING);
00224   glEnable(GL_LIGHT0);
00225 
00226   //Enable lighting calculation for backfaces as well.
00227   glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
00228     
00229   //Call CellProjector::initGL() which does initilization particular
00230   //to the CellProjector algorithm.
00231   m_Data->initOpenGL();
00232   return true;
00233 };
00234 
00235 //----------------------------------------------------------------------------
00236 //------------------------- protected: glRender() ----------------------------
00237 //----------------------------------------------------------------------------
00238 
00239 /*virtual*/ void vuCellProjector::glRender()
00240 {
00241   wxStopWatch watch; //used to time how long it takes to render each frame.
00242   watch.Start();
00243 
00244   //Clears the color buffer.
00245   glClear(GL_COLOR_BUFFER_BIT);
00246 
00247   glMatrixMode(GL_MODELVIEW);
00248   glLoadIdentity();
00249 
00250   m_Camera.gluLookAt(); //applied to the model view matrix.
00251 
00252   glTranslatef((float)m_Data->getDim1Size()/(-2.0f),
00253                (float)m_Data->getDim2Size()/(-2.0f),
00254                (float)m_Data->getDim3Size()/(-2.0f));
00255   
00256   m_Data->setViewVectors(m_Camera.getLookAtVector(),
00257                          m_Camera.getUpVector(),
00258                          m_Camera.getRightVector());
00259   
00260   //This is not necessary every frame, but done anyways,
00261   //because the non-modal tfuncDlg might have changed it.
00262   //The overhead is negligible so it's ok to keep.
00263   m_Data->setTransferFunc(m_TFunc);
00264     
00265   //Render the volume.
00266   m_Data->render();
00267 
00268   //print out the time it took to render the frame onto the status bar.  
00269   watch.Pause();
00270   SetStatusText(wxString("Render Time: ") + vuString(watch.Time()).c_str() + "ms");
00271 };
00272 
00273 //----------------------------------------------------------------------------
00274 //------------------------- protected: glResize() ----------------------------
00275 //----------------------------------------------------------------------------
00276 
00277 /*virtual*/ void vuCellProjector::glResize()
00278 {
00279   //Retrieves the new width and height of the window from the window itself.
00280   GLint newWidth = (GLint)m_glCanvas->getWidth();
00281   GLint newHeight = (GLint)m_glCanvas->getHeight();
00282 
00283   //Calculate an aspect ratio.
00284   GLfloat aspect_ratio = ((float) newWidth) / ((float) newHeight);
00285 
00286   //Set the viewport(left, bottom, width, height).
00287   glViewport(0, 0, newWidth, newHeight);
00288     
00289   //Find the largest dimension of the data, so it fits inside the window.
00290   dword max = m_Data->getDim1Size();
00291   if (m_Data->getDim2Size() > max)
00292     max = m_Data->getDim2Size();
00293   if (m_Data->getDim3Size() > max)
00294     max = m_Data->getDim3Size();
00295 
00296   //Switch the openGL projection matrix, required before calling glOrtho.
00297   glMatrixMode(GL_PROJECTION);
00298   glLoadIdentity(); //reset the projection matrix.
00299 
00300   //The following if/else loop gets rid of the horizontal or vertical
00301   //distortions associated with stretching the window.
00302   if(newHeight >= newWidth)
00303     //This means aspect_ratio <= 1.0
00304     //Output image stretched along y direction, so need to divide top and 
00305     //bottom by aspect_ratio (i.e. need more "slots" in the y direction to
00306     //not distort image)
00307     {
00308       //Sets up orthographic projection matrix and defines a viewing volume
00309       //that is a right parallelepiped.
00310       //glOrtho(left, right, bottom, top, near, far)
00311       glOrtho((float)max/(-1.0f*m_ViewScale), 
00312               (float)max/m_ViewScale,
00313               (float)max/aspect_ratio/(-1.0f*m_ViewScale), 
00314               (float)max/aspect_ratio/m_ViewScale,
00315               10000.0f, -10000.0f); 
00316       //10000 SHOULD be large enough, data sets that are larger
00317       //probably can't be rendered in available memory anyway.
00318     }
00319   else
00320     //This means aspect_ratio > 1.0
00321     //Output image stretched along x direction, so need to divide left and 
00322     //right by aspect_ratio (i.e. need more "slots" in the x direction to
00323     //not distort image)
00324     {
00325       glOrtho((float)max*aspect_ratio/(-1.0f*m_ViewScale), 
00326               (float)max*aspect_ratio/m_ViewScale,
00327               (float)max/(-1.0f*m_ViewScale), 
00328               (float)max/m_ViewScale,
00329               10000.0f, -10000.0f);
00330 
00331     }
00332     
00333   //Return to the model view matrix (for manipulating objects).
00334   glMatrixMode(GL_MODELVIEW);
00335   glLoadIdentity(); //this line probably can be removed.
00336   
00337   //Set the opengl light info.
00338   //float lpos[4] = {0.0, 0.0, 1024.0, 1.0};
00339   //glLightfv(GL_LIGHT0, GL_POSITION, lpos);
00340 }
00341 
00342 //----------------------------------------------------------------------------
00343 //------------------------- protected: onMouse() -----------------------------
00344 //----------------------------------------------------------------------------
00345 
00346 /*virtual*/ void vuCellProjector::glOnMouse(wxMouseEvent &ev)
00347   //Eventually, this could extend vuBasicUtility::glOnMouse(event).
00348   //For now, I have followed what everyone else has done.
00349 {
00350   //vuBasicUtility::glOnMouse(ev); 
00351   //extend the parent function, which deals with rotation and zooming
00352   //already. 
00353 
00354   if (ev.LeftDown() || ev.RightDown())
00355     {
00356       //Store the click position.
00357       m_x = (int) ev.GetX();
00358       m_y = (int) ev.GetY();
00359     }
00360   else if (ev.LeftIsDown() && ev.Moving())
00361     //Rotate the camera (same as rotating the volume)
00362     { 
00363       //get the camera location.
00364       vuVector t = m_Camera.getPosition();
00365       
00366       //get distance from camera to origin. Same as d = (t-origin).norm()
00367       float d = t.norm(); 
00368 
00369       m_Camera.translateXYZ(0.0f, 0.0f, d);
00370       m_Camera.rotateAboutUp(ev.GetX() - m_x);
00371       m_Camera.rotateAboutRight(ev.GetY() - m_y);
00372       m_Camera.translateXYZ(0.0f, 0.0f, -d);
00373       m_glCanvas->redraw();
00374 
00375       //Store the click position.
00376       m_x = (int) ev.GetX();
00377       m_y = (int) ev.GetY();
00378     }
00379   else if (ev.RightIsDown() && ev.Moving())
00380     //Zooming.
00381     {
00382       m_ViewScale -= ((float)ev.GetY() - m_y)/500.0f;
00383       this->glResize();
00384       m_glCanvas->redraw();
00385 
00386       //Store the click position.
00387       m_x = (int) ev.GetX();
00388       m_y = (int) ev.GetY();
00389     }
00390   else if (ev.LeftDClick())
00391     //Pop up the transfer function editor.
00392     {
00393       m_TFDialog.Show(true);
00394     }
00395 }
00396 
00397 //----------------------------------------------------------------------------
00398 //------------------------- protected: getVolume() ---------------------------
00399 //----------------------------------------------------------------------------
00400 
00401 /*virtual*/ vu1* vuCellProjector::getVolume()
00402   // Returns a parent pointer to the current algorithm.
00403 {
00404   return m_Data; 
00405   //m_Data is a pointer to the current algorithm, and vu1* is a parent
00406   //pointer so the upcasting is auto.
00407 }
00408 
00409 //----------------------------------------------------------------------------
00410 //------------------------- protected: OnChar() ------------------------------
00411 //----------------------------------------------------------------------------
00412 
00413 /*virtual*/ void vuCellProjector::OnChar(wxKeyEvent& event)
00414 {
00415   //vuBasicUtility::OnChar(event); //chain to parent.
00416   //the above function does not work right now, CellProjector has both
00417   //getVolume() and getCameraPtr() but does not work, not quite sure why.
00418   //should look into it later.
00419 
00420   dword dataSize = m_Data->m_DataSize;
00421   char key = event.GetKeyCode();
00422   if (dataSize == 8) 
00423     //Possibly enable manual display of tets.
00424     {
00425       switch(key)
00426         {
00427         case 'm': //manual tet enable
00428           m_Data->m_state = MANUAL_TET;
00429           break;
00430         case 'n': //normal (default)
00431           m_Data->m_state = NORMAL;
00432           break;
00433         };
00434       if (key >= '0' && key <= '9')
00435         //if 8 data points, then only tets avail for display.
00436         //if 12 data points, 10 tets avail for display
00437         {
00438           m_Data->m_tetIndex = key - '0';
00439           //the above line has been tested with cout statements
00440           if (m_Data->m_subdivScheme == SIX_FOLD && m_Data->m_tetIndex > 5)
00441             {
00442               m_Data->m_tetIndex = 5; //clamp, else out of bound index.
00443               cout<<"tet index: "<<m_Data->m_tetIndex<<endl;
00444             }
00445         }
00446     }
00447   //the following line seems to call glRender() from somewhere
00448   //already so no need to call glRender() again.
00449   this->DrawAgain(); //or this->notifyDataChanged();
00450 }
00451 
00452 //----------------------------------------------------------------------------
00453 //--------------- protected: onCheckBoxIsSort() ------------------------------
00454 //----------------------------------------------------------------------------
00455 
00456 #if wxMINOR_VERSION < 5
00457 void vuCellProjector::onCheckBoxIsSort()
00458 #else
00459 void vuCellProjector::onCheckBoxIsSort(wxCommandEvent&)
00460 #endif
00461 {
00462   m_Data->m_isSort = (bool) m_checkBoxIsSort->GetValue();
00463   this->notifyDataChanged();
00464 }
00465 
00466 //----------------------------------------------------------------------------
00467 //--------------- protected: onListBoxSubdivScheme() -------------------------
00468 //----------------------------------------------------------------------------
00469 
00470 #if wxMINOR_VERSION < 5
00471 void vuCellProjector::onListBoxSubdivScheme()
00472 #else
00473 void vuCellProjector::onListBoxSubdivScheme(wxCommandEvent&)
00474 #endif
00475 {  
00476   m_Data->m_subdivScheme = (SubdivEnum) m_listBoxSubdivScheme->GetSelection();
00477   this->notifyDataChanged();
00478 }
00479 
00480 //----------------------------------------------------------------------------
00481 //--------------- protected: onButtonRender() --------------------------------
00482 //----------------------------------------------------------------------------
00483 
00484 #if wxMINOR_VERSION < 5
00485 void vuCellProjector::onButtonRender()
00486 #else
00487 void vuCellProjector::onButtonRender(wxCommandEvent&)
00488 #endif
00489 {
00490   m_Data->m_isRender = true;
00491   this->notifyDataChanged();
00492 }
00493 
00494 //----------------------------------------------------------------------------
00495 //--------------- protected: addCheckBoxIsSort() -----------------------------
00496 //----------------------------------------------------------------------------
00497 
00498 void vuCellProjector::addCheckBoxIsSort(wxSizer* sizer)
00499 {
00500   m_checkBoxIsSort = new wxCheckBox(this, //parent window pointer
00501                                     idCheckBoxIsSort, //unique control id
00502                                     "Sort and Triangulate?");
00503   m_checkBoxIsSort->SetValue(m_Data->m_isSort);
00504 
00505   //if no following line, the checkbox will show up at the top left hand
00506   //corner of the utility window.
00507   sizer->Add(m_checkBoxIsSort, //check box added to right panel (sizer)
00508              0, //not stretcheable
00509              wxALL | wxALIGN_LEFT, //wxALL->all 4 borders,
00510              1); //border width = 1
00511 }
00512 
00513 //----------------------------------------------------------------------------
00514 //--------------- protected: addListBoxSubdivScheme() ------------------------
00515 //----------------------------------------------------------------------------
00516 
00517 void vuCellProjector::addListBoxSubdivScheme(wxSizer* sizer)
00518 {
00519   char scheme1[] = "5-Fold";
00520   char scheme2[] = "6-Fold";
00521   wxString listBoxEntries[] = {scheme1, scheme2};
00522   m_listBoxSubdivScheme = 
00523     new wxListBox(this, //parent window pointer
00524                   idListBoxSubdivScheme, //unique id
00525                   wxDefaultPosition,
00526                   wxSize(150,70), //arbitrary, in pixels
00527                   2, //2 entries initially
00528                   listBoxEntries,
00529                   wxLB_SINGLE | wxLB_ALWAYS_SB); 
00530   //can only select one entry at once and always show vert scrolling bar.
00531 
00532   m_listBoxSubdivScheme->SetSelection((int)(m_Data->m_subdivScheme),
00533                                       TRUE); //select subdiv scheme.
00534 
00535   sizer->Add(m_listBoxSubdivScheme , //check box added to right panel (sizer)
00536              0, //not stretcheable
00537              wxALL | wxALIGN_LEFT, //wxALL->all 4 borders,
00538              1); //border width = 1
00539 }
00540 
00541 //----------------------------------------------------------------------------
00542 //--------------- protected: addButtonRender() -------------------------------
00543 //----------------------------------------------------------------------------
00544 
00545 void vuCellProjector::addButtonRender(wxSizer* sizer)
00546 {
00547   sizer->Add(new wxButton(this, idButtonRender, "Render"), //ptr to button
00548              0, //unstretcheable
00549              wxALL | wxALIGN_LEFT, //all borders
00550              10); //border width = 10.
00551 }

Generated on Wed Dec 15 21:20:33 2004 for vuVolume by  doxygen 1.3.9.1