SpikeStream Application Library
0.2
|
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