Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Class Members | File Members

NetworkViewer.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   SpikeStream Application                                               *
00003  *   Copyright (C) 2007 by David Gamez                                     *
00004  *   david@davidgamez.eu                                                   *
00005  *   Version 0.1                                                           *
00006  *                                                                         *
00007  *   This program is free software; you can redistribute it and/or modify  *
00008  *   it under the terms of the GNU General Public License as published by  *
00009  *   the Free Software Foundation; either version 2 of the License, or     *
00010  *   (at your option) any later version.                                   *
00011  *                                                                         *
00012  *   This program is distributed in the hope that it will be useful,       *
00013  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00014  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00015  *   GNU General Public License for more details.                          *
00016  *                                                                         *
00017  *   You should have received a copy of the GNU General Public License     *
00018  *   along with this program; if not, write to the                         *
00019  *   Free Software Foundation, Inc.,                                       *
00020  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
00021  ***************************************************************************/
00022 
00023 //SpikeStream includes
00024 #include "NetworkViewer.h"
00025 #include "SpikeStreamMainWindow.h"
00026 #include "NetworkViewerProperties.h"
00027 #include "Debug.h"
00028 #include "Utilities.h"
00029 #include "PerformanceTimer.h"
00030 
00031 //Qt includes
00032 #include <qstring.h>
00033 #include <qmessagebox.h>
00034 
00035 //Other includes
00036 #include <mysql++.h>
00037 #include <math.h>
00038 #include <iostream>
00039 using namespace std;
00040 using namespace mysqlpp;
00041 
00042 
00043 /*! Define a constant for PI. */
00044 #define GL_PI 3.1415f
00045 
00046 
00047 /* gltools macro to convert degrees to radians and vice versa. */
00048 #define GLT_PI_DIV_180 0.017453292519943296
00049 #define GLT_INV_PI_DIV_180 57.2957795130823229
00050 #define gltDegToRad(x)  ((x)*GLT_PI_DIV_180)
00051 #define gltRadToDeg(x)  ((x)*GLT_INV_PI_DIV_180)
00052 
00053 
00054 /* Definitions of colours. */
00055 #define DEFAULT_NEURON_COLOUR_FULL 0.5f,0.5f,0.5f
00056 #define HIGHLIGHT_FIRST_NEURON_COLOUR_FULL 1.0f,0.0f,0.0f
00057 #define HIGHLIGHT_SECOND_NEURON_COLOUR_FULL 0.0f,1.0f,0.0f
00058 #define DEFAULT_NEURON_COLOUR_OUTLINE 0.0f,0.0f,0.0f
00059 #define HIGHLIGHT_FIRST_NEURON_COLOUR_OUTLINE 1.0f,0.0f,0.0f
00060 #define HIGHLIGHT_SECOND_NEURON_COLOUR_OUTLINE 0.0f,1.0f,0.0f
00061 #define CONNECTED_NEURON_COLOUR 1.0f,0.0f,1.0f
00062 #define POSITIVE_CONNECTION_COLOUR 0.718f,0.165f,0.180f
00063 #define NEGATIVE_CONNECTION_COLOUR 0.067f,0.553f,0.110f
00064 
00065 
00066 /* Light and material Data. */
00067 //FIXME THIS HAS BEEN PUT IN FAIRLY RANDOMLY TO ILLUMINATE THE NEURONS. SOMETHING BETTER COULD BE DONE HERE
00068 GLfloat fLightPos[4]   = { -100.0f, 100.0f, 50.0f, 1.0f };  // Point source
00069 GLfloat fNoLight[] = { 0.0f, 0.0f, 0.0f, 0.0f };
00070 GLfloat fLowLight[] = { 0.25f, 0.25f, 0.25f, 1.0f };
00071 GLfloat fogColor[] = {1.0f, 1.0f, 1.0f, 1.0f};
00072 GLfloat fBrightLight[] = { 1.0f, 1.0f, 1.0f, 1.0f };
00073 
00074 
00075 /*! Constructor. */
00076 NetworkViewer::NetworkViewer( QWidget *parent, QSplashScreen* splashScreen, DBInterface* dbInter, unsigned int maxAutoLoadConns) : QGLWidget(parent, "Network viewer") {
00077         //Store a reference to the database interface
00078         dbInterface = dbInter;
00079 
00080         /* Store short version of reference to main QApplication to enable the processing 
00081                 of events during heavy rendering operations */
00082         spikeStrApp = SpikeStreamMainWindow::spikeStreamApplication;
00083 
00084         //View state needs to be loaded at start up
00085         viewStateChanged = true;
00086 
00087         //Not currently painting GL
00088         paintingGL = false;
00089         
00090         /* Set max size of connection group that is automatically loaded. This value 
00091                 is taken from configuration file neuronapplication.config. */
00092         maxAutoLoadConnGrpSize = maxAutoLoadConns;
00093         
00094         //Set up load progress dialog
00095         loadProgressDialog = new QProgressDialog(this, "load progress", true);
00096         
00097         //Set up parameters to control the viewing perspective
00098         perspective_angle = 46.0f;
00099         perspective_near = 1.0f;
00100         perspective_far = 100000.0f;//Set this to a large number so everything will be visible
00101         
00102         //Set up timer for rendering
00103         renderTimer = new QTimer( this );
00104         connect( renderTimer, SIGNAL(timeout()), this, SLOT(setFullRender()) );
00105         
00106         //Initialise the camera and frame parameters. 
00107         //This must be done before loading the database, which changes some of the initialised parameters
00108         initialiseCameraParameters();
00109         fullRenderMode = false;
00110         fullRender = false;
00111         renderDelay_ms =1000;
00112         drawConnections = true;
00113         neuronConnectionMode = false;
00114         firstSingleNeuronID = 0;
00115         secondSingleNeuronID = 0;
00116         minFirstSingleNeuronID = 0;
00117         maxFirstSingleNeuronID = 0;
00118         firstSingleNeuronGroupWidth = 0;
00119         minSecondSingleNeuronID = 0;
00120         maxSecondSingleNeuronID = 0;
00121         secondSingleNeuronGroupWidth = 0;
00122         neuronFilterMode = false;
00123         maxWeight = 127;
00124         minWeight = -128;
00125         showFromConnections = true;
00126         showToConnections = true;
00127         showBetweenConnections = false;
00128 
00129         //Set up highlighting
00130         highlightMode = false;
00131         highlightNeuronMap.set_empty_key(EMPTY_NEURON_ID_KEY);
00132         highlightNeuronMap.set_deleted_key(DELETED_NEURON_ID_KEY);
00133 
00134         //Load up neuron Group data from database
00135         loadAllNeuronGroups(splashScreen);
00136         
00137         //Load connection group data from database
00138         loadAllConnectionGroups(splashScreen);
00139         
00140         //Set up keyboard accelerators for the network viewer
00141         //Use accelerators rather than key press event to avoid problems about focus
00142         keyboardAccelerator = new QAccel( this );
00143         
00144         //Add all  the key combinations that will be required.
00145         keyboardAccelerator->insertItem(Key_Up);
00146         keyboardAccelerator->insertItem(Key_Down);
00147         keyboardAccelerator->insertItem(Key_Left);
00148         keyboardAccelerator->insertItem(Key_Right);
00149         keyboardAccelerator->insertItem(CTRL + Key_Up);
00150         keyboardAccelerator->insertItem(CTRL + Key_Down);
00151         keyboardAccelerator->insertItem(CTRL + Key_Left);
00152         keyboardAccelerator->insertItem(CTRL + Key_Right);
00153         keyboardAccelerator->insertItem(SHIFT + Key_Up);
00154         keyboardAccelerator->insertItem(SHIFT + Key_Down);
00155         keyboardAccelerator->insertItem(SHIFT + Key_Left);
00156         keyboardAccelerator->insertItem(SHIFT + Key_Right);
00157         keyboardAccelerator->insertItem(ALT + Key_Up);
00158         keyboardAccelerator->insertItem(ALT + Key_Down);
00159         keyboardAccelerator->insertItem(ALT + Key_Left);
00160         keyboardAccelerator->insertItem(ALT + Key_Right);
00161         keyboardAccelerator->insertItem(SHIFT + ALT + Key_Up);
00162         keyboardAccelerator->insertItem(SHIFT + ALT + Key_Down);
00163         keyboardAccelerator->insertItem(SHIFT + ALT + Key_Left);
00164         keyboardAccelerator->insertItem(SHIFT + ALT + Key_Right);
00165         keyboardAccelerator->insertItem(CTRL + Key_Y);
00166         keyboardAccelerator->insertItem(CTRL + Key_Equal);
00167         keyboardAccelerator->insertItem(CTRL + Key_Minus);
00168          
00169          //Connect up accelerator with the method that will process the key events
00170          connect (keyboardAccelerator, SIGNAL(activated(int)), this, SLOT(acceleratorKeyPressed(int)));
00171 }
00172 
00173 
00174 /*! Destructor. */
00175 NetworkViewer::~NetworkViewer(){
00176         #ifdef MEMORY_DEBUG
00177                 cout<<"DELETING NETWORK VIEWER"<<endl;
00178         #endif//MEMORY_DEBUG
00179 
00180         //Delete all neuron group holders. These handle the deletion of their arrays
00181         for(map<unsigned int, NeuronGroupHolder*>::iterator iter = neuronGrpMap.begin(); iter != neuronGrpMap.end(); ++iter)
00182                 delete iter->second;
00183                 
00184         //Delete all connection group holders. These handle the deletion of their arrays
00185         for(map<unsigned int, ConnectionGroupHolder*>::iterator iter = connectionGrpMap.begin(); iter != connectionGrpMap.end(); ++iter)
00186                 delete iter->second;
00187 }
00188 
00189 
00190 //----------------------------------------------------------------------------------------------
00191 //------------------------------------- PUBLIC METHODS  ----------------------------------------
00192 //----------------------------------------------------------------------------------------------
00193 
00194 /*! Adds a neuron to be highlighted.*/
00195 void NetworkViewer::addHighlight(unsigned int neurID, RGBColor* highlightColor){
00196         highlightNeuronMap[neurID] = highlightColor;
00197         highlightColorMap[highlightColor] = true;
00198         highlightMode = true;
00199         viewStateChanged = true;
00200 }
00201 
00202 
00203 /*! Cancels the render in full render mode. */
00204 void NetworkViewer::cancelRenderProgress(){
00205         cancelRender = true;
00206 }
00207 
00208 
00209 /*! Clears all of the current highlights. */
00210 void NetworkViewer::clearHighlights(){
00211         highlightMode = false;
00212         highlightNeuronMap.clear();
00213 
00214         //Clean up colors allocatd on the heap
00215         for(HighlightColorMap::iterator iter = highlightColorMap.begin(); iter != highlightColorMap.end(); ++iter)
00216                 delete iter->first;
00217         highlightColorMap.clear();
00218 
00219         viewStateChanged = true;
00220         updateGL();
00221 }
00222 
00223 
00224 /*! Removes the data structures for a connection group after it has been deleted from the database
00225         by the ConnectionWidget. */
00226 void NetworkViewer::deleteConnectionGroup(unsigned int connGrpID){
00227         //Delete connection group holder pointed to by map
00228         delete connectionGrpMap[connGrpID];
00229 
00230         //Remove neuron group holder from map
00231         connectionGrpMap.erase(connGrpID);
00232         
00233         //Remove neuronGroupID from view vector
00234         vector<unsigned int>::iterator connViewIter;
00235         for(connViewIter = connectionViewVector.begin(); connViewIter != connectionViewVector.end(); ++connViewIter){
00236                 if(*connViewIter == connGrpID){
00237                         connectionViewVector.erase(connViewIter);
00238                         break;
00239                 }
00240         }
00241         //Record the fact that the view state has changed
00242         viewStateChanged = true;
00243 
00244         //Update the display
00245         updateGL();
00246 }
00247 
00248 
00249 /*! Removes the data structures for a neuron group after it has been deleted from the database
00250         by the LayerWidget. Also removes any connections to this neuron group. 
00251         Exception handling for this class should be done by the calling method. */
00252 void NetworkViewer::deleteNeuronGroup(unsigned int neuronGrpID){
00253         //Delete neuron group holder pointed to by map
00254         delete neuronGrpMap[neuronGrpID];
00255 
00256         //Remove neuron group holder from map
00257         neuronGrpMap.erase(neuronGrpID);
00258         
00259         //Remove neuronGroupID from view vector
00260         vector<unsigned int>::iterator layerViewIter;
00261         for(layerViewIter = layerViewVector.begin(); layerViewIter != layerViewVector.end(); ++layerViewIter){
00262                 if(*layerViewIter == neuronGrpID){
00263                         layerViewVector.erase(layerViewIter);
00264                         break;
00265                 }
00266         }
00267         //Delete the connection groups involving this neuron group
00268         try{
00269                 Query query = dbInterface->getQuery();
00270                 query.reset();
00271                 query<<"SELECT ConnGrpID FROM ConnectionGroups WHERE FromNeuronGrpID = "<<neuronGrpID<<" OR ToNeuronGrpID = "<<neuronGrpID;
00272 
00273                 Result connRes = query.store();
00274                 for(Result::iterator connIter = connRes.begin(); connIter != connRes.end(); ++connIter){
00275                         Row connRow(*connIter);
00276                         unsigned short connGrpID = Utilities::getUShort((std::string)connRow["ConnGrpID"]);
00277                         deleteConnectionGroup(connGrpID);
00278                 }
00279         }
00280         catch (const BadQuery& er) {// Handle any query errors
00281                 cerr<<"NetworkViewer: MYSQL QUERY EXCEPTION \""<<er.what()<<"\""<<endl;
00282                 QString errorString = "Bad query when removing connection group: \"";
00283                 errorString += er.what();
00284                 errorString += "\"";
00285                 QMessageBox::critical( 0, "Connection Group Error", errorString);
00286         }
00287         catch (const Exception& er) {// Catch-all for any other MySQL++ exceptions
00288                 cerr<<"NetworkViewer: MYSQL EXCEPTION \""<<er.what()<<"\""<<endl;
00289                 QString errorString = "Exception thrown removing connection group: \"";
00290                 errorString += er.what();
00291                 errorString += "\"";
00292                 QMessageBox::critical( 0, "Connection Group Error", errorString);
00293         }
00294         catch(std::exception& er){// Catch-all for std exceptions
00295                 cerr<<"NetworkViewer: STD EXCEPTION \""<<er.what()<<"\""<<endl;
00296                 QString errorString = "Exception thrown removing connection group: \"";
00297                 errorString += er.what();
00298                 errorString += "\"";
00299                 QMessageBox::critical( 0, "Connection Group Error", errorString);
00300         }
00301 
00302         //Sort out any variables linked to the neuron group
00303         if(neuronGrpID == firstSingleNeurGrpID){
00304                 firstSingleNeurGrpID = 0;
00305                 minFirstSingleNeuronID = 0;
00306                 maxFirstSingleNeuronID = 0;
00307                 firstSingleNeuronGroupWidth = 0;
00308                 showBetweenConnections = false;
00309         }
00310         if(neuronGrpID == secondSingleNeurGrpID){
00311                 secondSingleNeurGrpID = 0;
00312                 maxSecondSingleNeuronID = 0;
00313                 minSecondSingleNeuronID = 0;
00314                 secondSingleNeuronGroupWidth= 0;
00315                 showBetweenConnections = false;
00316         }
00317 
00318         //Record the fact that the view state has changed
00319         viewStateChanged = true;
00320 
00321         //Update the display
00322         updateGL();
00323 }
00324 
00325 
00326 /*! Returns the vector containing the connections that are showing. */
00327 vector<unsigned int>* NetworkViewer::getConnectionViewVector(){
00328         return &connectionViewVector;
00329 }
00330 
00331 
00332 /*! Loads a connection group with connGrpID from the database
00333         Only automatically loads connection groups less than 1000000 unless a 
00334         progress bar is being displayed.
00335         Exceptions should be handled by the class that calls this method. */
00336 void NetworkViewer::loadConnectionGroup(unsigned int connGrpID, bool showProgressDialog) {
00337         Query query = dbInterface->getQuery();
00338         
00339         //Get number of connections in connection group
00340         query.reset();
00341         query<<"SELECT COUNT(*) FROM Connections WHERE ConnGrpID = "<<connGrpID;
00342         Result connCountRes = query.store();
00343         Row connCountRow(*connCountRes.begin());
00344         unsigned int numberOfConnections = Utilities::getUInt((std::string)connCountRow.at(0));
00345         if((numberOfConnections > maxAutoLoadConnGrpSize) && !showProgressDialog)
00346                 return;//Do not automatically load large connection groups
00347                 
00348         //If using progress bar, set up with the number of neurons to be loaded
00349         int progressCount = 0;
00350         if(showProgressDialog){
00351                 loadProgressDialog->setTotalSteps(numberOfConnections);
00352                 loadProgressDialog->setLabelText("Loading connection group " + QString::number(connGrpID));
00353         }
00354         
00355         //Get type of connection group
00356         query.reset();
00357         query<<"SELECT ConnType, FromNeuronGrpID, ToNeuronGrpID FROM ConnectionGroups WHERE ConnGrpID = "<<connGrpID;
00358         Result connGrpRes = query.store();
00359         Row connGrpRow(*connGrpRes.begin());
00360         unsigned short connType = Utilities::getUShort((std::string)connGrpRow["ConnType"]);
00361         ConnectionGroupHolder *connGrpHolder = new ConnectionGroupHolder();
00362         connGrpHolder->connectionType = connType;
00363                 
00364         //Get the pre and post neuron group holders. 
00365         //These contain the data about the X, Y and Z positions and by using these from memory, many database accesses can be avoided
00366         unsigned int fromNeuronGrpID = Utilities::getUInt((std::string)connGrpRow["FromNeuronGrpID"]);
00367         unsigned int toNeuronGrpID = Utilities::getUInt((std::string)connGrpRow["ToNeuronGrpID"]);
00368         NeuronGroupHolder *fromNeurGrpHolder = neuronGrpMap[fromNeuronGrpID];
00369         NeuronGroupHolder *toNeurGrpHolder = neuronGrpMap[toNeuronGrpID];
00370         //Also get start IDs for the from and to neuron group holder
00371         unsigned int fromNeurGrpStartID = fromNeurGrpHolder->startNeuronID;
00372         unsigned int toNeurGrpStartID = toNeurGrpHolder->startNeuronID;
00373         
00374         //Now get pre and post neuron ids for all connections in this group
00375         query.reset();
00376         query<<"SELECT PreSynapticNeuronID, PostSynapticNeuronID, Weight FROM Connections WHERE ConnGrpID ="<<connGrpID;
00377         ResUse res = query.use();
00378         
00379         //Initialise arrays in connection group holder
00380         connGrpHolder->numberOfConnections = numberOfConnections;
00381         connGrpHolder->fromNeuronIDArray = new unsigned int[numberOfConnections];
00382         connGrpHolder->fromXArray = new float[numberOfConnections];
00383         connGrpHolder->fromYArray = new float[numberOfConnections];
00384         connGrpHolder->fromZArray = new float[numberOfConnections];
00385         connGrpHolder->toNeuronIDArray = new unsigned int[numberOfConnections];
00386         connGrpHolder->toXArray = new float[numberOfConnections];
00387         connGrpHolder->toYArray = new float[numberOfConnections];
00388         connGrpHolder->toZArray = new float[numberOfConnections];
00389         connGrpHolder->weightArray = new char[numberOfConnections];
00390         
00391         //Set up pointers to the arrays
00392         unsigned int *fromNeuronIDPtr = connGrpHolder->fromNeuronIDArray;
00393         float *fromXPtr = connGrpHolder->fromXArray;
00394         float *fromYPtr = connGrpHolder->fromYArray;
00395         float *fromZPtr = connGrpHolder->fromZArray;
00396         unsigned int *toNeuronIDPtr = connGrpHolder->toNeuronIDArray;
00397         float *toXPtr = connGrpHolder->toXArray;
00398         float *toYPtr = connGrpHolder->toYArray;
00399         float *toZPtr = connGrpHolder->toZArray;
00400         char *weightPtr = connGrpHolder->weightArray;
00401         
00402         //Work through the list of pre and post neurons to extract and store the positions of these neurons
00403         Row prePostNeuronRow;
00404         if(res){
00405                 try {
00406                         while (prePostNeuronRow = res.fetch_row()){
00407                                 unsigned int preNeuronID = Utilities::getUInt((std::string)prePostNeuronRow.at(0));
00408                                 unsigned int postNeuronID = Utilities::getUInt((std::string)prePostNeuronRow.at(1));
00409                                 
00410                                 //Extract the weight. This is stored as a char to save space
00411                                 *weightPtr = (char)Utilities::getShort((std::string)prePostNeuronRow.at(2));
00412                                 ++weightPtr;
00413                                 
00414                                 //Load up position of the from neuron
00415                                 *fromNeuronIDPtr = preNeuronID;
00416                                 *fromXPtr = fromNeurGrpHolder->xPosArray[preNeuronID - fromNeurGrpStartID];
00417                                 *fromYPtr = fromNeurGrpHolder->yPosArray[preNeuronID - fromNeurGrpStartID];
00418                                 *fromZPtr = fromNeurGrpHolder->zPosArray[preNeuronID - fromNeurGrpStartID];
00419                                 ++fromNeuronIDPtr;
00420                                 ++fromXPtr;
00421                                 ++fromYPtr;
00422                                 ++fromZPtr;
00423                                 
00424                                 //Load up position of the to neuron
00425                                 *toNeuronIDPtr = postNeuronID;
00426                                 *toXPtr = toNeurGrpHolder->xPosArray[postNeuronID - toNeurGrpStartID];
00427                                 *toYPtr = toNeurGrpHolder->yPosArray[postNeuronID - toNeurGrpStartID];
00428                                 *toZPtr = toNeurGrpHolder->zPosArray[postNeuronID - toNeurGrpStartID];
00429                                 ++toNeuronIDPtr;
00430                                 ++toXPtr;
00431                                 ++toYPtr;
00432                                 ++toZPtr;
00433                         
00434                                 //Increase the progress count. Update the progress bar every 1000;
00435                                 if(showProgressDialog){
00436                                         ++progressCount;
00437                                         if((progressCount % 1000)== 0)
00438                                                 loadProgressDialog->setProgress(progressCount);
00439                                 }
00440                         }
00441                 }
00442                 catch (const EndOfResults& er) {//EndOfResults exception thrown when fetch row no longer returns anything
00443                         //No need to do anything here - this is normal behaviour
00444                 }
00445 
00446                 //Store new connection group
00447                 connectionGrpMap[connGrpID] = connGrpHolder;
00448                 
00449                 //Hide progress bar if showing
00450                 if(showProgressDialog)
00451                         loadProgressDialog->setProgress(progressCount);
00452         }
00453         else{
00454                 cerr<<"CANNOT RETRIEVE CONNECTION GROUP DETAILS: "<<query.error()<<endl;
00455                 loadProgressDialog->reset();
00456         }
00457 
00458         //Record the fact that the view state has changed
00459         viewStateChanged = true;
00460 
00461         //Update the display if we are not loading up for the first time
00462         if(showProgressDialog)
00463                 updateGL();
00464 }
00465 
00466 
00467 /*! Loads the default clipping volume from the database.
00468         Exception handling should be done by the class that calls this method. */
00469 void NetworkViewer::loadDefaultClippingVolume(){
00470         //Need the maximum and minimum x, y and z values
00471         Query query = dbInterface->getQuery();
00472         query.reset();
00473         query<<"SELECT * FROM NeuronGroups";
00474         Result neuronGrpRes = query.store();
00475         if(neuronGrpRes.size() == 0){//No neurons in database, so set up default clipping volume around origin
00476                 defaultClippingVol.minX = -100;
00477                 defaultClippingVol.maxX = 100;
00478                 defaultClippingVol.minY = -100;
00479                 defaultClippingVol.maxY = 100;
00480                 defaultClippingVol.minZ = -100;
00481                 defaultClippingVol.maxZ = 100;
00482         }
00483         else{//Set default clipping volume so that it includes all layers and the origin.
00484                 query<<"SELECT MIN(X) FROM Neurons";
00485                 Result minXRes = query.store();
00486                 Row minXRow(*minXRes.begin());//Assume that there is only one result
00487                 defaultClippingVol.minX = getFloat((std::string)minXRow.at(0));
00488                 query.reset();
00489                 query<<"SELECT MAX(X) FROM Neurons";
00490                 Result maxXRes = query.store();
00491                 Row maxXRow(*maxXRes.begin());//Assume that there is only one result
00492                 defaultClippingVol.maxX = getFloat((std::string)maxXRow.at(0));
00493                 query.reset();
00494                 query<<"SELECT MIN(Y) FROM Neurons";
00495                 Result minYRes = query.store();
00496                 Row minYRow(*minYRes.begin());//Assume that there is only one result
00497                 defaultClippingVol.minY = getFloat((std::string)minYRow.at(0));
00498                 query.reset();
00499                 query<<"SELECT MAX(Y) FROM Neurons";
00500                 Result maxYRes = query.store();
00501                 Row maxYRow(*maxYRes.begin());//Assume that there is only one result
00502                 defaultClippingVol.maxY = getFloat((std::string)maxYRow.at(0));
00503                 query.reset();
00504                 query<<"SELECT MIN(Z) FROM Neurons";
00505                 Result minZRes = query.store();
00506                 Row minZRow(*minZRes.begin());//Assume that there is only one result
00507                 defaultClippingVol.minZ = getFloat((std::string)minZRow.at(0));
00508                 query.reset();
00509                 query<<"SELECT MAX(Z) FROM Neurons";
00510                 Result maxZRes = query.store();
00511                 Row maxZRow(*maxZRes.begin());//Assume that there is only one result
00512                 defaultClippingVol.maxZ = getFloat((std::string)maxZRow.at(0));
00513                 
00514                 //Want to include the origin in the starting clip volume
00515                 if(defaultClippingVol.minX >0)
00516                         defaultClippingVol.minX = 0;
00517                 if(defaultClippingVol.maxX < 0)
00518                         defaultClippingVol.maxX =0;
00519                 if(defaultClippingVol.minY >0)
00520                         defaultClippingVol.minY = 0;
00521                 if(defaultClippingVol.maxY < 0)
00522                         defaultClippingVol.maxY =0;
00523                 if(defaultClippingVol.minZ > 0)
00524                         defaultClippingVol.minZ = 0;
00525                 if(defaultClippingVol.maxZ < 0)
00526                         defaultClippingVol.maxZ = 0;
00527         }
00528 }
00529 
00530 
00531 /*! Loads up a neuron group with a particular neuron ID
00532         This is used to load up layers at the beginning of the application 
00533         and called by LayerWidget when a new layer is created.
00534         This method will return immediately if the neuron group has already
00535         been loaded. A neuron group needs to be explicitly deleted before
00536         it can be reloaded.
00537         Exception handling for this should be done by the invoking method. */
00538 void NetworkViewer::loadNeuronGroup(unsigned int neuronGroupID, bool showProgressDialog){
00539         //Check to see if neuron group is already loaded
00540         if(neuronGrpMap.count(neuronGroupID) > 0){
00541                 cout<<"NetworkViewer: Neuron group "<<neuronGroupID<<" already loaded"<<endl;
00542                 return;
00543         }
00544 
00545         //Get number of neurons in neuron group
00546         Query query = dbInterface->getQuery();
00547         query.reset();
00548         query<<"SELECT COUNT(*) FROM Neurons WHERE NeuronGrpID = "<<neuronGroupID;
00549         Result neuronCountRes = query.store();
00550         Row neuronCountRow(*neuronCountRes.begin());
00551         unsigned int numberOfNeurons = Utilities::getUInt((std::string)neuronCountRow.at(0));
00552         
00553         //If using progress bar, set up with the number of neurons to be loaded
00554         int progressCount = 0;
00555         if(showProgressDialog){
00556                 loadProgressDialog->setTotalSteps(numberOfNeurons);
00557                 loadProgressDialog->setLabelText("Loading neuron group " + QString::number(neuronGroupID));
00558         }
00559 
00560         //Get neuronType for this neuron group
00561         query.reset();
00562         query<<"SELECT NeuronType FROM NeuronGroups WHERE NeuronGrpID = "<<neuronGroupID;
00563         Result neuronGrpRes = query.store();
00564         Row neuronGrpRow(*neuronGrpRes.begin());
00565         unsigned short neuronType = Utilities::getUShort((std::string)neuronGrpRow["NeuronType"]);
00566         NeuronGroupHolder *neurGrpHolder = new NeuronGroupHolder();
00567         neurGrpHolder->neuronType = neuronType;
00568         
00569         //Get locations for all neurons in this group from the database
00570         query.reset();
00571         query<<"SELECT NeuronID, X, Y, Z FROM Neurons WHERE NeuronGrpID ="<<neuronGroupID<<" ORDER BY NeuronID";
00572         ResUse res = query.use();//ResUse is much more efficient for large queries
00573         bool firstTimeNeurons = true;//Used for the clipping volume and to get the startID
00574         
00575         //Initialise arrays in neuron group holder
00576         neurGrpHolder->numberOfNeurons = numberOfNeurons;
00577         neurGrpHolder->neuronIDArray = new unsigned int[numberOfNeurons];
00578         neurGrpHolder->xPosArray = new float[numberOfNeurons];
00579         neurGrpHolder->yPosArray = new float[numberOfNeurons];
00580         neurGrpHolder->zPosArray = new float[numberOfNeurons];
00581         unsigned int *neuronIDPtr = neurGrpHolder->neuronIDArray;
00582         float *xPosPtr = neurGrpHolder->xPosArray;
00583         float *yPosPtr = neurGrpHolder->yPosArray;
00584         float *zPosPtr = neurGrpHolder->zPosArray;
00585                 
00586         //Fill arrays in neuron group holder with coordinates of neurons
00587         Row neuronRow;
00588         if(res){
00589                 try {
00590                         while (neuronRow = res.fetch_row()){
00591                                 //Store the NeuronID and x, y, and z coordinates of the neuron
00592                                 *neuronIDPtr = Utilities::getUInt((std::string)neuronRow.at(0));
00593                                 *xPosPtr = getFloat((std::string)neuronRow[1]);
00594                                 *yPosPtr = getFloat((std::string)neuronRow[2]);
00595                                 *zPosPtr = getFloat((std::string)neuronRow[3]);
00596                 
00597                                 //Adjust the clipping volume of the neural network if necessary
00598                                 if(firstTimeNeurons){
00599                                         neurGrpHolder->startNeuronID = *neuronIDPtr;//Store the startID
00600                                         neurGrpHolder->clippingVolume.maxX = *xPosPtr;
00601                                         neurGrpHolder->clippingVolume.maxY = *yPosPtr;
00602                                         neurGrpHolder->clippingVolume.maxZ = *zPosPtr;
00603                                         neurGrpHolder->clippingVolume.minX = *xPosPtr;
00604                                         neurGrpHolder->clippingVolume.minY = *yPosPtr;
00605                                         neurGrpHolder->clippingVolume.minZ = *zPosPtr;
00606                                         firstTimeNeurons = false;
00607                                 }
00608                                 else{
00609                                         if(*xPosPtr > neurGrpHolder->clippingVolume.maxX)
00610                                                 neurGrpHolder->clippingVolume.maxX = *xPosPtr;
00611                                         else if(*xPosPtr < neurGrpHolder->clippingVolume.minX)
00612                                                 neurGrpHolder->clippingVolume.minX = *xPosPtr;
00613                                         if(*yPosPtr > neurGrpHolder->clippingVolume.maxY)
00614                                                 neurGrpHolder->clippingVolume.maxY = *yPosPtr;
00615                                         else if(*yPosPtr < neurGrpHolder->clippingVolume.minY)
00616                                                 neurGrpHolder->clippingVolume.minY = *yPosPtr;
00617                                         if(*zPosPtr > neurGrpHolder->clippingVolume.maxZ)
00618                                                 neurGrpHolder->clippingVolume.maxZ = *zPosPtr;
00619                                         else if(*zPosPtr < neurGrpHolder->clippingVolume.minZ)
00620                                                 neurGrpHolder->clippingVolume.minZ = *zPosPtr;
00621                                 }
00622                                 
00623                                 //Increase the pointers
00624                                 ++neuronIDPtr;
00625                                 ++xPosPtr;
00626                                 ++yPosPtr;
00627                                 ++zPosPtr;
00628                                 
00629                                 //Increase the progress count. Update the progress bar every 1000;
00630                                 if(showProgressDialog){
00631                                         ++progressCount;
00632                                         if((progressCount % 1000)== 0)
00633                                                 loadProgressDialog->setProgress(progressCount);
00634                                 }
00635                         }
00636                 }
00637                 catch (const EndOfResults& er) {//EndOfResults exception thrown when fetch row no longer returns anything
00638                         //No need to do anything here - this is normal behaviour
00639                 }
00640 
00641 
00642                 firstTimeNeurons = true;
00643                 neuronGrpMap[neuronGroupID] = neurGrpHolder;
00644                 
00645                 //Hide progress bar if showing
00646                 if(showProgressDialog)
00647                         loadProgressDialog->setProgress(progressCount);
00648                 
00649                 //Add ID to view vector. Default is to view all layers.
00650                 layerViewVector.push_back(neuronGroupID);
00651         }
00652         else{//An error retrieving result from database
00653                 cerr<<"CANNOT RETRIEVE CONNECTION GROUP DETAILS: "<<query.error()<<endl;
00654                 loadProgressDialog->reset();
00655                 firstTimeNeurons = true;
00656         }
00657 
00658         //View state has changed
00659         viewStateChanged = true;
00660 
00661         //Update the display if we are not loading up for the first time
00662         if(showProgressDialog)
00663                 updateGL();
00664 }
00665 
00666 
00667 /*! Called by external classes to repaint the display. */
00668 void NetworkViewer::refresh(){
00669         updateGL();
00670 }
00671 
00672 
00673 /*! Called after a new database has been loaded. */
00674 void NetworkViewer::reloadEverything(){
00675         deleteAllNeuronGroups();
00676         deleteAllConnectionGroups();
00677         loadAllNeuronGroups();
00678         loadAllConnectionGroups();
00679 
00680         //Record the fact that the view state has changed
00681         viewStateChanged = true;
00682 
00683         //Update the display
00684         updateGL();
00685 }
00686 
00687 
00688 /*! Resets the view so all neural networks can be seen. */
00689 void NetworkViewer::resetView(){
00690         viewClippingVolume_Horizontal(defaultClippingVol);
00691 }
00692 
00693 
00694 /*! Sets the visible connection groups. */
00695 void NetworkViewer::setConnectionView(vector<unsigned int> connIDVect){
00696         //Check to see if all of the selected connection groups have been loaded.
00697         //Larger connection groups are not loaded automatically at start up to reduce initialisation time
00698         for(vector<unsigned int>::iterator iter = connIDVect.begin(); iter != connIDVect.end(); ++iter){
00699                 if(!connectionGrpMap[*iter]){//Connection has not been loaded
00700                         try{
00701                                 loadConnectionGroup(*iter, true);
00702                         }
00703                         catch (const BadQuery& er) {// Handle any query errors
00704                                 cerr<<"NetworkViewer: MYSQL QUERY EXCEPTION \""<<er.what()<<"\""<<endl;
00705                                 QString errorString = "Bad query loading connection group: \"";
00706                                 errorString += er.what();
00707                                 errorString += "\"";
00708                                 QMessageBox::critical( 0, "Load Connection Group Error", errorString);
00709                         }
00710                         catch (const Exception& er) {// Catch-all for any other MySQL++ exceptions
00711                                 cerr<<"NetworkViewer: MYSQL EXCEPTION \""<<er.what()<<"\""<<endl;
00712                                 QString errorString = "Exception thrown loading connection group: \"";
00713                                 errorString += er.what();
00714                                 errorString += "\"";
00715                                 QMessageBox::critical( 0, "Load Connection Group Error", errorString);
00716                         }
00717                         catch(std::exception& er){// Catch-all for std exceptions
00718                                 cerr<<"NetworkViewer: STD EXCEPTION \""<<er.what()<<"\""<<endl;
00719                                 QString errorString = "Exception thrown loading connection group: \"";
00720                                 errorString += er.what();
00721                                 errorString += "\"";
00722                                 QMessageBox::critical( 0, "Load Connection Group Error", errorString);
00723                         }
00724                 }
00725         }
00726         
00727         //Now all connection groups should be loaded, set the vector containing 
00728         //the list of visible connection group IDs
00729         connectionViewVector = connIDVect;
00730         
00731         //Update connection details table to reflect changes in the view
00732         ((NetworkViewerProperties*)networkViewerProperties)->reloadConnections();
00733 
00734         //Record fact that view state has changed
00735         viewStateChanged = true;
00736 
00737         //Update the display
00738         updateGL();
00739 }
00740 
00741 
00742 /*! Controls whether neurons are represented as lit spheres or simple vertices. */
00743 void NetworkViewer::setFullRenderMode(bool enableFullRender){
00744         fullRenderMode = enableFullRender;
00745 
00746         //Record the fact that the view state has changed
00747         viewStateChanged = true;
00748 
00749         //Set up or disable full render mode
00750         if(fullRenderMode){
00751                 initialiseFullRender();
00752                 
00753                 //Render scene in high quality after render delay
00754                 renderTimer->stop();
00755                 renderTimer->start(renderDelay_ms, TRUE);
00756         }
00757         else{
00758                 disableFullRender();
00759                 updateGL();
00760         }
00761 }
00762 
00763 
00764 /*! Sets the visible neuron groups. */
00765 void NetworkViewer::setLayerView(vector<unsigned int> layerIDVect){
00766         layerViewVector = layerIDVect;
00767         viewStateChanged = true;//Record the fact that the view state has changed
00768         updateGL();
00769 }
00770 
00771 
00772 /*! Sets the maximum size of connection group that is automatically loaded at startup. */
00773 void NetworkViewer::setMaxAutoLoadConnGrpSize(unsigned int maxConnGrpSize){
00774         maxAutoLoadConnGrpSize = maxConnGrpSize;
00775 }
00776 
00777 
00778 /*! Sets the network viewer properties to enable communication. */
00779 void NetworkViewer::setNetworkViewerProperties(QWidget *nwViewerProps){
00780         networkViewerProperties = nwViewerProps;
00781 }
00782 
00783 
00784 /*! Switches on and off whether the connections to a single neuron are displayed
00785         Also controls whether all connections to that neuron are displayed or only the connections
00786         within a particular connection group. 0 indicates that all connections are to be displayed. */
00787 void NetworkViewer::setNeuronConnectionMode(bool neurConnMode, unsigned int firstNeurGrpID, bool betweenMode, unsigned int secondNeurGrpID){
00788         //Store data passed by method
00789         neuronConnectionMode = neurConnMode;
00790         showBetweenConnections = betweenMode;
00791 
00792         try{
00793                 if(neuronConnectionMode && (firstSingleNeurGrpID != firstNeurGrpID)){//Only load if neuron group has changed
00794                         firstSingleNeurGrpID = firstNeurGrpID;
00795         
00796                         //Need to set starting neuron for the mode. This is the neuron at the position of the neuron group
00797                         Query query = dbInterface->getQuery();
00798                         query.reset();
00799                         //Start by getting the X, Y, Z position of the neuron group
00800                         query<<"SELECT X, Y, Z, Width FROM NeuronGroups WHERE NeuronGrpID = "<<firstNeurGrpID;
00801                         Result firstGrpPosRes = query.store();
00802                         Row firstGrpPosRow = (*firstGrpPosRes.begin());
00803                         
00804                         //Now find the neuron at this position in the layer. This will be the starting neuron
00805                         query.reset();
00806                         query<<"SELECT NeuronID FROM Neurons WHERE X = "<<(std::string)firstGrpPosRow["X"]<<" AND Y = "<<(std::string)firstGrpPosRow["Y"]<<" AND Z = "<<(std::string)firstGrpPosRow["Z"];
00807                         Result firstNeuronRes = query.store();
00808                         Row firstNeuronRow = (*firstNeuronRes.begin());
00809                         firstSingleNeuronID = Utilities::getUInt((std::string)firstNeuronRow["NeuronID"]);
00810                         ((NetworkViewerProperties*)networkViewerProperties)->setFirstSingleNeuronNumber(firstSingleNeuronID);//Update network viewer properties with neuron number
00811                         
00812                         //Need to get the first and last IDs of this neuron group to enable user to move around in the layer with the arrow keys
00813                         query.reset();
00814                         query<<"SELECT MIN(NeuronID), MAX(NeuronID) FROM Neurons WHERE NeuronGrpID = "<<firstNeurGrpID;
00815                         Result firstMinMaxNeurIDRes = query.store();
00816                         Row firstMinMaxNeurRow(*firstMinMaxNeurIDRes.begin());
00817                         minFirstSingleNeuronID = Utilities::getInt((std::string)firstMinMaxNeurRow["MIN(NeuronID)"]);
00818                         maxFirstSingleNeuronID = Utilities::getInt((std::string)firstMinMaxNeurRow["MAX(NeuronID)"]);
00819                         
00820                         //Get the length of the neuron group
00821                         firstSingleNeuronGroupWidth = Utilities::getInt((std::string)firstGrpPosRow["Width"]);
00822                 }
00823                 //Disable navigation when neuron connection mode is off
00824                 else if(!neuronConnectionMode) {
00825                         firstSingleNeurGrpID = 0;
00826                 }
00827                 
00828                 //Load up all the stuff for the second neuron if in between mode
00829                 if(neuronConnectionMode && showBetweenConnections && (secondSingleNeurGrpID != secondNeurGrpID)){//Only load if neuron group has changed
00830                         secondSingleNeurGrpID = secondNeurGrpID;
00831         
00832                         //Need to set starting neuron for the mode. This is the neuron at the position of the neuron group
00833                         Query query = dbInterface->getQuery();
00834                         query.reset();
00835                         //Start by getting the X, Y, Z position of the neuron group
00836                         query<<"SELECT X, Y, Z, Width FROM NeuronGroups WHERE NeuronGrpID = "<<secondNeurGrpID;
00837                         Result secondGrpPosRes = query.store();
00838                         Row secondGrpPosRow = (*secondGrpPosRes.begin());
00839                         
00840                         //Now find the neuron at this position in the layer. This will be the starting neuron
00841                         query.reset();
00842                         query<<"SELECT NeuronID FROM Neurons WHERE X = "<<(std::string)secondGrpPosRow["X"]<<" AND Y = "<<(std::string)secondGrpPosRow["Y"]<<" AND Z = "<<(std::string)secondGrpPosRow["Z"];
00843                         Result secondNeuronRes = query.store();
00844                         Row secondNeuronRow = (*secondNeuronRes.begin());
00845                         secondSingleNeuronID = Utilities::getUInt((std::string)secondNeuronRow["NeuronID"]);
00846                         ((NetworkViewerProperties*)networkViewerProperties)->setSecondSingleNeuronNumber(secondSingleNeuronID);//Update network viewer properties with neuron number
00847                         
00848                         //Need to get the first and last IDs of this neuron group to enable user to move around in the layer with the arrow keys
00849                         query.reset();
00850                         query<<"SELECT MIN(NeuronID), MAX(NeuronID) FROM Neurons WHERE NeuronGrpID = "<<secondNeurGrpID;
00851                         Result secondMinMaxNeurIDRes = query.store();
00852                         Row secondMinMaxNeurRow(*secondMinMaxNeurIDRes.begin());
00853                         minSecondSingleNeuronID = Utilities::getInt((std::string)secondMinMaxNeurRow["MIN(NeuronID)"]);
00854                         maxSecondSingleNeuronID = Utilities::getInt((std::string)secondMinMaxNeurRow["MAX(NeuronID)"]);
00855                         
00856                         //Get the length of the neuron group
00857                         secondSingleNeuronGroupWidth = Utilities::getInt((std::string)secondGrpPosRow["Width"]);
00858                 }
00859                 //Not using second neuron group so disable navigation in this layer
00860                 else if (!neuronConnectionMode || !showBetweenConnections) {
00861                         secondSingleNeurGrpID = 0;
00862                 }
00863         }
00864         catch (const BadQuery& er) {// Handle any query errors
00865                 cerr<<"NetworkViewer: MYSQL QUERY EXCEPTION \""<<er.what()<<"\""<<endl;
00866                 QString errorString = "Bad query setting neuron connection mode: \"";
00867                 errorString += er.what();
00868                 errorString += "\"";
00869                 QMessageBox::critical( 0, "Connection View Error", errorString);
00870         }
00871         catch (const Exception& er) {// Catch-all for any other MySQL++ exceptions
00872                 cerr<<"NetworkViewer: MYSQL EXCEPTION \""<<er.what()<<"\""<<endl;
00873                 QString errorString = "Exception thrown setting neuron connection mode: \"";
00874                 errorString += er.what();
00875                 errorString += "\"";
00876                 QMessageBox::critical( 0, "Connection View Error", errorString);
00877         }
00878         catch(std::exception& er){// Catch-all for std exceptions
00879                 cerr<<"NetworkViewer: STD EXCEPTION \""<<er.what()<<"\""<<endl;
00880                 QString errorString = "Exception thrown setting neuron connection mode: \"";
00881                 errorString += er.what();
00882                 errorString += "\"";
00883                 QMessageBox::critical( 0, "Connection View Error", errorString);
00884         }
00885 
00886         //Record that view state has changed
00887         viewStateChanged = true;
00888 
00889         //Update the graphical display
00890         updateGL();
00891 }
00892 
00893 
00894 /*! Controls which connections are visible during single neuron connection mode. */
00895 void NetworkViewer::setNeuronFilterMode(bool mode, char minW, char maxW, bool showFrom, bool showTo, bool updateDisplay){
00896         neuronFilterMode = mode;
00897         
00898         if(neuronFilterMode){
00899                 //First check that min and max weight are ok
00900                 short minW_short = (short)minW;//Needed to facilitate comparison
00901                 short maxW_short = (short)maxW;//Needed to facilitate comparison
00902                 if((minW_short < -128) || (minW_short > 127) || (maxW_short < -128) || (maxW_short > 127)){
00903                         cerr<<"NetworkViewer: MIN OR MAX WEIGHTS ARE OUT OF RANGE"<<endl;
00904                         QMessageBox::critical( 0, "Filter Error", "Min or max weights are out of range.");
00905                         return;
00906                 }
00907 
00908                 //Set min and max weights
00909                 minWeight = minW;
00910                 maxWeight = maxW;
00911                 
00912                 //Set from/ to showing options
00913                 showFromConnections = showFrom;
00914                 showToConnections = showTo;
00915         }
00916 
00917         //Record that view state has changed
00918         viewStateChanged = true;
00919 
00920         //Update graphical display
00921         if(updateDisplay)
00922                 updateGL();
00923 }
00924 
00925 
00926 /*! Sets the delay between the last key press and the start of the full render. */
00927 void NetworkViewer::setRenderDelay(double renderDelay_sec){
00928         renderDelay_ms = (int)(renderDelay_sec * 1000.0);
00929 }
00930 
00931 
00932 /*! Store a reference to the progress bar to display rendering progress. */
00933 void NetworkViewer::setRenderProgressBar(QProgressBar *progBar){
00934         renderProgressBar = progBar;
00935 }
00936 
00937 
00938 /*! Switches connection drawing mode on or off. */
00939 void NetworkViewer::showConnections(bool sc){
00940         drawConnections = sc;
00941 
00942         //Record that view state has changed
00943         viewStateChanged = true;
00944 
00945         //Update the graphical display
00946         updateGL();
00947 }
00948 
00949 
00950 /*! Moves viewing position above selected layer and resizes it appropriately
00951         Don't need to set viewStateChanged here since the viewing angle is
00952         outside of the main list. */
00953 void NetworkViewer::zoomAboveLayer(unsigned int layerID){
00954         if(layerID == 0)
00955                 viewClippingVolume_Vertical(defaultClippingVol);
00956         else{
00957                 NeuronGroupHolder *tempNeurGrpHolder = neuronGrpMap[layerID];
00958                 viewClippingVolume_Vertical(tempNeurGrpHolder->clippingVolume);
00959         }
00960         updateGL();
00961 }
00962 
00963 
00964 /*! Moves viewing position beside selected layer and resizes it appropriately
00965         Don't need to set viewStateChanged here since the viewing angle is
00966         outside of the main list. */
00967 void NetworkViewer::zoomToLayer(unsigned int layerID){
00968         if(layerID == 0)
00969                 viewClippingVolume_Horizontal(defaultClippingVol);
00970         else{
00971                 NeuronGroupHolder *tempNeurGrpHolder = neuronGrpMap[layerID];
00972                 viewClippingVolume_Horizontal(tempNeurGrpHolder->clippingVolume);
00973         }
00974         updateGL();
00975 }
00976 
00977 
00978 //--------------------------------------------------------------------------------------
00979 //------------------- PROTECTED METHODS INHERITED FROM QGLWidget  ----------------------
00980 //--------------------------------------------------------------------------------------
00981 
00982 /*! Sets up the rendering context. */
00983 void NetworkViewer::initializeGL(){
00984         //Check progress bar has been set
00985         if(renderProgressBar == NULL){
00986                 cerr<<"NetworkViewer: RENDER PROGRESS BAR HAS NOT BEEN SET!"<<endl;
00987                 QMessageBox::critical( 0, "Error", "Render progress bar has not been set.");
00988                 return;
00989         }
00990 
00991         if(fullRenderMode)
00992                 initialiseFullRender();
00993 
00994         //White background
00995         glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
00996 
00997         //Create a unique id for the main display list
00998         mainDisplayList = glGenLists(1);
00999 }
01000 
01001 
01002 /*! Draw the scene. */
01003 void NetworkViewer::paintGL(){
01004         if(paintingGL){
01005                 #ifdef RENDER_DEBUG
01006                         cout<<"RENDER IN PROGRESS, RETURNING"<<endl;
01007                         cout.flush();
01008                 #endif//RENDER_DEBUG
01009                 paintSkipped = true;
01010                 return;
01011         }
01012 
01013         paintSkipped = false;
01014 
01015         /* Record that painting is in process so that accelerator keys can be filtered out */
01016         paintingGL = true;
01017 
01018         /* SpikeStreamApplication records the time at which the render starts so that
01019                 it can filter out accelerator keys pressed during the render. */
01020         spikeStrApp->startRender();
01021 
01022         #ifdef RENDER_DEBUG
01023                 cout<<"RENDER STARTED"<<endl;
01024                 cout.flush();
01025         #endif//RENDER_DEBUG
01026 
01027         //Reset the cancel render
01028         cancelRender = false;
01029 
01030         // Clear the window with current clearing color and store matrix state
01031     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
01032     glPushMatrix();
01033         
01034         //Point camera towards position specified in struct for camera
01035         gluLookAt(
01036                 //Location defined by fourth column of camera matrix
01037                 cameraMatrix[12], cameraMatrix[13], cameraMatrix[14],
01038                 //Forward is the Y axis so add this to position
01039                 (cameraMatrix[12] + cameraMatrix[4]), (cameraMatrix[13] + cameraMatrix[5]), (cameraMatrix[14] + cameraMatrix[6]),
01040                 //Up is the Z axis
01041                 cameraMatrix[8], cameraMatrix[9], cameraMatrix[10]
01042         );
01043                 
01044         //Rotate scene
01045         glRotatef(sceneRotateX, 1.0f, 0.0f, 0.0f);
01046         glRotatef(sceneRotateZ, 0.0f, 0.0f, 1.0f);
01047         
01048         // Draw the axes
01049         drawAxes();
01050         
01051         //Clear the maps to hold the ids of the neurons connecting from and to the single neuron
01052         if(neuronConnectionMode){
01053                 fromNeuronMap.clear();
01054                 toNeuronMap.clear();
01055         }
01056 
01057         /* Use an existing display list if one has already been created
01058                 Only use display lists when not in full render mode. They speed up
01059                 the graphics considerably, but crash when they are too big. */
01060         PerformanceTimer perfTimer;
01061         if(!viewStateChanged && !fullRender){
01062                 #ifdef RENDER_DEBUG
01063                         perfTimer.start("DISPLAY LIST RENDER");//Time the render
01064                 #endif//RENDER_DEBUG
01065 
01066                 //Call the display list
01067                 glCallList(mainDisplayList);
01068 
01069                 #ifdef RENDER_DEBUG
01070                         perfTimer.printTime();//Display duration of render
01071                 #endif//RENDER_DEBUG
01072 
01073                 //Painting has finished, can now process the next accelerator key
01074                 paintingGL = false;
01075 
01076                 //Record time at which render has stopped
01077                 spikeStrApp->stopRender();
01078 
01079                 //Check for OpenGL errors
01080                 checkOpenGLErrors();
01081 
01082                 #ifdef RENDER_DEBUG
01083                         cout<<"RENDER STOPPED, CHECKED FOR ERRORS"<<endl;
01084                         cout.flush();
01085                 #endif//RENDER_DEBUG
01086                 return;
01087         }
01088         
01089 
01090         /* No existing list, so need to redraw graphics into the display list
01091                 Only do this when not in full render mode to avoid memory problems */
01092         if(!fullRender){
01093                 //Start recording new display list
01094                 glNewList(mainDisplayList, GL_COMPILE_AND_EXECUTE);
01095 
01096                 #ifdef RENDER_DEBUG
01097                         perfTimer.start("COMPLETE RENDER STORING LIST");
01098                 #endif//RENDER_DEBUG
01099         }
01100         else{
01101                 #ifdef RENDER_DEBUG
01102                         perfTimer.start("COMPLETE RENDER NOT STORING LIST");
01103                 #endif//RENDER_DEBUG
01104         }
01105         
01106         //============================
01107         //    DRAW THE CONNECTIONS 
01108         //============================
01109         if(drawConnections){
01110                 //Set connection colour to blue
01111                 glColor3f(0.0f, 0.0f, 1.0f);
01112                 
01113                 //NeuronConnectionMode: ON: Connections to a single neuron will be displayed
01114                 if(neuronConnectionMode){
01115                         //Work through all the neuron groups listed in the view vector
01116                         //Only draw those which match the neuron ID
01117                         //Filter all connections not between minWeight and maxWeight
01118                         if(neuronFilterMode){
01119                                 vector<unsigned int>::iterator connGroupIter;
01120                                 for(connGroupIter = connectionViewVector.begin(); connGroupIter != connectionViewVector.end(); ++connGroupIter){
01121                                         fromNeuronIDPtr = connectionGrpMap[*connGroupIter]->fromNeuronIDArray;
01122                                         fromXPtr = connectionGrpMap[*connGroupIter]->fromXArray;
01123                                         fromYPtr = connectionGrpMap[*connGroupIter]->fromYArray;
01124                                         fromZPtr = connectionGrpMap[*connGroupIter]->fromZArray;
01125                                         toNeuronIDPtr = connectionGrpMap[*connGroupIter]->toNeuronIDArray;
01126                                         toXPtr = connectionGrpMap[*connGroupIter]->toXArray;
01127                                         toYPtr = connectionGrpMap[*connGroupIter]->toYArray;
01128                                         toZPtr = connectionGrpMap[*connGroupIter]->toZArray;
01129                                         weightPtr = connectionGrpMap[*connGroupIter]->weightArray;
01130 
01131                                         //Set up progress bar for rendering
01132                                         if(fullRender){
01133                                                 renderProgressBar->reset();
01134                                                 renderProgressBar->setTotalSteps(connectionGrpMap[*connGroupIter]->numberOfConnections);
01135                                                 ((NetworkViewerProperties*)networkViewerProperties)->setRenderProgressLabel("Rendering connection group " + QString::number(*connGroupIter));
01136                                         }
01137 
01138                                         glBegin(GL_LINES);
01139                                                 for(unsigned int i=0; i<connectionGrpMap[*connGroupIter]->numberOfConnections; ++i){
01140                                                         //Show connections between the two specified neurons
01141                                                         if(showBetweenConnections){
01142                                                                 if( (firstSingleNeuronID == *fromNeuronIDPtr && secondSingleNeuronID == *toNeuronIDPtr) || (secondSingleNeuronID == *fromNeuronIDPtr && firstSingleNeuronID == *toNeuronIDPtr) ){
01143                                                                         if((*weightPtr <= maxWeight) && (*weightPtr >= minWeight)){
01144                                                                                 
01145                                                                                 //Store a list of the to neuron IDs if only from connections are showing
01146                                                                                 if(showFromConnections && !showToConnections){
01147                                                                                         toNeuronMap[*toNeuronIDPtr] = true;
01148                                                                                 }
01149                                                                                 //Store a list of the from neuron IDs if only to connections are showing
01150                                                                                 else if(showToConnections && !showFromConnections){
01151                                                                                         fromNeuronMap[*fromNeuronIDPtr] = true;
01152                                                                                 }
01153                                                                                 
01154                                                                                 //Set the colour of the connection
01155                                                                                 if(*weightPtr >= 0)
01156                                                                                         glColor3f(POSITIVE_CONNECTION_COLOUR);
01157                                                                                 else
01158                                                                                         glColor3f(NEGATIVE_CONNECTION_COLOUR);
01159                                                                                         
01160                                                                                 //Draw the connection
01161                                                                                 glVertex3f(*fromXPtr, *fromYPtr, *fromZPtr);
01162                                                                                 glVertex3f(*toXPtr, *toYPtr, *toZPtr);
01163                                                                         }
01164                                                                 }
01165                                                         }
01166                                                         //Only draw connections to selected neuron
01167                                                         else if(((firstSingleNeuronID == *fromNeuronIDPtr) && showFromConnections) || ((firstSingleNeuronID == *toNeuronIDPtr) && showToConnections)){
01168                                                                 if((*weightPtr <= maxWeight) && (*weightPtr >= minWeight)){
01169                                                                         
01170                                                                         //Store a list of the to neuron IDs if only from connections are showing
01171                                                                         if(showFromConnections && !showToConnections){
01172                                                                                 toNeuronMap[*toNeuronIDPtr] = true;
01173                                                                         }
01174                                                                         //Store a list of the from neuron IDs if only to connections are showing
01175                                                                         else if(showToConnections && !showFromConnections){
01176                                                                                 fromNeuronMap[*fromNeuronIDPtr] = true;
01177                                                                         }
01178                                                                         
01179                                                                         //Set the colour of the connection
01180                                                                         if(*weightPtr >= 0)
01181                                                                                 glColor3f(POSITIVE_CONNECTION_COLOUR);
01182                                                                         else
01183                                                                                 glColor3f(NEGATIVE_CONNECTION_COLOUR);
01184                                                                                 
01185                                                                         //Draw the connection
01186                                                                         glVertex3f(*fromXPtr, *fromYPtr, *fromZPtr);
01187                                                                         glVertex3f(*toXPtr, *toYPtr, *toZPtr);
01188                                                                 }
01189                                                         }
01190                                                         ++fromNeuronIDPtr;
01191                                                         ++fromXPtr;
01192                                                         ++fromYPtr;
01193                                                         ++fromZPtr;
01194                                                         ++toNeuronIDPtr;
01195                                                         ++toXPtr;
01196                                                         ++toYPtr;
01197                                                         ++toZPtr;
01198                                                         ++weightPtr;
01199 
01200                                                         //Update progress bar in full render mode
01201                                                         if(fullRender){
01202                                                                 //Update progress bar and check for cancellation
01203                                                                 if(i % 1000 == 0){
01204                                                                         renderProgressBar->setProgress(i);
01205                                                                         spikeStrApp->processEvents();
01206                                                                         if(cancelRender)
01207                                                                         break;
01208                                                                 }
01209                                                         }
01210                                                 }
01211                                         glEnd();
01212                                 }
01213                         }
01214                         //Neuron filter mode is off.
01215                         //Draw all selected connection groups that connect to this neuron
01216                         else{
01217                                 vector<unsigned int>::iterator connGroupIter;
01218                                 for(connGroupIter = connectionViewVector.begin(); connGroupIter != connectionViewVector.end(); ++connGroupIter){
01219                                         fromNeuronIDPtr = connectionGrpMap[*connGroupIter]->fromNeuronIDArray;
01220                                         fromXPtr = connectionGrpMap[*connGroupIter]->fromXArray;
01221                                         fromYPtr = connectionGrpMap[*connGroupIter]->fromYArray;
01222                                         fromZPtr = connectionGrpMap[*connGroupIter]->fromZArray;
01223                                         toNeuronIDPtr = connectionGrpMap[*connGroupIter]->toNeuronIDArray;
01224                                         toXPtr = connectionGrpMap[*connGroupIter]->toXArray;
01225                                         toYPtr = connectionGrpMap[*connGroupIter]->toYArray;
01226                                         toZPtr = connectionGrpMap[*connGroupIter]->toZArray;
01227                                         weightPtr = connectionGrpMap[*connGroupIter]->weightArray;
01228 
01229                                         //Set up progress bar for rendering
01230                                         if(fullRender){
01231                                                 renderProgressBar->reset();
01232                                                 renderProgressBar->setTotalSteps(connectionGrpMap[*connGroupIter]->numberOfConnections);
01233                                                 ((NetworkViewerProperties*)networkViewerProperties)->setRenderProgressLabel("Rendering connection group " + QString::number(*connGroupIter));
01234                                         }
01235 
01236                                         glBegin(GL_LINES);
01237                                                 for(unsigned int i=0; i<connectionGrpMap[*connGroupIter]->numberOfConnections; ++i){
01238                                                         if(showBetweenConnections){
01239                                                                 if( (firstSingleNeuronID == *fromNeuronIDPtr && secondSingleNeuronID == *toNeuronIDPtr) || (secondSingleNeuronID == *fromNeuronIDPtr && firstSingleNeuronID == *toNeuronIDPtr) ){
01240                                                                         if(*weightPtr >= 0)
01241                                                                                 glColor3f(POSITIVE_CONNECTION_COLOUR);
01242                                                                         else
01243                                                                                 glColor3f(NEGATIVE_CONNECTION_COLOUR);
01244                                                                         glVertex3f(*fromXPtr, *fromYPtr, *fromZPtr);
01245                                                                         glVertex3f(*toXPtr, *toYPtr, *toZPtr);
01246                                                                 }
01247 
01248                                                         }
01249                                                         //Only draw connections to selected neuron
01250                                                         else if((firstSingleNeuronID == *fromNeuronIDPtr) || (firstSingleNeuronID == *toNeuronIDPtr)){
01251                                                                 if(*weightPtr >= 0)
01252                                                                         glColor3f(POSITIVE_CONNECTION_COLOUR);
01253                                                                 else
01254                                                                         glColor3f(NEGATIVE_CONNECTION_COLOUR);
01255                                                                 glVertex3f(*fromXPtr, *fromYPtr, *fromZPtr);
01256                                                                 glVertex3f(*toXPtr, *toYPtr, *toZPtr);
01257                                                         }
01258                                                         ++fromNeuronIDPtr;
01259                                                         ++fromXPtr;
01260                                                         ++fromYPtr;
01261                                                         ++fromZPtr;
01262                                                         ++toNeuronIDPtr;
01263                                                         ++toXPtr;
01264                                                         ++toYPtr;
01265                                                         ++toZPtr;
01266                                                         ++weightPtr;
01267 
01268                                                         //Update progress bar in full render mode
01269                                                         if(fullRender){
01270                                                                 //Update progress bar and check for cancellation
01271                                                                 if(i % 1000 == 0){
01272                                                                         renderProgressBar->setProgress(i);
01273                                                                         spikeStrApp->processEvents();
01274                                                                         if(cancelRender)
01275                                                                         break;
01276                                                                 }
01277                                                         }
01278                                                         else{//Filter out events during render
01279                                                                 if(i % 1000 == 0){
01280                                                                         spikeStrApp->processEvents();
01281                                                                 }
01282                                                         }
01283                                                 }
01284                                         glEnd();
01285                                 }
01286                         }
01287                 }
01288                 else{//Draw connections to all neurons or to all highlighted neurons in highlight mode
01289                         //Work through all the neuron groups listed in the view vector
01290                         vector<unsigned int>::iterator connGroupIter;
01291                         for(connGroupIter = connectionViewVector.begin(); connGroupIter != connectionViewVector.end(); ++connGroupIter){
01292                                 fromNeuronIDPtr = connectionGrpMap[*connGroupIter]->fromNeuronIDArray;
01293                                 fromXPtr = connectionGrpMap[*connGroupIter]->fromXArray;
01294                                 fromYPtr = connectionGrpMap[*connGroupIter]->fromYArray;
01295                                 fromZPtr = connectionGrpMap[*connGroupIter]->fromZArray;
01296                                 toNeuronIDPtr = connectionGrpMap[*connGroupIter]->toNeuronIDArray;
01297                                 toXPtr = connectionGrpMap[*connGroupIter]->toXArray;
01298                                 toYPtr = connectionGrpMap[*connGroupIter]->toYArray;
01299                                 toZPtr = connectionGrpMap[*connGroupIter]->toZArray;
01300                                 weightPtr = connectionGrpMap[*connGroupIter]->weightArray;
01301 
01302                                 //Set up progress bar for rendering
01303                                 if(fullRender){
01304                                         renderProgressBar->reset();
01305                                         renderProgressBar->setTotalSteps(connectionGrpMap[*connGroupIter]->numberOfConnections);
01306                                         ((NetworkViewerProperties*)networkViewerProperties)->setRenderProgressLabel("Rendering connection group " + QString::number(*connGroupIter));
01307                                 }
01308 
01309                                 glBegin(GL_LINES);
01310                                         for(unsigned int i=0; i < connectionGrpMap[*connGroupIter]->numberOfConnections; ++i){
01311                                                 if(*weightPtr >= 0)
01312                                                         glColor3f(POSITIVE_CONNECTION_COLOUR);
01313                                                 else
01314                                                         glColor3f(NEGATIVE_CONNECTION_COLOUR);
01315                                                 if(highlightMode){
01316                                                         if(highlightNeuronMap.count(*fromNeuronIDPtr) && highlightNeuronMap.count(*toNeuronIDPtr)){
01317                                                                 glVertex3f(*fromXPtr, *fromYPtr, *fromZPtr);
01318                                                                 glVertex3f(*toXPtr, *toYPtr, *toZPtr);
01319                                                         }
01320                                                 }
01321                                                 else{
01322                                                         glVertex3f(*fromXPtr, *fromYPtr, *fromZPtr);
01323                                                         glVertex3f(*toXPtr, *toYPtr, *toZPtr);
01324                                                 }
01325                                                 ++fromNeuronIDPtr;
01326                                                 ++fromXPtr;
01327                                                 ++fromYPtr;
01328                                                 ++fromZPtr;
01329                                                 ++toNeuronIDPtr;
01330                                                 ++toXPtr;
01331                                                 ++toYPtr;
01332                                                 ++toZPtr;
01333                                                 ++weightPtr;
01334 
01335                                                 //Update progress bar in full render mode
01336                                                 if(fullRender){
01337                                                         //Update progress bar and check for cancellation
01338                                                         if(i % 1000 == 0){
01339                                                                 renderProgressBar->setProgress(i);
01340                                                                 spikeStrApp->processEvents();
01341                                                                 if(cancelRender)
01342                                                                 break;
01343                                                         }
01344                                                 }
01345                                         }
01346                                 glEnd();
01347                         }
01348                 }
01349         }
01350         
01351                 
01352         //============================
01353         //     DRAW THE NEURONS 
01354         //============================
01355         /* This can be done in outline or full render.
01356                 Separate sections of code are used to draw neurons depending on whether the 
01357                 singleNeuronConnection mode is on. This is to prevent unnecessary if statements 
01358                 within parts of the code that need to run as quickly as possible
01359         */
01360         //DRAW NEURONS AS SPHERES WITH LIGHTING EFFECTS
01361         if(fullRender && !cancelRender){
01362                 //Create iterator to work through visible layers
01363                 vector<unsigned int>::iterator layerViewIter;
01364                 
01365                 // HIGHLIGHT SINGLE NEURON IN RED
01366                 if(neuronConnectionMode){//This highlights a single neuron in red
01367                         //Work through the neuron groups listed in the view vector
01368                         for(layerViewIter = layerViewVector.begin(); layerViewIter != layerViewVector.end(); ++layerViewIter){
01369                                 neuronIDPtr = neuronGrpMap[*layerViewIter]->neuronIDArray;
01370                                 xPosPtr = neuronGrpMap[*layerViewIter]->xPosArray;
01371                                 yPosPtr = neuronGrpMap[*layerViewIter]->yPosArray;
01372                                 zPosPtr = neuronGrpMap[*layerViewIter]->zPosArray;
01373 
01374                                 //Set up progress bar and label for rendering
01375                                 renderProgressBar->reset();
01376                                 renderProgressBar->setTotalSteps(neuronGrpMap[*layerViewIter]->numberOfNeurons);
01377                                 ((NetworkViewerProperties*)networkViewerProperties)->setRenderProgressLabel("Rendering neuron group " + QString::number(*layerViewIter));
01378 
01379                                 for(unsigned int i=0; i<neuronGrpMap[*layerViewIter]->numberOfNeurons; ++i){
01380                                         glPushMatrix();//Store current state of matrix
01381                                         glTranslatef(*xPosPtr, *yPosPtr, *zPosPtr);//Translate to sphere position
01382                                         if(*neuronIDPtr == firstSingleNeuronID)
01383                                                 glColor3f(HIGHLIGHT_FIRST_NEURON_COLOUR_FULL);
01384                                         else if(*neuronIDPtr == secondSingleNeuronID && showBetweenConnections)
01385                                                 glColor3f(HIGHLIGHT_SECOND_NEURON_COLOUR_FULL);
01386                                         else if(fromNeuronMap[*neuronIDPtr])//Paint neurons connecting from themselves to this neuron a differnt colour
01387                                                 glColor3f(CONNECTED_NEURON_COLOUR);
01388                                         else if(toNeuronMap[*neuronIDPtr])
01389                                                 glColor3f(CONNECTED_NEURON_COLOUR);
01390                                         else if(highlightMode && highlightNeuronMap.count(*neuronIDPtr))
01391                                                 glColor3f(highlightNeuronMap[*neuronIDPtr]->red, highlightNeuronMap[*neuronIDPtr]->green, highlightNeuronMap[*neuronIDPtr]->blue);
01392                                         else
01393                                                 glColor3f(DEFAULT_NEURON_COLOUR_FULL);
01394                                         drawSolidSphere(0.1f, 21, 11);
01395                                         glPopMatrix();
01396                                         ++neuronIDPtr;
01397                                         ++xPosPtr;
01398                                         ++yPosPtr;
01399                                         ++zPosPtr;
01400 
01401                                         //Update progress bar and check for cancellation
01402                                         if(i % 1000 == 0){
01403                                                 renderProgressBar->setProgress(i);
01404                                                 spikeStrApp->processEvents();
01405                                                 if(cancelRender)
01406                                                         break;
01407                                         }
01408                                 }
01409                         }
01410                 }
01411                 
01412                 // PAINT ALL NEURONS THE SAME COLOUR
01413                 else if(!cancelRender){
01414                         //Work through the neuron groups listed in the view vector
01415                         for(layerViewIter = layerViewVector.begin(); (layerViewIter != layerViewVector.end()) && !cancelRender; ++layerViewIter){
01416                                 xPosPtr = neuronGrpMap[*layerViewIter]->xPosArray;
01417                                 yPosPtr = neuronGrpMap[*layerViewIter]->yPosArray;
01418                                 zPosPtr = neuronGrpMap[*layerViewIter]->zPosArray;
01419 
01420                                 //Set up progress bar and label for rendering
01421                                 renderProgressBar->reset();
01422                                 renderProgressBar->setTotalSteps(neuronGrpMap[*layerViewIter]->numberOfNeurons);
01423                                 ((NetworkViewerProperties*)networkViewerProperties)->setRenderProgressLabel("Rendering neuron group " + QString::number(*layerViewIter));
01424 
01425                                 if(highlightMode){
01426                                         neuronIDPtr = neuronGrpMap[*layerViewIter]->neuronIDArray;
01427                                         for(unsigned int i=0; i<neuronGrpMap[*layerViewIter]->numberOfNeurons; ++i){
01428                                                 glPushMatrix();//Store current state of matrix
01429                                                 glTranslatef(*xPosPtr, *yPosPtr, *zPosPtr);//Translate to sphere position
01430                                                 if(highlightMode && highlightNeuronMap.count(*neuronIDPtr))
01431                                                         glColor3f(highlightNeuronMap[*neuronIDPtr]->red, highlightNeuronMap[*neuronIDPtr]->green, highlightNeuronMap[*neuronIDPtr]->blue);
01432                                                 else
01433                                                         glColor3f(DEFAULT_NEURON_COLOUR_FULL);
01434                                                 drawSolidSphere(0.1f, 21, 11);
01435                                                 glPopMatrix();
01436                                                 ++neuronIDPtr;
01437                                                 ++xPosPtr;
01438                                                 ++yPosPtr;
01439                                                 ++zPosPtr;
01440         
01441                                                 if(i % 1000 == 0){
01442                                                         renderProgressBar->setProgress(i);
01443                                                         spikeStrApp->processEvents();
01444                                                         if(cancelRender)
01445                                                                 break;
01446                                                 }
01447                                         }
01448                                 }
01449                                 else{
01450                                         //Set drawing colour to default
01451                                         glColor3f(DEFAULT_NEURON_COLOUR_FULL);
01452                                         for(unsigned int i=0; i<neuronGrpMap[*layerViewIter]->numberOfNeurons; ++i){
01453                                                 glPushMatrix();//Store current state of matrix
01454                                                 glTranslatef(*xPosPtr, *yPosPtr, *zPosPtr);//Translate to sphere position
01455                                                 drawSolidSphere(0.1f, 21, 11);
01456                                                 glPopMatrix();
01457                                                 ++xPosPtr;
01458                                                 ++yPosPtr;
01459                                                 ++zPosPtr;
01460         
01461                                                 if(i % 1000 == 0){
01462                                                         renderProgressBar->setProgress(i);
01463                                                         spikeStrApp->processEvents();
01464                                                         if(cancelRender)
01465                                                                 break;
01466                                                 }
01467                                         }
01468                                 }
01469                         }
01470                 }
01471 
01472                 //Finish off render bar information
01473                 renderProgressBar->setProgress(renderProgressBar->totalSteps());
01474                 ((NetworkViewerProperties*)networkViewerProperties)->setRenderProgressLabel("Render complete");
01475                 spikeStrApp->processEvents();
01476         }
01477 
01478         //DRAW NEURONS AS VERTICES
01479         else{
01480                 vector<unsigned int>::iterator layerViewIter;
01481                 
01482                 //NEURONCONNECTIONMODE ON: HIGHLIGHT SINGLE NEURON
01483                 if(neuronConnectionMode){
01484                 
01485                         //FILTERMODE ON: ONLY SHOW NEURONS WHOSE CONNECTIONS MATCH THE FILTER CRITERIA
01486                         if(neuronFilterMode){
01487                                 for(layerViewIter = layerViewVector.begin(); layerViewIter != layerViewVector.end(); ++layerViewIter){
01488                                         neuronIDPtr = neuronGrpMap[*layerViewIter]->neuronIDArray;
01489                                         xPosPtr = neuronGrpMap[*layerViewIter]->xPosArray;
01490                                         yPosPtr = neuronGrpMap[*layerViewIter]->yPosArray;
01491                                         zPosPtr = neuronGrpMap[*layerViewIter]->zPosArray;
01492                                         glPointSize(5.0f);
01493                                         glBegin(GL_POINTS);
01494                                                 for(unsigned int i=0; i<neuronGrpMap[*layerViewIter]->numberOfNeurons; ++i){
01495                                                         if(*neuronIDPtr == firstSingleNeuronID)
01496                                                                 glColor3f(HIGHLIGHT_FIRST_NEURON_COLOUR_OUTLINE);
01497                                                         else if(*neuronIDPtr == secondSingleNeuronID && showBetweenConnections)
01498                                                                 glColor3f(HIGHLIGHT_SECOND_NEURON_COLOUR_OUTLINE);
01499                                                         else if(fromNeuronMap[*neuronIDPtr])//Paint neurons connecting from themselves to this neuron a differnt colour
01500                                                                 glColor3f(CONNECTED_NEURON_COLOUR);
01501                                                         else if(toNeuronMap[*neuronIDPtr])
01502                                                                 glColor3f(CONNECTED_NEURON_COLOUR);
01503                                                         else if(highlightMode && highlightNeuronMap.count(*neuronIDPtr))//Highlight mode
01504                                                                 glColor3f(highlightNeuronMap[*neuronIDPtr]->red, highlightNeuronMap[*neuronIDPtr]->green, highlightNeuronMap[*neuronIDPtr]->blue);
01505                                                         else
01506                                                                 glColor3f(DEFAULT_NEURON_COLOUR_OUTLINE);
01507                                                         glVertex3f(*xPosPtr, *yPosPtr, *zPosPtr);
01508                                                         ++neuronIDPtr;
01509                                                         ++xPosPtr;
01510                                                         ++yPosPtr;
01511                                                         ++zPosPtr;
01512                                                 }
01513                                         glEnd();
01514                                 }
01515                         }
01516                         
01517                         //FILTERMODE OFF: DRAW ALL NEURONS CONNECTED TO THE HIGHLIGHTED NEURON
01518                         else{
01519                                 for(layerViewIter = layerViewVector.begin(); layerViewIter != layerViewVector.end(); ++layerViewIter){
01520                                         neuronIDPtr = neuronGrpMap[*layerViewIter]->neuronIDArray;
01521                                         xPosPtr = neuronGrpMap[*layerViewIter]->xPosArray;
01522                                         yPosPtr = neuronGrpMap[*layerViewIter]->yPosArray;
01523                                         zPosPtr = neuronGrpMap[*layerViewIter]->zPosArray;
01524                                         glPointSize(5.0f);
01525                                         glBegin(GL_POINTS);
01526                                                 for(unsigned int i=0; i<neuronGrpMap[*layerViewIter]->numberOfNeurons; ++i){
01527                                                         if(*neuronIDPtr == firstSingleNeuronID)
01528                                                                 glColor3f(HIGHLIGHT_FIRST_NEURON_COLOUR_OUTLINE);
01529                                                         else if(*neuronIDPtr == secondSingleNeuronID && showBetweenConnections)
01530                                                                 glColor3f(HIGHLIGHT_SECOND_NEURON_COLOUR_OUTLINE);
01531                                                         else if(highlightMode && highlightNeuronMap.count(*neuronIDPtr))//Highlight mode
01532                                                                 glColor3f(highlightNeuronMap[*neuronIDPtr]->red, highlightNeuronMap[*neuronIDPtr]->green, highlightNeuronMap[*neuronIDPtr]->blue);
01533                                                         else
01534                                                                 glColor3f(DEFAULT_NEURON_COLOUR_OUTLINE);
01535                                                         glVertex3f(*xPosPtr, *yPosPtr, *zPosPtr);
01536                                                         ++neuronIDPtr;
01537                                                         ++xPosPtr;
01538                                                         ++yPosPtr;
01539                                                         ++zPosPtr;
01540                                                 }
01541                                         glEnd();
01542                                 }
01543                         }
01544                 }
01545                 
01546                 //NEURONCONNECTIONMODE OFF: DRAW ALL NEURONS THE SAME COLOUR
01547                 else{
01548                         //Work through the neuron groups listed in the view vector
01549                         for(layerViewIter = layerViewVector.begin(); layerViewIter != layerViewVector.end(); ++layerViewIter){
01550                                 xPosPtr = neuronGrpMap[*layerViewIter]->xPosArray;
01551                                 yPosPtr = neuronGrpMap[*layerViewIter]->yPosArray;
01552                                 zPosPtr = neuronGrpMap[*layerViewIter]->zPosArray;
01553                                 glPointSize(5.0f);
01554                                 glBegin(GL_POINTS);
01555                                         if(highlightMode){
01556                                                 neuronIDPtr = neuronGrpMap[*layerViewIter]->neuronIDArray;
01557                                                 for(unsigned int i=0; i<neuronGrpMap[*layerViewIter]->numberOfNeurons; ++i){
01558                                                         if(highlightNeuronMap.count(*neuronIDPtr))
01559                                                                 glColor3f(highlightNeuronMap[*neuronIDPtr]->red, highlightNeuronMap[*neuronIDPtr]->green, highlightNeuronMap[*neuronIDPtr]->blue);
01560                                                         else
01561                                                                 glColor3f(DEFAULT_NEURON_COLOUR_OUTLINE);
01562                                                         glVertex3f(*xPosPtr, *yPosPtr, *zPosPtr);
01563                                                         ++neuronIDPtr;
01564                                                         ++xPosPtr;
01565                                                         ++yPosPtr;
01566                                                         ++zPosPtr;
01567                                                 }
01568                                         }
01569                                         else{
01570                                                 //Set drawing Colour to default
01571                                                 glColor3f(DEFAULT_NEURON_COLOUR_OUTLINE);
01572                                                 for(unsigned int i=0; i<neuronGrpMap[*layerViewIter]->numberOfNeurons; ++i){
01573                                                         glVertex3f(*xPosPtr, *yPosPtr, *zPosPtr);
01574                                                         ++xPosPtr;
01575                                                         ++yPosPtr;
01576                                                         ++zPosPtr;
01577                                                 }
01578                                         }
01579                                 glEnd();
01580                         }
01581                 }
01582         }
01583         
01584         //Restore the original state of the matrix
01585     glPopMatrix();
01586 
01587         //End of display list
01588         if(!fullRender){
01589                 glEndList();
01590         }
01591         #ifdef RENDER_DEBUG
01592                 perfTimer.printTime();
01593         #endif//RENDER_DEBUG
01594 
01595         //Have now created the display list so set viewStateChanged to false
01596         viewStateChanged = false;
01597 
01598         //Painting has finished, can now process the next accelerator key
01599         paintingGL = false;
01600 
01601         //Record time at which render stops to filter keyboard events during render
01602         spikeStrApp->stopRender();
01603 
01604         //Check for OpenGL errors
01605         checkOpenGLErrors();
01606 
01607         #ifdef RENDER_DEBUG
01608                 cout<<"RENDER STOPPED, CHECKED FOR ERRORS"<<endl;
01609                 cout.flush();
01610         #endif//RENDER_DEBUG
01611 
01612         /* If during the render, start render or resize were called and 
01613                 filtered out, need to re-render. */
01614         if(resizeSkipped){
01615                 resizeGL(newTempScreenWidth, newTempScreenHeight);
01616                 paintSkipped = true;
01617         }
01618         if(paintSkipped){
01619                 paintGL();
01620         }
01621 }
01622 
01623 
01624 /*! Called when the window is resized. Recalculates the viewport and clipping volume. */
01625 void NetworkViewer::resizeGL(int screenWidth, int screenHeight){
01626         if(paintingGL){
01627                 resizeSkipped = true;
01628         
01629                 //Store new screen width and height
01630                 newTempScreenWidth = screenWidth;
01631                 newTempScreenHeight = screenHeight;
01632                 return;
01633         }
01634 
01635         //Reset resizeSkipped
01636         resizeSkipped = false;
01637 
01638     // Prevent a divide by zero, when window is too short
01639     // (you cant make a window of zero width).
01640     if(screenHeight == 0)
01641         screenHeight = 1;
01642 
01643     glViewport(0, 0, screenWidth, screenHeight);
01644 
01645     // Reset the coordinate system before modifying
01646     glMatrixMode(GL_PROJECTION);
01647     glLoadIdentity();
01648         
01649     // Set the clipping volume
01650         GLfloat aspectRatio = (GLfloat)screenWidth / (GLfloat)screenHeight;     
01651         gluPerspective(perspective_angle, aspectRatio, perspective_near, perspective_far);
01652 
01653     glMatrixMode(GL_MODELVIEW);
01654     glLoadIdentity();
01655         
01656         //Check for errors
01657         checkOpenGLErrors();
01658 }
01659 
01660 
01661 //----------------------------------------------------------------------------------------------
01662 //----------------------------------------- SLOTS ----------------------------------------------
01663 //----------------------------------------------------------------------------------------------
01664 
01665 /*! Changes the viewpoint depending on which keys are pressed. 
01666         Controls movement around the 3D environment. */
01667 void NetworkViewer::acceleratorKeyPressed (int acceleratorID){
01668         /* Do not want to process accelerator key events triggered by spikeStrApp->processEvents()
01669                 whilst the full render is working since this can break out of the display list loop
01670                 and cause openGL errors.*/
01671         if(paintingGL)
01672                 return;
01673 
01674         //Disable full render. Do not want full render whilst the camera is moving.
01675         renderTimer->stop();//Do not want an earlier timing event to switch full render back on
01676         if(fullRenderMode && fullRender)
01677                 disableFullRender();
01678         
01679         //Get the key sequence
01680         int keySequence = keyboardAccelerator->key(acceleratorID);
01681         
01682         //Do different types of movement etc. depending on the key sequence
01683         switch(keySequence){
01684                 //CTRL + arrow keys rotates scene around X and Z axis
01685                 case (CTRL + Key_Up)://Rotates scene around X axis
01686                         sceneRotateX += 2.5f;
01687                 break;
01688                 case (CTRL + Key_Down)://Rotates scene around X axis
01689                         sceneRotateX -= 2.5f;
01690                 break;
01691                 case (CTRL + Key_Left)://Rotates scene around Z axis
01692                         sceneRotateZ += 2.5f;
01693                 break;
01694                 case(CTRL + Key_Right)://Rotates scene around Z axis
01695                         sceneRotateZ -= 2.5f;
01696                 break;
01697                 
01698                 //CTRL + Equal and Minus keys moves forward and backwards
01699                 //Moves forward from current position
01700                 //Y axis is forward direction so add Y vector to position
01701                 case(CTRL + Key_Equal):
01702                         cameraMatrix[12] += cameraMatrix[4];
01703                         cameraMatrix[13] += cameraMatrix[5];
01704                         cameraMatrix[14] += cameraMatrix[6];
01705                 break;
01706                 case(CTRL + Key_Minus)://Moves backwards from current position
01707                         cameraMatrix[12] -= cameraMatrix[4];
01708                         cameraMatrix[13] -= cameraMatrix[5];
01709                         cameraMatrix[14] -= cameraMatrix[6];
01710                 break;
01711                 
01712                 //Resets the view to starting position
01713                 case(CTRL + Key_Y):
01714                         resetView();
01715                 break;
01716 
01717                 //SHIFT + arrow keys rotates camera position around X and Z axes
01718                 case (SHIFT + Key_Up):
01719                         rotateXAxis(0.1f);
01720                 break;
01721                 case (SHIFT + Key_Down):
01722                         rotateXAxis(-0.1f);
01723                 break;
01724                 case (SHIFT + Key_Left):
01725                         rotateZAxis(0.1f);
01726                 break;
01727                 case(SHIFT + Key_Right):
01728                         rotateZAxis(-0.1f);
01729                 break;
01730 
01731                 //ALT + arrow keys are used to change the single neuron whose connections are displayed. The arrows increase and decrease the X and Y values
01732                 /* Layers are created by filling up each Y direction (length) for each X (width) position.
01733                         The neuron ids are sequentially increased when the layer is created.
01734                         So, to move horizontally just add the length to the neuronID up to the total length
01735                         To move vertically, just add the width to the neuronID up to the total width
01736                         Need to explicitly create an int copy of singleNeuronID. Otherwise comparison can
01737                         become very large when it goes below zero
01738                 */
01739                 //Select a neuron further along X positive
01740                 case(ALT + Key_Right):
01741                         if(neuronConnectionMode){
01742                                 if(firstSingleNeurGrpID == 0)//Check that we are in the right mode and a first neuron group is loaded
01743                                         break;
01744                                 if((firstSingleNeuronID + 1 - minFirstSingleNeuronID) % firstSingleNeuronGroupWidth != 0){//New value is not starting a new column
01745                                         ++firstSingleNeuronID;
01746                                         ((NetworkViewerProperties*)networkViewerProperties)->setFirstSingleNeuronNumber(firstSingleNeuronID);
01747                                         viewStateChanged = true;
01748                                 }
01749                         }
01750                 break;
01751                 //Select a neuron further along X negative
01752                 case(ALT + Key_Left):
01753                         if(neuronConnectionMode){
01754                                 if(firstSingleNeurGrpID == 0)//Check that we are in the right mode and a first neuron group is loaded
01755                                         break;
01756                                 if((firstSingleNeuronID - minFirstSingleNeuronID) % firstSingleNeuronGroupWidth != 0){//Only move down if it is not at the bottom of a column
01757                                         firstSingleNeuronID--;
01758                                         ((NetworkViewerProperties*)networkViewerProperties)->setFirstSingleNeuronNumber(firstSingleNeuronID);
01759                                         viewStateChanged = true;
01760                                 }
01761                         }
01762                 break;
01763                 //Select a neuron further along Y positive
01764                 case(ALT + Key_Up):
01765                         if(neuronConnectionMode){
01766                                 if(firstSingleNeurGrpID == 0)//Check that we are in the right mode and a first neuron group is loaded
01767                                         break;
01768                                 if(firstSingleNeuronID + firstSingleNeuronGroupWidth <= maxFirstSingleNeuronID){
01769                                         firstSingleNeuronID += firstSingleNeuronGroupWidth;
01770                                         ((NetworkViewerProperties*)networkViewerProperties)->setFirstSingleNeuronNumber(firstSingleNeuronID);
01771                                         viewStateChanged = true;
01772                                 }
01773                         }
01774                 break;
01775                 //Select a neuron further along Y negative
01776                 case(ALT + Key_Down):
01777                         if(neuronConnectionMode){
01778                                 if(firstSingleNeurGrpID == 0)//Check that we are in the right mode and a first neuron group is loaded
01779                                         break;
01780                                 if(firstSingleNeuronID < firstSingleNeuronGroupWidth)//Integers are unsigned so a negative number will be very large
01781                                         break;
01782                                 if((firstSingleNeuronID - firstSingleNeuronGroupWidth) >= minFirstSingleNeuronID){
01783                                         firstSingleNeuronID -= firstSingleNeuronGroupWidth;
01784                                         ((NetworkViewerProperties*)networkViewerProperties)->setFirstSingleNeuronNumber(firstSingleNeuronID);
01785                                         viewStateChanged = true;
01786                                 }
01787                         }
01788                 break;
01789 
01790                 /* CTRL and ALT are used to control the position of the second neuron when selecting
01791                         all the connections between two neurons. */
01792                 //Select a neuron further along X positive
01793                 case(SHIFT + ALT + Key_Right):
01794                         if(neuronConnectionMode){
01795                                 if(secondSingleNeurGrpID == 0)//Check that we are in the right mode and a second neuron group is loaded
01796                                         break;
01797                                 if((secondSingleNeuronID + 1 - minSecondSingleNeuronID)% secondSingleNeuronGroupWidth != 0){//New value is not starting a new column
01798                                         ++secondSingleNeuronID;
01799                                         ((NetworkViewerProperties*)networkViewerProperties)->setSecondSingleNeuronNumber(secondSingleNeuronID);
01800                                         viewStateChanged = true;
01801                                 }
01802                         }
01803                 break;
01804                 //Select a neuron further along X negative
01805                 case(SHIFT + ALT + Key_Left):
01806                         if(neuronConnectionMode){
01807                                 if(secondSingleNeurGrpID == 0)//Check that we are in the right mode and a second neuron group is loaded
01808                                         break;
01809                                 if((secondSingleNeuronID - minSecondSingleNeuronID) % secondSingleNeuronGroupWidth != 0){//Only move down if it is not at the bottom of a column
01810                                         secondSingleNeuronID--;
01811                                         ((NetworkViewerProperties*)networkViewerProperties)->setSecondSingleNeuronNumber(secondSingleNeuronID);
01812                                         viewStateChanged = true;
01813                                 }
01814                         }
01815                 break;
01816                 //Select a neuron further along Y positive
01817                 case(SHIFT + ALT + Key_Up):
01818                         if(neuronConnectionMode){
01819                                 if(secondSingleNeurGrpID == 0)//Check that we are in the right mode and a second neuron group is loaded
01820                                         break;
01821                                 if(secondSingleNeuronID + secondSingleNeuronGroupWidth <= maxSecondSingleNeuronID){
01822                                         secondSingleNeuronID += secondSingleNeuronGroupWidth;
01823                                         ((NetworkViewerProperties*)networkViewerProperties)->setSecondSingleNeuronNumber(secondSingleNeuronID);
01824                                         viewStateChanged = true;
01825                                 }
01826                         }
01827                 break;
01828                 //Select a neuron further along Y negative
01829                 case(SHIFT + ALT + Key_Down):
01830                         if(neuronConnectionMode){
01831                                 if(secondSingleNeurGrpID == 0)//Check that we are in the right mode and a second neuron group is loaded
01832                                         break;
01833                                 if(secondSingleNeuronID < secondSingleNeuronGroupWidth)//Integers are unsigned, so this condition will create a large positive number
01834                                         break;
01835                                 if((secondSingleNeuronID - secondSingleNeuronGroupWidth) >= minSecondSingleNeuronID){
01836                                         secondSingleNeuronID -= secondSingleNeuronGroupWidth;
01837                                         ((NetworkViewerProperties*)networkViewerProperties)->setSecondSingleNeuronNumber(secondSingleNeuronID);
01838                                         viewStateChanged = true;
01839                                 }
01840                         }
01841                 break;
01842 
01843                 //Arrow keys without CTRL or SHIFT translate viewing position horizontally and vertically
01844                 //Move along Z and X axes defined in cameraMatrix
01845                 case (Key_Up):
01846                         cameraMatrix[12] += cameraMatrix[8];
01847                         cameraMatrix[13] += cameraMatrix[9];
01848                         cameraMatrix[14] += cameraMatrix[10];
01849                 break;
01850                 case (Key_Down):
01851                         cameraMatrix[12] -= cameraMatrix[8];
01852                         cameraMatrix[13] -= cameraMatrix[9];
01853                         cameraMatrix[14] -= cameraMatrix[10];                   
01854                 break;
01855                 case (Key_Left):
01856                         cameraMatrix[12] -= cameraMatrix[0];
01857                         cameraMatrix[13] -= cameraMatrix[1];
01858                         cameraMatrix[14] -= cameraMatrix[2];;
01859                 break;
01860                 case(Key_Right):
01861                         cameraMatrix[12] += cameraMatrix[0];
01862                         cameraMatrix[13] += cameraMatrix[1];
01863                         cameraMatrix[14] += cameraMatrix[2];
01864                 break;
01865                 
01866                 //This accelerator should only have been set up with known key sequences
01867                 //So something is wrong if the default is reached
01868                 default: 
01869                         cerr<<"NetworkViewer: KEY ACCELERATOR KEY SEQUENCE NOT RECOGNISED: "<<keySequence<<endl;
01870                         QMessageBox::critical( 0, "Error", "Key accelerator sequence not recognized");
01871         }
01872 
01873         //Update the graphics display. Only reach this point if the key sequence has been recognised
01874         updateGL();
01875         
01876         //Set timer to start high quality rendering after appropriate delay
01877         if(fullRenderMode){
01878                 renderTimer->start(renderDelay_ms, TRUE );
01879         }
01880 }
01881 
01882 
01883 /*! Switches on full render. Full render mode must be enabled first. 
01884         Generally triggered after renderDelay_ms. */
01885 void NetworkViewer::setFullRender(){
01886         viewStateChanged = true;//Record the fact that the view state has changed
01887         if(fullRenderMode){
01888                 fullRender = true;
01889                 initialiseFullRender();
01890                 updateGL();
01891         }
01892 }
01893 
01894 
01895 //----------------------------------------------------------------------------------------------
01896 //------------------------------ PRIVATE UTILITY METHODS ---------------------------------------
01897 //----------------------------------------------------------------------------------------------
01898 
01899 /*! Checks for errors in OpenGL. */
01900 void NetworkViewer::checkOpenGLErrors(){
01901         GLenum err = glGetError();
01902         while(err != GL_NO_ERROR){
01903                 cerr<<"NetworkViewer OpenGL ERROR: "<<gluErrorString(err)<<endl;
01904                 cerr.flush();
01905                 err = glGetError();
01906         }
01907 }
01908 
01909 
01910 /*! Deletes all of the connection groups being displayed. */
01911 void NetworkViewer::deleteAllConnectionGroups(){
01912         //Delete all data structures associated with each connection group
01913         for(map<unsigned int, ConnectionGroupHolder*>::iterator iter = connectionGrpMap.begin(); iter != connectionGrpMap.end(); ++iter){
01914                 delete iter->second;
01915         }
01916 
01917         //Clear the references
01918         connectionGrpMap.clear();
01919         connectionViewVector.clear();
01920 }
01921 
01922 
01923 /*! Deletes all the neuron groups without deleteing associated connection groups. */
01924 void NetworkViewer::deleteAllNeuronGroups(){
01925         //Delete neuron group holders
01926         for(map<unsigned int, NeuronGroupHolder*>::iterator iter = neuronGrpMap.begin(); iter != neuronGrpMap.end(); ++iter)
01927                 delete iter->second;
01928 
01929         //Empty the maps and vectors
01930         neuronGrpMap.clear();
01931         layerViewVector.clear();
01932 
01933         //Sort out any variables linked to the neuron group
01934         firstSingleNeurGrpID = 0;
01935         minFirstSingleNeuronID = 0;
01936         maxFirstSingleNeuronID = 0;
01937         firstSingleNeuronGroupWidth = 0;
01938         secondSingleNeurGrpID = 0;
01939         maxSecondSingleNeuronID = 0;
01940         minSecondSingleNeuronID = 0;
01941         secondSingleNeuronGroupWidth = 0;
01942         showBetweenConnections = false;
01943 }
01944 
01945 
01946 /*! Switches off everything associated with full render mode. */
01947 void NetworkViewer::disableFullRender(){
01948         glDisable(GL_CULL_FACE);
01949         glDisable(GL_DEPTH_TEST);
01950         glDisable(GL_LIGHTING);
01951         glDisable(GL_LIGHT0);
01952         glDisable(GL_COLOR_MATERIAL);
01953         fullRender = false;
01954         viewStateChanged = true;//Want to rebuild the display list with vertices not spheres
01955 }
01956 
01957 
01958 /*! Draw X, Y and Z axes
01959         These are drawn so that they cover the clipping volume plus a bit of extra length. */
01960 void NetworkViewer::drawAxes(void){
01961         //Set the drawing colour to red
01962         glColor3f(1.0f, 0.0f, 0.0f);
01963         
01964         //Store current line width
01965         glPushAttrib(GL_LINE_BIT);
01966         
01967         //Set wide line 
01968         glLineWidth(2.0f);
01969         
01970         //Draw the axes, extending extraLength beyond clipping volume
01971     GLfloat extraLength = 20.0f;
01972         
01973         //Draw the main axes
01974     glBegin(GL_LINES);
01975                 //X Axis
01976                 glVertex3f(defaultClippingVol.minX - extraLength, 0.0f, 0.0f);
01977         glVertex3f(defaultClippingVol.maxX + extraLength, 0.0f, 0.0f);
01978                 //Y Axis
01979                 glVertex3f(0.0f, defaultClippingVol.minY - extraLength, 0.0f);
01980         glVertex3f(0.0f, defaultClippingVol.maxY + extraLength, 0.0f);
01981                 //Z Axis
01982                 glVertex3f(0.0f, 0.0f, defaultClippingVol.minZ - extraLength);
01983         glVertex3f(0.0f, 0.0f, defaultClippingVol.maxZ + extraLength);
01984         glEnd();
01985         
01986         //Work along axes, marking every point with a point
01987         GLfloat scaleMarkSpacing = 5.0f;
01988         
01989         //Set colour and point size
01990         glColor3f(0.0f, 0.0f, 1.0f);
01991         glPointSize(3.0f);
01992         
01993         //Draw markings on X axis
01994         for(float i=defaultClippingVol.minX - extraLength; i< defaultClippingVol.maxX + extraLength; i += scaleMarkSpacing){
01995                 glBegin(GL_POINTS);
01996                         glVertex3f(i, 0.0f, 0.0f);
01997                 glEnd();
01998         }
01999         
02000         //Draw markings on Y axis
02001         for(float i=defaultClippingVol.minY - extraLength; i< defaultClippingVol.maxY + extraLength; i += scaleMarkSpacing){
02002                 glBegin(GL_POINTS);
02003                         glVertex3f(0.0f, i, 0.0f);
02004                 glEnd();
02005         }
02006         
02007         //Draw markings on Z axis
02008         for(float i=defaultClippingVol.minZ - extraLength; i< defaultClippingVol.maxZ + extraLength; i += scaleMarkSpacing){
02009                 glBegin(GL_POINTS);
02010                         glVertex3f(0.0f, 0.0f, i);
02011                 glEnd();
02012         }
02013         
02014         //Reset line width to original value
02015         glPopAttrib();
02016 }
02017 
02018 
02019 /*! Used to represent neurons as a solid sphere
02020         Adapted from gltools
02021         FIXME A BETTER NEURON REPRESENTATION COULD BE CREATED - PERHAPS USING TEXTURE MAPPING. */
02022 void NetworkViewer::drawSolidSphere(GLdouble radius, GLint slices, GLint stacks){
02023         GLUquadricObj *pObj = gluNewQuadric();
02024         gluQuadricDrawStyle(pObj, GLU_FILL);
02025         gluQuadricNormals(pObj, GLU_SMOOTH);
02026   /* NOTE If we ever changed/used the texture or orientation state
02027      of quadObj, we'd need to change it to the defaults here
02028      with gluQuadricTexture and/or gluQuadricOrientation. */
02029         gluSphere(pObj, radius, slices, stacks);
02030 }
02031 
02032 
02033 /*! Adapted from gltools
02034         Fills the 4x4 rotation matrix to enable it to be used to rotate camera frame
02035         Note that angle is in radians NOT degrees. */
02036 void NetworkViewer::fillRotationMatrix(float angle, float x, float y, float z){
02037     float vecLength, sinSave, cosSave, oneMinusCos;
02038     float xx, yy, zz, xy, yz, zx, xs, ys, zs;
02039 
02040     // If NULL vector passed in, this will blow up...
02041     if(x == 0.0f && y == 0.0f && z == 0.0f){
02042         cerr<<"NetworkViewer: NULL MATRIX PASSED TO fillRotationMatrix.";
02043                 QMessageBox::critical( 0, "Error", "Null matrix passed to fillRotationMatrix.");
02044                 return;
02045     }
02046 
02047     // Scale vector
02048     vecLength = (float)sqrt( x*x + y*y + z*z );
02049 
02050     // Rotation matrix is normalized
02051     x /= vecLength;
02052     y /= vecLength;
02053     z /= vecLength;
02054 
02055     sinSave = (float)sin(angle);
02056     cosSave = (float)cos(angle);
02057     oneMinusCos = 1.0f - cosSave;
02058 
02059     xx = x * x;
02060     yy = y * y;
02061     zz = z * z;
02062     xy = x * y;
02063     yz = y * z;
02064     zx = z * x;
02065     xs = x * sinSave;
02066     ys = y * sinSave;
02067     zs = z * sinSave;
02068 
02069     rotationMatrix[0] = (oneMinusCos * xx) + cosSave;
02070     rotationMatrix[4] = (oneMinusCos * xy) - zs;
02071     rotationMatrix[8] = (oneMinusCos * zx) + ys;
02072     rotationMatrix[12] = 0.0f;
02073 
02074     rotationMatrix[1] = (oneMinusCos * xy) + zs;
02075     rotationMatrix[5] = (oneMinusCos * yy) + cosSave;
02076     rotationMatrix[9] = (oneMinusCos * yz) - xs;
02077     rotationMatrix[13] = 0.0f;
02078 
02079     rotationMatrix[2] = (oneMinusCos * zx) - ys;
02080     rotationMatrix[6] = (oneMinusCos * yz) + xs;
02081     rotationMatrix[10] = (oneMinusCos * zz) + cosSave;
02082     rotationMatrix[14] = 0.0f;
02083 
02084     rotationMatrix[3] = 0.0f;
02085     rotationMatrix[7] = 0.0f;
02086     rotationMatrix[11] = 0.0f;
02087     rotationMatrix[15] = 1.0f;
02088 }
02089 
02090 
02091 /*! Converts strings to floats. */
02092 float NetworkViewer::getFloat(string s){
02093         QString qStr(s);
02094         bool ok = true;
02095         float newFloat = qStr.toFloat(&ok);
02096         if(!ok){
02097                 cerr<<"NetworkViewer: STRING TO FLOAT CONVERSION ERROR WITH STRING: \""<<qStr<<"\""<<endl;
02098                 QMessageBox::critical( 0, "Conversion Error", "String to float conversion error.");
02099                 exit(1);
02100         }
02101         return newFloat;
02102 }
02103 
02104 
02105 /*! Sets the camera parameters to their starting values. */
02106 void NetworkViewer::initialiseCameraParameters(){
02107         //Scene rotate parameters are used to control the rotation of the scene
02108         sceneRotateX = 0.0f;
02109         sceneRotateZ = 0.0f;
02110         
02111         //Set up camera looking down positive Y direction with z axis pointing up and positive X to the right
02112         //X axis for camera frame of reference
02113         cameraMatrix[0] = 1.0f;
02114         cameraMatrix[1] = 0.0f;
02115         cameraMatrix[2] = 0.0f;
02116         cameraMatrix[3] = 0.0f;
02117         
02118         //Y axis for camera frame of reference
02119         cameraMatrix[4] = 0.0f;
02120         cameraMatrix[5] = 1.0f;
02121         cameraMatrix[6] = 0.0f;
02122         cameraMatrix[7] = 0.0f;
02123         
02124         //Z axis for camera frame of reference
02125         cameraMatrix[8] = 0.0f;
02126         cameraMatrix[9] = 0.0f;
02127         cameraMatrix[10] = 1.0f;
02128         cameraMatrix[11] = 0.0f;
02129         
02130         //Location for camera frame of reference
02131         cameraMatrix[12] = 0.0f;
02132         cameraMatrix[13] = -5.0f;
02133         cameraMatrix[14] = 0.0f;
02134 }
02135 
02136 
02137 /*! Sets up the graphics to do a detailed rendering of the network. */
02138 //FIXME THIS COULD DO WITH SOME CHECKING AND REFINEMENT ALONG WITH THE REST OF THE FULL RENDER STUFF
02139 void NetworkViewer::initialiseFullRender(){
02140         // Cull backs of polygons
02141         glCullFace(GL_BACK);
02142         glFrontFace(GL_CCW);
02143         glEnable(GL_CULL_FACE);
02144         glEnable(GL_DEPTH_TEST);
02145         
02146         // Setup light parameters
02147         glLightModelfv(GL_LIGHT_MODEL_AMBIENT, fNoLight);
02148         glLightfv(GL_LIGHT0, GL_AMBIENT, fLowLight);
02149         glLightfv(GL_LIGHT0, GL_DIFFUSE, fBrightLight);
02150         glLightfv(GL_LIGHT0, GL_SPECULAR, fBrightLight);
02151         glEnable(GL_LIGHTING);
02152         glEnable(GL_LIGHT0);
02153         
02154         // Mostly use material tracking
02155         glEnable(GL_COLOR_MATERIAL);
02156         glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
02157         glMateriali(GL_FRONT, GL_SHININESS, 128);
02158 }
02159 
02160 
02161 /*! Loads up all of the connection group data so that it can be displayed quickly. */
02162 void NetworkViewer::loadAllConnectionGroups(QSplashScreen* splashScreen){
02163         cout<<"Network viewer: loading connection groups";
02164 
02165         try{
02166                 //First get a list of ConnectionGrpIDs and store a data structure for each group
02167                 Query query = dbInterface->getQuery();
02168                 query.reset();
02169                 query<<"SELECT ConnGrpID, ConnType FROM ConnectionGroups";
02170                 Result connGrpRes = query.store();
02171                 for(Result::iterator connGrpIter = connGrpRes.begin(); connGrpIter != connGrpRes.end(); ++connGrpIter){
02172                         Row connGrpRow(*connGrpIter);
02173                         unsigned int connGrpID = Utilities::getUInt((std::string)connGrpRow["ConnGrpID"]);
02174                         if(splashScreen !=0)
02175                                 splashScreen->message("Loading connection group: " + QString::number(connGrpID), Qt::AlignBottom, QColor(255, 255, 255));
02176                         loadConnectionGroup(connGrpID, false);
02177                         cout<<".";
02178                 }
02179         }
02180         catch (const BadQuery& er) {// Handle any query errors
02181                 cerr<<"NetworkViewer: MYSQL QUERY EXCEPTION \""<<er.what()<<"\""<<endl;
02182                 QString errorString = "Bad query loading connection groups: \"";
02183                 errorString += er.what();
02184                 errorString += "\"";
02185                 QMessageBox::critical( 0, "Load Connection Group Error", errorString);
02186         }
02187         catch (const Exception& er) {// Catch-all for any other MySQL++ exceptions
02188                 cerr<<"NetworkViewer: MYSQL EXCEPTION \""<<er.what()<<"\""<<endl;
02189                 QString errorString = "Exception thrown loading connection groups: \"";
02190                 errorString += er.what();
02191                 errorString += "\"";
02192                 QMessageBox::critical( 0, "Load Connection Group Error", errorString);
02193         }
02194         catch(std::exception& er){// Catch-all for std exceptions
02195                 cerr<<"NetworkViewer: STD EXCEPTION \""<<er.what()<<"\""<<endl;
02196                 QString errorString = "Exception thrown loading connection groups: \"";
02197                 errorString += er.what();
02198                 errorString += "\"";
02199                 QMessageBox::critical( 0, "Load Connection Group Error", errorString);
02200         }
02201 
02202         cout<<" complete."<<endl;
02203 }
02204 
02205 
02206 /*! Loads up all the neuron groups into a data structure to enable rapid display. */
02207 void NetworkViewer::loadAllNeuronGroups(QSplashScreen* splashScreen){
02208         cout<<"Network viewer: loading layers";
02209 
02210         try{
02211                 //First get a list of NeuronGrpIDs and store a data structure for each group
02212                 Query query = dbInterface->getQuery();
02213                 query.reset();
02214                 query<<"SELECT NeuronGrpID, NeuronType FROM NeuronGroups";
02215                 Result neuronGrpRes = query.store();
02216                 for(Result::iterator neuronGrpIter = neuronGrpRes.begin(); neuronGrpIter != neuronGrpRes.end(); ++neuronGrpIter){
02217                         Row neuronGrpRow(*neuronGrpIter);
02218                         unsigned int neuronGrpID = Utilities::getUInt((std::string)neuronGrpRow["NeuronGrpID"]);
02219                         if(splashScreen != 0)
02220                                 splashScreen->message("Loading neuron group: " + QString::number(neuronGrpID), Qt::AlignBottom, QColor(255, 255, 255));
02221                         loadNeuronGroup(neuronGrpID, false);
02222                         cout<<".";
02223                 }
02224                 
02225                 //Load up the clipping volume from the database. This volume includes all of the neural networks
02226                 loadDefaultClippingVolume();
02227                 viewClippingVolume_Horizontal(defaultClippingVol);
02228         }
02229         catch (const BadQuery& er) {// Handle any query errors
02230                 cerr<<"NetworkViewer: MYSQL QUERY EXCEPTION \""<<er.what()<<"\""<<endl;
02231                 QString errorString = "Bad query loading neuron groups: \"";
02232                 errorString += er.what();
02233                 errorString += "\"";
02234                 QMessageBox::critical( 0, "Load Neuron Group Error", errorString);
02235         }
02236         catch (const Exception& er) {// Catch-all for any other MySQL++ exceptions
02237                 cerr<<"NetworkViewer: MYSQL EXCEPTION \""<<er.what()<<"\""<<endl;
02238                 QString errorString = "Exception thrown loading neuron groups: \"";
02239                 errorString += er.what();
02240                 errorString += "\"";
02241                 QMessageBox::critical( 0, "Load Neuron Group Error", errorString);
02242         }
02243         catch(std::exception& er){// Catch-all for std exceptions
02244                 cerr<<"NetworkViewer: STD EXCEPTION \""<<er.what()<<"\""<<endl;
02245                 QString errorString = "Exception thrown loading neuron groups: \"";
02246                 errorString += er.what();
02247                 errorString += "\"";
02248                 QMessageBox::critical( 0, "Load Neuron Group Error", errorString);
02249         }
02250         
02251         cout<<" complete."<<endl;//Loading of neuron data is finished
02252 }
02253 
02254 
02255 /*! Adapated from gltools
02256         Rotates a vector using a 4x4 matrix. Translation column is ignored. */
02257 void NetworkViewer::rotateVector(GLfloat x, GLfloat y, GLfloat z, GLfloat result[]){
02258     result[0] = rotationMatrix[0] * x + rotationMatrix[4] * y + rotationMatrix[8] *  z;
02259     result[1] = rotationMatrix[1] * x + rotationMatrix[5] * y + rotationMatrix[9] *  z;
02260     result[2] = rotationMatrix[2] * x + rotationMatrix[6] * y + rotationMatrix[10] * z;
02261 }
02262 
02263 
02264 /*! Rotates camera around its own X axis. */
02265 void NetworkViewer::rotateXAxis(float angle){
02266         //Rotating around X axis so pass vector defining this axis for the camera to fillRotationMatrix
02267         fillRotationMatrix(angle, cameraMatrix[0], cameraMatrix[1], cameraMatrix[2]);
02268         
02269         //Create temporary array to hold result
02270         GLfloat resultArray[3];
02271         
02272         //First rotate the Y axis around X axis
02273         rotateVector(cameraMatrix[4], cameraMatrix[5], cameraMatrix[6], resultArray);
02274         
02275         //Copy result array into cameraMatrix. Could probably simplify this
02276         cameraMatrix[4] = resultArray[0];
02277         cameraMatrix[5] = resultArray[1];
02278         cameraMatrix[6] = resultArray[2];
02279         
02280         //Now rotate the Z axis around X axis
02281         rotateVector(cameraMatrix[8], cameraMatrix[9], cameraMatrix[10], resultArray);
02282         
02283         //Copy result array into cameraMatrix. Could probably simplify this
02284         cameraMatrix[8] = resultArray[0];
02285         cameraMatrix[9] = resultArray[1];
02286         cameraMatrix[10] = resultArray[2];
02287 }
02288 
02289 
02290 /*! Rotates camera around its own Z axis. */
02291 void NetworkViewer::rotateZAxis(float angle){
02292         //Rotating around Z axis, so pass vector defining this axis for the camera to fillRotationMatrix
02293         fillRotationMatrix(angle, cameraMatrix[8], cameraMatrix[9], cameraMatrix[10]);
02294         
02295         //Create temporary array to hold result
02296         GLfloat resultArray[3];
02297         
02298         //First rotate the X axis around Z axis
02299         rotateVector(cameraMatrix[0], cameraMatrix[1], cameraMatrix[2], resultArray);
02300         
02301         //Copy result array into cameraMatrix. Could probably simplify this
02302         cameraMatrix[0] = resultArray[0];
02303         cameraMatrix[1] = resultArray[1];
02304         cameraMatrix[2] = resultArray[2];
02305         
02306         //Now rotate the Y axis around Z axis
02307         rotateVector(cameraMatrix[4], cameraMatrix[5], cameraMatrix[6], resultArray);
02308         
02309         //Copy result array into cameraMatrix. Could probably simplify this
02310         cameraMatrix[4] = resultArray[0];
02311         cameraMatrix[5] = resultArray[1];
02312         cameraMatrix[6] = resultArray[2];
02313 
02314 }
02315 
02316 
02317 /*! Sets the view so that the perspective fits the clipping volume seen horizontally. */
02318 void NetworkViewer::viewClippingVolume_Horizontal(ClippingVolume clipVolume){
02319         //First set camera parameters to their starting values
02320         initialiseCameraParameters();
02321 
02322         //Now adjust these parameters to view the whole of the clipping volume
02323         //X location should be half way along the clipping volume
02324         cameraMatrix[12] = clipVolume.minX + (clipVolume.maxX - clipVolume.minX)/2.0f;
02325         
02326         
02327         //Camera is looking down the Y axis. So need to move back far enough to see all of clipping volume within perspective
02328         //First find whether z or x direction is longest
02329         GLfloat backwardsDistance;
02330         if((clipVolume.maxX - clipVolume.minX) > (clipVolume.maxZ - clipVolume.minZ)){//X direction is longest
02331                 backwardsDistance = ((clipVolume.maxX - clipVolume.minX)/2.0f)/tan(gltDegToRad(perspective_angle)/2.0f);
02332         }
02333         else{//Z direction is longest
02334                 backwardsDistance = ((clipVolume.maxZ - clipVolume.minZ)/2.0f)/tan(gltDegToRad(perspective_angle)/2.0f);        
02335         }
02336         //Now move camera back so that it can see everything in both directions
02337         //In this case this moves camera back along the negative y direction
02338         cameraMatrix[13] = -1 * backwardsDistance;
02339         
02340         //Z location should be half way up clipping volume
02341         cameraMatrix[14] = clipVolume.minZ + (clipVolume.maxZ - clipVolume.minZ)/2.0f;
02342         
02343         //Forward vector does not need to be calculated because camera is initilised looking along positive Y, which is correct for horizontal view     
02344 }
02345 
02346 
02347 /*! Sets the view so that the perspective fits the clipping volume seen horizontally. */
02348 void NetworkViewer::viewClippingVolume_Vertical(ClippingVolume clipVolume){
02349         //First set camera parameters to their starting values
02350         initialiseCameraParameters();
02351         
02352         //X location should be half way along the clipping volume
02353         cameraMatrix[12] = clipVolume.minX + (clipVolume.maxX - clipVolume.minX)/2.0f;
02354         
02355         //Camera is looking down the Z axis. So need to move back far enough to see all of clipping volume within perspective
02356         //First find whether y or x direction is longest
02357         GLfloat backwardsDistance;
02358         if((clipVolume.maxX - clipVolume.minX) > (clipVolume.maxY - clipVolume.minY)){//X direction is longest
02359                 backwardsDistance = ((clipVolume.maxX - clipVolume.minX)/2.0f)/tan(gltDegToRad(perspective_angle)/2.0f);
02360         }
02361         else{//Y direction is longest
02362                 backwardsDistance = ((clipVolume.maxY - clipVolume.minY)/2.0f)/tan(gltDegToRad(perspective_angle)/2.0f);        
02363         }
02364 
02365         //Now move camera back so that it can see everything in both directions
02366         //To look above need to move up the positive direction of the Z axis 
02367         cameraMatrix[14] = 1.1f*(backwardsDistance + clipVolume.maxZ);
02368         
02369         //Y location should be half way along clipping volume
02370         cameraMatrix[13] = clipVolume.minY + (clipVolume.maxY - clipVolume.minY)/2.0f;
02371         
02372         //X axis stays the same 
02373         //Change camera Y axis so that it is pointing down negative Z
02374         cameraMatrix[4] = 0.0f;
02375         cameraMatrix[5] = 0.0f;
02376         cameraMatrix[6] = -1.0f;
02377         
02378         //Change camera Z axis so that it points along positive Y
02379         cameraMatrix[8] = 0.0f;
02380         cameraMatrix[9] = 1.0f;
02381         cameraMatrix[10] = 0.0f;
02382 }
02383 
02384 
02385 

Generated on Mon Sep 3 22:29:04 2007 for SpikeStream Application by  doxygen 1.4.4