SpikeStream Application Library  0.2
NetworkDisplay.cpp
Go to the documentation of this file.
00001 //SpikeStream includes
00002 #include "Globals.h"
00003 #include "GlobalVariables.h"
00004 #include "NetworkDisplay.h"
00005 #include "SpikeStreamException.h"
00006 #include "Util.h"
00007 using namespace spikestream;
00008 
00009 
00011 NetworkDisplay::NetworkDisplay(){
00012         //Reset this class when the network is changed
00013         connect(Globals::getEventRouter(), SIGNAL (networkChangedSignal()), this, SLOT(networkChanged()), Qt::QueuedConnection);
00014 
00015         //Inform other classes when the display has changed
00016         connect(this, SIGNAL(networkDisplayChanged()), Globals::getEventRouter(), SLOT(networkDisplayChangedSlot()), Qt:: QueuedConnection);
00017         connect(this, SIGNAL(visibleConnectionsChanged()), Globals::getEventRouter(), SLOT(visibleConnectionsChangedSlot()), Qt:: QueuedConnection);
00018         connect(this, SIGNAL(neuronGroupDisplayChanged()), Globals::getEventRouter(), SLOT(neuronGroupDisplayChangedSlot()), Qt:: QueuedConnection);
00019 
00020         //Listen for changes to network viewer
00021         connect(Globals::getEventRouter(), SIGNAL(networkViewChangedSignal()), this, SLOT(clearZoom()));
00022 
00023         /* Set colours of neurons that are used multiple times and need to be stored in the default
00024         map to prevent deletion */
00025         archiveFiringNeuronColor.set(1.0f, 0.0f, 1.0f);
00026         defaultColorMap[&archiveFiringNeuronColor] = true;
00027         simulationFiringNeuronColor.set(0.0f, 1.0f, 0.0f);
00028         defaultColorMap[&simulationFiringNeuronColor] = true;
00029         highlightNeuronColor.set(0.0f, 1.0f, 1.0f);
00030         defaultColorMap[&highlightNeuronColor] = true;
00031 
00032         //Set neuron colours that are used directly by NetworkViewer and do not need to be stored in map
00033         defaultNeuronColor.set(0.0f, 0.0f, 0.0f);
00034         defaultNeuronColorFullRender.set(0.5f, 0.5f, 0.5f);
00035         singleNeuronColor.set(1.0f, 0.75f, 0.0f);
00036         toNeuronColor.set(1.0f, 0.0f, 1.0f);
00037 
00038         //Connection colors do not need to be stored at present
00039         positiveConnectionColor.set(1.0f, 0.0f, 0.0f);
00040         negativeConnectionColor.set(0.0f, 0.0f, 1.0f);
00041 
00042         //Initialize color map
00043         neuronColorMap = new QHash<unsigned int, RGBColor*>();
00044 
00045         //Default connection mode settings
00046         connectionMode = 0;
00047         weightRenderMode = 0;
00048         singleNeuronID = 0;
00049         toNeuronID = 0;
00050 
00051         //Default render settings
00052         fullRenderMode = false;
00053 
00054         //Other defaults
00055         vertexSize = 7.5;
00056         sphereRadius = 0.1f;
00057         sphereQuality = 10;
00058         drawAxes = true;
00059         neuronTransparency = 1.0;
00060 }
00061 
00062 
00064 NetworkDisplay::~NetworkDisplay(){
00065 }
00066 
00067 
00068 /*----------------------------------------------------------*/
00069 /*-----                  PUBLIC SLOTS                  -----*/
00070 /*----------------------------------------------------------*/
00071 
00073 void NetworkDisplay::networkChanged(){
00074         //Clear current display information
00075         connGrpDisplayMap.clear();
00076         neurGrpDisplayMap.clear();
00077         clearNeuronColorMap();
00078         unsetConnectionModeFlag(CONNECTION_MODE_ENABLED);
00079         singleNeuronID = 0;
00080         toNeuronID = 0;
00081         zoomStatus = NO_ZOOM;
00082         zoomNeuronGroupID = 0;
00083 
00084         if(Globals::networkLoaded()){
00085                 //Make the neuron groups visible by default
00086                 setVisibleNeuronGroupIDs(Globals::getNetwork()->getNeuronGroupIDs(), false);
00087 
00088                 //Only show connection groups if they are not too many visible connections.
00089                 setDefaultVisibleConnectionGroupIDs();
00090         }
00091 }
00092 
00093 
00094 /*----------------------------------------------------------*/
00095 /*-----                 PRIVATE SLOTS                  -----*/
00096 /*----------------------------------------------------------*/
00097 
00100 void NetworkDisplay::clearZoom(){
00101         int oldZoomStatus = zoomStatus;
00102         zoomStatus = NO_ZOOM;
00103 
00104         //Inform other classs about the change
00105         if(oldZoomStatus != NO_ZOOM)
00106                 emit networkDisplayChanged();
00107 }
00108 
00109 
00110 /*----------------------------------------------------------*/
00111 /*-----                PUBLIC METHODS                  -----*/
00112 /*----------------------------------------------------------*/
00113 
00116 void NetworkDisplay::addDefaultColor(RGBColor *color){
00117         if(defaultColorMap.contains(color))
00118                 throw SpikeStreamException("Default colour has already been set.");
00119         defaultColorMap[color] = true;
00120 }
00121 
00122 
00125 void NetworkDisplay::addHighlightNeurons(const QList<unsigned int>& neuronIDs, RGBColor* color){
00126         //Obtain and lock the mutex
00127         QMutexLocker locker(&mutex);
00128 
00129         foreach(unsigned int neurID, neuronIDs){
00130                 //Add color if it is not already in the map
00131                 if(!neuronColorMap->contains(neurID)){
00132                         (*neuronColorMap)[neurID] = color;
00133                 }
00134                 //Replace the color
00135                 else{
00136                         //Delete the color associated with the neuron id if it is not a default color
00137                         if(!defaultColorMap.contains( (*neuronColorMap)[neurID]) )
00138                                 delete (*neuronColorMap)[neurID];
00139                         //Set the color in the map
00140                         (*neuronColorMap)[neurID] = color;
00141                 }
00142         }
00143 
00144         //Inform other classes that the display has changed
00145         emit networkDisplayChanged();
00146 }
00147 
00148 
00151 void NetworkDisplay::addHighlightNeurons(const QHash<unsigned int, RGBColor*>& colorMap){
00152         //Obtain and lock the mutex
00153         QMutexLocker locker(&mutex);
00154 
00155         for( QHash<unsigned int, RGBColor*>::const_iterator iter = colorMap.begin(); iter != colorMap.end(); ++iter){
00156                 //Add color if it is not already in the map
00157                 if(!neuronColorMap->contains(iter.key())){
00158                         (*neuronColorMap)[iter.key()] = iter.value();
00159                 }
00160                 //Replace the color
00161                 else{
00162                         //Delete the color associated with the neuron id if it is not a default color
00163                         if(!defaultColorMap.contains( (*neuronColorMap)[iter.key()]) )
00164                                 delete (*neuronColorMap)[iter.key()];
00165                         //Set the color in the map
00166                         (*neuronColorMap)[iter.key()] = iter.value();
00167                 }
00168         }
00169 
00170         //Inform other classes that the display has changed
00171         emit networkDisplayChanged();
00172 }
00173 
00174 
00178 unsigned NetworkDisplay::getConnectionThinningThreshold(){
00179         if(fullRenderMode && (weightRenderMode & WEIGHT_RENDER_ENABLED))
00180                 return connectionThinningThreshold_full;
00181         return connectionThinningThreshold_fast;
00182 }
00183 
00184 
00186 void NetworkDisplay::removeHighlightNeurons(const QList<unsigned int>& neuronIDs){
00187         foreach(unsigned int neurID, neuronIDs){
00188                 if(neuronColorMap->contains(neurID)){
00189                         //Delete the color associated with the neuron id if it is not a default color
00190                         if(!defaultColorMap.contains( (*neuronColorMap)[neurID]) )
00191                                 delete (*neuronColorMap)[neurID];
00192 
00193                         //Remove the entry for the neuron
00194                         neuronColorMap->remove(neurID);
00195                 }
00196         }
00197 
00198         //Inform other classes that the display has changed
00199         emit networkDisplayChanged();
00200 }
00201 
00202 
00204 bool NetworkDisplay::connectionGroupVisible(unsigned int conGrpID){
00205         if(connGrpDisplayMap.contains(conGrpID))
00206                 return true;
00207         return false;
00208 }
00209 
00210 
00212 bool NetworkDisplay::neuronGroupVisible(unsigned int neurGrpID){
00213         if(neurGrpDisplayMap.contains(neurGrpID))
00214                 return true;
00215         return false;
00216 }
00217 
00218 
00221 void NetworkDisplay::loadDisplaySettings(ConfigLoader* configLoader){
00222         vertexSize = Util::getFloat( configLoader->getParameter("vertex_size") );
00223         drawAxes = Util::getBool( configLoader->getParameter("draw_axes") );
00224         sphereRadius = Util::getFloat( configLoader->getParameter("sphere_radius") );
00225         sphereQuality = Util::getUInt( configLoader->getParameter("sphere_quality") );
00226         connectionVisibilityThreshold_fast = Util::getInt( configLoader->getParameter("connection_visibility_threshold_fast") );
00227         connectionVisibilityThreshold_full = Util::getInt( configLoader->getParameter("connection_visibility_threshold_full") );
00228         minimumConnectionRadius = Util::getFloat( configLoader->getParameter("minimum_connection_radius") );
00229         weightRadiusFactor = Util::getFloat( configLoader->getParameter("weight_radius_factor") );
00230         connectionQuality = Util::getUInt( configLoader->getParameter("connection_quality") );
00231         connectionThinningThreshold_fast = Util::getUInt( configLoader->getParameter("connection_thinning_threshold_fast") );
00232         connectionThinningThreshold_full = Util::getUInt( configLoader->getParameter("connection_thinning_threshold_full") );
00233 }
00234 
00235 
00237 void NetworkDisplay::lockMutex(){
00238         mutex.lock();
00239 }
00240 
00241 
00243 void NetworkDisplay::setConnectionGroupVisibility(unsigned int conGrpID, bool visible){
00244         if(visible){
00245                 connGrpDisplayMap[conGrpID] = true;
00246         }
00247         else{
00248                 connGrpDisplayMap.remove(conGrpID);
00249         }
00250 
00251         //Inform other classes that the display has changed
00252         emit networkDisplayChanged();
00253 }
00254 
00255 
00257 void NetworkDisplay::setFullRenderMode(bool fullRenderMode){
00258         this->fullRenderMode = fullRenderMode;
00259         setDefaultVisibleConnectionGroupIDs();
00260         emit networkDisplayChanged();
00261 }
00262 
00263 
00265 void NetworkDisplay::setNeuronColorMap(QHash<unsigned int, RGBColor*>* newMap){
00266         //Obtain and lock the mutex
00267         QMutexLocker locker(&mutex);
00268 
00269         //Clear current entries and delete existing map
00270         clearNeuronColorMap();
00271         delete neuronColorMap;
00272 
00273         //Point map to new map
00274         neuronColorMap = newMap;
00275 
00276         //Inform other classes that the display has changed
00277         emit neuronGroupDisplayChanged();
00278 }
00279 
00280 
00282 void NetworkDisplay::setNeuronGroupVisibility(unsigned int neurGrpID, bool visible){
00283         if(visible){
00284                 neurGrpDisplayMap[neurGrpID] = true;
00285         }
00286         else{
00287                 neurGrpDisplayMap.remove(neurGrpID);
00288         }
00289         //Inform other classes that the display has changed
00290         emit neuronGroupDisplayChanged();
00291 }
00292 
00293 
00295 void NetworkDisplay::setNeuronTransparency(float neuronTransparency){
00296          this->neuronTransparency = neuronTransparency;
00297          emit neuronGroupDisplayChanged();
00298 }
00299 
00300 
00302 void NetworkDisplay::setVisibleConnectionGroupIDs(const QList<unsigned int>& connGrpIDs, bool emitDisplayChangedSignal){
00303         //Obtain and lock the mutex
00304         QMutexLocker locker(&mutex);
00305 
00306         //Add the neuron group IDs to the map
00307         connGrpDisplayMap.clear();
00308         for(QList<unsigned int>::ConstIterator iter = connGrpIDs.begin(); iter != connGrpIDs.end(); ++iter)
00309                 connGrpDisplayMap[*iter] = true;
00310 
00311         //Inform other classes that the display has changed
00312         if(emitDisplayChangedSignal)
00313                 emit networkDisplayChanged();
00314 }
00315 
00316 
00318 void NetworkDisplay::setVisibleNeuronGroupIDs(const QList<unsigned int>& neurGrpIDs, bool emitDisplayChangedSignal){
00319         //Obtain and lock the mutex
00320         QMutexLocker locker(&mutex);
00321 
00322         neurGrpDisplayMap.clear();
00323         for(QList<unsigned int>::ConstIterator iter = neurGrpIDs.begin(); iter != neurGrpIDs.end(); ++iter)
00324                 neurGrpDisplayMap[*iter] = true;
00325 
00326         //Inform other classes that the display has changed
00327         if(emitDisplayChangedSignal)
00328                 emit neuronGroupDisplayChanged();
00329 }
00330 
00331 
00333 void NetworkDisplay::unlockMutex(){
00334         mutex.unlock();
00335 }
00336 
00337 
00339 void NetworkDisplay::setConnectionModeFlag(unsigned int flag){
00340         checkConnectionModeFlag(flag);
00341         connectionMode |= flag;
00342 }
00343 
00344 
00346 void NetworkDisplay::unsetConnectionModeFlag(unsigned int flag){
00347         checkConnectionModeFlag(flag);
00348         //Flip the bits in the flag and then AND it with the connection mode
00349         connectionMode &= ~flag;
00350 }
00351 
00352 
00354 bool NetworkDisplay::isZoomEnabled(){
00355         if(zoomStatus == NO_ZOOM)
00356                 return false;
00357         return true;
00358 }
00359 
00360 
00363 void NetworkDisplay::setZoom(unsigned int neurGrpID, int status){
00364         int oldStatus = zoomStatus;
00365         unsigned int oldNeurGrpID = zoomNeuronGroupID;
00366         zoomStatus = status;
00367         zoomNeuronGroupID = neurGrpID;
00368 
00369         //Inform other classes if display has changed
00370         if(oldStatus != zoomStatus|| oldNeurGrpID != neurGrpID)
00371                 emit networkDisplayChanged();
00372 }
00373 
00374 
00376 void NetworkDisplay::setSelectedNeuronID(unsigned int id, bool ctrlBtnDown){
00377         bool refreshDisplay = false;
00378 
00379         /* Connection mode is disabled and id is valid.
00380            Switch connection mode on for a single neuron */
00381         if( !(connectionMode & CONNECTION_MODE_ENABLED) && id != 0){
00382                 setConnectionModeFlag(CONNECTION_MODE_ENABLED);
00383                 singleNeuronID = id;
00384                 toNeuronID = 0;
00385                 refreshDisplay = true;
00386         }
00387 
00388         //Switch off connection mode if neuron id is invalid
00389         else if ( (connectionMode & CONNECTION_MODE_ENABLED) && id == 0){
00390                 unsetConnectionModeFlag(CONNECTION_MODE_ENABLED);
00391                 unsetConnectionModeFlag(SHOW_BETWEEN_CONNECTIONS);
00392                 singleNeuronID = 0;
00393                 toNeuronID = 0;
00394                 refreshDisplay = true;
00395         }
00396 
00397         //Connection mode is enabled for a single neuron
00398         else if( (connectionMode & CONNECTION_MODE_ENABLED) && !(connectionMode & SHOW_BETWEEN_CONNECTIONS) ){
00399                 //Enable between mode if a different neuron has been double clicked and control button is down
00400                 if(singleNeuronID != id && ctrlBtnDown){
00401                         toNeuronID = id;
00402                         setConnectionModeFlag(SHOW_BETWEEN_CONNECTIONS);
00403                         refreshDisplay = true;
00404                 }
00405                 //Control button is not down - select a different neuron
00406                 else if(singleNeuronID != id && !ctrlBtnDown){
00407                         singleNeuronID = id;
00408                         refreshDisplay = true;
00409                 }
00410         }
00411 
00412         //In between connection mode
00413         else if( (connectionMode & CONNECTION_MODE_ENABLED) && (connectionMode & SHOW_BETWEEN_CONNECTIONS) ){
00414                 //A neuron has been double clicked without the control button or the first neuron is also selected as the second neuron
00415                 if( !ctrlBtnDown || singleNeuronID == id ){
00416                         unsetConnectionModeFlag(SHOW_BETWEEN_CONNECTIONS);
00417                         singleNeuronID = id;
00418                         toNeuronID = 0;
00419                         refreshDisplay = true;
00420                 }
00421                 //User has double clicked on a different between neuron
00422                 else if (id != toNeuronID){
00423                         toNeuronID = id;
00424                         refreshDisplay = true;
00425                 }
00426         }
00427 
00428         //Refresh display if something has changed
00429         if(refreshDisplay){
00430                 visibleConnectionsList.clear();
00431                 emit visibleConnectionsChanged();
00432                 emit networkDisplayChanged();
00433         }
00434 }
00435 
00436 
00438 void NetworkDisplay::showPositiveConnections() {
00439         setConnectionModeFlag(SHOW_POSITIVE_CONNECTIONS);
00440         unsetConnectionModeFlag(SHOW_NEGATIVE_CONNECTIONS);
00441         emit networkDisplayChanged();
00442 }
00443 
00444 
00446 void NetworkDisplay::showNegativeConnections() {
00447         setConnectionModeFlag(SHOW_NEGATIVE_CONNECTIONS);
00448         unsetConnectionModeFlag(SHOW_POSITIVE_CONNECTIONS);
00449         emit networkDisplayChanged();
00450 }
00451 
00452 
00454 void NetworkDisplay::clearWeightFiltering() {
00455         unsetConnectionModeFlag(SHOW_NEGATIVE_CONNECTIONS);
00456         unsetConnectionModeFlag(SHOW_POSITIVE_CONNECTIONS);
00457         emit networkDisplayChanged();
00458 }
00459 
00460 
00462 void NetworkDisplay::showFromConnections() {
00463         setConnectionModeFlag(SHOW_FROM_CONNECTIONS);
00464         unsetConnectionModeFlag(SHOW_TO_CONNECTIONS);
00465         emit networkDisplayChanged();
00466 }
00467 
00468 
00470 void NetworkDisplay::showToConnections() {
00471         setConnectionModeFlag(SHOW_TO_CONNECTIONS);
00472         unsetConnectionModeFlag(SHOW_FROM_CONNECTIONS);
00473         emit networkDisplayChanged();
00474 }
00475 
00476 
00478 void NetworkDisplay::clearDirectionFiltering(){
00479         unsetConnectionModeFlag(SHOW_FROM_CONNECTIONS);
00480         unsetConnectionModeFlag(SHOW_TO_CONNECTIONS);
00481         emit networkDisplayChanged();
00482 }
00483 
00484 
00486 void  NetworkDisplay::disableWeightRender(){
00487         unsetWeightRenderFlag(WEIGHT_RENDER_ENABLED);
00488         setDefaultVisibleConnectionGroupIDs();
00489         emit networkDisplayChanged();
00490 }
00491 
00492 
00494 void  NetworkDisplay::renderTempWeights(){
00495         setWeightRenderFlag(WEIGHT_RENDER_ENABLED);
00496         setWeightRenderFlag(RENDER_TEMP_WEIGHTS);
00497         unsetWeightRenderFlag(RENDER_CURRENT_WEIGHTS);
00498         setDefaultVisibleConnectionGroupIDs();
00499         emit networkDisplayChanged();
00500 }
00501 
00502 
00504 void  NetworkDisplay::renderCurrentWeights(){
00505         setWeightRenderFlag(WEIGHT_RENDER_ENABLED);
00506         setWeightRenderFlag(RENDER_CURRENT_WEIGHTS);
00507         unsetWeightRenderFlag(RENDER_TEMP_WEIGHTS);
00508         setDefaultVisibleConnectionGroupIDs();
00509         emit networkDisplayChanged();
00510 }
00511 
00512 
00513 /*----------------------------------------------------------*/
00514 /*-----               PRIVATE METHODS                  -----*/
00515 /*----------------------------------------------------------*/
00516 
00518 void NetworkDisplay::clearNeuronColorMap(){
00519         QHash<unsigned int, RGBColor*>::iterator colorMapEnd = neuronColorMap->end();
00520         for(QHash<unsigned int, RGBColor*>::iterator iter = neuronColorMap->begin(); iter != colorMapEnd; ++iter){
00521                 //Don't delete one of the default colours - several neuron ids can point to the same default color for efficiency
00522                 if(!defaultColorMap.contains(iter.value()))
00523                         delete iter.value();
00524         }
00525         neuronColorMap->clear();
00526 }
00527 
00528 
00530 void NetworkDisplay::checkConnectionModeFlag(unsigned int flag){
00531         if(flag == CONNECTION_MODE_ENABLED)
00532                 return;
00533         if(flag == SHOW_BETWEEN_CONNECTIONS)
00534                 return;
00535         if(flag == SHOW_POSITIVE_CONNECTIONS)
00536                 return;
00537         if(flag == SHOW_NEGATIVE_CONNECTIONS)
00538                 return;
00539         if(flag == SHOW_FROM_CONNECTIONS)
00540                 return;
00541         if(flag == SHOW_TO_CONNECTIONS)
00542                 return;
00543         throw SpikeStreamException("Connection mode flag not recognized: " + QString::number(flag));
00544 }
00545 
00546 
00548 void NetworkDisplay::checkWeightRenderFlag(unsigned int flag){
00549         if(flag == WEIGHT_RENDER_ENABLED)
00550                 return;
00551         if(flag == RENDER_TEMP_WEIGHTS)
00552                 return;
00553         if(flag == RENDER_CURRENT_WEIGHTS)
00554                 return;
00555         throw SpikeStreamException("Weight render flag not recognized: " + QString::number(flag));
00556 }
00557 
00558 
00561 void NetworkDisplay::setDefaultVisibleConnectionGroupIDs(){
00562         if(!Globals::networkLoaded())
00563                 return;
00564 
00565         //Add up the number of potentially visible connections
00566         int totalVisCons = 0;
00567         int thinThresh = getConnectionThinningThreshold();
00568         QList<ConnectionGroup*> tmpConGrpList = Globals::getNetwork()->getConnectionGroups();
00569         foreach(ConnectionGroup* tmpConGrp, tmpConGrpList){
00570                 if(tmpConGrp->size() > thinThresh)
00571                         totalVisCons += thinThresh;
00572                 else
00573                         totalVisCons += tmpConGrp->size();
00574         }
00575 
00576         //Show connection groups if the total number of visible connections is less than the threshold
00577         QList<unsigned> visibleConGrpIDs;
00578         bool addAllCons = false;
00579         if(fullRenderMode){
00580                 if( (weightRenderMode & WEIGHT_RENDER_ENABLED) && (totalVisCons < connectionVisibilityThreshold_full) )
00581                         addAllCons = true;
00582                 else if( !(weightRenderMode & WEIGHT_RENDER_ENABLED) && (totalVisCons < connectionVisibilityThreshold_fast) )
00583                         addAllCons = true;
00584         }
00585         else{
00586                 if(totalVisCons < connectionVisibilityThreshold_fast){
00587                         addAllCons = true;
00588                 }
00589         }
00590 
00591         //Show all connection groups if we are below the threshold
00592         if(addAllCons){
00593                 foreach(ConnectionGroup* tmpConGrp, tmpConGrpList){
00594                         visibleConGrpIDs.append(tmpConGrp->getID());
00595                 }
00596         }
00597         setVisibleConnectionGroupIDs(visibleConGrpIDs, false);
00598 }
00599 
00600 
00602 void NetworkDisplay::setWeightRenderFlag(unsigned flag){
00603         checkWeightRenderFlag(flag);
00604         weightRenderMode |= flag;
00605 }
00606 
00607 
00609 void NetworkDisplay::unsetWeightRenderFlag(unsigned flag){
00610         checkWeightRenderFlag(flag);
00611         //Flip the bits in the flag and then AND it with the weight render mode
00612         weightRenderMode &= ~flag;
00613 }
00614 
 All Classes Files Functions Variables Typedefs Friends Defines